#!/var/opt/STORtools/bin/perl

require  "subroutines.pm";
&st_globals();
$HA_LOGDIR     = "${LOGDIR}/diags";

####################################################################
#
# Fibre Channel Host Adapter port test
# allow the user to choose a port from a menu and run a lbf test
# Usage:  ha_port_test
#
# replaces ha.test
# takes about 4 minutes per port 
#
# 8/30/98 aku create program
# 9/29/98 aku minor fixes
# Copyright (c) 1998  Sun Microsystems Computer Corporation, Inc.
####################################################################
$PROGNAME = "ha_port_test";

$RETCODE = 0;
$| = 1;                 # buffer to 1 line
$valid_choice = "";         # init var

&check_root_access( $PROGNAME );
&proc_cli;

&make_port_list;

$total_on_ports = $#LD_ON_PORTS + 1;
$total_off_ports = $#LD_OFF_PORTS + 1;
$max_ports = $total_on_ports + $total_off_ports;

# get a count of stale DMA errors in ${SYSLOG} from previous test
# ignore those errors.

my $expected_dma_errors = 0;
my $verbose = 0;
$DMA_ERRORS = &check_dma_errors( $expected_dma_errors, $verbose );

if (defined $ALL) {
    &print_menu;
    foreach $port (sort keys %PORT) {
        push @TEST_LIST, $PORT{$port};
    }
    $valid_choice = "TRUE";      # don't enter while loop
}

while ($valid_choice eq "")  {
    &print_menu;
    $choice = &get_response;
    exit if ($choice =~ /^q/i);
    if ($choice =~ /\d+/) {

        if (grep {/,/} $choice) {           # delimiter is , or
            @CHOICE = split(',', $choice);      #  blank
        } else {
            @CHOICE = split(' ', $choice);

        }
    

        foreach $tmp (@CHOICE) {
            ($pt) = $tmp =~ /\s*(\d+)/;
	    #validate response, checking for bad input: ie 1a
            if ((($pt > 0) & ($pt <= $max_ports)) && ($tmp eq $pt)) 
	    {

               push @TEST_LIST, $PORT{$pt-1};   # reconcile number to 0 based array pos.
               $valid_choice = "TRUE";
            } 
	       else {
                print "\n$tmp out of range.\n";
                print "Please select port[s] to test [<1 - $max_ports )> , a, list(1,2...), q ]: ";
		print "\nPress the return key to reselect. \n";
		&get_response;
                undef @TEST_LIST;
                undef $valid_choice;
                next;
            }
        }
    } elsif ($choice =~ /^a/i) {
        foreach $port (sort keys %PORT) {
            push @TEST_LIST, $PORT{$port};
        }
        $valid_choice = "TRUE";
    } elsif ($choice =~ /^l/i) {
        next;
    } else {
        print "Syntax error.  Please re-enter choice.  \n";
        print "Please select port[s] to test [<1 - $max_ports> , a, list(1,2...), q ]: ";
        sleep 2;
    }

}

$SIG{"INT"} = 'int_handler';
$SIG{CHLD} = sub { wait };          # avoid zombies
&exec_test_list;

# wait for all of my children to complete

wait;

&sum_results;

exit $RETCODE;
####################################################################
#               SUBROUTINES
#
####################################################################
####################################################################
# summarize the results by scanning the log files
####################################################################
sub sum_results {
    my $failcode = "FAIL";
    print "\n ******  Test Summary  ****** \n\n";

    my $line;
    foreach $line (@TEST_LIST) {
        my ($port) = $line =~ /(\S+)/;
        my ($ptstat) = $line =~ /\S+\s+(\S+)/;
        $real_port = $port;
        if ($ptstat eq "ONLINE") {
            foreach $p (sort keys %LD_ORIG_PORTS) {
                if ($LD_ORIG_PORTS{$p} eq $port) {
                    $real_port = $p;
                    last;
                }
            }
        }
        my $grc = `/bin/grep ${failcode} ${HA_LOGDIR}/${PROGNAME}.$$.$LOGMARK{$real_port}.*`;
        if ($grc) {
            $RESULT{$real_port} = "FAIL";
            $RETCODE = -1;
        } else {
            $RESULT{$real_port} = "PASS";
        }
        if ($ptstat eq "ONLINE") {
            print "($CNUM{$real_port}) ($SFNUM{$real_port}) $port : \t$RESULT{$real_port} \n";
        } else {
            print "(OFFLINE PORT) $port : \t$RESULT{$real_port}\n";
        }
    }
    my $verbose = 1;
    my $dma_errors = &check_dma_errors( $DMA_ERRORS, $verbose );
    if ( $dma_errors ) {
        print "${RED}A scan of /var/adm/messages detected $dma_errors DMA error(s).${RC}\n";
        print "${RED}Replace offending FC100 HBA immediately.${RC}\n";
    }

    print "\n\n";
    if ( ( $RETCODE == 0 ) && ( $dma_errors == 0 ) ) {
         print "${GREEN} ****** Test Passed ****** ${RC}\n";
    } else {
         print "${RED} ****** Test FAILED ****** ${RC}\n";
    }
}

