#!/opt/SUNWstade/bin/perl -I/opt/SUNWstade/lib
#This Program refers to unit indexes volume indexes unit id's and voulume id's
#indexes start at 0 and id's start at 1.
use Getopt::Std;
use Diags::T3Connection;
use Util;
use Data::Dumper;
use strict;

#flush output
$|=1;

$SIG{INT} = \&killVolOper;
$SIG{TERM} = \&killVolOper;


my $RETRYS = 120;    #how many times to retry the t3 if no reply
my $RETRYWAIT = 30;  #how many sec's to wait between retrys

my $test=undef;
my %Options;
my $ok = getopts('msekuh?vdfo:', \%Options);
my $numargs=keys(%Options);
my $t3=undef;

#check to see if usage needs to be displayed
if( !$ok || $numargs < 1 || $Options{"u"} eq 1 ||
     $Options{"?"} eq 1 || $Options{"h"} eq 1 ){
  printUsage();
  exit();
}



#parse all -o options or any volverify specific options
#disable all Options and specify valid parameters
my %volverifyParameters=undef; 
@volverifyParameters{"dev",
		"volume_name",
		"fix_errors",
		"rate",
		"usr",
		"passwd"}=
		(undef,"no","1",undef,undef); 


my $fix=0;#default don't fix errors
#split up indivdual volverify specific parameters
#these are variable needed to do this:
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;


  if($Options{"d"}&& $key!~/passwd/){ print "$i\n"; }
  elsif($Options{"d"}&& $key=~/passwd/){ print "$key=\n"; }

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

  #check to make sure values are OK
my $param=undef;
while(($param,$value) = each(%volverifyParameters)) {
  if($param=~/rate/){
    if(($value > 8) || ($value <= 0)){
      print "$param=$value is an invalid option.\n".
            "volverify did not execute.\n". 
            "volverify exiting.\n";
      printUsage();
      exit(1);
    }
  }
  if($param=~/unit_name/){
    if($value eq undef){
      print "volume_name must be specified.\n".
            "volverify did not execute.\n". 
            "volverify exiting.\n";
      printUsage();
      exit(1);
    }
  }
  if($param=~/fix_errors/){
    if($value =~ /y/i){
      $fix=1;
    }elsif($value =~ /n/i){
      $fix=0;
    }else{
      print "fix_errors must be specified.\n".
            "volverify did not execute.\n". 
            "volverify exiting.\n";
      printUsage();
      exit(1);
    }
  }
}

#if debug print out parameters
if($Options{"d"}){ 
  print "INPUT PARAMETERS:\n";
  while (($key,$value) = each(%volverifyParameters)){
    print "key: $key value:$value \n";
  }
}

while($volverifyParameters{dev} eq undef){
  print "Please Enter the IP address or hostname for array\n";
  chomp($volverifyParameters{dev}=<STDIN>);
}

if($volverifyParameters{usr} eq undef){
  print "Please Enter User Name for $volverifyParameters{dev}\n";
  chomp($volverifyParameters{usr}=<STDIN>);
}

if(!defined($volverifyParameters{passwd})){
  $volverifyParameters{passwd}="";
}

#useful Tokens
my $unitIndex = undef;
my $volIndex = undef;
my $volName = $volverifyParameters{volume_name};
my %volnames=undef; #volname => "u"unitid"vol"volid"volName"
my $unitvol = undef; # u.unitid.vol.volid
my $errtoken = undef;

#Done Parsing -o options
#looks Like we are ready to start issuing commands to the T3
#So let's declare a T3Connection to use

my $t3 = new T3Connection($volverifyParameters{dev}, 
                          $volverifyParameters{usr}, 
			  $volverifyParameters{passwd});

if ($Options{"v"}){
  $t3->set_verbose();
}

if ($Options{"d"}){
  #$t3->set_debug();
}

