Fixed up 3ware support, added HP smart array support

This commit is contained in:
Jamie Cameron
2009-01-14 01:34:17 +00:00
parent 0b4ded19fe
commit 2b1c2bc9e6
6 changed files with 86 additions and 37 deletions

View File

@@ -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.

View File

@@ -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);

View File

@@ -36,14 +36,16 @@ if ($config{'mode'} == 1 || $in{'drive'}) {
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);
}
}
@@ -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', "<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'});
@@ -87,18 +93,32 @@ if ($st->{'support'} && $st->{'enabled'}) {
"</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'} ],

View File

@@ -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

View File

@@ -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(<OUT>) {
s/\r|\n//g;
@@ -188,6 +213,7 @@ if ($config{'attribs'}) {
$rv{'errors'} = $1;
}
$lastline = $_;
$rv{'raw'} .= $_."\n";
}
close(OUT);
$rv{'attribs'} = \@attribs;
@@ -292,8 +318,8 @@ if (!$drive) {
&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";

View File

@@ -24,7 +24,7 @@ if (!-r $_[1]->{'drive'}) {
}
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,
@@ -74,13 +74,13 @@ sub status_monitor_dialog
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'} ] ]).
@@ -98,11 +98,11 @@ return $rv;
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'};