#!/usr/bin/perl -I/opt/SUNWstade/lib

use Getopt::Std;
use strict;
use Net::Telnet;


   $|=1;
   $SIG{INT} = \&killTest;
   $SIG{TERM} = \&killTest;

   my %Parameters=undef; 
   my %Options;
   my $ip = undef;
   my $password = undef;
   my $port = undef;
   my $iterations = 1000;
   my $fcaddr = undef;
   my $ok;
   my $user_pattern = 0x7e7e7e7e;
   my $pattern_type = "critical";
   my $gl_init_sync_loss = 0;
   my $gl_init_crc_err = 0;
   my $gl_init_enc_in = 0;
   my $gl_init_loss_sig = 0;


   my $verbose = 0;

   process_args();

   #looks Like we are ready to start issuing commands
   if($verbose){
      print "Connect to $ip\n";
   }
   my($t) = new Net::Telnet (
             errmode => "return",
             Timeout   => 30,
             Prompt    => '/.*\:admin+\>/',
             );

   if (!defined($t->open($ip))) 
   {
     # failed to open ip
      print "Cannot open IP $ip\n";
      print "Probable_Cause(s)\n";
      print "<Invalid IP>\n";
      print "<Ethernet disconnected from switch>\n";
      print "<No power to switch>\n";
      print "<Bad switch>\n";
      print "Recommended_Action(s)\n";
      print "<Check IP address>\n";
      print "<Check ethernet connection>\n";
      print "<Check power to switch>\n";
      print "<Replace switch>\n";

      exit(1);
   }

   if($verbose){
      print "Opened $ip\n";
   }

   $t->login("admin", $password);

   if ($t->errmsg()) 
   {
      my($errout) = $t->errmsg();

      print "$errout\n";
      print "Probable_Cause(s)\n";
      print "<Another user may be logged into the switch>\n";
      print "<Incorrect password given>\n";
      print "Recommended_Action(s)\n";
      print "<Check to see if someone is logged into switch>\n";
      print "<Check to see if a user has a telnet session active to this switch>\n";
      print "<Check for correct password>\n";

      exit(1);
   }
   if($verbose){
      print "Logged into $ip\n";
   }
   

   # clear any port errors
   # This will clear some of the port counters so you 
   # want to clear the errors before you get the original port counters
   clear_port_errors();

   get_port_counters();


   run_loopback();

   check_sensors();

   compare_port_counters();

   if($verbose){
      print "Close $ip\n";
   }

   $t->close;

   #sleep in order for logout to clean up
   #prevents failures from occurring if looping test
   sleep(5);
 
   exit(0);
##################### END OF MAIN #############################################



sub printUsage {
  print "Usage: brocade [-vu] [-o \"dev=<port:ip>|ip=<address>|port=<Port number>|iterations=<number>|passwd=<Switch password>\"\n";
  print "Standard arguments:\n";
  print "-u      list usage\n";
  print "-v      verbose mode\n";
  print "-o      Test specific options\n";
  print "\n";

  print "ip         =<Switch IP address>   IP address of switch to test.\n";
  print "port       =<Port number to test> Switch port to test.\n";
  print "passwd     =<switch Password>     Password for admin switch login.\n";
  print "iterations =<number of loops>     number of times to run loopback tests.\n";
  print "dev        =<port:ipddress>       Switch port and IP address to test.\n";
  print "                                  (Combines IP and port options together.)\n";
  
  print "IE:\n";
  print "brocadetest -v -o \"dev=5:10.0.0.1|passwd=switchpassword|iterations=10000000\"\n";
  print "brocadetest -v -o \"port=5|ip=10.0.0.1|passwd=switchpassword|iterations=10000\"\n";

}

##################################################################


