#!/usr/bin/expect --
# %Z%%M% %I% %W% %G% %U%

#
# Description:
#   Condition a Cluster node, i.e. 
#   - list the network adapter information such as hardware address, physical 
#     location code;
#   - network boot.
#   This version is for HMC attached systems
#
# Outputs:
#   Network adapter information writtent to stdout
#   Progress and error information written to stderr.
#
# Syntax:
#    Usage: Install partition
#           lpar_netboot [-n] [-v] [-x] [-f] [-i] [-E environment [-E ...]] 
#                        [-A -D | [-D] -l phys_loc | [-D] -m macaddress] [-g args] 
#                        -t ent -s speed -d duplex -S server -G gateway -C client [-K subnetmask]
#                        partition_name profile managed_system
#
#    Usage: Install for system supporting full system partition
#           lpar_netboot [-n] [-v] [-x] [-f] [-i] [-E environment [-E ...]]
#                        [-A -D | [-D] -l phys_loc | [-D] -m macaddress] [-g args] 
#                        -t ent -s speed -d duplex -S server -G gateway -C client [-K subnetmask]
#                        managed_system managed_system
#
#    Usage: Return macaddress
#           lpar_netboot -M -n [-v] [-x] [-f] [-i] [-E environment [-E ...]] [-A] -t ent 
#                        [-D -s speed -d duplex -S server -G gateway -C client [-K subnetmask]] 
#                         partition_name profile managed_system 
#
#    Usage: Return macaddress for system supporting full system partition
#           lpar_netboot -M -n [-v] [-x] [-f] [-i] [-E environment [-E ...]] [-A] -t ent 
#                        [-D -s speed -d duplex -S server -G gateway -C client [-K subnetmask]] 
#                        managed_system managed_system
#
#     -A  for discovery, return all adapters of the given type that successfully
#         ping the given server
#     -C  client ip address
#     -D  Perform ping test.  Use adapter upon a successful ping test.
#     -E  set environment variable setting.  The "-E LPAR_NETBOOT_DEBUG=1" is the same as "export LPAR_NETBOOT_DEBUG=1"
#     -F  hardware control password_file
#     -G  gateway ip address to ping through
#     -J  hostname of Hardware control point
#     -K  subnetmask to ping through
#     -M  discover et hernet adapter mac address and location code
#     -P  use with device discovery to list only physical adapter
#     -S  server ip address to ping to
#     -T  enable/disable spanning tree in Open Firmware
#     -c  use with device discovery to output devices in a colon separated format
#     -d  network adapter duplex
#     -f  force close virtual terminal session
#     -g  generic arguments for booting
#     -j Hardware control point type.
#     -i  immediate shutdown
#     -l  use the following physical location to perform the install
#     -m  use the following macaddress to perform the install
#     -n  Do not do network boot. Instead, power off the node after writing
#         the adapter information to stdout
#     -p password of hardware control point
#     -s  network adapter speed
#     -t  Specifies that only network adapters of type <type> will be returned.
#         <type> may be "ent", "tok", or "fddi".
#     -u username of hardware control point
#     -v  verbose
#     -x  enable debug output
#
#     --noshutdown Do not power off the server after getting the adapter mac
#     --disk Use for listing only disk in device discovery
#     --help print lpar_netboot usage
#
# Environment Variable:
#   =====================================================================================
#   INSTALLIOS_DEBUG           = The installios command used this environment variable to
#                                print out lpar_netboot debug. 
#   LPAR_NETBOOT_3EXEC         = Executing OF "dev /" and "ls" returns nothing, retry reboot and "ls".
#   LPAR_NETBOOT_DEBUG         = Setting this variable will enable lpar_netboot debug.
#   LPAR_NETBOOT_DEBUG_BOOT    = Setting this variable will initate the firmware
#                                boot command with -s trap.
#   LPAR_NETBOOT_ADD_TIMEOUT   = Extend timeout value by 5.  Ex. LPAR_NETBOOT_ADD_TIMEOUT=5
#   LPAR_NETBOOT_SUB_TIMEOUT   = Lower timeout value by 8.  Ex.  LPAR_NETBOOT_SUB_TIMEOUT=8
#   LPAR_NETBOOT_SPANNING_TREE = LPAR_NETBOOT_SPANNING_TREE 
#   OPEN_DEV_DEBUG             = Show firmware OPEN_DEV debug by setting value to yes.
#   FIRMWARE_DUMP              = Show firmware dump for firmware debugging by setting value to yes.
#    
# The chrp interface:
#   CHRP is an industry standard that defines interfaces for boot firmware. It
#   is defined in IEEE 1275-1994 Standard for Boot (Initialization 
#   Configuration) Firmware, with extensions for the RS/6000. At a very high
#   level, it defines a device tree, where the properties of all IO devices
#   are stored, and a command line interface for displaying and changing these 
#   properties. 
#
#   This version of lpar_netboot uses the Open Firmware commands at the command
#   line. The commands themselves are not very intuitive. Most of
#   the commands use a stack, which means that the command verb uses arguments
#   that were previously put on the stack and leaves results on the stack. 
#   From a practical point of view this means that the command verb is the   
#   last word on a command and that additional commands are needed to dump the
#   results of the command  off the stack. However, not all commands are this 
#   way. Some commands have the command verb first with arguements following.
#   More comments on how this works are in the get_mac_addr procedure.
#   
# Debug notes: 
#   The fastest way to debug the patterns in this script is by using the -d
#   flag. This displays the buffer, patterns, and whether a pattern matched
#   or not everytime additional data comes into expect. 
#
#   The main line code follows all procedures. 

log_user 0
set stm 1

#
# PROCEDURE
#
# Change timeout value based on global variable
proc change_timeout { timeout_value } {
    global PROGRAM
    global DSPMSG
    global CATALOG
    global signal
    global env

    if { [info exists env(LPAR_NETBOOT_ADD_TIMEOUT)] } {
        set timeout $env(LPAR_NETBOOT_ADD_TIMEOUT)
        if { [catch {set timeout_value [expr ($timeout_value + $timeout)] }] } {

            nc_msg "$PROGRAM Status: The value for the environment variable LPAR_NETBOOT_ADD_TIMEOUT must be a numerical value.\n"
            nc_msg "$PROGRAM Status: Using default timeout value of : $timeout_value.\n"
        } else {
            nc_msg "$PROGRAM Status: New timeout value : $timeout_value\n"
        }
    }

    if { [info exists env(LPAR_NETBOOT_SUB_TIMEOUT)] } {
        set timeout $env(LPAR_NETBOOT_SUB_TIMEOUT)
        if { $timeout_value > $timeout } {
            if { [catch {set timeout_value [expr ($timeout_value - $timeout)] }] } {
                nc_msg "$PROGRAM Status: The value for the environment variable LPAR_NETBOOT_SUB_TIMEOUT must be a numerical value.\n"
                nc_msg "$PROGRAM Status: Using default timeout value of : $timeout_value.\n"
            } else {
                nc_msg "$PROGRAM Status: New timeout value : $timeout_value\n"
            }
        }
    } 

    return $timeout_value
}

#
# 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.
#
proc nc_msg { msg } {
    global verbose
    global env
    global LOGFILE
    global PROGRAM
    global DSPMSG
    global CATALOG
    global signal

    if { ( $verbose == 1 ) || 
         ( [info exists env(LPAR_NETBOOT_DEBUG)] ) || 
         ( [info exists env(INSTALLIOS_DEBUG)] ) } {
        send_user $msg
    }

    if { $LOGFILE != "" } {
        puts -nonewline $LOGFILE "$msg"
    }
}

#
# PROCEDURE
#
# Declare procedure to write translatable messages to stdout
#
proc write_message { msg } {
    global env
    global LOGFILE

    system "$msg"
    
    if { $LOGFILE != "" } {
        puts -nonewline $LOGFILE "$msg"
    }
}

# 
# PROCEDURE
#   
# Declare procedure to write messages to a log file
#           
proc write_log { msg } {
    global LOGFILE

    if { $LOGFILE != "" } {
        puts -nonewline $LOGFILE "$msg"
    }
}

# 
# PROCEDURE
#
# Declare procedure to write messages to stdout as well as
# to a log file
#
proc write_send_user { msg } {
    global LOGFILE

    if { $LOGFILE != "" } {
        puts -nonewline $LOGFILE "$msg"
    }

    send_user $msg
}

#
# PROCEDURE
#
# Procedure to run the lssyscfg command
# test its return code and capture its output 
#
proc run_lssyscfg {} {
    global BINPATH
    global CATALOG
    global DSPMSG
    global PROGRAM
    global signal
    global env
    global manage
    global msg
    global node
    global profile
    global rc

    nc_msg "$PROGRAM Status: run_lssyscg start\n"
    set LANG "C"
    if {[info exists env(LC_ALL)]} {
        set LANG $env(LC_ALL)
    }
    set env(LC_ALL) "C"

    set runcmd [list exec $BINPATH/lssyscfg -r lpar -m $manage --filter lpar_names=$node -F state]
    set rc [catch $runcmd msg]
    nc_msg "$PROGRAM Status: run_lssyscg : partition status : $msg\n"

    set env(LC_ALL) "$LANG"

    if { $rc } {
        write_message "$DSPMSG -s 1 $CATALOG 38 '%s: Unable to determine machine state\n' \"$PROGRAM\" 2>/dev/null"
        nc_msg "$PROGRAM Status: error from lssyscfg command\n"

	# Execute lssyscfg again so that we can display the error message in its native locale.
        set runcmd [list exec $BINPATH/lssyscfg -r lpar -m $manage --filter lpar_names=$node -F state]
        set rc [catch $runcmd msg]

        write_message "$DSPMSG -s 1 $CATALOG 39 '%s: Error : %s\n' \"$PROGRAM\" \"$msg\" 2>/dev/null"
        exit 1
    }
}

#
# PROCEDURE
#
# Declare procedure to write usage message and exit
#
proc usage {} {
    global PROGRAM
    global DSPMSG
    global CATALOG
    global CTRLTYPE
    if { $CTRLTYPE == "AIX" } {
    write_message "$DSPMSG -s 1 $CATALOG 113 \
           'Usage: Install partition \
            \n\tlpar_netboot \[-v\] \[-x\] \[-f\] \[-i\] \[-g args\] \[-E environment \[-E ...\]\] \[-T {on|off}\] \[-A -D | \[-D\] -l phys_loc | \[-D\] -m macaddress\] \
            \n\t\t-t ent -s speed -d duplex -S server -G gateway -C client \[-J hostname -j Ctrlpoint_type -u username -p password\] \
            \n\t\t\[-K subnetmask\] lpar_id TargetHWSerialNum TargetHWTypeModel \
            \n \
            \nUsage: Install for system supporting full system partition \
            \n\tlpar_netboot \[-v\] \[-x\] \[-f\] \[-i\] \[-g args\] \[-E environment \[-E ...\]\] \[-T {on|off}\] \[-A -D | \[-D\] -l phys_loc | \[-D\] -m macaddress\] \
            \n\t\t-t ent -s speed -d duplex -S server -G gateway -C client \[-J hostname -j Ctrlpoint_type -u username -p password\] \
            \n\t\t\[-K subnetmask\] 1 TargetHWSerialNum TargetHWTypeModel \
            \n \
            \nUsage: Return macaddress from HMC managed lpar \
            \n\tlpar_netboot -M -n \[-v\] \[-x\] \[-f\] \[-i\] \[-E environment \[-E ...\]\] \[-A\] -t ent \[-J hostname -j Ctrlpoint_type -u username -p password\] \
            \n\t\t\[-D -s speed -d duplex -S server -G gateway -C client \[-K subnetmask\]\] \[-T {on|off}\] \[--noshutdown\] lpar_id \
            TargetHWSerialNum TargetHWTypeModel \
            \n \
            \nUsage: Return macaddress from FSP managed system \
            \n\tlpar_netboot -M -n \[-v\] \[-x\] \[-f\] \[-i\] \[-E environment \[-E ...\]\] \[-A\] -t ent \[-J hostname -j Ctrlpoint_type -u username -p password\] \
            \n\t\t\[-D -s speed -d duplex -S server -G gateway -C client \[-K subnetmask\]\] \[-T {on|off}\] \[--noshutdown\]\
            \n \
            \nUsage: Return macaddress from IVM managed lpar \
            \n\tlpar_netboot -M -n  \[-v\] \[-x\] \[-f\] \[-i\] \[-E environment \[-E ...\]\] \[-A\] -t ent \[-J hostname -j Ctrlpoint_type -u username -p password\] \
            \n\t\t\[-D -s speed -d duplex -S server -G gateway -C client \[-K subnetmask\]\] \[-T {on|off}\] \[--noshutdown\] lpar_id \
            \n \
            \nUsage: Return macaddress from BLADE server \
            \n\tlpar_netboot -M -n  \[-v\] \[-x\] \[-f\] \[-i\] \[-E environment \[-E ...\]\] \[-A\] -t ent \[-J hostname -j Ctrlpoint_type -u username -p password\] \
            \n\t\t\[-D -s speed -d duplex -S server -G gateway -C client \[-K subnetmask\]\] \[-T {on|off}\] \[--noshutdown\] TargetAccessID \
            \n \
            \n\t-A\tReturn all adapters of the given type \
            \n\t-C\tClient IP address \
            \n\t-D\tPerform ping test, use adapter that successfully ping the server \
            \n\t-E\tSet environment variable setting \
            \n\t-F\tPassword_file of hardware control point \
            \n\t-G\tGateway IP address \
            \n\t-J\tHostname of Hardware control point \
            \n\t-K\tSubnetmask IP address \
            \n\t-M\tDiscovery ethernet adapter mac address and location code \
            \n\t-S\tServer IP address \
            \n\t-T\tEnable or disble spanning tree \
            \n\t-d\tNetwork adapter duplex (auto|full|half) \
            \n\t-g\tGeneric arguments for booting \
            \n\t-i\tForce immediate shutdown. If lpar_netboot power off node failed, please try this option. \
            \n\t-j\tHardware control point type (ivm|hmc|bcmm) \
            \n\t-l\tPhysical location code \
            \n\t-m\tMAC Address \
            \n\t-n\tDo not boot partition \
            \n\t-p\tPassword of hardware control point \
            \n\t-s\tNetwork adapter speed (auto|10|100|1000) \
            \n\t-t\tSpecifies network type ent \
            \n\t-v\tVerbose output \
            \n\t-x\tDebug output \
            \n\t--noshutdown\tDo not power off the server after getting the adapter mac \
            \n\t--help\tPrints this help\n' \
            \"$PROGRAM\" \"$PROGRAM\" \"$PROGRAM\" \"$PROGRAM\" 2>/dev/null"
    } else {
        write_message "$DSPMSG -s 1 $CATALOG 114 \
           'Usage: Install partition \
            \n\t%s \[-v\] \[-x\] \[-f\] \[-i\] \[-g args\] \[-E environment \[-E ...\]\] \[-T {on|off}\] \[-A -D | \[-D\] -l phys_loc | \[-D\] -m macaddress\] \
            \n\t\t-t ent -s speed -d duplex -S server -G gateway -C client \[-K subnetmask\] partition_name profile managed_system \
            \n \
            \nUsage: Install for system supporting full system partition \
            \n\t%s \[-v\] \[-x\] \[-f\] \[-i\] \[-g args\] \[-E environment \[-E ...\]\] \[-T {on|off}\] \[-A -D | \[-D\] -l phys_loc | \[-D\] -m macaddress\] \
            \n\t\t-t ent -s speed -d duplex -S server -G gateway -C client \[-K subnetmask\] managed_system managed_system \
            \n \
            \nUsage: Return macaddress \
            \n\t%s -M -n \[-v\] \[-x\] \[-f\] \[-i\] \[-E environment \[-E ...\]\] \[-A\] -t ent \[-T {on|off}\] \[-D -s speed -d duplex -S server -G gateway -C client \[-K subnetmask\]\] \
            \n\t\tpartition_name profile managed_system \
            \n \
            \nUsage: Return macaddress for system supporting full system partition \
            \n\t%s -M -n \[-v\] \[-x\] \[-f\] \[-i\] \[-E environment \[-E ...\]\] -t ent \[-T {on|off}\] \[-D -s speed -d duplex -S server -G gateway -C client \[-K subnetmask\]\] \
            \n\t\tmanaged_system managed_system \
            \n \
            \n\t-A\tReturn all adapters of the given type \
            \n\t-C\tClient IP address \
            \n\t-D\tPerform ping test, use adapter that successfully ping the server \
            \n\t-E\tSet environment variable setting \
            \n\t-G\tGateway IP address \
            \n\t-K\tSubnetmask IP address \
            \n\t-M\tDiscovery ethernet adapter mac address and location code \
            \n\t-S\tServer IP address \
            \n\t-T\tEnable or disble spanning tree \
            \n\t-d\tNetwork adapter duplex \
            \n\t-f\tForce close virtual terminal session \
            \n\t-g\tGeneric arguments for booting \
            \n\t-i\tForce immediate shutdown \
            \n\t-l\tPhysical location code \
            \n\t-m\tMAC Address \
            \n\t-n\tDo not boot partition \
            \n\t-s\tNetwork adapter speed \
            \n\t-t\tSpecifies network type ent \
            \n\t-v\tVerbose output \
            \n\t-x\tDebug output \
            \n\t--help\tPrints this help\n' \
            \"$PROGRAM\" \"$PROGRAM\" \"$PROGRAM\" \"$PROGRAM\" 2>/dev/null"
    }
    exit 1
}

