????

Your IP : 216.73.216.174


Current Path : /lib/raider/Raider/Info/
Upload File :
Current File : //lib/raider/Raider/Info/satascsiata.pm

use strict;
use warnings;

package Raider::Info::satascsiata;
use base qw( Raider::Info );

use Raider::Notification::Email;
use Cwd ();
use JSON::Tiny qw(decode_json encode_json);

=head1 NAME

Raider::Info::satascsiata - satascsiata specific instructions for get-info 

=head1 DESCRIPTION

satascsiata specific methods to gather information required for populating the .info 
file.

=head1 USAGE

use Raider::Info::satascsiata;
my $noraidInfoObj = Raider::Info::satascsiata->new();

=head1 METHODS

=head2 get_info()

Initiates all needed steps to generate a finished satascsiata info file.

=head2 get_pci_id(\%args)

Returns the PCI ID of device.

=head2 get_disk_info(\%args)

Returns the info of a disk.

=head2 get_disks()

Return the disk devices we are working with.

=head2 get_satascsiata()

Return non raided disks.

=head2 is_hdd(\%args)

Returns 1 if device is a physical disk, 0 if not.

=head2 get_non_raid_devices()

Return non raided ID's.

=cut

sub get_info {
  my $self = shift;
  my $opts = shift;

  my $found_numdrives_arr = $self->get_satascsiata();
  my $found_numdrives = scalar(@{ $found_numdrives_arr });
  my ($disks_struct,$unidentifiable_disks,$unidentifiable_disks_usb) = $self->get_disks();

  my $d_struct_usb_storage = { };
  
  # Onboard controller identification.
  my $onboard_controller_id;
  my $id_int_key;
  
  my @onboard_controller_ids_raw = ();
  for my $line ( split /^/, `lspci -n` ) {
    
    # IDE/SATA AHCI
    if ( $line =~ /^\S+\s+0101:\s+(\S+)/ || $line =~ /^\S+\s+Class\s+0101:\s+(\S+)/i ) {
      $id_int_key = $1;
      push(@onboard_controller_ids_raw, $id_int_key);
    }
    # SATA
    elsif ( $line =~ /^\S+\s+0106:\s+(\S+)/ || $line =~ /^\S+\s+Class\s+0106:\s+(\S+)/i) {
      $id_int_key = $1;
      push(@onboard_controller_ids_raw, $id_int_key);
    }

  }
  
  # Remove duplicates
  my %seen = ();
  my @onboard_controller_ids = grep { ! $seen{$_} ++ } @onboard_controller_ids_raw;

  my $d_struct_controllers;
  for my $onboard_cntrl_id ( @onboard_controller_ids ) {
    $d_struct_controllers->{ $opts->{cntrl_cnt} } = { 
      identifier => "Onboard:::$onboard_cntrl_id",
      logical_disks => {}
    };
    $onboard_controller_id = $opts->{cntrl_cnt};
    $opts->{cntrl_cnt}++;
  }

  my $d_struct_disks = { };

  my $storm_d_struct = { controllers => { }, };
  $storm_d_struct->{'controllers'}->{ '0' } = { disks => { } };

  $storm_d_struct->{'controllers'}->{'0'}->{'numarrays'} = '0';
  $storm_d_struct->{'controllers'}->{'0'}->{'numdrives'} = $found_numdrives;
  $storm_d_struct->{'controllers'}->{'0'}->{'make'} = 'N/A';
  $storm_d_struct->{'controllers'}->{'0'}->{'model'} = 'N/A';
  $storm_d_struct->{'controllers'}->{'0'}->{'firmware'} = 'N/A';


  my @usb_disks = ();
  my @onboard_controller_disks = ();
  for my $disk ( @{ $disks_struct->{disk_cnt} } ) {

    my $disk_id;
    if ( defined("$disks_struct->{disk_info}->{ $disk }->{model}\:::$disks_struct->{disk_info}->{ $disk }->{serial}") ) {  
      $disk_id = "$disks_struct->{disk_info}->{ $disk }->{model}\:::$disks_struct->{disk_info}->{ $disk }->{serial}";
    }

    if ( $disks_struct->{disk_info}->{ $disk }->{udev_id_bus} =~ /usb/i ) {
      push(@usb_disks, $disk_id);
    }
    else {
      push(@onboard_controller_disks, $disk_id);
    }

    if ( defined($disk_id) ) {
      $d_struct_disks->{ $opts->{disk_cnt} } = {
        identifier => $disk_id,  
        size_mb => $disks_struct->{disk_info}->{ $disk }->{size_mb},
        size_unparsed => $disks_struct->{disk_info}->{ $disk }->{size_unparsed},
        serial => $disks_struct->{disk_info}->{ $disk }->{serial},
        model => $disks_struct->{disk_info}->{ $disk }->{model},
        type => $disks_struct->{disk_info}->{ $disk }->{disk_type},
        firmware => $disks_struct->{disk_info}->{ $disk }->{firmware},
        state => $disks_struct->{disk_info}->{ $disk }->{state},
        block_device => $disks_struct->{disk_info}->{ $disk }->{block_device},
        udev_id_bus => $disks_struct->{disk_info}->{ $disk }->{udev_id_bus}
      };
      if ( defined($disks_struct->{disk_info}->{ $disk }->{smart_attributes}) ) {
        $d_struct_disks->{ $opts->{disk_cnt} }->{'smart_attributes'} = $disks_struct->{disk_info}->{ $disk }->{smart_attributes};
      }
      $opts->{disk_cnt}++;
    }

    $storm_d_struct->{'controllers'}->{'0'}->{'disks'}->{ $disk }->{'type'} = $disks_struct->{disk_info}->{ $disk }->{disk_type};
  };


  if ( defined($onboard_controller_id) ) {
    $d_struct_controllers->{ $onboard_controller_id }->{'unidentifiable_disks'} = $unidentifiable_disks;
    
    my $each_onboard_cntrl_pd_count = 0;
    for my $each_onboard_cntrl_pd ( @onboard_controller_disks ) {
  
      my $accessor_key;  
      foreach my $key ( keys %{ $d_struct_disks } ) {
        if ( $d_struct_disks->{$key}->{identifier} =~ /$each_onboard_cntrl_pd/ ) {
          $accessor_key = $key;
        }
      }

      $d_struct_controllers->{ $onboard_controller_id }->{'logical_disks'}->{ $each_onboard_cntrl_pd_count }->{'size_mb'} = $d_struct_disks->{ $accessor_key }->{'size_mb'};
      $d_struct_controllers->{ $onboard_controller_id }->{'logical_disks'}->{ $each_onboard_cntrl_pd_count }->{'block_device'} = $d_struct_disks->{ $accessor_key }->{'block_device'};
      $d_struct_controllers->{ $onboard_controller_id }->{'logical_disks'}->{ $each_onboard_cntrl_pd_count }->{'physical_disks'} = [ $each_onboard_cntrl_pd ];

      $each_onboard_cntrl_pd_count++;
    }
  }

  # Increment passed controller counter for onboard USB if needed.
  if ( defined($d_struct_controllers->{ $opts->{cntrl_cnt} }->{'identifier'}) ) {
    $opts->{cntrl_cnt}++;
  }

  $d_struct_usb_storage->{ $opts->{cntrl_cnt} }->{'identifier'} = 'Onboard:::usb_storage';
  $d_struct_usb_storage->{ $opts->{cntrl_cnt} }->{'unidentifiable_disks'} = $unidentifiable_disks_usb;

  my $each_onboard_usb_pd_count = 0;
  for my $each_onboard_usb_pd ( @usb_disks ) {  
  
    my $accessor_key;
    foreach my $key ( keys %{ $d_struct_disks } ) {
      if ( $d_struct_disks->{$key}->{identifier} =~ /$each_onboard_usb_pd/ ) {
        $accessor_key = $key;
      }
    }

    $d_struct_usb_storage->{ $opts->{cntrl_cnt} }->{'logical_disks'}->{ $each_onboard_usb_pd_count }->{'size_mb'} = $d_struct_disks->{ $accessor_key }->{'size_mb'};
    $d_struct_usb_storage->{ $opts->{cntrl_cnt} }->{'logical_disks'}->{ $each_onboard_usb_pd_count }->{'block_device'} = $d_struct_disks->{ $accessor_key }->{'block_device'};
    $d_struct_usb_storage->{ $opts->{cntrl_cnt} }->{'logical_disks'}->{ $each_onboard_usb_pd_count }->{'physical_disks'} = [ $each_onboard_usb_pd ];

    $each_onboard_usb_pd_count++;
  }
  $self->write_json({data => $storm_d_struct, device => 'satascsiata' });

  return ($d_struct_usb_storage,$d_struct_controllers,$d_struct_disks,$opts->{cntrl_cnt},$opts->{disk_cnt});
}

