---- 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.
@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);
print &ui_form_start("index.cgi");
print "<b>$text{'index_show'}</b>\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);
}
}
{
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', "<tt>$_[0]->{'device'}</tt>"),
- undef, 2);
+print &ui_hidden("subdisk", $_[0]->{'subdisk'});
+local $h = defined($_[0]->{'subdisk'}) ?
+ &text('index_drivesub', "<tt>$_[0]->{'device'}</tt>",
+ $_[0]->{'subdisk'}) :
+ &text('index_drive', "<tt>$_[0]->{'device'}</tt>");
+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'});
"</font>");
}
print &ui_table_row($text{'index_check'},
- $st->{'check'} ? $text{'yes'} : "<font color=#ff0000>$text{'no'}</font>");
- 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'} :
+ "<font color=#ff0000>$text{'no'}</font>");
}
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,
+ "<pre>".&html_escape($st->{'raw'})."</pre>", 2);
+ print &ui_hidden_table_end();
+ }
+
if ($st->{'support'} && $st->{'enabled'}) {
print &ui_form_end([ [ "short", $text{'index_short'} ],
[ "ext", $text{'index_ext'} ],
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
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
=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])
# Fetch other attributes
local ($lastline, @attribs);
local $doneknown = 0;
+ $rv{'raw'} = "";
open(OUT, "$config{'smartctl'} $extra_args -a $qd |");
while(<OUT>) {
s/\r|\n//g;
$rv{'errors'} = $1;
}
$lastline = $_;
+ $rv{'raw'} .= $_."\n";
}
close(OUT);
$rv{'attribs'} = \@attribs;
&list_smart_disks_partitions();
}
local $extra_args = $config{'extra'};
-if ($drive && defined($drive->{'3ware'})) {
- $extra_args .= " -d 3ware,$drive->{'3ware'}";
+if ($drive && defined($drive->{'subdisk'})) {
+ $extra_args .= " -d $drive->{'subtype'},$drive->{'subdisk'}";
}
elsif ($config{'ata'}) {
$extra_args .= " -d ata";
}
local @drives = &list_smart_disks_partitions();
local ($d) = grep { $_->{'device'} eq $_[1]->{'drive'} &&
- $_->{'3ware'} eq $_[1]->{'3ware'} } @drives;
+ $_->{'subdisk'} eq $_[1]->{'subdisk'} } @drives;
if (!$d) {
# Not in list?!
return { 'up' => -1,
local $rv;
local @drives = &list_smart_disks_partitions();
local ($inlist) = grep { $_->{'device'} eq $_[1]->{'drive'} &&
- $_->{'3ware'} eq $_[1]->{'3ware'} } @drives;
+ $_->{'subdisk'} eq $_[1]->{'subdisk'} } @drives;
$inlist = 1 if (!$_[1]->{'drive'});
$rv .= &ui_table_row($text{'monitor_drive'},
&ui_select("drive", !$_[1]->{'drive'} ? $drives[0]->{'device'} :
- $inlist ? $inlist->{'drive'}.':'.$inlist->{'3ware'} :
+ $inlist ? $inlist->{'drive'}.':'.$inlist->{'subdisk'} :
undef,
- [ (map { [ $_->{'device'}.':'.$_->{'3ware'},
+ [ (map { [ $_->{'device'}.':'.$_->{'subdisk'},
$_->{'desc'}.($_->{'model'} ?
" ($_->{'model'})" : "") ] } @drives),
[ "", $text{'monitor_other'} ] ]).
sub status_monitor_parse
{
if ($_[2]->{'drive'}) {
- ($_[1]->{'drive'}, $_[1]->{'3ware'}) = split(/:/, $_[2]->{'drive'});
+ ($_[1]->{'drive'}, $_[1]->{'subdisk'}) = split(/:/, $_[2]->{'drive'});
}
else {
$_[1]->{'drive'} = $_[2]->{'other'};
- $_[1]->{'3ware'} = undef;
+ $_[1]->{'subdisk'} = undef;
$_[1]->{'drive'} =~ /^\S+$/ || &error($text{'monitor_edrive'});
}
$_[1]->{'errors'} = $_[2]->{'errors'};