package Agent::D2;
#<copyright>
# ----------------------------------------------------------
# Sun Proprietary/Confidential Code
# Copyright 2001, Sun Microsystems, Inc. All rights reserved.
# ----------------------------------------------------------
#</copyright>


#       "@(#)D2Agent.pm 1.8     01/09/06 SMI"

use Agent;
use Debug;
use Carp;
use Util;
use vars qw($AUTOLOAD);
use Debug;
use Report;
use Util::Http;
use Cwd;
use strict;
use base 'Agent';
use Data::Dumper;

sub isSelectable {"Sun D2"} # displayed by the GUI in front of a checkbox that allows

# admin to turn this Agent off.
sub revision {'$Revision: 1.5 $'}

sub new { # standard to all Agent packages.
   my($self) = Agent->new();
   bless ($self, 'Agent::D2');
   return $self;
}


sub RUN {
   my($agent, $static_list, $pass) = @_;

   $DB::single=1;
   my($dc, $device, $key, $timelapse);
   my $processed_list = [];

   foreach $device ( $agent->deviceList($static_list)) {
     next if ($device->{active} eq "N");
     $dc++;
     Debug->print1("-> " . uc($device->{type}) . ": Reading device $device->{name}/$device->{wwn}");
  
     my $renv  = System->get_renv(); # get environment data-struct
  
     my $report = $agent->probe_d2($device);
     my $error = $report->{"rc.error"};

     $device->{name} = $device->{key} if (!$device->{name});

     my $id = { 
        deviceName => $device->{key},
        active     => "Y",
        logFile   => "",
        display   =>"$device->{name} ($device->{wwn})",
        name      => $device->{name},
        class     => $device->{class},
        category  => Report::CAT_D2, # valid category
        ip => "",
     };
     $report = {} if (!$report);
     $agent->copyDev($device, $report);

     $report->{"id.name"} = $device->{name};
     $report->{"id.wwn"} = $device->{key};
     my $new_rep;
     if ($error) {
        $report->{'id.connect_errs'} = $error;
        $new_rep = Report->new($id, $report , undef, Report::STATUS_CANNOT_CONNECT);
     } else {
        Discover->updateTopoDevice($device, {report => $report});
        $new_rep = Report->new($id, $report , undef);
     }
     my $problems = PDM->get_last_event();
     require Health::D2;
     Health::D2->all_logic($new_rep); 
     PDM->saveReport($new_rep);

     my ($broke, $abort) = $agent->new_events($problems, $device, 1);
     push(@$processed_list, $device);
     last if ($broke && $pass == 1 || $abort);
   }
   return $processed_list;

}

sub probe_d2 {
  my($agent, $device) = @_;
   
   return Report->readTest($device) if (System->get_testMode());
   my $report;

   my $lux = System->find_luxadm;
   my($err,$com) = Util->run_command("$lux inq $device->{wwn} 2>&1", "luxadm.txt" , 60);
   if ($err) {
      $report->{"rc.error"} = $err;
      return $report;
   }
   if ("@$com" =~ /No such device/) {
      $report->{"rc.error"} = "@$com";
      return $report;
   }
   Timelapse->startDev( $device);
   my %R;
   # parse $com and generate data structure.

   my($addlogical) = 0;
   my($connect_check) = 0;
   foreach my $l (@$com) { # $com is a pointer to an array, thus @$ is needed.
      my($name, $val) = split(/: +/, $l, 2); # separate
      $name = Util->ltrim($name); # remove leading spaces
      $name =~ s/ /_/g; 
      $R{"info.$name"} = Util->rtrim($val) if ($name && defined($val));
   }
   $report = \%R;

   $agent->addIdentification($report); # add device location to the report
   
   #
   # Append the SAF-TE config and status info to the report.
   #
   $agent->read_enclosure_config($report, $device);
   $agent->read_enclosure_status($report, $device);
   $agent->read_device_slot_status($report, $device);
   $agent->read_disk_inquiry($report, $device);
   
   &dump_midplane_vpd($report, $device);
   &dump_esm_vpd($report, $device);
   Timelapse->stopDev( $device);
   return $report;

}