sub get_pci_id {
  my $self = shift;
  my $opts = shift;
  my $pci_id;
  my $is_ide_short_circuit = 0;

  my $all_bdev_ctrls = $self->get_nonraid_devs_to_path();
  while ( my($device, $device_path) = each %{ $all_bdev_ctrls } ) {
    if ( $device =~ /$opts->{device}/ ) {
      if ( $device_path =~ /ide-/ ) {
        $is_ide_short_circuit = 1;      
      }
      else {
        if ( $device_path =~ /\/sys\/devices\/[A-z]+\d+:\d+\/\d+:(\S+:\S+\.\d+)\// ) {
          $pci_id = $self->get_device_id({ device_path => $device_path });
        }
        else {
          $self->logger({ cat => 'c', msg => "Failed to extract pci_id from [$device_path]" });
        }
      }
    }
  };
  
  return 'IDE' if ( $is_ide_short_circuit );

  my $pci_id_desc;
  for my $line ( split /^/, `lspci` ) {
    if ( $pci_id && $line =~ /$pci_id/ ) {
      $line =~ /$pci_id\s+(.*)/;
      $pci_id_desc = $1;
    }
  }
  
  return $pci_id_desc;
}

sub get_disk_info {
  my $self = shift;
  my $opts = shift;
  my $device_name = substr $opts->{device}, 5, 3;
  my ($contains,$pci_id);

  my $size_mb = 0;
  my $size_unparsed = 'unknown';
  my $dtype = 'unknown';
  my $model = 'unknown';
  my $firmware = 'unknown';
  my $serial = 'unknown';
  my $state = 'unsupported';

  #
  # disk type
  ###############################################################################################
  
  ##
  ## SSD
  ##
  if ( -e "/sys/block/$device_name/device/vendor" ) {
    open FILE, "</sys/block/$device_name/device/vendor";
    $contains = do { local $/; <FILE> };
    close(FILE);
    if ( $contains =~ /SSD|KINGSTON|INTEL|CRUCIAL/i ) {
      $dtype = 'SSD';
    }
  }
  for my $line ( split /^/, `sginfo -z /dev/$device_name` ) {
    if ( $line =~ /Product:/i ) {
      if ( $line =~ /^M4-CT|SSD|^CT|^SKC|kingston|^C300-|crucial|intel/i ) {
        $dtype = 'SSD';
      }
    }
  }

  ##
  ## ZDRIVE
  ##
  if ( -e "/sys/block/$device_name/device/vendor" ) {
    $contains = `grep -q "OCZ" /sys/block/$device_name/device/vendor`;
    if ( $? == 0 ) {
      $dtype = 'ZDRIVE';
    }
  }

  $pci_id = $self->get_pci_id({ device => "$opts->{device}" });
  if ( $pci_id =~ /SATA/i ) {
    $dtype = 'SATA';
  }
  elsif ( $pci_id =~ /SCSI/i ) {
    $dtype = 'SCSI';
  }
  elsif ( $pci_id =~ /IDE/i ) {
    $dtype = 'PATA';
  }
  elsif ( $pci_id =~ /SAS/i ) {
    $dtype = 'SAS';
  }

  my $hdparm_info;
  if ( $dtype eq 'PATA' ) {
    $hdparm_info = `hdparm -i $opts->{device}`;
  }
  else {
    $hdparm_info = `hdparm -I $opts->{device}`;
  }
  my $smartctl_info = `smartctl -i $opts->{device} -T permissive`;

  if ( $hdparm_info =~ /Nominal\s+Media\s+Rotation\s+Rate:\s+Solid\s+State\s+Device/i ) {
    $dtype = 'SSD';
  }

  #
  # disk size
  ###############################################################################################

  my $sectors = 0;
  my $hdparm_output_geo = `hdparm -g $opts->{device}`;
  if ( $hdparm_output_geo =~ /geometry\s+=\s+\S+\s+sectors\s+=\s+(\d+)/i ) {
    $sectors = $1;
  }
  if ( $hdparm_output_geo =~ /(geometry\s+=\s+\S+\s+sectors\s+=.+)/i ) {
    $size_unparsed = $1;
  }
  # 512 bytes per sector..
  my $in_bytes = $sectors * 512;
  my $in_kb = $in_bytes / 1024;
  $size_mb = $in_kb / 1024;

  #
  # disk model
  ###############################################################################################

  if ( $hdparm_info =~ /Model\s+Number(\s+)?:(.+)/i ) {
    $model = $2;
    $model =~ tr/ //ds;
  }
  elsif ( $smartctl_info =~ /Device\sModel(\s+)?:(.+)/i ) {
    $model = $2;
    $model =~ tr/ //ds;
  }
  elsif ( $smartctl_info =~ /Device(\s+)?:(.+)/i ) {
    $model = $2;
    $model =~ tr/ //ds;
  }

  #
  # disk firmware
  ###############################################################################################
  
  if ( $hdparm_info =~ /Firmware\s+Revision(\s+)?:(.+)/i ) {
    $firmware = $2;
    $firmware =~ tr/ //ds;
  }
  elsif ( $smartctl_info =~ /Firmware\s+Version(\s+)?:(.+)/i ) {
    $firmware = $2;
    $firmware =~ tr/ //ds;
  }

  #
  # disk serial
  ###############################################################################################

  if ( $hdparm_info =~ /Serial\s+Number(\s+)?:(.+)/i ) {
    $serial = $2;
    $serial =~ tr/ //ds;
  }
  elsif ( $smartctl_info =~ /Serial\s+Number(\s+)?:(.+)/i ) {
    $serial = $2;
    $serial =~ tr/ //ds;
  }


  #
  # UDEV
  ###############################################################################################

  # Directly querying the disk for model/serial works well when the disk responds. However, since we ideally want to be able to uniquely
  # identify a disk, and our current identification system used by Sonar relies on $model-$serial identification, query udev db for
  # model/serial as well. This covers the scenario where a disk may be failed and not responding to requests, but the serial/model still
  # lives in the udev db. Obviously this isn't perfect , but covers the scenario where a disk fails after the udev db was generated, so that
  # we can still get the failed disks model/serial.
  #
  #   -- ssullivan May 15, 2013
  my $udev_info;
  if ( $serial eq 'unknown' || $model eq 'unknown' ) {
    $udev_info = $self->get_udev_block_device_info({ block_device_name => $device_name });
    # When querying disk directly for model-serial; use the udev info only on failure.
    if ( ref($udev_info) eq 'HASH' && defined($udev_info->{model}) && defined($udev_info->{id_serial}) ) {
      $model = $udev_info->{model};
      $serial = $udev_info->{id_serial};
    }
  }
  else {
    $udev_info = $self->get_udev_block_device_info({ block_device_name => $device_name });
  }

  # SMART health status doesn't seem to work with flash drives, so fudge it.
  if ( $model =~ /Flash_Disk/i ) {
    $dtype = 'Flash_Disk';
    $state = 'Present';
  }
  elsif ( ref($udev_info) eq 'HASH' && $udev_info->{disk_bus} =~ /usb/i ) {
    $dtype = 'USB_ATA';
  }
  # We don't want the block device of a RAID LD to show up.
  elsif ( ref($udev_info) eq 'HASH' && $udev_info->{id_vendor} =~ /^lsi|^adaptec|^3ware/i ) {
    return 'skip';
  }


  #
  # disk state & SMART attributes
  ###############################################################################################

  my $smart_attribs = 'unsupported';
  if ( `smartctl -H $opts->{device} -T permissive -s on` =~ /SMART\s+overall-health\s+self-assessment\s+test\s+result(\s+)?:\s+(.+)/i ) {
    $state = $2;
  }
  
  # SMART attributes
  if ( ref($udev_info) eq 'HASH' && $udev_info->{disk_bus} =~ /usb/i ) {
    $smart_attribs = $self->get_smart_attribs({ device => $opts->{device}, bus => 'usb' });
  }
  else {
    $smart_attribs = $self->get_smart_attribs({ device => $opts->{device} });
  }
  $smart_attribs = 'unsupported' if ( defined($smart_attribs->{error}) );

  if ( ref($udev_info) eq 'HASH' ) {
    return ($dtype,$size_mb,$model,$firmware,$serial,$state,$smart_attribs,$size_unparsed,$udev_info->{disk_bus});
  }
  else {
    return ($dtype,$size_mb,$model,$firmware,$serial,$state,$smart_attribs,$size_unparsed,'unknown');
  }
}

