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

#  $Name:  $ 
#  $Id: SE_MODULE.pm,v 1.35 2006/07/17 16:55:16 mckenney Exp $

use Catalog;
use strict;
use Report;
use Agent;
use State;
use base 'Agent';
use Agent::SWITCH;
use NWS::T3;
use SE;

sub isSelectable { 0 }  # used to control rack as device
sub type         { Report::CAT_SE }

sub revision     {'$Revision: 1.35 $'}
sub arrays       {",t3,6020,6120"}

use vars qw(%N2IP $ERR);

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

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

sub RUN {
  my($agent, $static_list, $pass) = @_;
  my($err_lines, $warn_lines,  $out,$device, $connect_errs);
  my($report ,  $id, $lines, $log_err, $type);
  my($onedayold, $wwn, $portWWN, $port2WWN);
  $DB::single = 1;
  my ($renv, $devs, $hosts, $notifs, $Config) = PDM::ConfigFile->read();
  my $se = $agent->type();

#  return if (!$renv->{include_se_device});
  my($sdt);
  my($dc) = 0;

#   INDY ONLY
#   RUN IF AGENT IS ON THE RACK
#
  if ($renv->{solution} eq $se) {
     my $key = System->serverName();
     Timelapse->start("$se:$key");
     my $report = $agent->INSTRUMENTATION($renv->{solution_model}, $devs, $key);
     Timelapse->stop("$se:$key", $key, Util->name2ip());

     my $name = $renv->{solution_model} . "-" . System->shortHostname($renv->{hostname});

     $id =  { 
                deviceName  => $key,
                active      => "Y",
                name        => $name,
                class       => "storage.$se",
                display     => $renv->{solution_model} . " " . $renv->{hostname},
                category    => $se,
                ip          => $renv->{ipno} || $renv->{hostname},
              };
     $report->{"id.name"}        = $renv->{hostname};
     $report->{"id.hostid"}      = System->hostid();
     $report->{"id.ip"}          = $renv->{ip};
     $report->{"id.ipno"}        = Util->name2ip();
     $report->{"id.wwn"}         = $key;
     $report->{'id.mgmtLevel'}   = 'DS';
  
     my $new_rep = Report->new($id, $report , "");
     require Health::SE_MODULE;
     Health::SE_MODULE->all_logic($new_rep);
     PDM->saveReport($new_rep);
     my $hostname = System->hostname();
     TO->clearTopo($hostname);
     my $to = TO->readTopo($hostname,1);
     TO->copyTopo($hostname,"MERGE-MASTER");

     my $errors = $to->errorsHash();
     my $e_txt ;
     foreach my $e (keys %$errors) {
        print "$e = $errors->{$e} \n";
     }
     print "Rack Topology created!\n";

     SE->vmcfg();
    Debug->print2("Cleaning Stale Reservations \n");
    my $key = "system";
    my $lock = LockManager->new();
    my $current = $lock->cleanLocks();

  }

  return [];

}

sub enclosure {
  my($class, $rep) = @_;
}



#  http or sub call, expect the topo to exist already

sub getLinks {
  my($class, $dev, $to) = @_;
  my $VAR1;
  if ($dev->{mgmtLevel} eq "D") {  # remote
    my ($err, $data) = Util::Http->readFile($dev->{ip}, "se_links");
    if ($err || substr($data,0,20) !~ /VAR1 /) {
       Debug->err(HTTP_ERROR => "$err $data");
       return {};
    }
    eval $data;
    return $VAR1;
  } else {
    return &get_links({ to => $to });
  }
}


