From 213c26db3f75fa585ea23f65a2d038a305c48ca3 Mon Sep 17 00:00:00 2001 From: Alexander Shaduri Date: Tue, 19 Apr 2011 17:59:44 +0000 Subject: [PATCH] Don't add sd* device if it's 3ware controller. Properly add devices detected through 3ware scan (linux). Limit smartctl sequential scans to 24 drives (it takes too long without it). --- gsmartcontrol/TODO | 16 +++++++----- .../src/applib/storage_detector_linux.cpp | 26 ++++++++++++++----- gsmartcontrol/src/applib/storage_device.cpp | 5 +--- gsmartcontrol/src/applib/storage_device.h | 2 +- 4 files changed, 31 insertions(+), 18 deletions(-) diff --git a/gsmartcontrol/TODO b/gsmartcontrol/TODO index 3f0e92e..d822234 100644 --- a/gsmartcontrol/TODO +++ b/gsmartcontrol/TODO @@ -43,13 +43,17 @@ Set tooltips wherever we have "No description available". !!! Allow quitting when test is running (ask first). -+"Add Device" window needs tooltips on both labels and entries. -+ Don't mention -d 3ware on windows in the tooltip. -+ Both points go for the preferences window as well. +Display -d type in the main window, tooltip, drive info window. + Otherwise it's just /dev/twa0. -+Fixed usb drive re-detection with scsi. -+Fixed invalid regexps in tw_cli parsing. -+Added support for "Product" field of USB drives (used instead of Device in newer smartctl) +When running smartctl on drives, run them on the driveptr-s directly, + (use -i -H -c options, maybe even drive->fetch...()), so that the drive + remembers it. + +Linux: Detect scsi number for 3ware and use that for tw_cli controller. + +Windows: If smartctl --scan-open returns no "sd*,port"-style devices, + check if 3dm2 is installed and execute "tw_cli show" to get the controllers. diff --git a/gsmartcontrol/src/applib/storage_detector_linux.cpp b/gsmartcontrol/src/applib/storage_detector_linux.cpp index 7fe84d3..1fe5e82 100644 --- a/gsmartcontrol/src/applib/storage_detector_linux.cpp +++ b/gsmartcontrol/src/applib/storage_detector_linux.cpp @@ -213,7 +213,7 @@ inline std::string read_proc_scsi_scsi_file(std::vector& lines) /// Get number of ports using tw_cli. Return -1 on error. inline std::string tw_cli_get_drives(const std::string& dev, int controller_no, - std::vector drives, ExecutorFactoryRefPtr ex_factory) + std::vector& drives, ExecutorFactoryRefPtr ex_factory) { hz::intrusive_ptr executor = ex_factory->create_executor(ExecutorFactory::ExecutorTwCli); @@ -279,7 +279,7 @@ inline std::string tw_cli_get_drives(const std::string& dev, int controller_no, /// Get number of ports by sequentially running smartctl on each port, until /// one of the gives an error. Return -1 on error. inline std::string smartctl_get_drives(const std::string& dev, const std::string& type, - int from, int to, std::vector drives, ExecutorFactoryRefPtr ex_factory) + int from, int to, std::vector& drives, ExecutorFactoryRefPtr ex_factory) { hz::intrusive_ptr smartctl_ex = ex_factory->create_executor(ExecutorFactory::ExecutorSmartctl); @@ -295,7 +295,7 @@ inline std::string smartctl_get_drives(const std::string& dev, const std::string } if (!error_msg.empty()) { - debug_out_info("app", "Sequential port scan aborted with error: " << error_msg); + debug_out_info("app", "Smartctl returned with an error: " << error_msg); } else { drives.push_back(StorageDeviceRefPtr(new StorageDevice(dev, type_arg))); } @@ -398,8 +398,17 @@ inline std::string detect_drives_linux_proc_partitions(std::vector smartctl_ex = ex_factory->create_executor(ExecutorFactory::ExecutorSmartctl); + for (std::size_t i = 0; i < devices.size(); ++i) { - drives.push_back(StorageDeviceRefPtr(new StorageDevice(devices.at(i)))); + StorageDeviceRefPtr drive(new StorageDevice(devices.at(i))); + drive->fetch_basic_data_and_parse(smartctl_ex); + + // 3ware controllers also export themselves as sd*. Smartctl detects that, + // so we can avoid adding them. + if (!app_pcre_match("/AMCC/3ware controller/im", drive->get_info_output())) { + drives.push_back(drive); + } } return std::string(); @@ -423,8 +432,10 @@ Detection: Grep /proc/devices for "twa" or "twe" (e.g. "251 twa"). Use this for /dev/tw* part. Grep /proc/scsi/scsi for AMCC or 3ware (LSI too?), use number of matched lines N for /dev/tw*[0, N-1]. -For detecting the number of ports, use "tw_cli /c0 show all", 0 being the controller N. - If there's no tw_cli, we'll have to scan all 128 ports. +For detecting the number of ports, use "tw_cli /cK show all", K being the controller + scsi number, which is displayed as scsiK in the scsi file. + If there's no tw_cli, we'll have to scan all the ports (up to supported maximum). + This is too slow however, so scan only 24. Implementation notes: it seems that twe uses "3ware" and twa uses "AMCC". We can't handle a situation with both twa and twe present, since we don't know @@ -485,7 +496,8 @@ inline std::string detect_drives_linux_3ware(std::vector& d error_msg = tw_cli_get_drives(dev, i, drives, ex_factory); if (!error_msg.empty()) { // no tw_cli - error_msg = smartctl_get_drives(dev, "3ware,%d", 0, (twa_found ? 127 : 15), drives, ex_factory); + // 128 smartctl calls are too much (it's too slow). Settle for 24. + error_msg = smartctl_get_drives(dev, "3ware,%d", 0, (twa_found ? 24 : 15), drives, ex_factory); } if (!error_msg.empty()) { diff --git a/gsmartcontrol/src/applib/storage_device.cpp b/gsmartcontrol/src/applib/storage_device.cpp index 814459c..229801f 100644 --- a/gsmartcontrol/src/applib/storage_device.cpp +++ b/gsmartcontrol/src/applib/storage_device.cpp @@ -153,11 +153,10 @@ std::string StorageDevice::fetch_basic_data_and_parse(hz::intrusive_ptrclear_fetched(); // clear everything fetched before, including outputs - std::string output; // We don't use "--all" - it may cause really screwed up the output (tests, etc...). // This looks just like "--info" only on non-smart devices. // --info --health --capabilities - std::string error_msg = execute_device_smartctl("-i -H -c", smartctl_ex, output, true); // set type to invalid if needed + std::string error_msg = execute_device_smartctl("-i -H -c", smartctl_ex, this->info_output_, true); // set type to invalid if needed // Smartctl 5.39 cvs/svn version defaults to usb type on at least linux and windows. // This means that the old SCSI identify command isn't executed by default, @@ -174,8 +173,6 @@ std::string StorageDevice::fetch_basic_data_and_parse(hz::intrusive_ptrinfo_output_ = output; - // Set some properties too - they are needed for e.g. AODC status, etc... return this->parse_basic_data(true); } diff --git a/gsmartcontrol/src/applib/storage_device.h b/gsmartcontrol/src/applib/storage_device.h index 09b2be7..41116c9 100644 --- a/gsmartcontrol/src/applib/storage_device.h +++ b/gsmartcontrol/src/applib/storage_device.h @@ -68,7 +68,7 @@ class StorageDevice : public hz::intrusive_ptr_referenced { // clear everything fetched before. void clear_fetched(bool including_outputs = true); - /// Calls "smartctl --info" (info section), then parse_basic_data(). + /// Calls "smartctl -i -H -c" (info section, health, capabilities), then parse_basic_data(). /// Called during drive detection. /// Note: this will clear the non-basic properties! std::string fetch_basic_data_and_parse(hz::intrusive_ptr smartctl_ex = 0);