sub read_disk_inquiry {
   my($class, $report, $device) = @_;

   my $command = System->get_home() . "/bin/disk_inquiry";
   my($err,$com) = Util->run_command( $command, "disk_inq",60); # run the command, timeout after 20 secs.
   my $in;
   my %REV;
   foreach my $el (keys %$report) {
      if ($el =~ /(^slot\.\d+\.\d+)\.dev/) {
         $REV{substr($report->{$el},0,-2)} = $1;
      }
   }
   foreach my $el (@$com) {
      if ($el =~ /Location/) {
         $in = 1;
      } elsif ($in) {
         my($ctd, $f2, $f3) = split(/\t/, $el);
         next if (!$f2);
         $ctd = Util->trim($ctd);
         my($vendor, $model) = split(/\s+/, $f2,2);
         my($rev, $serial) = split(/\s+/, $f3,2);
         my $el2;
         if (($el2 = $REV{$ctd})) {
            $report->{"$el2.vendor"}   = $vendor;
            $report->{"$el2.model"}    = $model;
            $report->{"$el2.revision"} = $rev;
            $report->{"$el2.serial"}   = $serial;
         }
      }
   }
}
         

   

sub read_enclosure_config {
   my($class, $report, $device) = @_;

   my $path = $device->{wwn};
   my $command = System->get_home() . "/bin/rdbuf $path";
   my($err,$com) = Util->run_command( $command, "readenc.txt",20); # run the command, timeout after 20 secs.
   if ($err) {
      Debug->print2("read_enclosure_config: err = $err");
      return;
   }
   foreach my $l (@$com) { # $com is a pointer to an array, thus @$ is needed.
      my($name, $val) = split(/: +/, $l,2); # separate
      next if (!defined($val));
      $name = Util->ltrim($name); # remove leading spaces
      $name =~ s/ /_/g; # join
      $val = Util->ltrim($val);
      $val =~ s/\(0x\w+\) //;
      $report->{"encConfig.$name"} = $val;
   }
}

sub read_enclosure_status {
   my($class, $report, $device) = @_;

   my $path = $device->{wwn};
   my $command = System->get_home() . "/bin/rdbuf $path 1";

   my($err,$com) = Util->run_command( $command, "readenc.txt",20); 
   if ($err) {
      Debug->print2("read_enclosure_status: err = $err");
      return;
   }
   foreach my $l (@$com) { # $com is a pointer to an array, thus @$ is needed.
      my($name, $val) = split(/: /, $l, 2); # separate
      next if (!defined($val));
      $name = Util->ltrim($name); # remove leading spaces
      $name =~ s/ /_/g; # join
      $val = Util->ltrim($val);
      $val =~ s/\(0x\w+\) //;
      $report->{"encStatus.$name"} = $val;
   }
}

sub read_device_slot_status {
  my($class, $report, $device) = @_;
  
  my $esm;
  foreach my $path ($device->{wwn}, $device->{wwn2}) {
     next if (!$path);
     my $command = System->get_home() . "/bin/identify -d -f $path";
     my($err,$com) = Util->run_command( $command, "rddevslot.txt",40);
     if ($err) {
        Debug->print2("read_device_slot_status: err = $err");
        return;
     }
     my $in;
     $report->{"fan.header"} = "fan";
     $report->{"power.header"} = "power";
     my $max = 0;
     foreach my $l (@$com) { # $com is a pointer to an array, thus @$ is needed.
        if ($l =~ /FW Revision: (\w+)\s+ESM: (\w+), Unit ID: (\d+), Temperature: (.+)/) {
           $esm = $2;
	   last;
	 }
      }
     foreach my $l (@$com) { # $com is a pointer to an array, thus @$ is needed.
        if ($l =~ /FW Revision: (\w+)\s+ESM: (\w+), Unit ID: (\d+), Temperature: (.+)/) {
           my $unit = $2;
           $report->{"esm.$unit.revision"} = $1;
           $report->{"info.esm"}          = $unit;
           $report->{"info.unitId"}       = $3;
           $report->{"info.temperature"}  = $4;
        } elsif ($l =~ /Fans:/) {
           $in = "fan";
        } elsif ($l =~ /SLOT\sTID/) {
           $in = "slot";
        } elsif ($l =~ /Power Supplies:/) {
           $in = "power";
        } elsif ($in eq "slot") {
           my($slot, $tid, $dev, $statusno, $status) = split(/\s+/, $l, 5);
           if ($status) {
             $report->{"slot.$esm.$slot.tid"} = $tid;
             $report->{"slot.$esm.$slot.dev"} = $dev;
             $status = lc($status); $status =~ s/ /_/g;
             $status =~ s/\.//g;
             $report->{"slot.$esm.$slot.status"} = $status;
           }
           $max = ($slot+1) if (($slot+1) > $max);
  
        } elsif ($in eq "fan") {
           $l = Util->ltrim($l);
           my($no, $val) = split(/\s*\:\s+/, $l, 2);
           $val =~ s/\(0x\w+\) //;
           $val =~ s/Fan is //;
           $report->{"fan.$no.status"} = $val;
           $val =~ s/ /_/g;
  
        } elsif ($in eq "power") {
           $l = Util->ltrim($l);
           my($no, $val) = split(/\s*\:\s+/, $l, 2);
           $val =~ s/\(0x\w+\) //;
           $val =~ s/Power supply is //;
           $val =~ s/ /_/g;
           $report->{"power.$no.status"} = $val;
        }
  
     }
     $report->{"slot.$esm.total"} = $max;
     $esm++;
   }
}

