]> git.uio.no Git - check_openmanage.git/blobdiff - check_openmanage
* version 3.5.8-beta2
[check_openmanage.git] / check_openmanage
index 6aab2986702dad00a94bd65a5b412dd015aba579..1edeea754d75add5eb94ffb992934bb72d327e61 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
@@ -35,10 +35,10 @@ use vars qw( $NAME $VERSION $AUTHOR $CONTACT $E_OK $E_WARNING $E_CRITICAL
             $snmp_session $snmp_error $omreport $globalstatus $global
             $linebreak $omopt_chassis $omopt_system $blade
             $exit_code $snmp
-            %check %opt %perfdata %reverse_exitcode %status2nagios
+            %check %opt %reverse_exitcode %status2nagios
             %snmp_status %snmp_probestatus %probestatus2nagios %sysinfo
             %blacklist %nagios_alert_count %count
-            @controllers @enclosures
+            @perl_warnings @controllers @enclosures @perfdata
             @report_storage @report_chassis @report_other
          );
 
@@ -46,17 +46,12 @@ 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; }
-}
+# Collect perl warnings in an array
+$SIG{__WARN__} = sub { push @perl_warnings, [@_]; };
 
 # Version and similar info
 $NAME    = 'check_openmanage';
-$VERSION = '3.5.0-beta16';
+$VERSION = '3.5.8-beta2';
 $AUTHOR  = 'Trond H. Amundsen';
 $CONTACT = 't.h.amundsen@usit.uio.no';
 
@@ -89,7 +84,7 @@ GENERAL OPTIONS:
 
 SNMP OPTIONS:
 
-   -H, --hostname      Hostname or IP of the server (needed for SNMP)
+   -H, --hostname      Hostname or IP (required for SNMP)
    -C, --community     SNMP community string
    -P, --protocol      SNMP protocol version
    --port              SNMP port number
@@ -99,9 +94,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 +112,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.
@@ -126,37 +121,38 @@ Written by $AUTHOR <$CONTACT>
 END_LICENSE
 
 # Options with default values
-%opt = ( 'blacklist'         => [],
-        'check'             => [],
-        'critical'          => [],
-        'warning'           => [],
-        'timeout'           => 30,  # default timeout is 30 seconds
-        'debug'             => 0,
-        'help'              => 0,
-        'perfdata'          => undef,
-        'info'              => 0,
-        'extinfo'           => 0,
-        'htmlinfo'          => undef,
-        'postmsg'           => undef,
-        'state'             => 0,
-        'short-state'       => 0,
-        'okinfo'            => 0,   # default "ok" output level
-        'linebreak'         => undef,
-        'version'           => 0,
-         'all'               => 0,
-        'only'              => undef,
-        'omreport'          => undef,
-        'port'              => 161, # default SNMP port
-        'hostname'          => undef,
-        'community'         => 'public',  # SMNP v1 or v2c
-        'protocol'          => 2,
-        'username'          => undef, # SMNP v3
-        'authpassword'      => undef, # SMNP v3
-        'authkey'           => undef, # SMNP v3
-        'authprotocol'      => undef, # SMNP v3
-        'privpassword'      => undef, # SMNP v3
-        'privkey'           => undef, # SMNP v3
-        'privprotocol'      => undef, # SMNP v3
+%opt = ( 'blacklist'         => [],       # blacklisting
+        'check'             => [],       # check control
+        'critical'          => [],       # temperature critical limits
+        'warning'           => [],       # temperature warning limits
+        'timeout'           => 30,       # default timeout is 30 seconds
+        'debug'             => 0,        # debugging / verbose output
+        'help'              => 0,        # display help output
+        'perfdata'          => undef,    # output performance data
+        'info'              => 0,        # display servicetag
+        'extinfo'           => 0,        # display extra info
+        'htmlinfo'          => undef,    # html tags in output
+        'postmsg'           => undef,    # post message
+        'state'             => 0,        # display alert type
+        'short-state'       => 0,        # display alert type (short)
+        'okinfo'            => 0,        # default "ok" output level
+        'linebreak'         => undef,    # specify linebreak
+        'version'           => 0,        # plugin version info
+         'all'               => 0,        # check everything
+        'only'              => undef,    # only one component
+        'omreport'          => undef,    # omreport path
+        'port'              => 161,      # default SNMP port
+        'hostname'          => undef,    # hostname or IP
+        'community'         => 'public', # SMNP v1 or v2c
+        'protocol'          => 2,        # default SNMP protocol 2c
+        'username'          => undef,    # SMNP v3
+        'authpassword'      => undef,    # SMNP v3
+        'authkey'           => undef,    # SMNP v3
+        'authprotocol'      => undef,    # SMNP v3
+        'privpassword'      => undef,    # SMNP v3
+        'privkey'           => undef,    # SMNP v3
+        'privprotocol'      => undef,    # SMNP v3
+         'use_get_table'     => 0,        # hack for SNMPv3 on Windows with net-snmp
        );
 
 # Get options
@@ -171,12 +167,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 +187,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
@@ -296,7 +293,7 @@ if (!$snmp && -f $FW_LOCK) {
     );
 
 # Performance data
-%perfdata = ();
+@perfdata = ();
 
 # Global health status
 $global         = 1;      # default is to check global status
@@ -557,7 +554,7 @@ sub snmp_initialize {
        }
     }
     else {
-       print "You need perl module Net::SNMP to run $NAME in SNMP mode\n";
+       print "ERROR: You need perl module Net::SNMP to run $NAME in SNMP mode\n";
        exit $E_UNKNOWN;
     }
     return;
