package Health::DSP;
#<copyright>
# ----------------------------------------------------------
# Copyright 2001, Sun Microsystems, Inc. All rights reserved.
# ----------------------------------------------------------
#</copyright>

#  $Name: bld21_017 $ 
#  $Id: DSP.pm,v 1.28 2005/05/16 16:23:44 edunning Exp $


use base 'Health';
use NWS::DSP;
use Ilist;
use Message;
use Report;
use Catalog;
use Events;
use strict;
use Debug;

sub revision {'$Revision: 1.28 $'}

#
#  ADD module revision event for I/O card
#  volume add/remov 
#  disks add/remove
#


sub all_logic {
  my($hm, $report) = @_;
  my($ev, $ed, $pertains, $x ,$y, $contain, $sd);
  my($orep, $key);
  my $rep      = $report->content;
  my $oreport  = PDM->getOldReport($report->fileKey);
  my $ip       = $report->id('ip');
  my $name     = $report->name;
  my $wwn      = $report->id('deviceName');
  my $id       = $report->id('display');
  my $type     = $report->category();

  my $mgmtLevel = $report->value('id.mgmtLevel') || 'D';
  if (!$wwn) {
    Debug->errNoRepeat(T3_NO_KEY => $ip, 24, "DSP ($name/$ip) cannot be identified");
     return;
  }

  CIM->version("1.1");
  $DB::single = 1;

  return if ($hm->connectionEvent($wwn, $report, {method => 2, threshold_severity => 0} ));
  my $freq  = System->get_renv()->{audit_freq} || 7;
  my $audit = System->get_audit() ? "YES" : Timer->isXdays("Audit$wwn", $freq);

  if (!$oreport || $audit eq "YES" ) {  

     my($etype) = $audit eq "YES" ? "$type.AuditEvent" : "$type.DiscoveryEvent";
     my($title) = $audit eq "YES" ? "Auditing a":"Discovered a new";
     my($dt)    = "A" if (!$audit);
     Grid->setCode($etype);
     $ev = CIM::Instance->new('NWS_Event', [
                  [ EventType   => $etype ],
                  [ EventId     => PDM->getEventSequence  ],
                  [ Target      => "$type:$wwn" ],
                  [ TargetName  => $id],
                  [ SourceIP    => $ip  ],
                  [ MgmtLevel   => $mgmtLevel],
                  [ Description => "$title DSP called $id"],
                  [ Data        => $hm->serial($rep) ],
                         ]);

     $sd = Events->sourceDetector({ event => $ev , host => 1, rep => $rep});
      
     my($p) = NWS::DSP->newSystem($rep);

     $pertains = CIM::Instance->new('NWS_EventPertainsToSystem', [
                  [ Event       => $ev  ],
                  [ Element     => $p->[0] ],
                  [ DiscoveryType => $dt],
                    ]);

     my($monitors) = CIM::Instance->new('NWS_AgentMonitors', [
                  [ Agent       => $sd->[0]  ],
                  [ Element     => $p->[0] ],
                    ]);

     $ed = Message->new( { id        => $report->id,
                            instances => [$ev, @$sd,  @$p, $monitors, $pertains ],
                            severity  => Message::SEVERITY_NORMAL });

     PDM->saveMessage($ed);
  }

  $orep = ($oreport)? $oreport->content() : $rep;

  foreach my $el ('1', '2') {
      Grid->setCode("$type.AlarmEvent.chassis.power");
      my $module=$report->value("psu.$el.Label");
      $hm->mapValueChangeEvent($report, $orep, "DSP", "psu.$el", "PsuState", $id, " Power Module $module",  $wwn, "powerState");
  }

  Grid->setCode("$type.AlarmEvent.chassis.fan");
  $hm->mapValueChangeEvent($report, $orep, "dsp", "fantray", "FanState", $id, $id, $wwn, "fantray");

  $hm->locationChangeEvent($report, $rep, $orep, $wwn);

  my($physicalFrame) = CIM::Key->new( ['CIM_PhysicalFrame',   # key of the frame
                        Tag               => $rep->get("id.wwn") ,
                        CreationClassName => 'CIM_PhysicalFrame' ]);

  if (exists $rep->{FC_COUNTERS}) {
    $hm->fcEvent($rep->{FC_COUNTERS}, $orep->{FC_COUNTERS});
  }


################
# PORTS

  my($comp, $m, $p);
  for ($m=1; $m <= 10; $m++) {
     for ($p=1; $p <= 16; $p++) {
       my $x = "m${m}p$p";
       if($rep->{"etherPort.$x.PortType"}){
         $comp = "etherPort.$x";
       }else{
         $comp = "fibrePort.$x";
       }

       my $slot = "RearModule$m,port$p";

       my $loop_count =  $rep->{"$comp.LoopResetEvents"};
       my $old_count  = $orep->{"$comp.LoopResetEvents"};
       if ($old_count && $loop_count > $old_count) {
          my $inc = $loop_count - $old_count;
          my($level, $cnt, $desc, $mins) = Thresholds->test("dsp", "loop_reset", "$wwn.$x", $inc);
          if ($level eq "W") {
             my $desc = "$comp: Received $cnt Loop Resets in $mins min(s)";
             Grid->setCode("dsp.AlarmEvent.loop_reset");
             $hm->valueChangeEvent($comp,"" , $report, $wwn, $desc, 1, "loop_reset");
          }
       }

       Grid->setCode("$type.StateChangeEvent.port");
       my $act = $orep->{"$comp.RemoteProduct"} =~ /^T[34]/ ? 1:0;

       $hm->stateChangeEvent($comp, 'port_status', $report, $rep, $orep, 'CIM_Card', "$wwn.$comp", $wwn, 
              {       info => "hardwareState=". $rep->{"$comp.HardwareState"}, 
                 comp_info => $slot ,
                  noAction => !$act,
               });
       my $proto = $rep->get("$comp.ProtocolOperational");
       my $oproto = $rep->get("$comp.ProtocolOperational");
       if ($proto ne $oproto) {
          my $sev = $proto =~ /Loop/ ? 1:0;
          Grid->setCode("$type.StateChangeEvent.eport");
          $hm->valueChangeEvent($comp, "", $report, $wwn,
           "Protocol of $slot on $id changed from '$oproto' to '$proto'", $sev, "protocol");
       }
       if($comp =~ /ether/){ #make a state change for the gig-e port
         Grid->setCode("$type.StateChangeEvent.eport");
         $hm->stateChangeEvent($comp, 'HardwareState_status', $report, $rep, 
                               $orep, 'CIM_Card', "$wwn.$comp", $wwn, 
                               { info => "Ethernet Port Hardware State=". 
                                 $rep->{"$comp.HardwareState"}, 
                                 comp_info => $slot 
                               });
       }
       ### iterate through ISCSI LINKS
       for(my $i=1; $i<= $rep->get("$comp.PeerLinkISCSI.total"); $i++){
         my $remoteIP=$rep->get("$comp.PeerLinkISCSI.$i.PeerLinkISCSIRemoteIP")
              ||     $orep->get("$comp.PeerLinkISCSI.$i.PeerLinkISCSIRemoteIP");
         my $des = $rep->get("$comp.PeerLinkISCSI.$i.PeerLinkISCSIDescription")
              ||  $orep->get("$comp.PeerLinkISCSI.$i.PeerLinkISCSIDescription");
         my $linkstate=$rep->get("$comp.PeerLinkISCSI.$i.PeerLinkISCSIState");
         Grid->setCode("$type.ValueChangeEvent.link");
         $hm->mapValueChangeEvent($report, $orep,"DSP", "$comp.PeerLinkISCSI.$i",
                         "PeerLinkISCSIState", $name, $id, $wwn, "PeerLinkISCSIState", 
                                 { info => "ISCSI link state to $remoteIP=$linkstate, Ethernet Port Hardware State=". 
					    $rep->{"$comp.HardwareState"}.  
					    ", Link Description=$des" , comp_info => $slot });

       }
     }
   }

################
# MODULES
################

  my($comp, $m, $p, $info);
  for ($p=1; $p <= 10; $p++) {
    my $comp = "MIC.Rear$p";
    if ($rep->{"$comp.State"} eq "Normal") {
      $info = "Master is $comp";
    }
  }

  foreach my $module (Agent::DSP->module_list()) {
    foreach my $side ('Front','Rear') {
       for ($p=1; $p <= 10; $p++) {
         my $x = "$side$p";
         $comp = "$module.$x";
         my $serial  = NWS::DSP->moduleKey($rep, $comp);
         my $oserial = NWS::DSP->moduleKey($orep, $comp);
         my $state  = $rep->{"$comp.State"};
         my $ostate = $orep->{"$comp.State"};
	   
         my $partnum  = $rep->{"$comp.PartNumber"};
         my $opartnum  = $orep->{"$comp.PartNumber"};
         my $serial0 = $rep->{"$comp.SerialNumber"};
         my $oserial0 = $orep->{"$comp.SerialNumber"};

         if ($state && $ostate && $serial0 eq $oserial0){#both states are pre
           if (!$partnum && $opartnum) {  # EEPROM forgot partnum
             Grid->setCode("$type.ValueChangeEvent.EEPROM");
             $hm->alarmEvent($comp, "", $report, $wwn,
                             "The $comp has failed to report its part number", 2, "$comp Error");
           }
           Grid->setCode("$type.StateChangeEvent.$module");
           $hm->stateEvent($comp, $report, $rep, $orep, 'CIM_Card', $comp, $wwn,
                  { info => $module eq "MIC" ? $info : "" });

         } else {

	   if ($oserial) {
               Grid->setCode("$type.ComponentRemoveEvent.$module");
               $hm->removeCompEvent($comp,$physicalFrame, $report, $orep, 'CIM_Card',
                    $oserial, $wwn);
           }
           if ($serial || $state) {
             my $mod = NWS::DSP->newModule($rep, $comp);
             next if (!$mod);
             Grid->setCode("$type.ComponentInsertEvent.$module");
             $hm->insertCompEvent($comp, $physicalFrame, $report, $orep, $mod, 
                     $serial, $wwn, { desc => "('$oserial' -> '$serial')" } 
                   );
           }
         }
       }
    }
  }

################
# SERVERS
################

#   'fcserver.2.Description' => 'N/A',
#   'fcserver.2.ElementName' => 'server1',
#   'fcserver.2.instance.1.InstanceName' => 'server1/4/5',
#   'fcserver.2.instance.1.InstanceState' => 'Allocated',
#   'fcserver.2.instance.1.InstanceStatus' => 'Online',
#   'fcserver.2.Status' => 'Online',
#   'fcserver.2.SVSD' => 'DEFAULT',
#   'fcserver.2.Wwn' => '21:00:00:E0:8B:07:7D:2E',
#  compare wwn against wwn

  my($s, $i, $x, %MAP);
  foreach my $el (keys %$orep) {
      if ($el =~ /^fcserver\.(\d+)\.ElementName/) {
         my $no = $1;
         $MAP{$orep->{"fcserver.$no.Wwn"}} = $no;
      }
  }

  for ($x=1; $x <= 2000; $x++) {
     my $comp   = $rep->{"fcserver.$x.ElementName"};
     my $serial = $rep->{"fcserver.$x.Wwn"};
     my $ono    = $MAP{$serial};
     my $ocomp  = $orep->{"fcserver.$ono.ElementName"};
     my $oinfo  = "SIO.RearModule$x";
     
     last if (!$comp && !$ocomp);
     Grid->setCode("$type.AlarmEvent.fcserver");

     if (!$comp) {
        $hm->valueChangeEvent("fcserver.$ocomp", "", $report, $wwn, 
              "fcserver $ocomp($oinfo) was removed from $id", 0, "fcserver.wwn");
        next;
     }
     if (!exists $MAP{$serial}) {
        $hm->valueChangeEvent("fcserver.$comp", "", $report, $wwn, 
              "fcserver $comp($oinfo) was added from $id", 0, "fcserver.wwn");
        next;
     } 
     # BOTH OLD AND NEW PRESENT  
     my $status  =  $rep->{"fcserver.$x.Status"};
     my $ostatus = $orep->{"fcserver.$ono.Status"};
     Grid->setCode("$type.StateChangeEvent.fcserver");
     $hm->mapValueChangeEvent($report, $orep, "DSP", "fcserver.$x", "Status", $name, $id, $wwn, 
                       "serverStatus", 
                   { el_info => $oinfo, old_status => $ostatus });

     my $name  =  $rep->{"fcserver.$x.ElementName"};
     my $oname = $orep->{"fcserver.$ono.ElementName"};
     if ($name ne $oname) {
          Grid->setCode("$type.AlarmEvent.fcserver.name");
          $hm->valueChangeEvent("fcserver.$comp", "", $report, $wwn,
            "The name of fcserver.$x($oinfo) on $id changed from '$oname' to '$name'", 
             0, "fcserver.name");
     }
   
     for ($i=1; $i <= 20; $i++) {
       my $nins_name  = $rep->{"fcserver.$x.instance.$i.InstanceName"};
       my $oins_name  = $orep->{"fcserver.$ono.instance.$i.InstanceName"};
       last if (!$nins_name && !$oins_name);
       my @P = split(/\//,  $nins_name);
       my $ins_port = $P[$#P];
       Grid->setCode("$type.AlarmEvent.fcserverInstance");
       if (!$nins_name) {
          $hm->valueChangeEvent("fcserver.$comp.instance.$i", "", $report, $wwn,
              "Instance $oins_name($oinfo.Port$ins_port) was removed from fcserver '$comp' in $id", 
               0, "fcserver.instance");
       } elsif (!$oins_name) {
          $hm->valueChangeEvent("fcserver.$comp.instance.$i", "", $report, $wwn,
              "Instance $nins_name($oinfo.Port$ins_port) was added to fcserver '$comp' in $id", 
               0, "fcserver.instance");
       } else {
         foreach my $el ('State','Status') {
           my $nins_state = $rep->{"fcserver.$x.instance.$i.Instance$el"};
           my $oins_state = $orep->{"fcserver.$ono.instance.$i.Instance$el"};

           Grid->setCode("$type.AlarmEvent.fcserverInstance." . lc($el));
           $hm->mapValueChangeEvent($report, $orep, "DSP",  "fcserver.$x.instance.$i", 
                               "Instance$el", $name, $id, $wwn, undef, 
                       {el_info    => "$oinfo.Port$ins_port", 
                        old_status => $oins_state,
                        comp_name  => $rep->{"fcserver.$x.instance.$i.InstanceName"},
                       });
         }
       }
     }
  }
  $hm->performance($rep, $orep);

}

#
# PORT PERFORMANCE
#

sub performance {
  my($class, $rep, $orep, $file, $prefix, $clean) = @_;

  my $renv = System->get_renv();

  my $DSP_BLOCK   =   1;  # dsp reports bytes

  return if ($rep eq $orep);
  return if (!exists $orep->{"id.timestamp"});
  my $name = $rep->{'id.device_name'};
  my $time = $rep->{'id.timestamp'} - $orep->{'id.timestamp'};
  return if ($time <= 0);
  my $today = Util->get_today();
  my $jd    = Util->get_today_jd();
  my $hour  = substr($today, 0,13);
  my($x, $u, $v);

  require Perf;
  my ($stat1, $stat3, $currentReplication, $hourlyReplication);
  if ($file) {
    $stat1 = Perf->read($file);
    $stat1->cleanOld($clean) if ($clean);
  } else {
    $stat1 = Perf->read("stat1");
    $stat3 = Perf->read("stat3");
    $stat3->cleanHours();
    $currentReplication= new Perf;
    $hourlyReplication= Perf->read("hourlyReplication");
    $hourlyReplication->cleanHours();
  }
  my $count = "1";
#DSP Replication Stats come in 512 bytes so $rep->{"volume.$v.ReplicationSet.QueueSize"}*512 == QueueSize in bytes
#                                        or $rep->{"volume.$v.ReplicationSet.QueueSize"}*512/1024 == Queue in kilobytes
#                                        or $rep->{"volume.$v.ReplicationSet.QueueSize"}*512/1024/1024 == Queue in megabytes

  my $volumeCount = $rep->{"totals.volume"};
  for ($v=1; $v <= $volumeCount; $v++) {		      
    if($rep->{"volume.$v.Type"}eq"RemoteMirror"){
      print $rep->{"volume.$v.ElementName"}."\n";
      next if(!$rep->{"volume.$v.ElementName"});
      print $rep->{"volume.$v.ElementName"}."\n";
      my $vName=$rep->{"volume.$v.ElementName"};
      my @N;
      $N[1] = $rep->{"volume.$v.ReplicationSet.QueueMaxDepth"}*512/1024/1024;
      $N[2] = $rep->{"volume.$v.ReplicationSet.QueueSize"}*512/1024/1024;

      $currentReplication->{"total.$name.$vName"}[0]    = $time;
      $hourlyReplication->{"$hour.$name.$vName"}[0]    += $time;
      print "$hour.$name.$vName @N\n";
      for ($x=1; $x <= 2; $x++) {
        $currentReplication->{"total.$name.$vName"}[$x] = $N[$x];
        $hourlyReplication->{"$hour.$name.$vName"}[$x] = $N[$x] if($hourlyReplication->{"$hour.$name.$vName"}[$x]<$N[$x]);
      }
      $currentReplication->write("currentReplication");
      $hourlyReplication->write("hourlyReplication");
    }
  }
  my ($skip, $m, $p);
  for ($m=1; $m <= 10; $m++) {		      
     for ($p=1; $p <= 16; $p++) {
        my $k1 = "m${m}p$p";
        my $k = "fibrePort.$k1";  
        if (!exists $rep->{"$k.BytesRead"}){
          $k = "etherPort.$k1";
        }
        next if (!exists $rep->{"$k.BytesRead"});

        my $portOperatingSpeed = $rep->{"$k.FcSpeedOperational"};
        my $portSpeed = 0;
        if ($portOperatingSpeed == "2G") {
           $portSpeed = 0.2; # Due to 8B/10B encoding	
        } elsif ($portOperatingSpeed == "1G") {
           $portSpeed = 0.1; # Due to 8B/10B encoding
        } elsif ($k =~ /^ether/) {
           $portSpeed = 0.125;	#Ethernet has no 8B/10B encoding
        }
        
	my $currentportReadPercentage = 0; 
        my $currentportWritePercentage = 0; 

        my @N;
        my $b1 =  $rep->{"$k.BytesRead"};
        my $b2 = $orep->{"$k.BytesRead"};
        if ($b1 < $b2) {
           $skip = 1; last;
        }
        $N[1] = ($b1 - $b2) * $DSP_BLOCK / 1024 / 1024;

        if ($portSpeed && ($portSpeed ne 0)) {
           my $gbpersec_read  = (($b1 - $b2) / 1024 / 1024 / 1024) / $time;
           $currentportReadPercentage = ($gbpersec_read / $portSpeed) * 100; 
        }

        my $wb1 =  $rep->{"$k.BytesWritten"};
        my $wb2 = $orep->{"$k.BytesWritten"};
        if ($wb1 < $wb2) {
           $skip = 1; last;
        }
        $N[2] =  ($wb1 - $wb2) * $DSP_BLOCK / 1024 / 1024;

        if ($portSpeed && ($portSpeed ne 0)) {
           my $gbpersec_written  = (($wb1 - $wb2) / 1024 / 1024 / 1024) / $time;
           $currentportWritePercentage = ($gbpersec_written / $portSpeed) * 100;
        }

        $N[3] = $rep->{"$k.InvalidCRC"}      - $orep->{"$k.InvalidCRC"};
        $N[4] = $rep->{"$k.LoopDownEvents"}  - $orep->{"$k.LoopDownEvents"};

        $N[5] = $rep->{"$k.ErrorCount"}      - $orep->{"$k.ErrorCount"};
        $N[6] = $rep->{"$k.LossofSynchronization"}  - $orep->{"$k.LossofSynchronization"};

        #IOPS
        if($k =~ /^ether/){
          $N[7] = ($rep->{"$k.PacketsRead"} - $orep->{"$k.PacketsRead"});
          $N[8] = ($rep->{"$k.PacketsWritten"} - $orep->{"$k.PacketsWritten"});
        }else{
          $N[7] = ($rep->{"$k.ReadCommands"} - $orep->{"$k.ReadCommands"});
          $N[8] = ($rep->{"$k.WriteCommands"} - $orep->{"$k.WriteCommands"});
        }

        $N[9]  = $currentportReadPercentage; 
        $N[10] = $currentportWritePercentage;
        $N[11] = $count;

        if ($file) {
          $stat1->{"$prefix.$name.$k1"}[0]    += $time;
          for ($x=1; $x <= 11; $x++) {
             $stat1->{"$prefix.$name.$k1"}[$x] += $N[$x];
          }
        } else {
          $stat1->{"total.$name.$k1"}[0]    = $time;
          $stat3->{"$hour.$name.$k1"}[0]    += $time;
          for ($x=1; $x <= 11; $x++) {
             $stat1->{"total.$name.$k1"}[$x] = $N[$x];
             $stat3->{"$hour.$name.$k1"}[$x] += $N[$x];
          }
        }
     }
     last if ($skip);
  }
  if (!$skip) {
    if ($file) {
      $stat1->write($file);
    } else {
      $stat1->write("stat1");
      $stat3->write("stat3");
    }
  }
}

sub HardwareState_status {
   my($hm, $rep, $orep, $comp) = @_;
   my $type = $rep->{'id.device_type'};
   my $map  = PDM->getDeviceStateMap("$type.availability");

   my($status, $ostatus, $old, $new, $sev, $act, $oready, $ready);

   $ostatus = $orep->getState("$comp.HardwareState");
   $status  = $rep->getState("$comp.HardwareState");
   ($old, $new, $sev, $act) = $map->transition("HardwareState.$ostatus", "HardwareState.$status", $orep, $rep);
   return ($ostatus, $status, $old, $new, $sev, $act );
}

sub port_status {
   my($hm, $rep, $orep, $comp) = @_;
   my $type = $rep->{'id.device_type'};
   my $map  = PDM->getDeviceStateMap("$type.availability");

   my($status, $ostatus, $old, $new, $sev, $act, $oready, $ready);

   $ostatus = $orep->getState("$comp.PortState");
   $status  = $rep->getState("$comp.PortState");
   ($old, $new, $sev, $act) = $map->transition("portState.$ostatus", "portState.$status", $orep, $rep);
   return ($ostatus, $status, $old, $new, $sev, $act );
}

sub link_status {
   my($hm, $rep, $orep, $comp) = @_;
   my $type = $rep->{'id.device_type'};
   my $map  = PDM->getDeviceStateMap("$type.availability");

   my($status, $ostatus, $old, $new, $sev, $act, $oready, $ready);

   $ostatus = $orep->getState("$comp.PeerLinkISCSIState");
   $status  = $rep->getState("$comp.PeerLinkISCSIState");
   ($old, $new, $sev, $act) = $map->transition("linkState.$ostatus", "linkState.  $status", $orep, $rep);
   return ($ostatus, $status, $old, $new, $sev, $act );
}



sub status {
   my($hm, $rep, $orep, $comp) = @_;
   my $type = $rep->{'id.device_type'};
   my $map  = PDM->getDeviceStateMap("$type.availability");

   my($status, $ostatus, $old, $new, $sev, $act, $oready, $ready);

   $ostatus = $orep->getState("$comp.State");
   $status  = $rep->getState("$comp.State");

   $oready  = $orep->getState("$comp.Ready");
   $ready   = $rep->getState("$comp.Ready");

   ($old, $new, $sev, $act) = $map->transition("moduleState.$oready/$ostatus", "moduleState.$ready/$status", $orep, $rep);
   return ("$oready/$ostatus", "$ready/$status", $old, $new, $sev, $act );

}






1;