sub dump_midplane_vpd {
   my($report, $device) = @_;

   my $path = $device->{wwn};
   my($dir) = cwd();
   chdir System->get_home() . "/bin";
   my $command = "./vpd $path 1";  # need to run the command from "bin"

   my($err,$com) = Util->run_command( $command, "dump_midplane_vpd.txt",20); 
   chdir $dir;
   $dir = cwd();
   if ($err) {
      Debug->print2("dump_midplane_vpd: err = $err");
      return;
   }
   my($full) = "";
   foreach my $l (@$com) { # $com is a pointer to an array, thus @$ is needed.
      my($val) = substr($l, 58 ,16);
      $full = $full . $val;
   }
   $full .= "  " x 100;
   $report->{"midplane.product"} = Util->rtrim(substr($full, 8, 12));
   $report->{"midplane.serial"}  = Util->rtrim(substr($full, 24, 12));
   $report->{"midplane.vendor"}  = Util->rtrim(substr($full, 40, 8));
   $report->{"midplane.date"}    = Util->rtrim(substr($full, 52, 8));
   $report->{"midplane.frutype"} = Util->rtrim(substr($full, 64, 8));
}

sub dump_esm_vpd {
  my($report, $device) = @_;

  my $esm;
  foreach my $path ($device->{wwn}, $device->{wwn2}) {
    next if (!$path);

     my $command = System->get_home() . "/bin/identify -d -f $path";
     my($err,$com) = Util->run_command( $command, "rddevslot.txt",20); 
     if ($err) {
        Debug->print2("read_device_slot_status: err = $err");
        return;
     }
     foreach my $l (@$com) { # $com is a pointer to an array, thus @$ is needed.
        if ($l =~ /FW Revision: (\w+)\s+ESM: (\w+), Unit ID: (\d+), Temperature: (.+)/) {
           $esm = $2;
	   last;
	 }
      }

     my($dir) = cwd();
     chdir System->get_home() . "/bin";
     my $command = "./vpd $path 2";  # need to run the command from "bin"
     my($err,$com) = Util->run_command( $command, "dump_esm_vpd.txt",20); 
     chdir $dir;
     $dir = cwd();
     if ($err) {
        Debug->print2("D2Agent: dump_esm_vpd: err = $err");
        return;
     }
     my($full) = "";
     foreach my $l (@$com) { # $com is a pointer to an array, thus @$ is needed.
        my($val) = substr($l, 58, 16);
        $full = $full . $val;
     }
     $full .= " " x 100;
     $report->{"esm.$esm.product"}  = Util->rtrim(substr($full, 8, 12));
     $report->{"esm.$esm.serial"}   = Util->rtrim(substr($full, 24, 12));
     $report->{"esm.$esm.vendor"}   = Util->rtrim(substr($full, 40, 8));
     $report->{"esm.$esm.date"}     = Util->rtrim(substr($full, 52, 8));
     $report->{"esm.$esm.frutype"}  = Util->rtrim(substr($full, 64, 8));
     $esm++;
  }
}

sub FRUS {
  my($class, $r, $name) = @_;
  my($v) = $r->{_value};
  my $devtype = $r->category();
  $name = "d2-$name";
  my @FRUS;
  my ($x, $y);
  for ($x=0; $x <= 1; $x++) {
    if (exists($v->{"esm.$x.frutype"}))  {
      my $fruid = lc($v->{"esm.$x.frutype"}) . ".$x";
      my $vendor = $v->{"esm.$x.vendor"};
      my $model  = $v->{"esm.$x.product"};
      my $serial = $v->{"esm.$x.serial"};
      my $rev    = $v->{"esm.$x.revision"};
      push(@FRUS, [ $name ,$devtype, lc($v->{"esm.$x.frutype"}), $fruid, $vendor, $model, $serial, $rev, " N/A"]);
    }
  }
  my $fruid = "midplane";
  my $vendor = $v->{"midplane.vendor"};
  my $model  = $v->{"midplane.product"};
  my $serial = $v->{"midplane.serial"};

  push(@FRUS, [ $name ,$devtype, $fruid, $fruid, $vendor, $model, $serial, "N/A", " N/A"]);

  for ($x=0; $x <= 1; $x++) {
     for ($y=0; $y <= 20; $y++) {
        if (exists($v->{"slot.$x.$y.model"})) {
           my $fruid  = "disk.$x.$y";
           my $vendor = $v->{"slot.$x.$y.vendor"};
           my $model  = $v->{"slot.$x.$y.model"};
	   $model =~ s/ +/-/;
           my $serial = $v->{"slot.$x.$y.serial"};
           my $rev    = $v->{"slot.$x.$y.revision"};
           my $st     = $v->{"slot.$x.$y.status"};
           push(@FRUS, [ $name ,$devtype, "disk", $fruid, $vendor, $model, $serial, $rev, $st]);
        }
     }
  }

  return \@FRUS;
}


