Work on 3ware support

This commit is contained in:
Jamie Cameron
2009-01-12 03:33:39 +00:00
parent d87f9e972b
commit bbb58184c3
6 changed files with 136 additions and 36 deletions

View File

@@ -9,3 +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.

View File

@@ -7,17 +7,18 @@ $mode = $in{'short'} ? "short" :
$in{'ext'} ? "ext" : "data";
&ui_print_header(undef, $text{$mode.'_title'}, "");
@drives = &fdisk::list_disks_partitions();
($d) = grep { $_->{'device'} eq $in{'drive'} } @drives;
@drives = &list_smart_disks_partitions();
($d) = grep { $_->{'device'} eq $in{'drive'} &&
$_->{'3ware'} == $in{'3ware'} } @drives;
print &text($mode."_doing", $d->{'desc'}),"\n";
if ($mode eq "short") {
($ok, $out) = &short_test($in{'drive'});
($ok, $out) = &short_test($in{'drive'}, $d);
}
elsif ($mode eq "ext") {
($ok, $out) = &ext_test($in{'drive'});
($ok, $out) = &ext_test($in{'drive'}, $d);
}
elsif ($mode eq "data") {
($ok, $out) = &data_test($in{'drive'});
($ok, $out) = &data_test($in{'drive'}, $d);
}
print "<pre>$out</pre>\n";
if ($ok) {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 0 B

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -26,9 +26,7 @@ if (!$ver) {
&text('index_version', $ver));
# Get list of drives
@drives = grep { $_->{'type'} eq 'ide' ||
$_->{'type'} eq 'scsi' } &fdisk::list_disks_partitions();
@drives = sort { $a->{'device'} cmp $b->{'device'} } @drives;
@drives = &list_smart_disks_partitions();
if (!@drives) {
&ui_print_endpage($text{'index_eidescsi'});
}
@@ -63,9 +61,10 @@ 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);
local $st = &get_drive_status($_[0]->{'device'});
local $st = &get_drive_status($_[0]->{'device'}, $_[0]);
print &ui_table_row($text{'index_desc'},
$_[0]->{'desc'});
if ($_[0]->{'cylsize'}) {

View File

@@ -1,15 +1,19 @@
# Functions for getting SMART status
=head1 smart-status-lib.pl
Functions for getting SMART status
=cut
do '../web-lib.pl';
&init_config();
do '../ui-lib.pl';
&foreign_require("fdisk", "fdisk-lib.pl");
$extra_args = $config{'extra'};
if ($config{'ata'}) {
$extra_args .= " -d ata";
}
# get_smart_version()
=head2 get_smart_version()
Returns the version number of the SMART tools on this system
=cut
sub get_smart_version
{
if (!defined($smartctl_version_cache)) {
@@ -21,12 +25,62 @@ if (!defined($smartctl_version_cache)) {
return $smartctl_version_cache;
}
# get_drive_status(device)
# Returns a hash reference containing the status of some drive
=head2 list_smart_disks_partitions
Returns a sorted list of disks that can support SMART.
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) {
# 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);
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,
});
}
$threecount++;
}
else {
push(@rv, $d);
}
}
return sort { $a->{'device'} cmp $b->{'device'} ||
$a->{'3ware'} <=> $b->{'3ware'} } @rv;
}
=head2 count_3ware_disks(&drive)
Returns the number of physical disks on some 3ware RAID device.
=cut
sub count_3ware_disks
{
return 4; # XXX
}
=head2 get_drive_status(device-name, [&drive])
Returns a hash reference containing the status of some drive
=cut
sub get_drive_status
{
local ($device, $drive) = @_;
local %rv;
local $qd = quotemeta($_[0]);
local $qd = quotemeta($device);
local $extra_args = &get_extra_args($device, $drive);
if (&get_smart_version() > 5.0) {
# Use new command format
@@ -141,13 +195,16 @@ if ($config{'attribs'}) {
return \%rv;
}
# short_test(drive)
# short_test(device, [&drive])
# Starts a short drive test, and returns 1 for success or 0 for failure, plus
# any output.
sub short_test
{
local ($device, $drive) = @_;
local $qm = quotemeta($device);
local $extra_args = &get_extra_args($device, $drive);
if (&get_smart_version() > 5.0) {
local $out = &backquote_logged("$config{'smartctl'} $extra_args -t short $_[0] 2>&1");
local $out = &backquote_logged("$config{'smartctl'} $extra_args -t short $qm 2>&1");
if ($? || $out !~ /testing has begun/i) {
return (0, $out);
}
@@ -156,7 +213,7 @@ if (&get_smart_version() > 5.0) {
}
}
else {
local $out = &backquote_logged("$config{'smartctl'} $extra_args -S $_[0] 2>&1");
local $out = &backquote_logged("$config{'smartctl'} $extra_args -S $qm 2>&1");
if ($? || $out !~ /test has begun/i) {
return (0, $out);
}
@@ -166,13 +223,16 @@ else {
}
}
# ext_test(drive)
# ext_test(device, [&drive])
# Starts an extended drive test, and returns 1 for success or 0 for failure,
# plus any output.
sub ext_test
{
local ($device, $drive) = @_;
local $qm = quotemeta($device);
local $extra_args = &get_extra_args($device, $drive);
if (&get_smart_version() > 5.0) {
local $out = &backquote_logged("$config{'smartctl'} $extra_args -t long $_[0] 2>&1");
local $out = &backquote_logged("$config{'smartctl'} $extra_args -t long $qm 2>&1");
if ($? || $out !~ /testing has begun/i) {
return (0, $out);
}
@@ -181,7 +241,7 @@ if (&get_smart_version() > 5.0) {
}
}
else {
local $out = &backquote_logged("$config{'smartctl'} $extra_args -X $_[0] 2>&1");
local $out = &backquote_logged("$config{'smartctl'} $extra_args -X $qm 2>&1");
if ($? || $out !~ /test has begun/i) {
return (0, $out);
}
@@ -191,13 +251,16 @@ else {
}
}
# data_test(drive)
# data_test(device, [&drive])
# Starts offline data collection, and returns 1 for success or 0 for failure,
# plus any output.
sub data_test
{
local ($device, $drive) = @_;
local $qm = quotemeta($device);
local $extra_args = &get_extra_args($device, $drive);
if (&get_smart_version() > 5.0) {
local $out = &backquote_logged("$config{'smartctl'} $extra_args -t offline $_[0] 2>&1");
local $out = &backquote_logged("$config{'smartctl'} $extra_args -t offline $qm 2>&1");
if ($? || $out !~ /testing has begun/i) {
return (0, $out);
}
@@ -206,7 +269,7 @@ if (&get_smart_version() > 5.0) {
}
}
else {
local $out = &backquote_logged("$config{'smartctl'} $extra_args -O $_[0] 2>&1");
local $out = &backquote_logged("$config{'smartctl'} $extra_args -O $qm 2>&1");
if ($? || $out !~ /test has begun/i) {
return (0, $out);
}
@@ -216,5 +279,27 @@ else {
}
}
=head2 get_extra_args(device, [&drive])
Returns extra command-line args to smartctl, needed for some drive type.
=cut
sub get_extra_args
{
local ($device, $drive) = @_;
if (!$drive) {
($drive) = grep { $_->{'device'} eq $device }
&list_smart_disks_partitions();
}
local $extra_args = $config{'extra'};
if ($drive && defined($drive->{'3ware'})) {
$extra_args .= " -d 3ware,$drive->{'3ware'}";
}
elsif ($config{'ata'}) {
$extra_args .= " -d ata";
}
return $extra_args;
}
1;

View File

@@ -22,7 +22,15 @@ if (!-r $_[1]->{'drive'}) {
return { 'up' => -1,
'desc' => $text{'monitor_nosuch'} };
}
local $st = &get_drive_status($_[1]->{'drive'});
local @drives = &list_smart_disks_partitions();
local ($d) = grep { $_->{'device'} eq $_[1]->{'drive'} &&
$_->{'3ware'} eq $_[1]->{'3ware'} } @drives;
if (!$d) {
# Not in list?!
return { 'up' => -1,
'desc' => $text{'monitor_nosuch'} };
}
local $st = &get_drive_status($d->{'drive'}, $d);
# Record number of errors since last time
local %errors;
@@ -64,15 +72,15 @@ else {
sub status_monitor_dialog
{
local $rv;
local @drives = grep { $_->{'type'} eq 'ide' ||
$_->{'type'} eq 'scsi' } &fdisk::list_disks_partitions();
@drives = sort { $a->{'device'} cmp $b->{'device'} } @drives;
local ($inlist) = grep { $_->{'device'} eq $_[1]->{'drive'} } @drives;
local @drives = &list_smart_disks_partitions();
local ($inlist) = grep { $_->{'device'} eq $_[1]->{'drive'} &&
$_->{'3ware'} eq $_[1]->{'3ware'} } @drives;
$inlist = 1 if (!$_[1]->{'drive'});
$rv .= &ui_table_row($text{'monitor_drive'},
&ui_select("drive", !$_[1]->{'drive'} ? $drives[0]->{'device'} :
$inlist ? $_[1]->{'drive'} : undef,
[ (map { [ $_->{'device'},
$inlist ? $inlist->{'drive'}.':'.$inlist->{'3ware'} :
undef,
[ (map { [ $_->{'device'}.':'.$_->{'3ware'},
$_->{'desc'}.($_->{'model'} ?
" ($_->{'model'})" : "") ] } @drives),
[ "", $text{'monitor_other'} ] ]).
@@ -89,8 +97,14 @@ return $rv;
# Parse form for selecting a rule
sub status_monitor_parse
{
$_[1]->{'drive'} = $_[2]->{'drive'} || $_[2]->{'other'};
$_[1]->{'drive'} =~ /^\S+$/ || &error($text{'monitor_edrive'});
if ($_[2]->{'drive'}) {
($_[1]->{'drive'}, $_[1]->{'3ware'}) = split(/:/, $_[2]->{'drive'});
}
else {
$_[1]->{'drive'} = $_[2]->{'other'};
$_[1]->{'3ware'} = undef;
$_[1]->{'drive'} =~ /^\S+$/ || &error($text{'monitor_edrive'});
}
$_[1]->{'errors'} = $_[2]->{'errors'};
}