#!/usr/bin/perl
#
# Examine Sun prtdiag -v output for errors.
# This is only really useful on Sun Solaris Sparc machines.
#
# There's some really ugly code in here.
#
# by Doke Scott, doke@udel.edu, 7 Sep 2003
#
# $Header: /home/doke/work/nagios/RCS/check_prtdiag,v 1.55 2017/06/16 20:52:30 doke Exp $

#use warnings;
use strict;
use Getopt::Long;

my( @crits, @warns, @unknowns, @oks, $mode, $reparse, $system_config,
    $ncpus, $cpumhz, $led1, $led2, $led3 );

$ENV{PATH} = "/usr/bin";

my $crit_temp = 60;   # for normal/older cpus, power supplies, boards, etc
my $warn_temp = 50;

my $crit_temp_die = 90;   # for on-die sensor cpus
my $warn_temp_die = 80;

my $verbose = 0;
my $help = 0;

#################

sub usage {
    my( $rc ) = @_;
    print "Usage: $0 [-vh]
    Check output of prtdiag -v for hardware faults.
    Only useful on Sun Solaris Sparc systems.
    -v    verbose
    -h    help
";
    exit $rc;
    }



Getopt::Long::Configure ("bundling");
GetOptions(
    'v+' => \$verbose,
    'h' => \$help,
    );
&usage( 0 ) if ( $help );





exit check_prtdiag();


#################



sub check_prtdiag {
    my( $rc );

    run_prtdiag();

    $rc = 0;   # nagios ok exit code
    $" = ", ";
    if ( scalar( @crits ) ) {
	print "CRITICAL: @crits ";
	$rc = 2;
	}
    if ( scalar( @warns ) ) {
	print "; " if ( $rc != 0 );
	print "Warning: @warns ";
	$rc = 1 if ( $rc == 0 );
	}
    if ( scalar( @unknowns ) ) {
	print "; " if ( $rc != 0 );
	print "Unknown: @unknowns ";
	$rc = -1 if ( $rc == 0 );
	}
    elsif ( $rc == 0 ) {
	print "OK @oks";
	}
    print "\n";
    return $rc;
    }



sub run_prtdiag {
    my( $prtdiag, $cmd, $memory, $units, $mode_prev );

    $prtdiag = '/usr/sbin/prtdiag';
    if ( ! -x $prtdiag ) {
	$prtdiag = '/usr/platform/sun4u/sbin/prtdiag';
	}
    if ( ! -x $prtdiag ) {
	$prtdiag = '/usr/platform/sun4m/sbin/prtdiag';
	}
    if ( ! -x $prtdiag ) {
	$prtdiag = '/usr/platform/sun4c/sbin/prtdiag';
	}
    if ( ! -x $prtdiag ) {
	print "can't find prtdiag command\n";
	return -1;   # nagios unknown exit code
	}

    $cmd = "$prtdiag -v |";
    if ( ! open( pH, $cmd ) ) {
	print "can't run $cmd: $!\n";
	return -1;   # nagios unknown exit code
	}

    $mode = 'default';
    $mode_prev = '';
    $reparse = 0;
    while ( 1 ) {
	if ( $verbose && $mode ne $mode_prev ) { 
	    print "mode: $mode\n";
	    $mode_prev = $mode;
	    }

	if ( $reparse )  { 
	    $verbose && print "reparse: $_\n";
	    }
	else { 
	    $_ = <pH>;
	    last if ( ! defined $_ );
	    $verbose && print ">$_";
	    chomp;
	    $reparse = 0;
	    }

	# ignore some crap
	next if ( m/^\s*$|^[\s=-]*$/ );

	if ( m/^System Configuration: *(\S.*)/ ) {
	    $system_config = $1;
	    if ( m/(Blade|Enterprise|Fire|Netra|Ultra)\s+(.*)/i ) {
		push @oks, "Sun $1 $2";
		}
	    elsif ( m/VMware Virtual Platform/ ) { 
		# no point to testing simulated virtual hardware
		push @oks, "VMware";
		return;
		}
	    next;
	    }

	next if ( m/^System clock frequency:/ );

	if ( m/^Memory size:\s*(\d+)\s*(Megabytes|MB|GB)/i ) {
	    $memory = $1;
	    $units = $2;
	    $units =~ s/Megabytes/MB/;
	    push @oks, sprintf( "memory %d %s", $memory, $units );
	    next;
	    }

	next if ( m/^Keyswitch position:/ );
	next if ( m/^BIOS Configuration:/ );
	next if ( m/^BMC Configuration:/ );


	###########
	# mode setting tests
	#
	if ( m/^=+\s*(Virtual\s+)?CPUs\s*=+$/ ) {
	    $mode = 'cpus';
	    }
	elsif ( m/^=+\s*(Memory|Memory Configuration|Physical Memory Configuration)\s*=+$/ ) {
	    if ( $system_config =~ m/v210/i ) {
		$mode = 'memory_v210';
		}
	    else {
		$mode = 'memory';
		}
	    }
	elsif ( m/^=+\s*IO Cards\s*=+$/ ) {
	    $mode = 'io_cards';
	    }
	elsif ( m/^=+\s*IO Devices\s*=+$/ ) {
	    $mode = 'io_devices';
	    }
	elsif ( m/^=+\s*IO Configuration\s*=+$/ ) {
	    $mode = 'io_configuration';
	    }
	elsif ( m/^=+\s*Active Boards for Domain\s*=+$/ ) {
	    $mode = 'active_boards';
	    }
	elsif ( m!^=+\s*Available Boards/Slots for Domain\s*=+$! ) {
	    $mode = 'available_boards';
	    }
	elsif ( m/^=+\s*Hardware Failures\s*=+$/ ) {
	    $mode = 'hardware_failures';
	    }
	elsif ( m/^=+\s*usb Devices\s*=+$/ ) {
	    $mode = 'usb_devices';
	    }
	elsif ( m/^=+\s*Environmental Status\s*=+$/ ) {
	    # we look for the subcategories
	    $mode = 'env_status';
	    }
	elsif ( m/^System Temperatures \(Celsius\):/ || m/^Temperature sensors:/ ) {
	    $mode = 'temps';
	    }
	elsif ( m/^Temperature indicators:/ ) {
	    $mode = 'temp_indicators';
	    }
	elsif ( m/^Current sensors:/ ) {
	    $mode = 'current_sensors';
	    }
	elsif ( m/^Current indicators:/ ) {
	    $mode = 'current_indicators';
	    }
	elsif ( m/^Voltage sensors:/ ) {
	    $mode = 'voltage_sensors';
	    }
	elsif ( m/^Voltage indicators:/ ) {
	    $mode = 'voltage_indicators';
	    }
	elsif ( m/^Keyswitch:/ ) {
	    $mode = 'keyswitch';
	    }
	elsif ( m/^Led State:|LEDs:/ ) {
	    $mode = 'led_state';
	    }
	elsif ( m/^Front Status Panel:/
		|| m/^Keyswitch position is in Normal Mode/
		|| m/^System Power Status: Redundant/ ) {
	    $mode = 'panel';
	    }
	elsif ( m/^Disk Status:/ ) {
	    $mode = 'disks';
	    }
	elsif ( m/^(Fan (Bank |Speeds|Status|sensors)|Fans):/i ){
	    $mode = 'fans';
	    }
	elsif ( m/^Power Supplies:/ ) {
	    $mode = 'power_supplies';
	    }
	elsif ( m/^=+\s*FRU (Operational )?Status\s*=+$/ ) {
	    $mode = 'fru_status';
	    }
	elsif ( m/^=+\s*HW Revisions\s*=+$/ ) {
	    # look for the subcategories
	    }
	elsif ( m/^=+\s*Hardware Revisions\s*=+$/ ) {
	    # look for the subcategories
	    }
	elsif ( m/^ASIC Revisions:/ ) {
	    $mode = 'asic_revs';
	    }
	elsif ( m/^=+\s*FW Version\s*=+\s*$/ ) {
	    $mode = 'fw_version';
	    }
	elsif ( m/^System PROM revisions:/
		|| m/^=+\s*System PROM revisions\s*=+\s*$/ 
		|| m/^System Board PROM revisions:/ ) {
	    $mode = 'prom_revs';
	    }
	elsif ( m/^IO ASIC revisions:/ ) {
	    $mode = 'io_asic_revs';
	    }
	elsif ( m/^=+\s*Processor\s*Sockets\s*=+$/ ) {
	    $mode = 'processor_sockets';
	    }
	elsif ( m/^=+\s*Memory\s*Device\s*Sockets\s*=+$/ ) {
	    $mode = 'memory_device_sockets';
	    }
	elsif ( m/^=+\s*On-Board\s*Devices\s*=+$/ ) {
	    $mode = 'on_board_devices';
	    }
	elsif ( m/^=+\s*Upgradeable\s*Slots\s*=+$/ ) {
	    $mode = 'upgradable_slots';
	    }
	elsif ( m/^Chassis Serial Number:?\s*$/ ) {
	    $mode = 'chassis_serial_number';
	    }
	elsif ( m/^===+\s*System Processor Mode\s*===+$/ ) {
	    # we look for the subcategories
	    $mode = 'sys_proc_mode';
	    }


	#############
	# explicit (no) failure notices
	#
	elsif ( m/^No Hardware failures found in System/i
		|| m/^No failures found in System/i
		|| m/^No System Faults found/i ) {
	    # can't trust this, sigh
	    push @oks, $_;
	    }
	#elsif ( m/NO_FAULT|\bno fault|\bno failure/i ) {
	    #}
	#elsif ( m/failed|failure|faulted|bad/i ) {
	    #push @crits, "line $. in main: $_";
	    #}



	else { 

	    if ( $reparse ) {
		# reparse didn't set a mode
		# if we continue into mode calls, we'll infinite loop
		$verbose && print "unexpected line in mode $mode $.: $_\n";
		push @warns, "unexpected line in mode $mode $.: $_";
		$reparse = 0;
		next;
		}

	    # Now do the per-mode calls.
	    # These don't return anything.  If they recognize the current line,
	    # they'll just return, possibly pushing something onto one of the
	    # message lists as a side effect.  If they don't recognize the
	    # line, they'll set reparse = 1 as a side effect. 
	    #

	    $reparse = 0;
	    if ( $mode eq 'default' )  {
		# should have been handled above by a mode setting match  
		$reparse = 1;
		next;
		}
	    elsif ( $mode eq 'cpus' )  {
		&check_cpus();
		}
	    elsif ( $mode eq 'memory' )  {
		&check_memory();
		}
	    elsif ( $mode eq 'memory_v210' )  {
		&check_memory_v210();
		}
	    elsif ( $mode eq 'io_cards' )  {
		&check_io_cards();
		}
	    elsif ( $mode eq 'io_devices' )  {
		&check_io_devices();
		}
	    elsif ( $mode eq 'io_configuration' )  {
		&check_io_configuration();
		}
	    elsif ( $mode eq 'active_boards' )  {
		&check_active_boards();
		}
	    elsif ( $mode eq 'available_boards' )  {
		&check_available_boards();
		}
	    elsif ( $mode eq 'hardware_failures' )  {
		&check_hardware_failures();
		}
	    elsif ( $mode eq 'usb_devices' )  {
		&check_usb_devices();
		}
	    elsif ( $mode eq 'env_status' )  {
		&check_env_status();
		}
	    elsif ( $mode eq 'temps' )  {
		&check_temps();
		}
	    elsif ( $mode eq 'temp_indicators' )  {
		&check_temp_indicators();
		}
	    elsif ( $mode eq 'current_sensors' )  {
		&check_current_sensors();
		}
	    elsif ( $mode eq 'current_indicators' )  {
		&check_current_indicators();
		}
	    elsif ( $mode eq 'voltage_sensors' )  {
		&check_voltage_sensors();
		}
	    elsif ( $mode eq 'voltage_indicators' )  {
		&check_voltage_indicators();
		}
	    elsif ( $mode eq 'keyswitch' )  {
		&check_keyswitch();
		}
	    elsif ( $mode eq 'led_state' )  {
		&check_led_state();
		}
	    elsif ( $mode eq 'panel' )  {
		&check_panel();
		}
	    elsif ( $mode eq 'disks' )  {
		&check_disks();
		}
	    elsif ( $mode eq 'fans' )  {
		&check_fans();
		}
	    elsif ( $mode eq 'power_supplies' )  {
		&check_power_supplies();
		}
	    elsif ( $mode eq 'fru_status' )  {
		&check_fru_status();
		}
	    elsif ( $mode eq 'asic_revs' )  {
		&check_asic_revs();
		}
	    elsif ( $mode eq 'fw_version' )  {
		&check_fw_version();
		}
	    elsif ( $mode eq 'prom_revs' )  {
		&check_prom_revs();
		}
	    elsif ( $mode eq 'io_asic_revs' )  {
		&check_io_asic_revs();
		}
	    elsif ( $mode eq 'processor_sockets' ) {
		check_processor_sockets();
		}
	    elsif ( $mode eq 'memory_device_sockets' ) {
		check_memory_device_sockets();
		}
	    elsif ( $mode eq 'on_board_devices' ) {
		check_on_board_devices();
		}
	    elsif ( $mode eq 'upgradable_slots' ) {
		check_upgradable_slots();
		}
	    elsif ( $mode eq 'chassis_serial_number' ) {
		check_chassis_serial_number();
		}
	    elsif ( $mode eq 'sys_proc_mode' ) {
		check_sys_proc_mode();
		}

	    else {
		$verbose && print "internal error: unknown mode $mode\n";
		push @crits, "internal error: unknown mode $mode";
		}
	    }
	}
    close pH;

    if ( $ncpus ) { 
	if ( $cpumhz ) { 
	    push @oks, "cpus $ncpus ${cpumhz}MHz";
	    }
	else { 
	    push @oks, "cpus $ncpus";
	    }
	}
    }





##########################







