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

#  $Name:  $ 
#  $Id: SWITCH.pm,v 1.55 2002/10/27 21:43:19 ccadieux Exp $

use strict;
use Agent;
use base 'Agent';
use Catalog;
use Data::Dumper;

sub isSelectable {"Sun Switch"}
sub revision {'$Revision: 1.55 $'}

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

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


sub getPortKey {
  my($class, $wwn, $port) = @_;
  return undef if (!$wwn);
  return "$wwn.port.$port";
}

  
sub RUN {
  my($agent,$ras_flag) = @_;
  my(%DONE, $HBA, $logfile, $r, @results);
  my( @all_connect_errors);
  my( @lux_dif, $dif, $xml, @all_dif);
  my($ev, @stats, $id, $log_lines, $sdt, $pdm);
  $pdm = $agent->{pdm};
  my($renv) = System->get_renv();

  $DB::single=1;
  Timelapse->start(ref($agent));

  my($today) = Util->today("YMDH");
  my($dc) = 0;
  my $se_conflict = System->get_se_conflict();

  foreach my $device ( $agent->deviceList()) {
    next if ($device->{active} eq "N"); # skip extra switches
    if ($se_conflict && index($se_conflict, $device->{name}) >= 0) {
      Debug->print2("-> Switch: skipping $device->{name}, detected se-config lockFile");
      next;
    }

    $dc++;
    Debug->print1("-> Switch: Reading device $device->{name}: $device->{ip}");

    if (!$device->{ip}) {
        Debug->errNoRepeat( 'SWITCH_IP',$device->{name}, 8 );
        next;
    }

    my($connect_errs, $wwn, $report) = $agent->read_switch($device);
    $wwn = lc($wwn);

    if ($wwn && $wwn ne $device->{wwn}) {
      # send command to master to update it's config-file
      PDM->fixConfig("switch", $device->{wwn}, $wwn);

      Debug->errNoRepeat( 'SWITCH_NEWIP', $device->{name}, 24,
           "wwn of switch $device->{ip} changed from $device->{wwn} to $wwn");
    }

    my $t1 = $device->{ipno} || $device->{ip};
    $id = {   
              deviceName  => $device->{wwn},
              active      => $device->{active},
              name        => $device->{name},
              class       => $device->{class},
              display     => "$device->{name} (ip=$t1)",
              category    => Report::CAT_SWITCH,
              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->{wwn};
    if ($device->{primary}) {
      $report->{'id.primary'} = 
          $device->{primary} . ":" . $device->{fc} . ":" . $device->{port};
    }

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

    } else {
        $pdm->saveReport(Report->new($id, $report , $log_lines));
    }
  }
  Debug->print2("  No devices found") if (!$dc);

  Timelapse->stop(ref($agent));
}

use vars qw ($ERR);

sub getVersion {
  my($class, $ip, $TO) = @_;
  my %V;
  my $renv = System->get_renv();
  my $swport = $renv->{sanbox_port} || 5001;

  my $DIR = System->get_home() . "/bin";
  my($err0,$version) = Util->run_command("$DIR/sanbox version -port $swport $ip 2>&1", "sanbox_version.txt", $TO);

  if ("@$version" =~ /failed exch/ || "@$version" =~ /bad hostname:/ ||
      $version->[0] =~ /Error:/) {
     $ERR = "@$version";
     return undef;
  } else {
     foreach my $l (@$version) {
       my($key, $val) = split(/:\s*/, $l);
       $V{$key} = $val;
     }
     return \%V;
  }
}



