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

#  $Name:  $ 
#  $Id: T3.pm,v 1.68 2002/10/03 16:06:24 ccadieux Exp $

use Catalog;
use strict;
use Report;
use Agent;
use base 'Agent';

sub isSelectable {"Sun T3"}

sub revision {'$Revision: 1.68 $'}


use vars qw(%N2IP $ERR);

sub new {
  my($self) = Agent->new();

  bless ($self, 'Agent::T3');
  return $self;
}

sub getPortKey {
  my($class, $key, $port) = @_;
  my($VAR1);

  my $ci = Catalog->deviceRead('t3', Catalog::Key, $key);

  if (!$ci) {
     Debug->print2("getPortKey: Cannot find key for $key:$port");
     return undef;
  }

  if ($port == 0) {
     return $ci->[Catalog::Port1];
  } else {
     return $ci->[Catalog::Port2];
  }
}

sub diskTotal {9}

sub RUN {
  my($agent,$ras_flag) = @_;
  my($err_lines, $warn_lines,  $out,$device, $connect_errs);
  my($report ,  $id, $lines, $log_err, $type);
  my( $wwn, $portWWN, $port2WWN);
  $DB::single = 1;
  my($pdm) = $agent->{pdm};
 
  Timelapse->start("T3MESSAGEAgent");

  my($renv)    = $agent->{renv};
  my($logfile) = $renv->{t300logfile};

  my $ISP;
  if ($logfile && -r $logfile) {
     ($log_err, $lines) = $agent->read_log_file($logfile,'NEW');  
     Debug->err('CANNOT_READ', $logfile) if ($log_err);

     ($warn_lines) = &find_alert($lines, $device, \$ISP);

     my($name) = $renv->{hostname} || System->hostname();
     if ($warn_lines) {
       $id = {
              deviceName  =>  System->hostid(),
              active      => "Y",
              logFile     => $logfile,
              display     => "$name (id=" . System->hostid() . ")",
              name        => $name, 
              class       => "host",
              category    => Report::CAT_T3MESSAGE,
              ip          => "",
           };
       $report->{"id.name"} = $name;

       $pdm->saveReport( 
               Report->new($id, $report , $warn_lines, Report::STATUS_OK));
     }
  }
  Timelapse->stop("T3MESSAGEAgent");

  Timelapse->start(ref($agent));

  my($sdt);
  my($dc) = 0;
  my $syslog_info  = System->grep("/etc/syslog.conf", "\.t3");

  my $se_conflict = System->get_se_conflict();

  foreach $device ( $agent->deviceList() ) {
     next if ($device->{active} eq "N");

     if ($se_conflict && index($se_conflict, $device->{name}) >= 0 ) {
       Debug->print2("-> T3: skipping $device->{name},  detected se-config lockfile");
       next;
     }
         
     $dc++;
     $id  = $device->{_name};

     Debug->print1("-> Reading T3:$device->{name}/$device->{ip}");
  
     if (!$device->{ip}) {
        Debug->errNoRepeat( T3_IP => $device->{name} , 8);
        next;
     }
     ($connect_errs, $report, $wwn, $portWWN, $port2WWN) = $agent->INSTRUMENTATION($device);

     my $tk = PDM->getCacheHandle("transition-$device->{key}");
     if (substr($connect_errs, 0,6) eq "Tokens"){#can ping , no tokens returned, timeout?
        if ($tk->{lost_tokens}++ < 2) {
          Debug->print2("can ping this t3 but no tokens");
          Timelapse->stop(ref($agent));
          next;
        }
     } else {
        $tk->{lost_tokens} = 0;
     }
     $wwn = lc($wwn);
     if (!$wwn) {
        Debug->errNoRepeat(T3_NO_KEY => $device->{name}, 8, "$device->{name} returned no midplane serial#");
     } elsif ($wwn ne $device->{key}) {
        Debug->errNoRepeat(T3_NEW_KEY => $device->{name}, 8);
     }

     my $t1 = $device->{ipno} || $device->{ip};

#    $id = $agent->newId(Report::CAT_T3, $device->{key}, $logfile, 
#                       "$device->{name} (ip=$t1)");
     $id =  { 
              deviceName  => $device->{key},
              active      => $device->{active},
              logFile     => $logfile,
              name        => $device->{name},
              class       => $device->{class},
              display     => "$device->{name} (ip=$t1)",
              category    => Report::CAT_T3,
              ip          => $device->{ip},
            };
     $report = {} if (!$report);
     $agent->copyDev($device, $report);

     $report->{"id.name"}        = $device->{name};
     $report->{"id.mgmtLevel"}   = $device->{mgmtLevel};
     $report->{"id.ip"}          = $device->{ip};
     $report->{"id.ipno"}        = $device->{ipno};
     $report->{"id.wwn"}         = $device->{key};

     $report->{"info.syslog"}    = $syslog_info;
     $report->{"info.OOB_date"} = Util->get_today();

     if ($connect_errs || !$wwn) {
        $report->{"info.OOB_connection"} = $connect_errs;
        $report->{'id.connect_errs'} = $connect_errs;
        $pdm->saveReport(
          Report->new($id, $report , "", Report::STATUS_CANNOT_CONNECT));

     } else {
        $report->{"info.OOB_connection"} = "OK";
        $pdm->saveReport(Report->new($id, $report , ""));
     }
  }
  Debug->print2("  No devices found") if (!$dc);
  Timelapse->stop(ref($agent));
}

