]> git.openstreetmap.org Git - chef.git/blobdiff - cookbooks/hardware/templates/default/ohai.rb.erb
Handle failed megaraid disks with no ID
[chef.git] / cookbooks / hardware / templates / default / ohai.rb.erb
index 8192d34c48bfee88b22d354cca6b39327f60cfb1..6e6e5f37e200d1f86c50ba95882fcdf126553970 100644 (file)
@@ -5,12 +5,12 @@ Ohai.plugin(:Hardware) do
 
   def read_sysctl_link(file)
     File.basename(File.readlink(file))
 
   def read_sysctl_link(file)
     File.basename(File.readlink(file))
-  rescue Errno::ENOENT
+  rescue Errno::ENOENT, Errno::ENOTDIR
   end
 
   def read_sysctl_file(file)
     IO.read(file).strip
   end
 
   def read_sysctl_file(file)
     IO.read(file).strip
-  rescue Errno::ENOENT, Errno::EINVAL
+  rescue Errno::ENOENT, Errno::ENOTDIR, Errno::EINVAL
   end
 
   def parse_memory_size(size)
   end
 
   def parse_memory_size(size)
@@ -148,16 +148,17 @@ Ohai.plugin(:Hardware) do
     find_direct_disks(disk)
     find_nvme_disks(disk)
 
     find_direct_disks(disk)
     find_nvme_disks(disk)
 
-    find_hp_disks(disk) if File.exist?("/usr/sbin/hpssacli")
+    find_hp_disks(disk) if File.exist?("/usr/sbin/ssacli")
     find_megaraid_disks(disk) if File.exist?("/usr/sbin/megacli")
     find_megaraid_disks(disk) if File.exist?("/usr/sbin/megacli")
-    find_mpt_disks(disk) if File.exist?("/usr/sbin/sas2ircu")
+    find_mpt1_disks(disk) if File.exist?("/usr/sbin/lsiutil")
+    find_mpt2_disks(disk) if File.exist?("/usr/sbin/sas2ircu")
     find_adaptec_disks(disk) if File.exist?("/usr/sbin/arcconf")
     find_areca_disks(disk) if File.exist?("/opt/areca/x86_64/cli64")
 
     find_md_arrays(disk)
 
     disk[:disks].each do |disk|
     find_adaptec_disks(disk) if File.exist?("/usr/sbin/arcconf")
     find_areca_disks(disk) if File.exist?("/opt/areca/x86_64/cli64")
 
     find_md_arrays(disk)
 
     disk[:disks].each do |disk|
-      if disk[:vendor] =~ /^CVPR/ && disk[:model] == "INTEL"
+      if disk[:vendor] =~ /^(BTWA|CVPR|PHDV)/ && disk[:model] == "INTEL"
         disk[:model] = disk[:serial_number]
         disk[:serial_number] = disk[:vendor]
         disk[:vendor] = "INTEL"
         disk[:model] = disk[:serial_number]
         disk[:serial_number] = disk[:vendor]
         disk[:vendor] = "INTEL"
@@ -255,24 +256,44 @@ Ohai.plugin(:Hardware) do
     array = nil
 
     File.new("/proc/mdstat", "r").each do |line|
     array = nil
 
     File.new("/proc/mdstat", "r").each do |line|
-      if line =~ /^(md\d+) : active raid(\d+)((?: (?:sd[a-z]|nvme\d+n\d+)\d*\[\d+\](?:\([A-Z]\))*)+)$/
+      if line =~ /^(md\d+) : active raid(\d+)((?: (?:sd[a-z]\d*|nvme\d+n\d+(?:p\d+)?)\[\d+\](?:\([A-Z]\))*)+)$/
         array = {
           :id => devices[:arrays].count,
           :device => "/dev/#{Regexp.last_match(1)}",
         array = {
           :id => devices[:arrays].count,
           :device => "/dev/#{Regexp.last_match(1)}",
+          :status => "optimal",
           :raid_level => Regexp.last_match(2),
           :disks => []
         }
 
           :raid_level => Regexp.last_match(2),
           :disks => []
         }
 
-        Regexp.last_match(3).scan(/ (sd[a-z]+|nvme\d+n\d+)\d*\[\d+\](?:\([A-Z]\))*/).flatten.each do |device|
-          if disk = devices[:disks].find { |d| d[:device] == "/dev/#{device}" }
-            disk[:arrays] << array[:id]
-            array[:disks] << disk[:id]
+        Regexp.last_match(3).split(" ").each do |member|
+          if member =~ /^(sd[a-z]+|nvme\d+n\d+).*/
+            device = Regexp.last_match(1)
+
+            if disk = devices[:disks].find { |d| d[:device] == "/dev/#{device}" }
+              if member =~ /\(F\)/
+                disk[:status] = "failed"
+              elsif member =~ /\(S\)/
+                disk[:status] = "hotspare"
+              else
+                disk[:status] = "online"
+              end
+
+              disk[:arrays] << array[:id]
+              array[:disks] << disk[:id]
+            end
           end
         end
 
         devices[:arrays] << array
           end
         end
 
         devices[:arrays] << array
