]> git.uio.no Git - check_openmanage.git/blobdiff - check_openmanage
bugfixing for get_table()
[check_openmanage.git] / check_openmanage
index be2a60d34cf8605dd7d5c87e7100aaa46c7cd0c1..b6d7709c95a4adb9651298053e6ad88b0acb5405 100755 (executable)
@@ -7,7 +7,7 @@
 #
 # $Id$
 #
-# Copyright (C) 2009 Trond H. Amundsen
+# Copyright (C) 2010 Trond H. Amundsen
 #
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -34,11 +34,11 @@ use vars qw( $NAME $VERSION $AUTHOR $CONTACT $E_OK $E_WARNING $E_CRITICAL
             $E_UNKNOWN $FW_LOCK $USAGE $HELP $LICENSE
             $snmp_session $snmp_error $omreport $globalstatus $global
             $linebreak $omopt_chassis $omopt_system $blade
-            $exit_code $snmp
+            $exit_code $snmp $original_sigwarn
             %check %opt %perfdata %reverse_exitcode %status2nagios
             %snmp_status %snmp_probestatus %probestatus2nagios %sysinfo
             %blacklist %nagios_alert_count %count
-            @controllers @enclosures
+            @perl_warnings @controllers @enclosures
             @report_storage @report_chassis @report_other
          );
 
