$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) {
-# 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)) {
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
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);
}
}
}
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);
}
}
}
-# 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);
}
}
}
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);
}
}
}
-# 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);
}
}
}
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);
}
}
}
+=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;
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;
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'} ] ]).
# 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'};
}