sub read_switch {
  my($agent, $device) = @_;
  my(@s, %dev, $in, %info);
  my($connect_err, %C);
  my($chassis, $port,  $loop, $config, $network, $toggle);
  my $renv = System->get_renv();
  my $swport = $renv->{sanbox_port} || 5001;
  
  my($ip)    = $device->{ip};
  my($s_ip) = $ip;
  if ($device->{primary}) {
     $s_ip = "-f $device->{fc} $device->{primary}";
  }
     
  my(@counts, @stats, $stat, $x);
  my($DIR) = System->get_home() . "/bin";
  my($TO) = $agent->{renv}{'timeout.snmp'};

  my($err0,$version) = Util->run_command("$DIR/sanbox version -port $swport $s_ip 2>&1", "sanbox_version.txt", $TO);
  if ($err0) {
    Debug->err(SANBOX => "Cannot run $DIR/sanbox $ip:$err0");
    return ($err0,"", undef) 
  }

  if ("@$version" =~ /failed exch/ || "@$version" =~ /bad hostname:/ ||
      $version->[0] =~ /Error:/) {
     $connect_err = "ERROR: @$version";
     return ($connect_err, "", undef);
  }
  ($err0,$chassis) = 
     Util->run_command("$DIR/sanbox chassis_status -port $swport $s_ip", "sanbox_chassis.txt", $TO);
  my($err2,$counts) = Util->run_command("$DIR/sanbox port_counts -port $swport $s_ip all", "sanbox_counts.txt", $TO, {cache => 0});
  my($err3,$state); #  = Util->run_command("$DIR/sanbox port_state -port $swport $s_ip all", "sanbox_state.txt", $TO);

  my($error, $wwn, $report) = $agent->parse2($version, $counts, $state, $chassis, $DIR, $s_ip, $TO);
  $report->{'id.name'} = $device->{name};

  return ($error, $wwn, $report);
}

sub getPortCount {
  my($class, $ip, $host, $TO) = @_;
  my $rc;
  $ERR = undef;
  if ($host) {
      $rc = Util::Http->getCommand($host, 
                "Agent::SWITCH::WWN&ip=$ip&HTTP=1&command=chassis_status", $TO);
      if (substr($rc,0,3) eq "ERR") {
         $ERR = $rc;
         return undef;
      } else {
         return $rc;
      }
  } else {
      return get_WWN({ip => $ip, command => "chassis_status"});
  }
}

#
# get WWN of a switch using ip or proxy.
#
sub getWWN {
  my($class, $ip, $host, $TO) = @_;
  my $rc;
  $ERR = undef;
  if ($host) {
      $rc = Util::Http->getCommand($host, "Agent::SWITCH::WWN&ip=$ip&HTTP=1", $TO);
      if ($rc =~ /ERR/) {
         $ERR = $rc;
         return undef;
      } else {
         return substr($rc,4);
      }
  } else {
      return get_WWN({ip => $ip});
  }
}

sub get_WWN {
  my($q) = @_;
  my $ip = $q->{ip};
  my $wwn;
  my $renv = System->get_renv();
  my $swport = $renv->{sanbox_port} || 5001;

  my $command = $q->{command} || "version";
  my $DIR = System->get_home() . "/bin";

  my($err1,$info) = Util->run_command("$DIR/sanbox $command -port $swport $ip ", 
                                      "sanbox_status.txt", 20);
  if ($command eq "chassis_status") {
     if ("@$info" =~ /Ports:\s+(\d+)/) {
        $wwn = $1;
     }
  } elsif ("@$info" =~ /WWN:\s+(\w+)/) {
        $wwn = $1;
  }
  if ($q->{HTTP}) {
    if ($wwn) {
      print "\nOK $wwn";
    } else {
      print "\nERR $err1";
    }
  } else {
    return $wwn;
  }
}

#Parity errors detected:              0
#Out of regular frame buffers errors: 0
#Out of small frame buffers errors:   0


sub getASIC {
  my($class, $DIR, $s_ip, $TO, $V) = @_;
  my($err, $x, $count);
  my $renv = System->get_renv();
  my $swport = $renv->{sanbox_port} || 5001;

  my($err1,$info) = Util->run_command("$DIR/sanbox chassis_counters -port $swport $s_ip all", "sanbox_status.txt", $TO);
  my $type;
  foreach my $l (@$info) {
     if ($l =~ /S4s on board:/) {
        $V->{"ASIC.count"} = substr($l,14) + 0;

     } elsif ($l =~ /Parity errors detected:\s+(\d+)/) {
        $V->{"ASIC.parityErrors"} = 1;

     } elsif ($l =~ /Out of regular frame buffers errors:\s+(\d+)/) {
        $V->{"ASIC.OutOfRegularFrame"} = 1;

     } elsif ($l =~ /Out of small frame buffers errors:\s+(\d+)/) {
        $V->{"ASIC.OutOfSmallFrame"} = 1;

     } elsif ($l =~ /^Interrupt Handler errors/) {
        my $l1 = substr($l,26);
        my @L = split(/\s+/, Util->ltrim($l1));
        
        for ($x=0; $x <= $#L; $x++) {
           $V->{"ASIC." . ($x+1) . ".InterruptError"} = $L[$x];
        }
     } elsif ($l =~ /^COF Parity Errors/) {
        my $l1 = substr($l,26);
        my @L = split(/\s+/, Util->ltrim($l1));
        
        for ($x=0; $x <= $#L; $x++) {
           $V->{"ASIC." . ($x+1) . ".COF_Parity"} = $L[$x];
        }
     } elsif ($l =~ /^COF CRC Error/) {
        my $l1 = substr($l,26);
        my @L = split(/\s+/, Util->ltrim($l1));
        
        for ($x=0; $x <= $#L; $x++) {
           $V->{"ASIC." . ($x+1) . ".COF_CRC"} = $L[$x];
        }
     } elsif ($l =~ /^Frame bus control/) {
        $type = "FrameBusControl";

     } elsif ($l =~ /^Internal Parity Er/) {
        $type = "InternalParity";

     } elsif ($l =~ /^ASIC\s+(\d+)\s+Port (\d+): (\d+)/) {
        my $asic = $1; my $port = $2; my $cnt = $3;
        $V->{"ASIC." . ($asic+1) . ".port.$port.$type"} = $cnt
     }
  }
}
      


