package Discman;

use System;
use Util;
use strict;
use vars qw (%DONE);


sub parse {
  my($class, $Topo, $com) = @_;
  my $renv = System->get_renv();
  my(%hosts, %hbas, %devices);
  %DONE     = ();
  my($SW)   = {};
  my($ST)   = {};
  my $Config = PDM::ConfigFile->read();
  my $cdevs = $Config->devices();
  foreach my $d (@$cdevs) {
     next if ($d->{type} ne "switch");
     next if (!Util->isMineToMonitor($d));
     $SW->{$d->{ipno}} = $d->{wwn} if ($d->{ipno} && $d->{wwn});
  }

  my($out, $l, $x, $hostname, $in, $curr_hba, $curr_dev_cnt, $curr_dev, @a );

#  my(@lux) = `/usr/sbin/luxadm probe -p`;  # needs run_command
  my($log);
#  $DB::single= 1;
  my $dev_cnt  = 0;
  for ($x=0; $x <= $#$com; $x++) {
      $l = $com->[$x];
      next if ($l =~ /^\s*$/);
      $l = Util->trim($l);
      if ($l =~ /^\s*Hostname:\s*(.*)/) {
          $hostname = System->hostname();
          $hosts{$hostname}{type}    = "Sun";
          $hosts{$hostname}{class}   = "host";
          $hosts{$hostname}{name}    = "host:$hostname";
          $hosts{$hostname}{hostid}  = System->hostid();
          $hosts{$hostname}{model}   = System->model();
          $hosts{$hostname}{release} = System->os_version();

      } elsif ($l =~ /^\s*Host type:\s*(.*)/) {
          $hosts{$hostname}{model2}   = $1;

      } elsif ($l =~ /^\s*Detected.*HBA port\(s\)/) {
          $in = "hbasumm";

      } elsif ($l =~ /^\s*Detected.*FCAL Device\(s\)/) {
          $in = "devicesumm";

      } elsif ($l =~ /^\s*HBA Port (\d+) Path:(.*)/) {
          $in = "hba"; $curr_hba = $1; #sprintf("%2.2d", $1);
          $hbas{$hostname}{$curr_hba}{path} = $2;
          $curr_dev_cnt = -1;

      } elsif ($l =~/^\s*Device # (\d+):\s*$/) {
          $in = "device";
          $curr_dev_cnt++; $dev_cnt++;
          $curr_dev = sprintf("%3.3d", $curr_dev_cnt);

      } elsif ($in eq "hbasumm") {     #  SOCAL HBA port(s):      0

      } elsif ($in eq "devicesumm") {
          @a = split(/\s*:\s*/, $l,2);
          $hosts{$hostname}{$a[0]} .= $a[1] . ",";

      } elsif ($in eq "hba") {
          @a = split(/\s*:\s*/, $l,2);
          $a[1] =~ s/[,\|]/ /g;
          $hbas{$hostname}{$curr_hba}{$a[0]} = $a[1];

      } elsif ($in eq "device") {
          @a = split(/\s*:\s*/, $l,2);
          if (length($a[1]) > 0) {
             $a[1] =~ s/[,\|]/ /g;
             $devices{$hostname}{$curr_hba}[$curr_dev_cnt]{$a[0]} = $a[1];
          }
      }
  }
  #return undef if (!$dev_cnt);

  my(%attached, $dinfo, $alpa, $sw_type, $portno, $current_sw, $devs);
  my($dp_port, @DP2OBJ, $last_sl_port, $hba);
  my(%PG, %PGM) ;
  my($host, $hostObj, $h, $hinfo , $dp_switch, $current_st, $st_type, 
    $current_hub , $st_port, $new);
  my($ip_port) = -1;
  my(%MAP, $from , $fromK);
  my $incomplete = {flag => 0};
  my $syns      = $Topo->[4];

  foreach $host (sort keys %hosts) {
    $hostObj = TO::HOST->new($Topo, $host, $hosts{$host});
    
    $out .= "Host: $host $hosts{$host}{type}\n";
    foreach $hba (sort keys %{$hbas{$host}}) {  # number
       $dp_port = 0; $dp_switch = -1;
       $out .= "\n[hba-$hba ";
       $hinfo = $hbas{$host}{$hba};
#       $hinfo->{_comp_id} = "port.$hba";
       $hinfo->{BoardSlotPort} = $hinfo->{'IO Board Slot'} . ':' .
                                 $hinfo->{'Slot on IO Board'} . ':' . 
                                 $hinfo->{'Port on Card'} ;
       delete $hinfo->{'IO Board Slot'};
       delete $hinfo->{'Slot on IO Board'};
       delete $hinfo->{'Port on Card'};

       $hinfo->{hbaNo} = $hba;
       $hostObj->{portInfo}[$hba] = $hinfo;
       #$Topo->[4]{$hinfo->{PortWWN}} = "host:$host:$hba";
       $dp_port = 0; $dp_switch = -1; %attached = (); $last_sl_port = "";

       if ($hinfo->{al_pa} == -2) {    # hba not attached
           $hostObj->{port}[$hba] = 0;
           $out .= "not connected]\n";
           next;
       }
       $MAP{"HBA$hba"} = [$hostObj, $hba];
       my %A5;
       my($p2) = $hinfo->{path};
       my($i2) = rindex($p2, ":");
       $p2 = substr($p2, 1, $i2-1);
       
       $out .= "$hinfo->{LGroup}, Port:$hinfo->{PortWWN}, alpa=$hinfo->{al_pa}]\n";
       $out .= "[       $hinfo->{path}  ]\n";
       $devs = $devices{$host}{$hba};
       my($dev_ix);
       for ($dev_ix=0; $dev_ix <= $#$devs; $dev_ix++) {
           $dinfo = $devs->[$dev_ix];
           my $next_dinfo = $devs->[$dev_ix+1];
           # SUN SWITCH
           if ($dinfo->{ProductID}  =~ /Switch/) {
               ($new, $current_sw) = TO::SWITCH->new($SW, $Topo, $host, $dinfo);
               last if (!$current_sw);
               $portno  = $dinfo->{sw_PortNum};
               $sw_type = TO::SWITCH->portType($dinfo);

               $MAP{"DEVICE".$dinfo->{DeviceID}} = [$current_sw, $portno];

               if ($current_sw->{portInfo}[$portno]) {
                  my $p = $current_sw->{portInfo}[$portno];
                  if (index("|$p->{registerList}|", "|$dinfo->{RegisterName}|") < 0) {
                    $p->{registerList} .= "|$dinfo->{RegisterName}";
                  }
               } else {
                  my $local = sprintf("20%2.2x%s", $portno-1, substr($current_sw->key(),4));
                  $syns->{$local} = $current_sw->name() . ":$portno";
                  my $portwwn;
                  if (exists($dinfo->{RemotePortWWN}) &&  $dinfo->{RemotePortWWN}) {
                     $portwwn = $dinfo->{RemotePortWWN};
                  } else {
                     $portwwn = $dinfo->{PortWWN};
                  }
                  $current_sw->{portInfo}[$portno] = {
                       sw_PortNum   => $dinfo->{sw_PortNum},
                       sw_PortType  => $dinfo->{sw_PortType},
                       sw_PortState => $dinfo->{sw_PortState},
                       PortWWN      => $portwwn,
                       LocalPortWWN    => $local, 
                       RemotePortWWN   => $dinfo->{RemotePortWWN},
                       sw_ipAddr_remote=> $dinfo->{sw_ipAddr_remote},
                       sw_remote_fcaddr=> $dinfo->{sw_remote_fcaddr},
                       sw_FabricID  => $dinfo->{sw_FabricID},
                       Status       => $dinfo->{Status},
                       RegisterName => $dinfo->{RegisterName},
                       registerList => $dinfo->{RegisterName},
                       Parent       => $dinfo->{Parent},
                       portType     => $sw_type,
                       'Parent type' => $dinfo->{'Parent type'},
                       };
               }
               $alpa = $dinfo->{sw_DevAlpas};
               $alpa = substr($alpa,0,11) . "..." if (length($alpa) > 11);

               $dp_port = 0; $dp_switch = -1;
               if ($dinfo->{NodeWWN} =~ /^0+$/) {
                   $current_sw->{port}[$portno] = 0;
               } else {
                  $fromK = $dinfo->{"Parent type"} . $dinfo->{Parent};
                  $from  = $MAP{$fromK};
                  if (!$from) {
                     Debug->info(TEXT => "TOPO: In sw-device $dinfo->{DeviceID}: Cannot find the parent $fromK");
                     next;
                  }
                  if ($from->[0] == $current_sw) { # port2port in same switch

                    if (index("-" .  $current_sw->{dport}[$from->[1]], "-$portno-") < 0) {
                        $current_sw->{dport}[$from->[1]] .= $portno . "-";
                    }

                  } elsif ($dinfo->{RegisterName} !~ /ZZZ/) {
                    $current_sw->{port}[$portno] = TO->nodeName($from->[0]) .":". $from->[1];
                    $from->[0]->{port}[$from->[1]] = TO->nodeName($current_sw) . ":$portno";
                  }
               }
           # STORAGE
           } else {
              #if ($dinfo->{LGroup} =~ /-Internal-/) {
              #    my $disk = $dinfo->{RegisterName};
              #    $hostObj->{diskInfo}{$disk} = $dinfo;
              #    next;
              #}
              # next if ($dinfo->{"Path State"} =~ /STATE_STANDBY/); # MPX

              ($new, $st_port, $st_type, $current_st) = 
                         $class->newStorage($ST, $Topo, $host, $dinfo ,$hba, 
                         $p2, $incomplete, \%attached, $next_dinfo);
              Debug->print3("Adding newStorage (inband): $st_type, " . $current_st->name()) if ($new);
              next if (!$current_st);

              $MAP{"DEVICE".$dinfo->{DeviceID}} = [$current_st, $st_port] ;

              my($vol) = 0;
              my($disk) = $dinfo->{RegisterName};
              if ($st_type eq "t3" || $st_type eq "6120" || $st_type eq "dsp" || $st_type eq "se2") {
                 $current_st->{volInfo}{$dinfo->{LogicalPath}} = {
                        PortWWN => $dinfo->{PortWWN},
                        NodeWWN => $dinfo->{NodeWWN},
                        Revision => $dinfo->{Revision},
                        PortMode => $dinfo->{PortMode},
                        Capacity => $dinfo->{Capacity},
                        Revision => $dinfo->{Revision},
                        PhysPath => $dinfo->{PhysPath},
                        SerialNo => $dinfo->{SerialNo},
                 };

                 if ($dinfo->{PortMode} =~ /Alternate/) {
                   $current_st->{info}{PG} = 1 ;
                   next; # do not show alternate lun, the primary should 
                         # always be there, unless it's a bad config.
                         # this happens with t3pg with only one connection.
                 }
              } elsif (index("a5k,v880disk", $st_type) >= 0) {
                 if ($dinfo->{RegisterName} !~ /\-ses(\d+)/) {  # disks device
                    my($i) = index($disk, "-");                 # c5t34d0-f2
                    $disk = substr($disk, $i+1);
                    my($id) = substr($disk,0,1) . sprintf("%2.2d", substr($disk,1));
                    if (exists($current_st->{diskInfo}{$disk})) {
                        $current_st->{diskInfo}{$disk}{LogicalPath} .= 
                                "|$dinfo->{LogicalPath}";
                    } else {
                      $current_st->{diskInfo}{$disk} = {
                        PortWWN => $dinfo->{PortWWN},
                        NodeWWN => $dinfo->{NodeWWN},
                        LogicalPath => $dinfo->{LogicalPath},
                        #sf_al_pa => $dinfo->{sf_al_pa},
                        VendorID => $dinfo->{VendorID} .":" . $dinfo->{SerialNo},
                        devID    => $id,
                        RegisterName => $dinfo->{RegisterName},

                        #FirmwareRev => $dinfo->{FirmwareRev},
                        #SerialNo => $dinfo->{SerialNo},
                      };
                    }
                    next;
                 }
                 next if ($current_st->{info}{"ses_cnt$hba"} > 0);
                 $current_st->{info}{"ses_cnt$hba"}++;

              } elsif (index(",a3500fc,tape,ve,internal,", ",$st_type,") < 0) {
                 $current_st->{diskInfo}{$disk} = $dinfo;
              }

              next if ($attached{TO->nodeName($current_st).$st_port}); 
              $attached{TO->nodeName($current_st).$st_port} = 1;

              $fromK = $dinfo->{"Parent type"} . $dinfo->{Parent};
              $from  = $MAP{$fromK};
              if (!$from) {
                 $incomplete->{flag} = 1;
                 my $M = "Discman Device $dinfo->{DeviceID}/$dinfo->{LGroup}/$dinfo->{NodeWWN}: Cannot find the parent-hba '$fromK', this device will not be connected to it's HBA";
                 $incomplete->{err} .= "$M\n";
                 Debug->print2($M);
                 next;
              }
              &addNode($host, $Topo, $from->[0], $from->[1], $st_type, $current_st, $st_port);
           }
       }
    }
  }

  my $H = $Topo->[0];
  foreach my $h (keys %$H) {
     my $h1 = $H->{$h};
     my $ports = $h1->portInfo();
     my $list = "";
     my $x;
     for ($x=0; $x <= $#$ports; $x++){
        my $p = $ports->[$x];
        next if (!$p->{PortWWN} || substr($p->{PortWWN},0,2) eq "00");
        if (index(",$list,", ",$p->{PortWWN},") >= 0) {
           $h1->{info}{errors} .= "found duplicate portWWN on hba# $x| ";
        } else {
           $list .= "$p->{PortWWN},";
        }
     }
  }

  # FIND EMPTY SLOTS IN A5K/V880
  #
  my $S = $Topo->[2];
  foreach my $s (keys %$S) {
     my $st = $S->{$s};
     if (index("a5k,v880disk", $st->{info}{type}) >= 0) {
       my $ds = $st->{diskInfo};
       my @E;
       foreach my $x (keys %$ds) {
          if ($st->{info}{type} eq "a5k") {
            my $x0 = $x;
            my $ix = index($x,"_");
            $x0 = substr($x,0,$ix) if ($ix > 0);
            my $p = (substr($x0,0,1) eq "f") ? substr($x0,1) : substr($x0,1) + 11;
            $E[$p] = 1;

          } elsif ($x =~ /slot(\d+)/) {  # v880
                my $x0 = $1;
                $E[$x0] = 1;
          }
       }
       for ($x=0; $x <= 21; $x++ ) {
           $E[$x] = ($E[$x] == 1) ? 0: -1;
       }
       $st->{info}{disk_map} = join(",", @E);
     }
  }
  return ($out, $incomplete);
}