sub killTest{
  print "Test has received kill signal\n";
  print "Exiting\n";
  exit(1);

}
##################################################################
# run loopback on port
sub run_loopback {
   
   my(@l);

   my($starttime) = time;

   my($found_port);

   $found_port = 0;


   # must find out what type of port we are on
   @l = $t->cmd("switchshow");
   
   foreach my $line (@l) 
   {
      if($line=~/port\s*$port:/)
      {
	 if($line=~ /L-Port/)
	 {
	    $found_port = 1;
	    if($verbose){
	       print "L port detected\n";
	    }
	    

	    run_loopport_test();
	 }
	 elsif($line =~ /E-Port/)
	 {
	    $found_port = 1;
	    if($verbose){
	      print "E port detected\n";
	    }

	    run_spinFab_port();
	 }
	 elsif($line =~ /F-Port/)
	 {
	    $found_port = 1;
	    print "F port detected\n";
	    print "No Test availble for F ports\n";
	    print "Probable_Cause(s)\n";
	    print "<port type unsupported>\n";
	    print "<Bad GBIC>\n";
	    print "Recommended_Action(s)\n";
	    print "<Insert a loopback plug into port and retest>\n";
	    print "<Replace GBIC>\n";
	    exit(4);


	 }
	 elsif($line =~ /Loopback/)
	 {
	    $found_port = 1;
	    if($verbose){
	       print "port is in loopback mode\n";
	    }
	    run_crossport_test();


	 }
	 elsif($line =~ /Disabled/)
	 {
	    $found_port = 1;
            print "This port is disabled\n";
            print "$line\n";
            print "Probable_Cause(s)\n";
            print "<Port was manually disabled>\n";
            print "<Bad switch>\n";
            print "Recommended_Action(s)\n";
            print "<Enable this port by logging into switch and issuing the command:\n";
            print "portEnable $port>\n";
            print "<Replace switch>\n";



            exit(100);

	 }
	 else
	 { 
	    $found_port = 1;
	    print "Loopback not supported on this port type\n";
	    print "$line\n";
	    print "Probable_Cause(s)\n";
	    print "<Port not connected>\n";
	    print "<Unknown port type>\n";
	    print "<Bad GBIC>\n";
	    print "<Bad switch>\n";
	    print "Recommended_Action(s)\n";
	    print "<Insert a loopback plug into port and retest>\n";
	    print "<Run linktest>\n";
	    print "<Replace GBIC>\n";



	    exit(3);
	 }
	 last; # break out of for each  
      }
   }	 
   if(!$found_port)
   {
     print "Couldn't determine port type\n";
     print "@l\n";
     print "Probable_Cause(s)\n";
     print "<downlevel firmware>\n";
     print "<Unknown port type>\n";
     print "<Bad GBIC>\n";
     print "<Bad switch>\n";
     print "Recommended_Action(s)\n";
     print "<Run revision check>\n";
     print "<Insert a loopback plug into port and retest>\n";
     print "<Run linktest>\n";
     print "<Replace GBIC>\n";
     exit(5);


   }

   my($testtime) = time - $starttime ;
   
   if($verbose){
      print("Loopback took $testtime seconds to run.\n");
   }






}
##################################################################
sub run_loopport_test{

   my(@l);
   my($line);
   my($ok);
   my($prematch, $match);

   if($verbose){
      print "Running loopport test\n";
   }

   my($timeout);

   # adjust telnet timeout for loopback 
   # add seconds to run_time as a buffer
   $timeout = ($iterations * .051) + 20;
   $t->timeout($timeout);

   
   # must clear some of the error counters since loopport test clears 
   # some of the counters. It doesn't clear them all...
   $gl_init_enc_in = 0;
   $gl_init_crc_err = 0;



   if($verbose){
      print "Sending command: loopPortTest $iterations,$port\n";
   }
   $ok = $t->print("loopPortTest $iterations,$port");

   $match = "INIT";
   $prematch= "INIT";

   ($prematch, $match) = $t->waitfor('/.*admin\>|Diags.*/');

   if($match =~ /Diags.*/)
   {
      # Test must have failed
      # send quit for diag results
      print "Detected loop failure\n";
      print "$prematch\n";

      #send a return to get to stop test menu
      $ok = $t->print("\n");
      #send a q to quit test
      @l = $t->cmd("q");

      loop_failed_exit();
   }
   if($verbose){
      print "$prematch $match\n";
   }
   # if here, test pased
   if($match =~ /.*admin/)
   {
      if($prematch =~ /passed/i)
      {
	 if($verbose){
            print "Test Passed\n";
	 }
      }
      else
      {
        #Test didn't pas??
	print "$prematch\n";
	loop_failed_exit();
      }
   }
   else
   {
     # we didn't get either response?
     loop_failed_exit();
   }


}
##################################################################
sub run_spinFab_port{

   my(@l);
   my($line);
   my($prematch, $match);


   if($verbose){
      print "Running spinFab test\n";
   }



   # must update iterations since command runs x million iterations
   $iterations = $iterations/  100;
   $iterations = int($iterations);
   if(!$iterations)
   {
      $iterations = 1;
   }

   my($timeout);

   # adjust telnet timeout for loopback 
   # add seconds to run_time as a buffer
   # Takes about 6 seconds per iteration
   $timeout = ($iterations * 7) + 20;
   $t->timeout($timeout);


   if($verbose){
      print "Number of megabit transfers = $iterations\n";
      print "Running command: spinFab $iterations,$port,$port\n";
   }

   $ok = $t->print("spinFab $iterations,$port,$port");

   $match = "INIT";
   $prematch= "INIT";
   ($prematch, $match) = $t->waitfor('/.*admin\>|Pt.*/');
    
   if($match =~ /Pt$port.*/)
   {
      # Test must have failed
      
      print "Detected loop failure\n";
      print "$match\n";
      #send a return to get to stop test menu
      $ok = $t->print("\n");
      #send a q to quit test
      @l = $t->cmd("q");

      #let test to stop
      #sleep(10);


      loop_failed_exit();
   }

   # if here, test pased
   if($match =~ /.*admin/)
   {
     
      if($prematch =~ /passed/i)
      {
	 if($verbose){
            print "Test Passed\n";
	 }
      }
      else
      {
        #Test didn't pas??
	print "$prematch\n";
	loop_failed_exit();
      }
   }
   else
   {
     # we didn't get either response?
     print "Didn't get response\n";
     loop_failed_exit();
   }



}
##################################################################