####################################################################
# print the menu
####################################################################
sub print_menu {
    my $port;
    if (! $ALL) {
        system_clear();
        &st_header();
        print "Host Adapter Test\n";        
        print "-----------------\n";
        print "\n";
    }

    if ($max_ports < 0) {
        $RETCODE = 2;
        print "\n\nNo FC Adapter ports. \n\n" if (! $ALL);
        exit($RETCODE);
    }

    $port_cnt = 0;
    if ($total_on_ports < 0) {
        print "\nNo Online FC Adapter ports. \n" if (! $ALL);
    } else {
        if (! $ALL) {
            print "\n";
            print "Online FC Adapter Ports\n";
            print "-----------------------\n";
        }
        foreach $port (@LD_ON_PORTS) {
            $port_print = $port_cnt+1;
            if (! $ALL) {
                print " [$port_print]\t ($CNUM{$port}) ($SFNUM{$port})\t $LD_ORIG_PORTS{$port} \n";
            }
            $PORT{$port_cnt} = "$LD_ORIG_PORTS{$port}  ONLINE";
            $port_cnt++;
        }
    }

    if ($total_off_ports < 0) {
        print "\n\nNo Offline FC Adapter ports. \n\n" if (! $ALL);
    } else {
        if (! $ALL) {
            print "\n";
            print "Offline FC Adapter Ports\n";
            print "------------------------\n";
        }
        foreach $port (@LD_OFF_PORTS) {
            $port_print = $port_cnt+1;
            print " [$port_print]\t(OFFLINE PORT) \t$LD_ORIG_PORTS{$port} \n" if (! $ALL);
            $PORT{$port_cnt} = "$LD_ORIG_PORTS{$port}  OFFLINE  off${port_print}";
            $port_cnt++;
        }
    }
    if (! $ALL) {
        print "\n\n";
        print " [a] = Test All Ports \n";
        print " [l] = Show this list again \n";
        print "\n\n";
        print "Please select port[s] to test [<1 - $max_ports> , a, list(1,2...), q ]: ";
    }
    
}

####################################################################
# test all ports in the test list
# 
####################################################################
sub exec_test_list {
    my ($port, $p, $real_port);
    foreach $port (@TEST_LIST) {
        @sport = split(' ', $port);
        print "\n\t****** Testing $sport[1] Port: $sport[0] ****** \n";
        $real_port = $sport[0];
        if ($sport[1] eq "ONLINE") {
            foreach $p (sort keys %LD_ORIG_PORTS) {
                if ($LD_ORIG_PORTS{$p} eq $sport[0]) {
                    $real_port = $p;
                    last;
                }
            }
        }
        &lbf_test_5("$real_port $sport[1] $sport[2]");
    }
}