# may need to add one argument to specify which rack if there are slaves.
# will change readTopo(<slave>)
#
sub get_links {
  my($q) = @_;
  my (%R, $x);
  my $HTTP = $q->{HTTP};
  my $renv   = System->get_renv();
  my $Config = PDM::ConfigFile->read();
  my $devs   = $Config->devices();

  my $model = $renv->{solution_model};
require TO;
  my $to    = $q->{to} || TO->readExistingTopo();
  my $Comp  = $q->{Comp};
  my $switches = $to->switchList();
  my $storages = $to->storageList();
  my $portCnt = 0;
  my $slotTotal;

  my $wwn_list;
  my $dsp;
  foreach my $d (@$devs) {
    $slotTotal++;
    $dsp = $d if ($d->{type} eq 'dsp');
    if ($d->{class} !~ /storage.se/) {
      $wwn_list .= "$d->{wwn}|";
      $wwn_list .= "$d->{wwn2}|" if ($d->{wwn2});
    }
  }
  $R{"info.slotTotal"} = $slotTotal;
  $R{"info.wwnList"}   = $wwn_list;

  if ($model eq "3910" || $model eq "3960") {
     foreach my $sw (@$switches) {
        my $name = $sw->name();
        my $rep1 = Report->readNew($name) if (!$HTTP);
        my $pi = $sw->portInfo();
        my $po = $sw->port();
        for ($x=0; $x <= $#$pi; $x++) {
            my $po0 = $po->[$x];
            my $pi0 = $pi->[$x];
            $pi0->{PortWWN} = $rep1->value("port.$x.link_wwn") if ($rep1 && $rep1->value("port.$x.link_wwn")); # fix wwn

            if (ref($pi0) eq "HASH" && defined($pi0->{PortWWN}) && (!$po0 || substr($po0,0,2) ne "t3") ) {
               $R{"fcPort.$portCnt.PortWWN"}      = $pi0->{RemotePortWWN} || $pi0->{PortWWN};
               $R{"fcPort.$portCnt.nodeId"}         = "$name:$x";
               $R{"fcPort.$portCnt.LocalPortWWN"} = $pi0->{LocalPortWWN};
               $R{"fcPort.$portCnt.portType"}     = $sw->type() . "." . $pi0->{sw_PortType};
               $R{"fcPort.$portCnt.encName"}       = $sw->info("BoxName");
               if ($rep1) {
                 $R{"fcPort.$portCnt.PortWWN"}=$rep1->value("port.$x.link_wwn");
                 $R{"fcPort.$portCnt.CRC"}   = $rep1->value("port.$x.error.CRC Errs");
                 $R{"fcPort.$portCnt.ITW"}   = $rep1->value("port.$x.error.InvalidTxWds");
                 $R{"fcPort.$portCnt.SIG"}   = $rep1->value("port.$x.error.loss_of_signal_cnt");
                 $R{"fcPort.$portCnt.SYNC"}  = $rep1->value("port.$x.error.sync_loss");
                 $R{"fcPort.$portCnt.LINK"}  = $rep1->value("port.$x.error.LinkFails");
                 $R{"fcPort.$portCnt.INF"}   = $rep1->value("port.$x.stats.Inframes");
                 $R{"fcPort.$portCnt.OUTF"}  = $rep1->value("port.$x.stats.Outframes");
               }
               &updStatus("fcPort.$portCnt", "$name:port.$x", \%R, $Comp);
               $portCnt++;
            }
        }
     }
  } elsif (index(",3900SL,6320," , ",$model,") >= 0) {
     foreach my $st (@$storages) {
        my $name = $st->name();
        next if (index( Agent::SE_MODULE->arrays, $st->type()) < 0);
        my $rep1 = Report->readNew($name) if (!$HTTP);
        my $pi = $st->portInfo();
        for ($x=0; $x <= $#$pi; $x++) {
          my $pi0 = $pi->[$x];
          if (ref($pi0) eq "HASH" && exists $pi0->{PortWWN}) {
             $R{"fcPort.$portCnt.PortWWN"}      = $pi0->{PortWWN};
             $R{"fcPort.$portCnt.LocalPortWWN"} = $pi0->{PortWWN};
             $R{"fcPort.$portCnt.nodeId"}         = "$name:$x";
             $R{"fcPort.$portCnt.encName"}      = $st->info("BoxName");
             $R{"fcPort.$portCnt.portType"}     = $st->type();
             if ($rep1) {
               $R{"fcPort.$portCnt.status"} = $rep1->value("controller.u" . ($x+1) . "ctr");
               if ($model eq "6320") {
                 my $e = "fc_stats.unit$x-ctrl" . ($x+1) . "-loop2";
                 $R{"fcPort.$portCnt.CRC"}   = $rep1->value("$e.InvCRCCnt") + 0;
                 $R{"fcPort.$portCnt.ITW"}   = $rep1->value("$e.InvTxWord") + 0;
                 $R{"fcPort.$portCnt.SIG"}   = $rep1->value("$e.LossSignalCnt") + 0;
                 $R{"fcPort.$portCnt.SYNC"}  = $rep1->value("$e.LossSyncCnt") + 0;

               } else {
                 $R{"fcPort.$portCnt.CRC"}   = $rep1->value("port." . ($x+1) . ".CRC");
                 $R{"fcPort.$portCnt.ITW"}   = $rep1->value("port." . ($x+1) . ".ITW");
                 $R{"fcPort.$portCnt.SIG"}   = $rep1->value("port." . ($x+1) . ".SIG");
                 $R{"fcPort.$portCnt.SYNC"}  = $rep1->value("port." . ($x+1) . ".SYNC");
                 $R{"fcPort.$portCnt.LINK"}  = $rep1->value("port." . ($x+1) . ".LINK");
               }
               $R{"fcPort.$portCnt.INF"}   = 0;
               $R{"fcPort.$portCnt.OUTF"}  = 0;
             }
             &updStatus("fcPort.$portCnt", 
                          "$name:controller.u" . ($x+1) . "ctr", , \%R, $Comp);
             $portCnt++;
          }
        }
     }
  } elsif ($model eq "6910" || $model eq "6960") {
     foreach my $sw (@$switches) {
        next if ($sw->type() eq "ve");
        my $ip3 = substr($sw->info('sw_ipAddr'), -2);
        next if ($ip3 ne "30" && $ip3 ne "31");
        my $name = $sw->name();
        my $rep1 = Report->readNew($name) if (!$HTTP);
        my $pi = $sw->portInfo();
        my $po = $sw->port();
        for ($x=0; $x <= $#$pi; $x++) {
            my $po0 = $po->[$x];
            my $pi0 = $pi->[$x];
            $pi0->{PortWWN} = $rep1->value("port.$x.link_wwn") if ($rep1 && $rep1->value("port.$x.link_wwn")); # fix wwn

            if (ref($pi0) eq "HASH" && defined($pi0->{PortWWN}) && (!$po0 || substr($po0,0,2) ne "ve") ) {
               $R{"fcPort.$portCnt.PortWWN"}      = $pi0->{RemotePortWWN} || $pi0->{PortWWN};
               $R{"fcPort.$portCnt.LocalPortWWN"} = $pi0->{LocalPortWWN};
               $R{"fcPort.$portCnt.nodeId"}         = "$name:$x";
               $R{"fcPort.$portCnt.portType"}     = $sw->type() . "." . $pi0->{sw_PortType};
               $R{"fcPort.$portCnt.encName"}      = $sw->info("BoxName");
               if ($rep1) {
                 $R{"fcPort.$portCnt.PortWWN"}=$rep1->value("port.$x.link_wwn");
                 $R{"fcPort.$portCnt.status"}= $rep1->value("port.$x.mode");
                 $R{"fcPort.$portCnt.CRC"}   = $rep1->value("port.$x.error.CRC Errs");
                 $R{"fcPort.$portCnt.ITW"}   = $rep1->value("port.$x.error.InvalidTxWds");
                 $R{"fcPort.$portCnt.SIG"}   = $rep1->value("port.$x.error.loss_of_signal_cnt");
                 $R{"fcPort.$portCnt.SYNC"}  = $rep1->value("port.$x.error.sync_loss");
                 $R{"fcPort.$portCnt.LINK"}  = $rep1->value("port.$x.error.LinkFails");
                 $R{"fcPort.$portCnt.INF"}   = $rep1->value("port.$x.stats.Inframes");
                 $R{"fcPort.$portCnt.OUTF"}  = $rep1->value("port.$x.stats.Outframes");
               }
               &updStatus("fcPort.$portCnt", "$name:port.$x", \%R, $Comp);
               $portCnt++;
            }
        }
     }

  # MASERATI ENTERPRISE / System 1 / Unity
  } elsif (index(",6920,6940,", ",$model,") >= 0 ) {
     require Agent::DSP;

     # try reading in an old report
     my $rc;
     my($oreport) = PDM->getOldReport("$dsp->{type}:$dsp->{key}");
     if($oreport){
        $rc = $oreport->content();
     }else{
       $rc = Agent::DSP::get_WWN({name => $dsp->{ipno}} );
     }
     my $dsppcnt = 0;
     foreach my $e (keys %$rc) {
        if ($e =~ /^fcPort\./ || $e =~ /^etherPort\./) {
           $R{$e}   = $rc->{$e};
	   if($e =~ /ModuleNum/){
	     $dsppcnt++;
	   }
        }
     }
     $portCnt = $R{"info.portTotal"} = $dsppcnt;


  # INDY SL  WITH VICOMS
  } elsif (index(",6910SL,6960SL,", ",$model,") >= 0 ) {
     foreach my $sw (@$switches) {
        next if ($sw->type() ne "ve");
        my $name = $sw->name();
        my $rep1 = Report->readNew($name) if (!$HTTP);
        my $pi  = $sw->portInfo();
        my $pi0 = $pi->[1];
        if (ref($pi0) eq "HASH" && $pi0->{PortWWN}) {
           $R{"fcPort.$portCnt.nodeId"}         = $sw->{name} . ":1";
           $R{"fcPort.$portCnt.PortWWN"}      = $pi0->{PortWWN};
           $R{"fcPort.$portCnt.LocalPortWWN"} = $pi0->{LocalPortWWN};
           $R{"fcPort.$portCnt.encName"}      = $sw->info("BoxName");
           $R{"fcPort.$portCnt.portType"}     = $sw->type();

           $R{"fcPort.$portCnt.status-sev"}   = 0;
           $R{"fcPort.$portCnt.status-desc"}  = "OK";
           $R{"fcPort.$portCnt.status-avail"} = 1;
           if ($rep1) {
             $R{"fcPort.$portCnt.CRC"}   = $rep1->value("fc.1.crc") + 0;
             $R{"fcPort.$portCnt.ITW"}   = $rep1->value("fc.1.itw") + 0;
             $R{"fcPort.$portCnt.SIG"}   = $rep1->value("fc.1.signal") + 0;
             $R{"fcPort.$portCnt.SYNC"}  = $rep1->value("fc.1.sync") + 0;
             $R{"fcPort.$portCnt.LINK"}  = $rep1->value("fc.1.link") + 0;
             $R{"fcPort.$portCnt.INF"}   = 0;
             $R{"fcPort.$portCnt.OUTF"}  = 0;
           }
           $portCnt++;
        }
     }
  }

  $R{"info.portTotal"} = $portCnt;
  if ($HTTP) {
require Data::Dumper;
     print "OK " . Data::Dumper::Dumper(\%R);
  } else {
     return \%R;
  }
}

