From bbb58184c3ba4e489cf02d28c33e93d2ee44ce7a Mon Sep 17 00:00:00 2001 From: Jamie Cameron Date: Mon, 12 Jan 2009 03:33:39 +0000 Subject: [PATCH] Work on 3ware support --- smart-status/CHANGELOG | 1 + smart-status/action.cgi | 11 +-- smart-status/images/smallicon.gif | Bin 0 -> 1217 bytes smart-status/index.cgi | 7 +- smart-status/smart-status-lib.pl | 121 +++++++++++++++++++++++++----- smart-status/status_monitor.pl | 32 +++++--- 6 files changed, 136 insertions(+), 36 deletions(-) diff --git a/smart-status/CHANGELOG b/smart-status/CHANGELOG index 4b1e0cdb8..8e105a2bf 100644 --- a/smart-status/CHANGELOG +++ b/smart-status/CHANGELOG @@ -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. diff --git a/smart-status/action.cgi b/smart-status/action.cgi index 44311d3e1..fa70184d8 100755 --- a/smart-status/action.cgi +++ b/smart-status/action.cgi @@ -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 "
$out
\n"; if ($ok) { diff --git a/smart-status/images/smallicon.gif b/smart-status/images/smallicon.gif index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a4bc6b2933d5c33813f68e043db1aa07e95dee6e 100644 GIT binary patch literal 1217 zcmZ?wbh9u|lwgox_|Cu(>X-7qV(%&>F}1a|VnTe?)zuSERRV!9A9s0qdGDQ`y$g#|3;l|Vivuh&qJyt(pHW^| zSg5U~xpc{r{QP_^ISqXk$@%l<`MF(APfvfiyEHX5)y@8@rGc7-x_)eQp|A6a(w#Jt6Gmty{N>@6;tm_*|P^>|kdTQRmiqB`ReqNE@!z_V`My1sjT+6s1ZGEzy235gYs zf4*J|wu#slTQ`56=Yj<9`93J3`B^Yi=v|NqR1?Y^#Szf>OZj?{H=aS1UI z4fBiazSU`GXJ=z$^XtQ%_0gsI>pknL9YdV-+vX?xdVAIuBz}9;S`%-7{rYupPxl#R z4p9z^;>-kpJSqNqwW{WP@u}Rr)2B~|`}k-|bDunUa?+)y`=2Onz zDIJa9A7)>?@b$^@1_o*X9grcQyuiTmkD;1V#^XYCcci_JV9bev1?D^v%OtoLZdiD< zJ!a9uj>Bt?%XIVHwBd5|IKt=^b>Zu;4}vNBX5uOmfn{Dj>>0^gb2%<=dT7Rby5&gH zhGjEXI3%ArxY2Nt`oUcBO$7nQo_^B4Cj>k+i+FD{P2*1VW1PZ!u}v?%=Iq90EWT45 z9~L!;zIc1cP+T}+rY2iw(;}XLHq~N>cjtB_C+yAqFp0fI+fHp?pz_g2oD)259bsJD zdPJCww=4U{0q3XP42;h6Vl}s~h?aMcW^$R3$Thi*Yr6`o=GR3Ii+rr>WM6$f#w8Kz z$B|<+HFG*!*zHSy3?J~gup4QI-CW4L%$kq;>W<}0Z-_1tU+?rlFZAMK_Lc=|&)+m0 zyg0XAkwLTL&Z661j23DN4Hx3H*0(q@D{re=#AG<*MR&^BF=JpFd#cS{'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', "$_[0]->{'device'}"), 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'}) { diff --git a/smart-status/smart-status-lib.pl b/smart-status/smart-status-lib.pl index 58a630e24..1d4d59d7c 100644 --- a/smart-status/smart-status-lib.pl +++ b/smart-status/smart-status-lib.pl @@ -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; diff --git a/smart-status/status_monitor.pl b/smart-status/status_monitor.pl index e9740ae8f..c68875c83 100644 --- a/smart-status/status_monitor.pl +++ b/smart-status/status_monitor.pl @@ -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'}; }