sub loop_failed_exit{

   my(@l);
   my($line);


   print "Test failed for port $port on IP: $ip\n";

   #get diag results
   # reset timeout
   $t->timeout(30);


   print "Get diagshow\n";

   $ok = $t->print("diagShow");
    
   my($prematch, $match) = $t->waitfor('/Total Diag Frames Rx.*/');
   print "$prematch";
   print "$match\n";

   print "Probable_Cause(s)\n";
   print "<Bad device on loop>\n";
   print "<Bad GBIC>\n";
   print "Recommended_Action(s)\n";
   print "<Insert a loopback plug into port and retest>\n";
   print "<Replace GBIC>\n";



   exit(2);
}


##################################################################
sub process_args{



   my $ok = getopts('seykruvdlfno:', \%Options);
   my $numargs=keys(%Options);
   
   $verbose = $Options{"v"};


   my $optstring = $Options{"o"};

   #remove password from output
   $optstring =~ s/passwd=[^\s\=\|]+/passwd=xxxxxxx/; #remove passwd from output

   if($verbose){
      print "Called with options: $optstring\n";
   }
   
   #check to see if usage needs to be displayed
   if( !$ok || $numargs < 1 || $Options{"u"} eq 1 )
   {
      printUsage();
      exit();
   }


   #parse all -o options 
   #disable all Options and specify valid parameters

   @Parameters{"ip",
	       "port",
	       "passwd",
	       "iterations",
	       "userpattern",
	       "selectpattern",
	       "dev"}=
	       (undef,undef,undef,1000,0x7e7e7e7e,"critical",undef); 


   # split up indivdual specific parameters
   my $i;
   my $key;
   my $value;
   my $match;
   my $validOption;

   my @tmpParams = split(/\|/,$Options{"o"});


   #loop through params
   foreach $i (@tmpParams)
   { 
      ($key, $value) = split(/=/,$i);

      # Remove any spaces from key and values.

      $key =~ s/\s*//g;
      $value=~ s/\s*//g;


      $match=undef;
      foreach $validOption (keys(%Parameters)) 
      {
         if ($key eq $validOption)
	 {
            $match = $validOption;
         }
      }
      #if the key does not match a valid option then the match does not get difined
      if(! (defined($match)))
      {
         print "$key is an invalid option.\n".
               "brocadetest did not execute.\n". 
               "brocadetest exiting.\n";
	       printUsage();
         exit(1);
      } 
      else  
      { 
         #finally stick the value in the @#$'n hash
         $Parameters{$key}=$value; 
      }
   }

   $ip = $Parameters{ip};
   $password = $Parameters{passwd};
   $port = $Parameters{port};


   if($Parameters{iterations} ne undef)
   {
      $iterations = $Parameters{iterations};
   }

   if($Parameters{dev} ne undef)
   {
      ($port,$ip,$fcaddr) = split(/:/,$Parameters{dev});
   }

   $user_pattern = $Parameters{userpattern};
   $pattern_type = $Parameters{selectpattern};


   #check to make sure values are OK
   my $param=undef;
   while(($param,$value) = each(%Parameters)) 
   {
      if($param=~/health_check|fast_test|fast_find|find/)
      {
         if(!($value =~/(en)|(dis)able/i))
	 {
            print "$param=$value is an invalid option.\n".
                 "brocadetest did not execute.\n". 
                 "brocadetest exiting.\n";
	    printUsage();
            exit(1);
         }
      } 
   }

   #if debug print out parameters
   if($Options{"d"})
   { 
     print "INPUT PARAMETERS:\n";
     while (($key,$value) = each(%Parameters))
     {
	if($key ne "passwd")
	{
           print "$key = $value \n";
	}
	else
	{
	   print "$key: xxxxxx\n";
	}
     }
   }
   #Done Parsing -o options



}
##################################################################