sub round {
  my($v) = @_;
  return ($v < 0) ? 0 : int($v+0.5);
}

# find the worst problem for this fru

sub updStatus2 {
  my($slot, $key, $R, $Comps ) = @_;
  return if (!$Comps);
  my $found = [-1];
  foreach my $el (keys %$Comps) {
      if ($el eq $key || substr($el,0,length($key)+1) eq "$key.") {
         my $c = $Comps->{$el};
         if ($c->[0] > $found->[0] || 
             ($c->[0] == $found->[0] && $c->[1] gt $found->[1])) {
             $found = $c;
         }
      }
  }
  if ($found->[0] >= 0) {
     $R->{"$slot.status-sev"}    = &round($found->[0]);
     $R->{"$slot.status-desc"}   = $found->[1];
     $R->{"$slot.status-avail"}  = $found->[3] + 0;
     $R->{"$slot.status-details"}= $found->[4];
  } else {
     $R->{"$slot.status-sev"}    = 0;
     $R->{"$slot.status-desc"}   = "OK";
     $R->{"$slot.status-avail"}  = 1;
  }
}

# find the worst problem for this enclosure

sub updStatus {
  my($slot, $key, $R, $State) = @_;
  return if (!$State);
  if (exists $State->{$key}) {
     $R->{"$slot.status-sev"}    = &round($State->{$key}[0]);
     $R->{"$slot.status-desc"}   = $State->{$key}[1];
     $R->{"$slot.status-avail"}  = $State->{$key}[3] + 0;
     $R->{"$slot.status-details"}= $State->{$key}[4];
  } else {
     $R->{"$slot.status-sev"}    = 0;
     $R->{"$slot.status-desc"}   = "OK";
     $R->{"$slot.status-avail"}  = 1;
  }
}

#'switch:100000c0dd00b0ce:port.1' => [
#      -2,
#      '08-27 12:06:10 \'port.1\' in SWITCH dvt2-sw1a (ip=192.168.0.30) is now Not-Available (state changed from \'Online\' to \'Offline\'):',
#      'dvt2-sw1a',
#      '0',
#      'EventType=switch.StateChangeEvent|Target=switch:100000c0dd00b0ce|TargetNa me=dvt2-sw1a (ip=192.168.0.30)|Caption=M.port.1|Actionable=TRUE|SourceIP=192.168 .0.30|Severity=2|PriorState=1|CurrentState=0|CurrentValue=Offline'
#    ],

# most recent event wins but highest severity is saved

sub compare2 {
  my($k, $comp, $sev, $DB) = @_;

  if (!exists($DB->{$k}) ) {
     $DB->{$k} = [@$comp];
     $DB->{$k}[0] = $sev;

  } else {
     my $curr_sev = $DB->{$k}[0];
     if ($comp->[1] gt $DB->{$k}[1]) {            # more recent event
       $DB->{$k}    = [@$comp];
     }
     $DB->{$k}[0] = $sev if ( $sev > $curr_sev);  # highest severity
  }

}



sub fruInfo {
  my($class, $rep, $slot) = @_;
  
  my $x;
  my $out = {};
  foreach my $k (keys %$rep) {
     next if ($k !~ /^fru\.(\d+)\./);
     my $fru = $1;
     if ($rep->{"fru.$fru.fruSlot"} == $slot) {
       $out->{$k} = $rep->{$k};
     }
  }
  return $out;
}
     


sub slotOrder {
  my($class, $devs, $renv) = @_;
  my (@MAP1, @MAP2, @MAP3, @MAP4);

  foreach my $d (@$devs) {
    next if ($d->{mgmtLevel} ne "C");
    my $last = substr($d->{ipno},-2);
    if ($last ==30 || $last == 31) {
        push(@MAP1, $d);
    } elsif (substr($last,0,1) eq "2") {
        push(@MAP2, $d);
    } elsif ($last == 32 || $last == 33) {
        push(@MAP3, $d);
    } else {
        push(@MAP4, $d);
    }
  }
  push(@MAP1, @MAP2, @MAP3, @MAP4);
  return (\@MAP1);
}