@@ -595,7 +592,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 +604,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 +612,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 +625,7 @@ sub find_omreport {
   OMREPORT_PATH:
     foreach my $bin (@omreport_paths) {
        if (-x $bin) {
-           $omreport = $bin;
+           $omreport = qq{"$bin"};
            last OMREPORT_PATH;
        }
     }
@@ -741,7 +739,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 +823,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 +837,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 +853,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 +881,7 @@ sub blacklisted {
 
     if (defined $blacklist{$name}) {
        foreach my $comp (@{ $blacklist{$name} }) {
-           if (defined $id and ($comp eq $id or $comp eq 'ALL')) {
+           if (defined $id and ($comp eq $id or uc($comp) eq 'ALL')) {
                $ret = 1;
            }
        }
@@ -944,17 +947,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;
 }
 
@@ -1045,6 +1057,15 @@ sub warranty_url {
 }
 
 
+# This helper function returns the corresponding value of a hash key,
+# but takes into account that the key may not exist
+sub get_hashval {
+    my $key  = shift || return undef;
+    my $hash = shift;
+    return exists $hash->{$key} ? $hash->{$key} : "Undefined value $key";
+}
+
+
 
 #---------------------------------------------------------------------
 # Check functions
@@ -1091,6 +1112,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 +1123,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 +1139,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' => 'controllerStorportDriverVersion',
+            '1.3.6.1.4.1.674.10893.1.20.130.1.1.56' => 'controllerMinRequiredStorportVer',
            );
 
        # We use get_table() here for the odd case where a server has
@@ -1144,18 +1171,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    = get_hashval($out->{controllerState}, \%ctrl_state);
+           $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->{'controllerMinRequiredStorportVer'}
+             ? $out->{controllerMinRequiredStorportVer} : undef;
+           $stdr     = exists $out->{controllerStorportDriverVersion}
+             ? $out->{controllerStorportDriverVersion} : undef;
            $nexus    = convert_nexus($out->{controllerNexusID});
        }
        else {
@@ -1171,6 +1202,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 +1219,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 +1237,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 +1267,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 +1298,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 +1330,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);
        }
@@ -1283,6 +1350,7 @@ sub check_physical_disks {
         7  => 'Recovering',
         11 => 'Removed',
         15 => 'Resynching',
+         22 => 'Replacing', # FIXME: this one is not defined in the OM 6.2.0.1 MIBs
         24 => 'Rebuilding',
         25 => 'No Media',
         26 => 'Formatting',
@@ -1300,24 +1368,30 @@ 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});
            }
-           $state    = $pdisk_state{$out->{arrayDiskState}};
+           $state    = get_hashval($out->{arrayDiskState}, \%pdisk_state);
            $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 +1419,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);