#initialize Connection with T3
if(!($t3->init())){ 
  print "Could not initialize Array\n";
  if ($Options{"v"}){
    print " $t3->{error}\n"; 
  }
  print "Unable to establish communication with Array.\n";
  print "PROBABLE-CAUSE:\n";
  print "\t This problem can be caused by a very slow network, or \n";
  print "\t because the ethernet connection to this Array was lost. \n";
  print "RECOMMENDED-ACTION:\n";
  print "\t 1. Verify correct login and password \n";
  print "\t 2. Check Ethernet connectivity to the affected Array\n";
  print "\t 3. Verify Array is booted correctly\n";
  print "\t 4. Verify correct TCP/IP settings on Array \n";
  exit(1);
}
#check to make sure there are defined volumes on the T3
if($t3->{sysHasVolumes}=~/n/i){
  print "No volumes Detected on $volverifyParameters{dev}\n";
  print "Volumes Must exist to run Volume Verify on.\n";
  exit(1);
}
# %volnames=undef; #volname => "u"unitid"vol"volid"volName"
my $unit_properties = $t3->{elemprop};
foreach my $key(keys %$unit_properties){
    if($key =~ /u\dvol\dvolName/){
      if(exists(%volnames->{$unit_properties->{$key}})){
        #print "Already exsist\n"
      }
      else{%volnames->{$unit_properties->{$key}}=$key;} #ex: v0=>u1vol1volName
    }
}
if(exists(%volnames->{$volName}) ){
  my @tmp = split(/vol/, %volnames->{$volName});
  $unitIndex = substr(@tmp[0], 1);
  $volIndex = @tmp[1];
  #change from id to index
  $unitIndex--;
  $volIndex--;
  $unitvol = "u".($unitIndex+1)."vol".($volIndex+1);
  $errtoken = $unitvol."volErrors";

}else{
  print "$volName is not a defined volume on $volverifyParameters{dev}\n";
  print "Please run volverify ".
  	   		"again on one of the volume names listed below:\n";
  print "VolumeNames:";
  foreach my $v (keys %volnames){
    print "$v \n";
  } 
  exit 1;
}

#find info about volumes on specified index
my @volindexes=undef;
foreach my $key (keys %{$t3->{elemprop}}){
  if($key =~ /VolIndex/){
    if(@volindexes>1){ 
      my $match =undef;
      foreach my $i (@volindexes){
        if($i == $t3->{elemprop}->{$key}){ 
          $match = 1;
        }
      }
      if(!(defined($match))) { 
        push(@volindexes, ($t3->{elemprop}->{$key}));}
    }else{
      push(@volindexes, ($t3->{elemprop}->{$key}));}
  }
}

my $volOK=undef;
foreach my $vol_iter (@volindexes){
  if($vol_iter==$volIndex){
    $volOK=1;
  }
}
if (!(defined($volOK))){
    print "Specified vol_index: $volverifyParameters{volume_index}\n";
    print "The only verifiable volume indexes on unit $unitIndex are: @volindexes \n";
    exit(1);
}

#if -k Kill current Tests
if($Options{"k"}){ 
killVolOper();
exit 0;
}
#done trying to kill current Volume Operation

#print out sysprop if -s and -d flags set
if ($Options{"s"} && $Options{"d"}){
  print "**********SYSPROP*******************************\n";
  my $sysprop=$t3->{sysprop};
  print $sysprop;
  print $t3->{volOperProgress}."is the progress\n";
  print "HealthCheck is $t3->{volOperProgress} complete\n";
  print "**********END SYSPROP*******************************\n";
}
#print out elemprop if -e and -d flags set
if ($Options{"e"} && $Options{"d"}){
  print "**********ELEMPROP*******************************\n";
  my $elemprop=$t3->{elemprop};
  print Dumper($elemprop);
  print "**********END ELEMPROP*******************************\n";
exit 0;
}

#check for other vol operations
if ($t3->{DiskScrubber}eq"on"){ #Check for diskscrubbing
  print "Internal Disk Scrubbing is currently enabled for ".
  $volverifyParameters{dev}."\n";
  print "Cannot start volume verify.\n";
  exit(1);
}
for(my $j=0; $j<$t3->{unitCount}; $j++){
  for(my $k=0; $k<$t3->{volCount}; $k++){
    my $uvid = "u".(1+$j)."vol".($k+1);
    if ($t3->{elemprop}->{$uvid."volOper"}=~/\w+/i ){ #Check for another VolOp
      print "Volume Operation is currently running on ".
    		  $volverifyParameters{dev}."\n";
      print "Cannot start volume verify.\n";
      print "Start volume verify after current volume operation has completed.\n";
      exit(1);
   }
 }
}
#check to make sure Volume is mounted
if($t3->{elemprop}->{$unitvol."volIsUnmounted"}=~/yes/i){
      print "Volume $volverifyParameters{volume_name} is not mounted on ".
    		  $volverifyParameters{dev}."\n";
      print "Cannot verify an unmounted volume.\n";
      exit(1);
}

  #isuue the vol verify command
