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

#  $Name:  $ 
#  $Id: A5K.pm,v 1.46 2002/10/27 21:43:18 ccadieux Exp $

#
# This package/Class inherits from the Agent Package and must implements
# the Agent interface. The Agent interface is composed of:

#
# isSelectable() : can this module be terned off from the GUI
# revision()     : autoatic
# new()          : create an empty object.
# RUN()          : execute the module against all device of this catagory
# getPortKey()   : find the key for a specific port
# FCCounters()   : get FibreChannel error counters for each subcomponent.

use strict;
use Agent;
use base 'Agent';

sub isSelectable {"Sun A5000"}
sub revision {'$Revision: 1.46 $'}

sub category {Report::CAT_A5K}
sub lux_category {"SENA"}


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

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


# translate port to the right  CIM key 

sub getPortKey {
  my($class, $wwn, $port) = @_;
  return undef if (!$wwn);
  return "$wwn.interface_board." . (($port==0)? "A":"B");
}

# called by V880 and A5
sub RUN {
  my($agent) = @_;
  my($HBA, $logfile, $r, @results);
  my($xml, @lux_dif, $dif, $ev, $found);
  my($log_err, $lines);
  my(%DONE, $report, $device, $wwn, $id, $x, $l, $connect_errs);
  $DB::single=1;
  
  my($renv) = System->get_renv();

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

  my($today) = Util->today("YMDH");

  my($lux) = System->find_luxadm;

  my($dc) = 0;

  foreach $device ( $agent->deviceList()) {
    next if ($device->{active} eq "N"); 
    $dc++;
    Debug->print1("-> " . uc($device->{type}) . ": Reading device $device->{name}/$device->{wwn}");

    ($wwn, $connect_errs, $report) = $agent->INSTRUMENTATION($device, $lux);
     if ($connect_errs eq "BUSY") {
       Debug->print2("$device->{name} is busy, skipping!");
       next;
     }
     if ($connect_errs && $Util::STILL_THERE > 0) {
       Debug->err(LUXADM_ERR => "luxadm hangs and cannot be killed, aborting");
       Timelapse->stop(ref($agent));
       return;
     }
     $wwn = lc($wwn);

     $id = {  
              deviceName  => $device->{wwn},
              active      => $device->{active},
              logFile     => "",
              display     => "$device->{name} (wwn=$device->{wwn})",
              name        => $device->{name},
              class       => $device->{class},
              category    => $agent->category(),
              ip          => "",
           };
     $report = {} if (!$report);
     $agent->copyDev($device, $report);

     $HBA = $device->{hba} || System->get_hba;
     $report->{"id.name"} = $device->{name};
     $report->{"id.ipno"} = System->get_ipno();
     $report->{"id.wwn"} = $device->{wwn};

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

     } else {
        PDM->saveReport(Report->new($id, $report , undef));
     }
  } 
  Debug->print2("  No devices found") if (!$dc);
  Timelapse->stop(ref($agent));
}

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

use vars qw ($ERR);

sub getWWN {
  my($agent, $name, $host) = @_;
  my($wwn);
  $ERR = undef;

  if (!$host) {
     return &get_WWN({name => $name});
  } else {
     my $rc = Util::Http->getCommand($host, "Agent::A5K::WWN&name=$name&HTTP=1" , 20);
     if ($rc =~ /ERR/) {
        $ERR = "A5K: getWWN: cannot identify $name on $host";
        return undef;
     } else {
        return substr($rc,4) ;
     }
  }
}

sub get_WWN {
  my($q) = @_;
  my $name = $q->{name};
  my($err,$com) = Util->run_command("/usr/sbin/luxadm display $name 2>&1", 
                          "luxadm.txt" , 30);
  if ($err) {
    $q->{HTTP}? print "\nERR $err" : return $err;
  }
    
  my $out = "@$com";
  $out =~ /Node WWN:([0-9a-f]+)/;
  my $wwn = $1;
  $q->{HTTP}? print "\nOK $wwn" : return $wwn;
}