sub get_disks {
  my $self = shift;
  my $found_numdrives_arr = $self->get_satascsiata();
  my $dnum = 0;

  my $struct = {
    disk_cnt => [],
    disk_info => {}
  };
  my $unidentifiable_disks = 0;
  my $unidentifiable_disks_usb = 0;

  if ( @{ $found_numdrives_arr } ) {
    for my $each_disk ( @{ $found_numdrives_arr } ) {
      my ($disk_type,$size_mb,$model,$firmware,$serial,$state,$smart_attribs,$size_unparsed,$udev_id_bus) = $self->get_disk_info({ device => $each_disk });
      next if ( $disk_type eq 'skip' );
      if ( $model eq 'unknown' || $serial eq 'unknown' ) {
        if ( $udev_id_bus =~ /usb/i ) {
          $unidentifiable_disks_usb++;
        }
        else {
          $unidentifiable_disks++;
        }
  
        next;
      }
      push(@{ $struct->{disk_cnt} }, $dnum);
      $struct->{disk_info}->{ $dnum } = {  
        disk_type => $disk_type,
        size_mb => $size_mb,
        size_unparsed => $size_unparsed,
        model => $model,
        firmware => $firmware,
        serial => $serial,
        state => $state,
        block_device => $each_disk,
        udev_id_bus => $udev_id_bus
      };
      if ( $smart_attribs ne 'unsupported' ) {
        $struct->{disk_info}->{ $dnum }->{'smart_attributes'} = $smart_attribs;
      }
      $dnum++;
    }
  }
  
  return ($struct,$unidentifiable_disks,$unidentifiable_disks_usb);
}