#
# if one of the zone-types fails, the whole zone report is skipped;
#
sub getZones {
  my($class, $DIR, $s_ip, $TO, $V) = @_;
  my($err);
  my $totzones;
  my $V1 = {};
  my $renv = System->get_renv();
  my $port = $renv->{sanbox_port} || 5001;

  foreach my $type ('hd','ns','sl') {
     my($err1, $info) = Util->run_command("$DIR/sanbox get_zone -port $port $s_ip $type all", "sanbox_status.txt", $TO);
     if ("@$info" =~ /Error:/) {
         $V->{"error.get_zone"} = "@$info, $s_ip, get_zone, $type";
         return "@$info, $s_ip, get_zone, $type";
     }
     my $z = -1;
     my $enabled;
     foreach my $l (@$info) {
        if ($l =~ /Zone:\s+(\d+), Enabled: yes/) {
           $z = $1;
           $totzones++ if ($z < 100);
            
        } elsif ($l =~ /Port: (\d+)/) {
           my $p = $1;
           if ($z < 100) {
             my $vz = " " . $V1->{"zone.$type.$z.members"};
             my $po = $1;
             if (index($vz, " $po ") < 0) {
               $V1->{"zone.$type.$z.members"} .= "$po ";
             }
           }
        }
     }
  }
  $V->{"zone.total"} = $totzones;
  foreach my $el (keys %$V1) {
    $V->{$el} = $V1->{$el};
  }
  return undef;

}

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

  my($ip)    = $device->{ip};
  my($s_ip) = $ip;
  if ($device->{primary}) {
     $s_ip = "-f $device->{fc} $device->{primary}";
  }
  my $V = {};
  my $D = System->get_home() . "/bin";
  $class->getStatus($D, $s_ip, 10, $V);
  $class->getLinks($s_ip, 10, $V);
  return $V;

}

#  Agent::SWICH->getLinks("1.1.1.1", 10, $R);

sub getLinks {
  my($class, $s_ip, $TO, $V) = @_;
  my($ch_text, $my_chassis_id);
  my $renv = System->get_renv();
  my $swport = $renv->{sanbox_port} || 5001;

  my $DIR = System->get_home() . "/bin";
  # get chassis id of this switch
  my($err2,$status1) = Util->run_command("$DIR/sanbox chassis_id -port $swport $s_ip",
                           "sanbox_status.txt", $TO);
  my($x, $l);
  my $chassis = "@$status1";
  $chassis =~ /ChassisID: (\d+)/;
  $my_chassis_id = $1;

  $V->{"id.chassis_id"}  = $my_chassis_id;

  my($err1,$status) = Util->run_command("$DIR/sanbox links -port $swport $s_ip all", 
                      "sanbox_status.txt", $TO);
  my $in = 0;
  my $my_id = 0;
  my $ch_id = -1;
  my ($a, $rest);
  for ($x=0; $x <= $#$status; $x++) {
    $l = $status->[$x];
    chomp($l);
    if ($l =~ /Chassis:/) {
       ($a, $ch_id, $rest) = split(/\s+/, Util->ltrim($l), 3);

    } elsif ($ch_id == $my_chassis_id){
       if ($l =~ /\s+Port:/) {
           my($a, $port, $chassis, $port2, $fc, $wwn) = split(/\s+/, Util->ltrim($l));
           $port = hex("0x" . $port);
           my $link_p = hex("0x" . $port2);
           $V->{"port.$port.link_port"} = $link_p; # hex to decimal
           $V->{"port.$port.link_wwn"}  = sprintf("20%2.2x%s",$link_p-1 , substr($wwn,4)) ;
           $V->{"port.$port.link_fc"}   = $fc;
       }
    }
  }
}