$t3->issueCommand("update?unitIndex=$unitIndex".
                  "volIndex= $volIndex",
		  "volClearStats=Clear");
$t3->runVolumeVerify( $unitIndex,
                      $volIndex,
                      $volverifyParameters{rate},
                      $fix);

#check to make sure vol verify started
my $test_started;
my $test_start_time;
my $num_failed_attempts=0;
my $num_check_for_start=10;
my $percent_complete;
#check for verify operation to make sure test started
for(my $i =0; $i<=$RETRYS; $i++){
  #keep trying for a connection
  if(!$t3->refresh("elemprop")){
    print "failed to connect to Array\n";
    $num_failed_attempts++;
    sleep($RETRYWAIT);
    next;
  }

  $percent_complete=$t3->{elemprop}->{$unitvol."volOperProgress"};
  if( $t3->{elemprop}->{$unitvol."volOper"} =~ /verify/i){
     $test_started="started";
     last; 
  }
}
if($test_started eq "started"){
  print "vol verify has started.\n";
  #$test_start_time = date;
}else{
  print "Array will not respond to volume commands.\n";
  print "Can not start vol verify.\n";
  if(($t3->{elemprop}->{$unitvol."volErrors"})){ 
    printError();
  }
  exit(1);
}

#start monitoring percent Complete
sleep(5);
$num_failed_attempts=0;
my $old_percent_complete=0;
my $occured_error;
while($num_failed_attempts <= $RETRYS && 
	$t3->{elemprop}->{$unitvol."volOper"} =~ /verify/i){
  if($t3->{elemprop}->{$errtoken} =~ /\w+/){
    print "vol verify has occured an error:\n".
                 $t3->{elemprop}->{$errtoken}."\n\n";
    $occured_error .= $t3->{elemprop}->{$errtoken}."\n\n";
  }

  if(!$t3->refresh("elemprop")){
    $num_failed_attempts++;
    sleep($RETRYWAIT);
    next;
  }

  #check to see if we have gotten any where 
  if ($percent_complete!=
                 $t3->{elemprop}->{$unitvol."volOperProgress"}){
    if($percent_complete!=0){
      $old_percent_complete=$percent_complete;
    }
    $percent_complete=$t3->{elemprop}->{$unitvol."volOperProgress"};
    if($percent_complete!=0){
      print "vol verify is $percent_complete percent complete\n";
    }
  }
  #check to make sure we are not going backwards
  if ($percent_complete < $old_percent_complete) { #we Have a problem
      if($old_percent_complete > 90 && $percent_complete==0){ 
        #volver prolly just finished
        print "vol verify Stopped\n"; 
	last;
      }else{
        print "vol verify was interupted by another operation\n";
  print "PROBABLE-CAUSE:\n";
  print "\t<Volume Verify was cancelled>\n";
  print "\t <This problem can be caused by a very slow network, or".
        " because the ethernet connection to this Array was lost.> \n";
  print "RECOMMENDED-ACTION:\n";
  print "\t < Check Ethernet connectivity to the affected Array >\n";
  print "\t < Verify Array is booted correctly >\n";
  print "\t < Verify correct TCP/IP settings on Array >\n";
  print "\t < Check for other volume operations running on array ".
        "when they have finished running restart vol verify. >\n";

        exit(1);
      }
  }
    #start again in 5 seconds
    sleep(5);
} 
if($num_failed_attempts > $RETRYS){  
  print "Lost communication with Array.\n";
  print "PROBABLE-CAUSE:\n";
  print "< slow network >\n";
  print "< ethernet connection to this Array was lost >\n";
  print "RECOMMENDED-ACTION:\n";
  print "< Check Ethernet connectivity to the affected Array >\n";
  print "< Verify Array is booted correctly >\n";
  print "< Verify correct TCP/IP settings on Array >\n";
  exit(1);
}
  #check to make sure we finished verifying
