diff --git a/smart-status/CHANGELOG b/smart-status/CHANGELOG index 8e105a2bf..4f2655fd1 100644 --- a/smart-status/CHANGELOG +++ b/smart-status/CHANGELOG @@ -9,4 +9,4 @@ ATA mode is now used by default on CentOS and Redhat Enterprise versions 5 and a ---- Changes since 1.440 ---- SCSI drives are visible in the System and Server Status module. The SMART status monitor now has an option to only alert if the error count on a drive has increased. -Improved support for 3ware drives, so that the underlying disks are now detected and can be reported on separately. +Improved support for 3ware and HP RAID devices, so that the underlying disks are now detected and can be reported on separately. diff --git a/smart-status/action.cgi b/smart-status/action.cgi index fa70184d8..52c62646a 100755 --- a/smart-status/action.cgi +++ b/smart-status/action.cgi @@ -9,7 +9,7 @@ $mode = $in{'short'} ? "short" : @drives = &list_smart_disks_partitions(); ($d) = grep { $_->{'device'} eq $in{'drive'} && - $_->{'3ware'} == $in{'3ware'} } @drives; + $_->{'subdisk'} == $in{'subdisk'} } @drives; print &text($mode."_doing", $d->{'desc'}),"\n"; if ($mode eq "short") { ($ok, $out) = &short_test($in{'drive'}, $d); diff --git a/smart-status/index.cgi b/smart-status/index.cgi index 067c62e34..63c509ba9 100755 --- a/smart-status/index.cgi +++ b/smart-status/index.cgi @@ -36,14 +36,16 @@ if ($config{'mode'} == 1 || $in{'drive'}) { print &ui_form_start("index.cgi"); print "$text{'index_show'}\n"; print &ui_select("drive", $in{'drive'}, - [ map { [ $_->{'device'}, + [ map { [ $_->{'device'}.":".$_->{'subdisk'}, $_->{'desc'}.($_->{'model'} ? " ($_->{'model'})" : "") ] } @drives ], 1, 0, 0, 0, "onChange='form.submit()'"); print &ui_submit($text{'index_ok'}),"\n"; print &ui_form_end(); if ($in{'drive'}) { - ($d) = grep { $_->{'device'} eq $in{'drive'} } @drives; + ($device, $subdisk) = split(/:/, $in{'drive'}); + ($d) = grep { $_->{'device'} eq $device && + $_->{'subdisk'} == $subdisk } @drives; &show_drive($d); } } @@ -61,9 +63,13 @@ sub show_drive { print &ui_form_start("action.cgi"); print &ui_hidden("drive", $_[0]->{'device'}); -print &ui_hidden("3ware", $_[0]->{'3ware'}); -print &ui_table_start(&text('index_drive', "$_[0]->{'device'}"), - undef, 2); +print &ui_hidden("subdisk", $_[0]->{'subdisk'}); +local $h = defined($_[0]->{'subdisk'}) ? + &text('index_drivesub', "$_[0]->{'device'}", + $_[0]->{'subdisk'}) : + &text('index_drive', "$_[0]->{'device'}"); +print &ui_table_start($h, "width=100%", 4, + [ "width=30%", undef, "width=30%", undef ]); local $st = &get_drive_status($_[0]->{'device'}, $_[0]); print &ui_table_row($text{'index_desc'}, $_[0]->{'desc'}); @@ -87,18 +93,32 @@ if ($st->{'support'} && $st->{'enabled'}) { ""); } print &ui_table_row($text{'index_check'}, - $st->{'check'} ? $text{'yes'} : "$text{'no'}"); - if ($config{'attribs'}) { - print &ui_table_hr(); - local $a; - foreach $a (@{$st->{'attribs'}}) { - next if ($a->[0] =~ /UDMA CRC Error Count/i); # too long - print &ui_table_row($a->[0], - $a->[2] =~ /^\s*(seconds|minutes|hours|days|months|years|weeks)\s*/i || !$a->[2] ? $a->[1]." ".$a->[2] : $a->[2]); - } - } + $st->{'check'} ? $text{'yes'} : + "$text{'no'}"); } print &ui_table_end(); + +# Show extra attributes +if ($config{'attribs'} && @{$st->{'attribs'}}) { + print &ui_hidden_table_start($text{'index_attrs'}, "width=100%", 2, + "attrs", 1, [ "width=30%" ]); + foreach my $a (@{$st->{'attribs'}}) { + next if ($a->[0] =~ /UDMA CRC Error Count/i); # too long + print &ui_table_row($a->[0], + $a->[2] =~ /^\s*(seconds|minutes|hours|days|months|years|weeks)\s*/i || !$a->[2] ? $a->[1]." ".$a->[2] : $a->[2]); + } + print &ui_hidden_table_end(); + } + +# Show raw data from smartctl +if ($config{'attribs'} && $st->{'raw'}) { + print &ui_hidden_table_start($text{'index_raw'}, "width=100%", 2, + "raw", @{$st->{'attribs'}} ? 0 : 1); + print &ui_table_row(undef, + "
".&html_escape($st->{'raw'})."", 2);
+ print &ui_hidden_table_end();
+ }
+
if ($st->{'support'} && $st->{'enabled'}) {
print &ui_form_end([ [ "short", $text{'index_short'} ],
[ "ext", $text{'index_ext'} ],
diff --git a/smart-status/lang/en b/smart-status/lang/en
index 578fb4240..a9b261599 100644
--- a/smart-status/lang/en
+++ b/smart-status/lang/en
@@ -6,6 +6,7 @@ index_show=Show status of drive:
index_ok=Show
index_eidescsi=No IDE or SCSI drives were found on your system.
index_drive=Status of drive $1
+index_drivesub=Status of drive $1, disk $2
index_desc=Location
index_size=Drive size
index_model=Make and model
@@ -17,6 +18,8 @@ index_ext=Extended Self Test
index_data=Data Collection Test
index_errors=Errors logged
index_ecount=$1 errors detected
+index_attrs=Additional SMART attributes
+index_raw=Full SMART status report
index_return=module index
monitor_type=SMART Drive Check
diff --git a/smart-status/smart-status-lib.pl b/smart-status/smart-status-lib.pl
index 1d4d59d7c..9b4008622 100644
--- a/smart-status/smart-status-lib.pl
+++ b/smart-status/smart-status-lib.pl
@@ -33,41 +33,65 @@ May include faked-up 3ware devices
=cut
sub list_smart_disks_partitions
{
-local @drives = grep { $_->{'type'} eq 'ide' ||
- $_->{'type'} eq 'scsi' } &fdisk::list_disks_partitions();
local @rv;
local $threecount = 0;
-foreach my $d (@drives) {
- if ($d->{'type'} eq 'scsi' && $d->{'model'} =~ /3ware/i) {
+foreach my $d (&fdisk::list_disks_partitions()) {
+ if (($d->{'type'} eq 'scsi' || $d->{'type'} eq 'raid') &&
+ $d->{'model'} =~ /3ware/i) {
# Actually a 3ware RAID device .. but we want to probe the
# underlying real disks, so add fake devices for them
- my $count = &count_3ware_disks($d);
+ my $count = &count_subdisks($d, "3ware");
for(my $i=0; $i<$count; $i++) {
push(@rv, { 'device' => '/dev/twe'.$threecount,
'prefix' => '/dev/twe'.$threecount,
'desc' => '3ware physical disk '.$i,
'type' => 'scsi',
- '3ware' => $i,
+ 'subtype' => '3ware',
+ 'subdisk' => $i,
});
}
$threecount++;
}
- else {
+ elsif ($d->{'device'} =~ /^\/dev\/cciss\/(.*)$/) {
+ # HP Smart Array .. add underlying disks
+ my $count = &count_subdisks($d, "cciss");
+ for(my $i=0; $i<$count; $i++) {
+ push(@rv, { 'device' => $d->{'device'},
+ 'prefix' => $d->{'device'},
+ 'desc' => 'HP Smart Array physical disk '.$i,
+ 'type' => 'scsi',
+ 'subtype' => 'cciss',
+ 'subdisk' => $i,
+ });
+ }
+ }
+ elsif ($d->{'type'} eq 'scsi' || $d->{'type'} eq 'ide') {
+ # Some other disk
push(@rv, $d);
}
}
return sort { $a->{'device'} cmp $b->{'device'} ||
- $a->{'3ware'} <=> $b->{'3ware'} } @rv;
+ $a->{'subdisk'} <=> $b->{'subdisk'} } @rv;
}
-=head2 count_3ware_disks(&drive)
+=head2 count_subdisks(&drive, type)
-Returns the number of physical disks on some 3ware RAID device.
+Returns the number of sub-disks for a hardware RAID device, by calling
+smartctl on them until failure.
=cut
-sub count_3ware_disks
+sub count_subdisks
{
-return 4; # XXX
+local ($d, $type) = @_;
+local $count = 0;
+while(1) {
+ local $cmd = "$config{'smartctl'} -d $type,$count ".
+ quotemeta($d->{'device'});
+ &execute_command($cmd);
+ last if ($?);
+ $count++;
+ }
+return $count;
}
=head2 get_drive_status(device-name, [&drive])
@@ -157,6 +181,7 @@ if ($config{'attribs'}) {
# Fetch other attributes
local ($lastline, @attribs);
local $doneknown = 0;
+ $rv{'raw'} = "";
open(OUT, "$config{'smartctl'} $extra_args -a $qd |");
while(