#
# PROCEDURE
#
# Check command line arguments
#
proc ck_args {} {
    global adap_speed
    global adap_duplex
    global client_ip
    global server_ip
    global gateway_ip
    global node
    global manage
    global profile
    global DSPMSG
    global CATALOG
    global PROGRAM
    global signal
    global discover_macaddr
    global extra_args
    global macaddress
    global phys_loc
    global discover_all
    global discovery
    global noboot
    global dev_type_found
    global spanning
    global CTRLTYPE
    global rmvterm_flag
    global ctrlpoint_type
    global username
    global password
    global password_file

    nc_msg "$PROGRAM Status: ck_args start\n"
    if { $discovery && ( $adap_speed == "" || $adap_duplex == "" ) } {
        write_message "$DSPMSG -s 1 $CATALOG 02 '%s: speed and duplex required\n' \"$PROGRAM\" 2>/dev/null"
        usage 
    }

    if { $discovery && $client_ip == "" } {
        write_message "$DSPMSG -s 1 $CATALOG 03 '%s: client IP is required\n' \"$PROGRAM\" 2>/dev/null"
        usage
    }

    if { $discovery && $server_ip == "" } { 
        write_message "$DSPMSG -s 1 $CATALOG 04 '%s: server IP is required\n' \"$PROGRAM\" 2>/dev/null"
        usage
    }

    if { $discovery && $gateway_ip == "" } {
        write_message "$DSPMSG -s 1 $CATALOG 05 '%s: gateway IP is required\n' \"$PROGRAM\" 2>/dev/null"
        usage
    }
    
    if { $ctrlpoint_type == "ivm" || $ctrlpoint_type == "hmc" } {
        if { $node == "" } {
            write_message "$DSPMSG -s 1 $CATALOG 111 '%s: lpar_id is required\n' \"$PROGRAM\" 2>/dev/null"
            usage
        } else {
            nc_msg "$PROGRAM Status: node $node\n"
        }
    }

    if { $ctrlpoint_type == "bcmm" } {
        if { $node == "" } {
            write_message "$DSPMSG -s 1 $CATALOG 112 '%s: TargetAccessID is required\n' \"$PROGRAM\" 2>/dev/null"
            usage
        } else {
            nc_msg "$PROGRAM Status: node $node\n"
        }
    }
    
    if { $ctrlpoint_type == "hmc" } {
        if { $manage == "" } {
            write_message "$DSPMSG -s 1 $CATALOG 110 '%s: TargetHWTypeModel is required\n' \"$PROGRAM\" 2>/dev/null"
            usage
        } else {
            nc_msg "$PROGRAM Status: managed system $manage\n"
        }
    }
    
    if { ![string compare $CTRLTYPE "AIX"] } {

        #check user:password
        if { $username == "" && $password_file == ""} {
            write_message "$DSPMSG -s 1 $CATALOG 111 '%s: username or password_file is required\n' \"$PROGRAM\" 2>/dev/null"
            usage
        } elseif { $username != "" && $password == "" } {
            write_message "$DSPMSG -s 1 $CATALOG 112 '%s: password is required\n' \"$PROGRAM\" 2>/dev/null"
            usage
        } else {
            nc_msg "$PROGRAM Status: username $username\n"
            nc_msg "$PROGRAM Status: password_file $password_file\n"
            nc_msg "$PROGRAM Status: password $password\n"
        }
    }

    if { $discover_macaddr && $extra_args != "" } {
        write_message "$DSPMSG -s 1 $CATALOG 62 '%s: can not specify -M and -g flags together.\n' \"$PROGRAM\" 2>/dev/null"
        usage
    }

    if { $discover_macaddr && ( $macaddress != "" || $phys_loc != "" ) } {
        write_message "$DSPMSG -s 1 $CATALOG 64 '%s: can not specify -M and -l or -m flags together.\n' \"$PROGRAM\" 2>/dev/null"
        usage
    }

    if { $macaddress != "" && $phys_loc != "" } {
        write_message "$DSPMSG -s 1 $CATALOG 65 '%s: can not specify -l and -m flags together.\n' \"$PROGRAM\" 2>/dev/null"
        usage
    }

    if { $discover_all && ( $macaddress != "" || $phys_loc != "" ) } {
        write_message "$DSPMSG -s 1 $CATALOG 66 '%s: can not specify -A and -m or -l flags together.\n' \"$PROGRAM\" 2>/dev/null"
        usage
    }
   
    if { $discover_all && !$discovery && !$noboot } {
        write_message "$DSPMSG -s 1 $CATALOG 67 '%s: flag -A must be Specify with flag -D for booting.\n' \"$PROGRAM\" 2>/dev/null"
        usage
    }

    if { $discover_macaddr && $discovery && 
         ( $server_ip == "" || $gateway_ip == "" || $client_ip == "" || $adap_speed == "" || $adap_duplex == "" ) } {
        write_message "$DSPMSG -s 1 $CATALOG 68 '%s: flag -M with -D require arguments for -C, -S, -G, -s and -d.\n' \"$PROGRAM\" 2>/dev/null"
        usage
    }
   
    if { $discover_macaddr && !$discovery && 
         ( $server_ip != "" || $gateway_ip != "" || $client_ip != "" || $adap_speed != "" || $adap_duplex != "" ) } {
        write_message "$DSPMSG -s 1 $CATALOG 69 '%s: flag -M with arguments for -C, -S, -G, -s and -d require -D flag.\n' \"$PROGRAM\" 2>/dev/null"
        usage
    }

    if { $discover_macaddr && !$noboot } {
        write_message "$DSPMSG -s 1 $CATALOG 70 '%s: -M flag requires -n.\n' \"$PROGRAM\" 2>/dev/null"
        usage
    }

    if { !$dev_type_found } {
        write_message "$DSPMSG -s 1 $CATALOG 80 '%s: -t flag required.\n' \"$PROGRAM\" 2>/dev/null"
        usage
    }

    if { $spanning != "" && $spanning != "on" && $spanning != "off" } {
        write_message "$DSPMSG -s 1 $CATALOG 81 '%s: -T flag only accepts the \"on\" or \"off\" values.\n' \"$PROGRAM\" 2>/dev/null"
        usage
    }
}

#
# 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.
#
proc send_command {} {

    global command 
    global spawn_id_rconsole
    global LOGFILE
    global PROGRAM
    global DSPMSG
    global CATALOG
    global signal

    # sleep so that any error messages from previous command are cleared up
    nc_msg "send_command start:$command\n"
    exec sleep 1
    send -i $spawn_id_rconsole -- $command
    if { $LOGFILE != "" } {
        puts $LOGFILE $command
    }
}

