]> git.uio.no Git - check_openmanage.git/blobdiff - check_openmanage
* version 3.5.8-beta2
[check_openmanage.git] / check_openmanage
index c4eab2f8a140a927958873914d984604af45bcb1..1edeea754d75add5eb94ffb992934bb72d327e61 100755 (executable)
@@ -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 $original_sigwarn
-            %check %opt %perfdata %reverse_exitcode %status2nagios
+            $exit_code $snmp
+            %check %opt %reverse_exitcode %status2nagios
             %snmp_status %snmp_probestatus %probestatus2nagios %sysinfo
             %blacklist %nagios_alert_count %count
-            @perl_warnings @controllers @enclosures
+            @perl_warnings @controllers @enclosures @perfdata
             @report_storage @report_chassis @report_other
          );
 
@@ -46,18 +46,12 @@ use vars qw( $NAME $VERSION $AUTHOR $CONTACT $E_OK $E_WARNING $E_CRITICAL
 # Initialization and global variables
 #---------------------------------------------------------------------
 
-# 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;
+# Collect perl warnings in an array
+$SIG{__WARN__} = sub { push @perl_warnings, [@_]; };
 
 # Version and similar info
 $NAME    = 'check_openmanage';
-$VERSION = '3.5.4-beta6';
+$VERSION = '3.5.8-beta2';
 $AUTHOR  = 'Trond H. Amundsen';
 $CONTACT = 't.h.amundsen@usit.uio.no';
 
@@ -90,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
@@ -100,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:
 
@@ -127,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
@@ -172,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},
@@ -192,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
@@ -297,7 +293,7 @@ if (!$snmp && -f $FW_LOCK) {
     );
 
 # Performance data
-%perfdata = ();
+@perfdata = ();
 
 # Global health status
 $global         = 1;      # default is to check global status
@@ -558,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;
@@ -596,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;
@@ -827,7 +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                                # No power monitoring capability
+#          | Current\sprobes\snot\sfound                                # OMSA + RHEL5.4 bug
         }xms;
 
     # Errors that are OK on blade servers
@@ -951,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;
 }
 
@@ -1052,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
@@ -1098,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;
@@ -1107,8 +1123,8 @@ sub check_controllers {
     my $mindr    = undef;
     my $firmware = undef;
     my $driver   = undef;
-    my $minstdr  = undef;  # Minimum required Storport driver version (whats this?)
-    my $stdr     = undef;  # Storport driver version (whats this?)
+    my $minstdr  = undef;  # Minimum required Storport driver version
+    my $stdr     = undef;  # Storport driver version
     my @output   = ();
 
     if ($snmp) {
@@ -1123,8 +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' => 'FIXME_StorportDriverVersion',
-            '1.3.6.1.4.1.674.10893.1.20.130.1.1.56' => 'FIXME_StorportMinDriverVersion',
+            '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
@@ -1157,7 +1173,7 @@ sub check_controllers {
        if ($snmp) {
            $id       = $out->{controllerNumber} - 1;
            $name     = $out->{controllerName};
-           $state    = $ctrl_state{$out->{controllerState}};
+           $state    = get_hashval($out->{controllerState}, \%ctrl_state);
            $status   = $snmp_status{$out->{controllerComponentStatus}};
            $minfw    = exists $out->{controllerMinFWVersion}
              ? $out->{controllerMinFWVersion} : undef;
@@ -1167,10 +1183,10 @@ sub check_controllers {
              ? $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} : 'N/A';
+           $minstdr  = exists $out->{'controllerMinRequiredStorportVer'}
+             ? $out->{controllerMinRequiredStorportVer} : undef;
+           $stdr     = exists $out->{controllerStorportDriverVersion}
+             ? $out->{controllerStorportDriverVersion} : undef;
            $nexus    = convert_nexus($out->{controllerNexusID});
        }
        else {
@@ -1191,7 +1207,7 @@ sub check_controllers {
              ? $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'} : 'N/A';
+             ? $out->{'Storport Driver Version'} : undef;
            $nexus    = $id;
        }
 
@@ -1203,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);
 
@@ -1250,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;
@@ -1280,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;
@@ -1295,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);
        }
@@ -1311,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',
@@ -1328,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'};
@@ -1383,15 +1429,17 @@ sub check_physical_disks {
        $vendor =~ s{\(tm\)\z}{}xms;
 
        # Special case: Failure predicted
-       if ($status eq 'Non-Critical' and $fpred) {
+       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
@@ -1416,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;
@@ -1440,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;
@@ -1483,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',
        );
 
@@ -1493,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});
@@ -1549,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;
@@ -1569,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;
@@ -1620,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;
@@ -1707,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;
@@ -1727,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;
@@ -1771,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;
@@ -1802,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;
@@ -1822,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;
@@ -1849,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});
@@ -1898,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;
@@ -1921,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';
 