sub getStatus {
  my($class, $DIR, $s_ip, $TO, $V) = @_;

  my $renv = System->get_renv();
  my $swport = $renv->{sanbox_port} || 5001;
  my($err1,$status) = Util->run_command("$DIR/sanbox port_status -port $swport -a $s_ip all", 
              "sanbox_status.txt", $TO);

  my $in = ""; my($p) = "8";
  my($x, $l);
  my($totzones) = 0;
  for ($x=0; $x <= $#$status; $x++) {
    $l = $status->[$x];
    chomp($l);
    my @b = split(/\s+/, $l);
    if ($l =~ /Port:/) {
       $p      = $b[1]; # sprintf("%3.3d", $b[1]);
       $V->{"port.$p.type"}   = $b[2];
       if ($l =~ /Offline/ || $l =~ /Not-logged-in/) {
         $V->{"port.$p.mode"}   =  $b[3] . $b[4];
       } else {
         $V->{"port.$p.mode"}   = "Online";
       }
       if ($status->[$x] =~ /Linked-to: (\w+) .* FC: (\w+)/ ) {
          $V->{"port.$p.link_wwn"} = $1;
          $V->{"port.$p.link_fc"} = $2;
 
       } elsif ($status->[$x+1] =~ /^\s+0x/) {
          my($alpa, $wwn, $wwn2) = split(/\s+/, Util->ltrim($status->[$x+1]));
          $V->{"port.$p.link_wwn"} = $wwn if ($wwn !~ /\</);
       }
    }
  }
  $V->{"version.ports"} = $p;
}