if($old_percent_complete < 90){
  print "vol verify was interupted by another operation\n";
  if(($t3->{elemprop}->{$unitvol."volErrors"})){ 
    printError();
  }
  exit(1);
}

if(testpassed()){
  print "volverify finished verifying the volume.\n";
  if ($Options{"d"}){ printError();print "\n"}
}else{
  print "volverify Failed\n";
  printError();
  print "\n";
  exit(-1);
}


sub testpassed{
  my $elemprop = $t3->{elemprop};
  if($elemprop->{$errtoken} =~ /\w+/){
    return 0;
  }

  if($t3->{elemprop}->{$unitvol."volSoftErrors"} > 0){
    return 0;
  }
  if($t3->{elemprop}->{$unitvol."volFirmErrors"} > 0){
    return 0;
  }
  if($t3->{elemprop}->{$unitvol."volHardErrors"} > 0){
    return 0;
  }
  if($occured_error){
    return 0;
  }
  return 1;
}

sub printError{
  my $elemprop = $t3->{elemprop};
  my $error = $elemprop->{$errtoken};
  print $error."/n";
  if($t3->{elemprop}->{$unitvol."volSoftErrors"} =~ /\w+/){
    print "volSoftErrors: ".
  	  $t3->{elemprop}->{$unitvol."volSoftErrors"}."\n";
  }
  if($t3->{elemprop}->{$unitvol."volFirmErrors"} =~ /\w+/){
    print "volFirmErrors: ".
  	  $t3->{elemprop}->{$unitvol."volFirmErrors"}."\n";
  }
  if($t3->{elemprop}->{$unitvol."volHardErrors"} =~ /\w+/){
    print "volHardErrors: ".
  	  $t3->{elemprop}->{$unitvol."volHardErrors"}."\n";
  }
  if($occured_error){
    print $occured_error;
  }
}


sub printUsage {
  print <<EOF;
  Usage: volverify [-yruvdlfn] [-o "dev={ip_name}|volume_name={volname}|
                    fix_errors={yes|no}|rate={1-8}|usr={login}|passwd={passwd}" ]

  Standard arguments:
     -k    Try to abort volverify currently running on Array
     -u    list usage
     -v    verbose mode
     -d    debug mode 

  volverify specific arguments [defaults]:
     dev=<Array name or IP address>
     volume_name=<volume_name>
     fix_errors={yes|no}
     rate={1-8} 8 being fastest with the greatest performance loss on host i/o
     usr=<adminusername>
     passwd=<admin Password>

  Example:
     volverify -o "volume_name=v0|dev=diagt4-1|usr=root|passwd=diags|rate=1|fix_errors=no"

EOF
}

sub killVolOper{
  my $unitnum;
  my @volnums=undef;
  my $unitvolid;
  my $failedabort=0;
	
  #send a kill to the specified volverify
  $t3->AbortVolumeOperation($unitIndex,$volIndex);
  print "Abort command sent to ".
         $volverifyParameters{dev}." u".($unitIndex+1)."vol".($volIndex+1)."\n";
}


sub refresh_sysprop{
  my $attempts = $RETRYS;
  while(!($t3->refresh("sysprop"))){
    print "Array quit Responding. Attempting to regain communication.\n";
    $attempts--;
    if( $attempts <= 0 ){
      print "Unable to regain ethernet communication with Array.\n";
      print "Diagnostic may still be running on Array.\n";
      exit 1;
    }
    sleep $RETRYWAIT;
  }
  return 1;
}

sub refresh_elemprop{
  my $attempts = $RETRYS;
  while(!($t3->refresh("elemprop"))){
    print "Array quit Responding. Attempting to regain communication.\n";
    $attempts--;
    if( $attempts <= 0 ){
      print "Unable to regain ethernet communication with Array.\n";
      print "Diagnostic may still be running on Array.\n";
      exit 1;
    }
    sleep $RETRYWAIT;
  }
  return 1;
}