sub get_nonraid_devs_to_path {
  my $self = shift;
  my $opts = shift;

  my $data;
  my $lspci_output = `lspci`;
  for our $device ( @{ $self->get_non_raid_devices() } ) {

    # Filter out FusionMPTSAS2 devices from this. We want them to show up as
    # attached to their specific controller, not as directly connected through
    # the motherboard. 
    if ( $lspci_output =~ /$device\s+.+Fusion-MPT\s+SAS-2/i ) {
      $self->logger({ cat => 'i', msg => "Filtering out [$device] from Info/satascsiata as it's a FusionMPTSAS2 controller" });
      next;
    }

    my $all_bdev_ctrls = $self->get_sys_ctrls_with_bdevs();
    for my $device_path ( keys %{ $all_bdev_ctrls } ) {
      # If this block device does not belong to our current controller, go to
      # next loop pass.
      next unless ( $device_path =~ /$device/ );

      $data->{ "/dev/$all_bdev_ctrls->{ $device_path }" } = $device_path;
    }
  }


  return $data;
}

sub get_satascsiata {
  my $self = shift;
  my $opts = shift;

  my @found_numdrives_arr;
  my $d_struct = $self->get_nonraid_devs_to_path();

  while ( my($device, $device_path) = each %{ $d_struct } ) {
    if ( $self->is_hdd({ device => $device }) ) {
      push(@found_numdrives_arr, $device);
    }
  }


  return \@found_numdrives_arr;
}