sub parse2 {
  my($agent, $version, $counts, $state, $chassis, 
      $DIR, $s_ip, $TO) = @_;
  my($in, %V, $enabled, $mfs, $fan, $attr, $l, @b);

  foreach $l (@$version) {
    chomp($l);
    @b = split(/\s*:\s*/, $l, 2);

    $V{"version.$b[0]"} = $b[1];
    if ($b[0] eq "WWN" || $b[0] eq "MAC") {
        $V{"id." . lc($b[0]) } = lc($b[1]);
    }
  }

# CHASSIS

  foreach $l (@$chassis) {
    chomp($l);
    if ($l =~ /Power:\s+(.+)/) {
        $V{"chassis.power.status"} = $1;

    } elsif ($l =~ /Temp:\s+(.+)/) {
        $V{"chassis.temp.status"} = $1;

    } elsif ($l =~ /Temp =\s+(.+)/) {
        $V{"chassis.temp.value"} = $1;

    } elsif ($l =~ /Uptime:\s+(.+)/) {
        $V{"chassis.uptime"} = $1;

    } elsif ($l =~ /Fan (\d+):\s+(.+)/) {
        $V{"chassis.fan.$1.status"} = $2;

    }elsif ($l =~ /Error: No response/){
      return ("Chassis status failed for device.", $V{"id.wwn"}, \%V );

    }
     
  }

  $agent->getStatus($DIR, $s_ip, $TO, \%V);
  $agent->getLinks($s_ip, 10, \%V);
  $agent->getZones($DIR, $s_ip, $TO, \%V);
  $agent->getASIC($DIR, $s_ip, $TO, \%V);

#
# COUNTS
#
  my($STATE_LIST) = "LinkFails,Total_LIP_Rcvd,InvalidTxWds,SyncLosses,CRC_Errs," .
               "Prim_Seq_Errs,AL_Init_Errs,AddressIdErrs,short_frame_err_cnt,"  .
              "long_frame_err_cnt,loss_of_signal_cnt,sync_loss,Discards," .
               "AL_Inits,LIF_flow_cntrl_err_cnt,lof_timeout_els," .
               "lof_timeout,";

  $in = "";
  foreach $l (@$counts) {
     chomp($l);
     @b = split(/\s*:\s*/, $l);
     next if ($b[0] =~ /-----------/);
     if (substr($l,0,5) eq "Port:") {
        $in = $b[1]; # sprintf("%3.3d", $b[1]);  
     } elsif ($in) {
        my($k) = $b[0];
        $k =~ s/ /_/g;
        $k =~ s/,/_/g;
        if (index($STATE_LIST, $k) >= 0) {
             $V{"port.$in.error.$b[0]"}   = $b[1];
        } else {
             $V{"port.$in.stats.$b[0]"}   = $b[1];
        }
     }

  }
  $V{'port.count'} = $in;

#
# PORT STATE
#
  $in = ""; my($port, $admin, $op );
  foreach $l (@$state) {
    chomp($l);
    $port = "";
    $l =~ /Port: *(\d+) +Admin: *(\w+), *Operational: *(\w+)/;
    $port = $1;
    $admin = $2;
    $op = $3;
    if ($port) {
       $port = $port ; # sprintf("%3.3d", $port);
       $V{"port.$port.admin"}         = $admin;
       $V{"port.$port.port"}          = $port;
       $V{"port.$port.operational"}   = $op;
    }
  }
  Debug->dump('switchConfig', \%V);

  $agent->addIdentification(\%V);

  return ("", $V{"id.wwn"}, \%V );
}

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

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

  $out .= $class->reportHead("SWITCH", $r);

  if(exists($v->{"id.connect_errs"})){
     print "<b><font color=red>NOTE: Errors were encountered when this report was generated. The data being displayed could be from an old report.</font></b>";
  }

  my($version) = $v->subset("version.");
  my($cnt) =0;
  foreach my $x (sort keys %$version) {
    $out .= "<tr>" if ($cnt++ % 2 == 0);
    $out .= "<td align=right bgcolor=#DDDDFF><b>$x:<td>$version->{$x}</td>";
  }
  $out .= "<tr><td align=right bgcolor=#DDDDFF><b>Temp:<td>$v->{'chassis.temp.status'} / $v->{'chassis.temp.value'}</td>".
          "<td align=right bgcolor=#DDDDFF><b>IP:<td>$v->{'id.ipno'}</td>";
  $out .= "<tr><td align=right bgcolor=#DDDDFF><b>Fan:<td>$v->{'chassis.fan.1.status'} / $v->{'chassis.fan.2.status'}</td>".
          "<td align=right bgcolor=#DDDDFF><b>Power:<td>$v->{'chassis.power.status'}</td>";
     
      
  $out .= "
  </table>
  <table border=0><tr><td></table>
  <table border=1 cellspacing=0 cellpadding=1 width=95% bgcolor=white>
  <tr bgcolor=#DDDDFF>
    <th><font >Component</th>
    <th><font >Type</th>
    <th><font >Info</th>
  ";

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

  my($b, $status, $mode, $type, $p0, $p);
  $cnt = 0;
  for ($p0=1; $p0 <= 16; $p0++) {
     $p = $p0; # sprintf("%3.3d", $p0);
     last if (!$v->{"port.$p.type"});

     $status = $v->{"port.$p.mode"};
     my $bg = ($status eq "Online")? "":"bgcolor=#FFFFD0";
     $mode = $v->{"port.$p.operational"};
     $mode = "(op:$mode)" if ($mode);
     $type = $v->{"port.$p.type"};
     $out .= "<tr>
  <td>&nbsp;port." . ($p+0) .
  "<td>&nbsp;$type</td>
  <td $bg>$status $mode</td>
  \n";
     $cnt++;
  }
  my($zones) = $v->{'zone.total'};
  my($val);

  # zone.hd.0.members
  my $Z = $v->subset('zone');
  foreach my $x (keys %$Z) {
     next if ($x eq "total");
     my $x0 = $x;
     $x0 =~ s/\.members//;
     $val = $Z->{$x};
     $val =~ s/ /, /g;
     $out .= "<tr>
 <td>&nbsp;$x0</td>
 <td>&nbsp;Zone</td>
 <td>&nbsp;members: $val</td>
 \n";
     $cnt++;
  }

  if (!$tableCnt) {
    $out .= "</table>";
  }
  return $out;

}


# get DB for all switches, works with proxy and cascaded
#
sub FCCounters {
  my($class,$arg) = @_;

  return $class->switchFCCounters("switch", $arg);
}

#  $dev = $node->getDevice();

sub FCfromDevice {
  my($class, $dev) = @_;
  my($db, $VAR1);
  $ERR = undef;
  my $renv = System->get_renv();
  my $rc;
  if ($dev->{host} && ($dev->{host} ne $renv->{hostname} )) {
    $rc = Util::Http->getCommand($dev->{hostIpno}, 
                "Agent::SWITCH::FC1&name=$dev->{name}&fc=$dev->{fc}&primary=$dev->{primary}".
                "&ipno=$dev->{ipno}&HTTP=1", 30);
    $rc = "ERR $Util::Http::ERROR" if (!defined($rc));

    if (substr($rc,0,3) eq "ERR" ) {
      $ERR = $rc;
      return undef;
    } else {
      eval substr($rc,3);
      $ERR = $rc if (!$VAR1);
      return $VAR1;
    }
  } else {
    return &get_FC1($dev);
  }
}