sub getGbicStatus {
  my($agent, $device) = @_;

  my $renv = System->get_renv();
  my $TO  = $renv->{'timeout.luxadm'};
  my $lux = "/usr/sbin/luxadm";
  my $w = $device->{wwn};
  my($err,$com) = Util->run_command("$lux display $w 2>&1", "luxadm.txt" , $TO);
  my ($in, %info, $ib, $no, $x, $status, $rev);
  foreach my $l (@$com) {
    if ($l =~ /^ESI/) {
        $in= "esi";
    } elsif ($in eq "esi") {
      if ($l =~ /^\s+([AB]): (.*)/) {
         $ib = $1; $x = $2; $x =~ s/\.//g;
         $no = ord($ib) - ord('A');
         ($status, $rev) = &get_status_rev($x);
         $info{"interface_board.$ib.rev"}    = $rev;
         $info{"interface_board.$ib.status"} = $status;
      } elsif ($l =~ /^\s+([01]) (.*)/) {
         my($port) = $1; $status = $2;
         my(@c) = split(/[\(\:]/, $status);
         $info{"interface_board.$ib.gbic$port.status"} = $c[0];
         $info{"interface_board.$ib.gbic$port.version"} = $c[1] if ($c[1]);
         $info{"interface_board.$ib.gbic$port.reason"} = $c[2] if ($c[2]);
      }
    }
  }
  return \%info;
}
  

sub INSTRUMENTATION {
  my($agent, $device, $lux) = @_;
  my(@s, %dev, $in, %info, $key, $state, $num);
  my($v3, $v1, $v2, $x, $wwn, $status, $rev, $ib, $no, $id);

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

  my $w = $device->{wwn} || $device->{name};
  my($err,$com) = Util->run_command("$lux display $w 2>&1", "luxadm.txt" , $TO);
  return ("",$err, undef) if ($err);
  return ("", "BUSY", undef) if ("@$com" =~ /Device busy/);

  $info{"disk_front.header"} = "disk_front";
  $info{"disk_rear.header"} = "disk_rear";
  $info{"backplane.header"} = "backplane";
  $info{"power.header"} = "power";
  $info{"fan.header"} = "fan";
  $info{"loop.header"} = "loop";
  $info{"interface_board.header"} = "interface_board";
  my $disk_done = 0;

  foreach my $l (@$com) {
    if ($l =~ /^ *Error:/) {
       return ("",$l, undef);
    }   
    if ($l =~ /^SLOT/) {
      $in = "slot";
    } elsif ($l =~ /^FW Rev/) {
      $in = 0;
      $l =~ /FW Revision:([\d\.]+) .* +Node WWN:(.*) +Enclosure/;
      $info{'revision.value'} = Util->rtrim($1);
      $key = lc(Util->trim($2));
      $info{'id.wwn'} = $key;

    } elsif ($l =~ /^Power Supplies/) {
      $in = "powers";
    } elsif ($l =~ /^Fans/) {
      $in = "fans";
    } elsif ($l =~ /^ESI/) {
      $in = "esi";
    } elsif ($l =~ /^Disk/) {
      $in = "disk";
    } elsif ($l =~ /^Interconnect/) {
      $in = "inter";
    } elsif ($l =~ /^Loop/) {
      $in = "loop";
    } elsif ($l =~ /^Language/) {
      $in = 0;
    } else {
      if ($in eq "slot") {
        if (substr($l,0,1) =~ /\d/) {
          $num =  substr($l,0,2) + 0;
          $x = substr($l,7,18);
          $info{"disk_front.$num.exist"} = 1;  # use this to know if the row is there,
          $wwn = substr($l,25,16);
          if ($x =~ /Not Inst/) {
            $status = "OK"; $state = "NotInstalled";
          } else {
            $x =~ /([ \w]+)(.*)/;
            $state = Util->rtrim($1); 
            $status = $2; 
            $status =~ s/[\(\)\.]//g;
            $status = Util->trim($status);
            $status =~ s/ /_/g;
          }
          $wwn = " " if ($wwn !~ /^[ 0-9a-f]+$/);
          $info{"disk_front.$num.wwn"} = $wwn;
          $info{"disk_front.$num.state"} = $state;

          $info{"disk_front.$num.status"} = $status;
          if ($state eq "On" && !$disk_done && $wwn =~ /^[0-9a-f]+$/ ) {
              my $info2 = {};
              $agent->disk_display("A", $wwn, $info2, $lux, 1);
              if ($info2->{"A.portA.class"}) {
                $info{"interface_board.A.mpx.class"} = $info2->{"A.portA.class"};
                $info{"interface_board.A.mpx.state"} = $info2->{"A.portA.state"};
                $info{"interface_board.B.mpx.class"} = $info2->{"A.portB.class"};
                $info{"interface_board.B.mpx.state"} = $info2->{"A.portB.state"};
              }
              $disk_done = 1;
          }
#             $agent->disk_display("disk_front.$num", $wwn, \%info, $lux, "f$num");
  
          $x = substr($l,45,18);
          $wwn = substr($l,63,16);
          if ($x =~ /Not Inst/) {
            $status = "OK"; $state = "NotInstalled";
          } else {
            $x =~ /(\w+)(.*)/;
            $state = $1; $status = $2;
            $status = Util->trim($status);
            $status =~ s/[\(\)\.]//g;
            $status =~ s/ /_/g;
          }
          $wwn = " " if ($wwn !~ /^[ 0-9a-f]+$/);
          $info{"disk_rear.$num.wwn"} = $wwn;
          $info{"disk_rear.$num.state"} = $state;

          $info{"disk_rear.$num.status"} = $status;
#         $agent->disk_display("disk_rear.$num", $wwn, \%info, $lux, "r$num");
        }
        
      } elsif ($in eq "powers") {
        $l =~ /0 (.*)\t1 (.*)\t2 (.*)/;
        $v1 = $1; $v2 = $2; $v3 = $3;
        if ($v1) {
           $v1 =~ s/\.//g; $v2 =~ s/\.//g; $v3 =~ s/\.//g;
           ($status, $rev) = &get_status_rev($v1);
           $info{"power.0.rev"}    = $rev;
           $info{"power.0.status"} = $status;

           ($status, $rev) = &get_status_rev($v2);
           $info{"power.1.rev"}    = $rev;
           $info{"power.1.status"} = $status;

           ($status, $rev) = &get_status_rev($v3);
           $info{"power.2.rev"}    = $rev;
           $info{"power.2.status"} = $status;
        } else {
           $info{"power.text"} = $l;
        }
      } elsif ($in eq "fans") {
        $l =~ /0 (.*)\t1 (.*)/;
        $v1 = $1; $v2 = $2;
        $v1 =~ s/\.//g; $v2 =~ s/\.//g;
        ($status , $rev) = &get_status_rev($v1);
        $status =~ s/ //g;
        $info{"fan.0.rev"}    = $rev;
        $info{"fan.0.status"} = $status;

        ($status , $rev) = &get_status_rev($v2);
        $status =~ s/ //g;
        $info{"fan.1.rev"}    = $rev;
        $info{"fan.1.status"} = $status;

      } elsif ($in eq "esi") {
        if ($l =~ /^\s+([AB]): (.*)/) {
           $ib = $1; $x = $2; $x =~ s/\.//g;
           $no = ord($ib) - ord('A');
           ($status, $rev) = &get_status_rev($x);
           $info{"interface_board.$ib.rev"}    = $rev;

           $info{"interface_board.$ib.status"} = $status;
        } elsif ($l =~ /^\s+([01]) (.*)/) {
           my($port) = $1; $status = $2;
           my(@c) = split(/[\(\:]/, $status);
           $info{"interface_board.$ib.gbic$port.status"} = $c[0];
           $info{"interface_board.$ib.gbic$port.version"} = $c[1] if ($c[1]);
           $info{"interface_board.$ib.gbic$port.reason"} = $c[2] if ($c[2]);

        }
      } elsif ($in eq "disk") {
        if ($l =~ /(\w+) Backplane: +(.*)/) {
          $v1 = $1;
          $x = $2; $x =~ s/\.//g;
          ($status, $rev) = &get_status_rev($x);
          my($pos) = lc($v1);
          $info{"backplane.$pos.status"} = $status;
          $info{"backplane.$pos.rev"}    = $rev;
        }
      } elsif ($in eq "inter") {
        $l =~ s/\.//g;
        
        ($status , $rev) = &get_status_rev(Util->ltrim($l));
        $info{"interconnect.status"} = $status;
        $info{"interconnect.rev"} = $rev;

#     Loop A is configured as a single loop.
      } elsif ($in eq "loop") {
        $l =~ /Loop (\w+) (.*)/;
        $id = $1;
        $no = ord($id) - ord('A');
        $info{"loop.$id.info"} = $2;
      }
    }
  }
  # do not loose information from last report.
  my($oreport) = PDM->getOldReport("a5k:$key");
  if ($oreport) {
    my($orep, $num);
    $orep = $oreport->content;
    foreach my $side ('disk_front','disk_rear') {
      for ($num=0; $num <= 10; $num++) {
	if ($orep->{"$side.$num.vendor"}) {

          $info{"$side.$num.vendor"}     = $orep->{"$side.$num.vendor"};
          $info{"$side.$num.revision"}   = $orep->{"$side.$num.revision"};
          $info{"$side.$num.product_id"} = $orep->{"$side.$num.product_id"};
          $info{"$side.$num.serial_no"}  = $orep->{"$side.$num.serial_no"};
          $info{"$side.$num.u_capacity"} = $orep->{"$side.$num.u_capacity"};
        }
      }
    }
  }
  $agent->addIdentification(\%info);
  Debug->dump('a5kConfig', \%info);
  return ($key, "", \%info);
}

# called by health monitor when needed (discovery, audit, topology )
# disk is * or  'disk_front.2' or 'disk_rear.2'

sub disks_display {
  my($agent, $disk, $rep) = @_;
  my($num, %info);
  my($lux) = System->find_luxadm;

  if ($disk eq "*") {
    for ($num=0; $num <= 10; $num++) {
       my($wwn) = $rep->{"disk_front.$num.wwn"};
       $agent->disk_display("disk_front.$num", $wwn, \%info, $lux, "f$num");
       $wwn = $rep->{"disk_rear.$num.wwn"};
       $agent->disk_display("disk_rear.$num", $wwn, \%info, $lux, "r$num");
    }
  } else {
       my($wwn) = $rep->{"$disk.wwn"};

       my(@a) = split(/\./, $disk);
       my($parm) = ($disk =~ /front/)? "f$a[1]":"r$a[1]";
       
       $agent->disk_display($disk, $wwn, \%info, $lux, $parm);
  }
    
  # merge new info into existing report
  foreach my $v (keys %info) {
      $rep->{$v} = $info{$v};
  }
}

  

sub disk_display {
  my($agent, $head, $wwn, $info, $lux, $num) = @_;
  my($x, @a);

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

  $wwn = Util->rtrim($wwn);
  if ($wwn) {
     Debug->dot2;
  } else {
     Debug->print2("    -> Cannot probe $head, no wwn");
     return;
  }
  my($err,$com) = Util->run_command("$lux display $wwn", "luxadm_disk.txt", $TO, {cache => 0} );
  my $path = 0;
  my $ab;
  foreach my $l (@$com) {
     
     @a = split(/ *:\s*/, $l);
     if ($a[0] =~ /Status\(Port (\w+)\)/) {
       $info->{$head . ".port$1.status"} = $a[1];
     } elsif ($a[0] =~ /Vendor/) {
       $info->{$head . ".vendor"} = $a[1];
     } elsif ($a[0] =~ /Revision/) {
       $info->{$head . ".revision"} = $a[1];

     } elsif ($a[0] =~ /Product ID/) {
       $info->{$head . ".product_id"} = $a[1];
     } elsif ($a[0] =~ /Serial Num/) {
       my($sn) = System->get_testMode() ? "$a[1]$num":$a[1];
       $info->{$head . ".serial_no"} = $sn;
     } elsif ($a[0] =~ /Unformatted capa/) {
       $info->{$head . ".u_capacity"} = $a[1];
#
#   .portA.state
#   .portB.class
#
     } elsif ($l =~ /^ +Device Address\s+(.*)/) {
       $ab = (substr($1,0,2) eq "21") ? "A":"B";

     } elsif ($l =~ /^ +State\s+(.*)/) {
       $path++;
       $info->{$head . ".port$ab.state"} = $1;
     } elsif ($l =~ /^ +Class\s+(.*)/) {
       $info->{$head . ".port$ab.class"} = $1;
     }
  }
}

sub get_status_rev {
  my($v) = @_;

  my($ix) = index($v, "(");
  if ($ix >= 0) {
     return (substr($v,0,$ix), substr($v,$ix+1,-1));
  } else {
     return ($v, "");
  }
}

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

  my($out);
  my($tableCnt) = $arg->{tableCnt};
  my($rev) = $r->{'_value'}{"revision.value"};
  my($host0) = $host || System->hostname();
  $out .= $class->reportHead('A5K', $r);
  $out .= "
   <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>WWN:</td><td>&nbsp;$r->{_id}{deviceName}</td>
       <td bgcolor=#F0F0F0 align=right><b>Rev:</td><td>&nbsp;$rev</td>
  </table>
  
  <table border=1 cellspacing=0 cellpadding=1 width=95% bgcolor=white>
  <tr bgcolor=#E0E0E0>
    <th><font color=black>Type</th>
    <th><font color=black>Identification</th>
    <th><font color=black>Component</th>
    <th><font color=black>Status</th>
    <th><font color=black>Revision</th>
  ";

  my($name) = $r->{_id}{name};
#  my($mon) = &mon('a5k',$name);

 
  my($v) = $r->{_value};
  my($d, $x, $status, $wwn, $ports);
  my($cnt)= 0;
  foreach $d ('front','rear') {
    $rev = $v->{"backplane.$d.rev"};
    for ($x=0; $x <= 10; $x++) {
      my($comp) = "disk_$d.$x";
      $status = $v->{"$comp.state"} . "-" . $v->{"$comp.status"};
      $b = ($v->{"$comp.status"} eq "OK")? "":"<font color=red>";

      $wwn = $v->{"$comp.product_id"} . " " . 
             $v->{"$comp.serial_no"}  . " " . 
             $v->{"$comp.wwn"} ;

      $rev = $v->{"$comp.revision"};
      #$ports  = $v->{"$comp.portA.status"} . "/" . $v->{"$comp.portB.status"};
      $out .= 
           "<tr><td><center>Disk".
           "<td><small>$wwn&nbsp;" .
           "<td>$d.$x".
           "</td><td>$b$status</td><td>$rev&nbsp;</td>\n";
      $cnt++;
    }
  }
  $status = $v->{"fan.0.status"} . "/ " . $v->{"fan.1.status"};
  $rev = substr($v->{"fan.0.rev"},4) . "/ " . substr($v->{"fan.1.rev"},4);
  $out .= "<tr><td><center>Fans<td>&nbsp;<td>fan 0/1<td>$status<td>$rev</td>";

  $rev = substr( $v->{"power.0.rev"},4) . "/ " . substr( $v->{"power.1.rev"},4)  . "/ " .
        substr( $v->{"power.2.rev"},4) ;
  $out .= "<tr><td><center>Power<td>&nbsp;<td>Power 0/1/2<td>" . 
                           $v->{"power.0.status"} . "/ " .
                           $v->{"power.1.status"}  . "/ " .
                           $v->{"power.2.status"} . "</td><td>$rev\n";
  foreach $d ('A','B') {
    $out .= "<tr><td><center>Gbic$d<td>&nbsp;<td>Gbic 0/1<td>" .
                   $v->{"interface_board.$d.gbic0.status"} . "/ " .
                   $v->{"interface_board.$d.gbic1.status"} . "<td>".
                   $v->{"interface_board.$d.gbic0.version"} . "/ " .
                   $v->{"interface_board.$d.gbic1.version"}  . "\n";

  }
  $out .= "<tr><td><center>Inter<td>Interconnect<td>&nbsp;<td>$v->{'interconnect.status'}<td>".
          "$v->{'interconnect.rev'}</td>";
  if (!$tableCnt) {
    $out .= "</table>\n";
  }
  return $out;

}



# save = 1 : use cache for all
# save = 0 : use cache for discovery stuff
# save = 2 : don't use cache at all


use FC;

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

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

  my($report) = 1 if ($arg->{report});
  my($encs)   = $arg->{encs};
  my($lux)    = "/usr/sbin/luxadm";
  my($err,$probe);
   
#
# Find ENCLOSURES AND PATHS with PROBE
#
  ($err,$probe) = Util->run_command("$lux probe -p","luxprobe", $TO);

  my($hbalist, $ix, $a5);
  my($MPX);
  my(%WWN2E);

  for ($ix=0; $ix <= $#$probe; $ix++) {
      $l = $probe->[$ix];
      if ($l =~ /Found/) {
        $in = 1;
      } elsif ($in) {
        if ($l =~ / Name:(.+)\s+Node WWN:([^\s]+)/) {
          my $lux_cat = $class->lux_category();
          my $off  = 2;
          my $name = Util->trim($1);
          my $wwn  = Util->trim($2);

          next if ($l !~ /$lux_cat/);
          $off = 1 if ($l =~ /Logical Path/);
          if ($encs && index(",$encs,", ",$name,") >= 0) {
            $WWN2E{$wwn} = $name;
            $ENC{$wwn} = 1;
          } else {
            $WWN2E{$wwn} = $name;
            $ENC{$wwn} = 1;
          }

          while ($probe->[$ix+$off] =~ /Physical Path:(.*)/ &&
                  $probe->[$ix+1] !~ /Node WWN:/ ) {
             my($hba) = $1;
             if ($hba =~ /\/devices\/scsi_/) { # MPX
               $MPX = 1;
             } else {
               my($ix2) = rindex($hba, "/");
               $hba = substr($hba,0, $ix2);
               if (index($hbalist, "$hba,") < 0) {
                 push(@HBA, $hba);
                 $hbalist .= "$hba,";
               }
             }
             $ix+= $off;
          }
        }
      }
  }

if (0) {
  if (defined($encs)) {
    %ENC = ();
    my(@a) = split(/,/, $encs);
    foreach my $enc (@a) {
        $ENC{$enc}  = 1;
    }
  }
}
  
  my(%PORTS, $ib);
  my($done) = 0;
  foreach my $enc (keys %ENC) {  # enc is wwn of enclosure
    Debug->print2("FC-A5K: Reading enclosure: $enc");
    ($err, $disks) = Util->run_command("$lux display $enc 2>&1","luxenc", $TO);
     $in = "";
     foreach $l (@$disks) {
        if ($l =~ /^SLOT/) {
          $in = "slot";
        } elsif ($l =~ /^FW Rev/) {
          $in = 0;
          $l =~ /FW Revision:([\d\.]+) .* +Node WWN:(.*) +Enclosure/;
          $node = Util->trim($2);
          $WWN{$node}{side}   = 'ses.';
          $WWN{$node}{enc}   = $enc;

        } elsif ($l =~ /^Power Supplies/) {
          $in = "powers";
        } elsif ($l =~ /^Fans/) {
          $in = "fans";
        } elsif ($l =~ /^ESI/) {
          $in = "esi";
        } elsif ($l =~ /^Disk/) {
          $in = "disk";
        } elsif ($l =~ /^Interconnect/) {
          $in = "inter";
        } elsif ($l =~ /^Loop/) {
          $in = "loop";
        } elsif ($l =~ /^Language/) {
          $in = 0;
        } else {
          if ($in eq "slot") {
            if (substr($l,0,1) =~ /\d/) {
              $num =  substr($l,0,2) + 0;
              $x = substr($l,7,17);
              $x =~ /([ \w]+)(.*)/;
              $node = substr($l,25,16);
              $WWN{$node}{side} = "front.";
              $WWN{$node}{no}   = $num;
              $WWN{$node}{enc}  = $enc;

              $x = substr($l,45,17);
              $x =~ /(\w+)(.*)/;
              $node = substr($l,63,16);

              $WWN{$node}{side} = "rear.";
              $WWN{$node}{no}   = $num;
              $WWN{$node}{enc}   = $enc;
              if (( Util->rtrim($node) ne "") && $MPX && !$done) {
                $done = 1;
                my($err2, $details) = Util->run_command("$lux display $node","luxdisp", $TO);
                foreach my $ll (@$details) {
                    if ($ll =~ /^\s+Controller\s+(.*)/) {
                       my($h2) = $1;
                       if (index($hbalist, "$h2,") < 0) {
                          push(@HBA, $h2);
                          $hbalist .= "$h2,";
                       }
                    }
                }
              }
            }
          } elsif ($in eq "esi") {
            if ($l =~ /^\s+([AB]): (.*)/) {
               $ib = $1; $x = $2; $x =~ s/\.//g;

            } elsif ($l =~ /^\s+([01]) (.*)/) {
               my($port) = $1; my($status) = $2;
               if ($status =~ /O.K./) {
                  $PORTS{"a5k:$enc:$ib"} = $port;
               }
            }
          }
        }
     }
  }
  #open(O, ">" . System->get_home() . "/DATA/GBICS");
  #print O Data::Dumper::Dumper(\%PORTS);
  #close(O);

#
# FOR EACH HBA, GET COUNTERS
#
  my($map, $err2, $rdls, @c, $hba);
  for ($x=0; $x <= $#HBA; $x++ ) {
     $hba = $HBA[$x];
     $hba .= ":devctl" if (substr($hba,-6) ne "devctl" && $hba =~ /qlc/);
     Debug->print2("FC-A5K: dump_map and rdls on $x ($hba) ");
     my($err,$map) = Util->run_command("$lux -e dump_map $hba","dump_map", $TO, $arg);
     my($last) = substr($hba,-1);
     my($err2,$rdls) = Util->run_command("$lux -e rdls $hba","", $TO, $arg);
     $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;
          if ($desc =~ /Host/) {
             $type = "hba";
          } elsif ($desc =~ /SES/) {
             $type = "ses";
          } else {
             $type = "disk";
          }
          $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(%ses_cnt) = 0;
  my(%E1, %H1, %X);
  if (!$report) {
    for ($x=0; $x <= $#HBA; $x++ ) {
       $H1{$x} = $HBA[$x];
    }
    foreach $x (keys %WWN2E) {
       $E1{$x} = $WWN2E{$x};
    }

  }
  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 (keys %$y) {
         $al2 = $y->{$al};
         $wwn  = $al2->{node};

         if ($al2->{type} eq "hba") {
           $disk = "hba";
           $enc  = "";

         } elsif ($WWN{$wwn}{enc}) {
           $enc  = $WWN{$wwn}{enc};
           $disk = $WWN{$wwn}{side} ;
           if (substr($disk,0,3) ne "ses") {
              $disk .= $WWN{$wwn}{no};          # front.0, rear.0
           } else {
              $disk .= $ses_cnt{"$hba-$enc"}++; # port.0
           }

         } else {
           next;
         }

         $device = $WWN{$wwn}{"logical$hba0"};

         $device = substr($device,9) if (substr($device,0,10) eq "/dev/rdsk/");
         $device = substr($device,4) if (substr($device,0,5) eq "/dev/");
#        $device = substr($device,0, -2) if ($al2->{desc} =~ /Disk/ && substr($device,-2) eq "s2");

         $device = substr($device, -12) if (length($device) > 12);
         if ($report) {
           my($enc0) = $enc;
           $enc0 = substr($enc0,-10) if (length($enc0) > 10) ;
           push(@X, sprintf($form2, $x, $enc0, $disk, $al, $wwn, $device, $al2->{desc},
                $al2->{link}, $al2->{signal}, $al2->{seq}, $al2->{crc},$al2->{sync},$al2->{word}))
;
         } else {
            my($key) = "$x|$enc|$disk|a5k";
            $X{$key} = "$al2->{link}\t$al2->{signal}\t$al2->{seq}\t$al2->{crc}\t$al2->{sync}\t$al2->{word}";

#           push(@X, "$x|$enc|$disk|a5k\t$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;
       }
     }
  }
  $out = { hba => \%H1, enc => \%E1 , data => \%X };
  if (!$report) {
    return ($out);
  } else {
    return $out;
  }
}


1;