sub is_hdd {
  my $self = shift;
  my $opts = shift;

  # Returns:
  #   0 -- if device is not a physical disk
  #   1 -- if device is a physical disk

  my $device_short;
  if ( $opts->{device} =~ /\/dev\/(\S+)/ ) {
    $device_short = $1;
  }
  else {
    $self->logger({ cat => 'c', msg => "is_hdd() [$opts->{device}] is of invalid type!" });
  }

  # Filter out CDROM device
  #  Some old hosts, like Cent5s, will sometimes show the CDROM as hda.
  #  Account for this situation.
  if ( -e '/proc/sys/dev/cdrom/info' ) {
    open(my $fh, '/proc/sys/dev/cdrom/info' ) 
      or $self->logger({
                          cat => 'c', 
                          msg => "Unable to open [/proc/sys/dev/cdrom/info]: $!" 
                       });
    while (my $line = <$fh>) {
      if ( $line =~ /^drive\s+name:\s+(\S+)/ ) {
        if ( $1 eq $device_short ) {
          return 0;
        } 
      }
    }
  }
  return 0 if ( $device_short =~ /^sr[0-9]+/ );

  # If the device name is of format fd[0-9]+ throw it out, as assume its a
  # floppy device.
  return 0 if ( $device_short =~ /^fd[0-9]+/ );

  # No entry in /sys/block ? Reject.
  return 0 unless ( -d "/sys/block/$device_short" );
  
  # Somehow doesn't exist? Reject.
  return 0 unless ( -e $opts->{device} );

  # If the size of the device is reported as 0, reject.
  if ( -e "/sys/block/$device_short/size" ) {
    my $device_size;
    open(my $fh, "/sys/block/$device_short/size") 
      or $self->logger({ 
                          cat => 'c', 
                          msg => "Unable to open [/sys/block/$device_short/size]: $!" 
                       });
    while (my $line = <$fh>) {
      chomp $line;
      $device_size = $line;
    }
    # 0 size, assume not a block device. Among likely other things, this gets
    # rid of loop devices from detecting as a physical disk.
    if ( $device_size == 0 ) {
      return 0;
    }
  }
  else {
    # No size? reject.
    return 0;
  }
 
  # With 2.6.32 (Cent6) and newer, there is a /sys/devices/virtual/block/
  # directory. Virtual devices like loop, dm, and md, devices show up in here
  # (which also show up in /sys/block). If /sys/devices/virtual/block/ exists,
  # filter out (reject) devices that show up here.
  if ( -d '/sys/devices/virtual/block' ) {
    return 0 if ( -e "/sys/devices/virtual/block/$device_short" );
  }
  else {
    return 0 if ( $device_short =~ /^loop[0-9]+/ );
    return 0 if ( $device_short =~ /^md[0-9]+/ );
    return 0 if ( $device_short =~ /^dm-[0-9]+/ );
    return 0 if ( $device_short =~ /^ram[0-9]+/ );
  }

  # Filter out things we gleam from basic SMART info that give this away as
  # not a physical disk.
  for my $line ( split /^/, `smartctl -i $opts->{device}` ) {
    # Filter out Adaptec RAID LDs
    if ( $line =~ /(Device|Vendor)\s*:\s+(Adaptec|ASR\S+)/i ) {
      return 0;
    }
    # Filter out LSI RAID LDs
    elsif ( $line =~ /(Device|Vendor)\s*:\s+LSI|megaraid/i ) {
      return 0;
    }
    # Filter out 3ware RAID LDs
    elsif ( $line =~ /(Device|Vendor)\s*:\s+3ware/i ) {
      return 0;
    }
    # iSCSI disk
    elsif ( $line =~ /(Device|Vendor)\s*:\s+IET/i ) {
      return 0;
    }
    # iSCSI disk
    elsif ( $line =~ /(Product)\s*:\s+VIRTUAL-DISK/i ) {
      return 0;
    }
  }


  # If we made it this far, assume its a physical disk.
  return 1;
}