sub get_FC1 {
  my($q) = @_;
  my($l, @b, @ST , @CNT);
  my $renv = System->get_renv();
  my $swport = $renv->{sanbox_port} || 5001;
   
  my($primary) = "-f $q->{fc} $q->{primary}" if ($q->{primary});
  my $baseZero = $q->{baseZero}; # is 1 on switch2 and others that start a port 0

  my($s_ip) = $primary || $q->{ipno}; # thru primary switch if available

  my $name = $q->{name};
  my($sb) = System->get_home() . "/bin/sanbox";

  my($err0,$version) = Util->run_command("$sb version -port $swport $s_ip", "test", 20);
  my($v) = "@$version";
  $v =~ /WWN:\s+([0-9a-f]+)/;
  my($wwn) = $1;
  if (!$wwn) {
    if ( $q->{HTTP}) {
      print "ERR No wwn for $s_ip";
    } else { 
      return undef;
    }
  }

  my($err,$status) = Util->run_command("$sb port_status -port $swport $s_ip all","test",20, {cache => 0});
  my($err1,$counts) = Util->run_command("$sb port_counts -port $swport $s_ip all","test",20, {cache => 0} );

  my($in) = ""; my($p) = "8";

  foreach $l (@$status) {
    chomp($l);
    @b = split(/\s+/, $l);
    if ($l =~ /Port:/) {
       $p      = $b[1];
       if ($l =~ /Offline/ || $l =~ /Not-logged-in/) {
         $ST[$p]   = "Offline";
       } else {
         $ST[$p]   = "Online";
       }
    }
  }

  my($STATE_LIST) = "LinkFails,Total_LIP_Rcvd,InvalidTxWds,SyncLosses,CRC_Errs,".
                "Prim_Seq_Errs,AL_Init_Errs,AddressIdErrs,short_frame_err_cnt," .
                "Inframes,Outframes,long_frame_err_cnt,loss_of_signal_cnt,sync_loss";
  $in = "";
  foreach $l (@$counts) {
     chomp($l);
     @b = split(/\s*:\s*/, $l);
     next if ($b[0] =~ /-----------/);
     if (substr($l,0,5) eq "Port:") {
        $in = $b[1]; # sprintf("%3.3d", $b[1]);
     } elsif ($in) {
        my($k) = $b[0];
        $k =~ s/ /_/g;
        $k =~ s/,/_/g;
        if ($ST[$in] ne "Offline" && index($STATE_LIST, $k) >= 0) {
             my $portno = $baseZero ? $in-1 : $in;
             $CNT[$portno]{$k}   = $b[1]+0;
        }
     }
  }
  my(%X, $port);
  my $start = $baseZero ? 0 : 1;
  for ($port=$start ; $port <= $#CNT; $port++) {
     my $c = $CNT[$port];
     next if (!$c);
     my($key) = "|$wwn|port.$port|switch";
     $X{$key} = "$c->{LinkFails}\t$c->{loss_of_signal_cnt}\t$c->{Prim_Seq_Errs}\t".
             "$c->{CRC_Errs}\t$c->{sync_loss}\t$c->{InvalidTxWds}\t$c->{Inframes}\t$c->{Outframes}";
  }
  my($out) = { enc => {$wwn => $name} , data => \%X };
  if ($q->{HTTP}) {
     print "OK " . Dumper($out);
  } else {
     return $out;
  }
}

#Port:           2
#Inframes:       10470092 
#Outframes:      17900116 
#Discards:       14 
#Fbsyframes:     0 
#C2Rjtframes:    0 
#LinkFails:      9 
#SyncLosses:     9 
#Prim Seq Errs:  0 
#InvalidTxWds:   217101 
#CRC Errs:       33 
#DelimiterErrs:  27 
#AddressIdErrs:  0 
#Link Reset In:  0 
#Link Reset Out: 0 
#OLS In:         0 
#OLS Out:        0 
#Total LIP Rcvd: 155 
#LIP F7 F7:      153 
#LIP F8 F7:      0 


1;