sub addHubs {
  my($class, $Topo, $type) = @_;
  my $hosts = $Topo->hostList();
  my $arrays = $Topo->storageList();
  my($x,$y, %X);

  foreach my $h (@$hosts, @$arrays) {
     my $ports = $h->port();
     for ($x=0; $x <= $#$ports; $x++) {
        my $p = $ports->[$x];
        next if (!$p);
        my $target = $Topo->nodeByName($p);
        next if (!$target || $target->class() =~ /^switch/ );
        my $key = $h->name() . ":" . $x;
        push(@{$X{$p}}, $key);
     }
  }
  my %HUBS;
  foreach my $key (keys %X) {
      my $v = $X{$key};
      next if ($#$v <= 0);
      my $hub_name;
      if (substr($key,0,4) ne "host") {
         $hub_name = $key;
      } else {
         $hub_name = "{{{{";
         foreach my $v0 (@$v) {
             $hub_name = $v0 if ($v0 lt $hub_name);
         }
      }
      push(@{$HUBS{$hub_name}}, @$v, $key);
  }

  foreach my $hub1 (keys %HUBS) {
       my $v = $HUBS{$hub1};
       my @h = split(/\:/, $hub1);
       my $hub_name = "hub:$h[1]-$h[2]" ;
       my $Hubs  = $Topo->[3];
       my($obj)  = {};
       $obj->{info}{type}  = 'hub';
       $obj->{info}{class} = 'switch.hub';
       $obj->{info}{name}  = $hub_name;
       $obj->{info}{userLabel} = "hub";
       $obj->{info}{host}  = "";
       bless($obj, 'TO::HUB');
       $Hubs->{$hub_name}  = $obj;
       my $count = 0;
       foreach my $v0 (@$v) {
         &connect($Topo, $v0, $obj, $count);
         $count++;
       }
  }

}

sub connect {
  my($Topo, $v, $hub, $pos) = @_;

  if ($pos == -1) {
    my $ports = $hub->port();
    $pos = $#$ports + 1;
  }
  my($node, $node_p) = $Topo->nodeByName($v);

  $node->{port}[$node_p]   = $hub->name() . ":$pos";
  $hub->{port}[$pos]       = $v;
}


sub addNode {
  my($host, $Topo, $from, $from_port, $st_type, $current_st, $st_port) = @_;
  my $renv = System->get_renv();
  my($current_hub);
  my $a1 = $from->{port}[$from_port];
  $from->{port}[$from_port]    = TO->nodeName($current_st) . ":$st_port";
  $current_st->{port}[$st_port] = TO->nodeName($from) . ":$from_port";
}





sub addNodeNU {
  my($host, $Topo, $from, $from_port, $st_type, $current_st, $st_port) = @_;
  my $renv = System->get_renv();
  my($current_hub);
  my $a1 = $from->{port}[$from_port];

  if (($renv->{use_hub} == 1) && $a1 && ($a1 ne TO->nodeName($current_st) . ":$st_port") && ($a1 !~ /switch/) ) {
      my(@a11) = split(/:/, $a1);
      my($h) = $Topo->nodeByName("$a11[0]:$a11[1]");
      if ($a11[0] eq "hub") { # already a hub, use it
          my($no) =  $h->{port};
          $no = $#$no + 1;
          $h->{port}[$no] =  "$st_type:" . TO->nodeName($current_st) . ":$st_port";
          $current_st->{port}[$st_port] = "hub:$a11[1]:$no";
      } else {              # create a hub.
          $current_hub = TO::HUB->new($Topo, $host, $from, $from_port);
          $from->{port}[$from_port]    = TO->nodeName($current_hub) . ":0";
          $current_hub->{port}[0]       = TO->nodeName($from) . ":$from_port";

          $current_hub->{port}[1]       = $a1;
          $h->{port}[$a11[2]]           = TO->nodeName($current_hub) . ":1";

          $current_hub->{port}[2]       = TO->nodeName($current_st) . ":$st_port";
          $current_st->{port}[$st_port] = TO->nodeName($current_hub) . ":2";
      }
  } else {
      $from->{port}[$from_port]    = TO->nodeName($current_st) . ":$st_port";
      $current_st->{port}[$st_port] = TO->nodeName($from) . ":$from_port";
  }
}


# applies to DISCMAN

sub storageType {
  my($class, $dinfo) = @_;
  if ($dinfo->{LGroup} =~ /VELUN/) {
     return 've';
  } elsif ($dinfo->{LGroup} =~ /Tapes/) {
     return 'tape';
  } elsif ($dinfo->{LGroup} =~ /A5/) {
     return 'a5k';
  } elsif ($dinfo->{LGroup} =~ /\-T3\-/) {
     return 't3';
  } elsif ($dinfo->{LGroup} =~ /\-6120\-/) {
     return '6120';
  } elsif ($dinfo->{LGroup} =~ /\-Daktari\-/) {
     return 'v880disk';
  } elsif ($dinfo->{LGroup} =~ /\-Internal\-/) {
     return 'internal';
  } elsif ($dinfo->{LGroup} =~ /\-A35/) {
     return 'a3500fc';
  } elsif ($dinfo->{LGroup} =~ /\-3510/) {
     return '3510';
  } elsif ($dinfo->{LGroup} =~ /\-3511/) {
     return '3511';
  } elsif ($dinfo->{LGroup} =~ /\-3120/) {
     return '3120jbod';
  } elsif ($dinfo->{LGroup} =~ /\-3310D/) {
     return '3310jbod';
  } elsif ($dinfo->{LGroup} =~ /\-3310/) {
     return '3310';
  } elsif ($dinfo->{LGroup} =~ /\-3320/) {
     return '3320';
  } elsif ($dinfo->{LGroup} =~ /HITACHI/) {
     return '9900';
  } elsif ($dinfo->{LGroup} =~ /LSI/) {
     return '6130';
  } elsif ($dinfo->{LGroup} =~ /PSX1/ || $dinfo->{LGroup} =~ /SE6920/) {
     return 'dsp';
  } else {
     return 'x';
  }
}

# new means first device of this enclusure or 
# for A5K, new is for each ses device.

sub newObj {
  my($type, $class, $name, $host, $hba, $dinfo, $dev) = @_;

  my($obj) = {};
  $obj->{"_hba" . $hba} = 1;
  $obj->{info}{type} = $type;
  $obj->{info}{class} = "storage.$type";
  $obj->{info}{ipAddr} = $dinfo->{ipAddr} if ($dinfo->{ipAddr});
  $obj->{info}{name} = $name;
  $obj->{info}{BoxName} = $dinfo->{BoxName};
  $obj->{info}{host} = $host;
  $obj->{info}{host_type} = "ib";
  $obj->{info}{PortWWN} = $dinfo->{PortWWN};
  $obj->{info}{userLabel} = $dev->{userLabel};
  $obj->{info}{mgmtLevel} = $dev->{mgmtLevel};

  $obj->{info}{NodeWWN} = $dinfo->{NodeWWN};
  $obj->{info}{LogicalPath} = $dinfo->{LogicalPath};
  $obj->{info}{LGroup} = $dinfo->{LGroup};
  $obj->{info}{VendorID} = $dinfo->{VendorID};

  my($p) =  $dinfo->{LGroup};
  my(@a) = split(/[\-\(]/, $p); 
  $p = substr($a[1],0,-1) + 0;
  $obj->{info}{sesCount} = $p;

  bless($obj, $class);
  return $obj;
}

sub setError {
  my($class, $to, $cat, $cat2, $error) = @_;

  $to->[6]{$cat}{$cat2} = $error . " ";
}

sub addError {
  my($class, $to, $cat, $cat2, $error) = @_;
  if (!$DONE{"$cat$cat2$error"}) {
     $to->[6]{$cat}{$cat2} .= $error . "<br> ";
     $DONE{"$cat$cat2$error"} = 1;
  }
}
  
sub find_port {
  my($ix, $hba_path) = @_;
  my($port, $new);
  if (exists($ix->{portInfo}[0]{hba_path}) &&
             $ix->{portInfo}[0]{hba_path} eq $hba_path) {
     $port = 0;
  } elsif (exists($ix->{portInfo}[1]{hba_path}) &&
                  $ix->{portInfo}[1]{hba_path} eq $hba_path) {
     $port = 1;
  } elsif ($ix->{portInfo}[0]{hba_path}) {
     $port = 1; $new = 1;
  } else {
     $port = 0; $new = 1;
  }
  return ($port, $new);
}



use vars qw(%TMP);
use vars qw(%T3MAP);

sub newStorage {
  my($class, $ST, $Topo, $host, $dinfo, $hba, $hba_path, $incomplete, $attached,
     $next_dinfo) = @_;
  my($size, $port, $ix, $key, $ci, $dev);
  my($name, $name2, $new_p, $obj);
  my $Config    = PDM::ConfigFile->read();
  my $storages  = $Topo->[2];
  my $switches  = $Topo->[1];
  my($syns)     = $Topo->[4];
  my($renv)     = System->get_renv();
  my $LB = Labels->read("discman");


  my($type) = $class->storageType($dinfo);
  my $new = 0;
  if ($type eq "ve") { 
     # adding a vicom in the switch array.
     $key = "29" . substr($dinfo->{PortWWN},2);
     my $vdev = $Config->deviceByKey("29" . substr($dinfo->{PortWWN},2));
     if (!$vdev) {
        if ($renv->{show_monitored_only} eq "Y") {
           $class->addError($Topo, "ve", "error", 
           $LB->expand(not_monitored => "ve", $dinfo->{PortWWN}));
           return (0, 0, 've',0);
        }
        $vdev = { key   => $key, wwn => $key, 
                  name  => $dinfo->{ProductID} . "." . substr($dinfo->{PortWWN}, -4),
                  type  => "ve",
                  class => "switch.ve" 
                };
     }

     ($new, $obj) = TO::VE->newFromDev($Topo, $host,  $vdev, "ib");
     $ix = $obj;

     $obj->{volInfo}{$dinfo->{LogicalPath}} = {
                        PortWWN => $dinfo->{PortWWN},
                        NodeWWN => $dinfo->{NodeWWN},
                        Revision => $dinfo->{Revision},
                        PortMode => $dinfo->{PortMode},
                        Capacity => $dinfo->{Capacity},
                        PhysPath => $dinfo->{PhysPath},
      };
     $port = (substr($dinfo->{PortWWN},0,2) eq "2b") ? 1:2;

     return ($new, $port, $type,$ix);

# --------------------------------
  } elsif (index(",3310,3320,3310jbod,3510,3511,3120jbod,", ",$type,") >= 0) {
     if (index(",3310,3320,3310jbod,3120jbod,", ",$type,") >= 0) {
         my $fixkey = "SUN." . $type . "." . lc($dinfo->{NodeWWN});
        ($dev) = $Config->deviceByKey($fixkey, undef, 1);
	$port = 0;
     }else{
        #3510, 3511
	($dev, $port) = $Config->deviceByWWN($dinfo->{NodeWWN}, undef, 1);
     }
     if (!$dev) {
	if ($renv->{show_monitored_only} eq "Y") {
          $class->setError($Topo, $type, $dinfo->{PortWWN}, 
           $LB->expand(not_monitored => $type, $dinfo->{PortWWN}));
          return (0, 0, $type,0);
        }
        my $sn  = lc($dinfo->{NodeWWN});
        $name = "$type:$sn";
        $dinfo->{BoxName} = $sn;
        $incomplete->{flag} = 1;
        if (!$TMP{$sn}) {
          $incomplete->{err} .= $LB->expand(cannot_id => $type, $sn) . "\n";
          $TMP{$sn} = 1;
        }
     } else {
        $name = "$type:$dev->{key}";
        $dinfo->{BoxName} = $dev->{name};
     }
     if ( !defined($storages->{$name})) {
        $obj = &newObj($type, uc("TO::$type"), $name, $host, $hba, $dinfo);
        $storages->{$name} = $obj;
        $obj->{info}{ProductID} = $dinfo->{ProductID};
        $new = 1;
     }	 
     $ix = $storages->{$name};
     if (index(",3310,3320,3310jbod,3120jbod,", ",$type,") >= 0 && !$ix->{port}[0]){
	$ix->{portInfo}[0] = { PortWWN => $name, portType => 'scsi' };
     }
     if (index(",3310,3320,3310jbod,3120jbod,", ",$type,") >= 0){
       $port = 0;
     }else{
        $port = substr($dinfo->{PortWWN},1,1)  - 1;
     }
     if($port < 0){
       $port = 0;
     }
     if (!exists($ix->{portInfo}[$port]{hba_path}) ) {
       $syns->{$dinfo->{PortWWN}} = "$name:$port";
       $ix->{portInfo}[$port] = $dinfo;
       $ix->{portInfo}[$port]{hba_path} = $hba_path; # store hba-path to the port
       $ix->{portInfo}[$port]{dataHost} = $host;
     } else {
       $ix->{portInfo}[$port]{LogicalPath} .= "|" . $dinfo->{LogicalPath};
     }
     if (index(",3511,", ",$type,") >= 0){
        $ix->{info}{port_cnt} = 6;
     }
     return ($new, $port, $type,$ix);
# --------------------------------
  } elsif (index(",6130,", ",$type,") >= 0) {
    ($dev, $port) = $Config->deviceByWWN(uc($dinfo->{NodeWWN}), undef, 0);
    if (!$dev) {
	if ($renv->{show_monitored_only} eq "Y") {
          $class->setError($Topo, $type, $dinfo->{PortWWN}, 
           $LB->expand(not_monitored => $type, $dinfo->{PortWWN}));
          return (0, 0, $type,0);
        }
        my $sn  = lc($dinfo->{NodeWWN});
        $name = "$type:$sn";
        $dinfo->{BoxName} = $sn;
        $incomplete->{flag} = 1;
        if (!$TMP{$sn}) {
          $incomplete->{err} .= $LB->expand(cannot_id => $type, $sn) . "\n";
          $TMP{$sn} = 1;
        }
     } else {
        $name = "$type:$dev->{key}";
        $dinfo->{BoxName} = $dev->{name};
     }
     if ( !defined($storages->{$name})) {
        $obj = &newObj($type, uc("TO::$type"), $name, $host, $hba, $dinfo);
        $storages->{$name} = $obj;
        $obj->{info}{ProductID} = $dinfo->{ProductID};
        $new = 1;
     }	 
     $ix = $storages->{$name};
     # Find  port
     # byte 6 = even, Controller A
     # byte 6 = odd, Controller B
     # byte 0 = ethernet MAC + 1, Port 0
     # byte 0 = ethernet MAC + 2, Port 1
     # ethernet MAC is NODE WWN
     my $endnumN = substr($dinfo->{NodeWWN},10);
     my $endnumP = substr($dinfo->{PortWWN},10);
     
     $port = hex($endnumP) - hex($endnumN);
     #Find controller
     if(substr($dinfo->{NodeWWN},2,2) eq substr($dinfo->{PortWWN},2,2) ){
       #Controller A
     }else{
       #Controller B
       $port += 2;
     }
     $port = $port - 1;
     if(($port < 0) || ($port >4)){
       $port = 0;
     }
     if (!exists($ix->{portInfo}[$port]{hba_path}) ) {
       $syns->{$dinfo->{PortWWN}} = "$name:$port";
       $ix->{portInfo}[$port] = $dinfo;
       $ix->{portInfo}[$port]{hba_path} = $hba_path; # store hba-path to the port
       $ix->{portInfo}[$port]{dataHost} = $host;
     } else {
       $ix->{portInfo}[$port]{LogicalPath} .= "|" . $dinfo->{LogicalPath};
     }

     $ix->{info}{port_cnt} = 4;
     return ($new, $port, $type,$ix);


# -----------------------------
    } elsif ($type eq "9900") {

     my $sn = hex(substr($dinfo->{SerialNo},4,-4)) if (length($dinfo->{SerialNo}) > 4);
     ($dev, $port) = $Config->deviceByWWN($sn) if ($sn);

     if (!$dev) {
       $sn = $dinfo->{SerialNo};
       ($dev, $port) = $Config->deviceByWWN($sn);
     }

     if (!$dev) {
	if ($renv->{show_monitored_only} eq "Y") {
          $class->setError($Topo, $type, $dinfo->{PortWWN}, 
           $LB->expand(not_monitored => $type, $dinfo->{PortWWN}));
          return (0, 0, $type,0);
        }
        $name = "9900:$sn";
        $dinfo->{BoxName} = $sn;
        $incomplete->{flag} = 1;
        if (!$TMP{$sn}) {
          $incomplete->{err} .= $LB->expand(cannot_id => "9900", $sn) . "\n";
          $TMP{$sn} = 1;
        }
     } else {
        $name = "9900:$dev->{key}";
        $dinfo->{BoxName} = $dev->{name};
     }

     if ( !defined($storages->{$name})) {
        $dinfo->{LGroup} = "hds9900";
        $obj = &newObj($type, "TO::9900", $name, $host, $hba, $dinfo);
        $storages->{$name} = $obj;
        $new = 1;
     }
     $ix = $storages->{$name};

     $port = &find_port2($ix, $dinfo->{PortWWN});  # find port based on PortWWN

     $syns->{$dinfo->{PortWWN}} = "$name:$port";
     $ix->{portInfo}[$port] = $dinfo;
     $ix->{portInfo}[$port]{hba_path} = $hba_path; # store hba-path to the port
     $ix->{portInfo}[$port]{dataHost} = $host;

     return ($new, $port, $type,$ix);


# --------------------------- 
  } elsif ($type eq "a3500fc") {
     ($dev, $port) = $Config->deviceByWWN($dinfo->{SerialNo});

     if (!$dev) {
        if (!$dev && ($renv->{show_monitored_only} eq "Y") ) {
          $class->addError($Topo, $type, "error", $LB->expand(not_monitored => $type, $name));
          return (0, 0, $type,0);
        }
        my $sn  = $dinfo->{SerialNo};
        $name = "a3500fc:$sn";
        $dinfo->{BoxName} = $sn;
        $incomplete->{flag} = 1;
        if (!$TMP{$sn}) {
          $incomplete->{err} .= $LB->expand(cannot_id => "A3500FC", $sn) . "\n";
          $TMP{$sn} = 1;
        }
     } else {
        $name = "a3500fc:$dev->{key}";
        $dinfo->{BoxName} = $dev->{name};
     }

     if ( !defined($storages->{$name})) {
        $obj = &newObj($type, "TO::A3500FC", $name, $host, $hba, $dinfo);
        $storages->{$name} = $obj;
        $new = 1;
     }
     $ix = $storages->{$name};

     ($port, $new_p) = &find_port($ix, $hba_path);

     if ($new_p) {
       $syns->{$dinfo->{PortWWN}} = "$name:$port";
       $ix->{portInfo}[$port] = $dinfo;
       $ix->{portInfo}[$port]{hba_path} = $hba_path; # store hba-path to the port
       $ix->{portInfo}[$port]{dataHost} = $host;
     } else {
       $ix->{portInfo}[$port]{LogicalPath} .= "|" . $dinfo->{LogicalPath};
     }
  
     return ($new, $port, $type,$ix);

# --------------------------------
# this will find a dsp standalone or in a rack.
#
  }  elsif ($type eq "dsp") {
     # adding a dsp in the switch array.
     $key = $dinfo->{NodeWWN};
     my $port_done;
     my ($vdev, $port) = $Config->deviceByWWN($dinfo->{PortWWN}, undef, 1); # use wwns
     if (!$vdev) {
        if ($renv->{show_monitored_only} eq "Y") {
           $class->addError($Topo, "dsp", "error",
           $LB->expand(not_monitored => "dsp", $dinfo->{PortWWN}));
           return (0, 0, 'dsp',0);
        }
        $vdev =  {  key => $key, wwn => $key,
                   name => $dinfo->{NodeWWN},
                   type => "dsp", 
                  class => "storage.dsp" };
        $name = "dsp:$key";
     } else {
        $port_done = 1;
        $key  = $vdev->{key};
        $name = "$vdev->{type}:$key";
        $type = $vdev->{type};
     }
     my $ss = $type eq "dsp" ? $switches : $storages;

     if (!defined($ss->{$name})) {
       $syns->{$key} = "$type:$key";
       $syns->{$dinfo->{PortWWN}} = "$type:$key:$port";
       $obj = &newObj($type, "TO::" . uc($type), $name, $host, $hba, $dinfo, $dev);
       $obj->{info}{ProductID}  = $vdev->{model} || $dinfo->{ProductID};
       $obj->{info}{BoxName}    = $vdev->{name};
       $ss->{$name} = $obj;

       $new = 1;
     }
     $ix = $ss->{$name};
     $port = &find_port2($ix, $dinfo->{PortWWN}) if (!$port_done);

     $ix->{portInfo}[$port] = $dinfo;
     $ix->{portInfo}[$port]{Slot} = "m" . substr($dinfo->{PortWWN},2,1) . "p" . 
                                          substr($dinfo->{PortWWN},3,1);
     $ix->{portInfo}[$port]{hba_path} = $hba_path; # store hba-path to the port
     $ix->{portInfo}[$port]{dataHost} = $host;
     $obj->{volInfo}{$dinfo->{LogicalPath}} = {
                        PortWWN => $dinfo->{PortWWN},
                        NodeWWN => $dinfo->{NodeWWN},
                        SerialNo => $dinfo->{SerialNo},
                        Revision => $dinfo->{Revision},
                        PortMode => $dinfo->{PortMode},
                        Capacity => $dinfo->{Capacity},
                        PhysPath => $dinfo->{PhysPath},
     };
     return ($new, $port, $type,$ix);


# --------------------------- 
  } elsif ($type eq "t3" || $type eq "6120" ) {
     ($dev, $port) = $Config->deviceByWWN($dinfo->{PortWWN});
     $key = $dev->{key};
     $syns->{$dinfo->{PortWWN}} = "$type:$key:$port";
     $dinfo->{BoxName} = $dev->{name} || $dev->{ipno};
     $dinfo->{ipAddr}  = $dev->{ipno};

     if (!$key) {
       if ($renv->{show_monitored_only} eq "Y") {
          $class->setError($Topo, $type, $dinfo->{PortWWN}, 
           $LB->expand(not_monitored => $type, $dinfo->{PortWWN}));
          return (0, 0, $type,0);
       }
       $incomplete->{flag} = 1;
       my $pwwn = $dinfo->{PortWWN};
       my $nwwn = $dinfo->{NodeWWN};
       my $short_pwwn = substr($dinfo->{PortWWN}, -8);
       my $short_nwwn = substr($dinfo->{NodeWWN}, -8);
       my $k = $T3MAP{$short_pwwn} || $T3MAP{$short_nwwn};
       if ($k) {
          $name = "$type:$k";
          $T3MAP{$short_pwwn} = $k;
          $T3MAP{$short_nwwn} = $k;
          if (exists $T3MAP{"$pwwn-$hba"}) {
            $port = $T3MAP{"$pwwn-$hba"};
          } else {  
            $port = $T3MAP{"$pwwn-$hba"} = 1;
          }
       } else {
          $name = "$type:$pwwn";
          $T3MAP{$short_pwwn} = $pwwn;
          $T3MAP{$short_nwwn} = $pwwn;
          $port = $T3MAP{"$pwwn-$hba"} = 0;
          $incomplete->{err} .= $LB->expand(cannot_id => "T3", $pwwn) . "\n";
       }
       $syns->{$dinfo->{PortWWN}} = "$name:$port";

     } else {
       $name = "$type:$key";
     }

     if ( !defined($storages->{$name})) {
       $syns->{$key} = "$type:$key";
       $obj = &newObj($type, "TO::" . uc($type), $name, $host, $hba, $dinfo, $dev);
       $storages->{$name} = $obj;
       $new = 1;
     }
     $ix = $storages->{$name};

     if (index($ix->{info}{vols}, "$dinfo->{SerialNo},")  < 0) {
       $ix->{info}{vols} .= "$dinfo->{SerialNo},";
     }
     $ix->{info}{PG} = 1 if ($port == 1);
     #if (! $ix->{portInfo}[$port]) {
        $ix->{portInfo}[$port] = $dinfo;
        $ix->{portInfo}[$port]{hba_path} = $hba_path; # store hba-path to the port
        $ix->{portInfo}[$port]{PortLabel} = "ctrl-" . ($port+1);
        $ix->{portInfo}[$port]{dataHost} = $host;
     #}
     return ($new, $port, $type,$ix);

# --------------------------- 
  } elsif ($type eq "internal") {  # Internal
     $key =  $host;
     $name = "internal:ID$key";
     my $ras_key = "ID$key";
     my $dev = $Config->deviceByKey($ras_key);
     if (!$dev && ($renv->{show_monitored_only} eq "Y") ) {
          $class->addError($Topo, $type, "error", $LB->expand(not_monitored => $type, $name));
          return (0, 0, $type,0);
     }
     if ( !defined($storages->{$name})) {
       $syns->{$key} = "internal:$key";
       $obj = &newObj($type, "TO::INTERNAL", $name, $host, $hba, $dinfo);
       $storages->{$name} = $obj;
       $syns->{$dinfo->{PortWWN}} = "$type:$key:$port";
       $new = 1;
     }
     $ix = $storages->{$name};

     my $ports = $ix->{portInfo};
     my $found = 0; my($p);
     for ($p=0; $p <= $#$ports; $p++) {
        if (exists $ports->[$p]{hba_no}  && $ports->[$p]{hba_no} == $hba) {
            $port = $p; $found = 1; last;
        }
     }
     $port = $#$ports+1 if (!$found);
     if (!exists $ix->{portInfo}[$port]{hba_no}) {
       $ix->{portInfo}[$port] = { 
           PortWWN      => $dinfo->{PortWWN},
           NodeWWN      => $dinfo->{NodeWWN},
           RegisterName => $dinfo->{RegisterName},
           LogicalPath  => $dinfo->{LogicalPath},
           PhysPath     => $dinfo->{PhysPath},
           LGroup       => $dinfo->{LGroup},
           hba_no       => $hba,
           dataHost     => $host,
           };
     }

     my $disk = $dinfo->{RegisterName};
     $ix->{diskInfo}{$disk} = {
           PortWWN      => $dinfo->{PortWWN},
           NodeWWN      => $dinfo->{NodeWWN},
           RegisterName => $dinfo->{RegisterName},
           LogicalPath  => $dinfo->{LogicalPath},
           PhysPath     => $dinfo->{PhysPath},
           LGroup       => $dinfo->{LGroup},
           Revision     => $dinfo->{Revision},
           VendorID     => $dinfo->{VendorID},
           ProductID    => $dinfo->{ProductID},
           SerialNo     => $dinfo->{SerialNo},
           };
     return ($new, $port, $type,$ix);

# --------------------------- 
  } elsif ($type eq "tape") {
     $key = $dinfo->{NodeWWN};
     $name = "tape:$key";

     if ( !defined($storages->{$name})) {
       my $dev = $Config->deviceByKey($key);
       if (!$dev && $renv->{show_monitored_only} eq "Y") {
           $class->addError($Topo, "tape", "error", 
                        $LB->expand(not_monitored => "tape", $storages->{$name}));
           return (0, 0, 'tape',0);
       }
       $syns->{$key} = "tape:$key";
       $obj = &newObj($type, "TO::TAPE", $name, $host, $hba, $dinfo);
       $storages->{$name} = $obj;
       $new = 1;
     }
     $port = 0;
     $syns->{$dinfo->{PortWWN}} = "$type:$key:$port";
     $ix = $storages->{$name};
     $ix->{portInfo}[$port] = $dinfo;
     $ix->{portInfo}[$port]{dataHost} = $host;

     return ($new, $port, $type,$ix);

#-----------------------------
  } elsif ($type eq "v880disk" || $type eq "a5k" ) {
     if ($dinfo->{LogicalPath} =~ /\/ses/) {
         $ST->{$dinfo->{BoxName}} = $dinfo->{NodeWWN};
     }
     $key = $ST->{$dinfo->{BoxName}};
     $name = "$type:$key";
     my $dev = $Config->deviceByKey($key);
     if (!$dev && ($renv->{show_monitored_only} eq "Y") ) {
          
          $class->addError($Topo, $type, "error", $LB->expand(not_monitored => $type, $name));
          return (0, 0, $type,0);
     }
     $name2= $type . ":" . $dinfo->{BoxName} if ($dinfo->{BoxName});

     if ( !defined($storages->{$name})) {
       $syns->{$key} = "$type:$key";
       $obj = &newObj($type, "TO::" . uc($type), $name, $host, $hba, $dinfo);
       if ($dev) {
         require Agent::A5K;
         my $gb = Agent::A5K->getGbicStatus($dev);
         my $gbic_map;
         foreach my $el ('A.gbic0','B.gbic0','A.gbic1','B.gbic1') {
            $gbic_map .= ($gb->{"interface_board.$el.status"} =~ /Not Ins/) ? -1 : 0;
            $gbic_map .= ",";
         }
         $obj->{info}{gbic_map} = $gbic_map;
       }
       $storages->{$name} = $obj;
       $new = 1;
     }
     $ix = $storages->{$name};

     if ($dinfo->{RegisterName} =~ /\-ses(\d+)/) {
       if ($dinfo->{"Connected on"}) {
         my $p = $dinfo->{"Connected on"};
         $port = (substr($p,0,1) eq "A") ? 0:1;
         $port += 2 if (substr($p,1,1) eq "1");

       } else {
         my($p) = $next_dinfo->{PortWWN};
         if ($p) {
            $port = (substr($p,0,2) eq "21") ? 0:1;
         } else {
            $port = index("129a", substr($dinfo->{PortWWN},-1)) >= 0 ? 0:1;
         }

       }
       $syns->{$dinfo->{PortWWN}} = "$type:$key:$port";

       if ($ix->{info}{"ses_cnt$hba"} == 0) {   # first ses
         $ix->{portInfo}[$port] = $dinfo;
         $ix->{portInfo}[$port]{hba_path} = $hba_path; # store hba-path to the port
         $ix->{portInfo}[$port]{dataHost} = $host;
       } else {
         $ix->{portInfo}[$port]{LogicalPath}  .= "|" .$dinfo->{LogicalPath};
       }
      
       # accumulate logical
     }
     return ($new, $port, $type,$ix);
  }
}

sub find_port2 {
  my($node, $portWWN) = @_;
  
  my $pi = $node->{portInfo};
  my($x);
  for ($x=0; $x <= $#$pi; $x++) {
     my $p = $pi->[$x];
     if ($p->{PortWWN} eq $portWWN  || ($p->{LocalPortWWN} eq $portWWN)) {
        return $x;
     }
  }
  return $#$pi+1;
}

1;