sub get_non_raid_devices {
  my $self = shift;

  my $all_bdev_ctrls = $self->get_sys_ctrls_with_bdevs();
  my @nonraid_bdev_ctrls = ();
  my $lspci_output = `lspci`;

  # in this path:
  #   /sys/devices/pci0000:00/0000:00:01.1/0000:02:00.0/host0/target0:2:0/0:2:0:0/block
  # 00:01.1 is the address of the PCI slot:
  #   00:01.1 PCI bridge: Intel Corporation Xeon E3-1200 v3/4th Gen Core Processor PCI Express x8 Controller (rev 06)
  # 02:00.0 is the address of the raid controller:
  #   02:00.0 RAID bus controller: Broadcom / LSI MegaRAID Tri-Mode SAS3516 (rev 01)
  # thus in these scenarios, we would need to look and see if this block device maps to 02:00.0

  # in this path:
  #   /sys/devices/pci0000:00/0000:00:1f.2/ata1/host1/target1:0:0/1:0:0:0/block
  # 00:1f.2 is the address of a SATA port on the motherboard:
  #   00:1f.2 SATA controller: Intel Corporation 8 Series/C220 Series Chipset Family 6-port SATA Controller 1 [AHCI mode] (rev 05)
  # Since its directly attached, there is no address after that. Thus in these scenarios, we need to look
  # and see if this block device maps to 00:1f.2

  for my $bdev_ctrl_path ( keys %{ $all_bdev_ctrls } ) { 
    # given this path /sys/devices/pci0000:00/0000:00:1f.2/host1/target1:0:0/1:0:0:0/block
    # would try to match on 00:1f.2
    my $ctrl_id;
    if ( $bdev_ctrl_path =~ /\/sys\/devices\/\S+\d+:\d+\/\d+:(\d+:\S+\.\d+)/ ) {
      # if theres a controller connected to the base address, $1 will look like this:
      #    00:01.1/0000:02:00.0
      # So we check for the presence of /, and treat it as true/false
      my ($has_ctrl) = $1 =~ /\// ? 1 : 0;
      unless ($has_ctrl) {
        $ctrl_id = $self->get_device_id({ device_path => $bdev_ctrl_path });;
      }
    }
    if ($ctrl_id) {
      for my $line ( split /^/, $lspci_output ) {
        # If our block device is _not_ raid..
        if ( $line =~ /^$ctrl_id/i && $line !~ /RAID/i ) {
          # Perl 5.8.8 doesn't support the below commented code..
          #if ( $ctrl_id ~~ @nonraid_bdev_ctrls ) {
          my %nonraid_bdev_ctrls_bash = map { $_ => 1 } @nonraid_bdev_ctrls;
          if ( exists($nonraid_bdev_ctrls_bash{$ctrl_id}) ) {
            # Dont duplicate it.
            next;
          }
          else {
            push(@nonraid_bdev_ctrls, $ctrl_id);
          }
        }
      }
    }
    else {
      $self->logger({ cat => 'w', msg => "get_non_raid_devices() Skipping device [$bdev_ctrl_path]" });
    }
  }

  return \@nonraid_bdev_ctrls;
}


1;