From f4e463df436b0b3c97efe7e53c81b663e4241180 Mon Sep 17 00:00:00 2001 From: Giuseppe Iuculano Date: Wed, 13 Jun 2012 16:26:15 +0200 Subject: [PATCH] Imported Upstream version 5.42+svn3561 --- CHANGELOG | 64 +++- INSTALL | 14 +- Makefile.am | 12 +- NEWS | 7 +- ataprint.cpp | 4 +- dev_interface.cpp | 13 +- dev_interface.h | 8 +- drivedb.h | 57 +++- os_freebsd.cpp | 31 +- os_linux.cpp | 47 ++- os_win32.cpp | 749 ++++++++++++++++++++++++++++++++++++++++- os_win32/installer.nsi | 222 ++++++------ smartctl.8.in | 66 ++-- smartd.8.in | 18 +- smartd.conf.5.in | 52 +-- smartd.service.in | 4 +- utility.h | 11 +- 17 files changed, 1157 insertions(+), 222 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 23994e4..cac139e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,6 @@ CHANGELOG for smartmontools -$Id: CHANGELOG 3539 2012-05-01 19:57:02Z chrfranke $ +$Id: CHANGELOG 3561 2012-06-05 19:49:31Z chrfranke $ The most recent version of this file is: http://smartmontools.svn.sourceforge.net/viewvc/smartmontools/trunk/smartmontools/CHANGELOG?view=markup @@ -41,6 +41,68 @@ Maintainers / Developers Key (alphabetic order): + [CF] man pages: Minor updates and syntax fixes. + + [CF] smartd.service.in: Add ExecReload and StandardOutput. + Make EnvironmentFile optional (ticket #194). + + [CF] drivedb.h USB updates: + - HP Desktop HD BD07 (0x03f0:0xbd07) + - Iomega Prestige Desktop USB 3.0 (0x059b:0x0070) + - Prolific PL2507 (0x067b:0x2507): unsupported -> -d usbjmicron,0 + - WD My Passport USB 3.0 (0x1058:0x0748) + - WD My Book Essential USB 3.0 (0x1058:0x1140) + - Sharkoon SATA QuickDeck Pro (0x1f75:0x0888): unsupported + - Hitachi Touro Desk (0x4971:0x1015) + + [CF] Move function str_starts_with() to utility.h. + + [CF] smartctl.8.in, smartd.conf.5.in: Note required Areca SAS firmware version. + + [CF] INSTALL, smartctl.8.in: Announce OS X SAT SMART Driver (ticket #25). + + [CF] Add smart_device::is_syscall_unsup(). + + [CF] os_win32.cpp: Avoid ENOTSUP which is not provided by some versions + of MinGW. + + [DG] os_linux.cpp: Fix scsi pass-through SG_INFO_CHECK mask logic + (ticket #225) + + [CF] drivedb.h updates: + - Sandforce Driven SSDs: OCZ-NOCTI + - Intel 330 Series SSDs (ticket #227) + + [CF] smartctl.8.in, smartd.conf.5.in: Document '-d areca N[/E]' support + for Windows. + + [CF] os_win32.cpp: Add help text and error messages for '-d areca,N[/E]'. + + [CF] os_win32.cpp win_areca_device: Disable full 48-bit ATA support. + Add missing set_err() calls. Remove unused function and parameter. + + [CF] os_win32.cpp: Add support for SATA disks behind Areca SATA and SAS + controllers. Requires '-d areca,N[/E]' as type and '[/dev/]arcmsrX' + as device name. + + Patch was provided by Hank Wu from Areca. + + [CF] Windows installer: Make name of checksum file 32-/64-bit specific. + + [CF] Windows installer: Add support for combined 32-/64-bit installer. + + [CF] Windows installer: Drop support for UBCD4Win. + + [AS] os_freebsd.cpp: sync Areca code with linux version by adding optional + enclosure number. + + [CF] smartctl.8.in, smartd.conf.5.in: Add brief doc for '-d areca N/E'. + + [CF] os_linux.cpp: Add optional enclosure number to '-d areca' option. + This adds support for SATA disks behind Areca SAS controllers. + + Patch was provided by Hank Wu from Areca. + [CF] smartctl: Add log addresses and statistics value from ACS-3 revision 2. [CF] drivedb.h updates: diff --git a/INSTALL b/INSTALL index 36fcb95..1863c34 100644 --- a/INSTALL +++ b/INSTALL @@ -1,7 +1,7 @@ Smartmontools installation instructions ======================================= -$Id: INSTALL 3537 2012-04-28 13:22:41Z chrfranke $ +$Id: INSTALL 3555 2012-06-01 21:07:33Z chrfranke $ Please also see the smartmontools home page: http://smartmontools.sourceforge.net/ @@ -193,6 +193,13 @@ Table of contents: hard drive comes with the offline test switched on by default, so even that works. + The OS X SAT SMART Driver provides access to SMART data for SAT capable + USB and Firewire devices: + https://github.com/kasbert/OS-X-SAT-SMART-Driver + https://github.com/RJVB/OS-X-SAT-SMART-Driver + This does not require any smartctl -d TYPE option and should work also + with older smartmontools releases. + H) OS/2, eComStation The code was tested on eComStation 1.1, but it should work on all versions @@ -495,6 +502,11 @@ To create a Windows installer, use: It is also possible to (cross-)build the installer on Linux. This was successfully tested on Debian with package "nsis". +To create a combined 32-/64-bit installer, use this in 32-bit build +directory if 64-build directory is at ../build64: + + make builddir_win64=../build64 installer_win32 + To both create and run the (interactive) installer, use: make install-win32 diff --git a/Makefile.am b/Makefile.am index cd3d8a5..d105556 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in # -# $Id: Makefile.am 3527 2012-03-25 16:42:24Z chrfranke $ +# $Id: Makefile.am 3545 2012-05-25 21:19:03Z chrfranke $ # @SET_MAKE@ @@ -656,7 +656,7 @@ FILES_WIN32 = \ $(docdir_win32)/README.txt \ $(docdir_win32)/TODO.txt \ $(docdir_win32)/WARNINGS.txt \ - $(docdir_win32)/checksums.txt \ + $(docdir_win32)/checksums$(win_bits).txt \ $(docdir_win32)/smartd.conf \ $(docdir_win32)/smartctl.8.html \ $(docdir_win32)/smartctl.8.txt \ @@ -708,11 +708,13 @@ if OS_WIN32_NSIS # Build NSIS installer # Note: Only option character '-' is also compatible with Linux version of makensis $(distinst_win32): os_win32/installer.nsi distdir.mkdir $(FILES_WIN32) + test -z '$(builddir_win64)' || ( cd $(builddir_win64) && make distdir-win32 ) @date=`sed -n 's,^.*DATE[^"]*"\([^"]*\)".*$$,\1,p' svnversion.h`; \ rev=`sed -n 's,^.*REV[^"]*"\([^"]*\)".*$$,r\1,p' svnversion.h`; \ verstr="$(PACKAGE_VERSION) $$date $$rev "$(BUILD_INFO); \ - echo "'$(MAKENSIS)' -V2 -NOCD -DINPDIR=$(distdir_win32) -DOUTFILE=$@ -DVERSTR='$$verstr' $<"; \ - '$(MAKENSIS)' -V2 -NOCD -DINPDIR=$(distdir_win32) -DOUTFILE=$@ -DVERSTR="$$verstr" $< + d64=; test -z '$(builddir_win64)' || d64='-DINPDIR64=$(builddir_win64)/$(PACKAGE)-$(VERSION).win64'; \ + echo "'$(MAKENSIS)' -V2 -NOCD -DINPDIR=$(distdir_win32) $$d64 -DOUTFILE=$@ -DVERSTR='$$verstr' $<"; \ + '$(MAKENSIS)' -V2 -NOCD -DINPDIR=$(distdir_win32) $$d64 -DOUTFILE=$@ -DVERSTR="$$verstr" $< md5sum $@ > $@.md5 sha1sum $@ > $@.sha1 sha256sum $@ > $@.sha256 @@ -772,7 +774,7 @@ $(docdir_win32)/%.conf: $(srcdir)/%.conf $(UNIX2DOS) < $< > $@ touch -r $< $@ -$(docdir_win32)/checksums.txt: $(EXEFILES_WIN32) +$(docdir_win32)/checksums$(win_bits).txt: $(EXEFILES_WIN32) (cd $(exedir_win32) && md5sum *.exe && sha1sum *.exe && sha256sum *.exe) \ | $(UNIX2DOS) > $@ diff --git a/NEWS b/NEWS index 07cbf41..a5b41cd 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,6 @@ smartmontools NEWS ------------------ -$Id: NEWS 3530 2012-03-27 19:54:06Z chrfranke $ +$Id: NEWS 3557 2012-06-04 19:50:21Z chrfranke $ The most up-to-date version of this file is: http://smartmontools.svn.sourceforge.net/viewvc/smartmontools/trunk/smartmontools/NEWS?view=markup @@ -18,9 +18,14 @@ Summary: smartmontools release 5.43 already running. Override with new option '-t force'. - smartctl supports extended self-test polling times greater than 255 minutes. +- Controller-independent SAT detection: '-d sat,auto[+TYPE]'. - smartd.conf DEFAULT directive. +- Many HDD, SSD and USB additions to drive database. +- Linux and FreeBSD: Support for SATA disks behind Areca SAS controllers. +- Windows: Support for SATA disks behind Areca controllers. - Windows smartd: directives '-l offlinests,ns' and '-l selfteststs,ns'. +- Windows installer: Combined 32-/64-bit support. - FreeBSD: fixed crash on SCSI devices with FreeBSD9-RC1 Date 2011-10-20 diff --git a/ataprint.cpp b/ataprint.cpp index 0007d34..4fd2724 100644 --- a/ataprint.cpp +++ b/ataprint.cpp @@ -40,7 +40,7 @@ #include "utility.h" #include "knowndrives.h" -const char * ataprint_cpp_cvsid = "$Id: ataprint.cpp 3539 2012-05-01 19:57:02Z chrfranke $" +const char * ataprint_cpp_cvsid = "$Id: ataprint.cpp 3554 2012-06-01 20:11:46Z chrfranke $" ATAPRINT_H_CVSID; @@ -2146,7 +2146,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options) int powermode = ataCheckPowerMode(device); switch (powermode) { case -1: - if (device->get_errno() == ENOSYS) { + if (device->is_syscall_unsup()) { pout("CHECK POWER MODE not implemented, ignoring -n option\n"); break; } powername = "SLEEP"; powerlimit = 2; diff --git a/dev_interface.cpp b/dev_interface.cpp index b63f34c..7651244 100644 --- a/dev_interface.cpp +++ b/dev_interface.cpp @@ -31,7 +31,7 @@ #include #endif -const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp 3524 2012-03-21 22:19:31Z chrfranke $" +const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp 3554 2012-06-01 20:11:46Z chrfranke $" DEV_INTERFACE_H_CVSID; ///////////////////////////////////////////////////////////////////////////// @@ -54,6 +54,17 @@ smart_device::~smart_device() throw() { } +bool smart_device::is_syscall_unsup() const +{ + if (get_errno() == ENOSYS) + return true; +#ifdef ENOTSUP + if (get_errno() == ENOTSUP) + return true; +#endif + return false; +} + bool smart_device::set_err(int no, const char * msg, ...) { if (!msg) diff --git a/dev_interface.h b/dev_interface.h index d887b60..136831c 100644 --- a/dev_interface.h +++ b/dev_interface.h @@ -18,7 +18,7 @@ #ifndef DEV_INTERFACE_H #define DEV_INTERFACE_H -#define DEV_INTERFACE_H_CVSID "$Id: dev_interface.h 3524 2012-03-21 22:19:31Z chrfranke $\n" +#define DEV_INTERFACE_H_CVSID "$Id: dev_interface.h 3554 2012-06-01 20:11:46Z chrfranke $\n" #include "utility.h" @@ -147,6 +147,10 @@ public: const char * get_errmsg() const { return m_err.msg.c_str(); } + /// Return true if last error indicates an unsupported system call. + /// Default implementation returns true on ENOSYS and ENOTSUP. + virtual bool is_syscall_unsup() const; + /// Set last error number and message. /// Printf()-like formatting is supported. /// Returns false always to allow use as a return expression. @@ -183,7 +187,7 @@ public: /// Open device with autodetection support. /// May return another device for further access. /// In this case, the original pointer is no longer valid. - /// Default Implementation calls 'open()' and returns 'this'. + /// Default implementation calls 'open()' and returns 'this'. virtual smart_device * autodetect_open(); /////////////////////////////////////////////// diff --git a/drivedb.h b/drivedb.h index 819dea6..31cce28 100644 --- a/drivedb.h +++ b/drivedb.h @@ -75,7 +75,7 @@ /* const drive_settings builtin_knowndrives[] = { */ - { "$Id: drivedb.h 3538 2012-05-01 19:45:49Z chrfranke $", + { "$Id: drivedb.h 3559 2012-06-05 18:35:10Z chrfranke $", "-", "-", "This is a dummy entry to hold the SVN-Id of drivedb.h", "" @@ -204,6 +204,7 @@ const drive_settings builtin_knowndrives[] = { "KINGSTON SH100S3(120|240)G|" // Hyper-X, SF-2281, tested with SH100S3240G/320ABBF0 "OCZ[ -](AGILITY2([ -]EX)?|COLOSSUS2|ONYX2|VERTEX(2|-LE))( [123]\\..*)?|" // SF-1200, // tested with OCZ-VERTEX2/1.11, OCZ-VERTEX2 3.5/1.11 + "OCZ-NOCTI|" // mSATA, SF-2100, tested with OCZ-NOCTI/2.15 "OCZ-REVODRIVE3?( X2)?|" // PCIe, SF-1200/2281, tested with // OCZ-REVODRIVE( X2)?/1.20, OCZ-REVODRIVE3 X2/2.11 "OCZ[ -](VELO|VERTEX2[ -](EX|PRO))( [123]\\..*)?|" // SF-1500, tested with @@ -456,6 +457,22 @@ const drive_settings builtin_knowndrives[] = { "-v 242,raw48,Host_Reads_32MiB " "-v 249,raw48,NAND_Writes_1GiB" }, + { "Intel 330 Series SSDs", // tested with INTEL SSDSC2CT180A3/300i + "INTEL SSDSC2CT(060|120|180)A3", + "", "", + //"-v 5,raw16(raw16),Reallocated_Sector_Ct " + "-v 9,msec24hour32,Power_On_Hours_and_Msec " + //"-v 12,raw48,Power_Cycle_Count " + //"-v 181,raw48,Program_Fail_Cnt_Total " // ] Missing in 330 specification from April 2012 + //"-v 182,raw48,Erase_Fail_Count_Total " // ] + //"-v 192,raw48,Power-Off_Retract_Count " + "-v 225,raw48,Host_Writes_32MiB " + //"-v 232,raw48,Available_Reservd_Space " + //"-v 233,raw48,Media_Wearout_Indicator " + "-v 241,raw48,Host_Writes_32MiB " + "-v 242,raw48,Host_Reads_32MiB " + "-v 249,raw48,NAND_Writes_1GiB" + }, { "Kingston branded X25-V SSDs", // fixed firmware "KINGSTON SSDNow 40GB", "2CV102(J[89A-Z]|[K-Z].)", // >= "2CV102J8" @@ -2214,6 +2231,13 @@ const drive_settings builtin_knowndrives[] = { // USB ID entries //////////////////////////////////////////////////// + // Hewlett-Packard + { "USB: HP Desktop HD BD07; ", // 2TB + "0x03f0:0xbd07", + "", + "", + "-d sat" + }, // ALi { "USB: ; ALi M5621", // USB->PATA "0x0402:0x5621", @@ -2345,6 +2369,12 @@ const drive_settings builtin_knowndrives[] = { "-d usbsunplus" }, // Iomega + { "USB: Iomega Prestige Desktop USB 3.0; ", + "0x059b:0x0070", + "", // 0x0004 + "", + "-d sat" // ATA output registers missing + }, { "USB: Iomega LPHD080-0; ", "0x059b:0x0272", "", @@ -2468,7 +2498,7 @@ const drive_settings builtin_knowndrives[] = { "0x067b:0x2507", "", "", - "" // unsupported + "-d usbjmicron,0" // Port number is required }, { "USB: ; Prolific PL3507", // USB+IEE1394->PATA "0x067b:0x3507", @@ -2746,6 +2776,12 @@ const drive_settings builtin_knowndrives[] = { "", "-d sat" }, + { "USB: WD My Passport USB 3.0; ", + "0x1058:0x0748", + "", + "", + "-d sat" + }, { "USB: WD My Book ES; ", "0x1058:0x0906", "", // 0x0012 @@ -2819,8 +2855,8 @@ const drive_settings builtin_knowndrives[] = { "-d sat" }, { "USB: WD My Book Essential USB 3.0; ", // 3TB - "0x1058:0x1130", - "", // 0x1012 + "0x1058:0x11[34]0", + "", // 0x1012/0x1003 "", "-d sat" }, @@ -3020,6 +3056,13 @@ const drive_settings builtin_knowndrives[] = { "", "-d usbsunplus" }, + // Unknown: 0x1f75 + { "USB: Sharkoon SATA QuickDeck Pro; ", // USB 2.0/3.0 + "0x1f75:0x0888", + "", // 0x0034 + "", + "" // unsupported + }, // Hitachi/SimpleTech { "USB: Hitachi Touro Desk; JMicron", // 3TB "0x4971:0x1011", @@ -3027,6 +3070,12 @@ const drive_settings builtin_knowndrives[] = { "", "-d usbjmicron" }, + { "USB: Hitachi Touro Desk 3.0; ", // 2TB + "0x4971:0x1015", + "", // 0x0000 + "", + "-d sat" // ATA output registers missing + }, { "USB: Hitachi/SimpleTech; JMicron", // 1TB "0x4971:0xce17", "", diff --git a/os_freebsd.cpp b/os_freebsd.cpp index 5038b12..d9a6add 100644 --- a/os_freebsd.cpp +++ b/os_freebsd.cpp @@ -74,7 +74,7 @@ #define PATHINQ_SETTINGS_SIZE 128 #endif -const char *os_XXXX_c_cvsid="$Id: os_freebsd.cpp 3525 2012-03-22 08:54:52Z samm2 $" \ +const char *os_XXXX_c_cvsid="$Id: os_freebsd.cpp 3542 2012-05-18 18:18:45Z samm2 $" \ ATACMDS_H_CVSID CCISS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_FREEBSD_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; #define NO_RETURN 0 @@ -194,8 +194,8 @@ static const char smartctl_examples[] = " smartctl -a --device=cciss,0 /dev/ciss0\n" " (Prints all SMART information for first disk \n" " on Common Interface for SCSI-3 Support driver)\n" - " smartctl -a --device=areca,1 /dev/arcmsr0\n" - " (Prints all SMART information for first disk \n" + " smartctl -a --device=areca,3/1 /dev/arcmsr0\n" + " (Prints all SMART information for 3rd disk in the 1st enclosure \n" " on first ARECA RAID controller)\n" ; @@ -1089,7 +1089,7 @@ class freebsd_areca_device public /*extends*/ freebsd_smart_device { public: - freebsd_areca_device(smart_interface * intf, const char * dev_name, int disknum); + freebsd_areca_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1); protected: virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); @@ -1313,12 +1313,13 @@ static int arcmsr_command_handler(int fd, unsigned long arcmsr_cmd, unsigned cha } -freebsd_areca_device::freebsd_areca_device(smart_interface * intf, const char * dev_name, int disknum) +freebsd_areca_device::freebsd_areca_device(smart_interface * intf, const char * dev_name, int disknum, int encnum) : smart_device(intf, dev_name, "areca", "areca"), freebsd_smart_device("ATA"), - m_disknum(disknum) + m_disknum(disknum), + m_encnum(encnum) { - set_info().info_name = strprintf("%s [areca_%02d]", dev_name, disknum); + set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum); } // Areca RAID Controller @@ -1437,7 +1438,8 @@ if (!ata_cmd_is_ok(in, return set_err(ENOTSUP, "DATA OUT not supported for this Areca controller type"); } - areca_packet[11] = m_disknum - 1; // drive number + areca_packet[11] = m_disknum - 1; // disk # + areca_packet[19] = m_encnum - 1; // enc# // ----- BEGIN TO SETUP CHECKSUM ----- for ( int loop = 3; loop < areca_packet_len - 1; loop++ ) @@ -2270,13 +2272,14 @@ smart_device * freebsd_smart_interface::get_custom_smart_device(const char * nam #endif // Areca? disknum = n1 = n2 = -1; - if (sscanf(type, "areca,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) { - if (n2 != (int)strlen(type)) { - set_err(EINVAL, "Option -d areca,N requires N to be a non-negative integer"); + int encnum = 1; + if (sscanf(type, "areca,%n%d/%d%n", &n1, &disknum, &encnum, &n2) >= 1 || n1 == 6) { + if (!(1 <= disknum && disknum <= 128)) { + set_err(EINVAL, "Option -d areca,N/E (N=%d) must have 1 <= N <= 128", disknum); return 0; } - if (!(1 <= disknum && disknum <= 24)) { - set_err(EINVAL, "Option -d areca,N (N=%d) must have 1 <= N <= 24", disknum); + if (!(1 <= encnum && encnum <= 8)) { + set_err(EINVAL, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum); return 0; } return new freebsd_areca_device(this, name, disknum); @@ -2287,7 +2290,7 @@ smart_device * freebsd_smart_interface::get_custom_smart_device(const char * nam std::string freebsd_smart_interface::get_valid_custom_dev_types_str() { - return "3ware,N, hpt,L/M/N, cciss,N, areca,N" + return "3ware,N, hpt,L/M/N, cciss,N, areca,N/E" #if FREEBSDVER > 800100 ", atacam" #endif diff --git a/os_linux.cpp b/os_linux.cpp index 46c8b3a..b68575a 100644 --- a/os_linux.cpp +++ b/os_linux.cpp @@ -5,9 +5,9 @@ * * Copyright (C) 2003-11 Bruce Allen * Copyright (C) 2003-11 Doug Gilbert - * Copyright (C) 2008 Hank Wu + * Copyright (C) 2008-12 Hank Wu * Copyright (C) 2008 Oliver Bock - * Copyright (C) 2008-11 Christian Franke + * Copyright (C) 2008-12 Christian Franke * Copyright (C) 2008 Jordan Hargrave * * Parts of this file are derived from code that was @@ -89,7 +89,7 @@ #define ARGUSED(x) ((void)(x)) -const char * os_linux_cpp_cvsid = "$Id: os_linux.cpp 3441 2011-10-12 17:22:15Z chrfranke $" +const char * os_linux_cpp_cvsid = "$Id: os_linux.cpp 3558 2012-06-05 16:42:05Z chrfranke $" OS_LINUX_H_CVSID; @@ -196,8 +196,9 @@ static const char smartctl_examples[] = " smartctl --all --device=hpt,1/1/3 /dev/sda\n" " (Prints all SMART info for the SATA disk attached to the 3rd PMPort\n" " of the 1st channel on the 1st HighPoint RAID controller)\n" - " smartctl --all --device=areca,3 /dev/sg2\n" - " (Prints all SMART info for 3rd ATA disk on Areca RAID controller)\n" + " smartctl --all --device=areca,3/1 /dev/sg2\n" + " (Prints all SMART info for 3rd ATA disk of the 1st enclosure\n" + " on Areca RAID controller)\n" ; @@ -605,7 +606,7 @@ static int sg_io_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report, } } - if (io_hdr.info | SG_INFO_CHECK) { /* error or warning */ + if (io_hdr.info & SG_INFO_CHECK) { /* error or warning */ int masked_driver_status = (LSCSI_DRIVER_MASK & io_hdr.driver_status); if (0 != io_hdr.host_status) { @@ -1652,13 +1653,14 @@ class linux_areca_device public /*extends*/ linux_smart_device { public: - linux_areca_device(smart_interface * intf, const char * dev_name, int disknum); + linux_areca_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1); protected: virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); private: int m_disknum; ///< Disk number. + int m_encnum; ///< Enclosure number. }; @@ -1964,12 +1966,13 @@ static int arcmsr_command_handler(int fd, unsigned long arcmsr_cmd, unsigned cha } -linux_areca_device::linux_areca_device(smart_interface * intf, const char * dev_name, int disknum) +linux_areca_device::linux_areca_device(smart_interface * intf, const char * dev_name, int disknum, int encnum) : smart_device(intf, dev_name, "areca", "areca"), linux_smart_device(O_RDWR | O_EXCL | O_NONBLOCK), - m_disknum(disknum) + m_disknum(disknum), + m_encnum(encnum) { - set_info().info_name = strprintf("%s [areca_%02d]", dev_name, disknum); + set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum); } // Areca RAID Controller @@ -2093,7 +2096,8 @@ if (!ata_cmd_is_ok(in, return set_err(ENOTSUP, "DATA OUT not supported for this Areca controller type"); } - areca_packet[11] = m_disknum - 1; // drive number + areca_packet[11] = m_disknum - 1; // disk# + areca_packet[19] = m_encnum - 1; // enc# // ----- BEGIN TO SETUP CHECKSUM ----- for ( int loop = 3; loop < areca_packet_len - 1; loop++ ) @@ -2927,12 +2931,6 @@ smart_device * linux_smart_interface::missing_option(const char * opt) return 0; } -// Return true if STR starts with PREFIX. -static inline bool str_starts_with(const char * str, const char * prefix) -{ - return !strncmp(str, prefix, strlen(prefix)); -} - // Return kernel release as integer ("2.6.31" -> 206031) static unsigned get_kernel_release() { @@ -3060,16 +3058,17 @@ smart_device * linux_smart_interface::get_custom_smart_device(const char * name, // Areca? disknum = n1 = n2 = -1; - if (sscanf(type, "areca,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) { - if (n2 != (int)strlen(type)) { - set_err(EINVAL, "Option -d areca,N requires N to be a non-negative integer"); + int encnum = 1; + if (sscanf(type, "areca,%n%d/%d%n", &n1, &disknum, &encnum, &n2) >= 1 || n1 == 6) { + if (!(1 <= disknum && disknum <= 128)) { + set_err(EINVAL, "Option -d areca,N/E (N=%d) must have 1 <= N <= 128", disknum); return 0; } - if (!(1 <= disknum && disknum <= 24)) { - set_err(EINVAL, "Option -d areca,N (N=%d) must have 1 <= N <= 24", disknum); + if (!(1 <= encnum && encnum <= 8)) { + set_err(EINVAL, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum); return 0; } - return new linux_areca_device(this, name, disknum); + return new linux_areca_device(this, name, disknum, encnum); } // Highpoint ? @@ -3121,7 +3120,7 @@ smart_device * linux_smart_interface::get_custom_smart_device(const char * name, std::string linux_smart_interface::get_valid_custom_dev_types_str() { - return "marvell, areca,N, 3ware,N, hpt,L/M/N, megaraid,N" + return "marvell, areca,N/E, 3ware,N, hpt,L/M/N, megaraid,N" #ifdef HAVE_LINUX_CCISS_IOCTL_H ", cciss,N" #endif diff --git a/os_win32.cpp b/os_win32.cpp index 1ab5749..ace6d32 100644 --- a/os_win32.cpp +++ b/os_win32.cpp @@ -4,6 +4,7 @@ * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2004-12 Christian Franke + * Copyright (C) 2012 Hank Wu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -85,7 +86,7 @@ #define SELECT_WIN_32_64(x32, x64) (x64) #endif -const char * os_win32_cpp_cvsid = "$Id: os_win32.cpp 3524 2012-03-21 22:19:31Z chrfranke $"; +const char * os_win32_cpp_cvsid = "$Id: os_win32.cpp 3558 2012-06-05 16:42:05Z chrfranke $"; // Disable Win9x/ME specific code if no longer supported by compiler. #ifdef _WIN64 @@ -531,6 +532,57 @@ private: }; +///////////////////////////////////////////////////////////////////////////// +/// Areca RAID support + +/* ARECA IO CONTROL CODE*/ +#define ARCMSR_IOCTL_READ_RQBUFFER 0x90002004 +#define ARCMSR_IOCTL_WRITE_WQBUFFER 0x90002008 +#define ARCMSR_IOCTL_CLEAR_RQBUFFER 0x9000200C +#define ARCMSR_IOCTL_CLEAR_WQBUFFER 0x90002010 +#define ARCMSR_IOCTL_RETURN_CODE_3F 0x90002018 +#define ARECA_SIG_STR "ARCMSR" + + +// The SRB_IO_CONTROL & SRB_BUFFER structures are used to communicate(to/from) to areca driver +typedef struct _SRB_IO_CONTROL +{ + unsigned int HeaderLength; + unsigned char Signature[8]; + unsigned int Timeout; + unsigned int ControlCode; + unsigned int ReturnCode; + unsigned int Length; +} sSRB_IO_CONTROL; + +typedef struct _SRB_BUFFER +{ + sSRB_IO_CONTROL srbioctl; + unsigned char ioctldatabuffer[1032]; // the buffer to put the command data to/from firmware +} sSRB_BUFFER; + +class win_areca_device +: public /*implements*/ ata_device, + public /*extends*/ win_smart_device +{ +public: + win_areca_device(smart_interface * intf, const char * dev_name, HANDLE fh, int disknum, int encnum = 1); + + static int arcmsr_command_handler(HANDLE fh, unsigned long arcmsr_cmd, unsigned char *data, int data_len); + +protected: + virtual bool open(); + + virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); + + bool arcmsr_ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); + +private: + int m_disknum; ///< Disk number. + int m_encnum; ///< Enclosure number. +}; + + ////////////////////////////////////////////////////////////////////// // Platform specific interfaces @@ -596,6 +648,10 @@ protected: virtual scsi_device * get_scsi_device(const char * name, const char * type); virtual smart_device * autodetect_smart_device(const char * name); + + virtual smart_device * get_custom_smart_device(const char * name, const char * type); + + virtual std::string get_valid_custom_dev_types_str(); }; @@ -827,6 +883,62 @@ smart_device * win_smart_interface::autodetect_smart_device(const char * name) return 0; } + +smart_device * winnt_smart_interface::get_custom_smart_device(const char * name, const char * type) +{ + // Areca? + int disknum = -1, n1 = -1, n2 = -1; + int encnum = 1; + HANDLE fh = INVALID_HANDLE_VALUE; + char devpath[32]; + + if (sscanf(type, "areca,%n%d/%d%n", &n1, &disknum, &encnum, &n2) >= 1 || n1 == 6) { + if (!(1 <= disknum && disknum <= 128)) { + set_err(EINVAL, "Option -d areca,N/E (N=%d) must have 1 <= N <= 128", disknum); + return 0; + } + if (!(1 <= encnum && encnum <= 8)) { + set_err(EINVAL, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum); + return 0; + } + + name = skipdev(name); +#define ARECA_MAX_CTLR_NUM 16 + n1 = -1; + int ctlrindex = 0; + if (sscanf(name, "arcmsr%d%n", &ctlrindex, &n1) >= 1 && n1 == (int)strlen(name)) { + /* + 1. scan from "\\\\.\\scsi[0]:" up to "\\\\.\\scsi[ARECA_MAX_CTLR_NUM]:" and + 2. map arcmsrX into "\\\\.\\scsiX" + */ + for (int idx = 0; idx < ARECA_MAX_CTLR_NUM; idx++) { + memset(devpath, 0, sizeof(devpath)); + sprintf(devpath, "\\\\.\\scsi%d:", idx); + if ( (fh = CreateFile( devpath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL )) != INVALID_HANDLE_VALUE ) { + if (win_areca_device::arcmsr_command_handler(fh, ARCMSR_IOCTL_RETURN_CODE_3F, NULL, 0) == 0) { + if (ctlrindex-- == 0) { + return new win_areca_device(this, devpath, fh, disknum, encnum); + } + } + CloseHandle(fh); + } + } + set_err(ENOENT, "No Areca controller found"); + } + else + set_err(EINVAL, "Option -d areca,N/E requires device name /dev/arcmsrX"); + } + + return 0; +} + +std::string winnt_smart_interface::get_valid_custom_dev_types_str() +{ + return "areca,N[/E]"; +} + + smart_device * winnt_smart_interface::autodetect_smart_device(const char * name) { smart_device * dev = win_smart_interface::autodetect_smart_device(name); @@ -1040,6 +1152,9 @@ std::string win_smart_interface::get_app_examples(const char * appname) " (Prints Attributes for physical drive 3 on 3ware 9000 RAID)\n" " smartctl -A /dev/tw_cli/c0/p1\n" " (Prints Attributes for 3ware controller 0, port 1 using tw_cli)\n" + " smartctl --all --device=areca,3/1 /dev/arcmsr0\n" + " (Prints all SMART info for 3rd ATA disk of the 1st enclosure\n" + " on 1st Areca RAID controller)\n" "\n" " ATA SMART access methods and ordering may be specified by modifiers\n" " following the device name: /dev/hdX:[saicm], where\n" @@ -2219,12 +2334,6 @@ static int get_identify_from_device_property(HANDLE hdevice, ata_identify_device ///////////////////////////////////////////////////////////////////////////// // USB ID detection using WMI -// Return true if STR starts with PREFIX. -static inline bool str_starts_with(const std::string & str, const char * prefix) -{ - return !strncmp(str.c_str(), prefix, strlen(prefix)); -} - // Get USB ID for a physical drive number static bool get_usb_id(int drive, unsigned short & vendor_id, unsigned short & product_id) { @@ -4175,6 +4284,632 @@ bool win_scsi_device::scsi_pass_through(struct scsi_cmnd_io * iop) return true; } +// Interface to SPT SCSI devices. See scsicmds.h and os_linux.c +static long scsi_pass_through_direct(HANDLE fd, struct scsi_cmnd_io * iop) +{ + int report = scsi_debugmode; // TODO + + if (report > 0) { + int k, j; + const unsigned char * ucp = iop->cmnd; + const char * np; + char buff[256]; + const int sz = (int)sizeof(buff); + + np = scsi_get_opcode_name(ucp[0]); + j = snprintf(buff, sz, " [%s: ", np ? np : ""); + for (k = 0; k < (int)iop->cmnd_len; ++k) + j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]); + if ((report > 1) && + (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) { + int trunc = (iop->dxfer_len > 256) ? 1 : 0; + + j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing " + "data, len=%d%s:\n", (int)iop->dxfer_len, + (trunc ? " [only first 256 bytes shown]" : "")); + dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); + } + else + j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n"); + pout("%s", buff); + } + + SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb; + if (iop->cmnd_len > (int)sizeof(sb.spt.Cdb)) { + return EINVAL; + } + + memset(&sb, 0, sizeof(sb)); + sb.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); + //sb.spt.PathId = 0; + sb.spt.TargetId = 127; + //sb.spt.Lun = 0; + sb.spt.CdbLength = iop->cmnd_len; + memcpy(sb.spt.Cdb, iop->cmnd, iop->cmnd_len); + sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf); + sb.spt.SenseInfoOffset = + offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf); + sb.spt.TimeOutValue = (iop->timeout ? iop->timeout : 60); + + bool direct = true; + switch (iop->dxfer_dir) { + case DXFER_NONE: + sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED; + break; + case DXFER_FROM_DEVICE: + sb.spt.DataIn = SCSI_IOCTL_DATA_IN; + sb.spt.DataTransferLength = iop->dxfer_len; + sb.spt.DataBuffer = iop->dxferp; + // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte + // transfers (needed for SMART STATUS check of JMicron USB bridges) + if (sb.spt.DataTransferLength == 1) + direct = false; + break; + case DXFER_TO_DEVICE: + sb.spt.DataIn = SCSI_IOCTL_DATA_OUT; + sb.spt.DataTransferLength = iop->dxfer_len; + sb.spt.DataBuffer = iop->dxferp; + break; + default: + return EINVAL; + } + + long err = 0; + if (direct) { + DWORD num_out; + if (!DeviceIoControl(fd, IOCTL_SCSI_PASS_THROUGH_DIRECT, + &sb, sizeof(sb), &sb, sizeof(sb), &num_out, 0)) + err = GetLastError(); + } + else + err = scsi_pass_through_indirect(fd, &sb); + + if (err) + { + return err; + } + + iop->scsi_status = sb.spt.ScsiStatus; + if (SCSI_STATUS_CHECK_CONDITION & iop->scsi_status) { + int slen = sb.ucSenseBuf[7] + 8; + + if (slen > (int)sizeof(sb.ucSenseBuf)) + slen = sizeof(sb.ucSenseBuf); + if (slen > (int)iop->max_sense_len) + slen = iop->max_sense_len; + memcpy(iop->sensep, sb.ucSenseBuf, slen); + iop->resp_sense_len = slen; + if (report) { + if (report > 1) { + pout(" >>> Sense buffer, len=%d:\n", slen); + dStrHex(iop->sensep, slen , 1); + } + if ((iop->sensep[0] & 0x7f) > 0x71) + pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n", + iop->scsi_status, iop->sensep[1] & 0xf, + iop->sensep[2], iop->sensep[3]); + else + pout(" status=%x: sense_key=%x asc=%x ascq=%x\n", + iop->scsi_status, iop->sensep[2] & 0xf, + iop->sensep[12], iop->sensep[13]); + } + } else + iop->resp_sense_len = 0; + + if ((iop->dxfer_len > 0) && (sb.spt.DataTransferLength > 0)) + iop->resid = iop->dxfer_len - sb.spt.DataTransferLength; + else + iop->resid = 0; + + if ((iop->dxfer_dir == DXFER_FROM_DEVICE) && (report > 1)) { + int trunc = (iop->dxfer_len > 256) ? 1 : 0; + pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len, + (trunc ? " [only first 256 bytes shown]" : "")); + dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); + } + + return 0; +} + + +#if 0 // For debugging areca code + +static void dumpdata(unsigned char *block, int len) +{ + int ln = (len / 16) + 1; // total line# + unsigned char c; + int pos = 0; + + printf(" Address = %p, Length = (0x%x)%d\n", block, len, len); + printf(" 0 1 2 3 4 5 6 7 8 9 A B C D E F ASCII \n"); + printf("=====================================================================\n"); + + for ( int l = 0; l < ln && len; l++ ) + { + // printf the line# and the HEX data + // if a line data length < 16 then append the space to the tail of line to reach 16 chars + printf("%02X | ", l); + for ( pos = 0; pos < 16 && len; pos++, len-- ) + { + c = block[l*16+pos]; + printf("%02X ", c); + } + + if ( pos < 16 ) + { + for ( int loop = pos; loop < 16; loop++ ) + { + printf(" "); + } + } + + // print ASCII char + for ( int loop = 0; loop < pos; loop++ ) + { + c = block[l*16+loop]; + if ( c >= 0x20 && c <= 0x7F ) + { + printf("%c", c); + } + else + { + printf("."); + } + } + printf("\n"); + } + printf("=====================================================================\n"); +} + +#endif + +// PURPOSE +// This is an interface routine meant to isolate the OS dependent +// parts of the code, and to provide a debugging interface. Each +// different port and OS needs to provide it's own interface. This +// is the Windows interface to the Areca "arcmsr" driver. It allows ATA +// commands to be passed through the SCSI driver. +// DETAILED DESCRIPTION OF ARGUMENTS +// fd: is the file descriptor provided by open() +// disknum is the disk number (0 to 127) in the RAID array +// command: defines the different operations. +// select: additional input data if needed (which log, which type of +// self-test). +// data: location to write output data, if needed (512 bytes). +// Note: not all commands use all arguments. +// RETURN VALUES +// -1 if the command failed +// 0 if the command succeeded, +// STATUS_CHECK routine: +// -1 if the command failed +// 0 if the command succeeded and disk SMART status is "OK" +// 1 if the command succeeded and disk SMART status is "FAILING" +int win_areca_device::arcmsr_command_handler(HANDLE fd, unsigned long arcmsr_cmd, unsigned char *data, int data_len) +{ + int ioctlreturn = 0; + sSRB_BUFFER sBuf; + struct scsi_cmnd_io io_hdr; + int dir = DXFER_TO_DEVICE; + + UINT8 cdb[10]; + UINT8 sense[32]; + + unsigned char *areca_return_packet; + int total = 0; + int expected = -1; + unsigned char return_buff[2048]; + unsigned char *ptr = &return_buff[0]; + memset(return_buff, 0, sizeof(return_buff)); + + memset((unsigned char *)&sBuf, 0, sizeof(sBuf)); + memset(&io_hdr, 0, sizeof(io_hdr)); + memset(cdb, 0, sizeof(cdb)); + memset(sense, 0, sizeof(sense)); + + + sBuf.srbioctl.HeaderLength = sizeof(sSRB_IO_CONTROL); + memcpy(sBuf.srbioctl.Signature, ARECA_SIG_STR, strlen(ARECA_SIG_STR)); + sBuf.srbioctl.Timeout = 10000; + sBuf.srbioctl.ControlCode = arcmsr_cmd; + + switch ( arcmsr_cmd ) + { + // command for writing data to driver + case ARCMSR_IOCTL_WRITE_WQBUFFER: + if ( data && data_len ) + { + sBuf.srbioctl.Length = data_len; + memcpy((unsigned char *)sBuf.ioctldatabuffer, (unsigned char *)data, data_len); + } + // commands for clearing related buffer of driver + case ARCMSR_IOCTL_CLEAR_RQBUFFER: + case ARCMSR_IOCTL_CLEAR_WQBUFFER: + cdb[0] = 0x3B; //SCSI_WRITE_BUF command; + break; + // command for reading data from driver + case ARCMSR_IOCTL_READ_RQBUFFER: + // command for identifying driver + case ARCMSR_IOCTL_RETURN_CODE_3F: + cdb[0] = 0x3C; //SCSI_READ_BUF command; + dir = DXFER_FROM_DEVICE; + break; + default: + // unknown arcmsr commands + return -1; + } + + cdb[1] = 0x01; + cdb[2] = 0xf0; + + io_hdr.dxfer_dir = dir; + io_hdr.dxfer_len = sizeof(sBuf); + io_hdr.dxferp = (unsigned char *)&sBuf; + io_hdr.cmnd = cdb; + io_hdr.cmnd_len = sizeof(cdb); + io_hdr.sensep = sense; + io_hdr.max_sense_len = sizeof(sense); + io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; + + while ( 1 ) + { + ioctlreturn = scsi_pass_through_direct(fd, &io_hdr); + if ( ioctlreturn || io_hdr.scsi_status ) + { + // errors found + break; + } + + if ( arcmsr_cmd != ARCMSR_IOCTL_READ_RQBUFFER ) + { + // if succeeded, just returns the length of outgoing data + return data_len; + } + + if ( sBuf.srbioctl.Length ) + { + //dumpdata(&sBuf.ioctldatabuffer[0], sBuf.srbioctl.Length); + memcpy(ptr, &sBuf.ioctldatabuffer[0], sBuf.srbioctl.Length); + ptr += sBuf.srbioctl.Length; + total += sBuf.srbioctl.Length; + // the returned bytes enough to compute payload length ? + if ( expected < 0 && total >= 5 ) + { + areca_return_packet = (unsigned char *)&return_buff[0]; + if ( areca_return_packet[0] == 0x5E && + areca_return_packet[1] == 0x01 && + areca_return_packet[2] == 0x61 ) + { + // valid header, let's compute the returned payload length, + // we expected the total length is + // payload + 3 bytes header + 2 bytes length + 1 byte checksum + expected = areca_return_packet[4] * 256 + areca_return_packet[3] + 6; + } + } + + if ( total >= 7 && total >= expected ) + { + //printf("total bytes received = %d, expected length = %d\n", total, expected); + + // ------ Okay! we received enough -------- + break; + } + } + } + + // Deal with the different error cases + if ( arcmsr_cmd == ARCMSR_IOCTL_RETURN_CODE_3F ) + { + // Silence the ARCMSR_IOCTL_RETURN_CODE_3F's error, no pout(...) + return -4; + } + + if ( ioctlreturn ) + { + pout("do_scsi_cmnd_io with write buffer failed code = %x\n", ioctlreturn); + return -2; + } + + if ( io_hdr.scsi_status ) + { + pout("io_hdr.scsi_status with write buffer failed code = %x\n", io_hdr.scsi_status); + return -3; + } + + if ( data ) + { + memcpy(data, return_buff, total); + } + + return total; +} + + +win_areca_device::win_areca_device(smart_interface * intf, const char * dev_name, HANDLE fh, int disknum, int encnum) +: smart_device(intf, dev_name, "areca", "areca"), + m_disknum(disknum), + m_encnum(encnum) +{ + set_fh(fh); + set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum); +} + +bool win_areca_device::open() +{ + HANDLE hFh; + + if( is_open() ) + { + return true; + } + + hFh = CreateFile( get_dev_name(), + GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL ); + if(hFh == INVALID_HANDLE_VALUE) + { + return false; + } + + set_fh(hFh); + return true; +} + +// Areca RAID Controller +bool win_areca_device::arcmsr_ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) +{ + // ATA input registers + typedef struct _ATA_INPUT_REGISTERS + { + unsigned char features; + unsigned char sector_count; + unsigned char sector_number; + unsigned char cylinder_low; + unsigned char cylinder_high; + unsigned char device_head; + unsigned char command; + unsigned char reserved[8]; + unsigned char data[512]; // [in/out] buffer for outgoing/incoming data + } sATA_INPUT_REGISTERS; + + // ATA output registers + // Note: The output registers is re-sorted for areca internal use only + typedef struct _ATA_OUTPUT_REGISTERS + { + unsigned char error; + unsigned char status; + unsigned char sector_count; + unsigned char sector_number; + unsigned char cylinder_low; + unsigned char cylinder_high; + } sATA_OUTPUT_REGISTERS; + + // Areca packet format for outgoing: + // B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61 + // B[3~4] : 2 bytes command length + variant data length, little endian + // B[5] : 1 bytes areca defined command code, ATA passthrough command code is 0x1c + // B[6~last-1] : variant bytes payload data + // B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1]) + // + // + // header 3 bytes length 2 bytes cmd 1 byte payload data x bytes cs 1 byte + // +--------------------------------------------------------------------------------+ + // + 0x5E 0x01 0x61 | 0x00 0x00 | 0x1c | .................... | 0x00 | + // +--------------------------------------------------------------------------------+ + // + + //Areca packet format for incoming: + // B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61 + // B[3~4] : 2 bytes payload length, little endian + // B[5~last-1] : variant bytes returned payload data + // B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1]) + // + // + // header 3 bytes length 2 bytes payload data x bytes cs 1 byte + // +-------------------------------------------------------------------+ + // + 0x5E 0x01 0x61 | 0x00 0x00 | .................... | 0x00 | + // +-------------------------------------------------------------------+ + unsigned char areca_packet[640]; + int areca_packet_len = sizeof(areca_packet); + unsigned char cs = 0; + + sATA_INPUT_REGISTERS *ata_cmd; + + // For debugging +#if 0 + memset(sInq, 0, sizeof(sInq)); + scsiStdInquiry(fd, (unsigned char *)sInq, (int)sizeof(sInq)); + dumpdata((unsigned char *)sInq, sizeof(sInq)); +#endif + memset(areca_packet, 0, areca_packet_len); + + // ----- BEGIN TO SETUP HEADERS ------- + areca_packet[0] = 0x5E; + areca_packet[1] = 0x01; + areca_packet[2] = 0x61; + areca_packet[3] = (unsigned char)((areca_packet_len - 6) & 0xff); + areca_packet[4] = (unsigned char)(((areca_packet_len - 6) >> 8) & 0xff); + areca_packet[5] = 0x1c; // areca defined code for ATA passthrough command + + // ----- BEGIN TO SETUP PAYLOAD DATA ----- + memcpy(&areca_packet[7], "SmrT", 4); // areca defined password + ata_cmd = (sATA_INPUT_REGISTERS *)&areca_packet[12]; + + // Set registers + { + const ata_in_regs & r = in.in_regs; + ata_cmd->features = r.features; + ata_cmd->sector_count = r.sector_count; + ata_cmd->sector_number = r.lba_low; + ata_cmd->cylinder_low = r.lba_mid; + ata_cmd->cylinder_high = r.lba_high; + ata_cmd->device_head = r.device; + ata_cmd->command = r.command; + } + bool readdata = false; + if (in.direction == ata_cmd_in::data_in) { + readdata = true; + // the command will read data + areca_packet[6] = 0x13; + } + else if ( in.direction == ata_cmd_in::no_data ) + { + // the commands will return no data + areca_packet[6] = 0x15; + } + else if (in.direction == ata_cmd_in::data_out) + { + // the commands will write data + memcpy(ata_cmd->data, in.buffer, in.size); + areca_packet[6] = 0x14; + } + else { + // COMMAND NOT SUPPORTED VIA ARECA IOCTL INTERFACE + return set_err(ENOSYS); + } + + areca_packet[11] = m_disknum - 1; // disk# + areca_packet[19] = m_encnum - 1; // enc# + + // ----- BEGIN TO SETUP CHECKSUM ----- + for ( int loop = 3; loop < areca_packet_len - 1; loop++ ) + { + cs += areca_packet[loop]; + } + areca_packet[areca_packet_len-1] = cs; + + // ----- BEGIN TO SEND TO ARECA DRIVER ------ + int expected = 0; + unsigned char return_buff[2048]; + memset(return_buff, 0, sizeof(return_buff)); + + expected = arcmsr_command_handler(get_fh(), ARCMSR_IOCTL_CLEAR_RQBUFFER, NULL, 0); + if (expected==-3) { + return set_err(EIO); + } + + expected = arcmsr_command_handler(get_fh(), ARCMSR_IOCTL_CLEAR_WQBUFFER, NULL, 0); + expected = arcmsr_command_handler(get_fh(), ARCMSR_IOCTL_WRITE_WQBUFFER, areca_packet, areca_packet_len); + if ( expected > 0 ) + { + expected = arcmsr_command_handler(get_fh(), ARCMSR_IOCTL_READ_RQBUFFER, return_buff, sizeof(return_buff)); + } + if ( expected < 0 ) + { + return set_err(EIO); + } + + // ----- VERIFY THE CHECKSUM ----- + cs = 0; + for ( int loop = 3; loop < expected - 1; loop++ ) + { + cs += return_buff[loop]; + } + + if ( return_buff[expected - 1] != cs ) + { + return set_err(EIO); + } + + sATA_OUTPUT_REGISTERS *ata_out = (sATA_OUTPUT_REGISTERS *)&return_buff[5] ; + if ( ata_out->status ) + { + if ( in.in_regs.command == ATA_IDENTIFY_DEVICE + && !nonempty((unsigned char *)in.buffer, in.size)) + { + return set_err(ENODEV, "No drive on port %d", m_disknum); + } + } + + // returns with data + if (readdata) + { + memcpy(in.buffer, &return_buff[7], in.size); + } + + // Return register values + { + ata_out_regs & r = out.out_regs; + r.error = ata_out->error; + r.sector_count = ata_out->sector_count; + r.lba_low = ata_out->sector_number; + r.lba_mid = ata_out->cylinder_low; + r.lba_high = ata_out->cylinder_high; + r.status = ata_out->status; + } + return true; +} + + +bool win_areca_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) +{ +#define SYNCOBJNAME "Global\\SynIoctlMutex" + int ctlrnum = -1; + char mutexstr[64]; + SECURITY_ATTRIBUTES sa; + PSECURITY_DESCRIPTOR pSD; + HANDLE hmutex; + + if (!ata_cmd_is_ok(in, + true, // data_out_support + false, // TODO: multi_sector_support + true) // ata_48bit_support + ) + return false; + + // Support 48-bit commands with zero high bytes + if (in.in_regs.is_real_48bit_cmd()) + return set_err(ENOSYS, "48-bit ATA commands not fully supported by Areca"); + + if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum) < 1) + return set_err(EINVAL, "unable to parse device name"); + + memset(mutexstr, 0, sizeof(mutexstr)); + sprintf(mutexstr, "%s%d",SYNCOBJNAME, ctlrnum); + pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); + if ( !InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION) ) + { + LocalFree((HLOCAL)pSD); + return set_err(EIO, "InitializeSecurityDescriptor failed"); + } + + if ( !SetSecurityDescriptorDacl(pSD, TRUE, (PACL)NULL, FALSE) ) + { + LocalFree((HLOCAL)pSD); + return set_err(EIO, "SetSecurityDescriptor failed"); + } + + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = pSD; + sa.bInheritHandle = TRUE; + hmutex = CreateMutex(&sa, FALSE, mutexstr); + if ( hmutex == NULL ) + { + LocalFree((HLOCAL)pSD); + return set_err(EIO, "CreateMutex failed"); + } + + // atomic access to driver + WaitForSingleObject(hmutex, INFINITE); + bool ok = arcmsr_ata_pass_through(in,out); + ReleaseMutex(hmutex); + + if(hmutex) + { + CloseHandle(hmutex); + } + + if ( (HLOCAL)pSD ) + { + LocalFree((HLOCAL)pSD); + } + + return ok; +} + ////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/os_win32/installer.nsi b/os_win32/installer.nsi index 101c04f..d918ac6 100644 --- a/os_win32/installer.nsi +++ b/os_win32/installer.nsi @@ -3,7 +3,7 @@ ; ; Home page of code is: http://smartmontools.sourceforge.net ; -; Copyright (C) 2006-11 Christian Franke +; Copyright (C) 2006-12 Christian Franke ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by @@ -13,13 +13,14 @@ ; You should have received a copy of the GNU General Public License ; (for example COPYING); If not, see . ; -; $Id: installer.nsi 3457 2011-10-20 16:36:47Z chrfranke $ +; $Id: installer.nsi 3545 2012-05-25 21:19:03Z chrfranke $ ; ;-------------------------------------------------------------------- ; Command line arguments: -; makensis -DINPDIR= -DOUTFILE= -DVERSTR= installer.nsi +; makensis -DINPDIR= -DINPDIR64= \ +; -DOUTFILE= -DVERSTR= installer.nsi !ifndef INPDIR !define INPDIR "." @@ -40,11 +41,17 @@ SetCompressor /solid lzma XPStyle on InstallColors /windows -InstallDir "$PROGRAMFILES\smartmontools" -InstallDirRegKey HKLM "Software\smartmontools" "Install_Dir" +; Set in .onInit +;InstallDir "$PROGRAMFILES\smartmontools" +;InstallDirRegKey HKLM "Software\smartmontools" "Install_Dir" Var EDITOR -Var UBCDDIR + +!ifdef INPDIR64 + Var X64 + Var INSTDIR32 + Var INSTDIR64 +!endif LicenseData "${INPDIR}\doc\COPYING.txt" @@ -61,12 +68,11 @@ RequestExecutionLevel admin Page license Page components -Page directory SkipProgPath "" "" -PageEx directory - PageCallbacks SkipUBCDPath "" "" - DirText "Setup will install the UBCD4Win plugin in the following folder." - DirVar $UBCDDIR -PageExEnd +!ifdef INPDIR64 + Page directory CheckX64 +!else + Page directory +!endif Page instfiles UninstPage uninstConfirm @@ -75,20 +81,41 @@ UninstPage instfiles InstType "Full" InstType "Extract files only" InstType "Drive menu" -InstType "UBCD4Win plugin" ;-------------------------------------------------------------------- ; Sections +!ifdef INPDIR64 + Section "64-bit version (EXPERIMENTAL)" X64_SECTION + ; Handled in Function CheckX64 + SectionEnd +!endif + SectionGroup "!Program files" + !macro FileExe path option + !ifdef INPDIR64 + ; Use dummy SetOutPath to control archive location of executables + StrCmp $X64 "" +5 + Goto +2 + SetOutPath "$INSTDIR\bin64" + File ${option} '${INPDIR64}\${path}' + GoTo +4 + Goto +2 + SetOutPath "$INSTDIR\bin" + File ${option} '${INPDIR}\${path}' + !else + File ${option} '${INPDIR}\${path}' + !endif + !macroend + Section "smartctl" SMARTCTL_SECTION SectionIn 1 2 SetOutPath "$INSTDIR\bin" - File "${INPDIR}\bin\smartctl.exe" + !insertmacro FileExe "bin\smartctl.exe" "" SectionEnd @@ -105,14 +132,15 @@ SectionGroup "!Program files" StrCmp $0 "" nosrv ExecWait "net stop smartd" $1 nosrv: - File "${INPDIR}\bin\smartd.exe" + !insertmacro FileExe "bin\smartd.exe" "" IfFileExists "$INSTDIR\bin\smartd.conf" 0 +2 MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2 "Replace existing configuration file$\n$INSTDIR\bin\smartd.conf ?" IDYES 0 IDNO +2 File "${INPDIR}\doc\smartd.conf" - IfFileExists "$WINDIR\system32\cmd.exe" 0 +2 - File /nonfatal "${INPDIR}\bin\syslogevt.exe" + IfFileExists "$WINDIR\system32\cmd.exe" 0 nosysl + !insertmacro FileExe "bin\syslogevt.exe" /nonfatal + nosysl: ; Restart service ? StrCmp $1 "0" 0 +3 @@ -126,7 +154,7 @@ SectionGroup "!Program files" SectionIn 1 2 SetOutPath "$INSTDIR\bin" - File "${INPDIR}\bin\smartctl-nc.exe" + !insertmacro FileExe "bin\smartctl-nc.exe" "" SectionEnd @@ -155,7 +183,14 @@ Section "!Documentation" DOC_SECTION File "${INPDIR}\doc\README.txt" File "${INPDIR}\doc\TODO.txt" File "${INPDIR}\doc\WARNINGS.txt" - File "${INPDIR}\doc\checksums.txt" +!ifdef INPDIR64 + StrCmp $X64 "" +3 + File "${INPDIR64}\doc\checksums64.txt" + GoTo +2 + File "${INPDIR}\doc\checksums32.txt" +!else + File "${INPDIR}\doc\checksums??.txt" +!endif File "${INPDIR}\doc\smartctl.8.html" File "${INPDIR}\doc\smartctl.8.txt" File "${INPDIR}\doc\smartd.8.html" @@ -169,7 +204,7 @@ SectionEnd Section "Uninstaller" UNINST_SECTION SectionIn 1 - AddSize 35 + AddSize 40 CreateDirectory "$INSTDIR" @@ -209,10 +244,11 @@ Section "Start Menu Shortcuts" MENU_SECTION ; runcmdu IfFileExists "$INSTDIR\bin\smartctl.exe" 0 +2 - IfFileExists "$INSTDIR\bin\smartd.exe" 0 +4 + IfFileExists "$INSTDIR\bin\smartd.exe" 0 noruncmd SetOutPath "$INSTDIR\bin" - File "${INPDIR}\bin\runcmdu.exe" + !insertmacro FileExe "bin\runcmdu.exe" "" File "${INPDIR}\bin\runcmdu.exe.manifest" + noruncmd: ; smartctl IfFileExists "$INSTDIR\bin\smartctl.exe" 0 noctl @@ -352,49 +388,6 @@ SectionGroup "Add smartctl to drive menu" SectionGroupEnd -Section "UBCD4Win Plugin" UBCD_SECTION - - SectionIn 4 - - SetOutPath "$UBCDDIR" - DetailPrint "Create file: smartmontools.inf" - FileOpen $0 "$UBCDDIR\smartmontools.inf" "w" - FileWrite $0 '; smartmontools.inf$\r$\n; PE Builder v3 plug-in INF file$\r$\n' - FileWrite $0 '; Created by smartmontools installer$\r$\n' - FileWrite $0 '; http://smartmontools.sourceforge.net/$\r$\n$\r$\n' - FileWrite $0 '[Version]$\r$\nSignature= "$$Windows NT$$"$\r$\n$\r$\n' - FileWrite $0 '[PEBuilder]$\r$\nName="Disk -Diagnostic: smartmontools"$\r$\n' - FileWrite $0 'Enable=1$\r$\nHelp="files\smartctl.8.html"$\r$\n$\r$\n' - FileWrite $0 '[WinntDirectories]$\r$\na=Programs\smartmontools,2$\r$\n$\r$\n' - FileWrite $0 '[SourceDisksFolders]$\r$\nfiles=a,,1$\r$\n$\r$\n' - FileWrite $0 '[Append]$\r$\nnu2menu.xml, smartmontools_nu2menu.xml$\r$\n' - FileClose $0 - - DetailPrint "Create file: smartmontools_nu2menu.xml" - FileOpen $0 "$UBCDDIR\smartmontools_nu2menu.xml" "w" - FileWrite $0 '$\r$\n$\r$\n' - FileWrite $0 '$\t$\r$\n$\t$\t' - FileWrite $0 'Disk Tools$\r$\n$\t$\r$\n$\t$\r$\n' - FileWrite $0 '$\t$\tDiagnostic$\r$\n$\t' - FileWrite $0 '$\r$\n$\t$\r$\n$\t$\t' - FileWrite $0 'smartctl$\r$\n$\t$\r$\n$\r$\n' - FileClose $0 - - SetOutPath "$UBCDDIR\files" - File "${INPDIR}\bin\smartctl.exe" - File "${INPDIR}\bin\smartd.exe" - File "${INPDIR}\doc\smartctl.8.html" - File "${INPDIR}\doc\smartctl.8.txt" - File "${INPDIR}\doc\smartd.8.html" - File "${INPDIR}\doc\smartd.8.txt" - File "${INPDIR}\doc\smartd.conf" - -SectionEnd - - ;-------------------------------------------------------------------- Section "Uninstall" @@ -457,7 +450,7 @@ Section "Uninstall" Delete "$INSTDIR\doc\README.txt" Delete "$INSTDIR\doc\TODO.txt" Delete "$INSTDIR\doc\WARNINGS.txt" - Delete "$INSTDIR\doc\checksums.txt" + Delete "$INSTDIR\doc\checksums*.txt" Delete "$INSTDIR\doc\smartctl.8.html" Delete "$INSTDIR\doc\smartctl.8.txt" Delete "$INSTDIR\doc\smartd.8.html" @@ -506,19 +499,37 @@ SectionEnd ;-------------------------------------------------------------------- ; Functions +!macro AdjustSectionSize section + SectionGetSize ${section} $0 + IntOp $0 $0 / 2 + SectionSetSize ${section} $0 +!macroend + Function .onInit + ; Set default install directories + StrCmp $INSTDIR "" 0 endinst ; /D=PATH option specified ? + ReadRegStr $INSTDIR HKLM "Software\smartmontools" "Install_Dir" + StrCmp $INSTDIR "" 0 endinst ; Already installed ? + StrCpy $INSTDIR "$PROGRAMFILES\smartmontools" +!ifdef INPDIR64 + StrCpy $INSTDIR32 $INSTDIR + StrCpy $INSTDIR64 "$PROGRAMFILES64\smartmontools" +!endif + endinst: + +!ifdef INPDIR64 + ; Sizes of binary sections include 32-bit and 64-bit executables + !insertmacro AdjustSectionSize ${SMARTCTL_SECTION} + !insertmacro AdjustSectionSize ${SMARTD_SECTION} + !insertmacro AdjustSectionSize ${SMARTCTL_NC_SECTION} +!endif + ; Use Notepad++ if installed StrCpy $EDITOR "$PROGRAMFILES\Notepad++\notepad++.exe" IfFileExists "$EDITOR" +2 0 StrCpy $EDITOR "notepad.exe" - ; Get UBCD4Win install location - ReadRegStr $0 HKLM "Software\UBCD4Win" "InstallPath" - StrCmp $0 "" 0 +2 - StrCpy $0 "C:\UBCD4Win" - StrCpy $UBCDDIR "$0\plugin\Disk\Diagnostic\smartmontools" - ; Hide "Add install dir to PATH" on 9x/ME IfFileExists "$WINDIR\system32\cmd.exe" +2 0 SectionSetText ${PATH_SECTION} "" @@ -526,6 +537,27 @@ Function .onInit Call ParseCmdLine FunctionEnd +; Check x64 section and update INSTDIR accordingly + +!ifdef INPDIR64 +Function CheckX64 + SectionGetFlags ${X64_SECTION} $0 + IntOp $0 $0 & ${SF_SELECTED} + IntCmp $0 ${SF_SELECTED} x64 + StrCpy $X64 "" + StrCmp $INSTDIR32 "" +3 + StrCpy $INSTDIR $INSTDIR32 + StrCpy $INSTDIR32 "" + Goto done + x64: + StrCpy $X64 "t" + StrCmp $INSTDIR64 "" +3 + StrCpy $INSTDIR $INSTDIR64 + StrCpy $INSTDIR64 "" + done: +FunctionEnd +!endif + ; Command line parsing !macro CheckCmdLineOption name section StrCpy $allopts "$allopts,${name}" @@ -554,6 +586,12 @@ Function ParseCmdLine Var /global nomatch StrCpy $nomatch "t" ; turn sections on or off +!ifdef INPDIR64 + !insertmacro CheckCmdLineOption "x64" ${X64_SECTION} + Call CheckX64 + StrCmp $opts "x64" 0 +2 + Return ; leave sections unchanged if only "x64" is specified +!endif !insertmacro CheckCmdLineOption "smartctl" ${SMARTCTL_SECTION} !insertmacro CheckCmdLineOption "smartd" ${SMARTD_SECTION} !insertmacro CheckCmdLineOption "smartctlnc" ${SMARTCTL_NC_SECTION} @@ -569,7 +607,6 @@ Function ParseCmdLine !insertmacro CheckCmdLineOption "drive3" ${DRIVE_3_SECTION} !insertmacro CheckCmdLineOption "drive4" ${DRIVE_4_SECTION} !insertmacro CheckCmdLineOption "drive5" ${DRIVE_5_SECTION} - !insertmacro CheckCmdLineOption "ubcd" ${UBCD_SECTION} StrCmp $opts "-" done StrCmp $nomatch "" done StrCpy $0 "$allopts,-" "" 1 @@ -578,45 +615,12 @@ Function ParseCmdLine done: FunctionEnd -; Directory page callbacks - -!macro CheckSection section - SectionGetFlags ${section} $0 - IntOp $0 $0 & 1 - IntCmp $0 1 done -!macroend - -Function SkipProgPath - !insertmacro CheckSection ${SMARTCTL_SECTION} - !insertmacro CheckSection ${SMARTCTL_NC_SECTION} - !insertmacro CheckSection ${SMARTD_SECTION} - !insertmacro CheckSection ${DRIVEDB_SECTION} - !insertmacro CheckSection ${DOC_SECTION} - !insertmacro CheckSection ${MENU_SECTION} - !insertmacro CheckSection ${PATH_SECTION} - !insertmacro CheckSection ${DRIVE_0_SECTION} - !insertmacro CheckSection ${DRIVE_1_SECTION} - !insertmacro CheckSection ${DRIVE_2_SECTION} - !insertmacro CheckSection ${DRIVE_3_SECTION} - !insertmacro CheckSection ${DRIVE_4_SECTION} - !insertmacro CheckSection ${DRIVE_5_SECTION} - Abort -done: -FunctionEnd - -Function SkipUBCDPath - !insertmacro CheckSection ${UBCD_SECTION} - Abort -done: -FunctionEnd - - ; Install runcmda.exe if missing Function CheckRunCmdA IfFileExists "$INSTDIR\bin\runcmda.exe" done 0 SetOutPath "$INSTDIR\bin" - File "${INPDIR}\bin\runcmda.exe" + !insertmacro FileExe "bin\runcmda.exe" "" File "${INPDIR}\bin\runcmda.exe.manifest" done: FunctionEnd @@ -789,6 +793,10 @@ FunctionEnd !endif Function ShellLinkSetRunAs + ; Set archive location of $PLUGINSDIR + Goto +2 + SetOutPath "$INSTDIR" + System::Store S ; push $0-$9, $R0-$R9 pop $9 ; $0 = CoCreateInstance(CLSID_ShellLink, 0, CLSCTX_INPROC_SERVER, IID_IShellLink, &$1) diff --git a/smartctl.8.in b/smartctl.8.in index 5034ff6..42ea719 100644 --- a/smartctl.8.in +++ b/smartctl.8.in @@ -1,7 +1,7 @@ .ig Copyright (C) 2002-10 Bruce Allen - $Id: smartctl.8.in 3530 2012-03-27 19:54:06Z chrfranke $ + $Id: smartctl.8.in 3561 2012-06-05 19:49:31Z chrfranke $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free @@ -85,6 +85,9 @@ than the SCSI device used for reading and writing data)! Use the forms \fB/dev/disk[0\-9]\fP or equivalently \fBdisk[0\-9]\fP or equivalently \fB/dev/rdisk[0\-9]\fP. Long forms are also available: please use \'\-h\' to see some examples. Note that there is currently no Darwin SCSI support. + +Use the OS X SAT SMART Driver to access SMART data on SAT capable USB and +Firewire devices (see INSTALL file). .\" %ENDIF OS Darwin .\" %IF OS FreeBSD .IP \fBFREEBSD\fP: 9 @@ -138,9 +141,13 @@ in the driver. Use \fB"/dev/tw_cli/stdin"\fP or \fB"/dev/tw_cli/clip"\fP to parse CLI or 3DM output from standard input or clipboard. The option \'\-d 3ware,N\' is not necessary on Windows. -[NEW EXPERIMENTAL SMARTCTL FEATURE] For disks behind Intel Matrix RAID -driver use \fB"/dev/csmi[0\-9],N"\fP where N specifies the port behind -the logical scsi controller "\\\\.\\Scsi[0\-9]:". +For disks behind an Intel ICHxR controller with RST driver use +\fB"/dev/csmi[0\-9],N"\fP where N specifies the port behind the logical +scsi controller "\\\\.\\Scsi[0\-9]:". + +[NEW EXPERIMENTAL SMARTCTL FEATURE] For SATA disks behind an Areca SATA +or SAS controller use \fB"/dev/arcmsr[0\-9]"\fP, see \'\-d areca,N[/E]\' below. + The prefix \fB"/dev/"\fP is optional. .\" %ENDIF OS Windows Cygwin .\" %IF OS Cygwin @@ -301,7 +308,8 @@ SAT defines two ATA PASS THROUGH SCSI commands, one 12 bytes long and the other 16 bytes long. The default is the 16 byte variant which can be overridden with either \'\-d sat,12\' or \'\-d sat,16\'. -If \'-d sat,auto\' is specified, device type SAT (for ATA/SATA disks) is +[NEW EXPERIMENTAL SMARTCTL FEATURE] If \'-d sat,auto\' is specified, +device type SAT (for ATA/SATA disks) is only used if the SCSI INQUIRY data reports a SATL (VENDOR: "ATA "). Otherwise device type SCSI (for SCSI/SAS disks) is used. @@ -433,12 +441,12 @@ The necessary WRITE LOG commands can not be passed through the SCSI interface. .\" %ENDIF OS FreeBSD Linux -.\" %IF OS Linux FreeBSD +.\" %IF OS FreeBSD Linux Windows Cygwin .I areca,N -\- [Linux and FreeBSD only] the device consists of one or more SATA disks connected to an -Areca SATA RAID controller. The positive integer N (in the range from 1 to -24 inclusive) denotes which disk on the controller is monitored. -.\" %ENDIF OS Linux FreeBSD +\- [FreeBSD, Linux, Windows and Cygwin only] the device consists of one or more SATA disks +connected to an Areca SATA RAID controller. The positive integer N (in the range +from 1 to 24 inclusive) denotes which disk on the controller is monitored. +.\" %ENDIF OS FreeBSD Linux Windows Cygwin .\" %IF OS Linux On Linux use syntax such as: .nf @@ -457,11 +465,22 @@ On FreeBSD use syntax such as: \fBsmartctl \-a \-d areca,3 /dev/arcmsr2\fP .fi .\" %ENDIF OS FreeBSD +.\" %IF OS Windows Cygwin +[NEW EXPERIMENTAL SMARTCTL FEATURE] On Windows and Cygwin use syntax such as: +.nf +\fBsmartctl \-a \-d areca,2 /dev/arcmsr0\fP +.fi +.nf +\fBsmartctl \-a \-d areca,3 /dev/arcmsr1\fP +.fi +.\" %ENDIF OS Windows Cygwin +.\" %IF OS FreeBSD Linux Windows Cygwin The first line above addresses the second disk on the first Areca RAID controller. The second line addresses the third disk on the second Areca RAID controller. +.\" %ENDIF OS FreeBSD Linux Windows Cygwin .\" %IF OS Linux -To help identify the correct device on Linus, use the command: +To help identify the correct device on Linux, use the command: .nf \fBcat /proc/scsi/sg/device_hdr /proc/scsi/sg/devices\fP .fi @@ -471,13 +490,21 @@ smartmontools are the ones with the type field equal to 3. If the incorrect device is addressed, please read the warning/error messages carefully. They should provide hints about what devices to use. .\" %ENDIF OS Linux +.\" %IF OS FreeBSD Linux Windows Cygwin -.\" %IF OS Linux FreeBSD Important: the Areca controller must have firmware version 1.46 or later. Lower-numbered firmware versions will give (harmless) SCSI error messages and no SMART information. -.\" %ENDIF OS Linux FreeBSD +.I areca,N/E +\- [FreeBSD, Linux, Windows and Cygwin only] [NEW EXPERIMENTAL SMARTCTL FEATURE] the +device consists of one or more SATA disks connected to an Areca SAS RAID controller. +The integer N (range 1 to 128) denotes the channel (slot) and E (range +1 to 8) denotes the enclosure. +Important: This requires upcoming Areca SAS controller firmware version 1.51 or a +recent beta version. + +.\" %ENDIF OS FreeBSD Linux Windows Cygwin .\" %IF OS FreeBSD Linux .I cciss,N \- [FreeBSD and Linux only] the device consists of one or more SCSI/SAS disks @@ -1064,9 +1091,9 @@ This number can be changed by the optional parameter NUM. If ',error' is appended and the Extended Comprehensive SMART error log is not supported, the Summary SMART self-test log is printed. -Please note that some recent (e.g. Samsung) drives report errors only -in the Extended Comprehensive SMART error log. The Summary SMART error -log can be read but is always empty. +Please note that recent drives may report errors only in the Extended +Comprehensive SMART error log. The Summary SMART error log may be reported +as supported but is always empty then. .I selftest \- [ATA] prints the SMART self\-test log. The disk maintains a self\-test @@ -1198,7 +1225,8 @@ and descriptions of the ATA Device Statistics log pages entries from all supported pages are printed. If PAGE 0 is specified, the list of supported pages is printed. Device Statistics was introduced in ATA\-8 ACS and is only supported by some recent devices -(e.g. Intel 320 and 710 Series SSDs). +(e.g. Hitachi 7K3000, Intel 320, 330 and 710 Series SSDs, Crucial/Micron +m4 SSDs). .I sataphy[,reset] \- [SATA only] prints values and descriptions of the SATA Phy Event @@ -1824,7 +1852,7 @@ T13/1699-D Revision 6a (ATA8-ACS). Note that the subcommands \fBWARNING: Only run subcommands documented by the vendor of the device.\fP -Example for Intel (X18\-M/X25\-M G2 and 320 Series) SSDs only: +Example for Intel (X18/X25\-M G2, 320, 520 and 710 Series) SSDs only: The subcommand 0x40 (\'\-t vendor,0x40\') clears the timed workload related SMART attributes (226, 227, 228). Note that the raw values of these attributes are held at 65535 (0xffff) until the workload timer @@ -2164,4 +2192,4 @@ Links to these and other documents may be found on the Links page of the .SH SVN ID OF THIS PAGE: -$Id: smartctl.8.in 3530 2012-03-27 19:54:06Z chrfranke $ +$Id: smartctl.8.in 3561 2012-06-05 19:49:31Z chrfranke $ diff --git a/smartd.8.in b/smartd.8.in index d3f7cc6..d234974 100644 --- a/smartd.8.in +++ b/smartd.8.in @@ -1,7 +1,7 @@ .ig Copyright (C) 2002-10 Bruce Allen -$Id: smartd.8.in 3529 2012-03-25 17:26:10Z chrfranke $ +$Id: smartd.8.in 3561 2012-06-05 19:49:31Z chrfranke $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -116,7 +116,7 @@ Authoritative list of disk devices is obtained from sysctl .\" %ENDIF OS NetBSD OpenBSD .\" %IF OS Solaris .IP \fBSOLARIS:\fP 9 -Examine all entries \fB"/dev/rdsk/c?t?d?s?"\fP for IDE/ATA and SCSI disk +Examine all entries \fB"/dev/rdsk/*s0"\fP for IDE/ATA and SCSI disk devices, and entries \fB"/dev/rmt/*"\fP for SCSI tape devices. .\" %ENDIF OS Solaris .\" %IF OS Darwin @@ -140,9 +140,9 @@ If a 3ware 9000 controller is installed, examine all entries \fB"/dev/sdX"\fP) and all physical disks (\'ports\' \fB",N"\fP) detected behind this controller. Same for a second controller if present. -[NEW EXPERIMENTAL SMARTD FEATURE] If directive \'\-d csmi\' is specified, -examine all entries \fB"/dev/csmi[0\-9],N"\fP for drives behind Intel -Matrix RAID driver. +If directive \'\-d csmi\' or no \'\-d\' directive is specified, +examine all entries \fB"/dev/csmi[0\-9],N"\fP for drives behind an Intel +ICHxR controller with RST driver. .\" %ENDIF OS Windows Cygwin .\" %IF OS Cygwin .IP \fBCYGWIN\fP: 9 @@ -223,7 +223,7 @@ file. Please use CONTROL-\e to exit .\" %IF OS Windows (Windows: CONTROL\-Break). -Windows only: The "debug" mode can be toggled by the command +[Windows only] The "debug" mode can be toggled by the command \fBsmartd sigusr2\fP. A new console for debug output is opened when debug mode is enabled. .\" %ENDIF OS Windows @@ -456,7 +456,7 @@ an important change (which usually results in a SYSLOG output) occurred. .\" %IF OS Windows .TP .B \-\-service -Windows only: Enables \fBsmartd\fP to run as a Windows service. +[Windows only] Enables \fBsmartd\fP to run as a Windows service. The option must be specified in the service command line as the first argument. It should not be used from console. See NOTES below for details. @@ -685,7 +685,7 @@ A compile time constant of\fB smartd\fP was too small. This can be caused by an excessive number of disks, or by lines in \fB /usr/local/etc/smartd.conf\fP that are too long. Please report this problem to \fB smartmontools-support@lists.sourceforge.net\fP. .TP -.B 10 +.B 10: An inconsistency was found in \fBsmartd\fP\'s internal data structures. This should never happen. It must be due to either a coding or compiler bug. \fIPlease\fP report such failures to @@ -788,4 +788,4 @@ Links to these and other documents may be found on the Links page of the .SH SVN ID OF THIS PAGE: -$Id: smartd.8.in 3529 2012-03-25 17:26:10Z chrfranke $ +$Id: smartd.8.in 3561 2012-06-05 19:49:31Z chrfranke $ diff --git a/smartd.conf.5.in b/smartd.conf.5.in index daccfc7..06425ee 100644 --- a/smartd.conf.5.in +++ b/smartd.conf.5.in @@ -1,7 +1,7 @@ .ig Copyright (C) 2002-10 Bruce Allen -$Id: smartd.conf.5.in 3519 2012-03-06 20:01:44Z chrfranke $ +$Id: smartd.conf.5.in 3561 2012-06-05 19:49:31Z chrfranke $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free @@ -53,7 +53,7 @@ running. In the absence of a configuration file \fBsmartd\fP will try to open all available devices. .\" %IF OS Linux -Ubder linux will try to open the 20 ATA devices +Under linux \fBsmartd\fP will try to open the 20 ATA devices .B /dev/hd[a-t] and the 26 SCSI devices .B /dev/sd[a-z]. @@ -386,7 +386,8 @@ SAT defines two ATA PASS THROUGH SCSI commands, one 12 bytes long and the other 16 bytes long. The default is the 16 byte variant which can be overridden with either \'\-d sat,12\' or \'\-d sat,16\'. -If \'-d sat,auto\' is specified, device type SAT (for ATA/SATA disks) is +[NEW EXPERIMENTAL SMARTD FEATURE] If \'-d sat,auto\' is specified, +device type SAT (for ATA/SATA disks) is only used if the SCSI INQUIRY data reports a SATL (VENDOR: "ATA "). Otherwise device type SCSI (for SCSI/SAS disks) is used. @@ -448,16 +449,24 @@ logical device corresponding to the particular physical disks. Please see the \fBsmartctl\fP(8) man page for further details. .\" %ENDIF OS FreeBSD Linux -.\" %IF OS Linux FreeBSD +.\" %IF OS FreeBSD Linux Windows Cygwin .I areca,N -\- [Linux and FreeBSD only] the device consists of one or more SATA disks connected to an -Areca SATA RAID controller. The positive integer N (in the range from 1 to -24 inclusive) denotes which disk on the controller is monitored. +\- [FreeBSD, Linux, Windows and Cygwin only] the device consists of one or more SATA disks +connected to an Areca SATA RAID controller. The positive integer N (in the range +from 1 to 24 inclusive) denotes which disk on the controller is monitored. In log files and email messages this disk will be identifed as areca_disk_XX with XX in the range from 01 to 24 inclusive. Please see the \fBsmartctl\fP(8) man page for further details. -.\" %ENDIF OS Linux FreeBSD +.I areca,N/E +\- [FreeBSD, Linux, Windows and Cygwin only] [NEW EXPERIMENTAL SMARTD FEATURE] the +device consists of one or more SATA disks connected to an Areca SAS RAID controller. +The integer N (range 1 to 128) denotes the channel (slot) and E (range +1 to 8) denotes the enclosure. +Important: This requires upcoming Areca SAS controller firmware version 1.51 or a +recent beta version. + +.\" %ENDIF OS FreeBSD Linux Windows Cygwin .\" %IF OS FreeBSD Linux .I cciss,N \- [FreeBSD and Linux only] the device consists of one or more SCSI/SAS disks @@ -669,9 +678,8 @@ battery. .\" %ENDIF OS Cygwin Windows .I scterc,READTIME,WRITETIME -\- [ATA only] [NEW EXPERIMENTAL SMARTD FEATURE] sets the SCT Error -Recovery Control settings to the specified values (deciseconds) -when \fBsmartd\fP starts up and has no further effect. +\- [ATA only] sets the SCT Error Recovery Control settings to the specified +values (deciseconds) when \fBsmartd\fP starts up and has no further effect. Values of 0 disable the feature, other values less than 65 are probably not supported. For RAID configurations, this is typically set to 70,70 deciseconds. @@ -725,10 +733,10 @@ The LBA range is based on the first span from the last test. See the \fBsmartctl \-t select,[next|redo|cont]\fP options for further info. -[NEW EXPERIMENTAL SMARTD FEATURE] Some disks (e.g. WD) do not preserve -the selective self test log accross power cycles. If state persistence -(\'\-s\' option) is enabled, the last test span is preserved by smartd -and used if (and only if) the selective self test log is empty. +Some disks (e.g. WD) do not preserve the selective self test log accross +power cycles. If state persistence (\'\-s\' option) is enabled, the last +test span is preserved by smartd and used if (and only if) the selective +self test log is empty. .IP \fBMM\fP 4 is the month of the year, expressed with two decimal digits. The @@ -1134,13 +1142,13 @@ or age of the device has exceeded its intended design life period." .TP .B \-p [ATA only] Report anytime that a Prefail Attribute has changed -its value since the last check, 30 minutes ago. [Please see the +its value since the last check. [Please see the .B smartctl \-A command-line option.] .TP .B \-u [ATA only] Report anytime that a Usage Attribute has changed its value -since the last check, 30 minutes ago. [Please see the +since the last check. [Please see the .B smartctl \-A command-line option.] .TP @@ -1292,19 +1300,19 @@ reports are disabled (\'-W 0\'). To track temperature changes of at least 2 degrees, use: .nf -\fB \-W 2 +.B \-W 2 .fi To log informal messages on temperatures of at least 40 degrees, use: .nf -\fB \-W 0,40 +.B \-W 0,40 .fi For warning messages/mails on temperatures of at least 45 degrees, use: .nf -\fB \-W 0,0,45 +.B \-W 0,0,45 .fi To combine all of the above reports, use: .nf -\fB \-W 2,40,45 +.B \-W 2,40,45 .fi For ATA devices, smartd interprets Attribute 194 as Temperature Celsius @@ -1575,4 +1583,4 @@ SEE ALSO: .SH SVN ID OF THIS PAGE: -$Id: smartd.conf.5.in 3519 2012-03-06 20:01:44Z chrfranke $ +$Id: smartd.conf.5.in 3561 2012-06-05 19:49:31Z chrfranke $ diff --git a/smartd.service.in b/smartd.service.in index 94930ee..1ce551b 100644 --- a/smartd.service.in +++ b/smartd.service.in @@ -3,8 +3,10 @@ Description=Self Monitoring and Reporting Technology (SMART) Daemon After=syslog.target [Service] -EnvironmentFile=/usr/local/etc/sysconfig/smartmontools +EnvironmentFile=-/usr/local/etc/sysconfig/smartmontools ExecStart=/usr/local/sbin/smartd -n $smartd_opts +ExecReload=/bin/kill -HUP $MAINPID +StandardOutput=syslog [Install] WantedBy=multi-user.target diff --git a/utility.h b/utility.h index 5635655..13d5ac9 100644 --- a/utility.h +++ b/utility.h @@ -4,7 +4,7 @@ * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2002-11 Bruce Allen - * Copyright (C) 2008-11 Christian Franke + * Copyright (C) 2008-12 Christian Franke * Copyright (C) 2000 Michael Cornwell * * This program is free software; you can redistribute it and/or modify @@ -26,7 +26,7 @@ #ifndef UTILITY_H_ #define UTILITY_H_ -#define UTILITY_H_CVSID "$Id: utility.h 3475 2011-11-10 21:43:40Z chrfranke $" +#define UTILITY_H_CVSID "$Id: utility.h 3558 2012-06-05 16:42:05Z chrfranke $" #include #include // for regex.h (according to POSIX) @@ -54,6 +54,13 @@ std::string strprintf(const char * fmt, ...) __attribute_format_printf(1, 2); std::string vstrprintf(const char * fmt, va_list ap); +// Return true if STR starts with PREFIX +inline bool str_starts_with(const char * str, const char * prefix) + { return !strncmp(str, prefix, strlen(prefix)); } + +inline bool str_starts_with(const std::string & str, const char * prefix) + { return !strncmp(str.c_str(), prefix, strlen(prefix)); } + #ifndef HAVE_WORKING_SNPRINTF // Substitute by safe replacement functions int safe_snprintf(char *buf, int size, const char *fmt, ...) -- 2.39.2