-       my $result = $snmp_session->get_entries(-columns => [keys %fan_oid]);
+           $result = $snmp_session->get_table(-baseoid => $fanTable);
+            my $ext = $snmp_session->get_table(-baseoid => $fanConnectionTable);
+
+           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;
@@ -1955,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;
@@ -1997,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;
@@ -2018,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;
@@ -2051,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};
@@ -2091,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;
@@ -2120,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;
@@ -2153,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};
@@ -2195,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;
@@ -2209,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;
@@ -2230,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;
@@ -2264,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};
@@ -2303,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;
@@ -2320,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;
@@ -2414,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;
@@ -2432,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;
@@ -2495,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;
@@ -2508,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;
@@ -2525,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;
@@ -2576,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;
 
@@ -2624,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;
@@ -2686,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'};
@@ -2715,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);
@@ -2791,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,
+                               };
            }
        }
     }
@@ -2805,6 +3001,8 @@ sub check_temperatures {
 # CHASSIS: Check processors
 #-----------------------------------------
 sub check_processors {
+    return if blacklisted('cpu', 'all');
+
     my $index   = undef;
     my $status  = undef;
     my $state   = undef;
@@ -2833,8 +3031,19 @@ sub check_processors {
             '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]);
+           $result = $snmp_session->get_table(-baseoid => $processorDeviceTable);
+           my $ext = $snmp_session->get_table(-baseoid => $processorDeviceStatusTable);
+
+            defined $ext && map { $$result{$_} = $$ext{$_} } keys %{ $ext };
+       }
+       else {
+           $result = $snmp_session->get_entries(-columns => [keys %cpu_oid]);
+       }
 
        if (!defined $result) {
            printf "SNMP ERROR [processors]: %s.\n", $snmp_session->error;
@@ -2872,49 +3081,132 @@ sub check_processors {
     # 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',
+        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:
@@ -2940,7 +3232,7 @@ sub check_processors {
                $state = join q{, }, @states;
            }
            else {
-               $state  = $cpu_state{$out->{processorDeviceStatusState}};
+               $state  = get_hashval($out->{processorDeviceStatusState}, \%cpu_state);
            }
            $man    = $out->{processorDeviceManufacturerName};
            $family = (exists $out->{processorDeviceFamily}
@@ -3009,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;
@@ -3050,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 {
@@ -3079,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;
@@ -3093,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;
@@ -3116,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 {
@@ -3141,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;
@@ -3162,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;
@@ -3217,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}
@@ -3261,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,
+                           };
        }
     }
 
@@ -3277,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;
            }
        }
@@ -3294,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;
            }
        }
@@ -3317,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;
@@ -3329,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;
@@ -3353,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'};
@@ -3692,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;
@@ -4063,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};
            }
@@ -4129,6 +4457,9 @@ else {
     }
 }
 
+# Reset the WARN signal
+$SIG{__WARN__} = 'DEFAULT';
+
 # Print any perl warnings that have occured
 if (@perl_warnings) {
     foreach (@perl_warnings) {
@@ -4138,26 +4469,21 @@ if (@perl_warnings) {
     $exit_code = $E_UNKNOWN;
 }
 
-# Reset the WARN signal
-$SIG{__WARN__} = $original_sigwarn;
-
 # 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