sub clear_port_errors{

   # Clear any errors that may be present on this port
   if($verbose){
      print "Clear port errors: send diagClearError $port\n";
   }
   my(@l) = $t->cmd("diagClearError $port");

   # give time for clearerror to work
   # otherwise when we do a portshow it doesn't return correct port type
   # if there was a failure before
   
   sleep(4);
   if($verbose){
      print "Port errors cleared\n";
   }

}
##################################################################

sub run_crossport_test{


   my(@l);
   my($line);
   my($prematch, $match);

   if($verbose){
      print "Running command: CrossPortTest $iterations,1\n";
      print "Note: You should only have a loopback on port $port.\n";
      print "If you have more than one loopback installed,\n";
      print "this test may report false errors.\n";
   }
   my($timeout);

   # adjust telnet timeout for loopback 
   # add seconds to run_time as a buffer
   # Takes about .051 seconds per iteration
   $timeout = ($iterations * .06) + 20;
   $t->timeout($timeout);


   # must clear some of the error counters since crossport test clears 
   # some of the counters. It doesn't clear them all...
   $gl_init_enc_in = 0;
   $gl_init_crc_err = 0;

   $ok = $t->print("CrossPortTest $iterations,1 ");

   ($prematch, $match) = $t->waitfor('/.*admin\>|Pt.*/');
    
   if($match =~ /Pt$port.*/)
   {
      # Test must have failed
      
      print "Detected loop failure\n";
      print "$match\n";
      #send a return to get to stop test menu
      $ok = $t->print("\n");
      #send a q to quit test
      @l = $t->cmd("q");

      #let test to stop
      #sleep(10);


      loop_failed_exit();
   }

   # if here, test pased
   if($match =~ /.*admin/)
   {
     
      if($prematch =~ /passed/i)
      {
         if($verbose){
            print "Test Passed\n";
	 }
      }
      else
      {
        #Test didn't pas??
	print "$prematch\n";
	loop_failed_exit();
      }
   }
   else
   {
     # we didn't get either response?
     print "Didn't get response\n";
     loop_failed_exit();
   }


}
##################################################################

sub get_port_counters(){

   my(@l);
   @l = $t->cmd("portErrShow");
   foreach my $line (@l) 
   {
      if($line =~ /^\s*$port: /)
      {
	 # This is the port we are looking for

	 my ($myport, $counters) = split(/^\s*$port:/,$line);

	 my ($first, $ftx, $frx, $encin, $crcerr, $tooshrt, $toolong, $badeof, $encout, $discc3, $linkfail, $losssync, $losssig, $frjt, $fbsy) = split(/ +/,$counters);

	 $gl_init_sync_loss  = $losssync;
	 $gl_init_crc_err = $crcerr;
	 $gl_init_enc_in = $encin;
	 $gl_init_loss_sig = $losssig;

      }
	
   }
}
##################################################################