sub check_cpus {
    my( $cpu, $temp_die, $temp_amb, $location, $status );

    # from a V100, with 5.9
    #                     Run   Ecache   CPU    CPU
    # Brd  CPU   Module   MHz     MB    Impl.   Mask
    # ---  ---  -------  -----  ------  ------  ----
    #  0     0     0      500     0.2   13       1.4
    return if ( m/^\s+Run   Ecache   CPU    CPU/ );
    return if ( m/^Brd  CPU   Module   MHz     MB    Impl.   Mask/ );
    if ( m/^\s*\d+ +\d+ +\d+ +(\d+) +[\d\.]+ +\d+ +[\d\.]+/ ) { 
	$ncpus++;
	$cpumhz = $1;
	return;
	}


    # from a Sun Blade 150 with 5.9
#               E$          CPU                  CPU    Temperature
#CPU  Freq      Size        Implementation       Mask   Die   Amb.  Location
#---  --------  ----------  -------------------  -----  ----  ----  --------
#  0   650 MHz  512KB       SUNW,UltraSPARC-IIe   3.3    61C   31C  +-board/cpu0
    return if ( m/^\s+E\$\s+CPU\s+CPU\s+Temperature/ix );
    return if ( m/^CPU \s+ Freq \s+ Size \s+ Implementation /ix );
    if ( m/^\s* (\d+) \s+ (\d+) \s+ [MG]Hz \s+ \d+[MK]B \s+ \S+ \s+ [\d\.]+ \s+
	    ([\d\.-]+)C? \s+ ([\d\.-]+)C? \s+ (\S+) \s*$/ix ) {
	( $cpu, $cpumhz, $temp_die, $temp_amb, $location ) = ( $1, $2, $3, $4, $5 );
	if ( $temp_die >= $crit_temp_die || $temp_amb >= $crit_temp ) {
	    push @crits, "cpu $cpu temperature too high $temp_die $temp_amb";
	    }
	elsif ( $temp_die >= $warn_temp_die || $temp_amb >= $warn_temp ) {
	    push @warns, "cpu $cpu temperature too high $temp_die $temp_amb";
	    }
	$ncpus ++;
	return;
	}



    # from a V210, with 5.9
#               E$          CPU                  CPU     Temperature
# CPU  Freq      Size        Implementation       Mask    Die   Amb.  Status      Location
# 0  1002 MHz  1MB         SUNW,UltraSPARC-IIIi   2.3     -     -    online      MB/P0
# from a Sun Blade 100 with 5.9
# 0   502 MHz  256KB       SUNW,UltraSPARC-IIe    1.4     53C   32C  online      +-board/cpu0

    if ( m/^ \s* (\d+) \s+ (\d+) \s+ MHz \s+ \d+[MK]B \s+ \S+ \s+ [\d\.]+ \s+ 
	    ([\d\.-]+)C? \s+ ([\d\.-]+)C? \s+ (\w+) \s+ (\S+) \s* $/xi ) {
	( $cpu, $cpumhz, $temp_die, $temp_amb, $status, $location ) 
	    = ( $1, $2, $3, $4, $5, $6 );
	if ( $status !~ m/on-?line/ ) {
	    push @crits, "cpu $cpu not online";
	    }
	elsif ( $temp_die >= $crit_temp_die || $temp_amb >= $crit_temp ) {
	    push @crits, "cpu $cpu temperature too high $temp_die $temp_amb";
	    }
	elsif ( $temp_die >= $warn_temp_die || $temp_amb >= $warn_temp ) {
	    push @warns, "cpu $cpu temperature too high $temp_die $temp_amb";
	    }
	$ncpus ++;
	return;
	}

    # from another v210, also with 5.9, but different patch rev
#               E$          CPU                  CPU    Temperature
#CPU  Freq      Size        Implementation       Mask   Die   Amb.  Location
#---  --------  ----------  -------------------  -----  ----  ----  --------
#  0  1002 MHz  1MB         SUNW,UltraSPARC-IIIi   2.4    -     -    MB/P0
#  1  1002 MHz  1MB         SUNW,UltraSPARC-IIIi   2.4    -     -    MB/P1

    if ( m/^\s+(\d+) +(\d+) +MHz +\d+MB +\S+ +[\d\.]+ +([\d\.-]+) +([\d\.-]+) +(\S+)\s*$/ ) {

	( $cpu, $cpumhz, $temp_die, $temp_amb, $location ) = ( $1, $2, $3, $4, $5 );
	if ( $temp_die >= $crit_temp_die || $temp_amb >= $crit_temp ) {
	    push @crits, "cpu $cpu temperature too high $temp_die $temp_amb";
	    }
	elsif ( $temp_die >= $warn_temp_die || $temp_amb >= $warn_temp ) {
	    push @warns, "cpu $cpu temperature too high $temp_die $temp_amb";
	    }
	$ncpus ++;
	return;
	}

    # from a v210, with Solaris 10 beta
#==================================== CPUs ====================================
#               E$          CPU                  CPU
#CPU  Freq      Size        Implementation       Mask    Status      Location
#---  --------  ----------  -------------------  -----   ------      --------
#  0  1002 MHz  1MB         SUNW,UltraSPARC-IIIi  2.4    online      MB/P0
#  1  1002 MHz  1MB         SUNW,UltraSPARC-IIIi  2.4    online      MB/P1

    # from a Sun Server Blade B1600 blade, with S10_55
#               E$          CPU                  CPU
#CPU  Freq      Size        Implementation       Mask    Status      Location
#---  --------  ----------  -------------------  -----   ------      --------
#  0   650 MHz  512KB       SUNW,UltraSPARC-IIe   3.3    on-line     Blade/CPU0

    # from a v440, with Sol10
#==================================== CPUs ====================================
#               E$          CPU                    CPU
#CPU  Freq      Size        Implementation         Mask    Status      Location
#---  --------  ----------  ---------------------  -----   ------      --------
#0    1281 MHz  1MB         SUNW,UltraSPARC-IIIi    2.4    on-line      -


    return if ( m/^\s+E\$\s+CPU\s+CPU/ );
    if ( m/^ \s* (\d+) \s+ (\d+) \s* MHz \s+ \d+[KM]B \s+ SUNW\S+ \s+ [\d\.]+
	    \s+ (\S+) \s+ (\S+) \s* $/ix ) {

	( $cpu, $cpumhz, $status, $location ) = ( $1, $2, $3, $4 );
	if ( $status eq "-" && $location eq "-" ) {
	    # v440 with 5.8, psychout
	    return;
	    }
	elsif ( $status !~ m/on-?line/ ) {
	    push @crits, "cpu $cpu not online: $_";
	    }
	$ncpus ++;
	return;
	}

    # from a 280R with 5.8
    # also a V880 with 5.9
    #           Run   E$    CPU    CPU
    # Brd  CPU  MHz   MB   Impl.   Mask
    # ---  ---  ---  ----  ------  ----
    #  A    0   750   8.0  US-III  5.4
    #  B    1   750   8.0  US-III  5.4
    #  A    0    900   8.0  US-III+  2.2
    #  B    1    900   8.0  US-III+  2.2
    return if ( m/^\s+Run +E. +CPU +CPU/ );
    return if ( m/^Brd +CPU +MHz +MB +Impl. +Mask/ );
    if ( m/^\s*[A-Z] +\d+ +(\d+) +[\d\.]+ +US-III?\+? +[\d\.]+/ ) { 
	$ncpus++;
	$cpumhz = $1;
	return;
	}

    # from a v440 with 5.8
#==================================== CPUs ====================================
#                      E$          CPU     CPU       Temperature         Fan
#       CPU  Freq      Size        Impl.   Mask     Die    Ambient   Speed   Unit
#       ---  --------  ----------  ------  ----  --------  --------  -----   ----
#         0  1281 MHz  1MB         US-IIIi  2.4       -        -
#         1  1281 MHz  1MB         US-IIIi  2.4       -        -
#         2  1281 MHz  1MB         US-IIIi  2.4       -        -
#         3  1281 MHz  1MB         US-IIIi  2.4       -        -
    return if ( m/^\s+E\$\s+CPU\s+CPU\s+Temperature\s+Fan/ );
    return if ( m/^\s*CPU +Freq +Size +Impl. +Mask +Die +Ambient +Speed/ );
    if ( m/^\s+\d+ +(\d+) +MHz +\d+MB +\S+ +[\d\.]+ +- +-\s*$/ ) { 
	$ncpus++;
	$cpumhz = $1;
	return;
	}


    # from a 450 with 5.8
    #                    Run   Ecache   CPU    CPU
    #Brd  CPU   Module   MHz     MB    Impl.   Mask
    #---  ---  -------  -----  ------  ------  ----
    #SYS     0     0      248     1.0   US-II    1.1
    #SYS     1     1      248     1.0   US-II    2.0
    if ( m/^SYS +\d+ +\d+ +(\d+) +[\d\.]+ +US-II +[\d\.]+/ ) { 
	$ncpus++;
	$cpumhz = $1;
	return;
	}


    # from a V490 with 5.10
#          Run   E$  CPU     CPU
#Brd  CPU  MHz   MB  Impl.   Mask
#--- ----- ---- ---- ------- ----
# A  0, 16 1500 32.0 US-IV+   2.2
# B  1, 17 1500 32.0 US-IV+   2.2
# A  2, 18 1500 32.0 US-IV+   2.2
# B  3, 19 1500 32.0 US-IV+   2.2
    if ( m/^ \s* [AB] \s+ \d+, \s* \d+ \s+ (\d+) \s+ [\d\.]+ \s+
	    US-IV\+ \s+ [\d\.]+ \s* $/ix ) { 
	$ncpus++;
	$cpumhz = $1;
	return;
	}


    # from a V890 with 5.9
    #            Run   E$  CPU    CPU
    # Brd  CPU   MHz   MB Impl.   Mask
    # --- ----- ---- ---- ------- ----
    #  A  0, 16 1200 16.0 US-IV    2.4
    #  B  1, 17 1200 16.0 US-IV    2.4
    #  A  2, 18 1200 16.0 US-IV    2.4
    #  B  3, 19 1200 16.0 US-IV    2.4
    if ( m/^\s*[A-Z] +\d+, +\d+ +(\d+) +[\d\.]+ +US-IV +[\d\.]+/ ) { 
	$ncpus++;
	$cpumhz = $1;
	return;
	}

    # from a 4000 with 5.8
    #                    Run   Ecache   CPU    CPU
    #Brd  CPU   Module   MHz     MB    Impl.   Mask
    #---  ---  -------  -----  ------  ------  ----
    # 0     0     0      248     4.0   US-II    1.1
    # 0     1     1      248     4.0   US-II    1.1
    if ( m/^\s*\d+ +\d+ +\d+ +(\d+) +[\d\.]+ +US-II +[\d\.]+/ ) { 
	$ncpus++;
	$cpumhz = $1;
	return;
	}


    # from a 3800 with 5.8
#            Port  Run    E$   CPU     CPU   Temp   Sensor  Voltage   Sensor
#FRU Name     ID   MHz    MB   Impl.   Mask  Deg C  Status  Volts DC  Status
#----------  ----  ----  ----  ------  ----  -----  ------  --------  ------
#/N0/SB2/P0    8    750   8.0  US-III  3.4   55     Green   1.74      Green
#/N0/SB2/P1    9    750   8.0  US-III  3.4   55     Green   1.71      Green
    return if ( m/^\s+Port  Run    E$   CPU     CPU   Temp   Sensor  Voltage/ );
    return if ( m/^FRU Name     ID   MHz    MB   Impl.   Mask  Deg C/ );
    if ( m!^(/N\d+/SB\d+/P\d+) +\d+ +(\d+) +[\d\.]+ +US-III +[\d\.]+ +(\d+) +(\w+) +([\d\.]+) +(\w+)\s*$! ) {
	if ( $4 ne "Green" || ( $2 < 500 && $3 >= $crit_temp )
		|| $3 >= $crit_temp_die ) {
	    push @crits, "$1 temperature too high $3 $4";
	    }
	if ( ( $2 < 500 && $3 >= $warn_temp ) || $3 >= $warn_temp_die ) {
	    push @warns, "$1 temperature too high $3 $4";
	    }
	if ( $5 < 1.70 || 1.75 < $5 || $6 ne "Green" ) {
	    push @crits, "$1 voltage bad $4 $5";
	    }
	$ncpus++;
	$cpumhz = $2;
	return;
	}


    # from a 4810 with 5.8
#            Port  Run    E$   CPU     CPU   Temp   Sensor  Voltage   Sensor
#FRU Name     ID   MHz    MB   Impl.   Mask  Deg C  Status  Volts DC  Status
#----------  ----  ----  ----  ------  ----  -----  ------  --------  ------
#/N0/SB0/P0    0    750   8.0  US-III  3.4   ???    ???     ???       ???
#/N0/SB0/P1    1    750   8.0  US-III  3.4   ???    ???     ???       ???
    if ( m!^/N\d+/SB\d+/P\d+ +\d+ +(\d+) +[\d\.]+ +US-III +[\d\.]+ +\?\?\?! ) {
	$ncpus++;
	$cpumhz = $1;
	return;
	}


    # from a 6800 with 5.9
    #             Port  Run    E$   CPU      CPU
    # FRU Name     ID   MHz    MB   Impl.    Mask
    # ----------  ----  ----  ----  -------  ----
    # /N0/SB2/P0    8    750   8.0  US-III   3.4
    # /N0/SB2/P1    9    750   8.0  US-III   3.4
    # /N0/SB2/P2   10    750   8.0  US-III   3.4
    return if ( m/^\s+Port  Run    E.   CPU      CPU/ );
    return if ( m/^FRU Name +ID +MHz +MB +Impl. +Mask/ );
    if ( m!^/N\d+/SB\d+/P\d+ +\d+ +(\d+) +[\d\.]+ +US-III +[\d\.]+! ) { 
	$ncpus++;
	$cpumhz = $1;
	return;
	}


    # from a 6800 with 5.10_52
#            CPU      Run    E$   CPU      CPU
#FRU Name    ID       MHz    MB   Impl.    Mask
#----------  -------  ----  ----  -------  ----
#/N0/SB2/P0    8       750   8.0  US-III   3.4

    return if ( m/^\s+CPU +Run +E. +CPU +CPU/ );



    # from a T2000 with 5.10
#========================= CPUs ===============================================
#
#                            CPU                 CPU
#Location     CPU   Freq     Implementation      Mask
#------------ ----- -------- ------------------- -----
#MB/CMP0/P0       0 1200 MHz  SUNW,UltraSPARC-T1
#MB/CMP0/P1       1 1200 MHz  SUNW,UltraSPARC-T1
#MB/CMP0/P31     31 1200 MHz  SUNW,UltraSPARC-T1

    return if ( m/^ \s+ CPU \s+ CPU \s* $/x );
    return if ( m/^ Location \s+ CPU \s+ Freq \s+ Implementation \s+ Mask \s* $/x );
    if ( m!^ MB/CMP\d+/P\d+ \s+ \d+ \s+ (\d+) \s MHz \s+ SUNW,\S+ \s* $!x ) {
	$ncpus++;
	$cpumhz = $1;
	return;
	}

    
    # from a Sun SPARC Enterprise M4000 Server
#==================================== CPUs ====================================
#
#       CPU              CPU            Run       L2$       CPU      CPU     
#LSB    Chip              ID            MHz        MB       Impl.    Mask    
#---    ----      --------------------  ----      ---       -----    ----    
# 00      1          8,   9,  10,  11   2150      5.0          6      146
    return if ( m/^ \s+ CPU \s+ CPU \s+ Run \s+ L2\$ \s+ 
	CPU \s+ CPU \s* $/x );
    return if ( m/^ \s* LSB \s+ Chip \s+ ID \s+ MHz \s+ MB \s+ 
	Impl. \s+ Mask \s* $/x );
    if ( m/^ \s* \d+ \s+ \d+ \s+ \d[\d,\s]* \s+ (\d+) \s+ [\d\.]+ \s+ 
	    \d+ \s+ \d+ \s* $/x ) {
	$ncpus++;
	$cpumhz = $1;
	return;
	}

    # from a Sun T3-1 with 5.10 Generic_142909-17
#CPU ID Frequency Implementation         Status
#------ --------- ---------------------- -------
#0      1649 MHz  SPARC-T3               on-line  
#1      1649 MHz  SPARC-T3               on-line  
#0      1200 MHz  SUNW,UltraSPARC-T1     on-line  
#1      1200 MHz  SUNW,UltraSPARC-T1     on-line  

    if ( $system_config =~ m/T3-|sun4v|T[12]00/ ) { 
	return if ( m/^ CPU \s+ ID \s+ Frequency \s+ Implementation \s+ Status \s* $/x );
	if ( m/^ (\d+) \s+ (\d+) \s MHz \s+ (SPARC-T\d+|SUNW,UltraSPARC-T\d) \s+ (\S+) \s* $/x ) { 
	    if ( $4 ne 'on-line' ) { 
		push @crits, "cpu $1 $3";
		}
	    $ncpus++;
	    $cpumhz = $2;
	    return;
	    }
	}




    $reparse = 1;
    }