@@ -1355,15 +1429,17 @@ sub check_physical_disks {
        $vendor =~ s{\(tm\)\z}{}xms;
 
        # Special case: Failure predicted
-       if ($status eq 'Non-Critical' and $fpred) {
-           my $msg = sprintf '%s <tt style="color: #555">[%s %s, %s]</tt> on ctrl %d needs attention: Failure Predicted',
+       if ($fpred) {
+           my $msg = sprintf '%s [%s %s, %s] on ctrl %d needs attention: Failure Predicted',
              $name, $vendor, $product, $capacity, $ctrl;
-           report('storage', $msg, $E_WARNING, $nexus);
-       }
-       # Special case: Rebuilding
-       elsif ($state eq 'Rebuilding') {
-           my $msg = sprintf '%s [%s] on ctrl %d is %s%s',
-             $name, $capacity, $ctrl, $state, $progr;
+            $msg .= " ($state)" if $state ne 'Predictive failure';
+           report('storage', $msg,
+                   ($status2nagios{$status} == $E_CRITICAL ? $E_CRITICAL : $E_WARNING), $nexus);
+       }
+       # Special case: Rebuilding / Replacing
+       elsif ($state =~ m{\A Rebuilding|Replacing \z}xms) {
+           my $msg = sprintf '%s [%s %s, %s] on ctrl %d is %s%s',
+             $name, $vendor, $product, $capacity, $ctrl, $state, $progr;
            report('storage', $msg, $E_WARNING, $nexus);
        }
        # Default
@@ -1388,6 +1464,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 +1489,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;
@@ -1455,7 +1539,7 @@ sub check_virtual_disks {
         8  => 'RAID-6',
         10 => 'RAID-10',
         12 => 'RAID-50',
-        19 => 'Concatenated RAID 1',
+        19 => 'Concatenated RAID-1',
         24 => 'RAID-60',
        );
 
@@ -1465,9 +1549,9 @@ sub check_virtual_disks {
        if ($snmp) {
            $id     = $out->{virtualDiskTargetID};
            $dev    = $out->{virtualDiskDeviceName};
-           $state  = $vdisk_state{$out->{virtualDiskState}};
+           $state  = get_hashval($out->{virtualDiskState}, \%vdisk_state);
+           $layout = get_hashval($out->{virtualDiskLayout}, \%vdisk_layout);
            $status = $snmp_status{$out->{virtualDiskComponentStatus}};
-           $layout = $vdisk_layout{$out->{virtualDiskLayout}};
            $size   = sprintf '%.2f GB', $out->{virtualDiskLengthInMB} / 1024;
            $progr  = q{};  # can't get this from SNMP(?)
            $nexus  = convert_nexus($out->{virtualDiskNexusID});
@@ -1490,6 +1574,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 +1605,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 +1626,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 +1668,7 @@ sub check_cache_battery {
         36 => 'Learning',
        );
 
+    # Specifies the learn state activity of the battery
     my %bat_learn_state
       = (
         1  => 'Failed',
@@ -1575,6 +1678,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
@@ -1587,12 +1691,10 @@ sub check_cache_battery {
   BATTERY:
     foreach my $out (@output) {
        if ($snmp) {
-           $state  = $bat_state{$out->{batteryState}};
            $status = $snmp_status{$out->{batteryComponentStatus}};
-           $learn  = exists $out->{batteryLearnState}
-             ? $bat_learn_state{$out->{batteryLearnState}} : undef;
-           $pred   = exists $out->{batteryPredictedCapacity}
-             ? $bat_pred_cap{$out->{batteryPredictedCapacity}} : undef;
+           $state  = get_hashval($out->{batteryState}, \%bat_state);
+           $learn  = get_hashval($out->{batteryLearnState}, \%bat_learn_state);
+           $pred   = get_hashval($out->{batteryPredictedCapacity}, \%bat_pred_cap);
            $ctrl   = $out->{batteryConnectionControllerNumber} - 1;
            $nexus  = convert_nexus($out->{batteryNexusID});
            $id     = $nexus;
@@ -1612,17 +1714,31 @@ sub check_cache_battery {
 
        # Special case: Charging
        if ($state eq 'Charging') {
-           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);
+           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') {
-           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);
+           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') {
@@ -1660,6 +1776,7 @@ sub check_cache_battery {
 #-----------------------------------------
 sub check_connectors {
     return if $#controllers == -1;
+    return if blacklisted('conn', 'all');
 
     my $id     = undef;
     my $nexus  = undef;
@@ -1680,7 +1797,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;
@@ -1724,9 +1848,9 @@ sub check_connectors {
         if ($snmp) {
             $id     = $out->{channelNumber} - 1;
             $name   = $out->{channelName};
-            $state  = $conn_state{$out->{channelState}};
             $status = $snmp_status{$out->{channelComponentStatus}};
-            $type   = $conn_bustype{$out->{channelBusType}};
+            $state  = get_hashval($out->{channelState}, \%conn_state);
+            $type   = get_hashval($out->{channelBusType}, \%conn_bustype);
            $nexus  = convert_nexus($out->{channelNexusID});
            $ctrl   = $nexus;
            $ctrl   =~ s{(\d+):\d+}{$1}xms;
@@ -1755,6 +1879,8 @@ sub check_connectors {
 # STORAGE: Check enclosures
 #-----------------------------------------
 sub check_enclosures {
+    return if blacklisted('encl', 'all');
+
     my $id       = undef;
     my $nexus    = undef;
     my $name     = undef;
@@ -1775,7 +1901,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;
@@ -1802,10 +1935,10 @@ sub check_enclosures {
   ENCLOSURE:
     foreach my $out (@output) {
         if ($snmp) {
-            $id       = $out->{'enclosureNumber'} - 1;
-            $name     = $out->{'enclosureName'};
-            $state    = $encl_state{$out->{'enclosureState'}};
-            $status   = $snmp_status{$out->{'enclosureComponentStatus'}};
+            $id       = $out->{enclosureNumber} - 1;
+            $name     = $out->{enclosureName};
+            $state    = get_hashval($out->{enclosureState}, \%encl_state);
+            $status   = $snmp_status{$out->{enclosureComponentStatus}};
            $firmware = exists $out->{enclosureFirmwareVersion}
              ? $out->{enclosureFirmwareVersion} : 'N/A';
            $nexus    = convert_nexus($out->{enclosureNexusID});
@@ -1851,6 +1984,7 @@ sub check_enclosures {
 #-----------------------------------------
 sub check_enclosure_fans {
     return if $#controllers == -1;
+    return if blacklisted('encl_fan', 'all');
 
     my $id        = undef;
     my $nexus     = undef;
@@ -1874,8 +2008,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;
@@ -1908,7 +2055,7 @@ sub check_enclosure_fans {
        if ($snmp) {
            $id        = $out->{fanNumber} - 1;
            $name      = $out->{fanName};
-           $state     = $fan_state{$out->{fanState}};
+           $state     = get_hashval($out->{fanState}, \%fan_state);
            $status    = $snmp_status{$out->{fanComponentStatus}};
            $speed     = $out->{fanProbeCurrValue};
            $encl_id   = $out->{fanConnectionEnclosureNumber} - 1;
@@ -1950,6 +2097,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;
@@ -1971,7 +2119,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;
@@ -2004,7 +2166,7 @@ sub check_enclosure_pwr {
        if ($snmp) {
            $id        = $out->{powerSupplyNumber};
            $name      = $out->{powerSupplyName};
-           $state     = $ps_state{$out->{powerSupplyState}};
+           $state     = get_hashval($out->{powerSupplyState}, \%ps_state);
            $status    = $snmp_status{$out->{powerSupplyComponentStatus}};
            $encl_id   = $out->{powerSupplyConnectionEnclosureNumber} - 1;
            $encl_name = $out->{powerSupplyConnectionEnclosureName};
@@ -2044,6 +2206,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;
@@ -2073,7 +2236,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;
@@ -2106,7 +2283,7 @@ sub check_enclosure_temp {
        if ($snmp) {
            $id        = $out->{temperatureProbeNumber} - 1;
            $name      = $out->{temperatureProbeName};
-           $state     = $temp_state{$out->{temperatureProbeState}};
+           $state     = get_hashval($out->{temperatureProbeState}, \%temp_state);
            $status    = $snmp_status{$out->{temperatureProbeComponentStatus}};
            $unit      = $out->{temperatureProbeUnit};
            $reading   = $out->{temperatureProbeCurValue};
@@ -2148,9 +2325,16 @@ sub check_enclosure_temp {
        # Collect performance data
        if (defined $opt{perfdata}) {
            $name =~ s{\A Temperature\sProbe\s(\d+) \z}{temp_$1}gxms;
-           my $pkey = "enclosure_${encl_id}_${name}";
-           my $pval = join q{;}, "${reading}C", $max_warn, $max_crit;
-           $perfdata{$pkey} = $pval;
+           my $label = "enclosure_${encl_id}_${name}";
+           my $mini = $label;
+           $mini =~ s{enclosure_(.+?)_temp_(.+?)}{e$1t$2}xms;
+           push @perfdata, {
+                            label => $label,
+                            mini  => $mini,
+                            value => $reading,
+                            warn  => $max_warn,
+                            crit  => $max_crit,
+                           };
        }
     }
     return;
@@ -2162,6 +2346,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;
@@ -2183,7 +2368,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;
@@ -2217,7 +2416,7 @@ sub check_enclosure_emms {
        if ($snmp) {
            $id        = $out->{enclosureManagementModuleNumber} - 1;
            $name      = $out->{enclosureManagementModuleName};
-           $state     = $emms_state{$out->{enclosureManagementModuleState}};
+           $state     = get_hashval($out->{enclosureManagementModuleState}, \%emms_state);
            $status    = $snmp_status{$out->{enclosureManagementModuleComponentStatus}};
            $encl_id   = $out->{enclosureManagementModuleConnectionEnclosureNumber} - 1;
            $encl_name = $out->{enclosureManagementModuleConnectionEnclosureName};
@@ -2256,6 +2455,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;
@@ -2273,7 +2474,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;
@@ -2367,6 +2575,8 @@ sub check_memory {
 # CHASSIS: Check fans
 #-----------------------------------------
 sub check_fans {
+    return if blacklisted('fan', 'all');
+
     my $index    = undef;
     my $status   = undef;
     my $reading  = undef;
@@ -2385,7 +2595,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;
@@ -2448,9 +2665,13 @@ sub check_fans {
            my $pname = lc $location;
            $pname =~ s{\s}{_}gxms;
            $pname =~ s{proc_}{cpu#}xms;
-           my $pkey = join q{_}, 'fan', $index, $pname;
-           my $pval = join q{;}, "${reading}RPM", $max_warn, $max_crit;
-           $perfdata{$pkey} = $pval;
+           push @perfdata, {
+                            label => "fan_${index}_${pname}",
+                            mini  => "f$index",
+                            value => $reading,
+                            warn  => $max_warn,
+                            crit  => $max_crit,
+                           };
        }
     }
     return;
@@ -2461,6 +2682,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;
@@ -2478,7 +2701,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;
@@ -2529,7 +2759,7 @@ sub check_powersupplies {
 
            $index    = $out->{powerSupplyIndex} - 1;
            $status   = $snmp_status{$out->{powerSupplyStatus}};
-           $type     = $ps_type{$out->{powerSupplyType}};
+           $type     = get_hashval($out->{powerSupplyType}, \%ps_type);
            $err_type = defined $out->{powerSupplyConfigurationErrorType}
              ? $ps_config_error_type{$out->{powerSupplyConfigurationErrorType}} : undef;
 
@@ -2577,6 +2807,8 @@ sub check_powersupplies {
 # CHASSIS: Check temperatures
 #-----------------------------------------
 sub check_temperatures {
+    return if blacklisted('temp', 'all');
+
     my $index    = undef;
     my $status   = undef;
     my $reading  = undef;
@@ -2639,17 +2871,24 @@ sub check_temperatures {
        if ($snmp) {
            $index    = $out->{temperatureProbeIndex} - 1;
            $status   = $snmp_probestatus{$out->{temperatureProbeStatus}};
-           $reading  = $out->{temperatureProbeReading} / 10;
            $location = $out->{temperatureProbeLocationName};
-           $max_crit = $out->{temperatureProbeUpperCriticalThreshold} / 10;
-           $max_warn = $out->{temperatureProbeUpperNonCriticalThreshold} / 10;
+           $reading  = exists $out->{temperatureProbeReading}
+             ? $out->{temperatureProbeReading} / 10 : '[N/A]';
+           $max_crit = exists $out->{temperatureProbeUpperCriticalThreshold}
+             ? $out->{temperatureProbeUpperCriticalThreshold} / 10 : '[N/A]';
+           $max_warn = exists $out->{temperatureProbeUpperNonCriticalThreshold}
+             ? $out->{temperatureProbeUpperNonCriticalThreshold} / 10 : '[N/A]';
            $min_crit = exists $out->{temperatureProbeLowerCriticalThreshold}
              ? $out->{temperatureProbeLowerCriticalThreshold} / 10 : '[N/A]';
            $min_warn = exists $out->{temperatureProbeLowerNonCriticalThreshold}
              ? $out->{temperatureProbeLowerNonCriticalThreshold} / 10 : '[N/A]';
-           $type     = $probe_type{$out->{temperatureProbeType}};
+           $type     = get_hashval($out->{temperatureProbeType}, \%probe_type);
            $discrete = exists $out->{temperatureProbeDiscreteReading}
-             ? $out->{temperatureProbeDiscreteReading} : undef;
+             ? $out->{temperatureProbeDiscreteReading} : '[N/A]';
+           # workaround for bad temp probes
+           if ($type eq 'AmbientESM' and $reading !~ m{\A \d+(\.\d+)? \z}xms) {
+               $type = 'Discrete';
+           }
        }
        else {
            $index    = $out->{'Index'};
@@ -2668,7 +2907,7 @@ sub check_temperatures {
        $count{temp}++;
 
        if ($type eq 'Discrete') {
-           my $msg = sprintf 'Temperature probe %d (%s): is %s',
+           my $msg = sprintf 'Temperature probe %d [%s] is %s',
              $index, $location, $discrete;
            my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
            report('chassis', $msg, $err, $index);
@@ -2733,7 +2972,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);
            }
@@ -2744,9 +2983,13 @@ sub check_temperatures {
                $pname =~ s{\s}{_}gxms;
                $pname =~ s{_temp\z}{}xms;
                $pname =~ s{proc_}{cpu#}xms;
-               my $pkey = join q{_}, 'temp', $index, $pname;
-               my $pval = join q{;}, "${reading}C", $max_warn, $max_crit;
-               $perfdata{$pkey} = $pval;
+               push @perfdata, {
+                                label => "temp_${index}_${pname}",
+                                mini  => "t$index",
+                                value => $reading,
+                                warn  => $max_warn,
+                                crit  => $max_crit,
+                               };
            }
        }
     }
@@ -2758,38 +3001,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.
+       # "Processor Device Status" OIDs. We check both the newer
+       # (preferred) OIDs and the old ones.
 
-       my %cpu_oid_new  # for newer models
+       my %cpu_oid
          = (
-            '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',
+             '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 %cpu_oid_old  # for older models
-         = (
-             '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',
-           );
-
-       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) {
@@ -2798,12 +3051,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") };
@@ -2830,14 +3078,148 @@ 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',                         40  => 'Core Duo',
+         41  => 'Core Duo mobile',                      42  => 'Core Solo mobile',
+         43  => 'Intel Atom',                           44  => undef,
+         45  => undef,                                  46  => undef,
+         47  => undef,                                  48  => 'Alpha',
+         49  => 'Alpha 21064',                          50  => 'Alpha 21066',
+        51  => 'Alpha 21164',                          52  => 'Alpha 21164PC',
+         53  => 'Alpha 21164a',                         54  => 'Alpha 21264',
+         55  => 'Alpha 21364',                          56  => 'Turion II Ultra Dual-Core Mobile M',
+         57  => 'Turion II Dual-Core Mobile M',         58  => 'Athlon II Dual-Core Mobile M ',
+         59  => 'Opteron 6100',                         60  => undef,
+         61  => undef,                                  62  => undef,
+         63  => undef,                                  64  => 'MIPS',
+        65  => 'MIPS R4000',                           66  => 'MIPS R4200',
+         67  => 'MIPS R4400',                           68  => 'MIPS R4600',
+         69  => 'MIPS R10000',                          70  => undef,
+         71  => undef,                                  72  => undef,
+         73  => undef,                                  74  => undef,
+         75  => undef,                                  76  => undef,
+         77  => undef,                                  78  => undef,
+         79  => undef,                                  80  => 'SPARC',
+        81  => 'SuperSPARC',                           82  => 'microSPARC II',
+         83  => 'microSPARC IIep',                      84  => 'UltraSPARC',
+         85  => 'UltraSPARC II',                        86  => 'UltraSPARC IIi',
+        87  => 'UltraSPARC III',                       88  => 'UltraSPARC IIIi',
+         89  => undef,                                  90  => undef,
+         91  => undef,                                  92  => undef,
+         93  => undef,                                  94  => undef,
+         95  => undef,                                  96  => '68040',
+         97  => '68xxx',                                98  => '68000',
+         99  => '68010',                                100 => '68020',
+         101 => '68030',                                102 => undef,
+         103 => undef,                                  104 => undef,
+         105 => undef,                                  106 => undef,
+         107 => undef,                                  108 => undef,
+         109 => undef,                                  110 => undef,
+         111 => undef,                                  112 => 'Hobbit',
+         113 => undef,                                  114 => undef,
+         115 => undef,                                  116 => undef,
+         117 => undef,                                  118 => undef,
+         119 => undef,                                  120 => 'Crusoe TM5000',
+         121 => 'Crusoe TM3000',                        122 => 'Efficeon TM8000',
+         123 => undef,                                  124 => undef,
+         125 => undef,                                  126 => undef,
+         127 => undef,                                  128 => 'Weitek',
+         129 => undef,                                  130 => 'Celeron M',
+         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',                      140 => 'AMD Phenom FX Quad-Core',
+         141 => 'AMD Phenom X4 Quad-Core',              142 => 'AMD Phenom X2 Dual-Core',
+         143 => 'AMD Athlon X2 Dual-Core',              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',
+         151 => undef,                                  152 => undef,
+         153 => undef,                                  154 => undef,
+         155 => undef,                                  156 => undef,
+         157 => undef,                                  158 => undef,
+         159 => undef,                                  160 => 'V30',
+         161 => 'Quad-Core Xeon 3200',                  162 => 'Dual-Core Xeon 3000',
+         163 => 'Quad-Core Xeon 5300',                  164 => 'Dual-Core Xeon 5100',
+         165 => 'Dual-Core Xeon 5000',                  166 => 'Dual-Core Xeon LV',
+         167 => 'Dual-Core Xeon ULV',                   168 => 'Dual-Core Xeon 7100',
+         169 => 'Quad-Core Xeon 5400',                  170 => 'Quad-Core Xeon',
+         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',                                   178 => undef,
+         179 => 'Pentium 4 HT',                         180 => 'AS400',
+         181 => undef,                                  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',                            192 => 'Core2 Solo',
+         193 => 'Core2 Extreme',                        194 => 'Core2 Quad',
+         195 => 'Core2 Extreme mobile',                 196 => 'Core2 Duo mobile',
+         197 => 'Core2 Solo mobile',                    198 => 'Core i7',
+         199 => 'Dual-Core Celeron',                    200 => 'IBM390',
+        201 => 'G4',                                   202 => 'G5',
+         203 => 'ESA/390 G6',                           204 => 'z/Architectur',
+         205 => 'Core i5',                              206 => undef,
+         207 => undef,                                  208 => undef,
+         209 => undef,                                  210 => 'C7-M',
+         211 => 'C7-D',                                 212 => 'C7',
+         213 => 'Eden',                                 214 => 'Multi-Core Xeon',
+         215 => 'Dual-Core Xeon 3xxx',                  216 => 'Quad-Core Xeon 3xxx',
+         217 => undef,                                  218 => 'Dual-Core Xeon 5xxx',
+        219 => 'Quad-Core Xeon 5xxx',                  220 => undef,
+         221 => 'Dual-Core Xeon 7xxx',                  222 => 'Quad-Core Xeon 7xxx',
+         223 => 'Multi-Core Xeon 7xxx',                 224 => undef,
+         225 => undef,                                  226 => undef,
+         227 => undef,                                  228 => undef,
+         229 => undef,                                  230 => 'Embedded AMD Opteron Quad-Core',
+         231 => 'AMD Phenom Triple-Core',               232 => 'AMD Turion Ultra Dual-Core Mobile',
+         233 => 'AMD Turion Dual-Core Mobile',          234 => 'AMD Athlon Dual-Core',
+         235 => 'AMD Sempron SI',                       236 => 'AMD Phenom II',
+         237 => 'AMD Athlon II',                        238 => 'Six-Core AMD Opteron',
+         239 => 'AMD Sempron M',                        240 => undef,
+         241 => undef,                                  242 => undef,
+         243 => undef,                                  244 => undef,
+         245 => undef,                                  246 => undef,
+         247 => undef,                                  248 => undef,
+         249 => undef,                                  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) {
@@ -2850,15 +3232,23 @@ sub check_processors {
                $state = join q{, }, @states;
            }
            else {
-               $index  = $out->{processorDeviceIndex} - 1;
-               $status = $snmp_status{$out->{processorDeviceStatus}};
-               $state  = $cpu_state{$out->{processorDeviceStatusState}};
+               $state  = get_hashval($out->{processorDeviceStatusState}, \%cpu_state);
            }
+           $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);
@@ -2876,16 +3266,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);
        }
     }
@@ -2897,6 +3301,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;
@@ -2938,10 +3344,10 @@ 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}};
+                : get_hashval($out->{voltageProbeDiscreteReading}, \%volt_discrete_reading);
            $location = $out->{voltageProbeLocationName};
        }
        else {
@@ -2967,6 +3373,8 @@ sub check_volts {
 # CHASSIS: Check batteries
 #-----------------------------------------
 sub check_batteries {
+    return if blacklisted('bp', 'all');
+
     my $index    = undef;
     my $status   = undef;
     my $reading  = undef;
@@ -2981,7 +3389,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;
@@ -3004,7 +3419,7 @@ sub check_batteries {
        if ($snmp) {
            $index    = $out->{batteryIndex} - 1;
            $status   = $snmp_status{$out->{batteryStatus}};
-           $reading  = $bat_reading{$out->{batteryReading}};
+           $reading  = get_hashval($out->{batteryReading}, \%bat_reading);
            $location = $out->{batteryLocationName};
        }
        else {
@@ -3029,6 +3444,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;
@@ -3050,7 +3467,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;
@@ -3105,8 +3529,8 @@ sub check_pwrmonitoring {
        if ($snmp) {
            $index    = $out->{amperageProbeIndex} - 1;
            $status   = $snmp_status{$out->{amperageProbeStatus}};
-           $reading  = $amp_type{$out->{amperageProbeType}} eq 'amperageProbeTypeIsDiscrete'
-             ? $amp_discrete{$out->{amperageProbeDiscreteReading}}
+           $reading  = get_hashval($out->{amperageProbeType}, \%amp_type) eq 'amperageProbeTypeIsDiscrete'
+             ? get_hashval($out->{amperageProbeDiscreteReading}, \%amp_discrete)
                : $out->{amperageProbeReading};
            $location = $out->{amperageProbeLocationName};
            $max_crit = exists $out->{amperageProbeUpperCriticalThreshold}
@@ -3124,7 +3548,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'};
@@ -3138,7 +3562,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}++;
 
@@ -3149,11 +3573,15 @@ sub check_pwrmonitoring {
        # Collect performance data
        if (defined $opt{perfdata}) {
            next AMP if $reading !~ m{\A \d+(\.\d+)? \z}xms; # discrete reading (not number)
-           my $pname = lc $location;
-           $pname =~ s{\s}{_}gxms;
-           my $pkey = join q{_}, 'pwr_mon', $index, $pname;
-           my $pval = join q{;}, "$reading$unit", $max_warn, $max_crit;
-           $perfdata{$pkey} = $pval;
+           my $label = join q{_}, 'pwr_mon', $index, lc $location;
+           $label =~ s{\s}{_}gxms;
+           push @perfdata, {
+                            label => $label,
+                            mini  => "p${index}" . lc $unit,
+                            value => $reading,
+                            warn  => $max_warn,
+                            crit  => $max_crit,
+                           };
        }
     }
 
@@ -3165,8 +3593,8 @@ sub check_pwrmonitoring {
        my %used  = ();
 
        # find used indexes
-       foreach (keys %perfdata) {
-           if (m/\A pwr_mon_(\d+)/xms) {
+       foreach (@perfdata) {
+           if ($_->{label} =~ m/\A pwr_mon_(\d+)/xms) {
                $used{$1} = 1;
            }
        }
@@ -3182,16 +3610,21 @@ sub check_pwrmonitoring {
                $found = 0;
                next AMP2;
            }
-           if ($found and $line =~ m/\A ([^;]+?) ; (\d*\.\d+) \s ([AW]) \z/xms) {
+           if ($found and $line =~ m/\A ([^;]+?) ; (\d*\.\d+) \s [AW] \z/xms) {
                my $aname = lc $1;
                my $aval = $2;
-               my $aunit = $3;
                $aname =~ s{\s}{_}gxms;
 
                # don't use an existing index
                while (exists $used{$index}) { ++$index; }
 
-               $perfdata{"pwr_mon_${index}_${aname}"} = "$aval$aunit;0;0";
+               push @perfdata, {
+                                label => "pwr_mon_${index}_${aname}",
+                                mini  => "p${index}a",
+                                value => $aval,
+                                warn  => 0,
+                                crit  => 0,
+                               };
                ++$index;
            }
        }
@@ -3205,6 +3638,8 @@ sub check_pwrmonitoring {
 # CHASSIS: Check intrusion
 #-----------------------------------------
 sub check_intrusion {
+    return if blacklisted('intr', 'all');
+
     my $index    = undef;
     my $status   = undef;
     my $reading  = undef;
@@ -3217,7 +3652,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;
@@ -3241,7 +3683,7 @@ sub check_intrusion {
        if ($snmp) {
            $index    = $out->{intrusionIndex} - 1;
            $status   = $snmp_status{$out->{intrusionStatus}};
-           $reading  = $int_reading{$out->{intrusionReading}};
+           $reading  = get_hashval($out->{intrusionReading}, \%int_reading);
        }
        else {
            $index    = $out->{'Index'};
@@ -3580,22 +4022,16 @@ sub get_snmp_system_operatingsystem {
 # Fetch OMSA version via SNMP, put in sysinfo hash
 #
 sub get_snmp_about {
-    my %omsa_oid
-      = (
-        '1.3.6.1.4.1.674.10892.1.100.10.0' => 'systemManagementSoftwareGlobalVersionName',
-       );
-    my $systemManagementSoftwareGroup = '1.3.6.1.4.1.674.10892.1.100';
-    my $result = $snmp_session->get_table(-baseoid => $systemManagementSoftwareGroup);
+    # systemManagementSoftwareGlobalVersionName
+    my $oid = '1.3.6.1.4.1.674.10892.1.100.10.0';
+    my $result = $snmp_session->get_request(-varbindlist => [$oid]);
+
     if (defined $result) {
-       foreach my $oid (keys %{ $result }) {
-           if (exists $omsa_oid{$oid} and $omsa_oid{$oid} eq 'systemManagementSoftwareGlobalVersionName') {
-               $sysinfo{om} = ($result->{$oid});
-           }
-       }
+       $sysinfo{om} = exists $result->{$oid} && $result->{$oid} ne q{}
+         ? $result->{$oid} : 'unknown';
     }
     else {
-       my $msg = sprintf 'SNMP ERROR getting OMSA info: %s',
-         $snmp_session->error;
+       my $msg = sprintf 'SNMP ERROR: Getting OMSA version failed: %s', $snmp_session->error;
        report('other', $msg, $E_UNKNOWN);
     }
     return;
@@ -3616,6 +4052,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};
 
@@ -3624,11 +4065,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;
 }
 
@@ -3797,8 +4233,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";
@@ -3816,7 +4254,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) = @{$_};
@@ -3949,12 +4387,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};
            }
@@ -4015,23 +4457,33 @@ else {
     }
 }
 
+# Reset the WARN signal
+$SIG{__WARN__} = 'DEFAULT';
+
+# Print any perl warnings that have occured
+if (@perl_warnings) {
+    foreach (@perl_warnings) {
+       chop @$_;
+       print "${linebreak}INTERNAL ERROR: @$_";
+    }
+    $exit_code = $E_UNKNOWN;
+}
+
 # Print performance data
-if (defined $opt{perfdata} && !$opt{debug} && %perfdata) {
+if (defined $opt{perfdata} && !$opt{debug} && @perfdata) {
     my $lb = $opt{perfdata} eq 'multiline' ? "\n" : q{ };  # line break for perfdata
     print q{|};
 
-    sub perfdata {
-       my %order
-         = (
-            fan       => 0,
-            pwr       => 1,
-            temp      => 2,
-            enclosure => 3,
-           );
-       return ($order{(split /_/, $a, 2)[0]} cmp $order{(split /_/, $b, 2)[0]}) || $a cmp $b;
+    # Sort routine for performance data
+    sub perfsort {
+       my %order = ( fan => 0, pwr => 1, tem => 2, enc => 3, );
+       return ($order{(substr $a->{label}, 0, 3)} cmp $order{(substr $b->{label}, 0, 3)}) ||
+         $a->{label} cmp $b->{label};
     }
 
-    print join $lb, map { "'$_'=$perfdata{$_}" } sort perfdata keys %perfdata;
+    # Print performance data sorted
+    my $type = $opt{perfdata} eq 'minimal' ? 'mini' : 'label';
+    print join $lb, map { "$_->{$type}=$_->{value};$_->{warn};$_->{crit}" } sort perfsort @perfdata;
 }
 
 # Print a linebreak at the end