sub REPORT {
  my($class, $host, $r, $arg) = @_;

  my($out);
  my($tableCnt) = $arg->{tableCnt};
  my $V = $r->{_value};

  my($host0) = $host || System->hostname();
  my $rev = $V->{"info.Revision"};
  my $comm = ($r->{_status} eq "CC") ? "<font color=red>Communication Lost: Data may be old!</font>" : "";

  $out .= $class->reportHead('D2', $r);
  $out .= "
   <tr><td bgcolor=#F0F0F0 colspan=4><b><center>$comm</td>

   <tr><td bgcolor=#F0F0F0 align=right><b>Name:</td><td width=25%>&nbsp;$r->{_id}{name}</td>
       <td bgcolor=#F0F0F0 align=right><b>Monitored on:</td><td>&nbsp;$host0</td>

   <tr><td bgcolor=#F0F0F0 align=right><b>Path:</td><td>&nbsp;$V->{'id.device_wwn'}</td>
       <td bgcolor=#F0F0F0 align=right><b>Rev:</td><td>&nbsp;$rev</td>
   <tr>
       <td bgcolor=#F0F0F0 align=right><b>Path2:</td><td>&nbsp;$V->{'id.device_wwn2'}</td>
       <td bgcolor=#F0F0F0 align=right><b>Temp.:</td><td>&nbsp;$V->{'info.temperature'}</td>
   ";
   $out .= "<tr bgcolor=$Style::LIGHT><td><b>Type<td><b>Status<td><b>Serial</td><td><b>Info";
   my $x;
   $out .= "<tr><td>Midplane<td>&nbsp;</td><td>$V->{'midplane.serial'}</td><td>$V->{'midplane.vendor'} $V->{'midplane.product'} $V->{'midplane.date'}</td>";
   foreach my $esm (0,1) {
     $out .= "<tr><td><b>ESM $esm<td>&nbsp;</td><td>&nbsp;" . $V->{"esm.$esm.serial"} . "</td><td>&nbsp;" . 
               $V->{"esm.$esm.vendor"} . " " .  $V->{"esm.$esm.product"} . " " .
               $V->{"esm.$esm.date"} . "</td>";
     for ($x=0; $x <= 20; $x++) {
       next if (!$V->{"slot.$esm.$x.status"});
       my $tag = $V->{"slot.$esm.$x.status"};
       $tag =~ s/_/_ /;
       $out .= "<tr><td>&nbsp;&nbsp;Slot$x<td>$tag" .
              "</td><td>&nbsp;" . 
              $V->{"slot.$esm.$x.serial"} . 
              "</td><td>" . 
              $V->{"slot.$esm.$x.vendor"} . " " . $V->{"slot.$esm.$x.revision"} . " " .
              $V->{"slot.$esm.$x.dev"} . "</td>";
     }
   }
   foreach my $el ('power.0','power.1') {
     my $bg;
     my $p0 = $V->{"$el.status"};
     if(!($p0 eq "operational_and_on")){
        $bg = "bgcolor=red";
     }
     $p0 =~ s/_/_ /;
     $out .= "<tr><td>" . lcfirst($el) . "<td $bg>$p0</td><td colspan=2>&nbsp;</td>";
   }
   foreach my $el ('fan.0','fan.1') {
     my $p0 = $V->{"$el.status"};
     $p0 =~ s/_/_ /;
     $out .= "<tr><td>" . lcfirst($el) . "<td>$p0</td><td colspan=2>&nbsp;</td>";
   }
   $out .= "<tr bgcolor=$Style::LIGHT><td colspan=2><b>Enclosure Info</td><td colspan=2><b>Value</td>";
   foreach my $x (keys %$V) {
       if ($x =~ /^encConfig./) {
          my $tag = substr($x,10);
          $tag =~ s/Number_of_//;
          $out .= "<tr><td colspan=2>$tag</td><td colspan=2>" . $V->{$x};
       }
   }
   $out .= "<tr><td colspan=2>SCSI</td><td colspan=2>$V->{'info.ANSI_version'}</td>";

   $out .= "</table>";
   return $out;

}

1;