sub check_memory {

    if ( m/^Segment Table:/ ) {
	$mode = "memory_v210";
	check_memory_v210();
	return;
	}

    # from a E250 with 5.8
#       Interlv.  Socket   Size
#Bank    Group     Name    (MB)  Status
#----    -----    ------   ----  ------
#  0      none     U0701   128      OK
#  0      none     U0801   128      OK
#  0      none     U0901   128      OK
#  0      none     U1001   128      OK
#  1      none     U0702   128      OK
#  1      none     U0802   128      OK
#  1      none     U0902   128      OK
#  1      none     U1002   128      OK
#  2      none     U0703   128      OK
    if ( $system_config =~ m/Enterprise 250/i ) {
	if ( m/^\s* (\d+) \s+ none \s+ (U\d+) \s+ (\d+) \s+ (\S+) \s*$/xi ) {
	    if ( $4 ne "OK" ) {
		push @crits, "mem $2 $4";
		}
	    return;
	    }
	}



    # from a 280R with 5.8
    # also a V880 with 5.9
#           Logical  Logical  Logical
#      MC   Bank     Bank     Bank         DIMM    Interleave  Interleaved
# Brd  ID   num      size     Status       Size    Factor      with
#----  ---  ----     ------   -----------  ------  ----------  -----------
#  A    0     0      1024MB   no_status     512MB     8-way        0
#  A    0     1      1024MB   no_status     512MB     8-way        0
# CA    0     2      2048MB   no_status    1024MB     2-way        0
    return if ( m/^\s+Logical  Logical  Logical/ );
    return if ( m/^\s+MC   Bank     Bank     Bank         DIMM/ );
    return if ( m/^\s*Brd  ID   num      size     Status/ );
    return if ( m/^\s*[A-Z]+ +\d+ +\d+ +\d+MB +(no_status|ok|pass) +\d+MB/ );

    # from a 450 with 5.8
    #Memory Interleave Factor = 4-way
    #
    #       Interlv.  Socket   Size
    #Bank    Group     Name    (MB)  Status
    #----    -----    ------   ----  ------
    #  0        0       1901   256      OK
    #  0      none      1901   128      OK
    return if ( m/^Memory Interleave Factor = \d+-way/ );
    return if ( m/^\s+Interlv.  Socket   Size/ );
    return if ( m/^Bank    Group     Name    \(MB\)  Status/ );
    return if ( m/^ +\d+ +(\d+|none) +\d+ +\d+ +OK/ );

    # from a 4000 with 5.8
    #                                              Intrlv.  Intrlv.
    #Brd   Bank   MB    Status   Condition  Speed   Factor   With
    #---  -----  ----  -------  ----------  -----  -------  -------
    # 0     0    1024   Active      OK       60ns    8-way     A
    # 0     1    1024   Active      OK       60ns    8-way     A
    return if ( m/^\s+Intrlv.  Intrlv./ );
    return if ( m/^Brd   Bank   MB    Status   Condition  Speed   Factor/ );
    return if ( m/^ +\d+ +\d+ +\d+ +Active +OK +\d+ns / );


    # from a 6800 with 5.9
#                     Logical  Logical  Logical
#               Port  Bank     Bank     Bank         DIMM    Interleave  Interlea
#ve
#FRU Name        ID   Num      Size     Status       Size    Factor      Segment
#-------------  ----  ----     ------   -----------  ------  ----------  --------
#--
#/N0/SB2/P0/B0    8    0      1024MB    pass          512MB     8-way       0
#/N0/SB2/P0/B0    8    2      1024MB    pass          512MB     8-way       0
#/N0/SB2/P1/B0    9    0      1024MB    pass          512MB     8-way       0
#/N0/SB2/P1/B0    9    2      1024MB    pass          512MB     8-way       0
#/N0/SB2/P2/B0   10    0      1024MB    pass          512MB     8-way       0
    return if ( m/^\s+Logical  Logical  Logical/ );
    return if ( m/^\s+Port  Bank     Bank     Bank         DIMM/ );
    return if ( m/^FRU Name        ID   Num      Size     Status/ );
    return if ( m!^/N\d+/SB\d+/P\d+/B\d+ +\d+ +\d+ +\d+MB +pass !i );



    # from a Sun SPARC Enterprise M4000 Server
#====================== Memory Configuration ======================
#
#       Memory  Available           Memory     DIMM      Number of 
#LSB    Group   Size                Status     Size      DIMMs     
#---    ------  ------------------  -------    ------    --------- 
# 00    A         8192MB            okay       2048MB            4
# 00    B         8192MB            okay       2048MB            4

    return if ( m/^ \s+ Memory \s+ Available \s+ Memory \s+ DIMM \s+ 
	Number \s+ of \s* $/x ); 
    return if ( m/^ LSB \s+ Group \s+ Size \s+ Status \s+ Size \s+ 
	DIMMs \s* $/x );
    if ( m/^ \s* (\d+) \s+ (\w+) \s+ (\d+[MG]B+) \s+ (\S.*) \s+ (\d+[MG]B+) \s+ 
	    (\d+) \s* $/x ) { 
	$verbose && print "memory group $1/2 $4\n";
	if ( $4 !~ m/^okay/i ) { 
	    push @crits, "memory group $1/$2 $4";
	    }
	return;
	}

    # from another Sun SPARC Enterprise M4000 Server
#       Memory  Available           Memory     DIMM    # of  Mirror  Interleave
#LSB    Group   Size                Status     Size    DIMMs Mode    Factor    
#---    ------  ------------------  -------    ------  ----- ------- ----------
# 00    A        32768MB            okay       2048MB     16 no       8-way

    return if ( m/^ \s+ Memory \s+ Available \s+ Memory \s+ DIMM \s+ 
	\# \s+ of \s+ /x ); 
    return if ( m/^ LSB \s+ Group \s+ Size \s+ Status \s+ Size \s+ 
	DIMMs \s+ /x );
    if ( m/^ \s* (\d+) \s+ (\w+) \s+ (\d+[MG]B+) \s+ (\S.*) \s+ (\d+[MG]B+) \s+ 
	    (\d+) \s+ /x ) { 
	$verbose && print "memory group $1/2 $4\n";
	if ( $4 !~ m/^okay/i ) { 
	    push @crits, "memory group $1/$2 $4";
	    }
	return;
	}


    $reparse = 1;
    }



# check memory for anything that reports a Segment Table
# v210 was the first machine I encountered that had this.
sub check_memory_v210 {
    

    # from a v210 with 5.9
#Segment Table:
#-----------------------------------------------------------------------
#Base Address       Size       Interleave Factor  Contains
#-----------------------------------------------------------------------
#0x0                1GB               1           BankIDs 0
#0x1000000000       1GB               1           BankIDs 16
#
#Bank Table:
#-----------------------------------------------------------
#           Physical Location
#ID       ControllerID  GroupID   Size       Interleave Way
#-----------------------------------------------------------
#0        0             0         1GB             0
#16       1             0         1GB             0
#
#Memory Module Groups:
#--------------------------------------------------
#ControllerID   GroupID  Labels         Status
#--------------------------------------------------
#0              0        MB/P0/B0/D0
#0              0        MB/P0/B0/D1
#1              0        MB/P1/B0/D0
#1              0        MB/P1/B0/D1


# From a v240 with 5.10 125100-10 and a failed DIMM
#
#============================ Memory Configuration ============================
#Segment Table:
#-----------------------------------------------------------------------
#Base Address       Size       Interleave Factor  Contains
#-----------------------------------------------------------------------
#0x0                1GB               1           BankIDs 0
#0x100000000        1GB               1           BankIDs 1
#0x1000000000       4GB               16          BankIDs 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
#
#Bank Table:
#-----------------------------------------------------------
#           Physical Location
#ID       ControllerID  GroupID   Size       Interleave Way
#-----------------------------------------------------------
#0        0             0         1GB             0
#1        0             0         1GB             0
#16       1             0         256MB           0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
#17       1             0         256MB
#18       1             1         256MB
#19       1             1         256MB
#20       1             0         256MB
#21       1             0         256MB
#
#Memory Module Groups:
#--------------------------------------------------
#ControllerID   GroupID  Labels         Status
#--------------------------------------------------
#0              1        MB/P0/B1/D0    unused
#0              1        MB/P0/B1/D1    failed
#0              0        MB/P0/B0/D0
#0              0        MB/P0/B0/D1




    return if ( m/^Segment Table:/ );
    return if ( m/^Base Address +Size +Interleave Factor +Contains/ );
    return if ( m/^0x[\da-f]+ +\d+GB +\d+ +BankIDs +\d+/ );
    return if ( m/^Bank Table:/ );
    return if ( m/^\s+Physical Location/ );
    return if ( m/^ID +ControllerID +GroupID +Size +Interleave Way/ );
    return if ( m/^\d+ +\d+ +\d+ +\d+GB +\d/ );
    return if ( m/^Memory Module Groups:/ );
    return if ( m/^ControllerID +GroupID +Labels +Status/ );
    return if ( m!^\d+ +\d+ +MB/P\d+/B\d+/D\d+ *$! );
    if ( m!^\d+ +\d+ +(MB/P\d+/B\d+/D\d+) +(\w+) *$! ) {
	if ( $2 eq "okay" ) {
	    return;
	    }
	elsif ( $2 eq "unused" ) {
	    push @warns, "Memory module $1 $2";
	    }
	else {
	    push @crits, "Memory module $1 $2";
	    }
	return;
	}


# from a Sun BladeServer B1600 running S10_55
#0x0                512MB             1           Blade
#0x40000000         512MB             1           Blade
    return if ( m/^0x[\da-f]+ +\d+MB +\d+ +Blade/ );


    # from another v210, also with 5.9, but different patch rev
#--------------------------------------------------
#ControllerID   GroupID  Labels
#--------------------------------------------------
#0              0        MB/P0/B0/D0
#0              0        MB/P0/B0/D1
#1              0        MB/P1/B0/D0
#1              0        MB/P1/B0/D1

    return if ( m/^ControllerID +GroupID +Labels\s*$/ );

    # from yet another v210 with 5.9 Generic_117171-12
#           Physical Location
#ID       ControllerID  GroupID   Size       Interleave Way
#-----------------------------------------------------------
#0        0             0         1GB             0,1
#1        0             0         1GB
#16       1             0         512MB           0,1,2,3
    return if ( m/^\s* \d+ \s+ \d+ \s+ \d+ \s+ \d+[MG]B \s+ \d([\d,]+\d)? \s*$/ix );
    return if ( m/^\s* \d+ \s+ \d+ \s+ \d+ \s+ \d+[MG]B \s*$/ix );


    # from a v440 with 5.9
#Bank Table:
#-----------------------------------------------------------
#           Physical Location
#ID       ControllerID  GroupID   Size       Interleave Way
#-----------------------------------------------------------
#0        0             0         256MB           0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
#1        0             0         256MB
#
#Memory Module Groups:
#--------------------------------------------------
#ControllerID   GroupID  Labels         Status
#--------------------------------------------------
#0              0        C0/P0/B0/D0

    return if ( m/^\d+ +\d+ +\d+ +\d+MB +\d+,\d/ );
    return if ( m/^\d+ +\d+ +\d+ +\d+MB\s*$/ );
    return if ( m!^\d+ +\d+ +C\d+/P\d+/B\d+/D\d+! );


    # from a Sun Blade 100 with 5.9
#============================ Memory Configuration ============================
#Segment Table:
#-----------------------------------------------------------------------
#Base Address       Size       Interleave Factor  Contains
#-----------------------------------------------------------------------
#0x0                128MB             1           chassis/system-board/DIMM0
#0x20000000         256MB             1           chassis/system-board/DIMM1

    return if ( m/^0x[\da-f]+ +\d+MB +\d+ +chassis\/system-board\/DIMM\d+/ );


    # from a Sun T3-1 with 5.10 Generic_142909-17
#======================= Physical Memory Configuration ========================
#Segment Table:
#--------------------------------------------------------------
#Base           Segment  Interleave  Bank     Contains
#Address        Size     Factor      Size     Modules
#--------------------------------------------------------------
#0x0            64 GB    2           32 GB    /SYS/MB/CMP0/BOB0/CH0/D0
#                                             /SYS/MB/CMP0/BOB0/CH0/D1
#                                             /SYS/MB/CMP0/BOB0/CH1/D0
#                                             /SYS/MB/CMP0/BOB0/CH1/D1
#                                             /SYS/MB/CMP0/BOB1/CH0/D0
#                                    32 GB    /SYS/MB/CMP0/BOB2/CH0/D0

    # from a Sun T1000 with 5.10 Generic_150400-28
#======================= Physical Memory Configuration ========================
#Segment Table:
#--------------------------------------------------------------
#Base           Segment  Interleave   Bank     Contains
#Address        Size     Factor       Size     Modules
#--------------------------------------------------------------
#0x0            8 GB     4            4 GB     MB/CMP0/CH0/R0/D0
#                                              MB/CMP0/CH0/R0/D1
#                                     4 GB     MB/CMP0/CH3/R0/D0
#                                              MB/CMP0/CH3/R0/D1
#


    if ( $system_config =~ m/T3-|sun4v|T[12]00/ ) { 
	return if ( m/^Base \s+ Segment \s+ Interleave \s+ Bank \s+ Contains \s*$/x );
	return if ( m/^Address \s+ Size \s+ Factor \s+ Size \s+ Modules \s*$/x );
	return if ( m!^0x[\da-f]+ \s+ \d+ \s GB \s+ \d+ \s+ \d+ \s GB \s+ /SYS/MB/CMP\d+/BOB\d+/CH\d+/D\d+ \s*$!x ); 
	return if ( m!^0x[\da-f]+ \s+ \d+ \s GB \s+ \d+ \s+ \d+ \s GB \s+ MB/CMP\d+/CH\d+/R\d+/D\d+ \s*$!x ); 
	return if ( m!^ \s+ \d+ \s GB \s+ /SYS/MB/CMP\d+/BOB\d+/CH\d+/D\d+ \s*$!x ); 
	return if ( m!^ \s+ \d+ \s GB \s+ MB/CMP\d+/CH\d+/R\d+/D\d+ \s*$!x ); 
	return if ( m!^ \s+ /SYS/MB/CMP\d+/BOB\d+/CH\d+/D\d+ \s*$!x ); 
	return if ( m!^ \s+ MB/CMP\d+/CH\d+/R\d+/D\d+ \s*$!x ); 
	}
	    


    # from an Oracle T5-8 with 5.11 11.3
#======================= Physical Memory Configuration ========================
#Segment Table:
#--------------------------------------------------------------
#Base               Segment  Interleave   Bank     Contains
#Address            Size     Factor       Size     Modules
#--------------------------------------------------------------
#0x0                256 GB   4            64 GB    /SYS/PM0/CM0/CMP/BOB0/CH0/D0
#                                              /SYS/PM0/CM0/CMP/BOB0/CH1/D0
#                                     64 GB    /SYS/PM0/CM0/CMP/BOB2/CH0/D0
#0x80000000000      256 GB   4            64 GB    /SYS/PM0/CM1/CMP/BOB0/CH0/D0
    if ( $system_config =~ m/T5-/ ) { 
	return if ( m/^Base \s+ Segment \s+ Interleave \s+ Bank \s+ Contains \s*$/x );
	return if ( m/^Address \s+ Size \s+ Factor \s+ Size \s+ Modules \s*$/x );
	return if ( m!^0x[\da-f]+ \s+ \d+ \s GB \s+ \d+ \s+ \d+ \s GB \s+ /SYS/PM\d+/CM\d+/CMP\d*/BOB\d+/CH\d+/D\d+ \s*$!x ); 
	return if ( m!^ \s+ \d+ \s GB \s+ /SYS/PM\d+/CM\d+/CMP\d*/BOB\d+/CH\d+/D\d+ \s*$!x ); 
	return if ( m!^ \s+ /SYS/PM\d+/CM\d+/CMP\d*/BOB\d+/CH\d+/D\d+ \s*$!x ); 
	}

    $reparse = 1;
    }  # check_memory_v210 








sub check_io_cards {

    # from a sparc 5/10
#     Bus#  Freq
#Brd  Type  MHz   Slot  Name                              Model
#---  ----  ----  ----  --------------------------------  ----------------------
# 0   PCI-1  33     1   ebus
# 0   PCI-1  33     1   network-SUNW,hme
# 0   PCI-1  33     2   SUNW,m64B                         ATY,GT-C
# 0   PCI-1  33     3   ide-pci1095,646
#
#     Bus   Freq
#Brd  Type  MHz   Slot  Name                              Model
#---  ----  ----  ----  --------------------------------  ----------------------
# 0   UPA   111    30   FFB, Double Buffered              SUNW,501-4788
    if ( $system_config =~ m!Sun Ultra 5/10 UPA/PCI! ) {
	return if ( m/^\s+Bus#  Freq/ );
	return if ( m/^\s+Bus   Freq/ );
	return if ( m/^Brd  Type  MHz   Slot  Name +Model/ );
	return if ( m/^ +\d+ +(PCI-\d+|UPA) +\d+ +\d+ / );
	}


    # from a V100, with 5.9
#     Bus#  Freq
#Brd  Type  MHz   Slot  Name                              Model
#---  ----  ----  ----  --------------------------------  ----------------------
# 0   PCI-0  33     0   dma-isadma
# 0   PCI-0  33     0   rtc-m5819                         m5819
    return if ( m/^\s*Bus#  Freq/ );
    return if ( m/^Brd +Type +MHz +Slot +Name/ );
    return if ( m/^\s*\d+ +PCI-\d+ +\d+ +\d+ / );

    # from a Netra T1 200 with 5.8
    return if ( m/^\s+Bus +Freq/ );
    return if ( m/^\s*\d+ +PCI +\d+ +\d+ / );


    # from a 280R with 5.8
#                         Bus  Max
#     IO   Port Bus       Freq Bus  Dev,
#Brd  Type  ID  Side Slot MHz  Freq Func State Name
#Model
#---- ---- ---- ---- ---- ---- ---- ---- ----- --------------------------------
#----------------------
#I/O   PCI   8    B    3    33   33  2,0  ok    SUNW,qlc-pci1077,2200.1077.4082.+
#
#I/O   PCI   8    B    2    33   33  3,0  ok    SUNW,qlc-pci1077,2200.1077.4082.+
    return if ( m/^\s+Bus  Max/ );
    return if ( m/^\s+IO   Port Bus       Freq Bus  Dev,/ );
    return if ( m/^Brd  Type  ID  Side Slot MHz  Freq Func State Name/ );
    return if ( m!^I/O +PCI +\d+ +[A-Z]+ +\d+ +\d+ +\d+ +[\d,]+ +ok +(SUNW|pci|network|scsi)! );

    # From a 280R with no io cards installed???  webctdev.udel.edu
    # io cards section was three blank lines

    # from a 450 with 5.8
#     Bus   Freq
#Brd  Type  MHz   Slot  Name                              Model
#---  ----  ----  ----  --------------------------------  ----------------------
#SYS   PCI    33     1   pciclass,001000                   Symbios,53C875
#SYS   PCI    33     2   pciclass,001000                   Symbios,53C875
    return if ( m/^SYS +PCI +\d+ +\d+ +(SUNW|pci|network|scsi)/ );


    # from a v490 with 5.10
#                    Bus  Max
# IO  Port Bus       Freq Bus  Dev,
#Type  ID  Side Slot MHz  Freq Func State Name                              Model
#---- ---- ---- ---- ---- ---- ---- ----- --------------------------------  ----------------------
#PCI   8    A    0    66   66  1,0  ok    SUNW,qlc-pci1077,141.1077.141.2/+ QLA2462
#PCI   8    A    0    66   66  1,1  ok    SUNW,qlc-pci1077,141.1077.141.2/+ QLA2462
#
    return if ( m/^ \s+ Bus \s+ Max \s* $/x );
    return if ( m/^ \s+ IO \s+ Port \s+ Bus \s+ Freq \s+ Bus \s+ Dev, \s* $/x );
    return if ( m/^ Type \s+ ID \s+ Side \s+ Slot \s+ MHz  \s+ Freq \s+
	Func \s+ State \s+ Name \s+ Model \s* $/x );
    if ( m/^ PCI \s+ \d+ \s+ [AB] \s+ \d+ \s+ \d+ \s+ \d+ \s+
	    [\d,]+ \s+ (\S+) \s+ (SUNW\S+ \s+ \S+) \s* $/x ) {
	return if ( $1 eq 'ok' );
	push @crits, "io device $2 $1";
	}

#PCI   8    A    0    66   66  1,0  ok    SUNW,emlxs-pci10df,fc10/fp (fp) LP11002-S             
#PCI   8    A    0    66   66  1,1  ok    SUNW,emlxs-pci10df,fc10/fp (fp) LP11002-S       
    if ( m/^ PCI \s+ \d+ \s+ [AB] \s+ \d+ \s+ \d+ \s+ \d+ \s+
	    [\d,]+ \s+ (\S+) \s+ (SUNW\S+ \s \(\S+\) \s+ \S+) \s* $/x ) {
	return if ( $1 eq 'ok' );
	push @crits, "io device $2 $1";
	}

#PCI   8    A    0    66   66  1,0  ok    SUNW,qlc-pci1077,2300.1077.106.1+
#PCI   8    A    1    66   66  2,0  ok    SUNW,qlc-pci1077,2300.1077.106.1+
#
    if ( m/^ PCI \s+ \d+ \s+ [AB] \s+ \d+ \s+ \d+ \s+ \d+ \s+
	    [\d,]+ \s+ (\S+) \s+ (SUNW\S+) \s* $/x ) {
	return if ( $1 eq 'ok' );
	push @crits, "io device $2 $1";
	}



    # from a 4000 with 5.8
#     Bus   Freq
#Brd  Type  MHz   Slot  Name                              Model
#---  ----  ----  ----  --------------------------------  ----------------------
# 1   SBus   25     0   QLGC,isp/sd (block)               QLGC,ISP1000
# 1   SBus   25     1   QLGC,isp/sd (block)               QLGC,ISP1000
    return if ( m/^ +\d+ +SBus +\d+ +\d+ +(SUNW|QLGC)/ );


    # from a 6800 with 5.9
#                                Bus  Max
#            IO   Port Bus       Freq Bus  Dev,
#FRU Name    Type  ID  Side Slot MHz  Freq Func State Name   ...    Model
#----------  ---- ---- ---- ---- ---- ---- ---- ----- ------ ... ---------
#/N0/IB6/P0  PCI   24   B    0    33   33  1,0  ok    pci-pci1011,24.3/pci108e,1000     pci-bridge
#/N0/IB6/P0  PCI   24   B    0    33   33  0,0  ok    pci108e,1000-pci108e,1000.1
    return if ( m/^\s+Port  Run    E.   CPU      CPU/ );
    return if ( m/^FRU Name    Type  ID  Side Slot MHz  Freq Func State/ );
    return if ( m!^/N\d+/IB\d+/P\d+ +PCI +\d+ +[A-Z]+ +\d+ +\d+ +\d+ +[\d,]+ +ok +(SUNW|pci|net)! );

    # from a 3800 with 5.8
    return if ( m!^/N\d+/IB\d+/P\d+ +cPCI +\d+ +[A-Z]+ +\d+ +\d+ +\d+ +[\d,]+ +ok +(SUNW|pci|net)! );

    $reparse = 1;
    }








sub check_io_devices {

    # from a Sun Blade 150 with 5.9
#================================= IO Devices =================================
#     Bus   Freq
#Brd  Type  MHz   Slot        Name                          Model
#---  ----  ----  ----------  ----------------------------  --------------------
# 0   pci    33   +s/system-board  isa/isadma (dma)
    return if ( m/^\s+Bus\s+Freq/ );
    return if ( m/^Brd +Type +MHz +Slot +Name +Model/ );
    return if ( m/^\s* \d+ \s+ pci \s+ \d+ \s+ \S+ \s+ (isa|pci|SUNW)/ix );



    # from a V210, with 5.9
#================================= IO Devices =================================
#Bus   Freq      Slot +  Name +
#Type  MHz       Status  Path                          Model
#----  ----  ----------  ----------------------------  --------------------
#pci    66           MB  pci108e,1648 (network)
#                  okay  /pci@1f,700000/network@2
#pci    33            7  isa/rmc-comm-rmc_comm (seria+
#                  okay  /pci@1e,600000/isa@7/rmc-comm@0,3e8

# from a Sun Blade 100 with 5.9
#pci    33   +s/system-board  isa/isadma (dma)
#                  okay  /pci@1f,0/isa@7/dma
#pci    33   +s/system-board  SUNW,hme (network)            SUNW,qsi-cheerio
#                  okay  /pci@1f,0/pci/SUNW,hme

# from a Sun Blade Server B1600
#pci    33        Blade  isa/su (serial)
#                  okay  /pci@1f,0/isa@7/serial@0,3f8



    return if ( m/^Bus\s+Freq\s+Slot/ );
    return if ( m/^Type +MHz +Status +Path +Model/ );
    return if ( m/^pci +\d+ +(MB|\d+|Blade) +(pci|isa|scsi)/ );
    return if ( m/^pci +\d+ +\S*board\S* +(pci|isa|scsi)/ );
    return if ( m/^pci +\d+ +\S*board\S* +SUNW,/ );
    if ( m/^ +(\w+) +(\/pci\@[\da-f]+,[\da-f]+\S+)/ ) {
	if ( $1 ne "okay" ) {
	    push @crits, "io device $_";
	    }
	return;
	}

    # from another V210, also with 5.9, but different patch rev
#     Bus   Freq
#Brd  Type  MHz   Slot        Name                          Model
#---  ----  ----  ----------  ----------------------------  --------------------
# 0   pci    66           MB  pci108e,1648 (network)
# 0   pci    33            7  isa/rmc-comm-rmc_comm (seria+

    return if ( m/^\s+Bus\s+Freq/ );
    return if ( m/^Brd +Type +MHz +Slot +Name +Model/ );
    return if ( m/^\s*\d+ +pci +\d+ +(MB|\d+) +(pci|isa|scsi)/ );

    # from a v210, with Solaris 10 beta
#================================= IO Devices =================================
#Bus   Freq      Slot +  Name +
#Type  MHz       Status  Path                          Model
#----  ----  ----------  ----------------------------  --------------------
#pci    66           MB  pci108e,1648 (network)
#                  okay  /pci@1f,700000/network@2
#pci    66           MB  pci108e,1648 (network)
#                  okay  /pci/network
    if ( m!^ +(\w+) +(/pci/network)! ) {
	if ( $1 ne "okay" ) {
	    push @crits, "io device $_";
	    }
	return;
	}

    # from a v440 with 5.8
#================================= IO Devices =================================
#     Bus   Freq
#Brd  Type  MHz   Slot        Name                          Model
#---  ----  ----  ----------  ----------------------------  --------------------
# 0   pci    66         PCI5  SUNW,qlc-pci1077,2300 (scsi-+
# 0   pci    66           MB  pci108e,abba (network)        SUNW,pci-ce
# 0   pci    66         PCI2  SUNW,qlc-pci1077,2300 (scsi-+
# 0   pci    33           MB  isa/su (serial)
# 0   pci    33           MB  isa/su (serial)
# 0   pci    33           MB  isa/rmc-comm-rmc_comm (seria+
# 0   pci    33           MB  pci10b9,5229 (ide)
# 0   pci    66           MB  pci108e,abba (network)        SUNW,pci-ce
# 0   pci    66           MB  scsi-pci1000,30 (scsi-2)      LSI,1030
# 0   pci    66           MB  scsi-pci1000,30 (scsi-2)      LSI,1030
    return if ( m/^\s*\d+ +pci +\d+ +(MB|\d+|PCI\d+) +(pci|isa|scsi|SUNW)/ );


    # from a v440 with 5.9
#================================= IO Devices =================================
#Bus   Freq      Slot +  Name +
#Type  MHz       Status  Path                          Model
#----  ----  ----------  ----------------------------  --------------------
#pci    66         PCI5  SUNW,qlc-pci1077,2300 (scsi-+
#                  okay  /pci@1c,600000/SUNW,qlc@1
#
#pci    66           MB  scsi-pci1000,30 (scsi-2)      LSI,1030
#                  okay  /pci@1f,700000/scsi@2,1

    return if ( m/^pci +\d+ +(MB|PCI\d+|\d+) +(pci|isa|scsi|SUNW,)/ );


    # from a Sun SPARC Enterprise M4000 Server
#========================= IO Devices =========================
#
#    IO                                                Lane/Frq                                                       
#LSB Type  LPID   RvID,DvID,VnID       BDF       State Act,  Max   Name                           Model               
#--- ----- ----   ------------------   --------- ----- ----------- ------------------------------ --------------------
#    Logical Path
#    ------------
#Getting lane width failed for path /pci@2,600000/network@0
#Getting lane width failed for path /pci@2,600000/network
#Getting lane width failed for path /pci@3,700000/SUNW,emlxs@0
#Getting lane width failed for path /pci@3,700000/SUNW,emlxs@0,1
#
    return if ( m/^ \s+ IO \s+ Lane\/Frq \s* $/x );
    return if ( m/^ LSB \s+ Type \s+ LPID \s+ RvID,DvID,VnID \s+ BDF \s+ State \s+ Act, \s+ Max \s+ Name \s+ Model \s* $/x );
    return if ( m/^ \s+ Logical \s+ Path \s* $/x );
    if ( m/^Getting lane width failed for path/i )  { 
	# doesn't seem to matter
	return;
	}

    # from another Sun SPARC Enterprise M4000 Server
#00  UNKN  0      bc, 8532, 10b5       2,  0,  0  okay   -- , --   pci-pciexclass,060400          N/A                 
#    /pci@0,600000/pci@0                                                                                 
    if ( m/^\d+ \s+ \S+ \s+ \d+ \s+ 
	    [\da-f]+, \s* [\da-f]+, \s* [\da-f]+ \s+
	    \d+, \s* \d+, \s* \d+ \s+ 
	    (\S+) \s+
	    [\d+-]+ \s* , \s* [\d+-]+ \s+
	    ((?:pci|scsi|network|SUNW)\S+) \s+
	    (\S*) \s* $/ix ) { 
	if ( $1 ne 'okay' ) { 
	    push @crits, "$2 $1";
	    }
	return;
	}
    elsif ( m/^ \s+ \/pci\S+ \s* $/ix ) { 
	return;
	}

    # from a Sun T3-1 with 5.10 Generic_142909-17
#================================ IO Devices ================================
#Slot +            Bus   Name +                            Model   
#Status            Type  Path                                      
#----------------------------------------------------------------------------
#/SYS/MB/SASHBA0   PCIE  scsi-pciex1000,72                 LSI,2008
#                        /pci@400/pci@1/pci@0/pci@4/scsi@0           
#/SYS/MB/RISER2/PCIE2PCIE  SUNW,qlc-pciex1077,2532           QLE2562 
#                        /pci@400/pci@1/pci@0/pci@6/SUNW,qlc@0       
#/SYS/MB/RISER2/PCIE2PCIE  SUNW,qlc-pciex1077,2532           QLE2562 
#                        /pci@400/pci@1/pci@0/pci@6/SUNW,qlc@0,1     
#/SYS/MB/SASHBA1   PCIE  scsi-pciex1000,72                 LSI,2008
#                        /pci@400/pci@2/pci@0/pci@4/scsi@0           
#/SYS/MB/NET0      PCIE  network-pciex8086,10c9                    
#                        /pci@400/pci@2/pci@0/pci@6/network@0        

    # from a Sun T3-1 with 5.10 Generic_148888-03
#================================= IO Devices =================================
#Slot +            Bus   Name +                            Model        Speed 
#Status            Type  Path                                                 
#------------------------------------------------------------------------------
#/SYS/MB/SASHBA0   PCIE  scsi-pciex1000,72                 LSI,2008     --
#                        /pci@400/pci@1/pci@0/pci@4/scsi@0           
#/SYS/MB/RISER2/PCIE2PCIE  SUNW,qlc-pciex1077,2532           QLE2562      --
#                        /pci@400/pci@1/pci@0/pci@6/SUNW,qlc@0       

    # from a Sun T3-1 with 5.10 Generic_148888-03 as root
#/SYS/MB/SASHBA0   PCIE  scsi-pciex1000,72                 LSI,2008     5.0GTx8
#                        /pci@400/pci@1/pci@0/pci@4/scsi@0           
#/SYS/MB/RISER2/PCIE2PCIE  SUNW,qlc-pciex1077,2532           QLE2562      5.0GTx4
#                        /pci@400/pci@1/pci@0/pci@6/SUNW,qlc@0       


    if ( $system_config =~ m/T3-/ ) { 
	return if ( m!^Slot \s \+ \s+ Bus \s+ Name \s \+ \s+ Model !x ); 
	return if ( m!^Status \s+ Type \s+ Path \s*$!x ); 
	return if ( m!^/SYS/MB/\S+ \s* (PCI[EX]|NIUSL) \s+ (scsi|network|SUNW|display|usb)[-,]\S+ (\s+ \S+)? \s*$!x ); 
	return if ( m!^/SYS/MB/\S+ \s* (PCI[EX]|NIUSL) \s+ (scsi|network|SUNW|display|usb)[-,]\S+ (\s+ \S+)? \s+ (?:--|[\d\.GTx]+) \s*$!x ); 
	return if ( m!^ \s+ /(pci|niu)@\d+\S+ \s*$!x ); 
	}


    # from an Oracle T5-8 with 5.11 11.3
#System Configuration:  Oracle Corporation  sun4v SPARC T5-8
#Memory size: 262144 Megabytes
#
#======================================== IO Devices =======================================
#Slot +            Bus   Name +                            Model      Max Speed  Cur Speed 
#Status            Type  Path                                         /Width     /Width    
#-------------------------------------------------------------------------------------------
#/SYS/PM3/CM6/CMP/IOS0 PCIX  network-pciex8086,10fb            X1109a-z/1109a-z 5.0GT/x8   5.0GT/x8   
#                        /pci@600/pci@1/pci@0/pci@8/network@0        
#/SYS/PM3/CM6/CMP/IOS1 PCIX  pciex15b3,1003                               8.0GT/x8   8.0GT/x8   
#                        /pci@640/pci@1/pci@0/pci@8/pciex15b3,1003@0 
#/SYS/MB/USB_CTLR  PCIE  usb-pciexclass,0c0330                        --         --
#                        /pci@300/pci@1/pci@0/pci@4/pci@0/pci@6/usb@0
#/SYS/RIO/XGBE0    PCIE  network-pciex8086,1528                       --         --
#                        /pci@300/pci@1/pci@0/pci@4/pci@0/pci@8/network@0
#/SYS/MB/SASHBA0   PCIE  scsi-pciex1000,87                 LSI,2308_2 --         --
#                        /pci@300/pci@1/pci@0/pci@4/pci@0/pci@c/scsi@0
#/SYS/RCSA/PCIE1   PCIE  network-pciex8086,10fb            X1109a-z/1109a-z --         --
#                        /pci@300/pci@1/pci@0/pci@6/network@0        


    if ( $system_config =~ m/T5-/ ) { 
	return if ( m!^Slot \s \+ \s+ Bus \s+ Name \s \+ \s+ Model !x ); 
	return if ( m!^Status \s+ Type \s+ Path \s!x ); 
	return if ( m!^/SYS/(PM\d+/CM\d+|MB|RIO|RCSA)/\S+ \s+ (PCI[EX]|NIUSL) \s+ 
	    (scsi|network|SUNW|display|usb|pciex[\da-f]+)[-,]\S+ \s+ 
	    (\S+ \s+)? (\d+\.\d+GT/x\d+|--) \s+ (\d+\.\d+GT/x\d+|--) \s*$!x );
	return if ( m!^ \s+ /(pci|niu)@\d+\S+ \s*$!x ); 
	}

    $reparse = 1;
    }  # check_io_devices 






sub check_io_configuration {

    # from a T2000 running 5.10
#========================= IO Configuration =========================
#
#            IO
#Location    Type  Slot Path                                          Name                      Model
#----------- ----- ---- --------------------------------------------- ------------------------- ---------
#IOBD/NET0    PCIE IOBD                /pci@780/pci@0/pci@1/network@0    network-pciex8086,105e
#
    return if ( m/^ \s+ IO \s* $/x );
    return if ( m/^ Location \s+ Type \s+ Slot \s+ Path \s+ Name \s+ Model \s* $/x );
    return if ( m!^ (IOBD/\S+) \s+ (\S+) \s+ (\S+) \s+ (\S+) \s+ (\S+) \s* $!x );
    return if ( m!^ (IOBD/\S+) \s+ (\S+) \s+ (\S+) \s+ (\S+) \s+ (\S+) \s+ (\S+) \s* $!x );


    # from a T1000 running 5.10 Generic_142909-17
#MB/NET0    PCIE     MB      /pci@7c0/pci@0/network@4    network-pci14e4,1668
#MB/PCIX    PCIX     MB      /pci@7c0/pci@0/pci@8/scsi@2   scsi-pci1000,50  LSI,1064
#
    return if ( m!^ (MB/(NET|PCI)\S+) \s+ (PCI\S+) \s+ MB \s+ (\S+) \s+ (\S+) \s* $!x );
    return if ( m!^ (MB/(NET|PCI)\S+) \s+ (PCI\S+) \s+ MB \s+ (\S+) \s+ (\S+) \s+ (\S+) \s* $!x );

    $reparse = 1;
    }






sub check_active_boards {
    my( $temp );

    # from a 3800 with 5.8
#          Power  Fault  HotPlug  Board    Temp. (Deg C)    Voltage               Sensor
#FRU Name   LED    LED     LED    Cond.    0   1   2   3    1.5V 3.3V 5.0V 12.0V  Status
#--------  -----  -----  -------  -------  --- --- --- ---  ---- ---- ---- -----  ------
#/N0/SB2   on     off    off      ok       32  33  32  33   1.51 3.31 -    -      Green
#/N0/IB6   on     off    off      ok       34  37  -   -    1.51 3.33 4.95 12.11  Green

    return if ( m/^\s+Power  Fault  HotPlug  Board    Temp. \(Deg C\)/ );
    return if ( m/^FRU Name   LED    LED     LED    Cond.    0   1   2   3/ );
    if ( m!^(/N\d+/[SI]B\d+) +on +off +off +ok +(\d+) +(\d+) +(\d+|-) +(\d+|-) +([\d\.]+) +([\d\.]+) +([\d\.]+|-) +([\d\.]+|-) +(\w+)\s*! ) {
	if ( $10 ne "Green" ) {
	    push @crits, "$1 $10";
	    }
	foreach $temp ( $2, $3, $4, $5 )  {
	    if ( $temp >= $crit_temp || $10 ne "Green") {
		push @crits, "$1 temperature too high $temp $10";
		}
	    elsif ( $temp >= $warn_temp ) {
		push @warns, "$1 temperature too high $temp $10";
		}
	    }
	# 1.5V +- 5%
	if ( $6 < 1.42 || 1.58 < $6 ) {
	    push @crits, "$1 1.5V voltage bad $6 $10";
	    }
	# 3.3V +- 5%
	if ( $7 < 3.14 || 3.46 < $7 ) {
	    push @crits, "$1 3.3V voltage bad $7 $10";
	    }
	# 5.0V +- 5%
	if ( $8 ne '-' && ( $8 < 4.75 || 5.25 < $8 ) ) {
	    push @crits, "$1 5.0V voltage bad $8 $10";
	    }
	# 12.0V +- 5%
	if ( $9 ne '-' && ( $9 < 11.4 || 12.6 < $9 ) ) {
	    push @crits, "$1 12.0V voltage bad $9 $10";
	    }
	return;
	}



    # from another 3800 with 5.8
#          Power  Fault  HotPlug  Board
#FRU Name   LED    LED     LED    Cond.
#--------  -----  -----  -------  -------
#/N0/SB0   on     off    off      ok
#/N0/IB8   on     off    off      ok
    return if ( m/^\s+Power  Fault  HotPlug  Board/ );
    return if ( m/^FRU Name   LED    LED     LED    Cond./ );
    return if ( m!^/N\d+/[SI]B\d+ +on +off +off +ok *$! );



    # from a 4810 with 5.8
#          Power  Fault  HotPlug  Board    Temp. (Deg C)    Voltage               Sensor
#FRU Name   LED    LED     LED    Cond.    0   1   2   3    1.5V 3.3V 5.0V 12.0V  Status
#--------  -----  -----  -------  -------  --- --- --- ---  ---- ---- ---- -----  ------
#/N0/SB0   on     off    off      ok       ??? ??? ??? ???  ???  ???  -    -      Green
#/N0/SB2   on     off    off      ok       ??? ??? ??? ???  ???  ???  -    -      Green
#/N0/IB6   on     off    off      ok       ??? ??? -   -    ???  ???  ???  ???    Green
    return if ( m/^\s+Power  Fault  HotPlug  Board    Temp/ );
    return if ( m/^FRU Name   LED    LED     LED    Cond.    0/ );
    return if ( m!^/N\d+/[SI]B\d+ +on +off +off +ok +\?\?\?! );


    # from a 4810 with 5.8
#           Board        Receptacle    Occupant
#FRU Name   Type         Status        Status        Condition Info
#---------  -----------  -----------   ------------  --------- ---------------
#/N0/SB4    CPU          connected     configured    ok        powered-on, assigned
#/N0/IB8    PCI_I/O_Boa  connected     configured    ok        powered-on, assigned



    # from a 6800 with 5.9
#           Board        Receptacle    Occupant
#FRU Name   Type         Status        Status        Condition Info
#---------  -----------  -----------   ------------  --------- ----------------------------------------
#/N0/SB2    CPU_Board    connected     configured    ok        powered-on, assigned
#/N0/SB4    CPU_Board    connected     configured    ok        powered-on, assigned
#/N0/IB6    PCI_I/O_Boa  connected     configured    ok        powered-on, assigned
    return if ( m/^\s+Board        Receptacle    Occupant/ );
    return if ( m/^FRU Name   Type         Status        Status        Condition Info/ );
    return if ( m!^/N\d+/[SI]B\d+ +(CPU|PCI)\S* +connected +configured +ok +powered-on, assigned! );

    $reparse = 1;
    }







sub check_available_boards {

    # from a 6800 with 5.9
#           Board        Receptacle    Occupant
#FRU Name   Type         Status        Status        Condition Info
#---------  -----------  -----------   ------------  --------- ---------------
#There are currently no Boards/Slots available to this Domain
    return if ( m/^\s+Board        Receptacle    Occupant/ );
    return if ( m/^FRU Name   Type         Status        Status        Condition Info/ );
    return if ( m!There are currently no Boards/Slots available to this Domain! );


    # from a 6800 with Solaris 10 beta
#           Board        Receptacle    Occupant
#FRU Name   Type         Status        Status        Condition Info
#---------  -----------  -----------   ------------  --------- ---------------
#/N0/IB9    PCI_I/O_Boa  disconnected  unconfigured  unknown
    if ( m!^(/N\d+/[SI]B\d+) +(CPU|PCI)\S+ +disconnected +unconfigured +unknown! ) {
	# should this be an error?
	# Is it worse to have an unconfigured board, or have a real error
	# go unnoticed because a board has been unconfigured and the
	# warning has been acknowledged and hidden?
	#push @warns, "board $1 is available";
	return;
	}



    # from a 4810 with 5.8
    return if ( m!Power  Fault  HotPlug  Board/Slot  Board/Slot! );
    return if ( m/^FRU Name   LED    LED     LED    Condition   Assigned/ );

    $reparse = 1;
    }





sub check_hardware_failures {

    # from a 6800 with 5.9
    #No Hardware failures found in System
    if ( m/^No Hardware failures found in System/i ) {
	push @oks, $_;
	return;
	}

    $reparse = 1;
    }






sub check_usb_devices {

    # from a Sun Blade 100 with 5.9
#=============================== usb Devices ===============================
#
#Name          Port#
#------------  -----
#keyboard        3
#mouse           4

    return if ( m/^Name +Port#/ );
    return if ( m/^keyboard +\d+/ );
    return if ( m/^mouse +\d+/ );
    return if ( m/^hub +\d+/ );

    $reparse = 1;
    }



sub check_env_status {
    my ( $s );

    if ( m/Mode switch is in (.+) mode/ ) {
	$s = $1;
	return if ( $s =~ m/UNLOCK/ );
	}

    $reparse = 1;
    }




sub check_temps {
    my( $sensor, $temp );

    # from a v210 with 5.9

#Temperature sensors:
#-----------------------------------------------------------------------------
#Location       Sensor         Temperature  Lo   LoWarn  HiWarn    Hi   Status
#-----------------------------------------------------------------------------
#MB/P0          T_CORE           61C       -     -       110C    115C   okay
#MB/P1          T_CORE           58C       -     -       110C    115C   okay
#MB             T_ENC            21C        -3C    5C     40C     48C   okay
#PS0            FF_OT            -         -     -       -        -     okay

    return if ( m/^Location +Sensor +Temperature +Lo +LoWarn +HiWarn +Hi +Status/ );
    if ( m/^(\S+) +(\S+) +(\S+) +(\S+) +(\S+) +(\S+) +(\S+) +(\S+)/ ) {
	if ( $8 ne "okay" ) {
	    push @crits, "temp $1 is $8: $_";
	    }
	return;
	}


    # from a v210, with Solaris 10 beta
#Temperature sensors:
#------------------------------------
#Location       Sensor         Status
#------------------------------------
#MB/P0          T_CORE         okay
#MB/P1          T_CORE         okay
#MB             T_ENC          okay
#PS0            FF_OT          okay
    return if ( m/^Location +Sensor +Status/ );
    if ( m!^ ((?:MB|SYS|PS)\S*) \s+ (\w+) \s+ (\S+) \s*$!ix ) {
	if ( $3 !~ m/ok/i ) {
	    push @crits, "temperature $1 $2 $3";
	    }
	return;
	}

# from a Serverblade B1600 with S10_55
#Location       Sensor         Status
#------------------------------------
#Blade/CPU0     Die            okay
#Blade/CPU0     Ambient        okay
    if ( m!^(Blade/[\w\d-]+) \s+ (\w+) \s+ (\S+) \s*$!ix ) {
	if ( $3 ne "okay" ) {
	    push @crits, "temperature $1 $2 $3";
	    }
	return;
	}




    # from an E250 with 5.8
#System Temperatures (Celsius):
#------------------------------
#      CPU0    41
#      CPU1    40
#       MB0    31
#       MB1    25
#       PDB    25
#      SCSI    25
    if ( $system_config =~ m/Enterprise 250/i ) {
	if ( m/^\s* (\w[\w\d]+) \s+ (\d+) \s*$/xi ) {
	    $sensor = $1;
	    $temp = $2;
	    if ( $sensor =~ m/CPU/ ) {
		if ( $temp > 60 ) {
		    push @crits, "$sensor temp too high $temp";
		    }
		elsif ( $temp > 50 ) {
		    push @warns, "$sensor temp too high $temp";
		    }
		}
	    else {
		if ( $temp > 50 ) {
		    push @crits, "$sensor temp too high $temp";
		    }
		elsif ( $temp > 40 ) {
		    push @warns, "$sensor temp too high $temp";
		    }
		}
	    return;
	    }
	}


    # from a 280R with 5.8
    #System Temperatures (Celsius):
    #------------------------------
    #cpu0   1
    #---------
    #  56  52
    return if ( m/^cpu\d+ +\d+/ );
    if ( m/^ *(\d+) +(\d+) *$/ ) {
	if ( $1 >= $crit_temp_die || $2 >= $crit_temp_die ) {
	    push @crits, "cpu temperature too high $1 $2";
	    }
	elsif ( $1 >= $warn_temp_die || $2 >= $warn_temp_die ) {
	    push @warns, "cpu temperature too high $1 $2";
	    }
	return;
	}

    # from a 450 with 5.8
    #System Temperatures (Celsius):
    #------------------------------
    #AMBIENT    19
    #CPU 0      43
    #CPU 1      40
    #CPU 2      43
    #CPU 3      47
    #=================================

    if ( m/^(AMBIENT|CPU \d+)\s+(\d+)$/ ) {
	if ( $2 >= $crit_temp ) {
	    push @crits, "$1 temperature too high $2";
	    }
	elsif ( $2 >= $warn_temp ) {
	    push @warns, "$1 temperature too high $2";
	    }
	return;
	}

    # from a V440 with 5.10
#Location       Sensor         Status
#------------------------------------
#C0/P0          T_CORE         okay
#C0             T_AMB          okay
#SCSIBP         T_AMB          okay
#MB             T_AMB          okay
    if ( m!^([CMPS][\w\d/]+) \s+ (T_\w+) \s+ (\S+) \s*$!ix ) {
	if ( $3 ne "okay" ) {
	    push @crits, "temperature $1 $2 $3";
	    }
	return;
	}



    # from a V880 with 5.9
    #System Temperatures (Celsius):
    #-------------------------------
    #Device          Temperature     Status
    #---------------------------------------
    #CPU0             76             OK
    #CPU1             77             OK
    return if ( m/^Device\s+Temperature\s+Status/ );
    if ( m/^(\S+)\s+(\d+)\s+(\S+)/ ) {
	if ( $3 ne "OK" || $2 > $crit_temp_die ) {
	    push @crits, "$1 temperature is $2 $3";
	    }
	if ( $2 > $warn_temp_die ) {
	    push @warns, "$1 temperature is $2 $3";
	    }
	return;
	}

    # from a 4000 with 5.9
    #System Temperatures (Celsius):
    #------------------------------
    #Brd   State   Current  Min  Max  Trend
    #---  -------  -------  ---  ---  -----
    # 0      OK       36     34   38  stable
    # 1      OK       36     34   37  stable
    #CLK     OK       27     25   28  stable
    return if ( m/^Brd   State   Current  Min  Max  Trend/ );
    if ( m/^ *(\S+) +(\w+) +(\d+) +(\d+) +(\d+) +(\w+)$/ ) {
	if ( $2 ne "OK" || $6 ne "stable" ) {
	    push @crits, "board $1 temperature is $3 $2 $6";
	    }
	elsif ( $3 > $crit_temp  ) {
	    push @crits, "board $1 temperature is $3 $2 $6";
	    }
	elsif ( $3 > $warn_temp  ) {
	    push @warns, "board $1 temperature is $3 $2 $6";
	    }
	return;
	}


    # from a T1000 running 5.10 Generic_142909-17
#Temperature sensors:
#----------------------------------------------------------------
#Location                           Sensor             Status    
#----------------------------------------------------------------
#0828NNE07U:CH/MB/IOB               T_CORE             ok
#0828NNE07U:CH/MB/CMP0              T_TCORE            ok
#0828NNE07U:CH/MB/CMP0              T_BCORE            ok
#0828NNE07U:CH/MB                   T_AMB              ok
    if ( $system_config =~ m/T1000/ ) { 
	if ( m!^([\d\w]+:CH/MB\S*) \s+ (T_\S+) \s+ (\S+) \s*$!ix ) {
	    if ( $3 ne 'ok' ) { 
		push @crits, "temp $1 $2 $3";
		}
	    return;
	    }
	}

    $reparse = 1;
    }






sub check_temp_indicators {

    
    # from a Sun T3-1 with 5.10 Generic_142909-17
#Temperature indicators:
#----------------------------------------------------------------
#Location                           Indicator          Condition
#----------------------------------------------------------------
#SYS/MB/DVRM_CMP0                   TEMP_FAULT         ok      
#SYS/MB/DVRM_M0                     TEMP_FAULT         ok      
#SYS/MB/DVRM_M1                     TEMP_FAULT         ok      

    if ( $system_config =~ m/T3-/ ) { 
	return if ( m/^Location \s+ Indicator \s+ Condition/x );
	if ( m!^ (SYS/MB/\S+) \s+ (\S+) \s+ (\S+) \s*$!ix ) {
	    if ( $3 !~ m/ok/i ) {
		push @crits, "temp indicator $1 $2 $3";
		}
	    return;
	    }
	}

    $reparse = 1;
    }








sub check_current_sensors {

    # from a v210 with 5.9
#Current sensors:
#----------------------------------------------------------------------
#Location  Sensor          Current    Lo     LoWarn  HiWarn   Hi    Status
#----------------------------------------------------------------------
#MB         FF_SCSI       -         -       -       -       -   okay
#PS0        FF_OC         -         -       -       -       -   okay
    return if ( m/^Location +Sensor +Current +Lo +LoWarn +HiWarn +Hi +Status/ );
    if ( m/^(\S+) +(\S+) +(\S+) +(\S+) +(\S+) +(\S+) +(\S+) +(\S+)/ ) {
	if ( $8 ne "okay" ) {
	    push @crits, "current $1 is $8: $_";
	    }
	return;
	}

    # from a v210, with Solaris 10 beta
#Current sensors:
#------------------------------
#Location  Sensor        Status
#------------------------------
#MB         FF_SCSI      okay
#PS0        FF_OC        okay
    return if ( m/^Location +Sensor +Status/ );
    if ( m!^ ((?:MB|PS|SYS)\S*) \s+ (\w+) \s+ (\w+)!ix ) {
	if ( $3 !~ m/^ok/i ) {
	    push @crits, "current $1 $2 $3";
	    }
	return;
	}


    # from a V440 with 5.10
#Location  Sensor        Status
#------------------------------
#MB         FF_SCSIA     okay
#MB         FF_POK       okay
#C0/P0      FF_POK       okay

    if ( m!^([CM][\w\d/]+) \s+ (FF_\w+) \s+ (\S+) \s*$!ix ) {
	if ( $3 ne "okay" ) {
	    push @crits, "current $1 $2 $3";
	    }
	return;
	}

    # from a Sun T3-1 with 5.10 Generic_142909-17
#Current sensors:
#----------------------------------------------------------------
#Location                           Sensor             Status    
#----------------------------------------------------------------
#SYS/MB/DVRM_CMP0                   I_VCORE            ok
#SYS/MB/DVRM_M0                     I_+1V5             ok
#SYS/MB/DVRM_M1                     I_+1V5             ok
#SYS/PS0                            I_IN               ok
    if ( $system_config =~ m/T3-/ ) { 
	return if ( m/^Location \s+ Indicator \s+ Condition/x );
	if ( m!^ (SYS/(?:MB|PS)\S*) \s+ (\S+) \s+ (\S+) \s*$!ix ) {
	    if ( $3 !~ m/^ok/i ) {
		push @crits, "current $1 $2 $3";
		}
	    return;
	    }
	}

    # from a T1000 running 5.10 Generic_142909-17
#Current sensors:
#----------------------------------------------------------------
#Location                           Sensor             Status    
#----------------------------------------------------------------
#0828NNE07U:CH/MB                   I_VCORE            ok
#0828NNE07U:CH/MB                   I_VMEM             ok
    if ( $system_config =~ m/T1000/ ) { 
	if ( m!^([\d\w]+:CH/MB\S*) \s+ (I_\S+) \s+ (\S+) \s*$!ix ) {
	    if ( $3 ne 'ok' ) { 
		push @crits, "current $1 $2 $3";
		}
	    return;
	    }
	}

    # from an Oracle T5-8 with 5.11 11.3
#Current sensors:
#----------------------------------------------------------------
#Location                           Sensor             Status    
#----------------------------------------------------------------
#SYS/PM0/CM0/CMP                    I_VCORE            ok
#SYS/PM0/CM0                        I_+12V             ok

    if ( $system_config =~ m/T5-/ ) { 
	return if ( m/^Location \s+ Sensor \s+ Status/x );
	if ( m!^ (SYS/\S*) \s+ (\S+) \s+ (\S+) \s*$!ix ) {
	    if ( $3 !~ m/^ok/i ) {
		push @crits, "current $1 $2 $3";
		}
	    return;
	    }
	}

    $reparse = 1;
    }  # check_current_sensors 






sub check_current_indicators {
    
    # from a Sun T3-1 with 5.10 Generic_142909-17
#Current indicators:
#----------------------------------------------------------------
#Location                           Indicator          Condition
#----------------------------------------------------------------
#SYS/MB/DVRM_CMP0                   OC_FAULT           ok      
#SYS/MB/DVRM_CMP0                   OVC_FAULT          ok      
#SYS/MB/DVRM_M0                     OC_FAULT           ok      
#SYS/MB/DVRM_M0                     OVC_FAULT          ok      
#SYS/MB/DVRM_M1                     OC_FAULT           ok      
#SYS/MB/DVRM_M1                     OVC_FAULT          ok      
#
    if ( $system_config =~ m/T3-/ ) { 
	return if ( m/^Location \s+ Indicator \s+ Condition/x );
	if ( m!^ (SYS/MB/\S+) \s+ (\S+) \s+ (\S+) \s*$!ix ) {
	    if ( $3 !~ m/^ok/i ) {
		push @crits, "current indicator $1 $2 $3";
		}
	    return;
	    }
	}

    $reparse = 1;
    }






sub check_voltage_sensors {

    # from a v210 with 5.9
#Voltage sensors:
#------------------------------------------------------------------------
#Location   Sensor       Voltage     Lo     LoWarn  HiWarn   Hi    Status
#------------------------------------------------------------------------
#MB/P0      V_CORE          1.45V       -     1.26V   1.54V     -   okay
#MB/P1      V_CORE          1.46V       -     1.26V   1.54V     -   okay
#MB         V_VTT           1.31V       -     1.17V   1.43V     -   okay
#MB         V_GBE_+2V5      2.51V       -     2.25V   2.75V     -   okay
#MB         V_GBE_CORE      1.20V       -     1.08V   1.32V     -   okay
#MB         V_VCCTM         2.54V       -     2.25V   2.75V     -   okay
#MB         V_+2V5          2.61V       -     2.34V   2.86V     -   okay
#MB         V_+1V5          1.51V       -     1.35V   1.65V     -   okay
#MB/BAT     V_BAT           2.98V       -     2.70V     -       -   okay
#PS0        P_PWR             -         -       -       -       -   okay
    return if ( m/^Location +Sensor +Voltage +Lo +LoWarn +HiWarn +Hi +Status/ );
    if ( m/^(\S+) +(\S+) +(\S+) +(\S+) +(\S+) +(\S+) +(\S+) +(\S+)/ ) {
	if ( $8 ne "okay" ) {
	    push @crits, "voltage $1 is $8: $_";
	    }
	return;
	}


    # from a v210, with Solaris 10 beta
#Voltage sensors:
#-------------------------------
#Location   Sensor        Status
#-------------------------------
#MB/P0      V_CORE        okay
#MB/P1      V_CORE        okay
#MB         V_+1V5        okay
#MB/BAT     V_BAT         okay
#PS0        P_PWR         okay
    return if ( m/^Location +Sensor +Status/ );
    if ( m!^([MP][\w\d/]+)\s+([\w\+]+)\s+(\w+)!i ) {
	if ( $3 ne "okay" ) {
	    push @crits, "voltage $1 $2 $3";
	    }
	return;
	}

    # from a V440 with 5.10
#Location   Sensor        Status
#-------------------------------
#MB         V_+1V5        okay
#MB         V_VCCTM       okay
#MB         V_NET0_1V2D   okay
#MB/BAT     V_BAT         okay
#MB         V_+12V        okay
#MB         V_-12V        okay
#PS0        P_PWR         okay
#PS0        FF_POK        okay
#PS1        P_PWR         okay
#PS1        FF_POK        okay
    if ( m!^([MP][\w\d/]+) \s+ ((V|P|FF)_[\w\d+-]+) \s+ (\S+) \s*$!ix ) {
	if ( $4 ne "okay" ) {
	    push @crits, "voltage $1 $2 $3";
	    }
	return;
	}

# from a Serverblade B1600 with S10_55
#-------------------------------
#Location   Sensor        Status
#-------------------------------
#Blade      5v            OK
#Blade      3.3v          OK
#Blade      2.5v          OK
#Blade      vcore         OK
    if ( m!^(Blade) \s+ ([\w\d\.]+) \s+ (\w+)!ix ) {
	if ( $3 ne "OK" ) {
	    push @crits, "voltage $1 $2 $3";
	    }
	return;
	}


    # from a Sun T3-1 with 5.10 Generic_142909-17
#Voltage sensors:
#----------------------------------------------------------------
#Location                           Sensor             Status    
#----------------------------------------------------------------
#SYS/MB/CMP0                        V_VNW              ok
#SYS/MB/CMP0                        V_VSB              ok
#SYS/MB/CMP0                        V_VCORE            ok
#SYS/MB/CMP0                        V_VDDA             ok
#SYS/MB                             V_VTT_M0           ok
#SYS/MB                             V_+1V5_M0          ok
#SYS/PS0                            V_IN               ok
#
    if ( $system_config =~ m/T3-/ ) { 
	return if ( m/^Location \s+ Indicator \s+ Condition/x );
	if ( m!^ (SYS/(?:MB|PS)\S*) \s+ (\S+) \s+ (\S+) \s*$!ix ) {
	    if ( $3 !~ m/ok/i ) {
		push @crits, "voltage sensor $1 $2 $3";
		}
	    return;
	    }
	}


    # from a T1000 running 5.10 Generic_142909-17
#Voltage sensors:
#----------------------------------------------------------------
#Location                           Sensor             Status    
#----------------------------------------------------------------
#0828NNE07U:CH/MB                   V_VCORE            ok
#0828NNE07U:CH/MB                   V_VMEM             ok
#0828NNE07U:CH/MB                   V_VTT              ok
#0828NNE07U:CH/MB                   V_+1V2             ok
#0828NNE07U:CH/MB                   V_+1V5             ok
#0828NNE07U:CH/MB                   V_+2V5             ok
#0828NNE07U:CH/MB                   V_+3V3             ok
#0828NNE07U:CH/MB                   V_+5V              ok
#0828NNE07U:CH/MB                   V_+12V             ok
#0828NNE07U:CH/MB                   V_+3V3STBY         ok
    if ( $system_config =~ m/T1000/ ) { 
	if ( m!^([\d\w]+:CH/MB\S*) \s+ (V_\S+) \s+ (\S+) \s*$!ix ) {
	    if ( $3 ne 'ok' ) { 
		push @crits, "voltage $1 $2 $3";
		}
	    return;
	    }
	}

    # from an Oracle T5-8 with 5.11 11.3
#Voltage sensors:
#----------------------------------------------------------------
#Location                           Sensor             Status    
#----------------------------------------------------------------
#SYS/MB/SP                          V_+1V0             ok
#SYS/MB/SP                          V_+1V5             ok
#SYS/MB                             V_+1V0_SAS0_OBPS   ok
#SYS/PM0/CM0/CMP                    V_VCORE            ok
#SYS/RIO                            V_+5V0_VREG        ok

    if ( $system_config =~ m/T5-/ ) { 
	return if ( m/^Location \s+ Sensor \s+ Status/x );
	if ( m!^ (SYS/\S*) \s+ (\S+) \s+ (\S+) \s*$!ix ) {
	    if ( $3 !~ m/ok/i ) {
		push @crits, "voltage sensor $1 $2 $3";
		}
	    return;
	    }
	}

    $reparse = 1;
    }  # check_voltage_sensors 




sub check_voltage_indicators {
    
    # from a Sun T3-1 with 5.10 Generic_142909-17
#Voltage indicators:
#----------------------------------------------------------------
#Location                           Indicator          Condition
#----------------------------------------------------------------
#SYS/MB/DVRM_CMP0                   OV_FAULT           ok      
#SYS/MB/DVRM_CMP0                   IUV_FAULT          ok      
#SYS/MB/DVRM_CMP0                   OOV_FAULT          ok      
#SYS/MB/DVRM_M0                     OV_FAULT           ok      
#SYS/MB/DVRM_M0                     IUV_FAULT          ok      
#SYS/MB/DVRM_M0                     OOV_FAULT          ok      
#SYS/MB/DVRM_M1                     OV_FAULT           ok      
#SYS/MB/DVRM_M1                     IUV_FAULT          ok      
#SYS/MB/DVRM_M1                     OOV_FAULT          ok      
#SYS/MB/RISER0/XAUI0                V_+5V0_FAULT       ok      
#SYS/MB/RISER0/XAUI0                V_+3V3_FAULT       ok      
#
    if ( $system_config =~ m/T3-/ ) { 
	return if ( m/^Location \s+ Indicator \s+ Condition/x );
	if ( m!^ (SYS/MB/\S+) \s+ (\S+) \s+ (\S+) \s*$!ix ) {
	    if ( $3 !~ m/ok/i ) {
		push @crits, "voltage indicator $1 $2 $3";
		}
	    return;
	    }
	}

    # from a T1000 running 5.10 Generic_142909-17
#Voltage indicators:
#----------------------------------------------------------------
#Location                           Indicator          Condition
#----------------------------------------------------------------
#0828NNE07U:CH/MB/BAT               V_BAT              ok      
    if ( $system_config =~ m/T1000/ ) { 
	return if ( m/^Location \s+ Indicator \s+ Condition/x );
	if ( m!^([\d\w]+:CH/MB/BAT\S*) \s+ (V_\S+) \s+ (\S+) \s*$!ix ) {
	    if ( $3 ne 'ok' ) { 
		push @crits, "voltage $1 $2 $3";
		}
	    return;
	    }
	}

    $reparse = 1;
    }









sub check_keyswitch {

    # from a v440 with 5.8
#Keyswitch:
#---------------------------------
#Location       Keyswitch   State
#---------------------------------
#SYS            SYSCTRL     NORMAL
    return if ( m!^Location +Keyswitch +State! );
    return if ( m!^SYS +SYSCTRL +NORMAL! );


    # from a v240 with 5.9
#Keyswitch:
#---------------------
#Location       State
#---------------------
#SYSCTRL        NORMAL
    return if ( m!^Location +State! );
    return if ( m!^SYSCTRL +NORMAL! );

    # from a v440 with 5.9
#Keyswitch:
#---------------------
#Location       State
#---------------------
#SYS/SYSCTRL    NORMAL
    return if ( m!^SYS/SYSCTRL +NORMAL! );

    # from a v240 with 5.10
#Keyswitch:
#-----------------------------------------
#Location       Keyswitch   State
#-----------------------------------------
#MB             SYSCTRL     NORMAL
    return if ( m!^MB \s+ SYSCTRL \s+ NORMAL!ix );


    $reparse = 1;
    }







sub check_led_state {

    # from a v210 with 5.9
#Led State:
#--------------------------------------------------
#Location   Led                   State       Color
#--------------------------------------------------
#MB         ACT                   on          green
#MB         SERVICE               off         amber
#MB         LOCATE                off         white
#PS0        ACT                   on          green
#PS0        SERVICE               off         amber
#PS0        OK2RM                 off         blue
#HDD0       SERVICE               off         amber
#HDD0       OK2RM                 off         blue
#HDD1       SERVICE               off         amber
#HDD1       OK2RM                 off         blue

    # from a v440 with 5.10 Generic_118833-36
#SYS                    ACT                   on          green           
#SYS                    SERVICE               off         amber           
#SYS                    LOCATE                off         white           
#PS1                    POK                   on          green           
#PS1                    STBY                  on          green           

    return if ( m/^Location +Led +State +Color/ );
    if ( m/^((?:MB|PS|HDD|SYS)\S*) +(\S+) +(\S+) +(\S+)/ ) {
	if ( $2 eq "SERVICE" && $3 ne "off" ) {
	    push @crits, "$1 $2 led $3";
	    }
	elsif ( $2 eq "OK2RM" && $3 ne "off" ) {
	    push @warns, "$1 $2 led $3";
	    }
	return;
	}


    # from a Sun T3-1 with 5.10 Generic_142909-17
#LEDs:
#----------------------------------------------------------------
#Location                           LED                State   
#----------------------------------------------------------------
#SYS/MB/CMP0/BOB0/CH0/D0            SERVICE            off     
#SYS/MB/CMP0/BOB0/CH0/D1            SERVICE            off     
#SYS/MB/RISER0/XAUI0                SERVICE            off     
#SYS/FANBD/FM0                      SERVICE            off     
#SYS/FANBD/FM0                      OK                 steady  
#SYS                                OK                 steady  
#SYS                                LOCATE             off     
#SYS                                SERVICE            off     
#SYS                                PS_FAULT           off     
#SYS                                TEMP_FAULT         off     
#SYS                                FAN_FAULT          off     
#SYS/HDD0                           SERVICE            off     
#SYS/HDD0                           OK2RM              off     
#
    if ( $system_config =~ m/T3-/ ) { 
	return if ( m/^Location \s+ LED \s+ State/x );
	if ( m!^ (SYS\S*) \s+ (\S+) \s+ (\S+) \s*$!ix ) {
	    if ( $2 eq 'SERVICE' && $3 ne 'off' 
		    || $2 eq 'OK' && $3 ne 'steady' 
		    || $2 eq 'PS_FAULT' && $3 ne 'off' 
		    || $2 eq 'TEMP_FAULT' && $3 ne 'off' 
		    || $2 eq 'FAN_FAULT' && $3 ne 'off' ) {
		push @crits, "led $1 $2 $3";
		}
	    elsif ( $2 eq 'OK' && $3 ne 'steady' ) {
		push @crits, "led $1 $2 $3";
		}
	    elsif ( $2 eq 'OK2RM' && $3 ne 'off' ) {
		push @warns, "led $1 $2 $3";
		}
	    return;
	    }
	}

    # from a T1000 running 5.10 Generic_142909-17
#LEDs:
#----------------------------------------------------------------
#Location                           LED                State   
#----------------------------------------------------------------
#0828NNE07U:CH/SYS                  ACT                steady  
#0828NNE07U:CH/SYS                  LOCATE             off     
#0828NNE07U:CH/SYS                  SERVICE            off     
    if ( $system_config =~ m/T1000/ ) { 
	return if ( m/^Location \s+ LED \s+ State/x );
	if ( m!^([\d\w]+:CH/SYS) \s+ (\S+) \s+ (\S+) \s*$!ix ) {
	    if ( $2 eq 'SERVICE' && $3 ne 'off' ) {
		push @crits, "led $1 $2 $3";
		}
	    return;
	    }
	}

    # from an Oracle T5-8 with 5.11 11.3
#LEDs:
#----------------------------------------------------------------
#Location                           LED                State   
#----------------------------------------------------------------
#SYS                                FAN_FAULT          off     
#SYS                                LOCATE             off     
#SYS/PM0/CM0/CMP/BOB0/CH0/D0        SERVICE            off     
#SYS/PM0                            OK                 steady  
#SYS/PM0                            OK2RM              off     
#SYS/SASBP0/HDD0                    OK2RM              off     
#SYS/SASBP0/HDD0                    SERVICE            off     

    if ( $system_config =~ m/T5-/ ) { 
	return if ( m/^Location \s+ LED \s+ State/x );
	if ( m!^ (SYS\S*) \s+ (\S+) \s+ (\S+) \s*$!ix ) {
	    if ( $2 eq 'SERVICE' && $3 ne 'off' 
		    || $2 eq 'OK' && $3 ne 'steady' 
		    || $2 =~ m/^PS\d+$/ && $3 ne 'enabled' 
		    || $2 eq 'FAN_FAULT' && $3 ne 'off' 
		    || $2 eq 'MM_FAULT' && $3 ne 'off' 
		    || $2 eq 'MM_READY' && $3 ne 'steady' 
		    || $2 eq 'SP_OK' && $3 ne 'steady' 
		    || $2 eq 'TEMP_FAULT' && $3 ne 'off' ) { 
		push @crits, "led $1 $2 $3";
		}
	    elsif ( $2 eq 'OK2RM' && $3 ne 'off' ) {
		push @warns, "led $1 $2 $3";
		}
	    return;
	    }
	}
    

    $reparse = 1;
    }  # check_led_state 









sub check_fru_status {

    # from a v210 with 5.9, works on lots of other stuff too
#=========================== FRU Operational Status ===========================
#-------------------------
#Fru Operational Status:
#-------------------------
#Location        Status
#-------------------------
#MB/SC           okay
#PS0             okay
#HDD0            present
#HDD1            present

    return if ( m/^Fru Operational Status:/i );
    return if ( m/^ Location \s+ Status \s*$/ix );
    if ( m/^((?:HDD|MB|PS|SC)\S*) \s+ (\w+) \s*$/ix ) {
	if ( $2 !~ m/okay|present/ ) {
	    push @crits, "fru $1 $2";
	    }
	return;
	}


    # from a Sun T3-1 with 5.10 Generic_142909-17
#============================ FRU Status ============================
#Location                           Name      Status  
#------------------------------------------------------
#                                   SYS       enabled  
#SYS                                MB        enabled  
#SYS/MB                             SP        enabled  
#SYS/MB                             BAT       enabled  
#SYS/MB/CMP0/BOB0/CH0               D0        enabled  
#SYS/MB/CMP0/BOB0/CH0               D1        enabled  
#SYS/MB/CMP0/BOB0/CH1               D0        enabled  
#SYS/MB/CMP0/BOB0/CH1               D1        enabled  
#SYS/MB/CMP0/BOB1/CH0               D0        enabled  
#SYS/MB                             SCC       enabled  
#SYS                                FANBD     enabled  
#SYS                                HDD11     enabled  
    if ( $system_config =~ m/T3-/ ) { 
	return if ( m/^ Location \s+ Name \s+ Status \s*$/ix );
	if ( m/^ \s+ (SYS) \s+ (\w+) \s*$/ix ) {
	    if ( $2 !~ m/enabled/ ) {
		push @crits, "fru $1 $2";
		}
	    return;
	    }
	if ( m/^(SYS\S*) \s+ (\w+) \s+ (\w+) \s*$/ix ) {
	    if ( $3 !~ m/enabled/ ) {
		push @crits, "fru $1 $2 $3";
		}
	    return;
	    }
	}

    # from a T1000 running 5.10 Generic_142909-17
#============================ FRU Status ============================
#Location                           Name      Status  
#------------------------------------------------------
#0828NNE07U:CH/FT0/F0               FAN       enabled  
#0828NNE07U:CH/FT0/F1               FAN       enabled  
#0828NNE07U:CH/FT0/F2               FAN       enabled  
#0828NNE07U:CH/FT0/F3               FAN       enabled  
#0828NNE07U:CH                      MB        enabled  
#0828NNE07U:CH/MB/CMP0/CH0/R0/D0    DIMM      enabled  
#0828NNE07U:CH/MB/CMP0/CH0/R0/D1    DIMM      enabled  
#0828NNE07U:CH/MB/CMP0/CH3/R0/D0    DIMM      enabled  
#0828NNE07U:CH/MB/CMP0/CH3/R0/D1    DIMM      enabled  
#0828NNE07U:CH                      PS0       enabled  

    if ( $system_config =~ m/T1000/ ) { 
	return if ( m/^ Location \s+ Name \s+ Status \s*$/ix );
	if ( m!^([\d\w]+:CH\S*) \s+ (\S+) \s+ (\S+) \s*$!ix ) {
	    if ( $3 ne 'enabled' ) { 
		push @crits, "fru $1 $2 $3";
		}
	    return;
	    }
	}

    # from an Oracle T5-8 with 5.11 11.3
#============================ FRU Status ============================
#Location                           Name      Status  
#------------------------------------------------------
#SYS                                FIO       enabled  
#SYS/MB                             BAT       enabled  
#SYS/PM0/CM0/CMP/BOB0/CH0           D0        enabled  
#SYS/RCSA/FBD0                      FM0       enabled  
#SYS/SASBP1                         HDD7      enabled  

    if ( $system_config =~ m/T5-/ ) { 
	return if ( m/^ Location \s+ Name \s+ Status \s*$/ix );
	if ( m/^(SYS\S*) \s+ (\w+) \s+ (\w+) \s*$/ix ) {
	    if ( $3 !~ m/enabled/ ) {
		push @crits, "fru $1 $2 $3";
		}
	    return;
	    }
	}

    $reparse = 1;
    }  # check_fru_status 






sub check_panel {

    # from a E250 with 5.8
#System LED Status:  DISK ERROR      POWER
#                      [OFF]         [ ON]
#                POWER SUPPLY ERROR  ACTIVITY
#                      [OFF]         [ ON]
#                    GENERAL ERROR   THERMAL ERROR
#                      [OFF]         [OFF]
#Disk LED Status:        OK = GREEN      ERROR = YELLOW
#		DISK  5: [EMPTY]        DISK  3:    [OK]        DISK  1:    [OK]
#		DISK  4: [EMPTY]        DISK  2:    [OK]        DISK  0:    [OK]

    if ( $system_config =~ m/Enterprise 250/i ) {
	return if ( m/^Keyswitch position is in On mode./ );
	if ( m/^System LED Status: +(DISK ERROR) +(POWER) *$/
		|| m/^ *(POWER SUPPLY ERROR) +(ACTIVITY) *$/
		|| m/^ *(GENERAL ERROR) +(THERMAL ERROR) *$/ ) {
	    $led1 = $1;
	    $led2 = $2;
	    return;
	    }
	if ( m/^ \s+ \[\s*(\w+)\s*\] \s+ \[\s*(\w+)\s*\] \s* $/x ) {
	    #print "$led1 $1, $led2 $2\n";
	    if ( $1 ne "OFF" ) {
		push @crits, "panel LED $led1 $1";
		}
	    if ( $led2 eq "POWER" ) {
		if ( $2 ne "ON" ) {
		    push @crits, "panel LED $led2 $2";
		    }
		}
	    elsif ( $led2 eq "ACTIVITY" ) {
		# ACTIVITY LED goes on and off all the time
		return;
		}
	    else {
		if ( $2 ne "OFF" ) {
		    push @crits, "panel LED $led2 $2";
		    }
		}
	    return;
	    }
	return if ( m/^Disk LED Status:\s+OK = GREEN\s+ERROR = YELLOW/ );
	if ( m/^\s+DISK +(\d+): +\[\s*(\w+)\]\s+DISK +(\d+): +\[\s*(\w+)\]\s+DISK +(\d+): +\[\s*(\w+)\]\s*$/i ){
	    if ( $2 ne "OK" && $2 ne "EMPTY" ) {
		push @crits, "disk $1 $2";
		}
	    if ( $4 ne "OK" && $4 ne "EMPTY" ) {
		push @crits, "disk $3 $4";
		}
	    if ( $6 ne "OK" && $6 ne "EMPTY" ) {
		push @crits, "disk $5 $6";
		}
	    return;
	    }
	}


    # from a 280R with 5.8
    #Front Status Panel:
    #-------------------
    #Keyswitch position: NORMAL
    #
    #System LED Status: POWER                   GEN FAULT
    #                   [ ON]                    [OFF]

    return if ( m/^Keyswitch position: NORMAL/ );
    if ( m/^System LED Status: (POWER) +(GEN FAULT)/ ) {
	$led1 = $1;
	$led2 = $2;
	return;
	}
    #return if ( m/\[ ON\] +\[OFF\]/ );


    # from a 450 with 5.8
#Front Status Panel:
#-------------------
#Keyswitch position is in On mode.
#
#System LED Status:    POWER     GENERAL ERROR      ACTIVITY
#                      [ ON]         [OFF]           [ ON]
#                    DISK ERROR  THERMAL ERROR  POWER SUPPLY ERROR
#                      [OFF]         [OFF]           [OFF]
#
#Disk LED Status:        OK = GREEN      ERROR = YELLOW
#                DISK 18: [EMPTY]        DISK 19: [EMPTY]
#                DISK 16: [EMPTY]        DISK 17: [EMPTY]
#                DISK 14: [EMPTY]        DISK 15: [EMPTY]
#                DISK 12: [EMPTY]        DISK 13: [EMPTY]
#                DISK 10: [EMPTY]        DISK 11: [EMPTY]
#                DISK  8: [EMPTY]        DISK  9: [EMPTY]
#                DISK  6: [EMPTY]        DISK  7: [EMPTY]
#                DISK  4: [EMPTY]        DISK  5: [EMPTY]
#                DISK  2: [EMPTY]        DISK  3: [EMPTY]
#                DISK  0:    [OK]        DISK  1:    [OK]
#=================================
    if ( $system_config =~ m/Enterprise 450/i ) {
	return if ( m/^Keyswitch position is in On mode./ );
	if ( m/^ System \s LED \s Status: \s+ (POWER) \s+ (GENERAL \s ERROR) 
		    \s+ (ACTIVITY) \s* $/xi
		|| m/^ \s* (DISK \s ERROR) \s+ (THERMAL \s ERROR) 
		    \s+ (POWER \s SUPPLY \s ERROR) \s* $/xi ) {
	    $led1 = $1;
	    $led2 = $2;
	    $led3 = $3;
	    $verbose && print "led1 $led1, led2 $led2, led3 $led3\n"; 
	    return;
	    }
	if ( m/^ \s* \[\s*(\w+)\] \s+ \[\s*(\w+)\] \s+ \[\s*(\w+)\] \s* $/x ) {
	    $verbose && print "led1 $led1 $1, led2 $led2 $2, led3 $led3 $3\n"; 
	    if ( $1 ne "OFF" ) {
		if ( $1 eq "ON" && $led1 eq "POWER" ) {
		    return;
		    }
		push @crits, "panel LED $led1 $1";
		}
	    if ( $2 ne "OFF" ) {
		push @crits, "panel LED $led2 $2";
		}
	    if ( $3 ne "OFF" ) {
		# ACTIVITY LED goes on and off all the time
		if ( $3 eq "ON" && $led3 eq "ACTIVITY" ) {
		    return;
		    }
		push @crits, "panel LED $led3 $3";
		}
	    return;
	    }
	return if ( m/^Disk LED Status:\s+OK = GREEN\s+ERROR = YELLOW/ );
	if ( m/^\s+DISK +(\d+): +\[\s*(\w+)\]\s+DISK +(\d+): +\[\s*(\w+)\]\s*$/ ){
	    if ( $2 ne "OK" && $2 ne "EMPTY" ) {
		push @crits, "disk $1 $2";
		}
	    if ( $4 ne "OK" && $4 ne "EMPTY" ) {
		push @crits, "disk $3 $4";
		}
	    return;
	    }
	}



    # from v490 with 5.10
#Front Status Panel:
#-------------------
#Keyswitch position: NORMAL
#
#System LED Status:
#
#  LOCATOR   FAULT    POWER
#  -------  -------  -------
#   [OFF]    [OFF]    [ ON]
    if ( $system_config =~ m/Sun Fire V490/i ) {
	return if ( m/^ \s+ LOCATOR \s+ FAULT \s+ POWER \s* $/x );
	if ( m/^ \s+ \[ \s* (\w+) \s* \] \s+
		\[ \s* (\w+) \s* \] \s+
		\[ \s* (\w+) \s* \] \s* $/x ) {
	    if ( $2 ne 'OFF' ) {
		push @crits, "FAULT LED $2";
		}
	    return;
	    }
	}


    # from a V880 with 5.9
#Front Status Panel:
#-------------------
#Keyswitch position: NORMAL
#
#System LED Status:
#                   GEN FAULT                REMOVE
#                    [OFF]                    [OFF]
#
#                   DISK FAULT               POWER FAULT
#                    [OFF]                    [OFF]
#
#                   LEFT THERMAL FAULT       RIGHT THERMAL FAULT
#                    [OFF]                    [OFF]
#
#                   LEFT DOOR                RIGHT DOOR
#                    [OFF]                    [OFF]
    return if ( m/^Keyswitch position: NORMAL/ );
    return if ( m/^System LED Status:/ );
    if ( m/(GEN FAULT)                (REMOVE)/
	    || m/(DISK FAULT)               (POWER FAULT)/
	    || m/(LEFT THERMAL FAULT)       (RIGHT THERMAL FAULT)/
	    || m/(LEFT DOOR)                (RIGHT DOOR)/ ) {
	$led1 = $1;
	$led2 = $2;
	return;
	}
    if ( m/^\s+\[\s*(\w+)\] +\[\s*(\w+)\]\s*$/ ) {
	if ( $1 ne "OFF" ) {
	    if ( $1 eq "ON" && $led1 eq "POWER" ) {
		# for 280R
		return;
		}
	    push @crits, "LED $led1 $1";
	    }
	if ( $2 ne "OFF" ) {
	    push @crits, "LED $led2 $2";
	    }
	return;
	}

    # from a 4000 with 5.8
#System Power Status: Redundant
#System LED Status:    GREEN     YELLOW     GREEN
#Normal                 ON        OFF       BLINKING
    return if ( m/^System Power Status: Redundant/ );
    return if ( m/^System LED Status:    GREEN     YELLOW     GREEN/ );
    return if ( m/^Normal                 ON        OFF       BLINKING/ );

    $reparse = 1;
    }









sub check_disks  {

    # from a 280R with 5.8
    #Disk Status:
    #          Presence      Fault Value
    #          --------      -----------
    #DISK   0: [PRESENT]     [NO_FAULT]
    #DISK   1: [PRESENT]     [NO_FAULT]
    #DISK   1: [EMPTY  ]
    return if ( m/^\s+Presence\s+Fault Value/ );
    return if ( m/^DISK +\d+: \[PRESENT\] +\[NO_FAULT\] *$/ );
    return if ( m/^DISK +\d+: \[\s*EMPTY\s*\] *$/ );

    # from a v490 with 5.10
#Disk Status:
#------------
#DISK 0: [NO_FAULT]
#DISK 1: [NO_FAULT]
    if ( m/^ DISK \s+ (\d+): \s+ \[ \s* (\w+) \s* \] \s* $/x ) {
	if ( $2 ne 'NO_FAULT' && $2 ne 'EMPTY' ) {
	    push @crits, "disk $1 $2";
	    }
	return;
	}

    # from a V880 with 5.9
    #Disk Status:
    #          Presence      Fault LED       Remove LED
    #DISK   0: [PRESENT]        [OFF]           [OFF]
    #DISK   1: [PRESENT]        [OFF]           [OFF]
    #DISK   2: [PRESENT]        [OFF]           [OFF]
    #DISK   7: [  EMPTY]
    return if ( m/^\s+Presence\s+Fault LED\s+Remove LED/ );
    return if ( m/^ DISK \s+ \d+: \s+ \[ \s* EMPTY \s* \] \s* $/x );
    if ( m/^ DISK \s+ (\d+): \s* \[PRESENT\] \s+ \[\s*(\w+)\s*\] \s+
	    \[\s*(\w+)\s*\]/xi ) {
	if ( $2 ne 'OFF' ) {
	    push @crits, "disk $1 fault led $2";
	    }
	elsif ( $3 ne 'OFF' ) {
	    push @warns, "disk $1 remove led $3";
	    }
	else {
	    return;
	    }
	}


    $reparse = 1;
    }



sub check_fans {

    # from a Sun Blade 150 with 5.9
#Fan Speeds:
#---------------------------------------
#Location       Sensor          Speed
#---------------------------------------
#+stem-fan-slot system-fan      100%
#
    return if ( m/^Location +Sensor +Speed/ );
    if ( m/^(\+stem-fan-slot) \s+ (system-fan) \s+ (\d+)%/ix ) {
	if ( $3 < 30 ) {
	    push @crits, "fan $3%";
	    }
	return;
	}


    # from a v210 with 5.9
#Fan Speeds:
#---------------------------------------------
#Location       Sensor          Status   Speed
#---------------------------------------------
#F0             RS              okay     9375 rpm
#MB/P0/F0       RS              okay     16875 rpm
#PS0            FF_FAN          okay

    return if ( m/^Location +Sensor +Status +Speed/ );
    return if ( m/^PS\d+ +(\S+) +okay/ );
    if ( $system_config =~ m/v210|v240/i && m/^(\S+) +(\S+) +(\S+) +(\d+ +rpm)/ ) {
	if ( $3 ne "okay" ) {
	    push @crits, "fan $_";
	    }
	return;
	}


    # from another v210, also with 5.9, but different patch rev
#Fan Speeds:
#---------------------------------------
#Location       Sensor          Speed
#---------------------------------------
#F0             RS              9507 rpm
#MB/P0/F0       RS              17307 rpm
#PS0            FF_FAN          okay

    return if ( m/^Location +Sensor +Speed/ );
    if ( $system_config =~ m/v210/i && m/^(\S+) +(\S+) +(\d+) +rpm/ ) {
	if ( $3 < 300 ) {
	    push @crits, "fan2 $_";
	    }
	return;
	}


    # from a v210, with Solaris 10 beta
    # also a v240 with sol10
#Fan Status:
#---------------------------------------
#Location       Sensor          Status
#---------------------------------------
#F0             RS              okay
#F1             RS              okay
#F2             RS              okay
#F3             RS              okay
#MB/P0/F0       RS              okay
#MB/P0/F1       RS              okay
#MB/P1/F0       RS              okay
#MB/P1/F1       RS              okay
#PS0            FF_FAN          okay
    return if ( m/^Location +Sensor +Status/ );
    if ( m!^ (F\d+|MB/P\d/F\d+|PS\d+) \s+ (RS|FF_FAN) \s+ (\w+) !ix ) {
	if ( $3 ne "okay" ) {
	    push @crits, "fan $1 $3";
	    }
	return;
	}



    # from a v245, with Solaris 10 
#Fan Status:
#-------------------------------------------
#Location             Sensor          Status
#-------------------------------------------
#PDB/HDDFB/FT6/F0     F0              okay
#PDB/HDDFB/FT6/F1     F1              okay
#MB/FIOB/FCB0/FT0/F0  F0              okay
#MB/FIOB/FCB0/FT1/F0  F0              okay
#MB/FIOB/FCB0/FT2/F0  F0              okay
#MB/FIOB/FCB1/FT3/F0  F0              okay
#MB/FIOB/FCB1/FT4/F0  F0              okay
#MB/FIOB/FCB1/FT5/F0  F0              okay
#PS0                  FF_FAN          okay         
#PS1                  FF_FAN          okay         
#
    if ( m!^ (MB/FIOB/FCB\d+/FT\d+/F\d+|PDB/HDDFB/FT\d+/F\d+|PS\d+) \s+ (F\d+|FF_FAN) \s+ (\S+) !ix ) {
	if ( $3 ne "okay" ) {
	    push @crits, "fan $1 $3";
	    }
	return;
	}

    

#
# from a SunBladeServer B1600 with S10_55
#---------------------------------------
#Location       Sensor          Status
#---------------------------------------
#Blade/cpu-fan  cpu_fan         failed (0%)
    if ( $system_config =~ m/Serverblade/i
	    && m!^(Blade/[\w\d-]+) \s+ ([\w\d-]+) \s+ (\w+)!ix ) {
	if ( $3 ne "okay" ) {
	    push @crits, "fan $1 $3";
	    }
	return;
	}


    # from a E250 with 5.8
#Bank      Speed     Status
#         (0-255)
#----      -----     ------
# SYS       161        OK
    if ( $system_config =~ m/Enterprise 250/i ) {
	return if ( m/^Bank +Speed +Status/i );
	return if ( m/\(0-255\)/i );
	if ( m/^\s* (\S+) \s+ (\d+) \s+ (\S+) \s*$/xi ) {
	    if ( $3 ne "OK" ) {
		push @crits, "fan $1 $3";
		}
	    return;
	    }
	}


    # from a 280R with 5.8
    #Fan Bank :
    #----------
    #
    #Bank                        Status
    #----                        -------
    #FAN                         [NO_FAULT]
    return if ( m/^Bank +Status/ );
    return if ( m/^FAN +\[NO_FAULT\]/ );

    # from a 450 with 5.8
    #Fans:
    #-----
    #Fan Bank   Speed    Status
    #--------   -----    ------
    #CPU          31       OK
    #PWR          31       OK
    return if ( m/^Fan Bank   Speed    Status/ );
    return if ( m/^(CPU|PWR) +(\d+) +OK/ );


    # from a v440 with 5.9
#============================ Environmental Status ============================
#Fan Speeds:
#---------------------------------------------
#Location       Sensor          Status   Speed
#---------------------------------------------
#FT0/F0         TACH            okay     3857 rpm
#FT1/F0         TACH            okay     3708 rpm
#FT1/F1         TACH            okay     3750 rpm
#PS0            FF_PDCT_FAN     okay
#PS1            FF_PDCT_FAN     okay

    if ( $system_config =~ m/v440/i && m/^(\S+) +(\S+) +(\S+) +(\d+ +rpm)/ ) {
	if ( $3 ne "okay" ) {
	    push @crits, "fan $_";
	    }
	return;
	}


    # from a v440 with 5.10
#Location       Sensor          Status
#---------------------------------------
#FT0/F0         TACH            okay
#FT1/F0         TACH            okay
#FT1/F1         TACH            okay
#PS0            FF_PDCT_FAN     okay
#PS1            FF_PDCT_FAN     okay

    if ( $system_config =~ m/v440/i && m/^(\w[\w\d\/]+) +(\w+) +(\S+)\s*$/i ) {
	if ( $3 ne "okay" ) {
	    push @crits, "fan $_";
	    }
	return;
	}


    # from a v490 with 5.10
#Fan Tray        Fan              RPM    Status
#-----------     ----            -----   ----------
#FAN_TRAY_0      CPU0_FAN         5454   [NO_FAULT]
#FAN_TRAY_0      CPU1_FAN         4000   [NO_FAULT]
#FAN_TRAY_0      CPU2_FAN         3947   [NO_FAULT]
#FAN_TRAY_1      IO0_FAN          4000   [NO_FAULT]
#FAN_TRAY_1      IO1_FAN          4166   [NO_FAULT]
    if ( $system_config =~ m/V490/i ) {
	return if ( m/^ Fan \s+ Tray \s+ Fan \s+ RPM \s+ Status \s* $/x );
	if ( m/^ (\w+) \s+ (\w+) \s+ (\d+) \s+ \[ \s* (\w+) \s* \] \s* $/ix ) {
	    if ( $4 ne 'NO_FAULT' ) {
		push @crits, "fan $2 $4";
		}
	    return;
	    }
	}


    # from a V880 with 5.9
    #Fan Bank :
    #----------
    #
    #Bank                        Speed         Status        Fan State
    #                           ( RPMS )
    #----                       --------      ---------      ---------
    #CPU0_PRIM_FAN                2542        [ENABLED]          OK
    #CPU1_PRIM_FAN                2727        [ENABLED]          OK
    #CPU0_SEC_FAN                    0        [DISABLED]         OK
    #CPU1_SEC_FAN                    0        [DISABLED]         OK
    #IO0_PRIM_FAN                 3797        [ENABLED]          OK
    #IO1_PRIM_FAN                 3750        [ENABLED]          OK
    #IO0_SEC_FAN                     0        [DISABLED]         OK
    #IO1_SEC_FAN                     0        [DISABLED]         OK
    #IO_BRIDGE_PRIM_FAN           3370        [ENABLED]          OK
    #IO_BRIDGE_SEC_FAN               0        [DISABLED]         OK
    return if ( m/^Bank +Speed +Status +Fan State/ );
    return if ( m/^\s+\( RPMS \)/ );
    return if ( m/^\S+\s+\d+\s+\[\w+\]\s+OK/i );

    # from a 4000 with 5.8
    #Fans:
    #-----
    #Unit   Status
    #----   ------
    #Rack    OK
    #Key     OK
    #AC      OK
    return if ( m/^Unit   Status/ );
    return if ( m/^(\w+) +OK *$/ );

# from a Sun Blade 100 with 5.9
#Fan Speeds:
#---------------------------------------------
#Location       Sensor          Status   Speed
#---------------------------------------------
#+stem-fan-slot system-fan      okay     100%

# from a Sun Blade 100 with 5.9 Generic_122300-25
#+sis/system-fan-slot system-fan      okay     100%            

    return if ( m/^\+stem-fan-slot +system-fan +okay +\d+%/ );
    return if ( m/^\+sis\/system-fan-slot \s+ system-fan \s+ okay \s+ \d+ %/xi );


    # from a Sun T3-1 with 5.10 Generic_142909-17
#Location                           Sensor             Status    
#----------------------------------------------------------------
#SYS/FANBD/FM0/F0                   TACH               ok
#SYS/FANBD/FM0/F1                   TACH               ok

    if ( $system_config =~ m/T3-/ ) { 
	if ( m!^(SYS/FANBD/FM\d+/F\d+) \s+ TACH \s+ (\S+) \s*$!ix ) {
	    if ( $2 ne 'ok' ) { 
		push @crits, "fan $1 $2";
		}
	    return;
	    }
	}

    # from a T1000 running 5.10 Generic_142909-17
#Fan sensors:
#----------------------------------------------------------------
#Location                           Sensor             Status    
#----------------------------------------------------------------
#0828NNE07U:CH/FT0/F0               RS                 ok
#0828NNE07U:CH/FT0/F1               RS                 ok
#0828NNE07U:CH/FT0/F2               RS                 ok
#0828NNE07U:CH/FT0/F3               RS                 ok
    if ( $system_config =~ m/T1000/ ) { 
	if ( m!^([\d\w]+:CH/FT\d+/F\d+) \s+ RS \s+ (\S+) \s*$!ix ) {
	    if ( $2 ne 'ok' ) { 
		push @crits, "fan $1 $2";
		}
	    return;
	    }
	}

    # from an Oracle T5-8 with 5.11 11.3
#Fan sensors:
#----------------------------------------------------------------
#Location                           Sensor             Status    
#----------------------------------------------------------------
#SYS/PS0/FAN0                       TACH               ok
#SYS/RCSA/FBD0/FM0                  TACH               ok
    if ( $system_config =~ m/T5-/ ) { 
	if ( m!^(SYS/\S+) \s+ TACH \s+ (\S+) \s*$!ix ) {
	    if ( $2 ne 'ok' ) { 
		push @crits, "fan $1 $2";
		}
	    return;
	    }
	}


    $reparse = 1;
    }  # check_fans 







sub check_power_supplies {


    # from a E250 with 5.8
#Supply     Status
#------     ------
#  0          OK
#  1          OK
    if ( $system_config =~ m/Enterprise 250/i ) {
	return if ( m/^Supply +Status/i );
	if ( m/^\s* (\d+) \s+ (\S+) \s*$/xi ) {
	    if ( $2 ne "OK" ) {
		push @crits, "supply $1 $2";
		}
	    return;
	    }
	}


    # from a 280R with 5.8
    #Power Supplies:
    #---------------
    #Supply     Status         PS Type
    #------     ------      ---------------
    #PS0       [NO_FAULT]     [Sun-Fire-280R]
    #PS1       [NO_FAULT]     [Sun-Fire-280R]
    return if ( m/^Supply     Status         PS Type/ );
    return if ( m/^PS\d+ +\[NO_FAULT\] +\[Sun-Fire-.*\]/ );

    # from a 280R with 5.10_63
    #Power Supplies:
    #PS0       [OK    ]     [Sun-Fire-280R]
    return if ( m/^PS\d+ +\[\s*OK\s*\] +\[Sun-Fire-.*\]/ );



    # from a 450 with 5.8
    #Power Supplies:
    #---------------
    #Supply     Rating    Temp    Status
    #------     ------    ----    ------
    #  0         550 W     35       OK
    #  1         550 W     36       OK
    return if ( m/^Supply     Rating    Temp    Status/ );
    if ( m/^ +(\d+) +\d+ W +(\d+) +(OK)/ ) {
	if ( $3 ne "OK" || $2 > $crit_temp  ) {
	    push @crits, "PS $1 temperature is $2 $3";
	    }
	if ( $2 > $warn_temp  ) {
	    push @warns, "PS $1 temperature is $2 $3";
	    }
	return;
	}


    # from a V490 with 5.10
#Supply     Status        Fault     Fan Fail   Temp Fail
#------    ------------   --------  ---------  ---------
#PS0      [NO_FAULT    ]   OFF       OFF       OFF
#PS1      [NO_FAULT    ]   OFF       OFF       OFF
    if ( $system_config =~ m/V490/i ) {
	return if ( m/^ Supply \s+ Status \s+ Fault \s+ Fan \s+ Fail \s+
	    Temp \s+ Fail \s* $/x );
	if ( m/^ (PS\d+) \s+ \[ \s* (\w+) \s* \] \s+ (\w+) \s+ (\w+) \s+
		(\w+) \s* $/ix ) {
	    if ( $2 ne 'NO_FAULT' ) {
		push @crits, "power supply $1 $2";
		}
	    elsif ( $3 ne 'OFF' ) {
		push @crits, "power supply $1 fault led $3";
		}
	    elsif ( $4 ne 'OFF' ) {
		push @crits, "power supply $1 fan-fail led $4";
		}
	    elsif ( $5 ne 'OFF' ) {
		push @crits, "power supply $1 temp-fail led $5";
		}
	    return;
	    }
	}


    # from a V880 with 5.9
#Power Supplies:
#---------------
#
#Supply     Status     Fan Fail  Temp Fail  CS Fail  3.3V   5V   12V   48V
#------  ------------  --------  ---------  -------  ----   --   ---   ---
#PS0      GOOD                                         6     4     3     6
#PS1      GOOD                                         7     4     3     6
#PS2      GOOD                                         7     4     3     6

    # from a V890 with 5.10
#                                                    Current Drain:
#Supply     Status     Fan Fail  Temp Fail  CS Fail  3.3V   5V   12V   48V
#------  ------------  --------  ---------  -------  ----   --   ---   ---
#PS0      GOOD                                         6     3     2     9
#PS1      GOOD                                         6     3     2     9
#PS2      GOOD                                         6     3     2     9
    return if ( m/^\s+Current Drain:/ );
    return if ( m/^Supply +Status +Fan Fail +Temp Fail +CS Fail/ );
    if ( m/^(PS\d+) +(\S+) +\d+ +\d+ +\d+ +\d+/ ) {
	return if ( $2 eq 'GOOD' );
	push @crits, "$1 $2";
	}


    # from a V880 with 5.9
    #Power Supplies:
    #---------------
    #Supply                        Status
    #---------                     ------
    #0                                OK
    #1                                OK
    #2                                OK
    #3                                OK
    #PPS                              OK
    #    System 3.3v                  OK
    #    System 5.0v                  OK
    #    Peripheral 5.0v              OK
    #    Peripheral 12v               OK
    #    Auxilary 5.0v                OK
    #    Peripheral 5.0v precharge    OK
    #    Peripheral 12v precharge     OK
    #    System 3.3v precharge        OK
    #    System 5.0v precharge        OK
    #AC Power                         OK
    return if ( m/^Supply +Status$/ );
    return if ( m/^ *.+ +OK$/ );




    # from a 3800 with 5.8
#Power Supplies:
#---------------
#          VDC 0                 VDC 1
#          Current Voltage Temp  Current Voltage  Sensor
#FRU Name   Amps     VDC   DegC   Amps     VDC    Status
#--------  ------- ------- ----  ------- -------  ------
#PS0       8.51    56.59   28    0.20    55.54    Green
#PS1       7.46    56.33   28    0.37    55.28    Green
#PS2       8.12    56.85   28    0.70    55.54    Green

    return if ( m/^\s+VDC 0\s+ VDC 1/ );
    return if ( m/^\s+Current Voltage Temp  Current Voltage  Sensor/ );
    return if ( m/^FRU Name   Amps     VDC   DegC   Amps     VDC    Status/ );

    if ( m/^(PS\d+) +[\d\.]+ +[\d\.]+ +(\d+) +[\d\.]+ +[\d\.]+ +(\S+)/ ) {
	if ( $2 >= $crit_temp ) {
	    push @crits, "$1 temperature too high $2 $3";
	    }
	elsif ( $2 >= $warn_temp ) {
	    push @warns, "$1 temperature too high $2 $3";
	    }
	return;
	}


    # from a 4810 with 5.8
#Power Supplies:
#---------------
#          VDC 0                 VDC 1
#          Current Voltage Temp  Current Voltage  Sensor
#FRU Name   Amps     VDC   DegC   Amps     VDC    Status
#--------  ------- ------- ----  ------- -------  ------
# (then nothing under the titlebar)


    $reparse = 1;
    }










sub check_asic_revs {

    # from a V100, with 5.9
    #ASIC Revisions:
    #---------------
    #  <then there was nothing under it>

    # from a Sun Blade 150 with 5.9
#ASIC Revisions:
#---------------
#ebus: Rev 1
    return if ( m/^ebus: Rev 1/ );

    # from a Netra T1 200 with 5.8
    return if ( m/^Cheerio: ebus Rev 1/ );


    # from a v210 with 5.9
#ASIC Revisions:
#-------------------------------------------------------------------
#Path                   Device           Status             Revision
#-------------------------------------------------------------------
#/pci@1f,700000         pci108e,a801     okay               3
#/pci@1e,600000         pci108e,a801     okay               3
#/pci@1c,600000         pci108e,a801     okay               3
#/pci@1d,700000         pci108e,a801     okay               3

    return if ( m/^Path +Device +Status +Revision/);
    if ( m!^(/\S+) +(\S+) +(\S+) +(\S+) *$! ) {
	if ( $3 ne "okay" ) {
	    push @crits, "asic: $_";
	    }
	return;
	}


    # from another v210, also with 5.9, but different patch rev
#ASIC Revisions:
#---------------
#pci: Rev 4
#pci: Rev 4
#pci: Rev 4
#pci: Rev 4

    return if ( m/^pci: Rev \d+$/ );

    # from a 450 with 5.8
    #ASIC Revisions:
    #---------------
    #STP2223BGA: Rev 4
    #STP2223BGA: Rev 4
    #STP2223BGA: Rev 4
    #STP2003QFP: Rev 1
    #STP2205BGA: Rev 1
    return if ( m/^STP[A-Z\d]+: Rev \d+/ );

    # from a 4000 with 5.8
#ASIC Revisions:
#---------------
#Brd  FHC  AC  SBus0  SBus1  PCI0  PCI1  FEPS  Board Type      Attributes
#---  ---  --  -----  -----  ----  ----  ----  ----------      ----------
# 0    1    5                                  CPU             84MHz Capable
# 1    1    5    1      1                 22   Dual-SBus       84MHz Capable
# 2    1    5                                  CPU             84MHz Capable
    return if ( m/^Brd  FHC  AC  SBus0  SBus1  PCI0  PCI1  FEPS  Board Type/);
    return if ( m/^ *\d+ +\d+ +\d+ +CPU +\d+MHz Capable$/ );
    return if ( m/^ *\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +(Dual-SBus|Dual-PCI) +\d+MHz Capable$/ );



    


    $reparse = 1;
    }






sub check_fw_version {

    # from a Sun T3-1 with 5.10 Generic_142909-17
#============================ FW Version ============================
#Version
#------------------------------------------------------------
# Sun System Firmware 8.0.0.e 2010/09/30 13:33

    # from a Sun T3-1 with 5.10 Generic_148888-03
#Sun System Firmware 8.3.0.b 2013/04/23 08:29

    # from a T1000 running 5.10 Generic_142909-17
#System Firmware 6.7.12  2011/07/06 20:03

    return if ( m/^Version\s*$/ );
    return if ( m/^\s*(Sun|Oracle) System Firmware / );
    return if ( m/^\s*System Firmware / );

    $reparse = 1;
    }





sub check_prom_revs {

    # from a V100, with 5.9
    #System PROM revisions:
    #----------------------
    #  CORE 1.0.14 2001/11/07 17:16
    return if ( m!CORE \d+.\d+.\d+ \d+/\d+/\d+ \d+:\d+! );


    # from a v210 with 5.9
#System PROM revisions:
#----------------------
#OBP 4.8.2 2003/03/27 13:22 Sun Fire V210/V240
#OBDIAG 4.8.2 2003/03/27 13:23
    return if ( m!OBP \d+.\d+.\d+ \d+/\d+/\d+ \d+:\d+! );
    return if ( m!OBDIAG \d+.\d+.\d+ \d+/\d+/\d+ \d+:\d+! );


    # from a 280R with 5.8
    # also a V880 with 5.9
    # also a 6800 with 5.9
    #System PROM revisions:
    #----------------------
    #OBP 4.2.2 2001/04/26 14:59
    return if ( m!^OBP \d+.\d+.\d+ \d+/\d+/\d+ \d+:\d+! );

    # from a 4000 with 5.8
#System Board PROM revisions:
#----------------------------
#Board  0:   OBP   3.2.23 1999/10/01 18:43   POST  3.9.23 1999/10/01 18:46
#Board  1:   FCODE 1.8.22 1999/05/12 15:32   iPOST 3.4.22 1999/05/12 15:37
    return if ( m!Board +\d+: +(FCODE|OBP) +\d+.\d+.\d+ \d+/\d+/\d+ \d+:\d+! );

# from a Sun Blade 100 with 5.9
#System PROM revisions:
#----------------------
#OBP 4.0.45 2001/02/08 14:33 Sun Blade 100
#POST 1.2.6 2000/08/30 21:20

# from a Serverblade B1600 with S10_55
#OBP  4.7.5 2003/01/08 11:38 Sun Serverblade1
    return if ( m!^OBP \s+ \d+.\d+.\d+ \s+ \d+/\d+/\d+ \s+ \d+:\d+
	\s+ Sun\sServerblade1!ix );

    return if ( m!POST \d+.\d+.\d+ \d+/\d+/\d+ \d+:\d+! );



    # from a Sun T3-1 with 5.10 Generic_142909-17
#====================== System PROM revisions =======================
#Version
#------------------------------------------------------------
#OBP 4.32.0.b 2010/09/29 19:13

    return if ( m/^Version\s*$/ );
    return if ( m/^OBP / );

    $reparse = 1;
    }





sub check_io_asic_revs {

    # from a 280R with 5.8
    #IO ASIC revisions:
    #------------------
    #                     Port
    #Model     ID  Status Version
    #-------- ---- ------ -------
    #Schizo    8     ok      4
    return if ( m/^\s+Port/ );
    return if ( m/^Model +ID  Status Version/ );
    return if ( m/^\S+ +\d+ +ok +\d+/ );

    # from a V880 with 5.9
    #IO ASIC revisions:
    #------------------
    #                     Port
    #Brd  Model            ID  Status Version
    #---- --------------- ---- ------ -------
    #IB-1 unknown          8    ok     4
    #IB-1 unknown          9    ok     4
    return if ( m/^\s+Port/ );
    return if ( m/^Brd  Model +ID  Status Version/ );
    return if ( m/^\S+ +\w+ +\d+ +ok +\d+/ );

    # from a 6800 with 5.9
    #IO ASIC revisions:
    #------------------
    #                          Port
    #FRU Name    Model            ID  Status Version
    #----------- --------------- ---- ------ -------
    #/N0/IB6/P0  SUNW,schizo      24   ok     3
    #/N0/IB6/P1  SUNW,schizo      25   ok     3
    #/N0/IB6/P0  SUNW,sgsbbc      24   ok     2
    return if ( m/^\s+Port/ );
    return if ( m/^FRU Name +Model +ID +Status +Version/ );
    return if ( m!^/N\d+/IB\d+/P\d+ +\S+ +\d+ +ok +\d+! );

    # from a T2000 with 5.10
#IO ASIC revisions:
#------------------
#Location             Path                                     Device                         Revision
#-------------------- ---------------------------------------- ------------------------------ ---------
#IOBD/SAS-SATA-HBA                                  /pci@780                 SUNW,sun4v-pci     0
#

    return if ( m/^ Location \s+ Path \s+ Device \s+ Revision \s* $/x );
    return if ( m!^ (IOBD/\S+) \s+ (/\S+) \s+ (\S+) \s+ (\S+) \s* $!x );



    # from a T1000 running 5.10 Generic_142909-17
#MB/IO-BRIDGE                                         /pci@780                 SUNW,sun4v-pci     0
#MB/SAS-SATA-HBA                                      /pci@7c0                 SUNW,sun4v-pci     0

    return if ( m!^\s* MB/\S+ \s+ /pci\S+ \s+ \S+ \s+ \d+ \s*$!x );

    $reparse = 1;
    }




sub check_processor_sockets {

    # from an x2200 m2  with 5.10
#==== Processor Sockets ====================================
#
#Version                          Location Tag
#-------------------------------- --------------------------
#Dual-Core AMD Opteron(tm) Processor 2214 CPU 1
#Dual-Core AMD Opteron(tm) Processor 2214 CPU 2
#

    # from another x2200 m2  with 5.10
#Dual-Core AMD Opteron(tm) Processor 2210 ^B^BU^D
#Dual-Core AMD Opteron(tm) Processor 2210 ^B^BU^D
    # from another x2200 m2  with 5.10
#Quad-Core AMD Opteron(tm) Processor 2356 CPU 1
    # from a x4500 with 5.10
#Dual Core AMD Opteron(tm) Processor 290 CPU1


    return if ( m/^Version \s+ Location \s+ Tag/ix );
    if ( m/^(Dual|Quad)[ -]Core AMD Opteron\(tm\) Processor \d+/i ) { 
	$ncpus++;
	return;
	}


    # from an x4100 with 5.10
#==== Processor Sockets ====================================
#
#Version                          Location Tag
#-------------------------------- --------------------------
#Dual Core AMD Opteron(tm) Processor 275 H0
#Dual Core AMD Opteron(tm) Processor 275 H1
#Dual Core AMD Opteron(tm) Processor 275 H2
#Dual Core AMD Opteron(tm) Processor 275 H3

    if ( m/^Dual Core AMD Opteron\(tm\) Processor \d+ H\d/i ) { 
	$ncpus++;
	return;
	}

    # from an x4440 with 5.10
#Version                          Location Tag
#-------------------------------- --------------------------
#Six-Core AMD Opteron(tm) Processor 8431 CPU 1
#Six-Core AMD Opteron(tm) Processor 8431 CPU 2
    if ( m/^Six-Core AMD Opteron\(tm\) Processor \d+ CPU \d+/i ) { 
	$ncpus++;
	return;
	}

    $reparse = 1;
    }




sub check_memory_device_sockets {

    # from an x2100 m2 with 5.10
#
#==== Memory Device Sockets ================================
#
#Type    Status Set Device Locator      Bank Locator
#------- ------ --- ------------------- --------------------
#unknown empty  0   DIMMA1              BANK0
#unknown empty  0   DIMMB1              BANK1
#unknown empty  0   DIMMA0              BANK2
#DDR2    in use 0   DIMMB0              BANK3


    # from an x2200 m2 with 5.10
#==== Memory Device Sockets ================================
#
#Type    Status Set Device Locator      Bank Locator
#------- ------ --- ------------------- --------------------
#DDR2    in use 0   CPU0_DIMM0          BANK0
#DDR2    in use 0   CPU0_DIMM1          BANK1
#unknown empty  0   CPU0_DIMM2          BANK2
#unknown empty  0   CPU0_DIMM3          BANK3
#unknown empty  0   CPU0_DIMM4          BANK4
#unknown empty  0   CPU0_DIMM5          BANK5
#unknown empty  0   CPU0_DIMM6          BANK6
#unknown empty  0   CPU0_DIMM7          BANK7
#DDR2    in use 0   CPU1_DIMM0          BANK0
#DDR2    in use 0   CPU1_DIMM1          BANK1
#unknown empty  0   CPU1_DIMM2          BANK2
#unknown empty  0   CPU1_DIMM3          BANK3
#unknown empty  0   CPU1_DIMM4          BANK4
#unknown empty  0   CPU1_DIMM5          BANK5
#unknown empty  0   CPU1_DIMM6          BANK6
#unknown empty  0   CPU1_DIMM7          BANK7


    # from an x4100 with 5.10
#==== Memory Device Sockets ================================
#
#Type    Status Set Device Locator      Bank Locator
#------- ------ --- ------------------- --------------------
#DDR     in use 0   H0_DIMM0            BANK0
#DDR     in use 0   H0_DIMM1            BANK1
#unknown empty  0   H0_DIMM2            BANK2
#unknown empty  0   H0_DIMM3            BANK3
#DDR     in use 0   H1_DIMM0            BANK4
#DDR     in use 0   H1_DIMM1            BANK5
#unknown empty  0   H1_DIMM2            BANK6
#unknown empty  0   H1_DIMM3            BANK7

    # from an x4600 with 5.10
#Type    Status Set Device Locator      Bank Locator
#------- ------ --- ------------------- --------------------
#DDR2    in use 0   DIMM0               BANK0
#DDR2    in use 0   DIMM1               BANK1


    return if ( m/^Type \s+ Status \s+ Set/xi );
    return if ( m/^unknown \s+ empty/xi );
    if ( m/^DDR2? \s+ (\S.+\S) \s+ \d+ \s+
		(DIMM\w*\d+|CPU\d+_DIMM\d+|H\d+_DIMM\d+) \s+
		(BANK\d+)/xi ) {
	if ( $1 ne "in use" ) {
	    push @warns, "memory $2 $3 $2";
	    }
	return;
	}

    $reparse = 1;
    }





sub check_on_board_devices {

    # from an x2200 m2 with 5.10
#==== On-Board Devices =====================================
#  To Be Filled By O.E.M.

    return if ( m/To Be Filled By O.E.M./i );


    # from an x4100 with 5.10
#==== On-Board Devices =====================================
# LSI serial-ATA #1
# Gigabit Ethernet #1
# Gigabit Ethernet #2
# ATI Rage XL VGA

    # from an x4240 with 5.10
# AST2000 VGA

    return if ( m/LSI serial-ATA/i );
    return if ( m/Gigabit Ethernet/i );
    return if ( m/ATI Rage.* VGA/i );
    return if ( m/AST2000 VGA/i );

    # from an x4500 with 5.10
# Marvell serial-ATA #1
# Intel 82546EB #1
# Intel 82551QM

    return if ( m/Marvell serial-ATA \#\d+/i );
    return if ( m/Intel (?:82546EB|82551QM)/i );

    $reparse = 1;
    }




sub check_upgradable_slots {

    # from an x2200 m2 with 5.10
#==== Upgradeable Slots ====================================
#
#ID  Status    Type             Description
#--- --------- ---------------- ----------------------------
#0   available PCI Express      PCIE 0
#1   available PCI Express      PCIE 1

    return if ( m/^ID \s+ Status \s+ Type \s+ Description/ix );

    # from an x4100 with 5.10
#ID  Status    Type             Description
#--- --------- ---------------- ----------------------------
#0   in use    PCI-X            PCIX SLOT0
#1   available PCI-X            PCIX SLOT1
#2   available PCI-X            PCIX SLOT2
#3   available PCI-X            PCIX SLOT3
#4   available PCI-X            PCIX SLOT4

    # from an x4500 with 5.10
#1   available PCI-X            PCIX0


    # from an x4600 with 5.10
#ID  Status    Type             Description
#--- --------- ---------------- ----------------------------
#0   in use    PCI-X            PCIX SLOT0
#1   available PCI-X            PCIX SLOT1
#2   available other            PCIExp SLOT2


    if ( m/^(\d+) \s+ (\S.+\S) \s+ (PCI-X|PCI.Express|other) \s+
	    (PCIX\s+SLOT\d+|PCIE\s+\d+|PCIExp\s+SLOT\d+)/xi ) {
	if ( $2 ne 'in use' && $2 ne 'available' ) {
	    push @warns, "slot $4 $2";
	    }
	return;
	}
    elsif ( m/^(\d+) \s+ (\S.+\S) \s+ (PCI-X|PCI.Express|other) 
	    \s+ (PCIX\d+)/xi ) { 
	if ( $2 ne 'in use' && $2 ne 'available' ) {
	    push @warns, "slot $4 $2";
	    }
	return;
	}

    $reparse = 1;
    }






sub check_chassis_serial_number { 

    # from a v245, with Solaris 10 
#Chassis Serial Number:
#----------------------
#0745FML0DM

    return if ( m/^[\dA-Z]{8,12}\s*$/ );

    $reparse = 1;
    }





sub check_sys_proc_mode { 

    # from a M4000 with 5.10 Generic_142909-17

    return if ( m/^SPARC64-VII mode\s*$/ );

    $reparse = 1;
    }