sub getUserLabel {
  my($class, $ctrl) = @_;
  my ($label);

  if ($ctrl !~ /^501/) {
    $label = "t3";
  } else {
    $label = "t3b";
  }
  return $label;
}


sub getWWN {
  my($class, $ip, $host, $TO) = @_;
  my $rc;
  $TO = 100 if (!$TO);
  $ERR = undef;
  if ($host) {
      $rc = Util::Http->getCommand($host, "Agent::T3::WWN&ip=$ip&HTTP=1&TO=$TO", $TO + 5);
      if (substr($rc,0,3) eq "ERR") {
         $ERR = $rc;
         return undef;
      }
  } else {
      $rc = get_WWN({ip => $ip, TO => $TO});
  }
  my($key, $w1, $w2, $ctr, $name) = split(/\|/, $rc);
  my $label = $class->getUserLabel($ctr);
  if (wantarray) {
     return ($key, $w1, $w2, $ctr, $name, $label);
  }  else {
     return $key;
  }
}

sub get_WWN {
  my($q) = @_;
  my $ip = $q->{ip};
  my $TO = $q->{TO};
  my($key, $wwn1, $wwn2, $ctr_model);
  my $alive = Util->ping($ip, 10);

  if ($alive) {
    my $elemprop0 = Agent::T3->getTokens($ip, 0, $TO);
    my $elemprop1 = Agent::T3->getTokens($ip, 1, $TO);
    foreach my $l (@$elemprop0, @$elemprop1) {
        if ($l =~ /;u1mpn,fruVendor,(.*);/) {
           $key = lc($1) . ".";
        } elsif  ($l =~ /;u1mpn,fruModel,(.*);/) {
           $key .= lc($1) . ".";
        } elsif  ($l =~ /u1ctr,fruModel,(.*);/) {
           $ctr_model = $1;
        } elsif  ($l =~ /;u1mpn,fruSerialNo,(.*);/) {
           $key .= lc($1);
        } elsif ($l =~ /;u1p1,portWWN,(.*);/) {
           $wwn1 = lc($1);
        } elsif ($l =~ /;u2p1,portWWN,(.*);/) {
           $wwn2 = lc($1);
        }
    }
  }
  $key =~ s/ //g;
  $key = "" if ($key eq ".." || $key eq ".");
#  if (!$key) {
#      if ($wwn2) {
#         $key = ($wwn1 gt $wwn2) ? "$wwn2.$wwn1" : "$wwn1.$wwn2";
#      } else {
#         $key = $wwn1;
#      }
#  }
  my $dir = System->get_home();
  my $ix = index($ip, ":");
  if ($ix > 0) {
    $ip = substr($ip,0,$ix);
  }
  my($err0,$n) = Util->run_command(
              "$dir/snmp/bin/snmpget -t 20 -m all -Onq $ip public .1.3.6.1.4.1.42.2.28.2.2.1.1.0");
  my($oid, $name) = split(/ "/, $n->[0]);
  chop($name);

  if ($name !~ /^\d+\.\d+\./) {
     my $ix = index($name, ".");
     $name = substr($name,0,$ix) if ($ix > 0);
  }

  if ($q->{HTTP}) {
    print "$key|$wwn1|$wwn2|$ctr_model|$name";
  } else {
    return "$key|$wwn1|$wwn2|$ctr_model|$name";
  }
}




############################################################
#                    SUBROUTINES
############################################################


%N2IP = ();

# 1 = warning
# 2 = errors

sub find_alert {
  my($lines, $device, $ISP) = @_;
  my( $level, $name, $no1, $no2, $rest);
  my($m, $year, $date, $comp, $x);
  my($ipno);
  my (@err);
  my $Config = PDM::ConfigFile->read();
  my $devs = $Config->devices();
  my %IP;
  foreach my $d (@$devs) {
     $IP{$d->{ipno}} = $d->{key};
  }

  for ($x = 0; $x <= $#$lines; $x++ ) {
     my $line = $lines->[$x];
     my(@a) = split(/\s+/, $line);
     my $t3_ip = Util->name2ip($a[3]);
     my $key;
     if (exists($IP{$t3_ip})) {
       $key = "t3:" . $IP{$t3_ip};
     } else {
       $key = "t3message:HOST";
     }
  
     if ($line =~ /: W: (.*)/) {
         $err[1]{$key}{line} .= $line . "\n";
         $err[1]{$key}{name} = $a[3];
         $err[1]{$key}{count}++;
         $err[1]{$key}{ip} = $t3_ip;
  
     } elsif ($line =~ /: E: (.*)/) {
         $err[2]{$key}{line} .= $line . "\n";
         $err[2]{$key}{name} = $a[3];
         $err[2]{$key}{count}++;
         $err[2]{$key}{ip} = $t3_ip;
  
     } elsif ($line =~ /: WARNING: / ) {
         $err[2]{$key}{line} .= $line . "\n";
         $err[2]{$key}{name} = $a[3];
         $err[2]{$key}{count}++;
         $err[2]{$key}{ip} = $t3_ip;
  
     #} elsif ($line =~ /ISP2\d\d\d/ ) {
     #     $$ISP = $$ISP + 1;
     #     $level = 0;
  
     } elsif ($line =~ /: [NI]: u\dd\d/ ) {
         my $e1;
         $e1 .= "$line\n";
         $e1 .= "$lines->[$x+1]\n" if ($lines->[$x+1] =~ /Sense/);
         if ($lines->[$x+2] =~ /Sense/) {
            $e1 .= "$lines->[$x+2]\n";
            $e1 .= "$lines->[$x+3]\n";
         }
         $err[2]{$key}{line} .= $line . "\n";
         $err[2]{$key}{name} = $a[3];
         $err[2]{$key}{count}++;
         $err[2]{$key}{ip} = $t3_ip;
  
     } elsif ($line =~ /: [N]: u\dpcu\d.*Battery .*OK/ ) {
         $err[2]{$key}{line} .= $line . "\n";
         $err[2]{$key}{name} = $a[3];
         $err[2]{$key}{count}++;
         $err[2]{$key}{ip} = $t3_ip;
  
     } elsif ($line =~ /: [N]: u\dpcu\d.*PCU\d hold time/) {
         $err[2]{$key}{line} .= $line . "\n";
         $err[2]{$key}{name} = $a[3];
         $err[2]{$key}{count}++;
         $err[2]{$key}{ip} = $t3_ip;
  
     }
  }
  return ( \@err);
}

sub getTokens {
   my($class, $ip, $unit, $to, $page) = @_;

   $page = "elemprop" if (!$page);
   my $out = Util::Http->get( 
            "http://guest\@$ip/$page.htm?unitIndex=$unit",$to);
   return undef if (!$out);
   my @x = split(/\n/, $out);
   return \@x;
}



#######################################################
#      READ/PARSE HTTP TOKENS
#######################################################
# ;u1ctr,fruCtlrPartnerId,u2ctr;

sub INSTRUMENTATION {
  my($agent, $device) = @_;
  my($fru_date, $mode);
  my($connect_err, $stats);
  my($config, $config_errors);
  my($l, $config2, $config_rep, $stats_rep);
  my($sysprop, $elemprop0, $elemprop1, $key , $portWWN, $port2WWN, $slices, $luns);

  my($renv)   = System->get_renv();
  my($ping_to) = $renv->{'timeout.ping'} || 10;
  my($http_to) = $renv->{'timeout.http'} || 60;
  my($id)     = $device->{_name};
  my($ip)     = $device->{ip};
  my($unit)   = $device->{name};
  my($home)   = System->get_home();
  my(@temp);

  if (System->get_testMode() ) {
    my $temp = Util->readf("$home/Test/t300.elemprop");
    @temp = split(/\n/, $temp);
    $elemprop0 = \@temp;
  } else {
    if (!Util->testIp($device->{ip},$ping_to)) {
       Debug->print(PING => "failed on $device->{host}/$device->{ip} (to=$ping_to)");
       return ("Ping: Ping failed on $device->{ip}", undef);
    }
       
    $elemprop0 = $agent->getTokens($device->{ip}, 0, $http_to);
    $elemprop1 = $agent->getTokens($device->{ip}, 1, $http_to);
    $sysprop   = $agent->getTokens($device->{ip}, 1, $http_to, "sysprop");
    $slices    = $agent->getTokens($device->{ip}, 0, $http_to, "slice");
    $luns    = $agent->getTokens($device->{ip}, 0, $http_to, "lun");
  }
  if ($elemprop0) {
     ($portWWN, $port2WWN, $key, $config_rep) = $agent->parse_elem($elemprop0, $elemprop1, $device);
     $agent->parse_slice($config_rep, $slices);
     $agent->parse_lun($config_rep, $luns);
     $agent->parse_sys($config_rep, $sysprop);
  } else {
     Debug->errNoRepeat(CANNOT_HTTP => $device->{ip}, 8);
     return ("Tokens: No tokens returned from $device->{ip}", undef);
  }
  my $t_err = $agent->telnet_monitor($device, $config_rep, $renv);
  return ( $connect_err, $config_rep, $key, $portWWN, $port2WWN);
}

# return error, loads hash pointer $R
#
sub telnet_monitor {
  my($agent, $device, $R, $renv) = @_;

require "Net/Telnet.pm";
  my $dt = $agent->diskTotal();

  return if ($renv->{'t3.telnet.monitor'} ne "Y");

  my($t) = new Net::Telnet (
             errmode => "return",
             Timeout   => 30,
             Prompt    => '/<\d+\>/',
             );
  my $ipno = $device->{ipno};

  my $ix = index($ipno, ":");
  if ($ix > 0) {
    $ipno = substr($ipno,0, $ix);
  }

  if (!defined($t->open($ipno))) {
      return "Cannot open $ipno";
  }
  $t->login("root", Util->decode($device->{telnet}));
  if ($t->errmsg()) {
     return $t->errmsg();
  }
  my @l = $t->cmd(".disk pathstat u1d1-$dt");
  foreach my $l (@l) {
      chop($l);
      next if (substr($l,0,1) ne "u");
      my($d, $rest) = split(/\s/, $l, 2);
      $R->{"disk.$d.pathstat"} = ($rest =~ /\[-1/)? "INVALID":"OK";
  }

  @l = $t->cmd(".disk pathstat u2d1-$dt");
  foreach my $l (@l) {
      chop($l);
      next if (substr($l,0,1) ne "u");
      my($d, $rest) = split(/\s/, $l, 2);
      $R->{"disk.$d.pathstat"} = ($rest =~ /\[-1/)? "INVALID":"OK";
  }
  return undef;
}

sub parse_slice {
  my($class, $rep, $slices) = @_;

  my $max = -1;
  foreach my $l (@$slices) {
       $l = Util->ltrim($l);
       if ($l =~ /^;sys,(.*);/) {
          my($name, $val) = split(/\,/, $1);
          $rep->{"sys.$name"} = $val;

       } elsif ($l =~ /^;slice(\d+),(.*);/) {
          my $no = $1;
          $max = $no if ($no > $max);
          my $rest = $2;
          my($name, $val) = split(/\,/, $rest);
          $rep->{"slice.$no.$name"} = $val;
       }
  }
  $rep->{"slice.count"} = $max + 1;
}

sub parse_lun {
  my($class, $rep, $luns) = @_;

  my $max = -1;
  foreach my $l (@$luns) {
       $l = Util->ltrim($l);
       if ($l =~ /^;sys,(.*);/) {
          my($name, $val) = split(/\,/, $1);
          $rep->{"sys.$name"} = $val;

       } elsif ($l =~ /^;lun(\d+),(.*);/) {
          my $no = $1;
          $max = $no if ($no > $max);
          my $rest = $2;
          my($name, $val) = split(/\,/, $rest);
          $rep->{"lun.$no.$name"} = $val;
       } elsif ($l =~ /^;lun(\d+)Initiator(\d+),(.*);/) {
          my $lunno = $1;
          my $initiator_no = $2;
          $max = $lunno if ($lunno > $max);
          my $rest = $3;
          my($name, $val) = split(/\,/, $rest);
          $rep->{"lun.$lunno.Initiator.$initiator_no.$name"} = $val;
       } elsif ($l =~ /^;slice(\d+),(.*);/) {
          my $no = $1;
          $max = $no if ($no > $max);
          my $rest = $2;
          my($name, $val) = split(/\,/, $rest);
          $rep->{"slice.$no.$name"} = $val;
       }
  }
  $rep->{"lun.count"} = $max + 1;
}


sub parse_elem {
  my($agent, $sys, $partner, $device) = @_;
  my(%V, $l);
  my($in, $disk_cnt, $ctrl_cnt, $type);

  if ($#$partner > 30) {  # add the partner info to the main array.
    $in = 0;
    foreach $l (@$partner) {
      if (lc($l) =~ /-- unit info/) {
         $in = 1;
      } elsif ($in) {
         push(@$sys, $l);
      }
    }
  }

  $in = 0; $disk_cnt = 0; $ctrl_cnt = 0;
  foreach $l (@$sys) {
     if (lc($l) =~ /-- unit info/) {
        $in = 1;
     } elsif ($in) {
        my(@b) = split(/,/, $l);
        next if (substr($b[1],0,6) eq "volSec" || substr($b[1],0,7) eq "portSec");

        if (substr($l,0,1)  eq ";" && $#b > 1)  {
          chop($b[2]) if (substr($b[2],-1) eq ";");
          $b[2] =~ s/ +/ /g;
          $b[2] =~ s/\c[//g;
          $b[0] = substr($b[0],1);
          $type = "";
          if (substr($b[0],0,2) eq "un") {
              $type = "unit";
          }elsif ($b[0] =~ /u(\d)d(\d+)/) {
              $type = "disk";
              my $uu = $1;
              my $dd = $2;
              $disk_cnt = $dd+0 if ($dd > $disk_cnt);
              $b[0] = "u$uu" . "d" . ($dd+0);
          }elsif (substr($b[0],2,1) eq "c") {
              $type = "controller";
              $ctrl_cnt = substr($b[0],1,1) if (substr($b[0],1,1) > $ctrl_cnt);
          }elsif (substr($b[0],2,1) eq "l") {
              $type = "loopcard";
          }elsif (substr($b[0],2,2) eq "pc") {
              $type = "power";
          }elsif (substr($b[0],2,1) eq "p") {
              $type = "port";
          }elsif (substr($b[0],2,1) eq "m") {
              $type = "midplane";
          }elsif (substr($b[0],2,1) eq "v") {
              $type = (substr($b[0],6,1) eq "-")? "volume_disk":"volume";
          }         
# l=;u1ctr,fruId,u1ctr; $b[0]=u1ctr, $b[1]=fruId, $b[2] = u1ctr
          
          my $val = Util->trim($b[2]);
          $val = "" if ($b[1] eq "portWWN" && $val =~ /^0+$/);
          $V{"$type.$b[0].$b[1]"} = $val;
        }
     } 
  }
  $V{"disk.count"} = $disk_cnt;
  $V{"controller.count"} = $ctrl_cnt;
  $V{"volume.u1vol1.volWWN"} =~ s/00000000000000/0/g;
  my($portWWN, $port2WWN);

  $portWWN  = $V{"port.u1p1.portWWN"};
  $port2WWN = $V{"port.u2p1.portWWN"};

#  substr($portWWN,-9,1) = "0" if (length($portWWN) > 10);
#  substr($port2WWN,-9,1) = "0" if (length($port2WWN) > 10);

  my($key);
  if ( $V{"midplane.u1mpn.fruVendor"} ) {
    $key = $V{"midplane.u1mpn.fruVendor"} . "." .  
           $V{"midplane.u1mpn.fruModel"} . "." .
           $V{"midplane.u1mpn.fruSerialNo"};
    $key =~ s/[^\w\-\.]/_/g;
  } else {
    $key = $device->{ipno};   # $portWWN;
  }
  $key = lc($key);

  $V{"loopcard.header"} = "loopcard";
  $V{"midplane.header"} = "midplane";
  $V{"power.header"} = "power";
  $V{"port.header"} = "port";
  $V{"unit.header"} = "unit";

# fix the missing serialNo
  foreach my $k ('u1pcu1','u1pcu2','u2pcu1','u2pcu2') {
    if ($V{"power.$k.fruSerialNo"} =~ /refer to/) {
       $V{"power.$k.fruSerialNo"} = "$key.$k";
    }
  }

  Debug->dump('T3Config'  , \%V);
  $agent->addIdentification(\%V);

  return ($portWWN,$port2WWN, $key, \%V);

}

sub parse_sys {
  my($agent, $report, $sys) = @_;
  my( $l, @b);

  my($in) = 0;
  foreach $l (@$sys) {
     if (lc($l) =~ /-- system info/) {
        $in = 1;
     } elsif ($in) {
        @b = split(/,/, $l);
        if ($#b > 1) {
          chop($b[2]) if (substr($b[2],-1) eq ";");
          $b[2] =~ s/ +/ /g;
          $b[2] =~ s/\c[//g;
          next if (substr($b[1],0,6) eq "sysSec");
          $report->{"system.$b[1]"} = Util->rtrim($b[2]);
        }
     } 
  }
}

# get CIM-Key using snmp locally or from the right host
# .iso.3.6.1.4.1.42.2.28.2.2.3.2.1.6.1.14
# .iso.3.6.1.4.1.42.2.28.2.2.3.2.1.7.1.14
# .iso.3.6.1.4.1.42.2.28.2.2.3.2.1.9.0.14 

sub getCimKey {
  my($class, $ip, $host) = @_;

  
}
  

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

  my($name) = $r->{_id}{name};
  my($comm);
  my($out);
  my($tableCnt) = $arg->{tableCnt};
  my($host0) = $host || System->hostname();
  $comm = "<br><font color=red>Management-Path Lost!</font>" if ($r->{_status} eq "CC");

  my($v) = $r->{_value};
  $out .= $class->reportHead("T3", $r);
  $out .= "
   <tr><td bgcolor=#F0F0F0 align=right><b>Name:</td><td width=25%>&nbsp;$r->{_id}{display}</td>
       <td bgcolor=#F0F0F0 align=right><b>WWN:</td><td>$v->{'port.u1p1.portWWN'} $v->{'port.u2p1.portWWN'}
   <tr><td bgcolor=#F0F0F0 align=right><b>Monitored:</td><td>&nbsp;$host0</td>
       <td bgcolor=#F0F0F0 align=right><b>Comm:</td><td>&nbsp;$comm</td>
  </table>
  <table border=0 cellspacing=0 width=95% bgcolor=white><tr><td></table>
  <table border=1 cellspacing=0 width=95% bgcolor=white>

  <tr bgcolor=#DDDDFF>
    <th><font color=black>Type</th>
    <th><font color=black>Identification</th>
    <th><font color=black>Comp</th>
    <th><font color=black>Status</th>
    <th><font color=black>Rev./Info</th>
  ";

#  my($mon) = &mon('t3',$name);

  my($bg, $cnt, $u, $d, $comp, $status, $id, $rev, $type, $bat, $fans);
  $cnt = 0;
  for ($u=1; $u <= 2; $u++) {
     $out .= "<tr bgcolor=#FFFFE0><td colspan=5 ><b>&nbsp;Unit $u</td>";
     last if (!$v->{"disk.u${u}d1.fruId"});
     for ($d=1; $d <= $class->diskTotal(); $d++) {
        $comp="disk.u${u}d$d";
        $status = $v->{"$comp.fruStatus"} . "- " . $v->{"$comp.fruState"};
        $bg = ($status eq "ready- enabled")? "":"bgcolor=#FFD0D0";
        $id = $v->{"$comp.fruVendor"} . "/ " . $v->{"$comp.fruModel"};
        $rev = $v->{"$comp.fruRevision"};
        my $pathstat;
        if (exists($v->{"$comp.pathstat"}) && $v->{"$comp.pathstat"} ne "OK") {
          $pathstat = " <font color=red>pathstat:" . $v->{"$comp.pathstat"}
        }
        $out .=  
            "<tr><td><center>Disk".
            "<td><small>$id".
            "<td>u${u}d$d".
            "</td><td $bg>$status$pathstat</td><td>$rev</td>\n";

        $cnt++;
     }
     $id =  $v->{"controller.u${u}ctr.fruVendor"} . "/ " .
            $v->{"controller.u${u}ctr.fruModel"};

     $status = $v->{"controller.u${u}ctr.fruStatus"} . "- ".
               $v->{"controller.u${u}ctr.fruState"};
     $bg = ($status eq "ready- enabled")? "":"bgcolor=#FFD0D0";
     $rev = $v->{"controller.u${u}ctr.fruRevision"};
     $out .= "\n<tr><td><center>Cntrl<td><small>$id<td>u$u.ctrl<td $bg>$status<td>$rev</td>";

     $id = $v->{"controller.u${u}ctr.fruVendor"} . "/ " . $v->{"midplane.u${u}mpn.fruSerialNo"};
     $status = $v->{"midplane.u${u}mpn.fruStatus"} . "- " . $v->{"midplane.u${u}mpn.fruState"};
     $bg = ($status eq "ready- enabled")? "":"bgcolor=#FFD0D0";
     $rev = $v->{"midplane.u${u}mpn.fruRevision"};
     $out .= "\n<tr><td><center>Midplane<td><small>$id&nbsp;<td>u$u.mpn<td $bg>$status<td>$rev&nbsp;</td>";

   for ($d=1; $d<= 2; $d++) {
        $comp = "loopcard.u${u}l$d";
        $status = $v->{"$comp.fruStatus"} . "- " . $v->{"$comp.fruState"};
        $bg = ($status eq "ready- enabled")? "":"bgcolor=#FFD0D0";
        $id = $v->{"$comp.fruSerialNo"};
        $rev = $v->{"$comp.fruRevision"};
        $out .= "<tr><td><center>Loop<td><small>$id<td>u${u}l$d<td $bg>$status</td><td>$rev</td>\n";
     }

     for ($d=1; $d<= 1; $d++) {
        $comp = "port.u${u}p$d";
        $status = $v->{"$comp.portStatus"};
        $bg = ($status eq "online")? "":"bgcolor=#FFD0D0";
        $id  = $v->{"$comp.portWWN"};
        $rev = $v->{"$comp.fruRevision"};
        $type = $v->{"$comp.portType"};
        $out .= "<tr><td><center>Port<td><small>$id<td>u${u}p$d</td><td $bg>$status</td><td>$rev&nbsp;</td>\n";
     }

     for ($d=1; $d<= 2; $d++) {
        $comp = "power.u${u}pcu$d";
        $status = $v->{"$comp.fruStatus"} . "- " . $v->{"$comp.fruState"};
        $bg = ($status eq "ready- enabled")? "":"bgcolor=#FFD0D0";
        $id = lc($v->{"$comp.fruVendor"}) . "- " . $v->{"$comp.fruModel"};
        $bat = $v->{"$comp.fruPowerBatState"};
        $fans = "fan1:" . $v->{"$comp.fruPowerFan1State"} . ", fan2:" . $v->{"$comp.fruPowerFan2State"};
        $rev = $v->{"$comp.fruRevision"};
        $out .= "<tr><td><center>Power<td><small>$id<td>u${u}pcu$d<td $bg>$status</td><td>$rev&nbsp;</td>\n";
        my $bg1 = "$bat, $fans";
        $bg1 =~ s/fault/<font color=red>fault<\/font>/g;
        $out .= "<tr><td colspan=1>&nbsp;<td colspan=4>Battery:$bg1</td>\n";
     }
     for ($d=1; $d<= 2; $d++) {
        $comp = "volume.u${u}vol$d";
        $status = $v->{"$comp.volStatus"};
        $name   = $v->{"$comp.volName"};
        $bg = ($status eq "mounted" || !$status)? "":"bgcolor=#FFD0D0";
        my $raid =  $v->{"$comp.volRaidLevel"};
        $raid = "($raid)" if ($raid);
        my $cap  =  sprintf("%.2f", ($v->{"$comp.volCapacity"} / 1000));
        $out .= "<tr><td>Volume<td>$name $raid&nbsp;<td>u${u}vol$d</td>".
                "<td $bg>$status&nbsp;<td>$cap Meg</td>";
     }
  }
  my $done;
  my $lun;
  for ($d=0; $d < 16; $d++) {
     $comp = "slice.$d";
     $name = $v->{"$comp.volSliceName"};
     last if (!$name);
     if (!$done) {
         $out .= "<tr bgcolor=#FFFFE0><td colspan=5><b>Slices</th>";
         $out .= "<tr bgcolor=#DDDDFF><th>&nbsp;<th>Name<th>Volume<th>Associated<br>LUN<th colspan=2>Size<br>(512K Blocks)</td>";
         $done = 1;
     }
     my $vol  = $v->{"$comp.volId"};
     my $lun  =  $v->{"$comp.lun"};
     #(my $junk, my $lunnum) = split(/lun/, $lun);
     #my $perm  = $v->{"lun.$lunnum.lunMaskAccessDefault"};
     my $size = $v->{"$comp.volSliceSize"};
     $out .= "<tr><td>slice $d<td>$name<td>$vol<td>$lun<td colspan=2>$size</td>";
  }
  if (!$tableCnt) {
    $out .= "</table>&nbsp;<br>";
  }
  return $out ;

}


# DISK LINKFAIL LOSSSYNC LOSSSIG PROTOERR INVTXWORD INVCRC
# --------------------------------------------------------
# u1d1  1        13       0       0        145       0       
#

sub FCCounters {
  my($class ,$arg) = @_;
  my(%ENC, $disks, $in, $l, $node, %WWN, @HBA, $num, $x, %ALPA, %MPX);

  my($confDevs) = $arg->{devs}; 
  my($report) = 1 if ($arg->{report});
  my($encs)   = $arg->{encs};
  my($renv) = System->get_renv();
  my($TO) = $renv->{'timeout.luxadm'};

  my($lux) = "/usr/sbin/luxadm";
  my($err,$probe);
  
#
# Find ENCLOSURES AND PATHS with PROBE
#
  $err = $class->readT3IB(0, \%ENC, \@HBA, \%MPX);

  if (defined($encs)) {
    %ENC = ();
    my(@a) = split(/,/, $encs);
    foreach my $enc (@a) {
        $ENC{$enc}  = 1;
    }
  }
  
  if (1) {

  foreach my $wwn (keys %ENC) {
    $WWN{$wwn}{enc} = $wwn ; # $ENC{$wwn};
    if ($confDevs) {
       foreach my $d (@$confDevs) {
          if ($d->{type} eq "t3" && 
               lc(substr($d->{wwn},-4)) eq lc(substr($wwn,-4))) {
               $WWN{$wwn}{enc} = $d->{name};
          }
       }
    } 
  }
  }

#
# FOR EACH HBA, GET COUNTERS 
#
  my($map, $err2, $rdls, @c, $hba);
  for ($x=0; $x <= $#HBA; $x++ ) {
     $hba = $HBA[$x];
     Debug->print2("FC-T3 : reading hba $x ($hba)");
     my($err,$map) = Util->run_command("$lux -e dump_map $hba","", $TO, {cache => 0});
     my($last) = substr($hba,-1);
     my($err2,$rdls) = Util->run_command("$lux -e rdls $hba","", $TO, {cache => 0});
     $in =0;
     my($fabric) = 0;
     foreach $l (@$map) {
        next if ($l =~ /^ *$/);
        if ($l =~ /^Pos/) {
            $in = 1;
            $fabric = 1 if ($l =~ /Port_ID/);
        } elsif ($in) {
          my($n,$alpa,$id,$hard,$port,$node,$type,$desc);
          if ($fabric) {
            ($n,$alpa,$hard,$port,$node,$type,$desc) = split(/\s+/, $l,7) ;
          } else {
            ($n,$alpa,$id,$hard,$port,$node,$type,$desc) = split(/\s+/, $l,8) ;
          }
          $alpa = sprintf("%02s", $alpa);
          $ALPA{$x}{$alpa}{port} = $port; 
          $ALPA{$x}{$alpa}{node} = $node;  # wwn
          $ALPA{$x}{$alpa}{type} = $type;
          @c = split(/ /, substr($desc,1));
          $ALPA{$x}{$alpa}{desc} = $c[0];
        }
     }
     $in =0; 
     foreach $l (@$rdls) {
        next if ($l =~ /^ *$/);
        if ($l =~ /^al_pa/) {
           $in = 1;
        } elsif ($l =~ /^NOTE:/) {
           $in = 0;
        } elsif ($in) {
           my($alpa,$lnk,$sync,$signal,$seq,$word,$crc) = split(/\s+/, $l);
           $alpa = sprintf("%02s", $alpa);
           $ALPA{$x}{$alpa}{link}   = $lnk;
           $ALPA{$x}{$alpa}{sync}   = $sync;
           $ALPA{$x}{$alpa}{signal} = $signal;
           $ALPA{$x}{$alpa}{seq}    = $seq;
           $ALPA{$x}{$alpa}{word}   = $word;
           $ALPA{$x}{$alpa}{crc}    = $crc;
        }
     }
     
  }
  my($out, @X, %SUMM,  $form0, $form, $form2, $al, $hba0);
  my(%X, %H1);
  my(%ses_cnt) = 0;
  if (!$report) {
    for ($x=0; $x <= $#HBA; $x++ ) {
       my($hb) = $HBA[$x];
       $hb = substr($hb, 0, -7) if (substr($hb, -7) eq ":devctl");
       $H1{$x} = $hb;
    }
  } 
  for ($x=0; $x <= $#HBA; $x++ ) {
     $hba = $hba0 = $HBA[$x];
     $hba =~ s/\/devices\///;
     if ($report) {
       @X = ();
       $out .= "\nHBA ($x): $hba \n";
       $form0 = "%-5.5s %-10.10s %-10.10s %-4.4s %-16.16s %-12.12s %-6.6s";
       $form  = "$form0 %6s %6s %6s %6s %6s %6s\n";
       $form2 = "$form0 %6d %6d %6d %6d %6d %6d\n";
       $out .= sprintf($form, "Path",
              "Enclosure","Disk","Alpa","Wwn","Logical","Desc","Link","Signal","Seq","Crc",
              "Sync","Word");
       $out .= "-" x 111 . "\n";
     }
     my($y) = $ALPA{$x};

     my($al2, $wwn, $enc, $disk, $device);
     my($hbadone)= 0;
     foreach $al (reverse sort keys %$y) {  # read each element on this hba(ctrl/hba)
         $al2 = $y->{$al};
         $wwn  = $al2->{node};
         if ($WWN{$wwn}{enc}) {
             $disk = "port.0";
             $enc = $WWN{$wwn}{enc};
         } else {
             next if ($hbadone);
             $hbadone = 1;
             #$enc = "hba";
             $disk = "hba";
         }
         my($path) = $x;
         if ($report) {
           my($enc0) = $enc;
           $enc0 = substr($enc0,-10) if (length($enc0) > 10) ;
           push(@X, sprintf($form2, $path, $enc0, $disk, $al, $wwn, $device, $al2->{desc},
                        $al2->{link}, $al2->{signal}, $al2->{seq}, $al2->{crc},$al2->{sync},$al2->{word}));
         } else {
           my($key) = "$path|$enc|$disk|t3";
           $X{$key} = "$al2->{link}\t$al2->{signal}\t$al2->{seq}\t$al2->{crc}\t$al2->{sync}\t$al2->{word}";
         }
     }
     if ($report) {
       foreach $l (sort @X) {
         $out .= $l;
       }
     }
  }
  $err = undef;

  if (!$report) {
    my($out) = { data => \%X,  hba => \%H1 };
    return ($out);
  } else {
    return $out;
  }
}

#  1         2         3       4         5       6
# LINKFAIL LOSSSYNC LOSSSIG PROTOERR INVTXWORD INVCRC
# link, sig, seq, crc, sync, word
#  1     3    4    6    2     5
#  ($sys_err, $hash, .command_error)

sub FCCountersOOB {
  my($class, $dev) = @_;
  my(@L, @l, %X, %W);
  my($err, $key);
  my($unit, $path, $l, $disk, $enc, $sim);

require "Net/Telnet.pm";

  if (!$dev->{telnet}) {
    return ("No telnet password",{});
  } elsif ($dev->{type} ne "t3") {
    return ("$dev->{name} not a T3", {} );
  }
  
  my($ip) = $dev->{ip};
  my($pass) = Util->decode($dev->{telnet});
  my $diskTotal = $class->diskTotal();
  my($t) = new Net::Telnet (
             errmode => "return",
             Timeout   => 30,
             Prompt    => '/<\d+\>/',
             );
  if (!defined($t->open($ip))) {
      return ("Cannot open $ip", {});
  }
  $t->login("root", $pass);
  if ($t->errmsg()) {
     return ($t->errmsg(), {});
  }


 if (0) {
  @l = $t->cmd("port list");
  foreach my $port (@l) {
     my(@b) = split(/\s+/, $port);
     $W{substr($b[0],0,2)} = $b[5];
  }
 }
  foreach $path ('0','1') {
    foreach $unit ('1','2') {
       @l = $t->cmd(".disk linkstat u${unit}d1-$diskTotal path $path");
       foreach $l (@l) {
         if ($l =~ /Failed/) {
            $err .= $l;
         } elsif ($l =~ /^u\dd\d/) {
           my(@a) = split(/\s+/, $l);
           $disk = $a[0];
           $key = "$path|$dev->{ipno}|$disk|t3";
           $X{$key} =  "$a[1]\t$a[3]\t$a[4]\t$a[6]\t$a[2]\t$a[5]";
         }
       }
    }
  }

  foreach $sim ('0','1', '2') {
      @l = $t->cmd(".sim -f num $sim linkstat");
      foreach $l (@l) {
        if ($l =~ /Error/) {
            $err .= "sim$sim: $l";
        } elsif ($l =~ /^\d+\s+\d+/) {
          my(@a) = split(/\s+/, $l);
          $key = "|$dev->{ip}|sim$sim|t3";
          $X{$key} =  "$a[0]\t$a[2]\t$a[3]\t$a[5]\t$a[1]\t$a[4]";
        }
     }
  }

  $t->close;
  return (undef,  \%X, $err);
}


sub inbandProbe {
  my($class) = @_;

  my($lux) = "/usr/sbin/luxadm";

  my($err,$probe) = Util->run_command("$lux probe -p", "luxprobe.txt", 40);
  my($in, $l, @list, $disks);
  my($hbalist, $t3, $ix);
  for ($ix=0; $ix <= $#$probe; $ix++) {
      $l = $probe->[$ix];
      if ($l =~ /Found/) {
        $in = 1;
      } elsif ($in) {
        if ($l =~ / Node WWN:(.+)\s+Device Type:Disk/) { # t3 or internal..
          my($wwn) = Util->trim($1);
          ($err, $disks) = Util->run_command("$lux display $wwn","lux",40);
          my($rep) = "@$disks";
          if ($rep =~ /T300/) {
             push(@list, $wwn);
          }
        }
      }
  }
  return @list;
}

#
# T3 InBand
# flag == 1 : only look for mpxio path 
# like  Logical Path:/dev/rdsk/c14t60020F2000003EE53AAF7A09000DA257d0s2

sub readT3IB {
  my($agent, $cache1, $ENC, $HBA, $MPX, $flag) = @_;
  my($err, $probe, $disks, $mpx_wwn, $mpx_class);

  my($renv) = System->get_renv();
  my($TO) = $renv->{'timeout.luxadm'};

  my($lux) = "/usr/sbin/luxadm";
  ($err,$probe) = Util->run_command("$lux probe -p","", $TO);

  return $err if ($err);
  my($in, $l);
  my($hbalist, $t3, $ix, $h2, $h3);
  for ($ix=0; $ix <= $#$probe; $ix++) {
      $l = $probe->[$ix];
      if ($l =~ /Found/) {
        $in = 1;
      } elsif ($in) {
        if ($l =~ / Node WWN:(.+)\s+Device Type:Disk/) { # t3 or internal..
          if ($flag) {
             next if ($probe->[$ix+3] !~ /scsi_v/);
          }
          my($wwn) = Util->trim($1); 
          ($err, $disks) = Util->run_command("$lux display $wwn","", $TO);
          my($rep) = "@$disks";
          if ($rep =~ /T300/) {
             $rep =~ /Serial Num:\s+(\d+)/;
             my($name) = $1;
             foreach my $el ('A','B') {
               if ($rep =~ /WWN\(Port $el\):\s+(\w+)/) {
                  my $w = $1;
                  substr($w,7,1) = "0" if (length($w) > 7);
                  $ENC->{$w} = $name;
               }
             }

             while ($probe->[$ix+1] =~ /Logical Path:(.*)/) {
               my($hba) = Util->trim($probe->[$ix+3]);
               if ($hba !~ /devices\/scsi_/) {
                    my($ii) = rindex($hba, "/");
                    $hba = substr($hba, 0 , $ii);
                    if (index($hbalist, "$hba,") < 0) {
                      push(@$HBA, $hba);
                      $hbalist .= "$hba,";
                    }
               } else {
                   $h3 = $h2 = $mpx_wwn = $mpx_class = "";
                   foreach my $ll (@$disks) {
                      if ($ll =~ /^\s+Controller\s+(.*)/) {
                         $h3 = $1;
                         $h2 = $1 . ":devctl";
                         if (index($hbalist, "$h2,") < 0) {
                            push(@$HBA, $h2);
                            $hbalist .= "$h2,";
                         }
                      } elsif ($ll =~ /Device Address\s+([0-9a-f]+)/) {
                         $mpx_wwn = $1;
                      } elsif ($ll =~ /Class\s+(.*)/) {
                         $mpx_class = $1;
                      } elsif ($ll =~ /State\s+(.*)/) {
                         $MPX->{$mpx_wwn} = "$1\t$h3" if ($mpx_class eq "primary");
                      }
                   }
           
               }
               $ix += 3;
             }
          }
        }
     }
  }
  return ;
}


1;