sub compare_port_counters(){

   my ($first, $ftx, $frx, $encin, $crcerr, $tooshrt, $toolong, $badeof, $encout, $discc3, $linkfail, $losssync, $losssig, $frjt, $fbsy) ;
   my(@l);
   @l = $t->cmd("portErrShow");
   foreach my $line (@l) 
   {
      if($line =~ /^\s*$port: /)
      {
	 # This is the port we are looking for
	 my ($myport, $counters) = split(/^\s*$port:/,$line);
	 ($first, $ftx, $frx, $encin, $crcerr, $tooshrt, $toolong, $badeof, $encout, $discc3, $linkfail, $losssync, $losssig, $frjt, $fbsy) = split(/ +/,$counters);

      }

      	
   }



   if($encin != $gl_init_enc_in)
   {
      print "Detected encoding errors inside of frames during test.\n";
      print "Original = $gl_init_enc_in, Current = $encin.\n";
      print "Probable_Cause(s)\n";
      print "<Bad port>\n";
      print "<Bad gbic>\n";
      print "<Bad fiber cable\n";
      print "Recommended_Action(s)\n";
      print "<Run link test on this port>\n";
      print "<Replace gbic>\n";
      print "<Replace fiber>\n";


      exit(1);
   }



   if($losssig != $gl_init_loss_sig)
   {
      print "Detected a loss of signal error during test.\n";
      print "Original = $gl_init_loss_sig, Current = $losssig.\n";
      print "Probable_Cause(s)\n";
      print "<Bad port>\n";
      print "<Bad gbic>\n";
      print "<Bad fiber fiber cable\n";
      print "Recommended_Action(s)\n";
      print "<Run link test on this port>\n";
      print "<Replace gbic>\n";
      print "<Replace fiber>\n";


      exit(1);
   }

   if($crcerr != $gl_init_crc_err)
   {
      print "Detected a crc error during test.\n";
      print "Original = $gl_init_crc_err, Current = $crcerr.\n";
      print "Probable_Cause(s)\n";
      print "<Bad port>\n";
      print "<Bad gbic>\n";
      print "<Bad fiber fiber cable\n";
      print "Recommended_Action(s)\n";
      print "<Run link test on this port>\n";
      print "<Replace gbic>\n";
      print "<Replace fiber>\n";


      exit(1);
   }

   if($losssync != $gl_init_sync_loss)
   {
      print "Detected a sync loss error during test.\n";
      print "Original = $gl_init_sync_loss, Current = $losssync.\n";
      print "Probable_Cause(s)\n";
      print "<Bad port>\n";
      print "<Bad gbic>\n";
      print "<Bad fiber fiber cable\n";
      print "Recommended_Action(s)\n";
      print "<Run link test on this port>\n";
      print "<Replace gbic>\n";
      print "<Replace fiber>\n";


      exit(1);
   }
}
##################################################################

sub check_sensors(){
   
   my (@l);
   my $line;
   
   # check Fans
   @l = $t->cmd("fanshow");
   
   foreach $line (@l) 
   {
      if($line =~/is OK/)
      {
	 if($verbose)
	 {
	    print "$line";
	 }
      }
      else
      {
	 print "\n*************************\n";
         print "Detected possible bad Fan\n";
	 print "$line\n";
	 print "**************************\n\n";

      }
   }

   # check power supplies
   @l = $t->cmd("psshow");

   foreach $line (@l)
   {  
      if($line)
      { 
      if($line=~/Power Supply/)
      {
         if($line=~/is OK/)
         {
	    if($verbose)
	    {
	       print "$line";
	    }
         }
         else
         {
	    print "\n**********************************\n";
            print "Detected possible bad Power supply\n";
	    print "$line";
	    print "**********************************\n\n";

         }
      }
      }
   }
	
}
##################################################################