sub addCores {
  my($class, $R) = @_;

  my @L  = `/usr/bin/find /var/crash -type f`;
  foreach my $f (@L) {
    next if($f =~ /triage/);
    chop($f);
    $R->{"core.$f"} = Util->fileSize($f);
  }
}


   
sub INSTRUMENTATION {
  my($class, $model, $devs, $se_key) = @_;
  my (%R, @MAP1, $x);
  my $renv = System->get_renv();
  my $MAP1 = $class->slotOrder($devs, $renv);

  my $rev = System->get_se_version() || "N/A";

  $R{"info.category"}              = "RAID";
  $R{"info.model"}                 =  $model;
  $R{"info.isRedundantController"} = "TRUE";
  $R{"info.supportsLUNMasking"}    = "TRUE";
  $R{"info.HGType"}                = "RAID";
  $R{"info.vendor"}                = "SUN";
  $R{"info.serialNumber"}          = "N/A";
  $R{"info.firmwareLevel"}         = $rev;
  $R{"info.spRevision"}            = $rev;
  $R{"info.SLAVE_DATA"}            = "Y";
  
  $R{"info.power_sequencer.status"} = $Agent::SP::SEQUENCER;
  $R{"info.power_sequencer.error"}  = $Agent::SP::SEQ_ERR;

  $class->addCores(\%R);

  my $first_ve  = 1;
  my $lun       = 1;
  my $slice     = 1;
  my $total_cap = 0;
  my $State =  State->slotStatus($devs); # State->getComponentState(2);  # with links
  my $Comp  = State->components();
  my $x;
  
  $DB::single = 1;
  my $to       = TO->readExistingTopo();

  my $host_info = Agent->hostInfo();
  my $hostid = System->hostid();
  my $hostkey = "sp:$hostid";

# SERVICE PROCESSOR is slot-0/fru-0

  $R{'slot.0.dev-type'} = 'sp';   # slot0 is SP
  $R{'slot.0.dev-name'} = $host_info->{hostname};
  $R{'slot.0.dev-key'}  = $host_info->{hostname};

  &updStatus("slot.0", $hostkey, \%R, $State);

  $R{'fru.0.fruSlot'}   = 0; 
  $R{'fru.0.fruType'}   = 'sp';
  $R{'fru.0.fruId'}     = 'sp';
  foreach my $el (keys %$host_info) {
     $R{'fru.0.info-' . $el} = $host_info->{$el};
  }
 
# EXTERNAL PORTS

  my $LINKS = &get_links({ to => $to, Comp => $Comp });
  Util->serialize("se_links", $LINKS);

  foreach my $el (keys %$LINKS) {
     $R{$el} = $LINKS->{$el};
  }

  &updStatus("links", "LINK", \%R, $State);

# DEVICES / SLOTS
  my $fru  = 1;
  my $slot = 1;
  my $vol = 1;
  my @array_reps;
  my $dsp_rep;

  foreach my $dev (@$MAP1) {
    my $key = $dev->{type} . ":" . $dev->{key};
    my $rep1 = Report->readNew($key);
    next if (!$rep1);
    my $repC = $rep1->content();
    if (!$rep1) {
      $rep1 = Report->new({deviceName => $se_key}, {});
    }

    foreach my $x (keys %$dev) {
      $R{"slot.$slot.dev-$x"} = $dev->{$x} if (substr($x,0,1) ne "_");
    }
    
    &updStatus("slot.$slot", $key, \%R, $State);
#    SWITCH2
    if (substr($dev->{type},0,7) eq "switch2") {
      $R{"fru.$fru.version-HW"}    = $rep1->value("info.version.Hardware_ASIC_Revision");
      $R{"fru.$fru.version-FLASH"} = $rep1->value("info.version.FLASH_Firmware_Revision") ;
      $R{"fru.$fru.version-PROM"}  = $rep1->value("info.version.PROM_Firmwware_Revision");
      $R{"fru.$fru.fruSlot"}     = $slot;
      $R{"fru.$fru.fruType"}     = "switch2";
      $R{"fru.$fru.fruId"}       = "switch";
      $fru++;

#    SWITCH
    } elsif (substr($dev->{type},0,6) eq "switch") {
      $R{"fru.$fru.version-HW"}    = $rep1->value("version.HW") || $rep1->value("info.version.Hardware_ASIC_Revision");
      $R{"fru.$fru.version-FLASH"} = $rep1->value("version.FLASH") || $rep1->value("info.version.FLASH_Firmware_Revision") ;
      $R{"fru.$fru.version-PROM"}  = $rep1->value("version.PROM") || $rep1->value("info.version.PROM_Firmwware_Revision");
      $R{"fru.$fru.fruSlot"}     = $slot;
      $R{"fru.$fru.fruType"}     = "switch";
      $R{"fru.$fru.fruId"}       = "switch";
      $fru++;

#   Power supplies
    } elsif ($dev->{type} eq "pseq") {
      $R{"fru.$fru.powerfru"} = "psq";
      $R{"fru.$fru.name"}     = $rep1->value("id.name");
      $R{"fru.$fru.status"}   = $rep1->value("info.power_seq.status");
      $R{"fru.$fru.state"}    = $rep1->value("info.power_seq.state");
      $R{"fru.$fru.fruSlot"}     = $slot;
      $R{"fru.$fru.fruType"}     = "pseq";
      $R{"fru.$fru.fruId"}       = "pseq";
      $fru++;

#   NTC
    } elsif ($dev->{type} eq "ntc") {
      $R{"fru.$fru.ntcfru"}    = "ntc";
      $R{"fru.$fru.ping"}      = $rep1->value("info.ping");
      $R{"fru.$fru.Serial"}    = $rep1->value("info.SerialNo");
      $R{"fru.$fru.Model"}     = $rep1->value("info.Model");
      $R{"fru.$fru.name"}      = $rep1->value("info.name");
      $R{"fru.$fru.firmwareRevision"}  = $rep1->value("info.firmwareRevision");
      $R{"fru.$fru.fruSlot"}     = $slot;
      $R{"fru.$fru.fruType"}     = "ntc";
      $R{"fru.$fru.fruId"}       = "ntc";
      $R{"fru.$fru.key"}      = $dev->{key};
      $fru++;

# DSP
    } elsif ($dev->{type} eq "dsp") {
      my($c);
      $dsp_rep=$rep1;
      
      # DSP_POOLS
      for ($vol=1; $vol <= $rep1->value("totals.volume"); $vol++) {
        my $lid = $rep1->value("volume.$vol.DeviceID");
        $lid =~ s/\://g;
        $R{"volume.$vol.VolumeSize"} = $rep1->value("volume.$vol.VolumeSize");
        $R{"volume.$vol.DeviceID"} = $lid;
        $R{"volume.$vol.ElementName"} = $rep1->value("volume.$vol.ElementName");
        $R{"volume.$vol.slice.total"} = $rep1->value("volume.$vol.slice.total");
        my($s);
        my $slice_cnt = $rep1->value("volume.$vol.slice.total") || 100;
        for ($s=1; $s <= $slice_cnt; $s++) {
           last if (!$repC->{"volume.$vol.slice.$s.SliceName"});
           foreach my $e1 ('SliceName','SliceSize','SliceStatus') {
             $R{"volume.$vol.slice.$s.$e1"} = $rep1->value("volume.$vol.slice.$s.$e1");
           }
        }
      }
      #dsp power supply info
      for (my $x=1; $x <= $rep1->value("totals.psu"); $x++) {
        $R{"fru.$fru.fruSlot"}  = $slot;
        $R{"fru.$fru.Type"}     = "dsp";
        $R{"fru.$fru.fruType"}  = "psu";
        $R{"fru.$fru.ipNo"}     = $dev->{ipno};
        $R{"fru.$fru.fruId"}    = $rep1->value("psu.$x.Index").
                                  $rep1->value("psu.$x.Label");
        $R{"fru.$fru.State"}    = $rep1->value("psu.$x.PsuState");
        $R{"fru.$fru.Label"}    = $rep1->value("psu.$x.Label");
        $R{"fru.$fru.Index"}    = $rep1->value("psu.$x.Index");
        $R{"fru.$fru.key"}      = $dev->{key} . ".psu$x";
        $fru++;
      }

      #dsp fan tray
      $R{"fru.$fru.fruSlot"}  = $slot;
      $R{"fru.$fru.Type"}     = "dsp";
      $R{"fru.$fru.fruType"}  = "fantray";
      $R{"fru.$fru.fruId"}    = "fantray";
      $R{"fru.$fru.State"}    = $rep1->value("fantray.FanState");
      $R{"fru.$fru.key"}      = $dev->{key} . ".fantray";
      $fru++;

      require NWS::DSP;

      foreach my $mod ('MIC','SIO','SRC','SFC') {
        foreach my $side ('Rear','Front') {
          for ($c=1; $c <= 10; $c++) {
            my $x = "$mod.$side$c";
            next if (!$rep1->value("$x.Class"));
            foreach my $el ('HWRev','PCBRev','Class','CardNum','Panel',
                            'Type','Ready','PartNumber','State','SerialNumber') {
               $R{"fru.$fru.$el"}    = $rep1->value("$x.$el");
            }
            $R{"fru.$fru.fruSlot"}  = $slot;
            $R{"fru.$fru.Type"}     = "dsp";
            $R{"fru.$fru.fruType"}  = $rep1->value("$x.Type");
            $R{"fru.$fru.fruId"}    = $x;
            $R{"fru.$fru.ipNo"}     = $dev->{ipno};
            $R{"fru.$fru.key"}      = NWS::DSP->moduleKey($repC, $x);
            &updStatus2("fru.$fru", "$key:$x", \%R, $Comp);
            $fru++;
          }
        }
      }
      for (my $x=1; $x <= $rep1->value("totals.disk"); $x++) {
         my $size = $rep1->value("disk.$x.InitSize");
         $total_cap += $size if ($size =~ /GB/);
      }
      $total_cap = ($total_cap/2) . " GB";


# ARRAY
    } elsif ($dev->{type} eq "6020" || $dev->{type} eq "t3") {

      my ($c, $d, $l);
      my $units = $rep1->value("unit.count") || 2;
      my $disks = $rep1->value("disk.count") || 9; 
      push(@array_reps, $rep1);

      for ($c=1; $c <= $units; $c++) {
         my $u = "u$c" . "ctr";
         if ($rep1->value("controller.$u.fruModel")) {
           $R{"slot.$slot.fruId"}       = $u;
           $R{"slot.$slot.fruModel"}    = $rep1->value("controller.$u.fruModel");
           $R{"slot.$slot.fruRevision"} = $rep1->value("controller.$u.fruRevision");
           $R{"slot.$slot.fruSerialNo"} = $rep1->value("controller.$u.fruSerialNo");
           $R{"slot.$slot.fruVendor"}   = $rep1->value("controller.$u.fruVendor");
         }
         &copy($slot, $fru, \%R, "controller.u${c}ctr", $rep1);
         &updStatus2("fru.$fru", "$key:controller.u${c}ctr", \%R, $Comp);
         $fru++;

         $R{"fru.$fru.portWWN"} = $rep1->value("port.u${c}p1.portWWN");
         &copy($slot, $fru, \%R, "midplane.u${c}mpn", $rep1);
         $fru++;

         &copy($slot, $fru, \%R, "power.u${c}pcu1", $rep1);
         &updStatus2("fru.$fru", "$key:power.u${c}pcu1", \%R, $Comp);
         $fru++;

         &copy($slot, $fru, \%R, "power.u${c}pcu2", $rep1);
         &updStatus2("fru.$fru", "$key:power.u${c}pcu2", \%R, $Comp);
         $fru++;

         for ($d=1; $d <= $disks; $d++) {
            my $d0 = "disk.u${c}d$d";
            &copy($slot, $fru, \%R, $d0, $rep1);
            &updStatus2("fru.$fru", "$key:$d0", \%R, $Comp);
            $fru++;
         }
         for ($l=1; $l <= 2; $l++) {
            my $c1 =  "loopcard.u${c}l$l";
            &copy($slot, $fru, \%R, $c1, $rep1);
            &updStatus2("fru.$fru", "$key:loopcard.u${c}l$l", \%R, $Comp);
            $fru++;
         }
      }
      # USE LUNS OF T3/T4
         my $v;
         for ($x=1; $x <= $units; $x++) {
             for ($v=1; $v <= 10; $v++) {
                my $id = "volume.u${x}vol$v";
                last if (!$rep1->value("$id.volRaidLevel"));
                $R{"lun.$lun.lunIndex"}   = $lun;
                $R{"lun.$lun.lunId"}         = $rep1->value("$id.volId");
                $R{"lun.$lun.volId"}        = $dev->{name} . "-u${x}vol$v";
                $R{"lun.$lun.lunName"}      = $dev->{name} . "-vol$v";
                $R{"lun.$lun.lunWwn"}        = $rep1->value("$id.volWWN");
                $R{"lun.$lun.lunRaidLevel"}  = $rep1->value("$id.volRaidLevel");
                $R{"lun.$lun.lunCapacity"}   = $rep1->value("$id.volCapacity");
                $R{"lun.$lun.lunType"}       = $dev->{type};
                $R{"lun.$lun.lunCacheMode"}  = $rep1->value("$id.volCacheMode");
                $R{"lun.$lun.lunVolName"}    = $rep1->value("$id.volName");
                $R{"lun.$lun.lunStatus"}     = $rep1->value("$id.volStatus");
                #$R{"lun.$lun.lunRemoteCopy"}    = "FALSE";
                #$R{"lun.$lun.lunBeingBackedUp"} = "FALSE";
                $total_cap +=  $R{"lun.$lun.lunCapacity"};
                $lun++;
             }
         }
         for ($x=0; $x < $rep1->value("slice.count"); $x++) {
             $R{"slice.$slice.lunName"}       = $rep1->value("slice.$x.lun-lun");
             $R{"slice.$slice.volId"}         = $rep1->value("slice.$x.volId");
             $R{"slice.$slice.volSliceEnd"}   = $rep1->value("slice.$x.volSliceEnd");
             $R{"slice.$slice.volSliceName"}  = $rep1->value("slice.$x.volSliceName");
             $R{"slice.$slice.volSliceSize"}  = $rep1->value("slice.$x.volSliceSize");
             $R{"slice.$slice.volSliceStart"} = $rep1->value("slice.$x.volSliceStart");
             $slice++;
         }
    } elsif ($dev->{type} eq "csm200") {
      my ($c, $d, $l);
      my $units = $rep1->value("iom.count") || 2;
      my $disks = $rep1->value("disk.count") || 32;
      my $sfp = $rep1->value("sfp.count") || 20;

      push(@array_reps, $rep1);

      $R{"slot.$slot.dev-units"} = $units;
      $R{"slot.$slot.dev-disks"} = $disks;
      $R{"slot.$slot.dev-sfp"} = $sfp;

      for ($c=1; $c <= $units; $c++) {
         my $u = "u$c" . "ctr";
         if ($rep1->value("ctrl.$c._Realized")) {
           my $r = $rep1->value("ctrl.$c._Realized");

           $R{"slot.$slot.fruId"}       = $rep1->value("ctrl.$c._DeviceID"); 
           #$R{"slot.$slot.fruModel"}   = $rep1->value("controller.$u.fruModel");
           $R{"slot.$slot.fruRevision"} = $rep1->value("ctrl.$c._FirmwareVersion");
           $R{"slot.$slot.fruSerialNo"} = $r;
           $R{"slot.$slot.fruVendor"}   = "SUN"
         }
      }
      my $repval=$rep1->{_value};
      foreach my $repkey (keys(%$repval)){
         if($repkey =~ /_DeviceID$/){
	    # Found device entry
	    #'sfp.15._DeviceID' => 't85ctrl2hssfp1',
            my @devarray = split(/\./, $repkey);
	    my $devkey = $devarray[0] . "\\." . $devarray[1] . "\\.";
	    $R{"fru.$fru._theType"} = $devarray[0];
	    $R{"fru.$fru.fruSlot"} = $slot;

	    # $devkey should be sfp.15.
	    foreach my $comp (keys(%$repval)){
               if($comp =~ /^$devkey/){
		  my @comparray = split(/\./, $comp);
	          my $compdata = $repval->{$comp};
		  $R{"fru.$fru.$comparray[2]"} = $compdata;
                  if($comp =~ /_Realized$/){
		     # sfp.15._Realized' => 'JDS UNIPHASE.JSH-42S4AA3.F5242417014B
		     foreach my $frus (keys(%$repval)){
		        # Must search again looking for the fru information
		        if($frus =~ /^fru.*_Key$/){
		           my $frudata = $repval->{$frus};
			   if($frudata eq $compdata){
			     # We have found the fru entry for this component
			     my @fruarray = split(/\./, $frus);
	                     my $frukey = $fruarray[0] . "\\." . $fruarray[1]. "\\.";
			     foreach my $fru1 (keys(%$repval)){
				if($fru1 =~ /^$frukey/){
				   my @fru1array = split(/\./, $fru1);
				   my $fru1data = $repval->{$fru1};
				   $R{"fru.$fru.$fru1array[2]"} = $fru1data;
				}
			     }
			     last;
		           }
		        }
		     }
                  }
               }
	    }
	    $fru++;
	 }
      }
# VE
    } elsif ($dev->{type} eq "ve") { # luns from vicoms
      $R{"fru.$fru.ipNo"}       = $rep1->id('ip');
      $R{"fru.$fru.version"}    = $rep1->value('initiator.version');
      $R{"fru.$fru.fruSlot"}  = $slot;
      $R{"fru.$fru.fruType"}    = "ve";
      $R{"fru.$fru.fruId"}      = "ve";
      $fru++;
      if ($first_ve) {
        $first_ve = 0;
        $rep1 = $rep1->subset("logical");
        foreach my $ix (keys %$rep1) {
          if ($ix =~ /(\w+)\.capacity/) {
             my $id = $1;
             $R{"lun.$lun.lunIndex"} = $lun;
             $R{"lun.$lun.volId"}       = $dev->{name} . "-vol$lun";
             $R{"lun.$lun.lunName"}     = $dev->{name} . "-vol$lun";            
             $R{"lun.$lun.lunType"}     = $rep1->value("$id.type");
             $R{"lun.$lun.lunCapacity"} = $rep1->value("$id.capacity");
             $R{"lun.$lun.lunId"}       = $rep1->value("$id.name");
             my $ww = $rep1->value("$id.serial");
             $ww =~ s/-//;
             $R{"lun.$lun.lunWwn"}      = $ww;
             $R{"lun.$lun.lunStatus"}   = $rep1->value("$id.status") || "N/A";
             $total_cap +=  $R{"lun.$lun.lunCapacity"};
             $lun++;
          }
        }
      }
    }
    $slot++;
  }
##Build Mapping of user vols to physical disks
  if ((substr($model,0,4) eq "6940"    || substr($model,0,4) eq "6920") && $dsp_rep) {
    for (my $volnum=1; $volnum <= $dsp_rep->value('totals.volume'); $volnum++) {
      for(my $vdisknum=1;
        $vdisknum<=$dsp_rep->value("volume.$volnum.slice.total");$vdisknum++){
        my $vdisk_key = "volume.$volnum.slice.$vdisknum";
        my $vdisk_name = substr($R{"$vdisk_key.SliceName"},0,-2);
        for(my $disks=1; $disks <= $dsp_rep->value('totals.disk'); $disks++){
          if(($dsp_rep->value("disk.$disks.path.1.Name") eq $vdisk_name)||
            ($dsp_rep->value("disk.$disks.path.2.Name") eq $vdisk_name)){
            my $lun_wwn = lc($dsp_rep->value("disk.$disks.LunWWN"));
            foreach my $array (@array_reps){
              for(my $slices=1;$slices<=$array->value('slice.count');$slices++){
                if($lun_wwn eq
                     lc(substr($array->value("slice.$slices.volSliceWWN"),8))){
                  my $sysId = $array->value('system.sysId');
                  my $volId = $array->value("slice.$slices.volId");
                  my $hsh = $array->{'_value'};
                  my $disk_count=0;
                  foreach my $key (keys(%$hsh)){
                    if($key =~ /volume_disk.$volId-d-(\d+).volDiskFruId/){
                  $disk_count++;
                  $R{"volume.$volnum.slice.$vdisknum.physicalDisk.$disk_count"}=
                      "$sysId.$volId.".
                       $array->value("volume_disk.$volId-d-$1.volDiskFruId");
                    }
                  }
                  $R{"volume.$volnum.slice.$vdisknum.physicalDisk.total"}=$disk_count;
                }
              }
            }
          }
        }
      }
    }
  }
  $R{"info.totalCapacity"} = $total_cap;
  $R{"info.slotTotal"} = $slot;  # slot 0 exists (sp)
  $R{"info.fruTotal"} = $fru;    # fru 0 exists
  $R{"info.lunTotal"} = $lun - 1;
  $R{"info.sliceTotal"} = $slice - 1;
  $R{"info.volTotal"} = $vol - 1;

  if (substr($model,0,2) eq "39") {
     $R{"info.supportedRAIDType"}    = "RAID1,RAID5";
  } else {
     $R{"info.supportedRAIDType"}    = "RAID1,RAID5";
  }
  $class->addIdentification(\%R);
  return \%R;
}

