package Ocsinventory::Agent::Backend::OS::Linux::Storages::3ware;

use Ocsinventory::Agent::Backend::OS::Linux::Storages;
# Tested on 2.6.* kernels
#
# Cards tested :
#
# 8006-2LP
# 9500S-4LP
# 9550SXU-4LP
# 9550SXU-8LP
# 9650SE-2LP
# 9650SE-4LPML
# 9650SE-8LPML
#
# AMCC/3ware CLI (version 2.00.0X.XXX)

use strict;

sub check {

  my ($card, $res);
# Do we have tw_cli ?
  if (can_run("tw_cli")) {
    foreach (`tw_cli info`) {
      $card = $1 if /^(c\d+).*/;
      if ($card) {
        $res = `tw_cli info $card numdrives`;
        $card = undef;
        $res =~ s/^.*=\s(\d+)/$1/;
# Do we have drives on the card ?   
        ($res == 0)?return 0:return 1;
      }
    }
  }

}

sub run {


  my $params = shift;
  my $inventory = $params->{inventory};
  my $logger = $params->{logger};

  my ($tw_cli, $hd);

  my ($card, $card_model, $unit, $unit_id, $port, $serialnumber, $serial, $model, $capacity, $firmware, $description, $media, $device, $manufacturer, $sn);

  my @devices = Ocsinventory::Agent::Backend::OS::Linux::Storages::getFromUdev();

# First, getting the cards : c0, c1... etc.
  foreach (`tw_cli info`) {

# Should output something like this :
#
# Ctl   Model        Ports   Drives   Units   NotOpt   RRate   VRate   BBU
# ------------------------------------------------------------------------
# c0    9650SE-2LP   2       2        1       0        1       1       -        

    if (/^(c\d)+\s+([\w|-]+)/) {
      $card = $1;
      $card_model = $2;
      $logger->debug("Card : $card - Model : $card_model");

    }
    if ($card) {

# Second, getting the units : u0, u1... etc.
      foreach (`tw_cli info $card`) {

# Example output :
#
# Unit  UnitType  Status         %RCmpl  %V/I/M  Stripe  Size(GB)  Cache  AVrfy
# ------------------------------------------------------------------------------
# u0    RAID-1    OK             -       -       -       65.1826   ON     OFF    
#
# Port   Status           Unit   Size        Blocks        Serial
# ---------------------------------------------------------------
# p0     OK               u0     69.25 GB    145226112     WD-WMANS1648590     
# p1     OK               u0     69.25 GB    145226112     WD-WMANS1344790     

        if (/^(u)(\d+).*/) {
          $unit = $1 . $2;
          $unit_id = $2;
        }
        if ($unit) {

# Try do get unit's serial in order to compare it to what was found in udev db.
# Works only on newer cards.
# Allow us to associate a node to a drive : sda -> WD-WMANS1648590
          $sn = `tw_cli info $card $unit serial 2> /dev/null`;
          $sn =~ s/^.*serial number\s=\s(\w*)\s*/$1/;

# Third, getting the ports : p0, p1... etc.
          foreach(`tw_cli info $card $unit`) {
            $port =  $1 if /^.*(p\d+).*/;
            if ($port) {

# Finally, getting drives' values.
              foreach (`tw_cli info $card $port model serial capacity firmware`) {

# Example output :      
#
# /c0/p0 Model = WDC WD740ADFD-00NLR4
# /c0/p0 Serial = WD-WMANS1648590
# /c0/p0 Capacity = 69.25 GB (145226112 Blocks)
# /c0/p0 Firmware Version = 21.07QR4

                $model = $1 if /^.*Model\s=\s(.*)/;
                $serialnumber = $1 if /^.*Serial\s=\s(.*)/;
                $capacity = 1024*$1 if /^.*Capacity\s=\s(\S+)\sGB.*/;
                $firmware = $1 if /^.*Firmware Version\s=\s(.*)/;
              }
              foreach $hd (@devices) {

# How does this work with multiple older cards where serial for units is not implemented ?
# Need to be tested on a system with multiple 3ware cards.
                if (($hd->{SERIALNUMBER} eq 'AMCC_' . $sn) or ($hd->{MODEL} eq 'Logical_Disk_' . $unit_id)) {
                  $device = $hd->{NAME};
                }
              }

# Getting description from card model, very basic and unreliable
# Assuming only IDE drives can be plugged in 5xxx/6xxx cards and
# SATA drives only to 7xxx/8xxx/9xxxx cards
              $description = undef;
              foreach ($card_model) {
                $description = "IDE" if /^[5-6].*/;
                $description = "SATA" if /^[7-9].*/;
              }
              $media = 'disk';
              $manufacturer = Ocsinventory::Agent::Backend::OS::Linux::Storages::getManufacturer($model);
              $port = undef;
              $logger->debug("3ware: $device, $manufacturer, $model, $description, $media, $capacity, $serialnumber, $firmware");
              $inventory->addStorages({
                  NAME => $device,
                  MANUFACTURER => $manufacturer,
                  MODEL => $model,
                  DESCRIPTION => $description,
                  TYPE => $media,
                  DISKSIZE => $capacity,
                  SERIALNUMBER => $serialnumber,
                  FIRMWARE => $firmware,
                  });
            }
            $port = undef;
          }
          $unit = undef;
        }
      }
      $card = undef;
      $card_model = undef;
    }
  }
}

1;