-      elsif array && line =~ /^\s+(\d+) blocks/
+      elsif array && line =~ /^\s+(\d+) blocks.*(?:\[([U_]+)\])?/
         array[:size] = format_disk_size(Regexp.last_match(1).to_i)
         array[:size] = format_disk_size(Regexp.last_match(1).to_i)
+        array[:status] = "degraded" if Regexp.last_match(2) =~ /_/
+      elsif array && line =~ /^\s+\[.*\]\s+(\S+)\s+=/
+        case Regexp.last_match(1)
+        when "recovery" then array[:status] = "rebuilding"
+        when "resync" then array[:status] = "rebuilding"
+        when "checking" then array[:status] = "checking"
+        end
       end
     end
   end
       end
     end
   end
@@ -285,10 +306,13 @@ Ohai.plugin(:Hardware) do
     array = nil
     disk = nil
 
     array = nil
     disk = nil
 
-    IO.popen(%w(hpssacli controller all show config detail)).each do |line|
-      if line =~ /^Smart Array (\S+) /
+    IO.popen(%w(ssacli controller all show config detail)).each do |line|
+      next unless line.valid_encoding?
+
+      if line =~ /^Smart (?:Array|HBA) (\S+) /
         controller = {
           :id => devices[:controllers].count,
         controller = {
           :id => devices[:controllers].count,
+          :type => "hp",
           :model => Regexp.last_match(1),
           :arrays => [],
           :disks => []
           :model => Regexp.last_match(1),
           :arrays => [],
           :disks => []
@@ -302,6 +326,7 @@ Ohai.plugin(:Hardware) do
         disk = nil
       elsif controller && line =~ /^   (\S.*):\s+(.*)$/
         case Regexp.last_match(1)
         disk = nil
       elsif controller && line =~ /^   (\S.*):\s+(.*)$/
         case Regexp.last_match(1)
+        when "Slot" then controller[:slot] = Regexp.last_match(2)
         when "Serial Number" then controller[:serial_number] = Regexp.last_match(2)
         when "Hardware Revision" then controller[:hardware_version] = Regexp.last_match(2)
         when "Firmware Version" then controller[:firmware_version] = Regexp.last_match(2)
         when "Serial Number" then controller[:serial_number] = Regexp.last_match(2)
         when "Hardware Revision" then controller[:hardware_version] = Regexp.last_match(2)
         when "Firmware Version" then controller[:firmware_version] = Regexp.last_match(2)
@@ -319,15 +344,12 @@ Ohai.plugin(:Hardware) do
         controller[:arrays] << array[:id]
 
         disk = nil
         controller[:arrays] << array[:id]
 
         disk = nil
-      elsif controller && line =~ /^      physicaldrive (\S+) /
-        disks << Regexp.last_match(1)
       elsif array && line =~ /^      physicaldrive (\S+)$/
         disk = {
           :id => devices[:disks].count,
           :controller => controller[:id],
           :arrays => [array[:id]],
       elsif array && line =~ /^      physicaldrive (\S+)$/
         disk = {
           :id => devices[:disks].count,
           :controller => controller[:id],
           :arrays => [array[:id]],
-          :location => Regexp.last_match(1),
-          :smart_device => "cciss,#{disks.find_index(Regexp.last_match(1))}"
+          :location => Regexp.last_match(1)
         }
 
         devices[:disks] << disk
         }
 
         devices[:disks] << disk
@@ -335,6 +357,8 @@ Ohai.plugin(:Hardware) do
         array[:disks] << disk[:id]
       elsif disk && line =~ /^         (\S[^:]+):\s+(.*\S)\s*$/
         case Regexp.last_match(1)
         array[:disks] << disk[:id]
       elsif disk && line =~ /^         (\S[^:]+):\s+(.*\S)\s*$/
         case Regexp.last_match(1)
+        when "Status" then disk[:status] = Regexp.last_match(2)
+        when "Drive Type" then disk[:drive_type] = Regexp.last_match(2)
         when "Interface Type" then disk[:interface] = Regexp.last_match(2)
         when "Size" then disk[:size] = Regexp.last_match(2)
         when "Rotational Speed" then disk[:rpm] = Regexp.last_match(2)
         when "Interface Type" then disk[:interface] = Regexp.last_match(2)
         when "Size" then disk[:size] = Regexp.last_match(2)
         when "Rotational Speed" then disk[:rpm] = Regexp.last_match(2)
@@ -342,10 +366,17 @@ Ohai.plugin(:Hardware) do
         when "Serial Number" then disk[:serial_number] = Regexp.last_match(2)
         when "Model" then disk[:model] = Regexp.last_match(2)
         end
         when "Serial Number" then disk[:serial_number] = Regexp.last_match(2)
         when "Model" then disk[:model] = Regexp.last_match(2)
         end
+      elsif array && line =~ /^         Status:\s+(.*\S)\s*$/
+        case Regexp.last_match(1)
+        when "OK" then array[:status] = "optimal"
+        when "Interim Recovery Mode" then array[:status] = "degraded"
+        else array[:status] = "unknown"
+        end
       elsif array && line =~ /^         (\S[^:]+):\s+(.*\S)\s*$/
         case Regexp.last_match(1)
         when "Size" then array[:size] = Regexp.last_match(2)
         when "Fault Tolerance" then array[:raid_level] = Regexp.last_match(2)
       elsif array && line =~ /^         (\S[^:]+):\s+(.*\S)\s*$/
         case Regexp.last_match(1)
         when "Size" then array[:size] = Regexp.last_match(2)
         when "Fault Tolerance" then array[:raid_level] = Regexp.last_match(2)
+        when "Status" then array[:status] = Regexp.last_match(2)
         when "Disk Name" then array[:device] = Regexp.last_match(2).strip
         when "Mount Points" then array[:mount_point] = Regexp.last_match(2).split.first
         when "Unique Identifier" then array[:wwn] = Regexp.last_match(2)
         when "Disk Name" then array[:device] = Regexp.last_match(2).strip
         when "Mount Points" then array[:mount_point] = Regexp.last_match(2).split.first
         when "Unique Identifier" then array[:wwn] = Regexp.last_match(2)
@@ -354,19 +385,48 @@ Ohai.plugin(:Hardware) do
     end
 
     controllers.each do |controller|
     end
 
     controllers.each do |controller|
+      slot = controller[:slot]
+
+      IO.popen(%W(ssacli controller slot=#{slot} pd all show status)).each do |line|
+        if line =~ /^   physicaldrive (\S+) /
+          disks << Regexp.last_match(1)
+        end
+      end
+
       if device = Dir.glob("/sys/bus/pci/devices/#{controller[:pci_slot]}/cciss*").first
         controller[:device] = File.basename(device).sub(/^cciss(\d+)$/, "/dev/cciss/c\\1d0")
       elsif device = Dir.glob("/sys/bus/pci/devices/#{controller[:pci_slot]}/host*/target*:3:0/*:3:0:0/scsi_generic/sg*").first
         controller[:device] = "/dev/#{File.basename(device)}"
       if device = Dir.glob("/sys/bus/pci/devices/#{controller[:pci_slot]}/cciss*").first
         controller[:device] = File.basename(device).sub(/^cciss(\d+)$/, "/dev/cciss/c\\1d0")
       elsif device = Dir.glob("/sys/bus/pci/devices/#{controller[:pci_slot]}/host*/target*:3:0/*:3:0:0/scsi_generic/sg*").first
         controller[:device] = "/dev/#{File.basename(device)}"
-      elsif device = Dir.glob("/sys/bus/pci/devices/#{controller[:pci_slot]}/host*/target*:1:0/*:1:0:0/scsi_generic/sg*").first
+      elsif device = Dir.glob("/sys/bus/pci/devices/#{controller[:pci_slot]}/host*/target*:1:0/*:1:0:*/scsi_generic/sg*").first
         controller[:device] = "/dev/#{File.basename(device)}"
       end
     end
         controller[:device] = "/dev/#{File.basename(device)}"
       end
     end
+
+    devices[:disks].each do |disk|
+      disk[:smart_device] = "cciss,#{disks.find_index(disk[:location])}"
+
+      if disk[:status] == "Failed"
+        disk[:status] = "failed"
+      elsif disk[:status] == "Predictive Failure"
+        disk[:status] = "failed"
+      elsif disk[:status] == "OK" && disk[:drive_type] == "Data Drive"
+        disk[:status] = "online"
+      elsif disk[:status] == "OK" && disk[:drive_type] == "Spare Drive"
+        disk[:status] = "hotspare"
+      elsif disk[:drive_type] == "Unassigned Drive"
+        disk[:status] = "unconfigured"
+      else
+        disk[:status] = "unknown"
+      end
+
+      disk.delete(:drive_type)
+    end
   end
 
   def find_megaraid_disks(devices)
     controllers = []
     arrays = []
   end
 
   def find_megaraid_disks(devices)
     controllers = []
     arrays = []
+    disks = []
 
     controller = nil
     array = nil
 
     controller = nil
     array = nil
@@ -376,6 +436,7 @@ Ohai.plugin(:Hardware) do
       if line =~ /^PCI information for Controller (\d+)$/
         controller = {
           :id => devices[:controllers].count,
       if line =~ /^PCI information for Controller (\d+)$/
         controller = {
           :id => devices[:controllers].count,
+          :type => "megaraid",
           :arrays => [],
           :disks => []
         }
           :arrays => [],
           :disks => []
         }
@@ -383,11 +444,11 @@ Ohai.plugin(:Hardware) do
         devices[:controllers] << controller
 
         controllers << controller
         devices[:controllers] << controller
 
         controllers << controller
-      elsif line =~ /^Bus Number\s+:\s+(\d+)$/
+      elsif line =~ /^Bus Number\s+:\s+([0-9a-f]+)$/i
         controller[:pci_slot] = format "0000:%02x", Integer("0x#{Regexp.last_match(1)}")
         controller[:pci_slot] = format "0000:%02x", Integer("0x#{Regexp.last_match(1)}")
-      elsif line =~ /^Device Number\s+:\s+(\d+)$/
+      elsif line =~ /^Device Number\s+:\s+([0-9a-f]+)$/i
         controller[:pci_slot] = format "%s:%02x", controller[:pci_slot], Integer("0x#{Regexp.last_match(1)}")
         controller[:pci_slot] = format "%s:%02x", controller[:pci_slot], Integer("0x#{Regexp.last_match(1)}")
-      elsif line =~ /^Function Number\s+:\s+(\d+)$/
+      elsif line =~ /^Function Number\s+:\s+([0-9a-f]+)$/i
         controller[:pci_slot] = format "%s.%01x", controller[:pci_slot], Integer("0x#{Regexp.last_match(1)}")
       end
     end
         controller[:pci_slot] = format "%s.%01x", controller[:pci_slot], Integer("0x#{Regexp.last_match(1)}")
       end
     end
@@ -436,23 +497,45 @@ Ohai.plugin(:Hardware) do
         devices[:disks] << disk
         controller[:disks] << disk[:id]
         array[:disks] << disk[:id]
         devices[:disks] << disk
         controller[:disks] << disk[:id]
         array[:disks] << disk[:id]
-      elsif disk && line =~ /^Firmware state:\s+(.*\S)\s*$/
-        Regexp.last_match(1).split(/,\s*/).each do |state|
-          case state
-          when "Online" then disk[:status] = "online"
-          when "Hotspare" then disk[:status] = "hotspare"
-          when "Spun Up" then disk[:spun_down] = false
-          when "Spun down" then disk[:spun_down] = true
-          end
+
+        disks << disk
+      elsif disk && line =~ /^Firmware state:\s+(\S.*)$/
+        status, state = Regexp.last_match(1).split(/,\s*/)
+        case status
+        when "Unconfigured(good)" then disk[:status] = "unconfigured"
+        when "Unconfigured(bad)" then disk[:status] = "unconfigured"
+        when "Hotspare" then disk[:status] = "hotspare"
+        when "Offline" then disk[:status] = "offline"
+        when "Online" then disk[:status] = "online"
+        when "Rebuild" then disk[:status] = "rebuilding"
+        when "Failed" then disk[:status] = "failed"
+        when "Copyback" then disk[:status] = "rebuilding"
+        else disk[:status] = "unknown"
+        end
+        case state
+        when "Spun Up" then disk[:state] = "spun_up"
+        when "Spun down" then disk[:state] = "spun_down"
+        else disk[:state] = "unknown"
         end
       elsif disk && line =~ /^(\S.*\S)\s*:\s+(\S.*)$/
         case Regexp.last_match(1)
         end
       elsif disk && line =~ /^(\S.*\S)\s*:\s+(\S.*)$/
         case Regexp.last_match(1)
-        when "Device Id" then disk[:smart_device] = "megaraid,#{Regexp.last_match(2)}"
+        when "Device Id" then disk[:device_id] = Regexp.last_match(2)
         when "WWN" then disk[:wwn] = Regexp.last_match(2)
         when "PD Type" then disk[:interface] = Regexp.last_match(2)
         when "Raw Size" then disk[:size] = memory_to_disk_size(Regexp.last_match(2).sub(/\s*\[.*\]$/, ""))
         when "Inquiry Data" then disk[:vendor], disk[:model], disk[:serial_number] = Regexp.last_match(2).split
         end
         when "WWN" then disk[:wwn] = Regexp.last_match(2)
         when "PD Type" then disk[:interface] = Regexp.last_match(2)
         when "Raw Size" then disk[:size] = memory_to_disk_size(Regexp.last_match(2).sub(/\s*\[.*\]$/, ""))
         when "Inquiry Data" then disk[:vendor], disk[:model], disk[:serial_number] = Regexp.last_match(2).split
         end
+      elsif array && line =~ /^State\s*:\s+(.*\S)\s*$/
+        case Regexp.last_match(1)
+        when "Partially Degraded" then array[:status] = "degraded"
+        when "Degraded" then array[:status] = "degraded"
+        when "Optimal" then array[:status] = "optimal"
+        when "Consistency Check" then array[:status] = "checking"
+        when "Background Initialization" then array[:status] = "initialising"
+        when "Initialization" then array[:status] = "initialising"
+        when "Reconstruction" then array[:status] = "rebuilding"
+        else array[:status] = "unknown"
+        end
       elsif array && line =~ /^(\S.*\S)\s*:\s+(\S.*)$/
         case Regexp.last_match(1)
         when "RAID Level" then array[:raid_level] = Regexp.last_match(2).scan(/Primary-(\d+)/).first.first
       elsif array && line =~ /^(\S.*\S)\s*:\s+(\S.*)$/
         case Regexp.last_match(1)
         when "RAID Level" then array[:raid_level] = Regexp.last_match(2).scan(/Primary-(\d+)/).first.first
@@ -466,7 +549,8 @@ Ohai.plugin(:Hardware) do
         controller = controllers[Regexp.last_match(1).to_i]
       elsif controller && line =~ /^Enclosure Device ID: \d+$/
         disk = {
         controller = controllers[Regexp.last_match(1).to_i]
       elsif controller && line =~ /^Enclosure Device ID: \d+$/
         disk = {
-          :controller => controller[:id]
+          :controller => controller[:id],
+          :arrays => []
         }
       elsif disk && line =~ /^WWN:\s+(\S+)$/
         unless devices[:disks].find { |d| d[:wwn] == Regexp.last_match(1) }
         }
       elsif disk && line =~ /^WWN:\s+(\S+)$/
         unless devices[:disks].find { |d| d[:wwn] == Regexp.last_match(1) }
@@ -474,19 +558,30 @@ Ohai.plugin(:Hardware) do
           disk[:wwn] = Regexp.last_match(1)
 
           devices[:disks] << disk
           disk[:wwn] = Regexp.last_match(1)
 
           devices[:disks] << disk
+
+          disks << disk
         end
         end
-      elsif disk && line =~ /^Firmware state:\s+(.*\S)\s*$/
-        Regexp.last_match(1).split(/,\s*/).each do |state|
-          case state
-          when "Online" then disk[:status] = "online"
-          when "Hotspare" then disk[:status] = "hotspare"
-          when "Spun Up" then disk[:state] = "spun_up"
-          when "Spun down" then disk[:state] = "spun_down"
-          end
+      elsif disk && line =~ /^Firmware state:\s+(\S.*)$/
+        status, state = Regexp.last_match(1).split(/,\s*/)
+        case status
+        when "Unconfigured(good)" then disk[:status] = "unconfigured"
+        when "Unconfigured(bad)" then disk[:status] = "unconfigured"
+        when "Hotspare" then disk[:status] = "hotspare"
+        when "Offline" then disk[:status] = "offline"
+        when "Online" then disk[:status] = "online"
+        when "Rebuild" then disk[:status] = "rebuilding"
+        when "Failed" then disk[:status] = "failed"
+        when "Copyback" then disk[:status] = "rebuilding"
+        else disk[:status] = "unknown"
+        end
+        case state
+        when "Spun Up" then disk[:state] = "spun_up"
+        when "Spun down" then disk[:state] = "spun_down"
+        else disk[:state] = "unknown"
         end
       elsif disk && line =~ /^(\S.*\S)\s*:\s+(\S.*)$/
         case Regexp.last_match(1)
         end
       elsif disk && line =~ /^(\S.*\S)\s*:\s+(\S.*)$/
         case Regexp.last_match(1)
-        when "Device Id" then disk[:smart_device] = "megaraid,#{Regexp.last_match(2)}"
+        when "Device Id" then disk[:device_id] = Regexp.last_match(2)
         when "PD Type" then disk[:interface] = Regexp.last_match(2)
         when "Raw Size" then disk[:size] = memory_to_disk_size(Regexp.last_match(2).sub(/\s*\[.*\]$/, ""))
         when "Inquiry Data" then disk[:vendor], disk[:model], disk[:serial_number] = Regexp.last_match(2).split
         when "PD Type" then disk[:interface] = Regexp.last_match(2)
         when "Raw Size" then disk[:size] = memory_to_disk_size(Regexp.last_match(2).sub(/\s*\[.*\]$/, ""))
         when "Inquiry Data" then disk[:vendor], disk[:model], disk[:serial_number] = Regexp.last_match(2).split
@@ -499,15 +594,108 @@ Ohai.plugin(:Hardware) do
         controller[:device] = "/dev/#{File.basename(device)}"
       end
     end
         controller[:device] = "/dev/#{File.basename(device)}"
       end
     end
+
+    disks.each do |disk|
+      controller = devices[:controllers][disk[:controller]]
+
+      if id = disk.delete(:device_id)
+        if device = Dir.glob("/sys/bus/pci/devices/#{controller[:pci_slot]}/host*/target0:0:#{id}/0:0:#{id}:0/block/sd*").first
+          disk[:device] = "/dev/#{File.basename(device)}"
+        else
+          disk[:smart_device] = "megaraid,#{id}"
+        end
+      end
+    end
+  end
+
+  def find_mpt1_disks(devices)
+    controllers = []
+    disks = []
+
+    controller = nil
+
+    IO.popen(%w(lsiutil -s)).each do |line|
+      if line =~ /^\/proc\/mpt\/ioc(\d+)\s+LSI Logic\s+(\S+)\s+/
+        controller = {
+          :id => devices[:controllers].count,
+          :type => "mpt1",
+          :model => Regexp.last_match(1),
+          :arrays => [],
+          :disks => []
+        }
+
+        controllers << controller
+        devices[:controllers] << controller
+      elsif line =~ /^\s+(\d+)\s+(\d+)\s+PhysDisk (\d+)\s+(\S+)\s+(\S+)\s+\d+\s+(\S+)\s+/
+        disks[Regexp.last_match(3).to_i] = {
+          :id => devices[:disks].count,
+          :controller => controller[:id],
+          :vendor => Regexp.last_match(4),
+          :model => Regexp.last_match(5),
+          :sas_address => Regexp.last_match(6),
+          :arrays => []
+        }
+
+        controller[:disks] << devices[:disks].count
+        devices[:disks] << disks[Regexp.last_match(3).to_i]
+      end
+    end
+
+    controllers.each_with_index do |controller, index|
+      port = index + 1
+      array = nil
+
+      IO.popen(["lsiutil", "-p", port.to_s, "-a", "69,0"]).each do |line|
+        if line =~ /^ (\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+RAID/
+          seg = Regexp.last_match(1).to_i
+          bus = Regexp.last_match(2).to_i
+          dev = Regexp.last_match(3).to_i
+          fun = Regexp.last_match(4).to_i
+
+          controller[:pci_slot] = sprintf("%04x:%02x:%02x.%01x", seg, bus, dev, fun)
+        end
+      end
+
+      IO.popen(["lsiutil", "-p", port.to_s, "-a", "21,1,0,0"]).each do |line|
+        if line =~ /^Volume (\d+) is/
+          array = {
+            :id => devices[:arrays].count,
+            :controller => controller[:id],
+            :number => Regexp.last_match(1),
+            :disks => []
+          }
+
+          devices[:arrays] << array
+          controller[:arrays] << array[:id]
+        elsif line =~ /^  Member \d+ is PhysDisk (\d+) /
+          array[:disks] << disks[Regexp.last_match(1).to_i][:id]
+          disks[Regexp.last_match(1).to_i][:arrays] << array[:id]
+        end
+      end
+    end
+
+    disks.each do |disk|
+      slot = controllers[disk[:controller]][:pci_slot]
+      sas_address = "0x#{disk[:sas_address]}"
+
+      Dir.glob("/sys/bus/pci/devices/#{slot}/host*/port-*:*/end_device-*:*/sas_device/end_device-*:*").each do |sas_device|
+        if read_sysctl_file("#{sas_device}/sas_address") == sas_address
+          if device = Dir.glob("#{sas_device}/device/target*:0:*/*:0:*:0/scsi_generic/sg*").first
+            disk[:device] = "/dev/#{File.basename(device)}"            
+          end
+        end
+      end
+    end
   end
 
   end
 
-  def find_mpt_disks(devices)
+  def find_mpt2_disks(devices)
     controllers = []
 
     IO.popen(%w(sas2ircu list)).each do |line|
       next unless line =~ /^\s+(\d+)\s+(\S+)\s+\h+h\s+\h+h\s+(\S+)\s+\h+h\s+\h+h\s*$/
       controllers[Regexp.last_match(1).to_i] = {
         :id => devices[:controllers].count,
     controllers = []
 
     IO.popen(%w(sas2ircu list)).each do |line|
       next unless line =~ /^\s+(\d+)\s+(\S+)\s+\h+h\s+\h+h\s+(\S+)\s+\h+h\s+\h+h\s*$/
       controllers[Regexp.last_match(1).to_i] = {
         :id => devices[:controllers].count,
+        :type => "mpt2",
         :model => Regexp.last_match(2),
         :pci_slot => Regexp.last_match(3).sub(/^(\h{2})h:(\h{2})h:(\h{2})h:0(\h)h$/, "00\\1:\\2:\\3.\\4"),
         :arrays => [],
         :model => Regexp.last_match(2),
         :pci_slot => Regexp.last_match(3).sub(/^(\h{2})h:(\h{2})h:(\h{2})h:0(\h)h$/, "00\\1:\\2:\\3.\\4"),
         :arrays => [],
@@ -548,6 +736,23 @@ Ohai.plugin(:Hardware) do
           controller[:disks] << disk[:id]
 
           disks << disk
           controller[:disks] << disk[:id]
 
           disks << disk
+        elsif disk && line =~ /^  State\s+:\s+(.*\S)\s*$/
+          Regexp.last_match(1).split(/,\s*/).each do |state|
+            case state
+            when "Online (ONL)" then disk[:status] = "online"
+            when "Hot Spare (HSP)" then disk[:status] = "hotspare"
+            when "Ready (RDY)" then disk[:status] = "unconfigured"
+            when "Available (AVL)" then disk[:status] = "unconfigured"
+            when "Failed (FLD)" then disk[:status] = "failed"
+            when "Missing (MIS)" then disk[:status] = "missing"
+            when "Standby (SBY)" then disk[:status] = "unconfigured"
+            when "Out of Sync (OSY)" then disk[:status] = "degraded"
+            when "Degraded (DGD)" then disk[:status] = "degraded"
+            when "Rebuilding (RBLD)" then disk[:status] = "rebuilding"
+            when "Optimal (OPT)" then disk[:status] = "online"
+            else disk[:status] = "unknown"
+            end
+          end
         elsif disk && line =~ /^  (\S.*\S)\s+:\s+(.*\S)\s*$/
           case Regexp.last_match(1)
           when "Enclosure #" then disk[:location] = Regexp.last_match(2)
         elsif disk && line =~ /^  (\S.*\S)\s+:\s+(.*\S)\s*$/
           case Regexp.last_match(1)
           when "Enclosure #" then disk[:location] = Regexp.last_match(2)
@@ -562,6 +767,18 @@ Ohai.plugin(:Hardware) do
           end
         elsif array && line =~ /^  PHY\[\d+\] Enclosure#\/Slot#\s+:\s+(\d+:\d+)\s*$/
           array[:disks] << Regexp.last_match(1)
           end
         elsif array && line =~ /^  PHY\[\d+\] Enclosure#\/Slot#\s+:\s+(\d+:\d+)\s*$/
           array[:disks] << Regexp.last_match(1)
+        elsif array && line =~ /^  Status of volume\s+:\s+(.*\S)\s*$/
+          Regexp.last_match(1).split(/,\s*/).each do |state|
+            case state
+            when "Okay (OKY)" then array[:status] = "optimal"
+            when "Degraded (DGD)" then array[:status] = "degraded"
+            when "Failed (FLD)" then array[:status] = "failed"
+            when "Missing (MIS)" then array[:status] = "missing"
+            when "Initializing (INIT)" then array[:status] = "initialising"
+            when "Online (ONL)" then array[:status] = "optimal"
+            else array[:status] = "unknown"
+            end
+          end
         elsif array && line =~ /^  (\S.*\S)\s+:\s+(.*\S)\s*$/
           case Regexp.last_match(1)
           when "Volume wwid" then array[:device] = find_sas_device(Regexp.last_match(2))
         elsif array && line =~ /^  (\S.*\S)\s+:\s+(.*\S)\s*$/
           case Regexp.last_match(1)
           when "Volume wwid" then array[:device] = find_sas_device(Regexp.last_match(2))
@@ -594,6 +811,7 @@ Ohai.plugin(:Hardware) do
       controller = {
         :id => devices[:controllers].count,
         :number => controller_number,
       controller = {
         :id => devices[:controllers].count,
         :number => controller_number,
+        :type => "adaptec",
         :arrays => [],
         :disks => []
       }
         :arrays => [],
         :disks => []
       }
@@ -635,6 +853,16 @@ Ohai.plugin(:Hardware) do
         elsif disk && line =~ /^         Reported Channel,Device\(T:L\)\s*:\s+(\d+),(\d+)\(\d+:0\)\s*$/
           disk[:channel_number] = Regexp.last_match(1)
           disk[:device_number] = Regexp.last_match(2)
         elsif disk && line =~ /^         Reported Channel,Device\(T:L\)\s*:\s+(\d+),(\d+)\(\d+:0\)\s*$/
           disk[:channel_number] = Regexp.last_match(1)
           disk[:device_number] = Regexp.last_match(2)
+        elsif disk && line =~ /^         State\s*:\s+(\S.*\S)\s*$/
+          case Regexp.last_match(1)
+          when "Online" then disk[:status] = "online"
+          when "Online (JBOD)" then disk[:status] = "online"
+          when "Hot Spare" then disk[:status] = "hotspare"
+          when "Ready" then disk[:status] = "unconfigured"
+          when "Global Hot-Spare" then disk[:status] = "hostspare"
+          when "Dedicated Hot-Spare" then disk[:status] = "hotspare"
+          else disk[:status] = "unknown"
+        end
         elsif disk && line =~ /^         (\S.*\S)\s*:\s+(\S.*\S)\s*$/
           case Regexp.last_match(1)
           when "Reported Location" then disk[:location] = Regexp.last_match(2)
         elsif disk && line =~ /^         (\S.*\S)\s*:\s+(\S.*\S)\s*$/
           case Regexp.last_match(1)
           when "Reported Location" then disk[:location] = Regexp.last_match(2)
@@ -650,6 +878,11 @@ Ohai.plugin(:Hardware) do
           end
         elsif array && line =~ / Present \(.*((?:Connector|Enclosure):\d+,\s*(?:Device|Slot):\d+)\) /
           array[:disks] << Regexp.last_match(1).tr(":", " ").gsub(/,\s*/, ", ")
           end
         elsif array && line =~ / Present \(.*((?:Connector|Enclosure):\d+,\s*(?:Device|Slot):\d+)\) /
           array[:disks] << Regexp.last_match(1).tr(":", " ").gsub(/,\s*/, ", ")
+        elsif array && line =~ /^   Status of Logical Device\s*:\s+(\S.*\S)\s*$/
+          case Regexp.last_match(1)
+          when "Optimal" then array[:status] = "optimal"
+          else array[:status] = "unknown"
+        end
         elsif array && line =~ /^   (\S.*\S)\s*:\s+(\S.*\S)\s*$/
           case Regexp.last_match(1)
           when "RAID level" then array[:raid_level] = Regexp.last_match(2)
         elsif array && line =~ /^   (\S.*\S)\s*:\s+(\S.*\S)\s*$/
           case Regexp.last_match(1)
           when "RAID level" then array[:raid_level] = Regexp.last_match(2)
@@ -682,10 +915,11 @@ Ohai.plugin(:Hardware) do
         array[:disks].map! do |location|
           disk = disks.find { |disk| disk[:location] == location }
 
         array[:disks].map! do |location|
           disk = disks.find { |disk| disk[:location] == location }
 
+          controller_number = controller[:number] - 1
           device_number = disk[:device_number]
           device_number = disk[:device_number]
-          device = Dir.glob("#{host}/device/target*:1:#{device_number}/*:1:#{device_number}:0/scsi_generic/*").first
 
           disk[:device] = "/dev/#{File.basename(device)}"
 
           disk[:device] = "/dev/#{File.basename(device)}"
+          disk[:smart_device] = "aacraid,#{controller_number},0,#{device_number}"
 
           disk[:arrays] << array[:id]
           disk[:id]
 
           disk[:arrays] << array[:id]
           disk[:id]
@@ -697,6 +931,7 @@ Ohai.plugin(:Hardware) do
   def find_areca_disks(devices)
     controller = {
       :id => devices[:controllers].count,
   def find_areca_disks(devices)
     controller = {
       :id => devices[:controllers].count,
+      :type => "areca",
       :arrays => [],
       :disks => []
     }
       :arrays => [],
       :disks => []
     }
@@ -749,6 +984,11 @@ Ohai.plugin(:Hardware) do
           device = Dir.glob("/sys/bus/pci/devices/#{pci_slot}/host*/target*:0:0/0:#{channel}:#{id}:#{lun}/block/*").first
 
           array[:device] = "/dev/#{File.basename(device)}"
           device = Dir.glob("/sys/bus/pci/devices/#{pci_slot}/host*/target*:0:0/0:#{channel}:#{id}:#{lun}/block/*").first
 
           array[:device] = "/dev/#{File.basename(device)}"
+        elsif line =~ /^Volume State\s+:\s+(.*\S)\s*$/
+          case Regexp.last_match(1)
+          when "Normal" then array[:status] = "optimal"
+          else array[:status] = "unknown"
+          end
         elsif line =~ /^(\S.*\S)\s+:\s+(.*\S)\s*$/
           case Regexp.last_match(1)
           when "Volume Set Name" then array[:volume_set] = Regexp.last_match(2)
         elsif line =~ /^(\S.*\S)\s+:\s+(.*\S)\s*$/
           case Regexp.last_match(1)
           when "Volume Set Name" then array[:volume_set] = Regexp.last_match(2)
@@ -790,6 +1030,11 @@ Ohai.plugin(:Hardware) do
           disk[:smart_device] = "areca,#{Regexp.last_match(1)}"
         elsif line =~ /^Device Location\s+:\s+Enclosure#(\d+) Slot#?\s*0*(\d+)\s*$/i
           disk[:smart_device] = "areca,#{Regexp.last_match(2)}/#{Regexp.last_match(1)}"
           disk[:smart_device] = "areca,#{Regexp.last_match(1)}"
         elsif line =~ /^Device Location\s+:\s+Enclosure#(\d+) Slot#?\s*0*(\d+)\s*$/i
           disk[:smart_device] = "areca,#{Regexp.last_match(2)}/#{Regexp.last_match(1)}"
+        elsif line =~ /^Device State\s+:\s+(.*\S)\s*$/
+          case Regexp.last_match(1)
+          when "NORMAL" then disk[:status] = "online"
+          else disk[:status] = "unknown"
+          end
         elsif line =~ /^(\S.*\S)\s+:\s+(.*\S)\s*$/
           case Regexp.last_match(1)
           when "Model Name" then disk[:vendor], disk[:model] = Regexp.last_match(2).split
         elsif line =~ /^(\S.*\S)\s+:\s+(.*\S)\s*$/
           case Regexp.last_match(1)
           when "Model Name" then disk[:vendor], disk[:model] = Regexp.last_match(2).split