sub copy {
   my($slot, $fru, $R, $key, $rep1) = @_;

   my $repC = $rep1->content();
   $R->{"fru.$fru.fruSlot"} = $slot;
   my $ix = index($key, ".");
   my $key0 = substr($key,$ix+1);
   $R->{"fru.$fru.fruId"} = $key0;
   foreach my $el (
           'fruType','fruModel','fruRevision','fruSerialNo',
           'fruVendor','fruState','fruStatus','fruDiskTemp','fruDiskCapacity',
           'fruDiskPort1State','fruDiskPort2State',
           'fruCtlrRole','fruErrors','fruLoopCable1State','fruLoopCable2State',
           'fruLoopMode','fruLoopTemp',
           'fruPowerBatLife','fruPowerFan1State','fruPowerFan2State',
           'fruCtlrVersion', 'fruLoopVersion',
          ) {
      if (exists $rep1->{_value}{"$key.$el"}) {
        $R->{"fru.$fru.$el"} = $rep1->value("$key.$el");
      }
   }
   foreach my $el ('fruLoopVersion','fruCtlrVersion') {
      if (exists $rep1->{_value}{"$key.$el"}) {
        $R->{"fru.$fru.fruVersion"} = $rep1->value("$key.$el");
      }
   }

   $R->{"fru.$fru.key"} = NWS::T3->getKey($repC, $key);
}