@@ -46,17 +46,18 @@ use vars qw( $NAME $VERSION $AUTHOR $CONTACT $E_OK $E_WARNING $E_CRITICAL
 # Initialization and global variables
 #---------------------------------------------------------------------
 
-# If we don't have a TTY, the plugin is probably run by Nagios. In
-# that case, redirect all output to STDERR to STDOUT. Nagios ignores
-# output to STDERR.
-if (! isatty *STDOUT) {
-    open STDERR, '>&', 'STDOUT'
-      or do { print "ERROR: Couldn't redirect STDERR to STDOUT\n"; exit 2; }
+# Small subroutine to collect any perl warnings during execution
+sub collect_perl_warning {
+  push @perl_warnings, [@_];
 }
 
+# Set the WARN signal to use our collect subroutine above
+$original_sigwarn = $SIG{__WARN__};
+$SIG{__WARN__} = \&collect_perl_warning;
+
 # Version and similar info
 $NAME    = 'check_openmanage';
-$VERSION = '3.5.0-beta14';
+$VERSION = '3.5.6-beta6';
 $AUTHOR  = 'Trond H. Amundsen';
 $CONTACT = 't.h.amundsen@usit.uio.no';
 
@@ -99,9 +100,9 @@ OUTPUT OPTIONS:
    -i, --info          Prefix any alerts with the service tag
    -e, --extinfo       Append system info to alerts
    -s, --state         Prefix alerts with alert state
-   --short-state       Prefix alerts with alert state (abbreviated)
+   -S, --short-state   Prefix alerts with alert state (abbreviated)
    -o, --okinfo        Verbosity when check result is OK
-   --htmlinfo          HTML output with clickable links
+   -I, --htmlinfo      HTML output with clickable links
 
 CHECK CONTROL AND BLACKLISTING:
 
@@ -117,7 +118,7 @@ END_HELP
 # Version and license text
 $LICENSE = <<"END_LICENSE";
 $NAME $VERSION
-Copyright (C) 2009 $AUTHOR
+Copyright (C) 2010 $AUTHOR
 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
 This is free software: you are free to change and redistribute it.
 There is NO WARRANTY, to the extent permitted by law.
@@ -157,6 +158,7 @@ END_LICENSE
         'privpassword'      => undef, # SMNP v3
         'privkey'           => undef, # SMNP v3
         'privprotocol'      => undef, # SMNP v3
+         'use_get_table'     => 0,
        );
 
 # Get options
@@ -171,12 +173,12 @@ GetOptions('b|blacklist=s'      => \@{ $opt{blacklist} },
           'p|perfdata:s'       => \$opt{perfdata},
           'i|info'             => \$opt{info},
           'e|extinfo'          => \$opt{extinfo},
-          'htmlinfo:s'         => \$opt{htmlinfo},
+          'I|htmlinfo:s'       => \$opt{htmlinfo},
           'postmsg=s'          => \$opt{postmsg},
           's|state'            => \$opt{state},
-          'short-state'        => \$opt{shortstate},
+          'S|short-state'      => \$opt{shortstate},
           'o|ok-info=i'        => \$opt{okinfo},
-          'l|linebreak=s'      => \$opt{linebreak},
+          'linebreak=s'        => \$opt{linebreak},
           'a|all'              => \$opt{all},
           'only=s'             => \$opt{only},
           'omreport=s'         => \$opt{omreport},
@@ -191,6 +193,7 @@ GetOptions('b|blacklist=s'      => \@{ $opt{blacklist} },
           'privpassword=s'     => \$opt{privpassword},
           'privkey=s'          => \$opt{privkey},
           'privprotocol=s'     => \$opt{privprotocol},
+           'use-get_table'      => \$opt{use_get_table},
          ) or do { print $USAGE; exit $E_UNKNOWN };
 
 # If user requested help
@@ -595,7 +598,7 @@ sub snmp_detect_blade {
     # Identify blade. Older models (4th and 5th gen models) and/or old
     # OMSA (4.x) don't have this OID. If we get "noSuchInstance" or
     # similar, we assume that this isn't a blade
-    if ($result->{$DellBaseBoardType} eq '3') {
+    if (exists $result->{$DellBaseBoardType} && $result->{$DellBaseBoardType} eq '3') {
        $blade = 1;
     }
     return;
@@ -607,7 +610,7 @@ sub snmp_detect_blade {
 sub find_omreport {
     # If user has specified path to omreport
     if (defined $opt{omreport} and -x $opt{omreport}) {
-       $omreport = $opt{omreport};
+       $omreport = qq{"$opt{omreport}"};
        return;
     }
 
@@ -615,6 +618,7 @@ sub find_omreport {
     my @omreport_paths
       = (
         '/usr/bin/omreport',                            # default on Linux
+        '/opt/dell/srvadmin/bin/omreport',              # default on Linux with OMSA 6.2.0
         '/opt/dell/srvadmin/oma/bin/omreport.sh',       # alternate on Linux
         '/opt/dell/srvadmin/oma/bin/omreport',          # alternate on Linux
         'C:\Program Files (x86)\Dell\SysMgt\oma\bin\omreport.exe', # default on Windows x64
@@ -627,7 +631,7 @@ sub find_omreport {
   OMREPORT_PATH:
     foreach my $bin (@omreport_paths) {
        if (-x $bin) {
-           $omreport = $bin;
+           $omreport = qq{"$bin"};
            last OMREPORT_PATH;
        }
     }
@@ -741,7 +745,7 @@ sub adjust_checks {
            print qq{ERROR: Wrong simultaneous usage of the "--only" and "--check" options\n};
            exit $E_UNKNOWN;
        }
-       if (! exists $check{$opt{only}} and $opt{only} ne 'chassis') {
+       if (! exists $check{$opt{only}} && $opt{only} ne 'chassis') {
            print qq{ERROR: "$opt{only}" is not a known keyword for the "--only" option\n};
            exit $E_UNKNOWN;
        }
@@ -825,6 +829,7 @@ sub run_omreport {
           | No\scontrollers\sfound                                     # No RAID controller
           | No\sbattery\sprobes\sfound\son\sthis\ssystem               # No battery probes
           | Invalid\scommand:\spwrmonitoring                           # Older OMSAs lack this command(?)
+#          | Current\sprobes\snot\sfound                                # OMSA + RHEL5.4 bug
         }xms;
 
     # Errors that are OK on blade servers
@@ -838,11 +843,15 @@ sub run_omreport {
     return [] if !defined $rawtext;
 
     # Workaround for Openmanage BUG introduced in OMSA 5.5.0
-    $rawtext =~ s/\n;/;/gxms if $command eq 'storage controller';
+    $rawtext =~ s{\n;}{;}gxms if $command eq 'storage controller';
+
+    # Openmanage sometimes puts a linebreak between "Error" and the
+    # actual error text
+    $rawtext =~ s{^Error\s*\n}{Error: }xms;
 
     # Parse output, store in array
-    for ((split /\n/xms, $rawtext)) {
-       if (m/\A Error/xms) {
+    for ((split m{\n}xms, $rawtext)) {
+       if (m{\AError}xms) {
            next if m{$ok_errors}xms;
            next if ($blade and m{$ok_blade_errors}xms);
            report('other', "Problem running 'omreport $command': $_", $E_UNKNOWN);
@@ -850,7 +859,7 @@ sub run_omreport {
 
        next if !m/(.*?;){2}/xms;  # ignore lines with less than 3 fields
        my @vals = split /;/xms;
-       if ($vals[0] =~ m/\A (Index|ID|Severity) \z/xms) {
+       if ($vals[0] =~ m/\A (Index|ID|Severity|Processor|Current\sSpeed) \z/xms) {
            @keys = @vals;
        }
        else {
@@ -878,7 +887,7 @@ sub blacklisted {
 
     if (defined $blacklist{$name}) {
        foreach my $comp (@{ $blacklist{$name} }) {
-           if (defined $id and $comp eq $id) {
+           if (defined $id and ($comp eq $id or uc($comp) eq 'ALL')) {
                $ret = 1;
            }
        }
@@ -944,17 +953,26 @@ sub custom_temperature_thresholds {
 # Gets the output from SNMP result according to the OIDs checked
 sub get_snmp_output {
     my ($result,$oidref) = @_;
+    my @temp   = ();
     my @output = ();
 
     foreach my $oid (keys %{ $result }) {
-       my @dummy = split /\./xms, $oid;
-       my $id = pop @dummy;
-       --$id;
-       my $foo = join q{.}, @dummy;
-       if (exists $oidref->{$foo}) {
-           $output[$id]{$oidref->{$foo}} = $result->{$oid};
+       my $short = $oid;
+       $short =~ s{\s}{}gxms;                   # remove whitespace
+       $short =~ s{\A (.+) \. (\d+) \z}{$1}xms; # remove last number
+       my $id = $2;
+       if (exists $oidref->{$short}) {
+           $temp[$id]{$oidref->{$short}} = $result->{$oid};
        }
     }
+
+    # Remove any empty indexes
+    foreach my $out (@temp) {
+       if (defined $out) {
+           push @output, $out;
+       }
+    }
+
     return \@output;
 }
 
@@ -1091,6 +1109,8 @@ sub check_global {
 # STORAGE: Check controllers
 #-----------------------------------------
 sub check_controllers {
+    return if blacklisted('ctrl', 'all');
+
     my $id       = undef;
     my $nexus    = undef;
     my $name     = undef;
@@ -1100,6 +1120,8 @@ sub check_controllers {
     my $mindr    = undef;
     my $firmware = undef;
     my $driver   = undef;
+    my $minstdr  = undef;  # Minimum required Storport driver version
+    my $stdr     = undef;  # Storport driver version
     my @output   = ();
 
     if ($snmp) {
@@ -1114,6 +1136,8 @@ sub check_controllers {
             '1.3.6.1.4.1.674.10893.1.20.130.1.1.41' => 'controllerDriverVersion',
             '1.3.6.1.4.1.674.10893.1.20.130.1.1.44' => 'controllerMinFWVersion',
             '1.3.6.1.4.1.674.10893.1.20.130.1.1.45' => 'controllerMinDriverVersion',
+            '1.3.6.1.4.1.674.10893.1.20.130.1.1.55' => 'FIXME_StorportDriverVersion',
+            '1.3.6.1.4.1.674.10893.1.20.130.1.1.56' => 'FIXME_StorportMinDriverVersion',
            );
 
        # We use get_table() here for the odd case where a server has
@@ -1144,18 +1168,22 @@ sub check_controllers {
   CTRL:
     foreach my $out (@output) {
        if ($snmp) {
-           $id       = $out->{'controllerNumber'} - 1;
-           $name     = $out->{'controllerName'};
-           $state    = $ctrl_state{$out->{'controllerState'}};
-           $status   = $snmp_status{$out->{'controllerComponentStatus'}};
-           $minfw    = exists $out->{'controllerMinFWVersion'}
-             ? $out->{'controllerMinFWVersion'} : undef;
-           $mindr    = exists $out->{'controllerMinDriverVersion'}
-             ? $out->{'controllerMinDriverVersion'} : undef;
+           $id       = $out->{controllerNumber} - 1;
+           $name     = $out->{controllerName};
+           $state    = $ctrl_state{$out->{controllerState}};
+           $status   = $snmp_status{$out->{controllerComponentStatus}};
+           $minfw    = exists $out->{controllerMinFWVersion}
+             ? $out->{controllerMinFWVersion} : undef;
+           $mindr    = exists $out->{controllerMinDriverVersion}
+             ? $out->{controllerMinDriverVersion} : undef;
            $firmware = exists $out->{controllerFWVersion}
              ? $out->{controllerFWVersion} : 'N/A';
            $driver   = exists $out->{controllerDriverVersion}
              ? $out->{controllerDriverVersion} : 'N/A';
+           $minstdr  = exists $out->{'FIXME_StorportMinDriverVersion'}
+             ? $out->{FIXME_StorportMinDriverVersion} : undef;
+           $stdr     = exists $out->{FIXME_StorportDriverVersion}
+             ? $out->{FIXME_StorportDriverVersion} : undef;
            $nexus    = convert_nexus($out->{controllerNexusID});
        }
        else {
@@ -1171,6 +1199,12 @@ sub check_controllers {
              ? $out->{'Firmware Version'} : 'N/A';
            $driver   = $out->{'Driver Version'} ne 'Not Applicable'
              ? $out->{'Driver Version'} : 'N/A';
+           $minstdr  = (exists $out->{'Minimum Required Storport Driver Version'}
+                        and $out->{'Minimum Required Storport Driver Version'} ne 'Not Applicable')
+             ? $out->{'Minimum Required Storport Driver Version'} : undef;
+           $stdr     = (exists $out->{'Storport Driver Version'}
+                        and $out->{'Storport Driver Version'} ne 'Not Applicable')
+             ? $out->{'Storport Driver Version'} : undef;
            $nexus    = $id;
        }
 
@@ -1182,6 +1216,7 @@ sub check_controllers {
        $sysinfo{'controller'}{$id}{'name'}     = $name;
        $sysinfo{'controller'}{$id}{'driver'}   = $driver;
        $sysinfo{'controller'}{$id}{'firmware'} = $firmware;
+       $sysinfo{'controller'}{$id}{'storport'} = $stdr;
 
        next CTRL if blacklisted('ctrl', $nexus);
 
@@ -1199,9 +1234,16 @@ sub check_controllers {
              $id, $name, $driver;
            report('storage', $msg, $E_WARNING, $nexus);
        }
+       # Special case: old storport driver
+       if (!blacklisted('ctrl_stdr', $id) && defined $minstdr) {
+           chomp $stdr;
+           my $msg = sprintf q{Controller %d [%s]: Storport driver '%s' is out of date},
+             $id, $name, $stdr;
+           report('storage', $msg, $E_WARNING, $nexus);
+       }
        # Ok
        if ($status eq 'Ok' or ($status eq 'Non-Critical'
-                               and (defined $minfw or defined $mindr))) {
+                               and (defined $minfw or defined $mindr or defined $minstdr))) {
            my $msg = sprintf 'Controller %d [%s] is %s',
              $id, $name, $state;
            report('storage', $msg, $E_OK, $nexus);
@@ -1222,6 +1264,7 @@ sub check_controllers {
 #-----------------------------------------
 sub check_physical_disks {
     return if $#controllers == -1;
+    return if blacklisted('pdisk', 'all');
 
     my $id       = undef;
     my $nexus    = undef;
@@ -1252,10 +1295,27 @@ sub check_physical_disks {
             '1.3.6.1.4.1.674.10893.1.20.130.4.1.24' => 'arrayDiskComponentStatus',
             '1.3.6.1.4.1.674.10893.1.20.130.4.1.26' => 'arrayDiskNexusID',
             '1.3.6.1.4.1.674.10893.1.20.130.4.1.31' => 'arrayDiskSmartAlertIndication',
-            '1.3.6.1.4.1.674.10893.1.20.130.5.1.5'  => 'arrayDiskEnclosureConnectionEnclosureNumber',
             '1.3.6.1.4.1.674.10893.1.20.130.5.1.7'  => 'arrayDiskEnclosureConnectionControllerNumber',
+            '1.3.6.1.4.1.674.10893.1.20.130.6.1.7'  => 'arrayDiskChannelConnectionControllerNumber',
            );
-       my $result = $snmp_session->get_entries(-columns => [keys %pdisk_oid]);
+       my $result = undef;
+       if ($opt{use_get_table}) {
+           my $arrayDiskTable = '1.3.6.1.4.1.674.10893.1.20.130.4';
+           my $arrayDiskEnclosureConnectionControllerNumber = '1.3.6.1.4.1.674.10893.1.20.130.5.1.7';
+           my $arrayDiskChannelConnectionControllerNumber = '1.3.6.1.4.1.674.10893.1.20.130.6.1.7';
+
+           $result  = $snmp_session->get_table(-baseoid => $arrayDiskTable);
+           my $ext1 = $snmp_session->get_table(-baseoid => $arrayDiskEnclosureConnectionControllerNumber);
+           my $ext2 = $snmp_session->get_table(-baseoid => $arrayDiskChannelConnectionControllerNumber);
+
+           if (defined $result) {
+               defined $ext1 && map { $$result{$_} = $$ext1{$_} } keys %{ $ext1 };
+               defined $ext2 && map { $$result{$_} = $$ext2{$_} } keys %{ $ext2 };
+           }
+       }
+       else {
+           $result = $snmp_session->get_entries(-columns => [keys %pdisk_oid]);
+       }
 
        if (!defined $result) {
            printf "SNMP ERROR [storage / pdisk]: %s.\n", $snmp_session->error;
@@ -1267,6 +1327,10 @@ sub check_physical_disks {
     }
     else {
        foreach my $c (@controllers) {
+           # This blacklists disks with broken firmware, which includes
+           # illegal XML characters that makes openmanage choke on itself
+           next if blacklisted('ctrl_pdisk', $c);
+
            push @output, @{ run_omreport("storage pdisk controller=$c") };
            map_item('ctrl', $c, \@output);
        }
@@ -1300,9 +1364,9 @@ sub check_physical_disks {
     foreach my $out (@output) {
        if ($snmp) {
            $name   = $out->{arrayDiskName};
-           if ($name =~ m{.*\d+:\d+:\d+\z}xms) {
+           if (exists $out->{arrayDiskEnclosureID}) {
                $id = join q{:}, ($out->{arrayDiskChannel}, $out->{arrayDiskEnclosureID},
-                                $out->{arrayDiskTargetID});
+                                 $out->{arrayDiskTargetID});
            }
            else {
                $id = join q{:}, ($out->{arrayDiskChannel}, $out->{arrayDiskTargetID});
@@ -1311,13 +1375,19 @@ sub check_physical_disks {
            $status   = $snmp_status{$out->{arrayDiskComponentStatus}};
            $fpred    = $out->{arrayDiskSmartAlertIndication} == 2 ? 1 : 0;
            $progr    = q{};
-           $ctrl     = exists $out->{arrayDiskEnclosureConnectionControllerNumber}
-             ? $out->{arrayDiskEnclosureConnectionControllerNumber} - 1
-               : -1;
            $nexus    = convert_nexus($out->{arrayDiskNexusID});
            $vendor   = $out->{arrayDiskVendor};
            $product  = $out->{arrayDiskProductID};
            $capacity = $out->{arrayDiskLengthInMB} * 1024**2;
+           if (exists $out->{arrayDiskEnclosureConnectionControllerNumber}) {
+               $ctrl = $out->{arrayDiskEnclosureConnectionControllerNumber} - 1;
+           }
+           elsif (exists $out->{arrayDiskChannelConnectionControllerNumber}) {
+               $ctrl = $out->{arrayDiskChannelConnectionControllerNumber} - 1;
+           }
+           else {
+               $ctrl = -1;
+           }
        }
        else {
            $id       = $out->{'ID'};
@@ -1345,8 +1415,8 @@ sub check_physical_disks {
           ? sprintf '%.1fTB', ($capacity / 1000**4)
            : sprintf '%.0fGB', ($capacity / 1000**3);
        $capacity = '450GB' if $capacity eq '449GB';  # quick fix for 450GB disks
+       $capacity = '300GB' if $capacity eq '299GB';  # quick fix for 300GB disks
        $capacity = '146GB' if $capacity eq '147GB';  # quick fix for 146GB disks
-       $capacity = '300GB' if $capacity eq '299GB';  # quick fix for 146GB disks
 
        # Capitalize only the first letter of the vendor name
        $vendor = (substr $vendor, 0, 1) . lc (substr $vendor, 1, length $vendor);
@@ -1388,6 +1458,7 @@ sub check_physical_disks {
 #-----------------------------------------
 sub check_virtual_disks {
     return if $#controllers == -1;
+    return if blacklisted('vdisk', 'all');
 
     my $id     = undef;
     my $name   = undef;
@@ -1412,7 +1483,14 @@ sub check_virtual_disks {
             '1.3.6.1.4.1.674.10893.1.20.140.1.1.20' => 'virtualDiskComponentStatus',
             '1.3.6.1.4.1.674.10893.1.20.140.1.1.21' => 'virtualDiskNexusID',
            );
-       my $result = $snmp_session->get_entries(-columns => [keys %vdisk_oid]);
+       my $result = undef;
+       if ($opt{use_get_table}) {
+           my $virtualDiskTable = '1.3.6.1.4.1.674.10893.1.20.140.1';
+           $result = $snmp_session->get_table(-baseoid => $virtualDiskTable);
+       }
+       else {
+           $result = $snmp_session->get_entries(-columns => [keys %vdisk_oid]);
+       }
 
        # No logical drives is OK
        return if !defined $result;
@@ -1490,6 +1568,9 @@ sub check_virtual_disks {
        next VDISK if blacklisted('vdisk', $nexus);
        $count{vdisk}++;
 
+       # The device name is undefined sometimes
+       $dev = q{} if !defined $dev;
+
        # Special case: Regenerating
        if ($state eq 'Regenerating') {
            my $msg = sprintf q{Logical drive %d '%s' [%s, %s] on ctrl %d is %s%s},
@@ -1518,6 +1599,7 @@ sub check_virtual_disks {
 #-----------------------------------------
 sub check_cache_battery {
     return if $#controllers == -1;
+    return if blacklisted('bat', 'all');
 
     my $id     = undef;
     my $nexus  = undef;
@@ -1538,7 +1620,21 @@ sub check_cache_battery {
             '1.3.6.1.4.1.674.10893.1.20.130.15.1.12' => 'batteryLearnState',
             '1.3.6.1.4.1.674.10893.1.20.130.16.1.5'  => 'batteryConnectionControllerNumber',
            );
-       my $result = $snmp_session->get_entries(-columns => [keys %bat_oid]);
+       my $result = undef;
+       if ($opt{use_get_table}) {
+           my $batteryTable = '1.3.6.1.4.1.674.10893.1.20.130.15';
+            my $batteryConnectionTable = '1.3.6.1.4.1.674.10893.1.20.130.16';
+
+           $result = $snmp_session->get_table(-baseoid => $batteryTable);
+            my $ext = $snmp_session->get_table(-baseoid => $batteryConnectionTable);
+
+           if (defined $result) {
+                defined $ext && map { $$result{$_} = $$ext{$_} } keys %{ $ext };
+            }
+       }
+       else {
+           $result = $snmp_session->get_entries(-columns => [keys %bat_oid]);
+       }
 
        # No cache battery is OK
        return if !defined $result;
@@ -1566,6 +1662,7 @@ sub check_cache_battery {
         36 => 'Learning',
        );
 
+    # Specifies the learn state activity of the battery
     my %bat_learn_state
       = (
         1  => 'Failed',
@@ -1575,6 +1672,7 @@ sub check_cache_battery {
         16 => 'Idle',
        );
 
+    # This property displays the battery's ability to be charged
     my %bat_pred_cap
       = (
         1 => 'Failed',  # The battery cannot be charged and needs to be replaced
@@ -1612,22 +1710,46 @@ sub check_cache_battery {
 
        # Special case: Charging
        if ($state eq 'Charging') {
-           my $msg = sprintf 'Cache battery %d in controller %d is %s (%s) [probably harmless]',
-             $id, $ctrl, $state, $pred;
-           report('storage', $msg, $E_WARNING, $nexus);
+           if ($pred eq 'Failed') {
+               my $msg = sprintf 'Cache battery %d in controller %d is %s (%s) [replace battery]',
+                 $id, $ctrl, $state, $pred;
+               report('storage', $msg, $E_CRITICAL, $nexus);
+           }
+           else {
+               next BATTERY if blacklisted('bat_charge', $nexus);
+               my $msg = sprintf 'Cache battery %d in controller %d is %s (%s) [probably harmless]',
+                 $id, $ctrl, $state, $pred;
+               report('storage', $msg, $E_WARNING, $nexus);
+           }
        }
        # Special case: Learning (battery learns its capacity)
        elsif ($state eq 'Learning') {
-           my $msg = sprintf 'Cache battery %d in controller %d is %s (%s) [probably harmless]',
-             $id, $ctrl, $state, $learn;
-           report('storage', $msg, $E_WARNING, $nexus);
+           if ($learn eq 'Failed') {
+               my $msg = sprintf 'Cache battery %d in controller %d is %s (%s)',
+                 $id, $ctrl, $state, $learn;
+               report('storage', $msg, $E_CRITICAL, $nexus);
+           }
+           else {
+               next BATTERY if blacklisted('bat_charge', $nexus);
+               my $msg = sprintf 'Cache battery %d in controller %d is %s (%s) [probably harmless]',
+                 $id, $ctrl, $state, $learn;
+               report('storage', $msg, $E_WARNING, $nexus);
+           }
        }
        # Special case: Power Low (first part of recharge cycle)
        elsif ($state eq 'Power Low') {
+           next BATTERY if blacklisted('bat_charge', $nexus);
            my $msg = sprintf 'Cache battery %d in controller %d is %s [probably harmless]',
              $id, $ctrl, $state;
            report('storage', $msg, $E_WARNING, $nexus);
        }
+       # Special case: Degraded and Non-Critical (usually part of recharge cycle)
+       elsif ($state eq 'Degraded' && $status eq 'Non-Critical') {
+           next BATTERY if blacklisted('bat_charge', $nexus);
+           my $msg = sprintf 'Cache battery %d in controller %d is %s (%s) [probably harmless]',
+             $id, $ctrl, $state, $status;
+           report('storage', $msg, $E_WARNING, $nexus);
+       }
        # Default
        elsif ($status ne 'Ok') {
            my $msg = sprintf 'Cache battery %d in controller %d needs attention: %s (%s)',
@@ -1650,6 +1772,7 @@ sub check_cache_battery {
 #-----------------------------------------
 sub check_connectors {
     return if $#controllers == -1;
+    return if blacklisted('conn', 'all');
 
     my $id     = undef;
     my $nexus  = undef;
@@ -1670,7 +1793,14 @@ sub check_connectors {
             '1.3.6.1.4.1.674.10893.1.20.130.2.1.9'  => 'channelNexusID',
              '1.3.6.1.4.1.674.10893.1.20.130.2.1.11' => 'channelBusType',
             );
-        my $result = $snmp_session->get_entries(-columns => [keys %conn_oid]);
+       my $result = undef;
+       if ($opt{use_get_table}) {
+           my $channelTable = '1.3.6.1.4.1.674.10893.1.20.130.2';
+           $result = $snmp_session->get_table(-baseoid => $channelTable);
+       }
+       else {
+           $result = $snmp_session->get_entries(-columns => [keys %conn_oid]);
+       }
 
         if (!defined $result) {
             printf "SNMP ERROR [storage / channel]: %s.\n", $snmp_session->error;
@@ -1745,6 +1875,8 @@ sub check_connectors {
 # STORAGE: Check enclosures
 #-----------------------------------------
 sub check_enclosures {
+    return if blacklisted('encl', 'all');
+
     my $id       = undef;
     my $nexus    = undef;
     my $name     = undef;
@@ -1765,7 +1897,14 @@ sub check_enclosures {
             '1.3.6.1.4.1.674.10893.1.20.130.3.1.25' => 'enclosureNexusID',
             '1.3.6.1.4.1.674.10893.1.20.130.3.1.26' => 'enclosureFirmwareVersion',
             );
-        my $result = $snmp_session->get_entries(-columns => [keys %encl_oid]);
+       my $result = undef;
+       if ($opt{use_get_table}) {
+           my $enclosureTable = '1.3.6.1.4.1.674.10893.1.20.130.3';
+           $result = $snmp_session->get_table(-baseoid => $enclosureTable);
+       }
+       else {
+           $result = $snmp_session->get_entries(-columns => [keys %encl_oid]);
+       }
 
         # No enclosures is OK
         return if !defined $result;
@@ -1841,6 +1980,7 @@ sub check_enclosures {
 #-----------------------------------------
 sub check_enclosure_fans {
     return if $#controllers == -1;
+    return if blacklisted('encl_fan', 'all');
 
     my $id        = undef;
     my $nexus     = undef;
@@ -1864,8 +2004,21 @@ sub check_enclosure_fans {
             '1.3.6.1.4.1.674.10893.1.20.130.8.1.4'  => 'fanConnectionEnclosureName',
             '1.3.6.1.4.1.674.10893.1.20.130.8.1.5'  => 'fanConnectionEnclosureNumber',
            );
+       my $result = undef;
+       if ($opt{use_get_table}) {
+           my $fanTable = '1.3.6.1.4.1.674.10893.1.20.130.7';
+            my $fanConnectionTable = '1.3.6.1.4.1.674.10893.1.20.130.8';
+
+           $result = $snmp_session->get_table(-baseoid => $fanTable);
+            my $ext = $snmp_session->get_table(-baseoid => $fanConnectionTable);
 
-       my $result = $snmp_session->get_entries(-columns => [keys %fan_oid]);
+           if (defined $result) {
+                defined $ext && map { $$result{$_} = $$ext{$_} } keys %{ $ext };
+            }
+       }
+       else {
+           $result = $snmp_session->get_entries(-columns => [keys %fan_oid]);
+       }
 
        # No enclosure fans is OK
        return if !defined $result;
@@ -1940,6 +2093,7 @@ sub check_enclosure_fans {
 #-----------------------------------------
 sub check_enclosure_pwr {
     return if $#controllers == -1;
+    return if blacklisted('encl_ps', 'all');
 
     my $id        = undef;
     my $nexus     = undef;
@@ -1961,7 +2115,21 @@ sub check_enclosure_pwr {
             '1.3.6.1.4.1.674.10893.1.20.130.10.1.4' => 'powerSupplyConnectionEnclosureName',
             '1.3.6.1.4.1.674.10893.1.20.130.10.1.5' => 'powerSupplyConnectionEnclosureNumber',
            );
-       my $result = $snmp_session->get_entries(-columns => [keys %ps_oid]);
+       my $result = undef;
+       if ($opt{use_get_table}) {
+           my $powerSupplyTable = '1.3.6.1.4.1.674.10893.1.20.130.9';
+            my $powerSupplyConnectionTable = '1.3.6.1.4.1.674.10893.1.20.130.10';
+
+           $result = $snmp_session->get_table(-baseoid => $powerSupplyTable);
+            my $ext = $snmp_session->get_table(-baseoid => $powerSupplyConnectionTable);
+
+           if (defined $result) {
+                defined $ext && map { $$result{$_} = $$ext{$_} } keys %{ $ext };
+            }
+       }
+       else {
+           $result = $snmp_session->get_entries(-columns => [keys %ps_oid]);
+       }
 
        # No enclosure power supplies is OK
        return if !defined $result;
@@ -2034,6 +2202,7 @@ sub check_enclosure_pwr {
 #-----------------------------------------
 sub check_enclosure_temp {
     return if $#controllers == -1;
+    return if blacklisted('encl_temp', 'all');
 
     my $id        = undef;
     my $nexus     = undef;
@@ -2063,7 +2232,21 @@ sub check_enclosure_temp {
             '1.3.6.1.4.1.674.10893.1.20.130.12.1.4'  => 'temperatureConnectionEnclosureName',
             '1.3.6.1.4.1.674.10893.1.20.130.12.1.5'  => 'temperatureConnectionEnclosureNumber',
            );
-       my $result = $snmp_session->get_entries(-columns => [keys %temp_oid]);
+       my $result = undef;
+       if ($opt{use_get_table}) {
+           my $temperatureProbeTable = '1.3.6.1.4.1.674.10893.1.20.130.11';
+            my $temperatureConnectionTable = '1.3.6.1.4.1.674.10893.1.20.130.12';
+
+           $result = $snmp_session->get_table(-baseoid => $temperatureProbeTable);
+            my $ext = $snmp_session->get_table(-baseoid => $temperatureConnectionTable);
+
+           if (defined $result) {
+                defined $ext && map { $$result{$_} = $$ext{$_} } keys %{ $ext };
+            }
+       }
+       else {
+           $result = $snmp_session->get_entries(-columns => [keys %temp_oid]);
+       }
 
        # No enclosure temperature probes is OK
        return if !defined $result;
@@ -2152,6 +2335,7 @@ sub check_enclosure_temp {
 #-----------------------------------------
 sub check_enclosure_emms {
     return if $#controllers == -1;
+    return if blacklisted('encl_emm', 'all');
 
     my $id        = undef;
     my $nexus     = undef;
@@ -2173,7 +2357,21 @@ sub check_enclosure_emms {
             '1.3.6.1.4.1.674.10893.1.20.130.14.1.4'  => 'enclosureManagementModuleConnectionEnclosureName',
             '1.3.6.1.4.1.674.10893.1.20.130.14.1.5'  => 'enclosureManagementModuleConnectionEnclosureNumber',
            );
-       my $result = $snmp_session->get_entries(-columns => [keys %emms_oid]);
+       my $result = undef;
+       if ($opt{use_get_table}) {
+           my $enclosureManagementModuleTable = '1.3.6.1.4.1.674.10893.1.20.130.13';
+            my $enclosureManagementModuleConnectionTable = '1.3.6.1.4.1.674.10893.1.20.130.14';
+
+           $result = $snmp_session->get_table(-baseoid => $enclosureManagementModuleTable);
+            my $ext = $snmp_session->get_table(-baseoid => $enclosureManagementModuleConnectionTable);
+
+           if (defined $result) {
+                defined $ext && map { $$result{$_} = $$ext{$_} } keys %{ $ext };
+            }
+       }
+       else {
+           $result = $snmp_session->get_entries(-columns => [keys %emms_oid]);
+       }
 
        # No enclosure EMMs is OK
        return if !defined $result;
@@ -2246,6 +2444,8 @@ sub check_enclosure_emms {
 # CHASSIS: Check memory modules
 #-----------------------------------------
 sub check_memory {
+    return if blacklisted('dimm', 'all');
+
     my $index    = undef;
     my $status   = undef;
     my $location = undef;
@@ -2263,7 +2463,14 @@ sub check_memory {
             '1.3.6.1.4.1.674.10892.1.1100.50.1.14.1' => 'memoryDeviceSize',
             '1.3.6.1.4.1.674.10892.1.1100.50.1.20.1' => 'memoryDeviceFailureModes',
            );
-       my $result = $snmp_session->get_entries(-columns => [keys %dimm_oid]);
+       my $result = undef;
+       if ($opt{use_get_table}) {
+           my $memoryDeviceTable = '1.3.6.1.4.1.674.10892.1.1100.50.1';
+           $result = $snmp_session->get_table(-baseoid => $memoryDeviceTable);
+       }
+       else {
+           $result = $snmp_session->get_entries(-columns => [keys %dimm_oid]);
+       }
 
        if (!defined $result) {
            printf "SNMP ERROR [memory]: %s.\n", $snmp_session->error;
@@ -2357,6 +2564,8 @@ sub check_memory {
 # CHASSIS: Check fans
 #-----------------------------------------
 sub check_fans {
+    return if blacklisted('fan', 'all');
+
     my $index    = undef;
     my $status   = undef;
     my $reading  = undef;
@@ -2375,7 +2584,14 @@ sub check_fans {
             '1.3.6.1.4.1.674.10892.1.700.12.1.10.1' => 'coolingDeviceUpperCriticalThreshold',
             '1.3.6.1.4.1.674.10892.1.700.12.1.11.1' => 'coolingDeviceUpperNonCriticalThreshold',
            );
-       my $result = $snmp_session->get_entries(-columns => [keys %cool_oid]);
+       my $result = undef;
+       if ($opt{use_get_table}) {
+           my $coolingDeviceTable = '1.3.6.1.4.1.674.10892.1.700.12.1';
+           $result = $snmp_session->get_table(-baseoid => $coolingDeviceTable);
+       }
+       else {
+           $result = $snmp_session->get_entries(-columns => [keys %cool_oid]);
+       }
 
        if ($blade && !defined $result) {
            return 0;
@@ -2451,6 +2667,8 @@ sub check_fans {
 # CHASSIS: Check power supplies
 #-----------------------------------------
 sub check_powersupplies {
+    return if blacklisted('ps', 'all');
+
     my $index    = undef;
     my $status   = undef;
     my $type     = undef;
@@ -2468,7 +2686,14 @@ sub check_powersupplies {
             '1.3.6.1.4.1.674.10892.1.600.12.1.11.1' => 'powerSupplySensorState',
             '1.3.6.1.4.1.674.10892.1.600.12.1.12.1' => 'powerSupplyConfigurationErrorType',
            );
-       my $result = $snmp_session->get_entries(-columns => [keys %ps_oid]);
+       my $result = undef;
+       if ($opt{use_get_table}) {
+           my $powerDeviceTable = '1.3.6.1.4.1.674.10892.1.600.12.1';
+           $result = $snmp_session->get_table(-baseoid => $powerDeviceTable);
+       }
+       else {
+           $result = $snmp_session->get_entries(-columns => [keys %ps_oid]);
+       }
 
        # No instrumented PSU is OK (blades, low-end servers)
        return 0 if !defined $result;
@@ -2567,6 +2792,8 @@ sub check_powersupplies {
 # CHASSIS: Check temperatures
 #-----------------------------------------
 sub check_temperatures {
+    return if blacklisted('temp', 'all');
+
     my $index    = undef;
     my $status   = undef;
     my $reading  = undef;
@@ -2723,7 +2950,7 @@ sub check_temperatures {
                else {
                    $msg .= sprintf ' (min=%s/%s, max=%s/%s)',
                      $min_warn, $min_crit, $max_warn, $max_crit;
-               }                   
+               }
                my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
                report('chassis', $msg, $err, $index);
            }
@@ -2748,38 +2975,48 @@ sub check_temperatures {
 # CHASSIS: Check processors
 #-----------------------------------------
 sub check_processors {
+    return if blacklisted('cpu', 'all');
+
     my $index   = undef;
     my $status  = undef;
     my $state   = undef;
-    my $oid_ver = 'new';
-    my @output  = ();
+    my $brand   = undef;
+    my $family  = undef;
+    my $man     = undef;
+    my $speed   = undef;
+    my @output = ();
 
     if ($snmp) {
 
        # NOTE: For some reason, older models don't have the
-       # "Processor Device Status" OIDs. We first check the newer
-       # (preferred) OIDs, and if that doesn't work, check the "old"
-       # OIDs.
-
-       my %cpu_oid_new  # for newer models
-         = (
-            '1.3.6.1.4.1.674.10892.1.1100.32.1.2.1' => 'processorDeviceStatusIndex',
-            '1.3.6.1.4.1.674.10892.1.1100.32.1.5.1' => 'processorDeviceStatusStatus',
-            '1.3.6.1.4.1.674.10892.1.1100.32.1.6.1' => 'processorDeviceStatusReading',
-           );
+       # "Processor Device Status" OIDs. We check both the newer
+       # (preferred) OIDs and the old ones.
 
-       my %cpu_oid_old  # for older models
+       my %cpu_oid
          = (
-             '1.3.6.1.4.1.674.10892.1.1100.30.1.2.1' => 'processorDeviceIndex',
-             '1.3.6.1.4.1.674.10892.1.1100.30.1.5.1' => 'processorDeviceStatus',
-             '1.3.6.1.4.1.674.10892.1.1100.30.1.9.1' => 'processorDeviceStatusState',
+             '1.3.6.1.4.1.674.10892.1.1100.30.1.2.1'  => 'processorDeviceIndex',
+             '1.3.6.1.4.1.674.10892.1.1100.30.1.5.1'  => 'processorDeviceStatus',
+             '1.3.6.1.4.1.674.10892.1.1100.30.1.8.1'  => 'processorDeviceManufacturerName',
+             '1.3.6.1.4.1.674.10892.1.1100.30.1.9.1'  => 'processorDeviceStatusState',
+             '1.3.6.1.4.1.674.10892.1.1100.30.1.10.1' => 'processorDeviceFamily',
+             '1.3.6.1.4.1.674.10892.1.1100.30.1.12.1' => 'processorDeviceCurrentSpeed',
+             '1.3.6.1.4.1.674.10892.1.1100.30.1.23.1' => 'processorDeviceBrandName',
+            '1.3.6.1.4.1.674.10892.1.1100.32.1.2.1'  => 'processorDeviceStatusIndex',
+            '1.3.6.1.4.1.674.10892.1.1100.32.1.5.1'  => 'processorDeviceStatusStatus',
+            '1.3.6.1.4.1.674.10892.1.1100.32.1.6.1'  => 'processorDeviceStatusReading',
            );
+       my $result = undef;
+       if ($opt{use_get_table}) {
+           my $processorDeviceTable = '1.3.6.1.4.1.674.10892.1.1100.30.1';
+           my $processorDeviceStatusTable = '1.3.6.1.4.1.674.10892.1.1100.32.1';
 
-       my $result = $snmp_session->get_entries(-columns => [keys %cpu_oid_new]);
+           $result = $snmp_session->get_table(-baseoid => $processorDeviceTable);
+           my $ext = $snmp_session->get_table(-baseoid => $processorDeviceStatusTable);
 
-       if (!defined $result) {
-           $oid_ver = 'old';
-           $result = $snmp_session->get_entries(-columns => [keys %cpu_oid_old]);
+            defined $ext && map { $$result{$_} = $$ext{$_} } keys %{ $ext };
+       }
+       else {
+           $result = $snmp_session->get_entries(-columns => [keys %cpu_oid]);
        }
 
        if (!defined $result) {
@@ -2788,12 +3025,7 @@ sub check_processors {
            exit $E_UNKNOWN;
        }
 
-       if ($oid_ver eq 'new') {
-           @output = @{ get_snmp_output($result, \%cpu_oid_new) };
-       }
-       else {
-           @output = @{ get_snmp_output($result, \%cpu_oid_old) };
-       }
+       @output = @{ get_snmp_output($result, \%cpu_oid) };
     }
     else {
        @output = @{ run_omreport("$omopt_chassis processors") };
@@ -2820,14 +3052,65 @@ sub check_processors {
         1024 => 'Throttled',           # Processor Throttled
        );
 
+    # Mapping between family numbers from SNMP and actual CPU family
+    my %cpu_family
+      = (
+        1   => 'Other',                2   => 'Unknown',              3   => '8086',
+        4   => '80286',                5   => '386',                  6   => '486',
+        7   => '8087',                 8   => '80287',                9   => '80387',
+        10  => '80487',                11  => 'Pentium',              12  => 'Pentium Pro',
+        13  => 'Pentium II',           14  => 'Pentium with MMX',     15  => 'Celeron',
+        16  => 'Pentium II Xeon',      17  => 'Pentium III',          18  => 'Pentium III Xeon',
+        19  => 'Pentium III',          20  => 'Itanium',              21  => 'Xeon',
+        22  => 'Pentium 4',            23  => 'Xeon MP',              24  => 'Itanium 2',
+        25  => 'K5',                   26  => 'K6',                   27  => 'K6-2',
+        28  => 'K6-3',                 29  => 'Athlon',               30  => 'AMD2900',
+        31  => 'K6-2+',                32  => 'Power PC',             33  => 'Power PC 601',
+        34  => 'Power PC 603',         35  => 'Power PC 603+',        36  => 'Power PC 604',
+        37  => 'Power PC 620',         38  => 'Power PC x704',        39  => 'Power PC 750',
+        48  => 'Alpha',                49  => 'Alpha 21064',          50  => 'Alpha 21066',
+        51  => 'Alpha 21164',          52  => 'Alpha 21164PC',        53  => 'Alpha 21164a',
+        54  => 'Alpha 21264',          55  => 'Alpha 21364',          64  => 'MIPS',
+        65  => 'MIPS R4000',           66  => 'MIPS R4200',           67  => 'MIPS R4400',
+        68  => 'MIPS R4600',           69  => 'MIPS R10000',          80  => 'SPARC',
+        81  => 'SuperSPARC',           82  => 'microSPARC II',        83  => 'microSPARC IIep',
+        84  => 'UltraSPARC',           85  => 'UltraSPARC II',        86  => 'UltraSPARC IIi',
+        87  => 'UltraSPARC III',       88  => 'UltraSPARC IIIi',      96  => '68040',
+        97  => '68xxx',                98  => '68000',                99  => '68010',
+        100 => '68020',                101 => '68030',                112 => 'Hobbit',
+        120 => 'Crusoe TM5000',        121 => 'Crusoe TM3000',        122 => 'Efficeon TM8000',
+        128 => 'Weitek',               131 => 'Athlon 64',            132 => 'Opteron',
+        133 => 'Sempron',              134 => 'Turion 64 Mobile',     135 => 'Dual-Core Opteron',
+        136 => 'Athlon 64 X2 DC',      137 => 'Turion 64 X2 M',       138 => 'Quad-Core Opteron',
+        139 => '3rd gen Opteron',      144 => 'PA-RISC',              145 => 'PA-RISC 8500',
+        146 => 'PA-RISC 8000',         147 => 'PA-RISC 7300LC',       148 => 'PA-RISC 7200',
+        149 => 'PA-RISC 7100LC',       150 => 'PA-RISC 7100',         160 => 'V30',
+        171 => 'Dual-Core Xeon 5200',  172 => 'Dual-Core Xeon 7200',  173 => 'Quad-Core Xeon 7300',
+        174 => 'Quad-Core Xeon 7400',  175 => 'Multi-Core Xeon 7400', 176 => 'M1',
+        177 => 'M2',                   180 => 'AS400',                182 => 'Athlon XP',
+        183 => 'Athlon MP',            184 => 'Duron',                185 => 'Pentium M',
+        186 => 'Celeron D',            187 => 'Pentium D',            188 => 'Pentium Extreme',
+        189 => 'Core Solo',            190 => 'Core2',                191 => 'Core2 Duo',
+        198 => 'Core i7',              199 => 'Dual-Core Celeron',    200 => 'IBM390',
+        201 => 'G4',                   202 => 'G5',                   203 => 'ESA/390 G6',
+        204 => 'z/Architectur',        210 => 'C7-M',                 211 => 'C7-D',
+        212 => 'C7',                   213 => 'Eden',                 214 => 'Multi-Core Xeon',
+        215 => 'Dual-Core Xeon 3xxx',  216 => 'Quad-Core Xeon 3xxx',  218 => 'Dual-Core Xeon 5xxx',
+        219 => 'Quad-Core Xeon 5xxx',  221 => 'Dual-Core Xeon 7xxx',  222 => 'Quad-Core Xeon 7xxx',
+        223 => 'Multi-Core Xeon 7xxx', 250 => 'i860',                 251 => 'i960',
+       );
 
   CPU:
     foreach my $out (@output) {
        if ($snmp) {
-           if ($oid_ver eq 'new') {
+           $index  = exists $out->{processorDeviceStatusIndex}
+             ? $out->{processorDeviceStatusIndex} - 1
+               : $out->{processorDeviceIndex} - 1;
+           $status = exists $out->{processorDeviceStatusStatus}
+             ? $snmp_status{$out->{processorDeviceStatusStatus}}
+               : $snmp_status{$out->{processorDeviceStatus}};
+           if (exists $out->{processorDeviceStatusReading}) {
                my @states  = ();  # contains states for the CPU
-               $index  = $out->{processorDeviceStatusIndex} - 1;
-               $status = $snmp_status{$out->{processorDeviceStatusStatus}};
 
                # get the combined state from the StatusReading OID
                foreach my $mask (sort keys %cpu_reading) {
@@ -2840,15 +3123,23 @@ sub check_processors {
                $state = join q{, }, @states;
            }
            else {
-               $index  = $out->{processorDeviceIndex} - 1;
-               $status = $snmp_status{$out->{processorDeviceStatus}};
                $state  = $cpu_state{$out->{processorDeviceStatusState}};
            }
+           $man    = $out->{processorDeviceManufacturerName};
+           $family = (exists $out->{processorDeviceFamily}
+                      and exists $cpu_family{$out->{processorDeviceFamily}})
+             ? $cpu_family{$out->{processorDeviceFamily}} : undef;
+           $speed  = $out->{processorDeviceCurrentSpeed};
+           $brand  = $out->{processorDeviceBrandName};
        }
        else {
            $index  = $out->{'Index'};
            $status = $out->{'Status'};
            $state  = $out->{'State'};
+           $brand  = exists $out->{'Processor Brand'} ? $out->{'Processor Brand'} : undef;
+           $family = exists $out->{'Processor Family'} ? $out->{'Processor Family'} : undef;
+           $man    = exists $out->{'Processor Manufacturer'} ? $out->{'Processor Manufacturer'} : undef;
+           $speed  = exists $out->{'Current Speed'} ? $out->{'Current Speed'} : undef;
        }
 
        next CPU if blacklisted('cpu', $index);
@@ -2866,16 +3157,30 @@ sub check_processors {
 
        $count{cpu}++;
 
+       if (defined $brand) {
+           $brand =~ s{\s\s+}{ }gxms;
+           $brand =~ s{\((R|tm)\)}{}gxms;
+           $brand =~ s{\s(CPU|Processor)}{}xms;
+           $brand =~ s{\s\@}{}xms;
+       }
+       elsif (defined $family and defined $man and defined $speed) {
+           $speed =~ s{\A (\d+) .*}{$1}xms;
+           $brand = sprintf '%s %s %.2fGHz', $man, $family, $speed / 1000;
+       }
+       else {
+           $brand = "unknown";
+       }
+
        # Default
        if ($status ne 'Ok') {
-           my $msg = sprintf 'CPU %d needs attention: %s',
-             $index, $state;
+           my $msg = sprintf 'Processor %d [%s] needs attention: %s',
+             $index, $brand, $state;
            report('chassis', $msg, $status2nagios{$status}, $index);
        }
        # Ok
        else {
-           my $msg = sprintf 'CPU %d is %s',
-             $index, $state;
+           my $msg = sprintf 'Processor %d [%s] is %s',
+             $index, $brand, $state;
            report('chassis', $msg, $E_OK, $index);
        }
     }
@@ -2887,6 +3192,8 @@ sub check_processors {
 # CHASSIS: Check voltage probes
 #-----------------------------------------
 sub check_volts {
+    return if blacklisted('volt', 'all');
+
     my $index    = undef;
     my $status   = undef;
     my $reading  = undef;
@@ -2928,7 +3235,7 @@ sub check_volts {
     foreach my $out (@output) {
        if ($snmp) {
            $index    = $out->{voltageProbeIndex} - 1;
-           $status   = $snmp_status{$out->{voltageProbeStatus}};
+           $status   = $snmp_probestatus{$out->{voltageProbeStatus}};
            $reading  = exists $out->{voltageProbeReading}
              ? sprintf('%.3f V', $out->{voltageProbeReading}/1000)
              : $volt_discrete_reading{$out->{voltageProbeDiscreteReading}};
@@ -2957,6 +3264,8 @@ sub check_volts {
 # CHASSIS: Check batteries
 #-----------------------------------------
 sub check_batteries {
+    return if blacklisted('bp', 'all');
+
     my $index    = undef;
     my $status   = undef;
     my $reading  = undef;
@@ -2971,7 +3280,14 @@ sub check_batteries {
             '1.3.6.1.4.1.674.10892.1.600.50.1.6.1' => 'batteryReading',
             '1.3.6.1.4.1.674.10892.1.600.50.1.7.1' => 'batteryLocationName',
            );
-       my $result = $snmp_session->get_entries(-columns => [keys %bat_oid]);
+       my $result = undef;
+       if ($opt{use_get_table}) {
+           my $batteryTable = '1.3.6.1.4.1.674.10892.1.600.50.1';
+           $result = $snmp_session->get_table(-baseoid => $batteryTable);
+       }
+       else {
+           $result = $snmp_session->get_entries(-columns => [keys %bat_oid]);
+       }
 
        # No batteries is OK
        return 0 if !defined $result;
@@ -3019,6 +3335,8 @@ sub check_batteries {
 # CHASSIS: Check amperage probes (power monitoring)
 #-----------------------------------------
 sub check_pwrmonitoring {
+    return if blacklisted('amp', 'all');
+
     my $index    = undef;
     my $status   = undef;
     my $reading  = undef;
@@ -3040,7 +3358,14 @@ sub check_pwrmonitoring {
             '1.3.6.1.4.1.674.10892.1.600.30.1.11.1' => 'amperageProbeUpperNonCriticalThreshold',
             '1.3.6.1.4.1.674.10892.1.600.30.1.16.1' => 'amperageProbeDiscreteReading',
            );
-       my $result = $snmp_session->get_entries(-columns => [keys %amp_oid]);
+       my $result = undef;
+       if ($opt{use_get_table}) {
+           my $amperageProbeTable = '1.3.6.1.4.1.674.10892.1.600.30.1';
+           $result = $snmp_session->get_table(-baseoid => $amperageProbeTable);
+       }
+       else {
+           $result = $snmp_session->get_entries(-columns => [keys %amp_oid]);
+       }
 
        # No pwrmonitoring is OK
        return 0 if !defined $result;
@@ -3114,7 +3439,7 @@ sub check_pwrmonitoring {
        }
        else {
            $index    = $out->{'Index'};
-           next if $index !~ m/^\d+$/x;
+           next AMP if (!defined $index || $index !~ m/^\d+$/x);
            $status   = $out->{'Status'};
            $reading  = $out->{'Reading'};
            $location = $out->{'Probe Name'};
@@ -3128,7 +3453,7 @@ sub check_pwrmonitoring {
            $max_crit =~ s{\A (\d+.*?)\s+[a-zA-Z]+ \s*\z}{$1}xms;
        }
 
-       next AMP if blacklisted('pm', $index);
+       next AMP if blacklisted('amp', $index);
        next AMP if $index !~ m{\A \d+ \z}xms;
        $count{amp}++;
 
@@ -3195,6 +3520,8 @@ sub check_pwrmonitoring {
 # CHASSIS: Check intrusion
 #-----------------------------------------
 sub check_intrusion {
+    return if blacklisted('intr', 'all');
+
     my $index    = undef;
     my $status   = undef;
     my $reading  = undef;
@@ -3207,7 +3534,14 @@ sub check_intrusion {
             '1.3.6.1.4.1.674.10892.1.300.70.1.5.1' => 'intrusionStatus',
             '1.3.6.1.4.1.674.10892.1.300.70.1.6.1' => 'intrusionReading',
            );
-       my $result = $snmp_session->get_entries(-columns => [keys %int_oid]);
+       my $result = undef;
+       if ($opt{use_get_table}) {
+           my $intrusionTable = '1.3.6.1.4.1.674.10892.1.300.70.1';
+           $result = $snmp_session->get_table(-baseoid => $intrusionTable);
+       }
+       else {
+           $result = $snmp_session->get_entries(-columns => [keys %int_oid]);
+       }
 
        # No intrusion is OK
        return 0 if !defined $result;
@@ -3606,6 +3940,11 @@ sub get_sysinfo
        $snmp ? get_snmp_chassis_bios() : get_omreport_chassis_bios();
     }
 
+    # Get OMSA information. Only if needed
+    if ($opt{okinfo} >= 3 or $opt{debug}) {
+       $snmp ? get_snmp_about() : get_omreport_about();
+    }
+
     # Return now if debug
     return if $opt{debug};
 
@@ -3614,11 +3953,6 @@ sub get_sysinfo
        $snmp ? get_snmp_system_operatingsystem() : get_omreport_system_operatingsystem();
     }
 
-    # Get OMSA information. Only if needed
-    if ($opt{okinfo} >= 3) {
-       $snmp ? get_snmp_about() : get_omreport_about();
-    }
-
     return;
 }
 
@@ -3787,8 +4121,10 @@ if ($snmp) {
 # Print messages
 if ($opt{debug}) {
     print "   System:      $sysinfo{model}\n";
-    print "   ServiceTag:  $sysinfo{serial}\n";
-    print "   BIOS/date:   $sysinfo{bios} $sysinfo{biosdate}\n";
+    print "   ServiceTag:  $sysinfo{serial}";
+    print q{ } x (25 - length $sysinfo{serial}), "OMSA version:    $sysinfo{om}\n";
+    print "   BIOS/date:   $sysinfo{bios} $sysinfo{biosdate}";
+    print q{ } x (25 - length "$sysinfo{bios} $sysinfo{biosdate}"), "Plugin version:  $VERSION\n";
     if ($#report_storage >= 0) {
        print "-----------------------------------------------------------------------------\n";
        print "   Storage Components                                                        \n";
@@ -3806,7 +4142,7 @@ if ($opt{debug}) {
        print "-----------------------------------------------------------------------------\n";
        print "   Chassis Components                                                        \n";
        print "=============================================================================\n";
-       print "  STATE  |  ID  |  MESSAGE TEXT                                          \n";
+       print "  STATE  |  ID  |  MESSAGE TEXT                                              \n";
        print "---------+------+------------------------------------------------------------\n";
        foreach (@report_chassis) {
            my ($msg, $level, $nexus) = @{$_};
@@ -3939,12 +4275,16 @@ elsif ($exit_code == $E_OK && !$opt{debug}) {
            my @storageprint = ();
            foreach my $id (sort keys %{ $sysinfo{controller} }) {
                chomp $sysinfo{controller}{$id}{driver};
-               push @storageprint, sprintf q{----- CTRL %s (%s): FW='%s', DR='%s'},
+               my $msg = sprintf q{----- Ctrl %s [%s]: Fw='%s', Dr='%s'},
                  $sysinfo{controller}{$id}{id}, $sysinfo{controller}{$id}{name},
                    $sysinfo{controller}{$id}{firmware}, $sysinfo{controller}{$id}{driver};
+               if (defined $sysinfo{controller}{$id}{storport}) {
+                   $msg .= sprintf q{, Storport: '%s'}, $sysinfo{controller}{$id}{storport};
+               }
+               push @storageprint, $msg;
            }
            foreach my $id (sort keys %{ $sysinfo{enclosure} }) {
-               push @storageprint, sprintf q{----- ENCL %s (%s): FW='%s'},
+               push @storageprint, sprintf q{----- Encl %s [%s]: Fw='%s'},
                  $sysinfo{enclosure}{$id}->{id}, $sysinfo{enclosure}{$id}->{name},
                    $sysinfo{enclosure}{$id}->{firmware};
            }
@@ -4005,6 +4345,18 @@ else {
     }
 }
 
+# Print any perl warnings that have occured
+if (@perl_warnings) {
+    foreach (@perl_warnings) {
+       chop @$_;
+       print "${linebreak}INTERNAL ERROR: @$_";
+    }
+    $exit_code = $E_UNKNOWN;
+}
+
+# Reset the WARN signal
+$SIG{__WARN__} = $original_sigwarn;
+
 # Print performance data
 if (defined $opt{perfdata} && !$opt{debug} && %perfdata) {
     my $lb = $opt{perfdata} eq 'multiline' ? "\n" : q{ };  # line break for perfdata