#
# PROCEDURE
#
proc poweroff-on {} {

    global spawn_id_rconsole
    global expect_out
    global rc
    global command
    global DSPMSG
    global CATALOG
    global PROGRAM
    global HMCNAME
    global BINPATH
    global manage
    global node
    global profile
    global msg

    #
    # power off the node
    #
    write_message "$DSPMSG -s 1 $CATALOG 41 '# Power off the node.\n' 2>/dev/null"

    set rc [catch {eval exec $BINPATH/chsysstate -r lpar -o shutdown -m \"$manage\" --immed -n \"$node\"} msg]

    if { $rc } {
        write_message "$DSPMSG -s 1 $CATALOG 42 '%s: cannot power off %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
        nc_msg "$PROGRAM Status: error from chsysstate command\n"
        write_message "$DSPMSG -s 1 $CATALOG 39 '%s: Error : %s\n' \"$PROGRAM\" \"$msg\" 2>/dev/null"
        exit 1
    }

    write_message "$DSPMSG -s 1 $CATALOG 43 '# Wait for power off.\n' 2>/dev/null"

    #
    # chsysstate will return a successful result if it was able to pass the power
    # command from the HMC to the node, but the node may not be powered off yet.  Need
    # to query to make sure the node is off before we continue
    #
    set done 0
    set query_count 0
    set timeout 60
    set timeout [change_timeout $timeout]
    while { ! $done } {
        if { $query_count > $timeout } {
            write_message "$DSPMSG -s 1 $CATALOG 45 '%s: Timed out waiting for power off of %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
            nc_msg "$PROGRAM Status: error from lssyscfg command : \"$msg\"\n"
            exit 1
        }

        run_lssyscfg

        #
        # separate the nodename from the query status
        #
        if { ([string compare "$msg" "Off"] == 0) || ([string compare "$msg" "Not Activated"] == 0) } {
            write_message "$DSPMSG -s 1 $CATALOG 40 '# Power off complete.\n' 2>/dev/null"
            set done 1
        }

        incr query_count

        sleep 1
    }

    write_message "$DSPMSG -s 1 $CATALOG 46 '# Power on %s to Open Firmware.\n' \"$HMCNAME\" 2>/dev/null"
    set rc [catch {eval exec $BINPATH/chsysstate -r lpar -o on -b of -m \"$manage\" -n \"$node\" -f \"$profile\"} msg]

    nc_msg "$PROGRAM Status: wait for power on\n"

    if { $rc } {
        write_message "$DSPMSG -s 1 $CATALOG 47 '%s: cannot power on %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
        nc_msg "$PROGRAM Status: error from chsysstate command\n"
        write_message "$DSPMSG -s 1 $CATALOG 39 '%s: Error : %s\n' \"$PROGRAM\" \"$msg\" 2>/dev/null"
        exit 1
    }

    #
    # Verify node is powered on before continuing
    #
    set done 0
    set query_count 0
    set timeout 600
    set timeout [change_timeout $timeout]

    while { ! $done } {
        if { $query_count > $timeout } {
            write_message "$DSPMSG -s 1 $CATALOG 49 '%s: Timed out waiting for power on of %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
            nc_msg "$PROGRAM Status: error from lssyscfg command : \"$msg\" \n"
            exit 1
        }

        run_lssyscfg

        #
        # separate the nodename from the query status
        #
        if { ([string compare "$msg" "Open Firmware"] == 0) || ([string compare "$msg" "Open firmware"] == 0) } {
            write_message "$DSPMSG -s 1 $CATALOG 48 '# Power on complete.\n' 2>/dev/null"
            set done 1
            continue
        }
        incr query_count

        sleep 1
    }

    set done 0
    set timeout 200
    set timeout [change_timeout $timeout]
    nc_msg "$PROGRAM Status: Check for active console.\n"
    while { ! $done } {
        expect {
            -i $spawn_id_rconsole
            -re "(.*)\[SCSI|scsi\](.*)0 >" {
                write_log $expect_out(buffer)
                nc_msg "$PROGRAM Status: active console\n"
                set done 1
            }
            -re "PowerPC Firmware(.*)SMS(.*)" {
                write_log $expect_out(buffer)
                nc_msg "$PROGRAM Status: SMS active console\n"
                set done 1
            }
            -re "To select this console as the active console press 0" {
                write_log $expect_out(buffer)
                nc_msg "$PROGRAM Status: selecting active console\n"
                exec sleep 1
                set command "0"
                send_command
            }
            -re "Press 0 to select this console.*as the active console" {
                write_log $expect_out(buffer)
                nc_msg "$PROGRAM Status: selecting active console\n"
                exec sleep 1
                set command "0"
                send_command
            }
            -re "(.*)elect this consol(.*)" {
                write_log $expect_out(buffer)
                nc_msg "$PROGRAM Status: selecting active console\n"
                exec sleep 1
                set command "0"
                send_command
            }
            timeout {
                nc_msg "$PROGRAM Status: timeout in main checking for active console with timeout value : $timeout\n"
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 50 '%s: timeout; exiting\n' \"$PROGRAM\" 2>/dev/null"
                exit 1
            }
            eof {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 11 '%s: cannot connect to %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
                exit 1
            }
        }
    }

    return 0
}

#
# 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.
# 
proc get_phandle {} {

    global spawn_id_rconsole
    global expect_out
    global phandle_array
    global full_path_name_array
    global rc
    global command
    global adapter_found
    global adap_type
    global dev_count
    global dev_pat
    global dev_type
    global DSPMSG
    global CATALOG
    global PROGRAM
    global signal
    global DSPMSG
    global HMCNAME

    nc_msg "$PROGRAM Status: get_phandle start\n"
    nc_msg "$PROGRAM Status: Starting to get full device name and phandle\n"

    # 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. 
    #
    set timeout 60     ;# shouldn't take long
    set timeout [change_timeout $timeout]
 
    nc_msg "$PROGRAM Status: sending dev / command\n"
    set command  "dev /\r"
    send_command
    expect {
        -i $spawn_id_rconsole
        -re ">(.*)" {
            write_log $expect_out(buffer)
            nc_msg "$PROGRAM Status: at root\n"
        }
        -re "]" {
            write_log $expect_out(buffer)
            write_message "$DSPMSG -s 1 $CATALOG 09 '%s: unexpected prompt\n' \"$PROGRAM\" 2>/dev/null"
            
            set rc 1
            return
        }
        timeout {
            nc_msg "$PROGRAM Status: timeout in get_phandle with timeout value : $timeout\n"
            write_log $expect_out(buffer)
            write_message "$DSPMSG -s 1 $CATALOG 10 '%s: timeout\n' \"$PROGRAM\" 2>/dev/null"
            set rc 1
            return
        }
        eof {
            write_log $expect_out(buffer)
            write_message "$DSPMSG -s 1 $CATALOG 11 '%s : cannot connect to %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
            set rc 1
            return
        }
    }

    # 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.  
    #
    nc_msg "$PROGRAM Status: sending ls command\n"
    set command  "ls\r"   
    send_command

    set adapter_found 0
    set done 0

    set timeout 60     ;# shouldn't take more than a few minutes
    set timeout [change_timeout $timeout]

    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.
        #  
        expect {
            -i $spawn_id_rconsole
            -re "unknown word" {
                # This error indicates that some characters may have been
                # lost on the serial console line.
                #
                nc_msg "$PROGRAM Status: error sending open firmware command\n"
                write_message "$DSPMSG -s 1 $CATALOG 94 '%s : Error sending open firmware command\n' \"$PROGRAM\" 2>/dev/null"
                if { $retry_count < 5 } {
                    nc_msg "$PROGRAM Status: retry count is $retry_count\n"
                    incr retry_count 1
                    send_command
                    continue
                } else {
                    nc_msg "$PROGRAM Status: retry count exceeded\n"
                    write_message "$DSPMSG -s 1 $CATALOG 95 '%s : retry count exceeded\n' \"$PROGRAM\" 2>/dev/null"
                    clean_exit 1
                }
            }
            -re "(\n)(\[^\r]*)(\r)" {
                write_log $expect_out(buffer)
                if { [regexp "\n(\[^\r]*):(\[ ]+)/(\[^\r]*)\r" $expect_out(0,string) x1 x2 x3 x4] } {

                    # Each level is inspected for a match
                    set level [expr ([string length $x3]-1)/2]
                    set path($level) $x4
                    for {set j 0} {$j < $dev_count} {incr j 1} {
                        if {[regexp $dev_pat($j) $x4]} {
                            incr adapter_found 1
                            for {set i 0} {$i <= $level} {incr i 1} {
                                append full_path_name_array($adapter_found) "/$path($i)"
                            }
                            set phandle_array($adapter_found) $x2
                            set adap_type($adapter_found) $dev_type($j) 
                            break
                        }
                    }
                }
            } 
            -re "dev /  ok\r\n0 >" {
                continue
            }
            -re "> $" {
                write_log $expect_out(buffer)
                set done 1
            }
            timeout {
                nc_msg "$PROGRAM Status: timeout in get_phandle with timeout value : $timeout\n"
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 12 '%s : timeout isolating single line of ls output\n' \"$PROGRAM\" 2>/dev/null"
                set rc 1
                return
            }
            eof {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 11 '%s : cannot connect to %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
                set rc 1
                return
            }
        }
    }
    # Did we find one or more adapters?
    if { $adapter_found > 0 } {
        set rc 0
    } else {
        write_message "$DSPMSG -s 1 $CATALOG 13 '%s : No network adapters found\n' \"$PROGRAM\" 2>/dev/null"
        set rc -1
    }
}


#
# 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.
#

proc get_adap_prop { phandle } {

    global rc
    global spawn_id_rconsole
    global expect_out
    global command
    global adap_prop_list
    global DSPMSG
    global CATALOG
    global PROGRAM
    global signal
    global HMCNAME

    nc_msg "$PROGRAM Status : get_adap_prop start\n"
    set adap_prop_list {}
    set rc 0
    set timeout 60
    set timeout [change_timeout $timeout]

    set state 0
    nc_msg "$PROGRAM Status: get_adap_prop start\n"

    # state 0, stack count 0
    set done(0) 0
    set cmd(0) "\" supported-network-types\" $phandle get-package-property\r"
    set msg(0) "$PROGRAM Status: rc and all supported network types now on stack\n"
    set pattern(0) "(.*)3 >(.*)"
    set newstate(0) 1

    # state 1, return code and string on stack
    set done(1) 0
    set cmd(1) ".\r"
    set msg(1) "$PROGRAM Status: All supported network types now on stack\n"
    set pattern(1) "(.*)2 >(.*)"
    set newstate(1) 2

    # state 2, data ready to decode
    set done(2) 0
    set cmd(2) "decode-string\r"
    set msg(2) "$PROGRAM Status: supported network type isolated on stack\n"
    set pattern(2) "(.*)ok(.*)4 >(.*)"
    set newstate(2) 3

    # state 3, decoded string on stack
    set done(3) 0
    set cmd(3) "dump\r"
    set msg(3) "$PROGRAM Status: supported network type off stack\n"
    set pattern(3) ".*:.*:(.*):.*:.*:(.*):.*(2 >)(.*)"
    set newstate(3) 4

    # state 4, need to check for more data to decode
    set done(4) 0
    set cmd(4) ".s\r"
    set msg(4) "$PROGRAM Status: checking for more supported network types\n"
    set pattern(4) ".s (\[0-9a-f]* )(.*)>"
    set newstate(4) 5

    # state 5, done decoding string, clear stack
    set done(5) 0
    set cmd(5) ".\r"
    set msg(5) "$PROGRAM Status: one entry on stack cleared\n"
    set pattern(5) "(.*)ok(.*)1 >(.*)"
    set newstate(5) 6

    # state 6, finish clearing stack, choose correct adapter type
    set done(6) 0
    set cmd(6) ".\r"
    set msg(6) "$PROGRAM Status: finished clearing stack\n"
    set pattern(6) "(.*)ok(.*)0 >(.*)"
    set newstate(6) 7

    # state 7, done
    set done(7) 1

    while { $done($state) == 0 } {
        nc_msg "$PROGRAM Status: command is $cmd($state)\n"
        set command $cmd($state)
        send_command
        expect {
            -i $spawn_id_rconsole
            -re $pattern($state) {
                write_log $expect_out(buffer)
                nc_msg $msg($state)
                set state $newstate($state)

                # 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 == 4 } {
                    set nw_type $expect_out(1,string)$expect_out(2,string)

                    #  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 "$PROGRAM Status: Adapter properties are $adap_prop\n"

                    # if it's not in the list, add it, otherwise continue
                    if { [ lsearch adap_prop_list $adap_prop ] == -1 } {
                        lappend adap_prop_list $adap_prop
                        nc_msg "$PROGRAM 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 == 5 } {
                    if { [ string index $expect_out(2,string) 0] != 0 } {
                        set state 2
                   }
                }

            }
            -re "]" {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 09 '%s: unexpected prompt\n' \"$PROGRAM\" 2>/dev/null"
                set rc 1
                return
            }
            -re "(.*)DEFAULT(.*)" {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 14 '%s: default catch error\n' \"$PROGRAM\" 2>/dev/null"
                set rc 1
                return
            }
            timeout {
                nc_msg "$PROGRAM Status: timeout in get_adap_prop with timeout value : $timeout\n"
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 10 '%s: timeout\n' \"$PROGRAM\" 2>/dev/null"
                nc_msg "timeout state is $state\n"
                set rc 1
                return
            }
            eof {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 11 '%s: cannot connect to %s' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
                set rc 1
                return
            }
        }
    }
    set rc 0
    return
}

#
# 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. 

proc get_mac_addr { phandle } {

    global rc
    global spawn_id_rconsole
    global expect_out
    global command     
    global DSPMSG
    global CATALOG
    global PROGRAM
    global signal
    global HMCNAME

    set rc 0
    nc_msg "$PROGRAM 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
    set done(0) 0
    set cmd(0) "\" local-mac-address\" $phandle get-package-property\r"
    set msg(0) "$PROGRAM Status: return code and mac-address now on stack\n"
    set pattern(0) "(.*)3 >(.*)"
    set 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
    set done(1) 0
    set cmd(1) ".\r"
    set msg(1) "$PROGRAM Status: mac-address now on stack\n"
    set pattern(1) "(.*)2 >(.*)"
    set 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
    set done(2) 0
    set cmd(2) "dump\r"
    set msg(2) "$PROGRAM Status: mac-address displayed, stack empty\n"
    set pattern(2) "(.*)(: )(.*)( :)(.*)(: ok)"
    set newstate(2) 3

    # state 3, all done
    set done(3) 1

    set state 0
    set timeout 60     ;# shouldn't take long
    set timeout [change_timeout $timeout]

    while { $done($state) == 0 } {
        nc_msg "$PROGRAM Status: command is $cmd($state)\n"
        set command $cmd($state)
        send_command
        expect {
            -i $spawn_id_rconsole
            -re $pattern($state) {
                write_log $expect_out(buffer)
                nc_msg $msg($state)  
                set state $newstate($state)
            }
            "1 > " {
                write_log $expect_out(buffer)
                if { $state == 0 } {
                    # An error occurred while obtaining the mac address.  Log the error,
                    # but don't quit lpar_netboot.  instead, return NA for the address
                    #
                    set command ".\r"
                    send_command
                    expect {
                        -i $spawn_id_rconsole
                        -re "(-*\[0-9\]*)  ok(.*)0 >(.*)" {
                            write_log $expect_out(buffer)
                            set mac_rc $expect_out(1,string)
                            nc_msg "$PROGRAM Status: Error getting MAC address for phandle=$phandle. RC=$mac_rc.\n"
                            write_message "$DSPMSG -s 1 $CATALOG 15 '# Could not obtain MAC address; setting MAC to \"NA\"\n' 2>/dev/null" 
                            set rc 0
                            set mac_address "NA"
                            return $mac_address
                        }
                        timeout {
                            write_log $expect_out(buffer)
                            write_message "$DSPMSG -s 1 $CATALOG 10 '%s: timeout\n' \"$PROGRAM\" 2>/dev/null"
                            nc_msg "timeout state is $state\n"
                            set rc 1
                            return
                        }
                        eof {
                            write_log $expect_out(buffer)
                            write_message "$DSPMSG -s 1 $CATALOG 11 '%s: cannot connect to %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
                            set rc 1
                            return
                        }
                    }
                }
            }
            -re "]" {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 09 '%s: unexpected prompt\n' \"$PROGRAM\" 2>/dev/null"
                set rc 1
                return
            }
            -re "(.*)DEFAULT(.*)" {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 14 '%s: default catch error\n' \"$PROGRAM\" 2>/dev/null"
                set rc 1
                return
            }
            timeout {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 10 '%s: timeout\n' \"$PROGRAM\" 2>/dev/null"
                nc_msg "timeout state is $state\n"
                set rc 1
                return
            }
            eof {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 11 '%s: cannot connect to %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
                set rc 1
                return
            }
        }
    }
    # if the state is 0, 1, or 2, an error occurred and the join will fail
    if { $state == 3 } {
        set mac_address [ join $expect_out(3,string) "" ]
        set rc 0
        return $mac_address
    } else {
        set rc -1
    }
}

#
# 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. 

proc get_adaptr_loc { phandle } {

    global rc
    global spawn_id_rconsole
    global expect_out
    global command     
    global DSPMSG
    global CATALOG
    global PROGRAM
    global signal
    global HMCNAME
    global list_disk

    set rc 0
    nc_msg "$PROGRAM 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
    set done(0) 0
    set cmd(0) "\" ibm,loc-code\" $phandle get-package-property\r"
    set msg(0) "$PROGRAM Status: return code and loc-code now on stack\n"
    set pattern(0) "(.*)3 >(.*)"
    set 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
    set done(1) 0
    set cmd(1) ".\r"
    set msg(1) "$PROGRAM Status: loc-code now on stack\n"
    set pattern(1) "(.*)2 >(.*)"
    set newstate(1) 2

    # state 2, loc-code on stack
    set done(2) 0
    set cmd(2) "dump\r"
    set msg(2) "$PROGRAM Status: loc-code displayed, stack empty\n"
    set pattern(2) "(.*)(: )(.*)( :)(.*)(\.: ok)"
    set newstate(2) 3

    # state 3, all done
    set done(3) 1

    set state 0
    set timeout 60    ;# shouldn't take long
    set timeout [change_timeout $timeout]

    while { $done($state) == 0 } {
        nc_msg "$PROGRAM Status: command is $cmd($state)\n"
        set command $cmd($state)
        send_command
        expect {
            -i $spawn_id_rconsole
            -re $pattern($state) {
                write_log $expect_out(buffer)
                nc_msg $msg($state)  
                set state $newstate($state)
            }
            "1 > " {
                write_log $expect_out(buffer)
                if { $state == 0 } {
                    set command ".\r"
                    send_command
                    expect {
                        -i $spawn_id_rconsole
                        -re "(-*\[0-9\]*)  ok(.*)0 >(.*)" {
                            write_log $expect_out(buffer)
                            set loc_rc $expect_out(1,string)
                            if { $list_disk != 1 } {
                                write_message "$DSPMSG -s 1 $CATALOG 16 '%s: Error getting adapter physical location.\n' \"$PROGRAM\" 2>/dev/null"
                            }
                            nc_msg "$PROGRAM Status: Error getting physical location for phandle=$phandle. RC=$loc_rc.\n"
                            set rc 1
                            return
                        }
                        timeout { 
                            nc_msg "$PROGRAM Status: timeout in get_adaptr_loc with timeout value : $timeout\n"
                            write_log $expect_out(buffer)
                            write_message "$DSPMSG -s 1 $CATALOG 10 '%s: timeout\n' \"$PROGRAM\" 2>/dev/null"
                            set rc 1
                            return
                        }
                        eof {
                            write_log $expect_out(buffer)
                            write_message "$DSPMSG -s 1 $CATALOG 11 '%s: cannot connect to %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
                            set rc 1
                            return
                        }
                    }
                }
            }
            -re "]" {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 09 '%s: unexpected prompt\n' \"$PROGRAM\" 2>/dev/null"
                set rc 1
                return
            }
            -re "(.*)DEFAULT(.*)" {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 14 '%s: default catch error\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
                set rc 1
                return
            }
            timeout {
                nc_msg "$PROGRAM Status: timeout in get_adaptr_loc with timeout value : $timeout\n"
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 10 '%s: timeout\n' \"$PROGRAM\" 2>/dev/null"
                nc_msg "$PROGRAM Status: timeout state is $state\n"
                set rc 1
                return
            }
            eof {
                write_message "$DSPMSG -s 1 $CATALOG 11 '%s: cannot connect to %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
                set rc 1
                return
            }
        }
    }
    if { $state == 3 } {
        set rc 0
        if { [regexp "(.*)(: )(.*)( :)(.*)(:)" $expect_out(1,string) v1 v2 v3 v4 v5 v6 ] } {
            return $v6$expect_out(5,string)
        } else {
            return $expect_out(5,string)
        }
    } else {
        set rc -1
    }
}

#
# PROCEDURE
#
# Declare procedure to ping the given server through the specified LAN adapter.
# The procedure will return 0 if the ping is successful, and 1 if the ping
# was unsuccessful.  The global rc variable will be set if there's an error.
#

proc ping_server { full_path_name phandle } {

    global spawn_id_rconsole
    global expect_out
    global server_ip
    global client_ip
    global gateway_ip
    global subnetmask_ip
    global list_type
    global list_disk
    global adap_speed
    global adap_duplex
    global command
    global adap_prop_list
    global rc
    global DSPMSG
    global CATALOG
    global PROGRAM
    global DSPMSG
    global signal
    global HMCNAME
    global env

    nc_msg "$PROGRAM Status: ping_server start\n"
    nc_msg "$PROGRAM Status: full_path_name : $full_path_name\n"
    nc_msg "$PROGRAM Status: phandle        : $phandle\n"

    if {[info exists env(FIRMWARE_DUMP)]} {
        Firmware_Dump $full_path_name $phandle
    }

    set j 0
    set tty_do_ping 0
    set stack_level 0
    set properties_matched 0
    set adap_conn ""
    set speed_list {}
    set duplex_list {}
    set adap_conn_list {}

    # 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
    set done(0) 0
    set cmd(0) "dev $full_path_name\r"
    set msg(0) "$PROGRAM Status: selected $full_path_name as the active adapter\n"
    set pattern(0) "(.*)0 >(.*)"
    set newstate(0) 1

    # state 1, send property command to set selected type
    set done(1) 0
    set cmd(1) "\" ethernet,$adap_speed,$adap_conn,$adap_duplex\" encode-string \" chosen-network-type\" property\r"
    set msg(1) "$PROGRAM Status: chosen network type set\n"
    set pattern(1) "(.*)0 >(.*)"
    set newstate(1) 2

    # state 2, activate /packages/net
    set done(2) 0
    set cmd(2) "dev /packages/net\r"
    set msg(2) "$PROGRAM Status: selected the /packages/net node as the active package\n"
    set pattern(2) "(.*)ok(.*)0 >(.*)"
    set newstate(2) 3

    # state 3, ping the server
    set done(3) 0
    set msg(3) "$PROGRAM Status: ping return code now on stack\n"
    set newstate(3) 4
    if {$subnetmask_ip == ""} {
      set cmd(3) "ping $full_path_name:$server_ip,$client_ip,$gateway_ip\r"
    } else {
      set cmd(3) "ping $full_path_name:$server_ip,$client_ip,$gateway_ip,0,$subnetmask_ip\r"
    }
    set pattern(3) "(.*)ok(.*)0 >(.*)"

    # state 4, all done
    set done(4) 0
    set cmd(4) "0 to my-self\r"
    set msg(4) "$PROGRAM Status: resetting pointer\n"
    set pattern(4) "(.*)ok(.*)0 >(.*)"
    set newstate(4) 5
    
    # state 5, all done
    set done(5) 1

    # for ping, only need to set speed and duplex for ethernet adapters
    #
    if { $list_type == "ent" } {
        set state 0

        # Get the list of properties for this adapter
        #
        get_adap_prop $phandle
        if { $rc != 0 } {
            exit 1
        }

        if { [ llength $adap_prop_list ] == 0 } {
            write_message "$DSPMSG -s 1 $CATALOG 20 '%s: no properties found for adapter %s\n' \"$PROGRAM\" \"$full_path_name\" 2>/dev/null"
            set rc 0
            return 1
        }

        # Now need to verify that the network params we were passed are valid for
        # the given adapter
        #
        foreach prop $adap_prop_list {
            regexp (.*),(.*),(.*) $prop dummy a_speed a_conn a_duplex
            if { ( $a_speed == $adap_speed ) && ( $a_duplex == $adap_duplex ) } {
                set properties_matched 1
                if { [ lsearch $adap_conn_list $a_conn ] == -1 } {
                    lappend adap_conn_list $a_conn
                }
            }
        }

        set i [ llength $adap_conn_list ]

        if { $properties_matched == 0 } {
            write_message "$DSPMSG -s 1 $CATALOG 21 '%s: %s/%s settings are not supported on this adapter\n' \"$PROGRAM\" \"$adap_speed\" \"$adap_duplex\" 2>/dev/null"
            set rc 0
            return 1
        }
    } else {
        set state 2
    }

    set timeout 300
    set timeout [change_timeout $timeout]

    while { $done($state) == 0 } {
        nc_msg "$PROGRAM Status: command is $cmd($state)\n"
        set command $cmd($state)

        send_command

        expect {
            -i $spawn_id_rconsole
            -re $pattern($state) {
                write_log $expect_out(buffer)
                nc_msg $msg($state)
                set state $newstate($state)

                if { $state == 1 } {
                    set adap_conn [ lindex $adap_conn_list $j ]
                    set cmd(1) "\" ethernet,$adap_speed,$adap_conn,$adap_duplex\" encode-string \" chosen-network-type\" property\r"
                    nc_msg "$PROGRAM Status: Trying connector type $adap_conn\n"
                    incr j 1
                }

                if { ( ($tty_do_ping == 1) && ($state == 4) ) || ($tty_do_ping != 1) && ($state == 3) } {
                    set ping_debug $expect_out(buffer)
                }

                if { ( ($tty_do_ping == 1) && ($state == 5) ) || ($tty_do_ping != 1) && ($state == 4) } {
                    if { ($tty_do_ping == 1) && ($state == 5) } {
                        set ping_rc $expect_out(1,string)
                        set stack_level $expect_out(3,string)
                    } elseif { ($state == 4) && ($tty_do_ping != 1) && ([regexp "PING SUCCESS" $expect_out(buffer)]) } {
                        set ping_rc 0
                    } elseif { [regexp "unknown word" $expect_out(buffer)] } {
                        nc_msg "$PROGRAM Status: try tty-do-ping.\n"
                        set ping_rc 1
                        set tty_do_ping 1
                        set state 3 
                        set cmd(3) "\" $full_path_name:$client_ip,$server_ip,$gateway_ip\" tty-do-ping\r"
                        set pattern(3) "(.*)ok(.*)(\[1-2\]) >(.*)"
                                    
                        # state 4, get the return code off the stack
                        set done(4) 0
                        set cmd(4) ".\r"
                        set msg(4) "$PROGRAM Status: return code displayed, stack empty\n"
                        set pattern(4) "(\[0-9\]*)  ok(.*)(\[0-1\]) >(.*)"
                        set 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, reset pointer
                        set done(5) 0
                        set cmd(5) "0 to my-self\r"
                        set msg(5) "$PROGRAM Status: resetting pointer\n" 
                        set pattern(5) "(.*)ok(.*)0 >(.*)"
                        set newstate(5) 6 
                                
                        # state 6, all done
                        set done(6) 1
                    } else {
                        set ping_rc 1
                    }

                    if { $ping_rc == 0 } {
                        if { $list_disk != 1 } {
                            write_message "$DSPMSG -s 1 $CATALOG 74 '# %s ping successful.\n' \"$full_path_name\" 2>/dev/null"
                        }
                    } elseif { $ping_rc ==  1 } {
                        if { $list_disk != 1 } {
                            write_message "$DSPMSG -s 1 $CATALOG 75 '# %s ping unsuccessful\n' \"$full_path_name\" 2>/dev/null"
                        }
                        nc_msg "# $full_path_name ping unsuccessful.\n"
                        nc_msg "$ping_debug\n"

                        # An unsuccessful return may leave another item on the stack to
                        # be removed.  Check for it, and remove if necessary
                        while { $stack_level != 0 } {
                            set command ".\r"
                            send_command
                            expect {
                                -i $spawn_id_rconsole
                                -re "(\[0-9\]*)  ok(.*)(\[0-1\]) >(.*)" {
                                    write_log $expect_out(buffer)
                                    set stack_level $expect_out(3,string)
                                    nc_msg "$PROGRAM Status: stack_level is <$stack_level>\n"
                                }
                                -re "]" {
                                    write_log $expect_out(buffer)
                                    write_message "$DSPMSG -s 1 $CATALOG 09 '%s: unexpected prompt\n' \"$PROGRAM\" 2>/dev/null"
                                    set rc 1
                                    return
                                }
                                -re "(.*)DEFAULT(.*)" {
                                    write_log $expect_out(buffer)
                                    write_message "$DSPMSG -s 1 $CATALOG 14 '%s: default catch error\n' \"$PROGRAM\" 2>/dev/null"
                                    set 1
                                    return
                                }
                                timeout {
                                    nc_msg "$PROGRAM Status: timeout in ping_server with timeout value : $timeout\n"
                                    write_log $expect_out(buffer)
                                    write_message "$DSPMSG -s 1 $CATALOG 10 '%s: timeout\n' \"$PROGRAM\" 2>/dev/null"
                                    set 1
                                    return
                                }
                                eof {
                                    write_log $expect_out(buffer)
                                    write_message "$DSPMSG -s 1 $CATALOG 11 '%s: cannot connect to %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
                                    set 1
                                    return
                                }
                            }
                        }
                        # Check if there are any more adapter connector types
                        # to try
                        #
                        if { ( $list_type == "ent" ) && ( $j < $i ) } {
                            set adap_conn [ lindex $adap_conn_list $j ]
                            nc_msg "$PROGRAM Status: Trying connector type $adap_conn\n"
                            incr j 1

                            # 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.
                            #
                            set done(0) 0
                            set cmd(0) "0 to my-self\r"
                            set msg(0) "$PROGRAM Status: resetting pointer\n"
                            set pattern(0) "(.*)ok(.*)0 >(.*)"
                            set newstate(0) 1

                            set state 0
                        }
                    } else {
                        write_messagewrite_messagewrite_messagewrite_messagewrite_messagewrite_messagewrite_messagewrite_messagewrite_message "$DSPMSG -s 1 $CATALOG 24 '%s: unexpected ping return code\n' \"$PROGRAM\" 2>/dev/null"
                        set rc 1
                        return
                    }
                }
            }
            -re "]" {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 09 '%s: unexpected prompt\n' \"$PROGRAM\" 2>/dev/null"
                set rc 1
                return
            }
            -re "(.*)DEFAULT(.*)" {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 14 '%s: default catch error\n' \"$PROGRAM\" 2>/dev/null"
                set rc 1
                return
            }
            timeout {
                nc_msg "$PROGRAM Status: timeout in ping_server with timeout value : $timeout\n"
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 10 '%s: timeout\n' \"$PROGRAM\" 2>/dev/null"
                set rc 1
                return
            }
            eof {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 11 '%s: cannot connect to %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
                set rc 1
                return
            }
        }
    }
    set rc 0
    return $ping_rc
}

proc get_disk_info_sms {} {
    global rc
    global expect_out
    global spawn_id_rconsole
    global command
    global CATALOG 
    global DSPMSG
    global PROGRAM
    global signal
    global HMCNAME
    global phandle_array
    global full_path_name_array
    global adapter_found
    global adap_type
    global sms_dev_array_loc
    global sms_dev_array_name
    global sms_dev_array_os
    global sms_dev_array_os_ver
    global colon
    global list_physical

    nc_msg "$PROGRAM Status: get_disk_info_sms start\n"
    # state 0, get SMS screen
    set done(0) 0
    set command ""
    regexp "(\n)(\[ ])(\[0-9])(\[.])(\[ ]+)Select Boot Options(\r)" $expect_out(2,string) x0 x1 x2 command
    if {$command == ""} { set command "5" }
    set cmd(0) "$command\r"
    set msg(0) "$PROGRAM Status: sending return to repaint SMS screen\n"
    set pattern(0)  "(\n)(\[ ])(\[0-9])(\[.])(\[ ]+)Select Install(.*)Boot(.*)Device(\r)"
    set newstate(0) 1

    # state 1, get Select Boot Options
    set done(1) 0
    set msg(1) "$PROGRAM Status: Select Boot Options\n"
    set pattern(1) "(\n)(\[ ])(\[0-9])(\[.])(\[ ]+)Hard Drive(\r)"
    set newstate(1) 2
    
    # state 2, Select Install/Boot Device
    set done(2) 0
    set msg(2) "$PROGRAM Status: Select Install/Boot Device\n"
    set pattern(2) "(\n)(\[ ])(\[0-9])(\[.])(\[ ]+)List All Devices(\r)"
    set newstate(2) 3

    # state 3, List All Devices
    set done(3) 0
    set msg(3) "$PROGRAM Status: Hard Drive\n"
    set pattern(3) "Select Device(\r)"
    set newstate(3) 4

    # state 4, Getting Disk information
    set done(4) 0
    set cmd(4) "M"
    set msg(4) "$PROGRAM Status: Getting disk information.\n" 
    set pattern(4) "(.*)Navigation key(.*)"
    set newstate(4) 5

    # state 5, Get to SMS Main Menu
    set done(5) 0
    set cmd(5) "0\r"
    set msg(5) "$PROGRAM Status: Getting to SMS Main Menu.\n"
    set pattern(5) "(.*)Exit SMS(.*)Prompt?(.*)"
    set newstate(5) 6

    # state 6, Exiting SMS
    set done(6) 0
    set cmd(6) "Y"
    set msg(6) "$PROGRAM Status: Exiting SMS.\n"
    set pattern(6) "(.*)ok(.*)0 >(.*)"
    set newstate(6) 7

    # state 7, all done
    set done(7) 1

    set timeout 360
    set timeout [change_timeout $timeout]

    set state 0
    set sms_dev_count 0

    set dev_name ""
    set dev_size ""
    set dev_os ""
    set dev_os_ver ""
    set dev_loc ""

    while { $done($state) == 0 } {
        nc_msg "$PROGRAM Status: command is $cmd($state)\n"
        set command $cmd($state)
        send_command
        expect {
            -i $spawn_id_rconsole
            -re $pattern($state) {
                write_log $expect_out(buffer)
                if { $state == 3 } {
                    set statedone 0
                    incr sms_dev_count
                    set timeout2 360     ;# shouldn't take more than a few second
                    set timeout2 [change_timeout $timeout2]

		    while { ! $statedone } {
		        expect {  
		            -re "(\n)(\[^\r]*)(\r)" {
                                    write_log $expect_out(buffer)
				    if { [regexp "(\[0-9]+\.)(\[ ]+)(\[0-9|\-])(\[ ]+)(.*)" $expect_out(2,string) x0 x1 x2 x3 x4 x5] } { 
					set dev_name $x5
                                        if { [regexp "(.*) (.*) (.*) (.*) (.*) (\[(])(.*) (.*)(\[)])" $dev_name x0 x1 x2 x3 x4 x5 x6 x7 x8] } {
                                            set dev_name $x1
                                            set dev_size $x2
                                            set dev_os $x7
                                            set dev_os_ver $x8
					} else {
					    set dev_os ""
					    set dev_os_ver ""
					}
				    }

			            if { [regexp "loc=(.*)" $expect_out(2,string) x0 x1] } {
					set dev_loc $x1
					if { [regexp "(.*) (\[)])" $dev_loc x0 x1] } {
					    set dev_loc $x1
					}
				    } else {
				        set dev_loc ""
				    }

				    if { $dev_loc != "" } {
					set sms_dev_array_name($sms_dev_count) "$dev_name"
					set sms_dev_array_loc($sms_dev_count) "$dev_loc"
					set sms_dev_array_os($sms_dev_count) "$dev_os"
					set sms_dev_array_os_ver($sms_dev_count) "$dev_os_ver"
					
					incr sms_dev_count
				    }

				    if { [regexp "(.*)N = Next(.*)" $expect_out(2,string)] == 0 } {
                                       set command "N"
                                       send_command
                                       continue
				    }
		            }

			    -re "select Navigation key:" {
                                write_log $expect_out(buffer)
				set statedone 1
			    }

		            timeout2 { 
                                nc_msg "$PROGRAM Status: timeout in get_disk_info_sms with timeout value : $timeout2\n"
                                write_log $expect_out(buffer)
		                write_message "$DSPMSG -s 1 $CATALOG 12 '%s : timeout isolating single line of ls output\n' \"$PROGRAM\" 2>/dev/null"
		                set rc 1
		                return
		            }
		            eof {
                                write_log $expect_out(buffer)
		                write_message "$DSPMSG -s 1 $CATALOG 11 '%s : cannot connect to %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
		                set rc 1
		                return
		            }
		        }
		    } 
		}

                set state $newstate($state)
                if { ($state != 4) && ($state != 5) && ($state != 6) } {
			set cmd($state) "$expect_out(3,string)\r"
		}
            }
            timeout {
                nc_msg "$PROGRAM Status: timeout in get_disk_info_sms with timeout value : $timeout\n"
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 10 '%s: timeout\n' \"$PROGRAM\" 2>/dev/null"
                set rc 1
                return
            }
            eof {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 11 '%s : cannot connect to %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
                set rc 1
                return
            }
	}
    }
}

proc get_disk_info {} {
    global rc
    global expect_out
    global spawn_id_rconsole
    global command
    global CATALOG
    global DSPMSG
    global PROGRAM
    global signal
    global HMCNAME
    global phandle_array
    global full_path_name_array
    global adapter_found
    global adap_type
    global disk_count
    global disk_array_size
    global disk_array_loc
    global disk_array_path
    global disk_array_devtype
    global sms_dev_array_loc            
    global sms_dev_array_name
    global sms_dev_array_os
    global sms_dev_array_os_ver         
    global colon
    global list_physical

    nc_msg "$PROGRAM Status: get_disk_info start\n"

    nc_msg "$PROGRAM Status: sending dev /packages/gui command\n"
    set command  "dev /packages/gui\r"
    send_command
    expect {
        -i $spawn_id_rconsole 
        -re "(.*)ok(.*)0 >(.*)" {
            write_log $expect_out(buffer)
            nc_msg "$PROGRAM Status: at root\n"
        }
        -re "]" {
            write_log $expect_out(buffer)
            write_message "$DSPMSG -s 1 $CATALOG 09 '%s: unexpected prompt\n' \"$PROGRAM\" 2>/dev/null"
            set rc 1
            return
        } 
        timeout {
            nc_msg "$PROGRAM Status: timeout in get_disk_info with timeout value : $timeout\n"
            write_log $expect_out(buffer)
            write_message "$DSPMSG -s 1 $CATALOG 10 '%s: timeout\n' \"$PROGRAM\" 2>/dev/null"
            set rc 1
            return
        }
        eof {
            write_log $expect_out(buffer)
            write_message "$DSPMSG -s 1 $CATALOG 11 '%s : cannot connect to %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
            set rc 1
            return
        }
    }

    nc_msg "$PROGRAM Status: sending display_boot_devices #DISK command\n"
    set command "display_boot_devices #ALL\r"
    send_command 
    set done 0
    set timeout 60
    set timeout [change_timeout $timeout]

    set disk_count 1
    set rc 0

    while { ! $done } {
        expect {
            -i $spawn_id_rconsole
            -re "More(.*)" {
                nc_msg "\n$PROGRAM Status= more devices\n"
                set command "\r"
                send_command
                expect {
                    -i $spawn_id_rconsole
                    -re "(\[0-9]+\.) (.*) (\[0-9]+) MB Harddisk (.*)loc=(.*)\[)]" {
                        write_log $expect_out(buffer)
                        set disk_array_size($disk_count) "$expect_out(3,string)"
                        set disk_array_loc($disk_count)  [string trimright "$expect_out(5,string)"]
                        set disk_array_path($disk_count) ""
                        incr disk_count
                    }
                }
            }

            -re "(\n)(\[^\r]*)(\r)" {
                write_log $expect_out(buffer)
                if { [regexp "(.*) (\[0-9]+) MB Harddisk (.*)loc=(.*)\[)]" $expect_out(2,string) x0 x1 x2 x3 x4] } {
                    set disk_array_size($disk_count) "$x2"
                    set disk_array_loc($disk_count)  [string trimright "$x4"]
                    set disk_array_path($disk_count) ""
                    incr disk_count 
                }
            }

            -re "0 >" { 
                write_log $expect_out(buffer)
                nc_msg "$PROGRAM Status: at root\n"
                set done 1
            }
            timeout {
                nc_msg "$PROGRAM Status: timeout in get_disk_info with timeout value : $timeout\n"
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 10 '%s: timeout\n' \"$PROGRAM\" 2>/dev/null"
                set rc 1
                return
            }
            eof {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 11 '%s : cannot connect to %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
                set rc 1
                return
            }
        }
    }

    set disk_count [array size disk_array_path]    
    for {set i 1} {$i <= $disk_count} {incr i 1} {
        set phandle_count [array size phandle_array]
        for { set j 1 } { $j <= $phandle_count } { incr j 1 } {
            set loc_code [get_adaptr_loc $phandle_array($j)]
            if { [string first "$loc_code" "$disk_array_loc($i)"] != -1 } {
                set disk_array_path($i) $full_path_name_array($j)
                break
            }
        }

        if { [string first "vdevice" "$disk_array_path($i)"] != -1 } {
            set disk_array_devtype($i) "virtual"
        } else {
            set disk_array_devtype($i) "physical"
        }

        set disk_array_os($i) ""
        set disk_array_os_ver($i) ""

        set sms_dev_count [array size sms_dev_array_loc]
        for { set j 1 } { $j <= $sms_dev_count } { incr j 1 } {
            if { [string first "$sms_dev_array_loc($j)" "$disk_array_loc($i)"] != -1 } {
                 set disk_array_os($i) $sms_dev_array_os($j)
                 set disk_array_os_ver($i) $sms_dev_array_os_ver($j)
            }
        }

        if { $colon } {
                    write_send_user "disk\:$disk_array_loc($i)\:\:$disk_array_path($i)\:\:$disk_array_devtype($i)\:$disk_array_size($i)\:$disk_array_os($i)\:$disk_array_os_ver($i)\:\n"
        } else {
            write_send_user "disk $disk_array_loc($i) $disk_array_path($i) $disk_array_devtype($i) $disk_array_size($i) $disk_array_os($i) $disk_array_os_ver($i)\n"
        }
    }
}

#
# 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.   
#

proc toggle_spanning_tree { location spanning } {

    global rc
    global spawn_id_rconsole
    global expect_out
    global command   
    global DSPMSG     
    global CATALOG
    global PROGRAM
    global signal
    global HMCNAME

    nc_msg "$PROGRAM Status: toggle_spanning_tree start\n"
    nc_msg "$PROGRAM Status: location : $location\n"
    nc_msg "$PROGRAM Status: state    : $spanning\n"
    set rc 0

    if { $spanning == "on" } {
        set spanning 1
        nc_msg "$PROGRAM Status: set spanning to enable\n"
    } elseif { $spanning == "off" } {
        set spanning 0
        nc_msg "$PROGRAM Status: set spanning to disable\n"
    } else {
        nc_msg "$PROGRAM Status: Spanning value not set correctly. Valid on/off\n"
        set rc 1
        return
    }

    set timeout 120     ;# shouldn't take long
    set timeout [change_timeout $timeout]

    nc_msg "$PROGRAM Status: sending dev /packages/gui command\n"
    set command  "dev /packages/gui\r"
    send_command
    expect {
        -i $spawn_id_rconsole
        -re "(.*)ok(.*)(\[0-9]) >(.*)" {
            write_log $expect_out(buffer)
            nc_msg "$PROGRAM Status: in /packages/gui\n"
        }
        -re "]" {
            write_log $expect_out(buffer)
            write_message "$DSPMSG -s 1 $CATALOG 09 '%s: unexpected prompt\n' \"$PROGRAM\" 2>/dev/null"
            set rc 1
        }
        timeout {
            nc_msg "$PROGRAM Status: timeout in toggle_spanning_tree with timeout value : $timeout\n"
            write_log $expect_out(buffer)
            nc_msg "$PROGRAM Status: timeout waiting for dev /packages/gui.  Continuing on ...\n"
            nc_msg "$PROGRAM Status: Unable to change the state of the spanning tree for the adapter.\n"
        }
        eof {
            write_log $expect_out(buffer)
            write_message "$DSPMSG -s 1 $CATALOG 11 '%s : cannot connect to %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
            set rc 1
        }
    }

    set command  "set_spanning_config $spanning $location\r"
    send_command 
    expect {
        -i $spawn_id_rconsole
        -re "\[S|s\]ucceeded(.*)" {
            write_log $expect_out(buffer)
            nc_msg "$PROGRAM Status: SMS Macro Operation Succeeded.\n"
        }
        -re "\[F|f\]ailed(.*)" {
            write_log $expect_out(buffer)
            nc_msg "$PROGRAM Status: SMS Macro Operation Failed.\n"
        }
        -re "]" {
            write_log $expect_out(buffer)
            write_message "$DSPMSG -s 1 $CATALOG 09 '%s: unexpected prompt\n' \"$PROGRAM\" 2>/dev/null"
            set rc 1
        }
        timeout {
            nc_msg "$PROGRAM Status: timeout in toggle_spanning_tree with timeout value : $timeout\n"
            write_log $expect_out(buffer)
            nc_msg "$PROGRAM Status: timeout waiting for dev /packages/gui.  Continuing on ...\n"
            nc_msg "$PROGRAM Status: Unable to change the state of the spanning tree for the adapter.\n"
        }
        eof {
            write_log $expect_out(buffer)
            write_message "$DSPMSG -s 1 $CATALOG 11 '%s : cannot connect to %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
            set rc 1   
        }
    }

    return
}


###################################################################
#
# 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.
###################################################################
proc boot_network {} {
    global rc
    global spawn_id_rconsole
    global full_path_name
    global command
    global speed
    global duplex
    global chosen_adap_type
    global server_ip
    global client_ip
    global gateway_ip
    global subnetmask_ip
    global extra_args
    global CATALOG
    global DSPMSG
    global PROGRAM
    global signal
    global HMCNAME
    global expect_out
    global env
    set rc 0
    set i 0

    nc_msg "$PROGRAM 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
    set done(0) 0
#   set cmd(0) "boot $full_path_name:speed=$speed,duplex=$duplex,bootp,0.0.0.0,,0.0.0.0,0.0.0.0\r"
    # cmd(0) is set below
    set msg(0) "$PROGRAM Status: network boot initiated\n"
    set pattern(0) "(TFTP|BOOTP)"
    set newstate(0) 99

    # If the install adapter is FDDI, don't set the speed and duplex
    # state 1
    set done(1) 0
#   set cmd(1) "boot $full_path_name:bootp,0.0.0.0,,0.0.0.0,0.0.0.0\r"
    # cmd(1) is set below
    set msg(1) "$PROGRAM Status: network boot initiated\n"
    set pattern(1) "BOOTP"
    set newstate(1) 99

    # state 99, all done
    set done(99) 1

    # state -1, all done
    set done(-1) 1

    # set cmd and boot_continue
    if {$subnetmask_ip == ""} {
      set cmd(0) "boot $full_path_name:speed=$speed,duplex=$duplex,bootp,$server_ip,,$client_ip,$gateway_ip $extra_args\r"
      if { [info exists env(LPAR_NETBOOT_DEBUG_BOOT)] } {
        set cmd(0) "boot $full_path_name:speed=$speed,duplex=$duplex,bootp,$server_ip,,$client_ip,$gateway_ip $extra_args -s trap\r"
      }
      set cmd(1) "boot $full_path_name:bootp,$server_ip,,$client_ip,$gateway_ip\r"
      set boot_continue 0
    } else {
      set cmd(0) "boot $full_path_name:speed=$speed,duplex=$duplex,bootp,$server_ip,,$client_ip,$gateway_ip,,,$subnetmask_ip $extra_args\r"
      if { [info exists env(LPAR_NETBOOT_DEBUG_BOOT)] } {
        set cmd(0) "boot $full_path_name:speed=$speed,duplex=$duplex,bootp,$server_ip,,$client_ip,$gateway_ip,,,$subnetmask_ip $extra_args -s trap\r"
      }
      set cmd(1) "boot $full_path_name:bootp,$server_ip,,$client_ip,$gateway_ip,$gateway_ip,,,$subnetmask_ip\r"
      set boot_continue 1
    }

    ##############################################################################
    # This is the expect code.        
    # First, the initial state is set to 0.
    # Then, in a loop, 
    #    the done flag is checked,
    #    the command is sent to the chrp interface
    #    expect listens with the pattern 
    #    
    ##############################################################################
    if { $chosen_adap_type ==  "fddi" } {
        set state 1
    } else {
        if { $speed == "" || $duplex == "" } {
            write_message "$DSPMSG -s 1 $CATALOG 25 '%s: cannot set speed or duplex for network boot\n' \"$PROGRAM\" 2>/dev/null"
            set rc 1
            return
        }
        set state 0
    }

    set timeout 300  
    set timeout [change_timeout $timeout]

    while { $done($state) == 0 } {
        nc_msg "$PROGRAM Status: command is $cmd($state)\n"
        set command $cmd($state)
        send_command
        expect {
            -i $spawn_id_rconsole
            -re $pattern($state) {
                write_log $expect_out(buffer)
                nc_msg $msg($state)
                set state $newstate($state)
            }
            -re "]" {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 09 '%s: unexpected prompt\n' \"$PROGRAM\" 2>/dev/null"
                set rc 1
                return
            }
            -re "(.*)DEFAULT(.*)" {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 14 '%s: default catch error\n' \"$PROGRAM\" 2>/dev/null"
                set rc 1
                return
            }
            -re "(.*)ok(.*)0 >(.*)" {
                if { $boot_continue } {
                    nc_msg "retrying boot without subnet mask\n"
                    set state 0
                    set boot_continue 0
                    set cmd(0) "boot $full_path_name:speed=$speed,duplex=$duplex,bootp,$server_ip,,$client_ip,$gateway_ip $extra_args\r"

                    if { [info exists env(LPAR_NETBOOT_DEBUG_BOOT)] } {
                        set cmd(0) "boot $full_path_name:speed=$speed,duplex=$duplex,bootp,$server_ip,,$client_ip,$gateway_ip $extra_args -s trap\r"
                    }
                } 
            }
            timeout {
                nc_msg "$PROGRAM Status: timeout in boot_network with timeout value : $timeout\n"
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 10 '%s: timeout\n' \"$PROGRAM\" 2>/dev/null"
                nc_msg "timeout state is $state\n"
            }
            eof {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 11 '%s: cannot connect to %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
                set rc 1
                return
            }
        }
    }
}

#
# PROCEDURE
#
#
proc Boot {} {
    global rc
    global expect_out
    global spawn_id_rconsole
    global CATALOG
    global DSPMSG
    global PROGRAM
    global HMCNAME
    global env
    global signal
    
    set rc 0

    nc_msg "Boot function started\n"
    nc_msg "$PROGRAM Status: waiting for the boot image to boot up.\n"

    set timeout 1200      ;# could take a while depending on configuration
    set timeout [change_timeout $timeout]

    # check for bootp response error
    expect {
        -i $spawn_id_rconsole 
        -re "RESTART-CMD" {
            write_log $expect_out(buffer)

            # 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
            write_message "$DSPMSG -s 1 $CATALOG 26 '%s: The network boot ended in an error.\n' \"$PROGRAM\" 2>/dev/null"
            write_message "$DSPMSG -s 1 $CATALOG 39 '%s: Error : %s\n' \"$PROGRAM\" \"RESTART-CMD\" 2>/dev/null"
            set rc 5
            return
        }
        -re {!([0-9A-F]+)} {
            write_log $expect_out(buffer)
            write_message "$DSPMSG -s 1 $CATALOG 26 '%s: The network boot ended in an error.\n' \"$PROGRAM\" 2>/dev/null"
            nc_msg "$expect_out(buffer)\n"

            set rc 1
            return
        }
        -ex {--------------------------------} {
            write_log $expect_out(buffer)
            write_message "$DSPMSG -s 1 $CATALOG 27 '# Network boot proceeding, %s is exiting.\n' \"$PROGRAM\" 2>/dev/null"
        }
        timeout {
            nc_msg "$PROGRAM Status: timeout in Boot function with timeout value : $timeout\n"
            write_log $expect_out(buffer)
            set mins [expr ($timeout/60)]
            write_message "$DSPMSG -s 1 $CATALOG 59 \
                           '%s: timeout waiting for the boot image to boot up. \
                           \n%s waited %s 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' \
                           \"$PROGRAM\" \"$PROGRAM\" \"$mins\" \
                           2>/dev/null"
            nc_msg $expect_out(buffer)
            set rc 1
            return
        }                                                                       
        eof {
            write_log $expect_out(buffer)
            write_message "$DSPMSG -s 1 $CATALOG 60 '%s: Port closed waiting for boot image to boot.\n' \"$PROGRAM\" 2>/dev/null"                                       
            set rc 1                                                            
            return                                                              
        }
    }

    expect {
        -i $spawn_id_rconsole
        -re "(.*)Welcome(.*)" {
            write_log $expect_out(buffer)
        }
        -ex {--------------------------------} {
            write_log $expect_out(buffer)
        }
        timeout {
           nc_msg "$PROGRAM Status: timeout in boot function timeout value : $timeout\n"
           write_log $expect_out(buffer)
           return
        }
        eof {
            write_log $expect_out(buffer)
            return  
        }
    }
}

###################################################################
#
# 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.
#
###################################################################
proc multiple_open-dev {} {
    global rc
    global expect_out
    global spawn_id_rconsole
    global CATALOG
    global DSPMSG
    global PROGRAM
    global signal
    global HMCNAME
    global command
    global env

    nc_msg "$PROGRAM Status: multiple_open-dev start\n"
    set command  "dev /packages/net \r"
    send_command

    set command  "FALSE value OPEN-DEV_DEBUG \r"
    send_command

    if {[info exists env(OPEN_DEV_DEBUG)]} {
       set command "TRUE to OPEN-DEV_DEBUG \r"
       send_command
    }

    set 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

    set command " patch new-open-dev open-dev net-ping \r"
    send_command

    set timeout 60
    set timeout [change_timeout $timeout]

    expect {
        -i $spawn_id_rconsole
	-re ">(.*)" {
            write_log $expect_out(buffer)
            nc_msg "$PROGRAM Status: at End of multiple_open-dev \n"
        }
        -re "]" {
            write_log $expect_out(buffer)
            write_message "$DSPMSG -s 1 $CATALOG 09 '%s: unexpected prompt\n' \"$PROGRAM\" 2>/dev/null"
            set rc 1
            return
        }
        timeout {
            nc_msg "$PROGRAM Status: timeout in multiple_open-dev with timeout value : $timeout\n"
            write_log $expect_out(buffer)
            write_message "$DSPMSG -s 1 $CATALOG 10 '%s: timeout\n' \"$PROGRAM\" 2>/dev/null"
            set rc 1
            return
        }
        eof {
            write_log $expect_out(buffer)
            write_message "$DSPMSG -s 1 $CATALOG 11 '%s : cannot connect to %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
            set rc 1
            return
        }
    }
}

###################################################################
#  
# PROCEDURE
#  
# Declare procedure to get additional firmware debug statement.
#  
###################################################################
proc Firmware_Dump { device_path phandle } {
    global rc
    global expect_out
    global spawn_id_rconsole
    global CATALOG
    global DSPMSG
    global PROGRAM
    global signal
    global HMCNAME
    global command

    nc_msg "$PROGRAM Status: Firmware_Dump start\n"

    # state 0
    set done(0) 0
    set cmd(0) "dev /packages/obp-tftp\r"
    set msg(0) "$PROGRAM Status: selected /packages/obp_tftp\n"
    set pattern(0) "(.*)ok(.*)(\[0-9]) >(.*)"
    set newstate(0) 1

    # state 1
    set done(1) 0
    set cmd(1) ": testing1 .\" OBP-TFTP entry\" cr init-nvram-adptr-parms ;\r"
    set msg(1) "$PROGRAM Status: running test - OBP-TFTP entry\n"
    set pattern(1) "(.*)ok(.*)(\[0-9]) >(.*)"
    set newstate(1) 2

    # state 2
    set done(2) 0
    set cmd(2) ": testing2 .\" OBP-TFTP exit, TRUE\" cr true ;\r"
    set msg(2) "$PROGRAM Status: running test - OBP-TFTP exit\n"
    set pattern(2) "(.*)ok(.*)(\[0-9]) >(.*)"
    set newstate(2) 3

    # state 3
    set done(3) 0
    set cmd(3) "patch testing1 init-nvram-adptr-parms open\r"
    set msg(3) "$PROGRAM Status: running test - patch testing1\n"
    set pattern(3) "(.*)ok(.*)(\[0-9]) >(.*)"
    set newstate(3) 4

    # state 4
    set done(4) 0
    set cmd(4) "patch testing2 true open\r"
    set msg(4) "$PROGRAM Status: running test - patch testing2\n"
    set pattern(4) "(.*)ok(.*)(\[0-9]) >(.*)"
    set newstate(4) 5

    # state 5
    set done(5) 0
    set cmd(5) "dev $device_path\r"
    set msg(5) "$PROGRAM Status: running test - dev $device_path\n"
    set pattern(5) "(.*)ok(.*)(\[0-9]) >(.*)"
    set newstate(5) 6

    # state 6
    set done(6) 0
    set cmd(6) "true to debug-init\r"
    set msg(6) "$PROGRAM Status: running test - true to debug-init\n"
    set pattern(6) "(.*)ok(.*)(\[0-9]) >(.*)"
    set newstate(6) 7

    # state 7
    set done(7) 0
    set cmd(7) "true to debug-error\r"
    set msg(7) "$PROGRAM Status: running test - true to debug-error\n"
    set pattern(7) "(.*)ok(.*)(\[0-9]) >(.*)"
    set newstate(7) 8

    # state 8
    set done(8) 0
    set cmd(8) "$phandle to active-package\r"
    set msg(8) "$PROGRAM Status: running $phandle to active-package\n"
    set pattern(8) "(.*)ok(.*)(\[0-9]) >(.*)"
    set newstate(8) 9

    # state 9
    set done(9) 0
    set cmd(9) ".properties\r"
    set msg(9) "$PROGRAM Status: running .properies\n"
    set pattern(9) "(.*)ok(.*)(\[0-9]) >(.*)"
    set newstate(9) 10

    # state 10
    set done(10) 0
    set cmd(10) "clear\r"
    set msg(10) "$PROGRAM Status: running clear\n"
    set pattern(10) "(.*)ok(.*)(\[0-9]) >(.*)"
    set newstate(10) 11

    # state 11, all done
    set done(11) 1

    set state 0
    set timeout 60    ;# shouldn't take long
    set timeout [change_timeout $timeout]

    while { $done($state) == 0 } {
        set command $cmd($state)
        nc_msg "$PROGRAM Status: command is $cmd($state)\n"
        send_command
        expect {
            -i $spawn_id_rconsole
            -re $pattern($state) {
                write_log $expect_out(buffer)
                nc_msg $msg($state)
                set state $newstate($state)
            }
            -re "]" {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 09 '%s: unexpected prompt\n' \"$PROGRAM\" 2>/dev/null"
                set rc 1
                return
            }
            -re "(.*)DEFAULT(.*)" {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 14 '%s: default catch error\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
                set rc 1
                return
            }
            timeout {
                nc_msg "$PROGRAM Status: timeout in Firmware_Dump with timeout value : $timeout\n"
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 10 '%s: timeout\n' \"$PROGRAM\" 2>/dev/null"
                nc_msg "$PROGRAM Status: timeout state is $state\n"
                set rc 1
                return
            }
            eof {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 11 '%s: cannot connect to %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
                set rc 1
                return
            }
        }
    }
}

###################################################################
#
# PROCEDURE
#
# Declare procedure to get interact with debug kernel for debug boot
#
###################################################################
proc debug_boot {} {
    global rc
    global expect_out
    global spawn_id_rconsole
    global command
    global CATALOG
    global DSPMSG
    global PROGRAM
    global signal
    global HMCNAME

    nc_msg "$PROGRAM Status: debug_boot start\n"

    set done(0) 0
    set cmd(0) "\r"
    set msg(0) "$PROGRAM Status: At root for debug boot KDB prompt\n"   
    set pattern(0) "(.*)KDB(.*)"
    set newstate(0) 1

    # state 1, enter debug
    set done(1) 0
    set cmd(1) "mw enter_dbg\r"
    set msg(1) "$PROGRAM Status: sending enter_dbg command\n"
    set pattern(1) "(.*) =(.*)"
    set newstate(1) 2

    # state 2, set debug code
    set done(2) 0
    set cmd(2) "42\r"
    set msg(2) "$PROGRAM Status: sending debug code - 42\n"
    set pattern(2)  "(.*) =(.*)"
    set newstate(2) 3

    # state 3, end debug code input
    set done(3) 0
    set cmd(3) ".\r"
    set msg(3) "$PROGRAM Status: sending debug code - .\n"
    set pattern(3) "(.*)KDB(.*)"
    set newstate(3) 4

    # state 4, proceed with debug install
    set done(4) 0
    set cmd(4) "g\r"
    set msg(4) "$PROGRAM Status: Start debug install\n"
    set pattern(4) "(.*)"
    set newstate(4) 5

    # state 5, all done
    set done(5) 1

    set state 0
    set timeout 120    ;# shouldn't take long
    while { $done($state) == 0 } {
        set command $cmd($state)
        nc_msg "$PROGRAM Status: command is $cmd($state)\n"
        send_command
        expect {
            -i $spawn_id_rconsole
            -re $pattern($state) {
                nc_msg $msg($state)
                set state $newstate($state)
            }
            -re "]" {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 09 '%s: unexpected prompt\n' \"$PROGRAM\" 2>/dev/null"
                set rc 1
                return
            }
            -re "(.*)DEFAULT(.*)" {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 14 '%s: default catch error\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
                set rc 1
                return
            }
            timeout {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 10 '%s: timeout\n' \"$PROGRAM\" 2>/dev/null"
                nc_msg "$PROGRAM Status: timeout state is $state\n"
                set rc 1
                return
            }
            eof {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 11 '%s: cannot connect to %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
                set rc 1
                return
            }
        }
    }
}

proc release_lock { release_code } {

    global OF_LOCK
    global HAVE_LOCK
    global PROGRAM
    global DSPMSG
    global CATALOG
    global signal

    if { $HAVE_LOCK == 1 && [catch { system "/bin/rm $OF_LOCK 2>/dev/null" }] == 0 } {
        nc_msg "$PROGRAM Status: released OF lock ($release_code)\n"
    }
    set HAVE_LOCK 0
}

proc clean_exit { exit_code } {

    global node
    global BINPATH
    global js22_blade
    global ctrlpoint_type
    global PROGRAM
    global DSPMSG
    global CATALOG
    global signal
    global DSMDSMBINPATH


    nc_msg "$PROGRAM Status: clean-exit called with code $exit_code\n"


    
    # Release the lock - this step may be overkill as we have an
    # exit handler but better to be safe than sorry. (note: locking only
    # used for hmc nodes)
    #

    # If node was a JS22 blade, reset the boot mode
    #
    if { $js22_blade } {
        nc_msg "$PROGRAM Status: Resetting boot mode for POWER6 blade\n"
        set rc [catch {eval exec $DSMDSMBINPATH\dpower -n \"$node|$ctrlpoint_type|$ctrlpoint|$optval|$HWPW\" setnormal} msg]

        if { $rc } {
            nc_msg "dpower query failure detected\n"
            nc_msg "$msg\n"
        }
    }

    exit $exit_code
}

#
# Signal handling stuff
# SIGKILL (9) cannot be caught so it SHOULD NOT be used as that
# may leave OF_LOCK around
#
trap {
    nc_msg "$PROGRAM Status: received signal named SIG[trap -name]\n"
    clean_exit 3
} {INT HUP QUIT TERM}

#
# Exit handler.  This will release the lock when:
# - script bails because of syntax error (undefined variable)
# - script runs out of code to run
# - an exit is called
#
exit -onexit {

    global node_type
    global throttle
    global node

    # Release the lock (note: locking only used for hmc nodes)
    #
    if { ( $node_type == "hmc" ) && ( $throttle ) } {
        release_lock "EH"
    }

    # if we were asked to open a temp file, close it
    # on the way out
    #
    if { $tmp_fh } {
        close $tmp_fh
    }
}


#
# PROCEDURE
#
#   close_vterm
#
proc close_vterm { conserver_avail } {
    global spawn_id_rconsole
    global node
    global oc_retry_count
    global command
    global BINPATH
    global PROGRAM
    global DSPMSG
    global CATALOG
    global signal
    global ctrlpoint_type
    global ctrlpoint
    global optval
    global HWPW

    nc_msg "$PROGRAM Status: Closing remote console session\n"
    if { $conserver_avail } {
        set command "\005c.\r"
        send_command
    } else {
        set command "\r"
        send_command

        # If the vterm is in use and conserver is not available,
        # we exit the rconsole session by sending a return
        # character.  Since rconsole was invoked with the -z
        # flag, this will result in an error code being written
        # to STDOUT.  We need another expect statement to
        # catch this error, so it won't be caught by the
        # next clause of the main expect statement the next
        # time through the while loop.
        #
        expect {
            -i $spawn_id_rconsole \
            -re "-=>(\[0-9\])<=-" {
                nc_msg "$PROGRAM Status: retrieved status code from STDOUT\n"
            }
        }
    }

    nc_msg "$PROGRAM Status: restarting console session\n"
    incr oc_retry_count 1
    open_console
}

proc open_console {} {

    global BINPATH
    global DSMBINPATH
    global spawn_id_rconsole
    global Boot_timeout
    global node
    global command
    global oc_retry_count
    global oc_done
    global mgtsvr
    global ctrlpoint_type
    global PROGRAM
    global DSPMSG
    global CATALOG
    global signal
    global ctrlpoint
    global optval
    global HWPW

    if { $oc_retry_count > 5 } {
        nc_msg "$PROGRAM Status: exceeded maximum number of retries attempting to open console\n"
        write_message "$DSPMSG -s 1 $CATALOG 96 '%s: Exceeded maximum number of retries attempting to open console.\n' \"$PROGRAM\" 2>/dev/null"
        clean_exit 1
    }

    set count 0

    # In SLES9, expect cannot get correct rconsole information because the 
    # default encoding in SLES9 is utf8, the encoding need to be set to 
    # iso8859-1 which is the same with it in SLES8 and RedHat.
    encoding system iso8859-1
    if { $ctrlpoint_type == "bcmm" } {
        set RCONSOLE_CMD "$DSMBINPATH/dconsole -f -t -n \"$node|$ctrlpoint_type|$ctrlpoint|$optval|$HWPW\""
    } else {
        set RCONSOLE_CMD "$DSMBINPATH/dconsole -c -f -t -n \"$node|$ctrlpoint_type|$ctrlpoint|$optval|$HWPW\""
    }
    set state "unknown"

    #
    # open the S1 serial port
    #
    nc_msg "$PROGRAM Status: open S1 port\n"

    nc_msg "$PROGRAM Status: console command is $RCONSOLE_CMD\n"
    set pid_rconsole [eval spawn -nottycopy -nottyinit $RCONSOLE_CMD]
    set spawn_id_rconsole $spawn_id

    sleep 2

    # If the console state is "up", it means that conserver is running, and another
    # process initiated a console session to our target node before hmc_nodecond.
    # Since hmc_nodecond runs rconsole with -f, it will take the read-write session
    # for itself.  Because the session was already established, there's nothing else for
    # this function to do, so we can simply return.
    #
    if { $state == "up" } {
        nc_msg "$PROGRAM Status: console session already established\n"
        return
    }

    # Allow a longer timeout for HMC nodes
    #
    if { $ctrlpoint_type == "hmc" } {
        set timeout 180
    } else {
        set timeout 10
    }
    
    while { ! $oc_done } {
        expect {
            -i $spawn_id_rconsole
            "Open Completed" {
               nc_msg "$PROGRAM Status: connected to S1 serial port\n"
               set oc_done 1
            }
            "All available Virtual Terminal Sessions have been opened and are in use" {
                nc_msg "$PROGRAM Status: Regatta Virtual Terminal in use\n"
                close_vterm $conserver_avail
            }
            "2651-663" {
                nc_msg "$PROGRAM Status: Regatta Virtual Terminal in use\n"
                close_vterm $conserver_avail
            }
            "2651-785" {
                nc_msg "$PROGRAM Status: Squadron Virtual Terminal in use\n"
                close_vterm $conserver_avail
            }
            -re "-=>(\[0-9\])<=-" {
                nc_msg "$PROGRAM Status: dconsole failure detected\n"
                nc_msg $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 93 '%s: dconsole failure detected.\n' \"$PROGRAM\" 2>/dev/null"
                clean_exit 1
            }
            "*:*265\[1|9]\-*\n" {  # use \n to ensure we get the entire
                             # message in the expect buffer
                nc_msg "$PROGRAM Status: dconsole failure detected\n"
                nc_msg $expect_out(buffer)

                # parse the error message out and display to the user
                #
                regexp .*(265\[1|9]\\-.*\n) $expect_out(buffer) dummy errmsg
                send_user $errmsg
                clean_exit 1
            }
            "2760-255" {
                nc_msg "$PROGRAM Status: dconsole failure detected\n"
                nc_msg $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 93 '%s: dconsole failure detected.\n' \"$PROGRAM\" 2>/dev/null"
                set command "\r"
                send_command 
                clean_exit 1
            }
            "2760-100" {
                nc_msg "$PROGRAM Status: dconsole failure detected\n"
                nc_msg $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 93 '%s: dconsole failure detected.\n' \"$PROGRAM\" 2>/dev/null"
                set command "\r"
                send_command 
                clean_exit 1
            }
            
            timeout { 
                # For HMC nodes, allow up to 180 seconds to connect
                # For all other types, we can assume success.
                    nc_msg "$PROGRAM Status: Connected to S1 serial port\n"
                    set oc_done 1
            }
            eof {
                nc_msg "cannot connect to S1 serial port\n"
                write_message "$DSPMSG -s 1 $CATALOG 97 '%s: Cannot connect to S1 serial port\n' \"$PROGRAM\" 2>/dev/null"
                clean_exit 1
            }
        }
    }
}

proc reboot {} {
    global BINPATH
    global DSMBINPATH
    global spawn_id_rconsole
    global Boot_timeout
    global node
    global command
    global oc_retry_count
    global oc_done
    global mgtsvr
    global ctrlpoint_type
    global PROGRAM
    global DSPMSG
    global CATALOG
    global signal
    global ctrlpoint
    global optval
    global HWPW
    global simulation
    global immed_flag
    global max_rpower_retries
    global DSMDSMBINPATH
    global node_type

    write_message "$DSPMSG -s 1 $CATALOG 37 '# Checking for power off.\n' 2>/dev/null"
    nc_msg "$PROGRAM Status: check for power off\n"

#Change the timeout back
    set timeout 200
    set timeout [change_timeout $timeout]
# power state strings are nationalized, so invoke dpower
# with hidden query_val flag to return the state as a number instead
# of a string
#
    set done 0
    set query_count 0
    while { ! $done } {
        set rc [catch {eval exec $DSMDSMBINPATH\dpower -n \"$node|$ctrlpoint_type|$ctrlpoint|$optval|$HWPW\" query_val} msg]
        if { $rc } {
            #
            # If we see the "Initializing" error it means the HWCTRLRM is
            # still coming up.  Don't fail outright, but wait for a while
            # and try the command again.
            #
            if { [regexp "2651-691" $msg junk] == 1 } {
                nc_msg "$PROGRAM Status: Initializing\n"
                incr query_count
                if { $query_count > $max_rpower_retries } {
                    nc_msg "dpower query failure detected\n"
                    write_message "$DSPMSG -s 1 $CATALOG 98 '%s: power query failure detected\n' \"$PROGRAM\" 2>/dev/null"
                    clean_exit 1
                } else {
                    sleep 10
                    continue
                }
            }
            nc_msg "dpower query failure detected\n"
            nc_msg "$msg\n"
            write_message "$DSPMSG -s 1 $CATALOG 98 '%s: power query failure detected\n' \"$PROGRAM\" 2>/dev/null"
            clean_exit 1
        } else {
            set done 1
            continue
        }
    }

    set power_status [split $msg " "]
    if { [lindex $power_status 1] == "0"  } {
        # If dpower returns off, perform one more check for the actual power
        # state. Per POK CMVC 145259, a failed open firmware BOOTP will leave
        # p5 and p6 LPARs in a "powering-on" state, which CSM interprets as
        # powered off.  However, a power on to open firmware will not be accepted
        # in this state.  Therefore, if state = powering-on, we need to explicitly
        # issue a power off command to the LPAR. (Note also we cannot simply
        # power off the LPAR without checking the state first - see POK CMVC
        # 88514.)  This is not an issue for p4, since a failed BOOTP leaves the
        # LPAR in "open-firmware" state, which CSM interprets as "on".
        #
        nc_msg "$PROGRAM Status: power reported as off, checking power state\n"
        set rc [catch {eval exec $DSMDSMBINPATH\dpower -n \"$node|$ctrlpoint_type|$ctrlpoint|$optval|$HWPW\" state} msg]
        if { $rc } {
            nc_msg "cannot get power state from node $node\n"
            nc_msg "$msg\n"
            write_message "$DSPMSG -s 1 $CATALOG 30 99 '%s: cannot get power state\n' \"$PROGRAM\" 2>/dev/null"
            clean_exit 1
        }        

        nc_msg "$PROGRAM Status: power state is $msg\n"
        if { [regexp "powering-on" $msg junk] == 0 } {
            nc_msg "$PROGRAM Status: power off complete\n"
            set power_off_needed 0
        } else {
            nc_msg "$PROGRAM Status: power off needed\n"
            set power_off_needed 1
        }

    } else {
        set power_off_needed 1
    }

    if { $power_off_needed == 1 } {
        #
        #
        # power off the node
        #
        nc_msg "$PROGRAM Status: power off the node\n"
        if { $immed_flag } {
            set rc [catch {eval exec $DSMDSMBINPATH\dpower -n \"$node|$ctrlpoint_type|$ctrlpoint|$optval|$HWPW\" off_immediate} msg]
        } else {  
            set rc [catch {eval exec $DSMDSMBINPATH\dpower -n \"$node|$ctrlpoint_type|$ctrlpoint|$optval|$HWPW\" off} msg]
        }
        if { $rc } {
            nc_msg "cannot power off node $node\n"
            nc_msg "$msg\n"
            write_message "$DSPMSG -s 1 $CATALOG 100 '%s: cannot power off node\n' \"$PROGRAM\" 2>/dev/null"
            clean_exit 1
        }

        #
        #
        # dpower will return a successful result if it was able to pass the power
        # command to the HMC, but the node may not be powered off yet.  Need
        # to query to make sure the node is off before we continue
        #
        nc_msg "$PROGRAM Status: wait for power off\n"

        sleep 5

        set done 0
        set query_count 0
        while { ! $done } {
            set rc [catch {eval exec $DSMDSMBINPATH\dpower -n \"$node|$ctrlpoint_type|$ctrlpoint|$optval|$HWPW\" query_val} msg]
            if { $rc } {
                #
                # If we see the "Initializing" error it means the HWCTRLRM is
                # still coming up.  Don't fail outright, but wait for a while
                # and try the command again.
                #
                if { [regexp "2651-691" $msg junk] == 1 } {
                    nc_msg "$PROGRAM Status: Initializing\n"
                    incr query_count
                    if { $query_count > $max_rpower_retries } {
                        nc_msg "dpower query failure detected\n"
                        write_message "$DSPMSG -s 1 $CATALOG 98 '%s: power query failure detected\n' \"$PROGRAM\" 2>/dev/null"
                        clean_exit 1
                    } else {
                        sleep 10
                        continue
                    }
                }
                nc_msg "dpower query failure detected\n"
                nc_msg "$msg\n"
                write_message "$DSPMSG -s 1 $CATALOG 98 '%s: power query failure detected\n' \"$PROGRAM\" 2>/dev/null"
                clean_exit 1
            }
       
            #
            # separate the nodename from the query status
            #
            set power_status [split $msg " "]
            if { ( [lindex $power_status 1] == "0" ) || ( ( [lindex $power_status 1] == "4" ) && ( $simulation ) )  } {
                nc_msg "$PROGRAM Status: power off complete\n"
                set done 1
                continue
            }
            incr query_count
            if { $query_count > $max_rpower_retries } {
                nc_msg "$PROGRAM Status: Timed out waiting for power off\n"

                nc_msg "$PROGRAM Status: Power off node\n"
                set rc [catch {eval exec $DSMDSMBINPATH\dpower -n \"$node|$ctrlpoint_type|$ctrlpoint|$optval|$HWPW\" query_val} msg]
                if { $rc } {
                    nc_msg "dpower query failure detected\n"
                    nc_msg "$msg\n"
                    write_message "$DSPMSG -s 1 $CATALOG 98 '%s: power query failure detected\n' \"$PROGRAM\" 2>/dev/null"
                    clean_exit 1
                }                

                #
                # separate the nodename from the query status
                #
                set power_status [split $msg " "]
                if { [lindex $power_status 1] == "0"  } {
                    nc_msg "$PROGRAM Status: power off complete\n"
                    set done 1
                    continue
                } else {
                    nc_msg "$PROGRAM Status: Unable to power off node\n"
                    nc_msg "$msg\n"
                    write_message "$DSPMSG -s 1 $CATALOG 102 '%s: Unable to power off node\n' \"$PROGRAM\" 2>/dev/null"
                    clean_exit 1
                }
            }
            sleep 10
        }
    }

#
# power on the node
#
    nc_msg "$PROGRAM Status: power on the node to Open Firmware\n"
    if { $ctrlpoint_type == "bcmm" } {
        set rc [catch {eval exec $DSMDSMBINPATH\dpower -n \"$node|$ctrlpoint_type|$ctrlpoint|$optval|$HWPW\" on} msg]
    } else {
        set rc [catch {eval exec $DSMDSMBINPATH\dpower -n \"$node|$ctrlpoint_type|$ctrlpoint|$optval|$HWPW\" open_firmware} msg]
    }

    if { $rc } {
        nc_msg "cannot power on node $node\n"
        nc_msg "$msg\n"
        write_message "$DSPMSG -s 1 $CATALOG 103 '%s: Unable to power on node\n' \"$PROGRAM\" 2>/dev/null"
        clean_exit 1
    }

    nc_msg "$PROGRAM Status: wait for power on\n"

    sleep 5

#
# Verify node is powered on before continuing
#
    set done 0
    set query_count 0
    while { ! $done } {
        set rc [catch {eval exec $DSMDSMBINPATH\dpower -n \"$node|$ctrlpoint_type|$ctrlpoint|$optval|$HWPW\" query_val} msg]
        if { $rc } {
            if { [regexp "2651-691" $msg junk] == 1 } {
                nc_msg "$PROGRAM Status: Initializing\n"
                incr query_count
                if { $query_count > $max_rpower_retries } {
                    nc_msg "dpower query failure detected\n"
                    write_message "$DSPMSG -s 1 $CATALOG 98 '%s: power query failure detected\n' \"$PROGRAM\" 2>/dev/null"
                    clean_exit 1
                } else {
                    sleep 10
                    continue
                }
            }
            nc_msg "dpower query failure detected\n"
            nc_msg "$msg\n"
            write_message "$DSPMSG -s 1 $CATALOG 98 '%s: power query failure detected\n' \"$PROGRAM\" 2>/dev/null"
            clean_exit 1
        }

        #
        # separate the nodename from the query status
        #
        set power_status [split $msg " "]
        if { ( [lindex $power_status 1] == "1" ) || ( ( [lindex $power_status 1] == "4" ) && ( $simulation ) )  } {    
            nc_msg "$PROGRAM Status: power on complete\n"
            set done 1
            continue
        }
        incr query_count
     
        if { $query_count > $max_rpower_retries } {
            nc_msg "$PROGRAM Status: Timed out waiting for power on\n"
            }                

#
# separate the nodename from the query status
#
            set power_status [split $msg " "]
            if { [lindex $power_status 1] == "1"  } {
                nc_msg "$PROGRAM Status: power on complete\n"
                set done 1
                continue
            } else {
                nc_msg "$PROGRAM Status: Unable to power on node\n"
                write_message "$DSPMSG -s 1 $CATALOG 103 '%s: Unable to power on node\n' \"$PROGRAM\" 2>/dev/null"
                clean_exit 1
            }
        
        sleep 10
    }

# first thing we need to do is wait for the RS/6000 logo to appear.
# below the logo will be the words:
#
# memory      keyboard     network      scsi      speaker
#
#
# WARNING:
# i've found during development that if you try to send the "8" while the
# Service Processor is writing any one of the above words, it won't accept it.
# i also noticed that there was always a long delay (15 secs or so) between
# writing the word scsi and speaker. this is where i try to sneak in the "8".
#
# If the node is a Winterhawk, and Defect 266132 firmware has been applied,
# the "8" is not necessary. We will just wait for the "0 >" prompt.
#
#
#
# this gets us past the logo
#
    set done 0
    nc_msg "$PROGRAM Status: waiting for RS/6000 logo\n"

# if running in simulation mode, the logo will never appear.
#
    if { $simulation } {
        puts $tmp_fh "SIM hw-sim-mode 0000000000000000"
        nc_msg "$PROGRAM Status: Running in simulation mode - exiting with rc 0\n"
        clean_exit 0
    }

    while { ! $done } {
        expect {
            -i $spawn_id_rconsole \
            -re "Press 0 to select this console.*as the active console" {
                nc_msg "$PROGRAM Status: selecting active console\n"
                exec sleep 1
                send -i $spawn_id_rconsole "0";
            }
            -re "\[Mm]emory\[ ]+\[Kk]eyboard.*\[Nn]etwork\[ ]+\[SCSI|scsi]" {
                nc_msg "$PROGRAM Status: at RS/6000 logo\n"
                if { $node_type == "js20_blade" } {
                    send -i $spawn_id_rconsole "8"; sleep 15
                }
                set done 1
            }
            -re "E1F1" {
                # JS20 blades do not show the same prompt as other pSeries
                # machines, so if we see the E1F1 code, and we're a js20_blade,
                # we're at the equivalent of the "RS/6000 logo"
                if { $node_type == "js20_blade" } {
                    nc_msg "$PROGRAM Status: at RS/6000 logo\n"
                    set done 1
                }
            }
            timeout {
                nc_msg "timeout waiting for RS/6000 logo; exiting\n"
                nc_msg "This indicates either an dconsole failure, a hardware failure,\n"
                nc_msg "or a timeout value that is too short.\n"
                clean_exit 1
            }
            eof {
                nc_msg "cannot connect to S1 serial port\n"
                write_message "$DSPMSG -s 1 $CATALOG 97 '%s: Cannot connect to S1 serial port\n' \"$PROGRAM\" 2>/dev/null"
                clean_exit 1
            }
        }
    }
}

################################################################################
#                                                                              #
#  Main MAIN main Main MAIN main Main MAIN main Main MAIN main Main MAIN main  #
#                                                                              #
################################################################################

#
# Signal handling stuff
#
trap {
    global DSPMSG
    global CATALOG
    global PROGRAM

    set signal SIG[trap -name]

    write_message "$DSPMSG -s 1 $CATALOG 30 '%s: received signal named %s\n' \"$PROGRAM\" \"$signal\" 2>/dev/null"
    exit 3
} {INT HUP QUIT TERM}

set DSPMSG "/usr/bin/dspmsg"
set PROGRAM "lpar_netboot"
set CATALOG "/usr/lib/nls/msg/C/IBMhsc.netboot.cat"
set LOGFILE ""

# Determine the location of the message catalog
if {[info exists env(LANG)]} {
    set LANG $env(LANG)
    set lang [lindex [split ${LANG} {_}] 0]
    set CATALOG "/usr/lib/nls/msg/$lang/IBMhsc.netboot.cat"

    if { [file readable $CATALOG] && ([file size $CATALOG] > 0) } {
	# Do nothing because CATALOG is set
    } else {
        set CATALOG /usr/share/locale/$LANG/LC_MESSAGES/IBMhsc.netboot.cat
        if { [file readable $CATALOG] && ([file size $CATALOG] > 0) } {
	     # Do nothing because CATALOG is set
        } else {
             set CATALOG "/usr/share/locale/en/LC_MESSAGES/IBMhsc.netboot.cat"
        }
    }
}

set noboot 0        ;# default is to boot

# Flags and initial variable
set discovery 0
set discover_all 0
set hdr_printed 0
set verbose 0
set discover_macaddr 0
set rc 0
set debug_flag 0
set rmvterm_flag 0
set immed_flag 0
set list_physical 0
set list_disk 0
set colon 0
set choice 0
set dev_type_found 0
set adapter_found 0

set oc_retry_count 0
set oc_done 0
set js22_blade 0
set js20_blade 0
set nopowercycle 0
set simulation 0
set of_ok 0
set noshutdown 0
set max_rpower_retries 10
set spawn_id_rconsole ""
set node_type ""
set optval ""
set HWPW ""
set password_file ""
set username ""
set password ""
set ctrlpoint ""
set ctrlpoint_type ""
set node ""
set profile ""
set manage ""

set full_path_name ""
set adap_speed ""
set adap_duplex ""
set client_ip ""
set server_ip ""
set gateway_ip ""
set subnetmask_ip ""
set extra_args ""
set macaddress ""
set phys_loc ""
set spanning ""
set lparid ""
set bmode_original ""
set ctrlpoint_type ""
set tmp_filename ""

set CTRLTYPE ""
set HMCBINPATH "/opt/hsc/bin"
set IVMBINPATH "/usr/ios/lpm/bin"
set AIXBINPATH "/usr/bin"
set CSMBINPATH "/opt/csm/bin"
set DSMBINPATH "/opt/ibm/sysmgt/dsm/bin/"
set DSMDSMBINPATH "/opt/ibm/sysmgt/dsm/dsmbin/"
set IOSCLI "/usr/ios/cli/ioscli"

#
# Log the starting date and process id
#
nc_msg [timestamp -format "%x\n"]

set proc_id [ eval pid ]

nc_msg "Nodecond Status: process id is $proc_id\n"


set LOGFNAME "/tmp/lpar_netboot.exec.$proc_id.log"


set LOGFILE ""

# determine type of control system (HMC/IVM) and set an appropriate BINPATH
if {[file executable "$HMCBINPATH/lshmc"]} {
    set CTRLTYPE "HMC"
    set BINPATH $HMCBINPATH
    nc_msg "CTRLTYPE is HMC"
} elseif {[file executable "$IVMBINPATH/lsivm"]} {
    set CTRLTYPE "IVM"
    set BINPATH $IVMBINPATH
    nc_msg "CTRLTYPE is IVM"
} elseif {[file executable "$AIXBINPATH/oslevel"]} {
    set CTRLTYPE "AIX"
    set BINPATH $AIXBINPATH
    nc_msg "CTRLTYPE is AIX"
} else {
    nc_msg "unable to determine type of control system\n"
    write_message "$DSPMSG -s 1 $CATALOG 87 '%s: unable to determine type of control system\n' \"$PROGRAM\" 2>/dev/null"
    exit 1
}



if { [info exists env(LPAR_NETBOOT_DEBUG)] } {
    # Uncomment for internal debug
    exp_internal 1
}

if { [file exists $LOGFNAME] } {
    if { [catch { file delete -force $LOGFNAME }] } {
        nc_msg "Unable to delete $LOGFNAME.  Continuing ...\n"
    }
}

if {[catch {open $LOGFNAME {WRONLY CREAT APPEND}} LOGFILE] } {
    nc_msg "Unable to open logfile : $LOGFNAME.  Continuing ... \n"
    set LOGFILE ""
} else {
    log_file $LOGFNAME
}

# 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.
set dev_pat(0) "ethernet"
set dev_type(0) "ent"
set dev_pat(1) "token-ring"
set dev_type(1) "tok"
set dev_pat(2) "fddi"
set dev_type(2) "fddi"
set dev_count [array size dev_pat]

#
#
# Process command line options and parameters
#
#
while { [llength $argv] > 0} {
    set flag [lindex $argv 0]
    switch -glob -- $flag {

        "-A" { set discover_all 1
               set argv [lrange $argv 1 end]
             }

        "-C" { set client_ip [lindex $argv 1]
               set argv [lrange $argv 2 end]
             }

        "-D" { set discovery 1
               set argv [lrange $argv 1 end]
             }

        "-E" {
               set env_variable [lindex $argv 1]
               set argv [lrange $argv 2 end]
               set environment [lindex [split ${env_variable} {=}] 0]
               set variable_setting [lindex [split ${env_variable} {=}] 1]
               set env($environment) "$variable_setting"
               nc_msg "ENVIRONMENT      : $environment\n"
               nc_msg "VARIABLE_SETTING : $variable_setting\n"
             }
	
        "-G" { set gateway_ip [lindex $argv 1]
               set argv [lrange $argv 2 end]
             }

        "-K" { set subnetmask_ip [lindex $argv 1]
               set argv [lrange $argv 2 end]
             }

        "-P" { set list_physical 1
               set argv [lrange $argv 1 end]
             }

        "-M" { set discover_macaddr 1
               set argv [lrange $argv 1 end]
             }

        "-S" { set server_ip [lindex $argv 1]
               set argv [lrange $argv 2 end]
             }

        "-T" { set spanning [lindex $argv 1]
               set argv [lrange $argv 2 end]
             }

        "-c" { set colon 1
               set argv [lrange $argv 1 end]
             }

        "-d" { set adap_duplex [lindex $argv 1]
               set argv [lrange $argv 2 end]
             }

        "-f" { set rmvterm_flag 1
               set argv [lrange $argv 1 end]
             }

        "-F" { set password_file [lindex $argv 1]
                set argv [lrange $argv 2 end]
            }

        "-g" { set extra_args [lindex $argv 1]
               set argv [lrange $argv 2 end]
             }

        "-i" { set immed_flag 1
               set argv [lrange $argv 1 end]
             }

        "-l" { set phys_loc [lindex $argv 1]
               set argv [lrange $argv 2 end]
             }

        "-m" { set macaddress [lindex $argv 1]
               set argv [lrange $argv 2 end]
             }

        "-n" { set noboot 1
               set argv [lrange $argv 1 end]
             }

        "-N" { set nopowercycle 1;
                set argv [lrange $argv 1 end];
            }

        "-u" { set username [lindex $argv 1]
                set argv [lrange $argv 2 end]
            }

        "-p" { set password [lindex $argv 1]
                set argv [lrange $argv 2 end]
            }

        "-j" { set ctrlpoint_type [lindex $argv 1]
               set argv [lrange $argv 2 end]
             }

        "-J" { set ctrlpoint [lindex $argv 1]
                set argv [lrange $argv 2 end]
            }
            
        "-s" { set adap_speed [lindex $argv 1]
               set argv [lrange $argv 2 end]
             }

        "-t" { set list_type [lindex $argv 1]
               set argv [lrange $argv 2 end]

               #
               # Validate the argument
               #
               foreach dev [array names dev_type] {
                   if {$dev_type($dev) == $list_type} {
                       set dev_type_found 1
                       break
                   }
               }

               if {$dev_type_found == 0 } {
                  write_message "$DSPMSG -s 1 $CATALOG 31 '%s: %s is not a valid adapter choice\n' \"$PROGRAM\" \"$list_type\" 2>/dev/null"
                  exit 1
               }
             }

        "-v" { set verbose 1
               set argv [lrange $argv 1 end]
             }

        "-x" { set debug_flag 1
               set argv [lrange $argv 1 end]
             }

        "--disk" {
               set list_disk 1
               set argv [lrange $argv 1 end]
             }

        "--help" {
                usage
             }

        "--noshutdown" { set nopowercycle 1;
                set argv [lrange $argv 1 end];
            }

        "-temp_file" { set tmp_filename [lindex $argv 1]
               set argv [lrange $argv 2 end]
               nc_msg "$PROGRAM Status: using temp filename of $tmp_filename\n"
               if [ catch { open $tmp_filename "w" } tmp_fh ] {
                   # if there's an error opening the temp file, log it and
                   # write it to stdout, then exit
                   #
                   nc_msg "$PROGRAM Status: unable to open file\n"
                   nc_msg "$tmp_fh\n"
                   puts "$tmp_fh\n"
                   exit 1
               }
            }

        "-*" { write_message "$DSPMSG -s 1 $CATALOG 32 '%s: illegal option: %s\n' \"$PROGRAM\" \"$flag\" 2>/dev/null"
               usage
             }

        default {break}
    }
}

# For direct-attach FSP support for POWER5 systems with console server
# access to the console (accesses via physical serial port, not HMC
# or FSP virtual serial port).  In this mode, OF will prompt the
# user for the CEC's admin password.  The password must be set into
# this environment variable before the command invoking hmc_nodecond
# (installnode, csmsetupks, getadapters, etc) is run.
#
if { $ctrlpoint_type == "fsp" } {
    set of_pswd $ctrlpoint_type
    nc_msg "$PROGRAM Status: CSM_OFW_PSWD environment variable is set\n"
} else {
    set of_pswd ""
}


if { ( [llength $argv] < 2 ) && ( $ctrlpoint_type == "hmc" ) } {
    write_message "$DSPMSG -s 1 $CATALOG 33 '%s: missing parameter\n' \"$PROGRAM\" 2>/dev/null"
    usage
}

if { [llength $argv] < 1 && ( $ctrlpoint_type == "bcmm" || $ctrlpoint_type == "ivm" ) } {
    write_message "$DSPMSG -s 1 $CATALOG 33 '%s: missing parameter\n' \"$PROGRAM\" 2>/dev/null"
    usage
}

set arg0 [lindex $argv 0]
set arg1 [lindex $argv 1]

#if { [llength $argv] > 0 && $ctrlpoint_type == "fsp" } {
#    write_message "$DSPMSG -s 1 $CATALOG 34 '%s: extraneous parameter(s)\n' \"$PROGRAM\" 2>/dev/null"
#    usage
#}

if { [llength $argv] > 3 && $ctrlpoint_type == "hmc" } {
    write_message "$DSPMSG -s 1 $CATALOG 34 '%s: extraneous parameter(s)\n' \"$PROGRAM\" 2>/dev/null"
    usage
}

if { [llength $argv] > 1 && ( $ctrlpoint_type == "bcmm" || $ctrlpoint_type == "ivm" ) } {
    write_message "$DSPMSG -s 1 $CATALOG 34 '%s: extraneous parameter(s)\n' \"$PROGRAM\" 2>/dev/null"
    usage
}

if { $list_physical == 0 } {
    set dev_pat(3) "l-lan"
    set dev_type(3) "ent"
    set dev_count [array size dev_pat]
} else {
    set dev_pat(3) ""
    set dev_type(3) "" 
    set dev_count [array size dev_pat]
}

if { $list_disk == 1 } {
    set dev_pat(4) "scsi"
    set dev_type(4) "disk"
    #set dev_pat(5) "fibre-channel"
    #set dev_type(5) "disk"
 
    set dev_count [array size dev_pat]
}


    set node [lindex $argv 0]
    set profile [lindex $argv 1]
    set manage [lindex $argv 2]
    nc_msg "$PROGRAM Status: node = $node, profile = $profile, manage = $manage\n"

if {$ctrlpoint_type == "hmc"} {
    set optval "TargetHWTypeModel=$manage:TargetHWSerialNum=$profile:TargetLPARID=$node"
} elseif {$ctrlpoint_type == "ivm"} {
    set optval "TargetLPARID=$node"
} elseif {$ctrlpoint_type == "fsp"} {
    set optval ""
} elseif {$ctrlpoint_type == "bcmm"} {
    set optval "TargetAccessID=$node"
}

if {$password_file != ""} {
    set HWPW "$password_file"
} elseif {$username != "" && $password != ""} {
    set HWPW "$username:$password"
}

set Boot_timeout 3000
set Boot_timeout [change_timeout $Boot_timeout]

nc_msg "$PROGRAM Status: process id is $proc_id\n"

if {$dev_type_found}    { nc_msg "$PROGRAM Status: -t List only $list_type adapters\n"            }
if {$noboot}            { nc_msg "$PROGRAM Status: -n (no boot) flag detected\n"                  }
if {$discovery}         { nc_msg "$PROGRAM Status: -D (discovery) flag detected\n"                }
if {$discover_all}      { nc_msg "$PROGRAM Status: -A (discover all) flag detected\n"             }
if {$verbose}           { nc_msg "$PROGRAM Status: -v (verbose debug) flag detected\n"            }
if {$discover_macaddr}  { nc_msg "$PROGRAM Status: -M (discover mac address) flag detected\n"     }
if {$immed_flag}        { nc_msg "$PROGRAM Status: -i (force immediate shutdown) flag detected\n" }
if {$list_physical}     { nc_msg "$PROGRAM Status: -P (list only phsical network) flag detected\n"}
if {$colon}             { nc_msg "$PROGRAM Status: -c (list colon separated ) flag detected\n"    }
if {$nopowercycle}  { nc_msg "$PROGRAM Status: --noshutdown (no power off) flag detected\n" }

if {$debug_flag || 
    ([info exists env(LPAR_NETBOOT_DEBUG)]) } { 
    nc_msg "$PROGRAM Status: -d (debug) flag detected\n" 
    log_user 1
}

if { [info exists env(LPAR_NETBOOT_SPANNING_TREE)] } {
    set spanning $env(LPAR_NETBOOT_SPANNING_TREE)
}

if {$discovery && $adap_speed    != ""} { nc_msg "$PROGRAM Status: using adapter speed of $adap_speed\n"            }
if {$discovery && $adap_duplex   != ""} { nc_msg "$PROGRAM Status: using adapter duplex of $adap_duplex\n"          }
if {$discovery && $server_ip     != ""} { nc_msg "$PROGRAM Status: using server IP address of $server_ip\n"         }
if {$discovery && $client_ip     != ""} { nc_msg "$PROGRAM Status: using client IP address of $client_ip\n"         }
if {$discovery && $gateway_ip    != ""} { nc_msg "$PROGRAM Status: using gateway IP address of $gateway_ip\n"       }
if {$discovery && $subnetmask_ip != ""} { nc_msg "$PROGRAM Status: using subnetmask IP address of $subnetmask_ip\n" }
if {$discovery && $macaddress    != ""} { nc_msg "$PROGRAM Status: using macaddress of $macaddress\n"               }
if {$discovery && $phys_loc      != ""} { nc_msg "$PROGRAM Status: using physical location code of $phys_loc\n"     }

if {$spanning != ""} { nc_msg "$PROGRAM Status: -T Toggle spanning tree with state : $spanning\n" }

set HMCNAME $node

ck_args

if {$extra_args != "" }  { nc_msg "$PROGRAM Status: extra arguments sent to booting: $extra_args\n" }

if { ! $noboot } {
    set hdw_addr ""
    set speed $adap_speed
    set duplex $adap_duplex
}

# If CTRLTYPE is AIX,do some pre-process 
if { ![string compare $CTRLTYPE "AIX"] } {
    if { ( $ctrlpoint_type == "bcmm" ) } {
        nc_msg "$PROGRAM Status: BladeCenter node detected\n"
        
# Need to determine whether this is a p or xBlade
        set rc [catch {eval exec $DSMDSMBINPATH/dpower -n \"$node|$ctrlpoint_type|$ctrlpoint|$optval|$HWPW\" ispblade} BLADEINFO]
#        set BLADEINFO "$node yes"
        if { $rc } {
            nc_msg "Error querying the blade type for node $node.\n"
            nc_msg "$BLADEINFO\n"
            write_message "$DSPMSG -s 1 $CATALOG 106 '%s: Error querying the blade type.\n' \"$PROGRAM\" 2>/dev/null"
            exit 1
        }

        set blade_info [split $BLADEINFO " "]
        if { [lindex $blade_info 1] == "yes" } {
            nc_msg "$PROGRAM Status: POWER-based blade detected\n"
            set node_type "js20_blade"
        }

        if { $node_type != "js20_blade" } {
            nc_msg "$PROGRAM Status: non POWER-based blades are not supported\n"
            exit 1
        }       
    } elseif { $ctrlpoint_type == "hmc" } {
        # only need the lock processing for hmc nodes
        nc_msg "$PROGRAM Status: hmc-controlled node detected\n"
        set node_type "hmc"
        set max_rpower_retries 90
        set max_chars_sec 100

    } elseif { $ctrlpoint_type == "fsp" } {
        nc_msg "$PROGRAM Status: fsp-direct attached node detected\n"
        set node_type "fsp"
        set max_chars_sec 100

    } elseif { $ctrlpoint_type == "ivm" } {
        nc_msg "$PROGRAM Status: IVM node detected\n"
        set node_type "ivm"
        set max_chars_sec 100

    } else {
        nc_msg "$PROGRAM Status: unsupported node type $ctrlpoint_type\n"
        write_message "$DSPMSG -s 1 $CATALOG 107 '%s: unsupported node type.\n' \"$PROGRAM\" 2>/dev/null"
        exit 1
    }

    nc_msg "$PROGRAM Status: node type is $node_type\n"
}



# extract lpar id # for creating and removing virtual terminals on the IVM
if { ![string compare $CTRLTYPE "HMC"] || ![string compare $CTRLTYPE "IVM"]} {
	set rc [catch {eval exec $BINPATH/lssyscfg -r lpar -m \"$manage\" --filter lpar_names=\"$node\" -F lpar_id} lparid]
}
if { $rc } {
  nc_msg "$PROGRAM Status: warning: error from lssyscfg command\n"
  write_message "$DSPMSG -s 1 $CATALOG 39 '%s: Error : %s\n' \"$PROGRAM\" \"$lparid\" 2>/dev/null"
  exit 1
}

if {$rmvterm_flag} {
    nc_msg "$PROGRAM Status: -f (force close virtual session) flag detected\n"

    # our behavior depends on the type of control system that
    # we are on since the HMC and IVM environments differ
    switch $CTRLTYPE {
      "HMC" { set rc [catch {eval exec $BINPATH/rmvterm -m \"$manage\" -p \"$node\"} msg] }
      "IVM" { set rc [catch {eval exec $IOSCLI rmvt -id $lparid} msg] }
    }

    if { $rc } {
        nc_msg "$PROGRAM Status: warning: error from rmvterm command\n"
        write_message "$DSPMSG -s 1 $CATALOG 39 '%s: Error : %s\n' \"$PROGRAM\" \"$msg\" 2>/dev/null"
    }
}

#
# open the S1 serial port
#
nc_msg "$PROGRAM Status: open port\n"

# our behavior depends on the type of control system that
# we are on since the HMC and IVM environments differ
switch $CTRLTYPE {
  "HMC" {
        set pid_rconsole [eval spawn -nottycopy -nottyinit $BINPATH/mkvterm -m \"$manage\" -p \"$node\"]
        set spawn_id_rconsole $spawn_id
    }
  "IVM" {
        set pid_rconsole [eval spawn -nottycopy -nottyinit $IOSCLI mkvt -id $lparid]
        set spawn_id_rconsole $spawn_id
    }
  "AIX"  { 
        open_console
  }
}

nc_msg "$PROGRAM Status: spawn_id is $spawn_id_rconsole\n"

#
# ensure we got the serial connection before we power off the node.
# what we don't want is eof. this means that we didn't get the
# connection. we will accept a timeout. this means that we timed 
# out waiting for nothing, but we didn't get eof.  
#
# when a virtual terminal is created in an IVM environment, nothing is printed
# to the screen to confirm that it was successfully connected therefore there
# is nothing to 'expect'. So we'll assume for now that the virtual terminal was
# created and subsequent 'expect eof's will handle the scenario where it wasn't
# connected for some reason.

set timeout 200
set timeout [change_timeout $timeout]
set done 0
while { ! [string compare $CTRLTYPE "HMC"] && ! $done } {
    expect {
        -i $spawn_id_rconsole

        "NVTS* 9734 *_VT_" {
            write_log $expect_out(buffer)
            write_message "$DSPMSG -s 1 $CATALOG 35 '# Connecting to %s.\n' \"$HMCNAME\" 2>/dev/null"
            set done 1
        }
        "Open in progress" {
            write_log $expect_out(buffer)
            write_message "$DSPMSG -s 1 $CATALOG 35 '# Connecting to %s.\n' \"$HMCNAME\" 2>/dev/null"
            set done 1
    }
        timeout { 
            nc_msg "$PROGRAM Status: timeout in main trying to connect to console with timeout value : $timeout\n"
            write_log $expect_out(buffer)
            write_message "$DSPMSG -s 1 $CATALOG 10 '%s: timeout\n' \"$PROGRAM\" 2>/dev/null" 
            set rc 1
            return
        }
        eof {
            write_log $expect_out(buffer)
            write_message "$DSPMSG -s 1 $CATALOG 11 '%s: cannot connect to %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
            exit 1
        }
    }
}

write_message "$DSPMSG -s 1 $CATALOG 36 '# Connected\n' 2>/dev/null" 

# check power status. The methods are different on HMC and AIX.
if { ![string compare $CTRLTYPE "HMC"] || ![string compare $CTRLTYPE "IVM"] } {
    write_message "$DSPMSG -s 1 $CATALOG 37 '# Checking for power off.\n' 2>/dev/null"
    run_lssyscfg
    if { ([string compare "$msg" "Off"] == 0) || ([string compare "$msg" "Not Activated"] == 0) } {
        write_message "$DSPMSG -s 1 $CATALOG 40 '# Power off complete.\n' 2>/dev/null"
    } else { 
        #
        # power off the node
        #
        write_message "$DSPMSG -s 1 $CATALOG 41 '# Power off the node.\n' 2>/dev/null"

        if { $immed_flag } {
            set rc [catch {eval exec $BINPATH/chsysstate -r lpar -o shutdown -m \"$manage\" --immed -n \"$node\"} msg]
        } else {
            set rc [catch {eval exec $BINPATH/chsysstate -r lpar -o shutdown -m \"$manage\" -n \"$node\"} msg]
        }

        if { $rc } {
            write_message "$DSPMSG -s 1 $CATALOG 42 '%s: cannot power off %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
            nc_msg "$PROGRAM Status: error from chsysstate command\n"
            write_message "$DSPMSG -s 1 $CATALOG 39 '%s: Error : %s\n' \"$PROGRAM\" \"$msg\" 2>/dev/null"
            exit 1
        }

        write_message "$DSPMSG -s 1 $CATALOG 43 '# Wait for power off.\n' 2>/dev/null"

        #   
        # chsysstate will return a successful result if it was able to pass the power
        # command from the HMC to the node, but the node may not be powered off yet.  Need
        # to query to make sure the node is off before we continue
        #   
        set done 0
        set query_count 0
        set timeout 600
        set timeout [change_timeout $timeout]

        while { ! $done } {
            if { $query_count > $timeout } {
                write_message "$DSPMSG -s 1 $CATALOG 45 '%s: Timed out waiting for power off of %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
                nc_msg "$PROGRAM Status: error from lssyscfg command : \"$msg\"\n"
                exit 1
            }

            run_lssyscfg 

            #
            # separate the nodename from the query status
            #
            if { ([string compare "$msg" "Off"] == 0) || ([string compare "$msg" "Not Activated"] == 0) } {
                write_message "$DSPMSG -s 1 $CATALOG 40 '# Power off complete.\n' 2>/dev/null"
                set done 1
                continue
            }

            incr query_count 

            sleep 1
        }
    }

# executing chsysstate on the IVM changes the partition profile's boot_mode so
# we need to extract this boot_mode value before we execute chsysstate in case
# we need to revert back to its original state later on
    if { $CTRLTYPE == "IVM" } {
        nc_msg "$PROGRAM Status: get boot_mode start\n"

        set LANG "C"
        if {[info exists env(LC_ALL)]} {
            set LANG $env(LC_ALL)
        }

        set env(LC_ALL) "C"
        set rc [catch {eval exec $BINPATH/lssyscfg -r prof -m \"$manage\" --filter lpar_names=\"$node\" -F boot_mode} bmode_original]
        set env(LC_ALL) "$LANG"

        if { $rc } {
            write_message "$DSPMSG -s 1 $CATALOG 88 '%s: Unable to determine machine boot mode\n' \"$PROGRAM\" 2>/dev/null"
            nc_msg "$PROGRAM Status: error from lssyscfg command\n"

            # Execute lssyscfg again so that we can display the error message in its native locale.
            set rc [catch {eval exec $BINPATH/lssyscfg -r prof -m \"$manage\" --filter lpar_names=\"$node\" -F boot_mode} bmode_original]

            write_message "$DSPMSG -s 1 $CATALOG 39 '%s: Error : %s\n' \"$PROGRAM\" \"$bmode_original\" 2>/dev/null"
            exit 1
        }
    }

    if { $list_disk == 1 } {
        nc_msg "$PROGRAM Status: Power on to SMS.\n"
        set rc [catch {eval exec $BINPATH/chsysstate -r lpar -o on -b sms -m \"$manage\" -n \"$node\" -f \"$profile\"} msg]

    } else {
        write_message "$DSPMSG -s 1 $CATALOG 46 '# Power on %s to Open Firmware.\n' \"$HMCNAME\" 2>/dev/null"
        set rc [catch {eval exec $BINPATH/chsysstate -r lpar -o on -b of -m \"$manage\" -n \"$node\" -f \"$profile\"} msg]
    }

    nc_msg "$PROGRAM Status: wait for power on\n"

    if { $rc } {
        write_message "$DSPMSG -s 1 $CATALOG 47 '%s: cannot power on %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
        nc_msg "$PROGRAM Status: error from chsysstate command\n"
        write_message "$DSPMSG -s 1 $CATALOG 39 '%s: Error : %s\n' \"$PROGRAM\" \"$msg\" 2>/dev/null"
        exit 1
    }
#
# Verify node is powered on before continuing
#
    set done 0
    set query_count 0
    set timeout 600
    set timeout [change_timeout $timeout]
    while { ! $done } {
        if { $query_count > $timeout } {
            write_message "$DSPMSG -s 1 $CATALOG 49 '%s: Timed out waiting for power on of %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
            nc_msg "$PROGRAM Status: error from lssyscfg command : \"$msg\" \n"
            exit 1
        }

        run_lssyscfg
        #
        # separate the nodename from the query status
        #
        if { ([string compare "$msg" "Open Firmware"] == 0) || ([string compare "$msg" "Open firmware"] == 0) } {
            write_message "$DSPMSG -s 1 $CATALOG 48 '# Power on complete.\n' 2>/dev/null"
            set done 1
            continue
        }
        incr query_count

        sleep 1
    }

# executing chsysstate on the IVM changes the partition profile's boot_mode so
# we need to either revert back to its original state (when no network boot is
# requested) or change it to "norm" so that when the install completes it
# doesn't reboot into SMS or open firmware.
    if { $CTRLTYPE == "IVM" } {
      if { $list_disk == 1 } {
        set rc [catch {eval exec $BINPATH/chsyscfg -r prof -m \"$manage\" -i \"lpar_name=$node,boot_mode=$bmode_original\"} msg]
      } else {
        set rc [catch {eval exec $BINPATH/chsyscfg -r prof -m \"$manage\" -i \"lpar_name=$node,boot_mode=norm\"} msg]
      }

      if { $rc } {
        write_message "$DSPMSG -s 1 $CATALOG 89 '%s: Unable to change machine boot mode\n' \"$PROGRAM\" 2>/dev/null"
        nc_msg "$PROGRAM Status: warning: error from chsyscfg command\n"
        write_message "$DSPMSG -s 1 $CATALOG 39 '%s: Error : %s\n' \"$PROGRAM\" \"$msg\" 2>/dev/null"
      }
    }
} else {
    set timeout 5
    set timeout [change_timeout $timeout]
    write_message "$DSPMSG -s 1 $CATALOG 90 '# Checking for OF prompt.\n' 2>/dev/null"
    nc_msg "$PROGRAM Status: check for OF prompt\n"
    set command "\r"
    send_command
    expect {
        -i $spawn_id_rconsole \
        -re "0 >" {
            set of_ok 1
            write_message "$DSPMSG -s 1 $CATALOG 91 '# Found OF prompt, will not reboot the node.\n' 2>/dev/null"
            nc_msg "$PROGRAM Status: found OF prompt\n"
        }
        timeout {
            nc_msg "timeout waiting for OF prompt; rebooting\n"
            write_message "$DSPMSG -s 1 $CATALOG 108 '# Timeout waiting for OF prompt; rebooting.\n' 2>/dev/null"
            set of_ok 0
        }
        eof {
            nc_msg "cannot checking OF prompt; rebooting\n"
            set of_ok 0
        }
    }

    if { $of_ok == 0 } {
        reboot
    } 
}

set done 0
set timeout 200
set timeout [change_timeout $timeout]
nc_msg "$PROGRAM Status: Check for active console.\n"
nc_msg "DONE: $done.\n"
while { ! $done } {
    if { $of_ok == 1 } {
#If we are in OF prompt, send \n to re-active console
        set command "\r"
        send_command
    }
    expect {  
        -i $spawn_id_rconsole
        -re "(.*)\[SCSI|scsi\](.*)0 >" {
            write_log $expect_out(buffer)
            nc_msg "$PROGRAM Status: active console\n"
            set done 1
        }
        -re "PowerPC Firmware(.*)SMS(.*)" {
            write_log $expect_out(buffer)
            nc_msg "$PROGRAM Status: SMS active console\n"
            set done 1
        } 
        -re "To select this console as the active console press 0" {
            write_log $expect_out(buffer)
            nc_msg "$PROGRAM Status: selecting active console\n"
            exec sleep 1
            set command "0"
            send_command
        }
        -re "Press 0 to select this console.*as the active console" {
            write_log $expect_out(buffer)
            nc_msg "$PROGRAM Status: selecting active console\n"
            exec sleep 1
            set command "0"
            send_command
        }
        -re "(.*)elect this consol(.*)" {
            write_log $expect_out(buffer)
            nc_msg "$PROGRAM Status: selecting active console\n"
            exec sleep 1
            set command "0"
            send_command 
        }
# following is for AIX env.
        -re "English|French|German|Italian|Spanish|Portuguese|Chinese|Japanese|Korean" {
            nc_msg "$PROGRAM Status: Languagae Selection Panel received\n"
            exec sleep 1
            send -i $spawn_id_rconsole "2\r"
        }
        -re "'admin'" {
            nc_msg "$PROGRAM Status: password prompt received\n"
            if { $of_pswd != "" } {
                if { $pswd_prompt_count == 0 } {
                    incr pswd_prompt_count 1
                    exec sleep 1
                    send -i $spawn_id_rconsole "$of_pswd\r"
                } else {
                    nc_msg "$PROGRAM Status: password invalid.  Ensure the FSP 'admin' account password set with -p flag is correct\n"
                    write_message "$DSPMSG -s 1 $CATALOG 104 '%s: Ensure the FSP 'admin' account password set with -p flag is correct\n' \"$PROGRAM\" 2>/dev/null"
                    clean_exit 1
                }
            } else {
                nc_msg "$PROGRAM Status: no password available - set the FSP 'admin' account password with -p flag and invoke the command again\n"
                write_message "$DSPMSG -s 1 $CATALOG 105 '%s: Set the FSP 'admin' account password with -p flag and invoke the command again\n' \"$PROGRAM\" 2>/dev/null"
                clean_exit 1
            }
        }
        -re "Invalid Password" {
            nc_msg "$PROGRAM Status: password invalid.  Ensure the FSP 'admin' account password set with -p flag is correct\n"
            write_message "$DSPMSG -s 1 $CATALOG 104 '%s: Ensure the FSP 'admin' account password set with -p flag is correct\n' \"$PROGRAM\" 2>/dev/null"
            clean_exit 1
        }
        -re "0 >" {
            nc_msg "$PROGRAM Status: at ok prompt\n"

            # If node was a JS22 blade, reset the boot mode
            #
            if { $js22_blade } {
                nc_msg "$PROGRAM Status: Resetting boot mode for POWER6 blade\n"
                set rc [catch {eval exec $DSMDSMBINPATH\dpower -n \"$node|$ctrlpoint_type|$ctrlpoint|$optval|$HWPW\" setnormal} msg]

                if { $rc } {
                    nc_msg "dpower query failure detected\n"
                    nc_msg "$msg\n"
                }
            }

            set done 1
        }
        timeout {
            nc_msg "$PROGRAM Status: timeout in main checking for active console with timeout value : $timeout\n"
            write_log $expect_out(buffer)
            write_message "$DSPMSG -s 1 $CATALOG 50 '%s: timeout; exiting\n' \"$PROGRAM\" 2>/dev/null"
            exit 1
        }
        eof {
            write_log $expect_out(buffer)
            write_message "$DSPMSG -s 1 $CATALOG 11 '%s: cannot connect to %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
            exit 1
        }
    }
}

if { $list_disk == 1 } {
    get_disk_info_sms
}

global phandle

# 
# Call get_phandle to gather information for all the supported network adapters
# in the device tree.
#
get_phandle

if { $rc } {
    if { [info exists env(LPAR_NETBOOT_3EXEC)] } {
	set loop_exec 3
	if { [string is int $env(LPAR_NETBOOT_3EXEC)] && $env(LPAR_NETBOOT_3EXEC) > $loop_exec } {
            set loop_exec $env(LPAR_NETBOOT_3EXEC)
		
	}
        set query_count 0

        while { $query_count < $loop_exec } {
            poweroff-on
            get_phandle
            if { $rc } {
                incr query_count
            } elseif { $rc == 0 } {
                break
            }
        }
    }
   
    if { $rc } {
        write_message "$DSPMSG -s 1 $CATALOG 51 '%s: Unable to obtain network adapter information.  Quitting.\n' \"$PROGRAM\" 2>/dev/null"
        exit 1
    }
}

# Call multiple_open-dev to circumvent firmware OPEN-DEV failure
multiple_open-dev
if { $rc } {
    nc_msg "Unable to create multiple_open-dev.\n"
    write_message "$DSPMSG -s 1 $CATALOG 51 '%s: Unable to obtain network adapter information.  Quitting.\n' \"$PROGRAM\" 2>/dev/null"
    exit 1
}

if { $discovery } {
    write_message "$DSPMSG -s 1 $CATALOG 17 '# Client IP address is %s.\n' \"$client_ip\" 2>/dev/null"
    write_message "$DSPMSG -s 1 $CATALOG 18 '# Server IP address is %s.\n' \"$server_ip\" 2>/dev/null"
    write_message "$DSPMSG -s 1 $CATALOG 19 '# Gateway IP address is %s.\n' \"$gateway_ip\" 2>/dev/null"
    if {$subnetmask_ip != ""} { write_message "$DSPMSG -s 1 $CATALOG 86 '# Subnetmask IP address is %s.\n' \"$subnetmask_ip\" 2>/dev/null" }
}

if { $noboot } { # Display information for all supported adapters
    write_message "$DSPMSG -s 1 $CATALOG 52 '# Getting adapter location codes.\n' 2>/dev/null"
 
    if {[info exists list_type]} {
        set match_pat $list_type
    } else {
        set match_pat ".*"  ;# match anything
    }

    if { $discover_all } { 
        nc_msg "NO_BOOT : DISCOVER_ALL\n"
        for {set i 1} {$i <= $adapter_found} {incr i 1} {
            if {[regexp $match_pat $adap_type($i)] != 0 } {
                set ping_result ""
                set mac_address [get_mac_addr $phandle_array($i)]
                set loc_code [get_adaptr_loc $phandle_array($i)]

                if { $discovery } {
                    toggle_spanning_tree $loc_code $spanning
                    set ping_rc [ping_server $full_path_name_array($i) $phandle_array($i)]
                    nc_msg "$PROGRAM Status: ping_server returns $ping_rc\n"
                    if { $ping_rc != 0 } {
                        set ping_result "unsuccessful"
                    } else {
                        set ping_result "successful"
                    }
                }

                if { $ping_result == "" } {
                    set ping_result "n/a"
                }

                if { $hdr_printed == 0 } {
                    if { $colon } {
                        write_send_user "#Type:Location_Code:MAC_Address:Full_Path_Name:Ping_Result:Device_Type:Size_MB:OS:OS_Version:\n"
                    } else {
                        write_send_user "# Type\t Location Code\t MAC Address\t Full Path Name\t Ping Result\t Device Type\n"
                    }
                    set hdr_printed 1
                }

                if { [string first "vdevice" "$full_path_name_array($i)"] != -1 } {
                    set device_type "virtual"
                } else {
                    set device_type "physical"
                }

                if { $colon } {
                    write_send_user "$adap_type($i)\:$loc_code\:$mac_address\:$full_path_name_array($i)\:$ping_result\:$device_type\:\:\:\:\n"
                } else {
                    write_send_user "$adap_type($i) $loc_code $mac_address $full_path_name_array($i) $ping_result $device_type\n"
                    if { $tmp_filename !="" } {
                        puts $tmp_fh "$adap_type($i) $loc_code $mac_address $ping_result"
                    }
                }
            }
        }

        if { $list_disk == 1 } {
            get_disk_info
        }

    } elseif { $macaddress != "" } {
        nc_msg "NO_BOOT : MACADDRESS SET\n"
        set match 0
        for {set i 1} {$i <= $adapter_found} {incr i 1} {
            set mac_address [get_mac_addr $phandle_array($i)]

            if { [string compare -nocase "$mac_address" "$macaddress"] == 0 } {
                set ping_result ""
                if { $discovery == 1 } {
                    if { $spanning == "on" || $spanning == "off" } {
                        set loc_code [get_adaptr_loc $phandle_array($i)]
                        toggle_spanning_tree $loc_code $spanning
                    }

                    set ping_rc [ping_server $full_path_name_array($i) $phandle_array($i)]
                    if { $ping_rc != 0 } {
                        set ping_result "unsuccessful"
                    } else {
                        set ping_result "successful"
                    }
                }
                set phandle $phandle_array($i)
                set full_path_name $full_path_name_array($i)
                set chosen_adap_type $adap_type($i)

                if { [string first "vdevice" "$full_path_name_array($i)"] != -1 } {
                    set device_type "virtual"
                } else {
                    set device_type "physical"
                }
                
                if { $ping_result == "" } {
                    set ping_result "n/a"
                }

                if { $colon } {
                    write_send_user "#Type:MAC_Address:Full_Path_Name:Ping_Result:Device_Type:Size_MB:OS:OS_Version:\n"
                    write_send_user "$adap_type($i)\:$mac_address\:$full_path_name_array($i)\:$ping_result\:$device_type\:\:\:\:\n"
                } else {
                    write_send_user "# Type \tMAC Address\t Full Path Name\t Ping Result\t Device Type\n"
                    write_send_user "$adap_type($i) $mac_address $full_path_name_array($i) $ping_result $device_type\n"
                    if { $tmp_filename !="" } {
                        puts $tmp_fh "$adap_type($i) N/A $mac_address $ping_result"
                    }
                }
                set match 1
                break
            }
        }

        if { !$match } {
            write_message "$DSPMSG -s 1 $CATALOG 71 '%s: can not find mac address %s.\n' \"$PROGRAM\" \"$macaddress\" 2>/dev/null"
            exit 1
        }

    } elseif { $phys_loc != "" } {
        nc_msg "NO_BOOT : PHYSICAL_LOCATION\n"
        set match 0
        for {set i 1} {$i <= $adapter_found} {incr i 1} {
            set loc_code [get_adaptr_loc $phandle_array($i)]
            if { [string first "$phys_loc" "$loc_code"] != -1 } {
                set ping_result ""
                if { $discovery == 1 } {
                    toggle_spanning_tree $loc_code $spanning
                    set ping_rc [ping_server $full_path_name_array($i) $phandle_array($i)]
                    if { $ping_rc != 0 } {
                        set ping_result "unsuccessful"
                    } else {
                        set ping_result "successful"
                    }
                }

                set phandle $phandle_array($i)
                set full_path_name $full_path_name_array($i)
                set chosen_adap_type $adap_type($i)

                if { [string first "vdevice" "$full_path_name_array($i)"] != -1 } {
                    set device_type "virtual"
                } else {
                    set device_type "physical"
                }

                if { $ping_result == "" } {
                    set ping_result "n/a"
                }

                if { $colon } {
                    write_send_user "#Type:Location_Code:Full_Path_Name:Ping_Result:Device_Type:Size_MB:OS:OS_Version:\n"
                    write_send_user "$adap_type($i)\:$loc_code\:$full_path_name_array($i)\:$ping_result\:$device_type\:\:\:\:\n"
                } else {
                    write_send_user "# Type\t Location Code\t Full Path Name\t Ping Result\t Device Type\n"
                    write_send_user "$adap_type($i) $loc_code $full_path_name_array($i) $ping_result $device_type\n"
                    if { $tmp_filename !="" } {
                        puts $tmp_fh "$adap_type($i) $loc_code N/A $ping_result"
                    }
                }
                set match 1
                break
            }
        }

        if { !$match } {
            write_message "$DSPMSG -s 1 $CATALOG 72 '%s: can not find physical location %s.\n' \"$PROGRAM\" \"$phys_loc\" 2>/dev/null"
            exit 1
        }

    } else {
        nc_msg "NO_BOOT : 1st ADAPTER\n"
        for {set i 1} {$i <= $adapter_found} {incr i 1} {
            if {[regexp $match_pat $adap_type($i)] != 0 } {
                set ping_result "" 
                set mac_address [get_mac_addr $phandle_array($i)]
                set loc_code [get_adaptr_loc $phandle_array($i)]
                if { $discovery } {
                    toggle_spanning_tree $loc_code $spanning
                    set ping_rc [ping_server $full_path_name_array($i) $phandle_array($i)]
                    nc_msg "$PROGRAM Status: ping_server returns $ping_rc\n"
                    if { $ping_rc != 0 } {
                        set ping_result "unsuccessful"
                    } else {
                        set ping_result "successful"
                    }
                }
                if { [string first "vdevice" "$full_path_name_array($i)"] != -1 } {
                    set device_type "virtual"
                } else {
                    set device_type "physical"
                }
                
                if { $ping_result == "" } {
                    set ping_result "n/a"
                }

                if { $colon } {
                    write_send_user "#Type:Location_Code:MAC_Address:Full_Path_Name:Ping_Result:Device_Type:Size_MB:OS:OS_Version:\n"
                    write_send_user "$adap_type($i)\:$loc_code\:$mac_address\:$full_path_name_array($i)\:$ping_result\:$device_type\:\:\:\:\n"
                } else {
                    write_send_user "# Type\t Location Code\t MAC Address\t Full Path Name\t Ping Result\t Device Type\n"
                    write_send_user "$adap_type($i) $loc_code $mac_address $full_path_name_array($i) $ping_result $device_type\n"
                    if { $tmp_filename !="" } {
                        puts $tmp_fh "$adap_type($i) $loc_code $mac_address $ping_result"
                    }
                }
                break;
            }
        }

        if { $list_disk == 1 } {
            get_disk_info
        }
    }

    if { $nopowercycle == 0 } {
        nc_msg "$PROGRAM Status: power off the node after noboot == 1\n"
        if { ![string compare $CTRLTYPE "HMC"] || ![string compare $CTRLTYPE "IVM"]} {
            if { $immed_flag } {
                set rc [catch {eval exec $BINPATH/chsysstate -r lpar -o shutdown -m \"$manage\" --immed -n \"$node\"} msg]
            } else {
                set rc [catch {eval exec $BINPATH/chsysstate -r lpar -o shutdown -m \"$manage\" -n \"$node\"} msg]
            }
         } else {
            # Need to do an dpower query to refresh the HMC classes' internal power states -
            # power off may not be successful otherwise
            #
            set rc [catch {eval exec $DSMDSMBINPATH\dpower -n \"$node|$ctrlpoint_type|$ctrlpoint|$optval|$HWPW\" query_val} msg]
            if { $rc } {
                nc_msg "dpower query failure detected\n"
                nc_msg "$msg\n"
                exit 1
            }

            nc_msg "$PROGRAM Status: power off the node after noboot == 1\n"
            if { $immed_flag } {
                set rc [catch {eval exec $DSMDSMBINPATH\dpower -n \"$node|$ctrlpoint_type|$ctrlpoint|$optval|$HWPW\" off_immediate} msg]
            } else {  
                set rc [catch {eval exec $DSMDSMBINPATH\dpower -n \"$node|$ctrlpoint_type|$ctrlpoint|$optval|$HWPW\" off} msg]
            }
            if { $rc } {
                nc_msg "cannot power off node $node\n"
                nc_msg "$msg\n"
                exit 1
            }
         }

        if { $rc } {
            write_message "$DSPMSG -s 1 $CATALOG 42 '%s: cannot power off %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
            nc_msg "$PROGRAM Status: error from chsysstate command\n"
            write_message "$DSPMSG -s 1 $CATALOG 39 '%s: Error : %s\n' \"$PROGRAM\" \"$msg\" 2>/dev/null"
            exit 1
        }
    }
} else {  # Do a network boot
    write_message "$DSPMSG -s 1 $CATALOG 52 '# Getting adapter location codes.\n' 2>/dev/null"

    if {[info exists list_type]} {
        set match_pat $list_type
    } else {
        set match_pat ".*"  ;# match anything
    }

    # 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 == 1 } {
        nc_msg "BOOT : DISCOVERY_ALL\n"
        for {set i 1} {$i <= $adapter_found} {incr i 1} {
            if {[regexp $match_pat $adap_type($i)] != 0 } {
                if { $spanning == "on" || $spanning == "off" } {
                    set loc_code [get_adaptr_loc $phandle_array($i)]
                    toggle_spanning_tree $loc_code $spanning
                }

                set ping_rc [ping_server $full_path_name_array($i) $phandle_array($i)]
                nc_msg "$PROGRAM Status: ping_server returns $ping_rc\n"

                # if ping was successful, then use that adapter for lpar_netboot
                if { $ping_rc == 0 } {
                    set phandle $phandle_array($i)
                    set full_path_name $full_path_name_array($i)
                    set chosen_adap_type $adap_type($i)
                    break
                }
            } 
        }
    } elseif { $macaddress != "" } {
        nc_msg "BOOT : MACADDRESS SET\n"
        set match 0
        for {set i 1} {$i <= $adapter_found} {incr i 1} {
            set mac_address [get_mac_addr $phandle_array($i)]
            if { [string compare -nocase "$mac_address" "$macaddress"] == 0 } {
                if { $discovery == 1 } {
                    if { $spanning == "on" || $spanning == "off" } {
                        set loc_code [get_adaptr_loc $phandle_array($i)]
                        toggle_spanning_tree $loc_code $spanning
                    }

                    set ping_rc [ping_server $full_path_name_array($i) $phandle_array($i)]
                    if { $ping_rc != 0 } {
                        write_message "$DSPMSG -s 1 $CATALOG 73 '%s: Unable to boot network adapter.\n' \"$PROGRAM\" 2>/dev/null"
                        exit 1
                    }
                }
                set phandle $phandle_array($i)
                set full_path_name $full_path_name_array($i)
                set chosen_adap_type $adap_type($i)
                set match 1
                break
            }
        }
        if { !$match } {
            write_message "$DSPMSG -s 1 $CATALOG 71 '%s: can not find mac address %s.\n' \"$PROGRAM\" \"$macaddress\" 2>/dev/null"
            exit 1
        }
    } elseif { $phys_loc != "" } {
        nc_msg "BOOT : PHYSICAL_LOCATION SET\n"
        set match 0
        for {set i 1} {$i <= $adapter_found} {incr i 1} {
            set loc_code [get_adaptr_loc $phandle_array($i)]

            if { [string first "$phys_loc" "$loc_code"] != -1 } {
                if { $discovery == 1 } {
                    toggle_spanning_tree $loc_code $spanning
                    set ping_rc [ping_server $full_path_name_array($i) $phandle_array($i)]
                    if { $ping_rc != 0 } {
                        write_message "$DSPMSG -s 1 $CATALOG 73 '%s: Unable to boot network adapter.\n' \"$PROGRAM\" 2>/dev/null"
                        exit 1
                    }
                }
                set phandle $phandle_array($i)
                set full_path_name $full_path_name_array($i)
                set chosen_adap_type $adap_type($i)
                set match 1
                break
            }
        }
        if { !$match } {
            write_message "$DSPMSG -s 1 $CATALOG 72 '%s: can not find physical location %s.\n' \"$PROGRAM\" \"$phys_loc\" 2>/dev/null"
            exit 1
        }
    } else {
        nc_msg "BOOT : 1st ADAPTER\n"
        #
        # Use the first ethernet adapter in the
        # device tree.
        #
        for {set i 1} {$i <= $adapter_found} {incr i 1} {
            if { $adap_type($i) == $list_type } {
                if { $discovery == 1 } {
                    if { $spanning == "on" || $spanning == "off" } {
                        set loc_code [get_adaptr_loc $phandle_array($i)]
                        toggle_spanning_tree $loc_code $spanning
                    }

                    set ping_rc [ping_server $full_path_name_array($i) $phandle_array($i)]
                    if { $ping_rc != 0 } {
                        exit 1
                    }
                }
                set phandle $phandle_array($i)
                set full_path_name $full_path_name_array($i)
                set chosen_adap_type $adap_type($i)
                break
            }
        }
    }

    if { $full_path_name == "" } {
        write_message "$DSPMSG -s 1 $CATALOG 73 '%s: Unable to boot network adapter.\n' \"$PROGRAM\" 2>/dev/null"
        exit 1
    } else {
        write_message "$DSPMSG -s 1 $CATALOG 54 '# Network booting install adapter.\n' 2>/dev/null"
            #Set bootp spanning tree
        if { $spanning == "on" || $spanning == "off" } {
        write_message "$DSPMSG -s 1 $CATALOG 200 '# spanning tree.\n' 2>/dev/null"
        set loc_code [get_adaptr_loc $phandle]
            toggle_spanning_tree $loc_code $spanning
        }
        boot_network
    }

    if { $rc == 0 } {
        write_message "$DSPMSG -s 1 $CATALOG 55 '# bootp sent over network.\n' 2>/dev/null"
        Boot
    } else {
        nc_msg "return code $rc from boot_network\n"
    }

    if { $rc == 5} {
        # Need to retry network boot because of intermittant network failure 
        # after partition reboot.  Force partition to stop at Open Firmware prompt.
        expect {
            -i $spawn_id_rconsole
            -re "(.*)\[SCSI|scsi\](.*)" {
                write_log $expect_out(buffer)
                set command "8"
                send_command 
                sleep 10
            }
            timeout {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 50 '%s: timeout; exiting\n' \"$PROGRAM\" 2>/dev/null"
                exit 1
            }
            eof {
                write_log $expect_out(buffer)
                write_message "$DSPMSG -s 1 $CATALOG 11 '%s: cannot connect to %s\n' \"$PROGRAM\" \"$HMCNAME\" 2>/dev/null"
                exit 1
            }
        }

        write_message "$DSPMSG -s 1 $CATALOG 54 '# Network booting install adapter.\n' 2>/dev/null"
        nc_msg "Retrying network-boot from RESTART-CMD error.\n"
        set done 0
        while { ! $done } {
            boot_network
            if { $rc == 0 } {
                set done 1
            } else {
                # try again in 10 seconds
                sleep 10
            }
        } 
        write_message "$DSPMSG -s 1 $CATALOG 55 '# bootp sent over network.\n' 2>/dev/null"
        Boot
    }
}

#
# mission accomplished, beam me up scotty.
#
if { (!$noboot) && ( $rc == 0 ) } { 
    if { [info exists env(LPAR_NETBOOT_DEBUG_BOOT)] } {
        debug_boot
    }

    write_message "$DSPMSG -s 1 $CATALOG 56 '# Finished.\n' 2>/dev/null" 
}

if { ($noboot) && ($nopowercycle == 0) } {
    set done 0
    set query_count 0
    set timeout 60
    set timeout [change_timeout $timeout]

    while { ! $done } {
        if { ![string compare $CTRLTYPE "HMC"] || ![string compare $CTRLTYPE "IVM"]} {
            run_lssyscfg
            # separate the nodename from the query status                
            #                                                            
            if { ([string compare "$msg" "Off"] == 0) || ([string compare "$msg" "Not Activated"] == 0) } { 
                set done 1                                               
            } 
          } else {
            nc_msg "$PROGRAM Status: Querying for power off\n"
            set rc [catch {eval exec $DSMDSMBINPATH\dpower -n \"$node|$ctrlpoint_type|$ctrlpoint|$optval|$HWPW\" query_val} msg]
            if { $rc } {
                nc_msg "dpower query failure detected\n"
                nc_msg "$msg\n"
                write_message "$DSPMSG -s 1 $CATALOG 98 '%s: power query failure detected\n' \"$PROGRAM\" 2>/dev/null"
                clean_exit 1
            }
            set power_status [split $msg " "]
            if { [lindex $power_status 1] == "0"  } {
                nc_msg "$PROGRAM Status: power off complete\n"
                set done 1
                continue
            }
          }
                                                           
        incr query_count                                             
        if { $query_count > $timeout } {
            nc_msg "$PROGRAM Status: Unable to power off node\n"
            nc_msg "$msg\n"
            write_message "$DSPMSG -s 1 $CATALOG 102 '%s: Unable to power off node\n' \"$PROGRAM\" 2>/dev/null"
            set done 1                                                   
        }                                                            
                                                                     
        sleep 1                                                      
    }                                                                
}

exit $rc