####################################################################
# 5 pass lbf test to given port
#   INPUTS:     physical port name  (OFFLINE/ONLINE)
#   OUTPUTS:    set $RESULT
# 
####################################################################
sub lbf_test_5 {
    my ($port) = @_;
    my $tmprc = 0;
    my $lbf_test = "$BINDIR/lbf ";
    my $logfile;
    my $res;

    my ($phyport) = $port =~ /(\S+)/;
    &st_sync();

LBF_FORK:
    if ($pid = fork) {
        # parent here
        # child process pid is available in $pid
        push @MY_CHILDREN, $pid;
        $LOGMARK{$phyport} = $pid;
    } elsif (defined $pid) {
        # child here
        # parent process pid is available with getppid
        my $parent = getppid;
        my ($portstat) = $port =~ /\S+\s+(\S+)/;
        @lbf_tst_f = "$BINDIR/lbf -t ffffffff -n 1000 -k 64 -c $phyport";
        @lbf_tst_0 = "$BINDIR/lbf -t 00000000 -n 1000 -k 64 -c $phyport";


        if ($portstat eq "OFFLINE") 
	{
	    my ($offptid) = $port =~ /\S+\s+\S+\s+(\S+)/;
            $logfile = "${HA_LOGDIR}/${PROGNAME}.$parent.$$.${offptid}";

	    #check for no ifp or qlc
	    if( !(($phyport =~ /qlc/) || ($phyport =~ /ifp/)))
	    {
               print "\n*** Setting INTERNAL LOOPBACK for $sport[0] ***\n";
               `/usr/sbin/luxadm -e internal_loopback $sport[0]`;
               sleep 1;
	    }
        } else {
            $logfile = "${HA_LOGDIR}/${PROGNAME}.$parent.$$.$SFNUM{$phyport}";
        }
        print "\nPrinting to logfile:  $logfile \n";
        # open a file
        open (LF, ">$logfile");
        my $oldfh = select LF; $| = 1; select $oldfh; # turn off buffering

        # write what you're doing into the file
        # start a test, capture the output

        print ".";


	if( ($phyport =~ /qlc/) || ($phyport =~ /ifp/))
	{
	   # we have a qlc or ifp, use hba_test to test
	   print LF "hba_test $phyport\n";
	   $res = `$BINDIR/hba_test $phyport`;
	   if ($res =~ /fail/i) 
	   {
              print "\n$res\n";
              $tmprc = -1;
           }
	   print LF "$res\n";

	   
	}
	else
	{  
	   # we aren't working with a qlc or ifp so use lbf


           for (my $i =1; $i < 6; $i++) {
               print LF "* pass $i * \n";
               print LF "@lbf_tst_f \n";
               $res = `@lbf_tst_f`;
               if ($res =~ /fail/i) {
                  print "\n$res\n";
                  $tmprc = -1;
               }
               print LF "$res\n";
               print ".";

               print LF "@lbf_tst_0 \n";
               $res = `@lbf_tst_0`;
               if ($res =~ /fail/i) {
                 print "\n$res\n";
                 $tmprc = -1;
              }
               print LF "$res\n";
               print ".";
           }
	}# end of else 

        # if failed, then write output to display
        #   and set return code
        # print output to file
        # exit 

        close(LF);
        if ($tmprc == 0) {
            $RESULT{$phyport} = "Test Passed\n";
        } else {
            $RESULT{$phyport} = "Test FAILED\n";
        }
        if ($portstat eq "OFFLINE") 
	{
	    #check for no ifp or qlc
	    if( !(($phyport =~ /qlc/) || ($phyport =~ /ifp/)))
	    {
         
               print "\n*** UNSETTING INTERNAL LOOPBACK for $sport[0] ***\n";
               `/usr/sbin/luxadm -e no_loopback $sport[0]`;
               sleep 1;
	    }
        }

        exit($tmprc);

    } elsif ($! =~ /No more process/) {
        # EAGAIN, supposedly recoverable fork error
        sleep 5;
        redo LBF_FORK;
    } else {
        # weird fork error
        die "Can't fork:  $! \n";
    }
}

####################################################################
# control c interrupt trap
####################################################################

sub int_handler {
    print "Unbypass offline ports.\n";
    foreach $offport (@LD_OFF_PORTS) {
       if( !(($phyport =~ /qlc/) || ($phyport =~ /ifp/)))
       {
           `/usr/sbin/luxadm -e no_loopback $offport`;
       }
    }
    exit;
}

####################################################################
# control c interrupt trap
####################################################################

sub proc_cli {

    # print the usage
    $usage[0] = "USAGE:  \t$PROGNAME [-all] \n";
    $usage[1] = "\t\t\tall  - test all Host Adapter Loops, no menu \n";

    # init vars
    undef $ALL;
    &set_color( "ON" );

    $arg = shift @ARGV;
    while($arg) {
        if ($arg =~ /-all/) {
            $ALL = "TRUE";
        } elsif ($arg =~ /[?|h]/i) {
            die @usage;
        } else {
            die "\nUndefined Option!\n\n @usage";
        }
        $arg = shift @ARGV;
    }
}