sub FCfromDevice {
  my($agent, $report) = @_;

  return {};
}

sub report_fru {
  my($q) = @_;
  print Html->body();
  my $r = Report->readNew($q->{file});
  my $fru = $q->{fru};
  my $len = length($fru);
  my $v = $r->{_value};
  my $slot      = $v->{"$fru.fruSlot"};
  my $slot_name = $v->{"slot.$slot.dev-name"};
  my $slot_type = $v->{"slot.$slot.dev-type"};
  my $bg = " align=right bgcolor=$Style::LIGHT";
  my $sd = $v->{"$fru.status-desc"};
  my $ss = $v->{"$fru.status-sev"};
  my $GIF = State->sev_gifs();
  
  my $current_err = "<tr><td $bg>Last Alert:</td><td><img src=/gif/$GIF->[$ss]>&nbsp;$sd</td>" if ($sd);

  print "<table border=1 cellspacing=0 width=100% bgcolor=white>
  <tr><td colspan=2 bgcolor=$Style::DARK>&nbsp;<font color=white><b> Fru Details</td>
  <tr><td $bg>Device:</td><td>&nbsp;$slot_type $slot_name</td>
  $current_err
  ";

  foreach my $e (sort keys %$v) {
     if ($e =~ /^$fru\./) {
        next if ($e =~ /^$fru\.status\-/);
        my $val = $v->{$e};
        my $e0 = substr($e,$len+1);
        $e0 = substr($e0,3) if (substr($e0,0,3) eq "fru");
        print "<tr><td $bg>$e0:</td><td>&nbsp;$val</td>\n";
     }
  }
  print "</table><form><input type=submit value=Close onclick=window.close()></form>";
}

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

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

  my($v) = $r->{_value};
  my $seq = $v->{'info.power_sequencer.status'} || "N/A";
  $out .= $class->reportHead($v->{'info.model'}, $r);
  $out .= "
 <script>
   function show1(file, fru) {
      var b = '$Http::WEBPROC?GO=Agent::SE_MODULE::report_fru&file=' + file + '&fru=' + fru;
      var O = window.open(b,'linfo','menubar=yes,resizable=yes,scrollbars=yes,width=500,height=400');
      O.focus();
   } 
   </script> 
   <tr><td bgcolor=$LIGHT align=right width=10%><b>Name:</td><td>&nbsp;$r->{_id}{display}</td>
     <td bgcolor=$LIGHT align=right width=10%><b>Model:</td><td width=25%>&nbsp;$v->{'info.model'}</td>
   <tr>
        <td bgcolor=$LIGHT align=right width=10%><b>Revision:</td>
        <td >&nbsp;$v->{'info.firmwareLevel'}</td>
        <td bgcolor=$LIGHT align=right width=10%><b>Power Sequencer:</td>
        <td >&nbsp;$seq $v->{'info.power_sequencer.error'}</td>
  </table>
  <table border=0 cellspacing=0 width=100% bgcolor=white><tr><td></table>
  <table border=1 cellspacing=0 width=$Style::WIDTH bgcolor=white>
   <tr bgcolor=$LIGHT><th>Component
       <th>Name
       <th>Status
  ";
  my($x);
  my @ER  = ($G->{ok}, $G->{warning}, $G->{error}, $G->{down});
  my @COL = ('', 'bgcolor=#FFFFD0',  'bgcolor=#FFE0E0', 'bgcolor=#FFD0D0');

  for ($x=0; $x < $v->{'info.slotTotal'}; $x++) {
     my $type  = $v->{"slot.$x.dev-type"};
     my $type0 = $type eq "sp" ? "host": $type;
     my $label = $v->{"slot.$x.dev-userLabel"} || $type0;
     my $name  = $v->{"slot.$x.dev-name"};
     my $status = $v->{"slot.$x.status-sev"};
     my $info  = $v->{"slot.$x.status-desc"};
     my $k     = "$type0:" . $v->{"slot.$x.dev-key"};
     my $h1    =  ($v->{"id.mgmtLevel"} eq "D") ? $v->{"id.ipno"} : $host;
     my $u     = $name; # "<a href=$Http::WEBPROC?GO=GUI::Instr::rStart&file=$k&host=$h1>$name</a>";
     $out     .= "<tr><td><b>&nbsp;$x-$label<td>&nbsp;$u<td $COL[$status]>&nbsp;$ER[$status]\n";
  }
  $out .= "</table>
  <table border=0 cellspacing=0 width=100% bgcolor=white><tr><td></table>
  <table border=1 cellspacing=0 width=$Style::WIDTH bgcolor=white>
   <tr bgcolor=$LIGHT><th>Port
       <th>Id
       <th>WWN
       <th>Status
  ";
  my $pcnt;
  for ($x=0; $x < $v->{'info.portTotal'}; $x++) {
     my $type   = $v->{"fcPort.$x.encName"} || $v->{"fcPort.$x.PortId"};
     my $status = $ER[$v->{"fcPort.$x.status-sev"}];
     my $wwn    = $v->{"fcPort.$x.LocalPortWWN"};
     $pcnt++;
     $out .= "<tr><td>&nbsp;<b>" . ($x+1) . 
                "<td>&nbsp;$type<td>&nbsp;$wwn<td>&nbsp;$status</td>\n";
     my $info = $v->{"fcPort.$x.status-desc"};
     #$out .= "<tr><td colspan=4><small>$info" if ($info);

  }
  if (!$pcnt) {
     $out .= "<tr><td colspan=4>No port found!</td>"
  }
  my $tot = $v->{'info.fruTotal'};
  $out .= "</table>
  <table border=0 cellspacing=0 width=100% bgcolor=white><tr><td></table>
  <table border=1 cellspacing=0 width=$Style::WIDTH bgcolor=white>
   <tr bgcolor=$LIGHT><th>FRU
       <th>Type
       <th>Name
       <th>Rev
       <th>Status
  ";
  my ($dev, $last_dev);
  require SE;
  for ($x=0; $x < $tot; $x++) {
     my ($info, $rev, $status);
     my $se     = SE->fruInfo($v, $x);
     my $type   = $se->{devType} || $se->{name};
     my $ss     = $se->{severity};
     my $status = $se->{status};
     my $slot   = $se->{slot};
     my $rev    = $se->{revString};
     my $bg     = $COL[$ss] if ($ss > 0 && $ss < 4);

     $dev = $v->{"slot.$slot.dev-name"};
     if ($dev ne $last_dev) {
        my $type2  = $se->{devLabel} || $se->{devType};
        $out .= "<tr bgcolor=#FFFFEE><td>&nbsp;<td><b>$type2<td colspan=3><b>&nbsp;$dev\n";
        $last_dev = $dev;
     }
     $status = $ER[$ss] if (!$status && $ss > 0);
     $out .= "<tr><td center>$x<td>$type<td>$se->{name}<td nowrap>$rev&nbsp;<td $bg><center>$status&nbsp;</td>\n";

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

#
  my $model = $v->{'info.model'};
  if (substr($model,0,2) eq "39" || substr($model,0,2) eq "63") { 
    $out .= "</table>
   <table border=0 cellspacing=0 width=100% bgcolor=white><tr><td></table>
    <table border=1 cellspacing=0 width=$Style::WIDTH bgcolor=white>
     <tr bgcolor=$LIGHT><td colspan=6 bgcolor=#FFFFEE><b> Volumes
     <tr bgcolor=$LIGHT><th>#
       <th>Id
       <th>Name
       <th>Status
       <th>Raid
       <th>Capacity
    ";

    my $tot = $v->{'info.lunTotal'};
    my $last = $tot;
    my $MAX = 130;
    $last = $MAX if ($last > $MAX && !$q->{ALL});
    for ($x=1; $x <= $last; $x++) {
       my $type   = $v->{"lun.$x.lunVolName"};
       my $status = $v->{"lun.$x.lunStatus"};
       my $name   = $v->{"lun.$x.lunName"};
       my $cap    = sprintf("%.3f", $v->{"lun.$x.lunCapacity"} / 1024);
       my $raid   = $v->{"lun.$x.lunRaidLevel"};

       $out .= "<tr><td center>" . ($x-1) . 
            "<td><center>$type</td>
             <td>$name</td>
             <td>$status</td>
             <td>$raid&nbsp;</td>
             <td align=right>$cap GB</td>
               ";

    }
    $out .= "</table>";
  
    if ($tot > $last) {
      my $key = $r->id("category") . ":" . $r->id("deviceName");
      $out .= "<a href=$Http::WEBPROC?GO=GUI::Instr::rStart&file=$key&Roption=1&ALL=1>[ Show All Luns ($tot)]</a>\n";
    }

    $out .= "
    <table border=0 cellspacing=0 width=100% bgcolor=white><tr><td></table>
    <table border=1 cellspacing=0 width=$Style::WIDTH bgcolor=white>
     <tr bgcolor=$LIGHT><td colspan=4 bgcolor=#FFFFEE><b>Slices / Luns
     <tr bgcolor=$LIGHT><th>#
         <th>VolId
         <th>Name
         <th>Size
    ";
    my $tot = $v->{'info.sliceTotal'};
    for ($x=1; $x <= $tot; $x++) {
       my $vol   = $v->{"slice.$x.volId"};
       my $size  = sprintf("%.3f", $v->{"slice.$x.volSliceSize"}/1024/1024/2);
       my $n2    = $v->{"slice.$x.volSliceName"};
       my $name  = $v->{"slice.$x.lunName"};
  
       $out .= "<tr><td center>" . ($x-1) . "
              <td><center>$vol&nbsp;</td>
              <td>$name $n2&nbsp;</td>
              <td align=right>$size GB&nbsp;</td>
               ";
    }

  }else{
    $out .= "</table>
    <table border=0 cellspacing=0 width=100% bgcolor=white><tr><td></table>
    <table border=1 cellspacing=0 width=$Style::WIDTH bgcolor=white>
     <tr bgcolor=$LIGHT><td colspan=6 bgcolor=$LIGHT><b> Volumes
     <tr bgcolor=$LIGHT><th>#
       <th>Name
       <th>Capacity
       <th>Id
    ";

    my $tot = $v->{'info.volTotal'};
    my $last = $tot;
    my $MAX = 130;
    $last = $MAX if ($last > $MAX && !$q->{ALL});
    for ($x=1; $x <= $last; $x++) {
      my $size = $v->{"volume.$x.VolumeSize"};
      my $ID = $v->{"volume.$x.DeviceID"};
      my $name = $v->{"volume.$x.ElementName"};
      $out .= "<tr><td center>" . ($x-1) ." 
             <td align=left>$name</td>
             <td align=right>$size</td>
             <td>$ID</td>
               ";
      my ($s);
      my $first=1;
      for ($s=1; $s <= 200; $s++) {
          last if (!$v->{"volume.$x.slice.$s.SliceName"});
          if ($first) {
            $out .= "<tr><td></td><td>SliceName</td><td>Size</td><td>Status</td>";
            $first = 0;
          }
          my $name = $v->{"volume.$x.slice.$s.SliceName"};
          my $size = $v->{"volume.$x.slice.$s.SliceSize"};
          my $st   = $v->{"volume.$x.slice.$s.SliceStatus"};
          $out .= "<tr><td></td><td>$name</td><td>$size</td><td>$st</td>";
        
      }
    }
    $out .= "</table>";
  }

  $out .= "</table>";
  $out .= "&nbsp;<p>&nbsp;";
}


1;
