]> git.proxmox.com Git - mirror_smartmontools-debian.git/commitdiff
Imported Upstream version 5.40+svn3296
authorGiuseppe Iuculano <iuculano@debian.org>
Sun, 20 Mar 2011 15:39:06 +0000 (16:39 +0100)
committerGiuseppe Iuculano <iuculano@debian.org>
Sun, 20 Mar 2011 15:39:06 +0000 (16:39 +0100)
59 files changed:
CHANGELOG
INSTALL
Makefile.am
NEWS
TODO
atacmds.cpp
atacmds.h
ataprint.cpp
ataprint.h
cciss.cpp
configure.in
csmisas.h [new file with mode: 0644]
dev_interface.cpp
dev_interface.h
dev_legacy.cpp
do_release
drivedb.h
examplescripts/Example3
examplescripts/Makefile.am [deleted file]
extern.h [deleted file]
getopt/getopt.c
getopt/getopt1.c
knowndrives.cpp
knowndrives.h
megaraid.h
os_freebsd.cpp
os_freebsd.h
os_generic.cpp
os_linux.cpp
os_netbsd.cpp
os_openbsd.cpp
os_os2.cpp
os_qnxnto.cpp
os_win32.cpp
os_win32/daemon_win32.cpp
os_win32/installer.nsi
os_win32/smartctl_vc8.vcproj
os_win32/smartd_vc8.vcproj
os_win32/syslogevt.c
os_win32/syslogevt.mc
os_win32/update-smart-drivedb.nsi [new file with mode: 0644]
os_win32/wbemcli_small.h [new file with mode: 0644]
os_win32/wmiquery.cpp [new file with mode: 0644]
os_win32/wmiquery.h [new file with mode: 0644]
scsiata.cpp
scsicmds.cpp
scsicmds.h
scsiprint.cpp
scsiprint.h
smartctl.8.in
smartctl.cpp
smartctl.h
smartd.8.in
smartd.conf
smartd.conf.5.in
smartd.cpp
update-smart-drivedb.in
utility.cpp
utility.h

index d03e378b017ff63f8f891516a4ebc653a5955619..b71494899a289bfbccba852daf3367a75fce0040 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,6 @@
 CHANGELOG for smartmontools
 
-$Id: CHANGELOG 3124 2010-07-12 19:21:00Z chrfranke $
+$Id: CHANGELOG 3296 2011-03-16 22:17:51Z chrfranke $
 
 The most recent version of this file is:
 http://smartmontools.svn.sourceforge.net/viewvc/smartmontools/trunk/smartmontools/CHANGELOG?view=markup
@@ -39,10 +39,479 @@ Maintainers / Developers Key (alphabetic order):
 [SZ]  Shengfeng Zhou
 [RZ]  Richard Zybert
 
-NOTES FOR FUTURE RELEASES: see TODO file.
-
 <DEVELOPERS: ADDITIONS TO THE CHANGE LOG GO JUST BELOW HERE, PLEASE>
 
+  [CF] Windows: Add update-smart-drivedb.nsi NSIS script to build
+       drivedb.h update tool.
+
+  [CF] Windows: Move search for NSIS compiler from Makefile.am to
+       configure.in.
+
+  [CF] update-smart-drivedb.in: Move DRIVEDB_BRANCH name creation
+       from script to configure.in.
+
+  [CF] os_linux.cpp: Replace printf() by pout().  Disable unused
+       function dumpdata().
+
+  [CF] Windows: Include CSMI (for Intel RAID) in default DEVICESCAN.
+
+  [CF] configure.in: Remove info messages about old defaults.
+
+  [CF] drivedb.h: Set unneeded USB bcdDevice patterns to empty.
+
+  [CF] Rework USB ID drivedb search.  Stop search at first matching
+       entry with empty bcd_device pattern.
+
+  [CF] Move handling of '-F swapid' from formatting to identity read
+       function.  Remove unneeded 'fix_swapped_id' parameters.
+
+  [CF] smartd: Log warning from drive database if present.
+       smartctl: Do not search drive database twice.
+
+  [MS] drivedb.h USB updates:
+       - Samsung S2 Portable variant (0x04e8:0x1f08)
+       - Lacie rikiki (0x059f:0x102a)
+       - Toshiba Stor.E Steel series (0x0930:0x0b11)
+       - Super Top generic enclosure (0x14cd:0x6116)
+
+  [CF] Let constructor of regular_expression throw on error by default.
+
+  [CF] smartd: Preserve last selective self-test span in '.state' file
+       and use it if the selective self-test log was cleared (ticket #88).
+
+  [CF] smartctl --scan-open: Make output compatible with smartd.conf
+       (ticket #108).  Fix possible crash if autodetect_open() returns
+       new object.
+
+  [CF] do_release: Re-add signing of tarball.
+
+  [CF] os_linux.cpp: Change '-d sat' to '-d sat,12' for USB only if
+       kernel is older than 2.6.29.  Add kernel release to version info.
+
+  [CF] smartd: Add '-l scterc,READTIME,WRITETIME' directive (ticket #150).
+
+  [CF] smartctl: Fix exit status of '-l xerror' and '-l xselftest'
+       (ticket #144).
+
+  [CF] smartd: Use '-M daily' as default if state persistence is enabled.
+       This avoids that emails are suppressed forever (ticket #35).
+
+  [CF] smartd: Log identify information of each ATA device.
+
+  [CF] smartd: Disable '-C' and '-U' monitoring if raw values are
+       very large (ticket #148).
+
+  [CF] smartd: Write reserved attribute byte to '.state' file
+       (ticket #118).
+
+  [MS] drivedb.h USB updates:
+       - Seagate FreeAgent Go Flex Desk USB 3.0
+       - Toshiba Canvio 500GB
+
+  [MS] drivedb.h USB updates:
+       - Freecom HD 500GB (0x07ab:0xfcda)
+       - Generic JMicron adapter (0x152d:0x2337)
+       - RaidSonic ICY BOX IB-110StU3-B (0x1759:0x500[02])
+       - Connectland BE-USB2-35BP-LCM (0x040d:0x6204)
+       - Freecom Classic HD 120GB (0x07ab:0xfccd)
+       - OCZ THROTTLE OCZESATATHR8G (0x152d:0x0602)
+       - Vantec NST-400MX-SR (0x1a4a:0x1670)
+       - Intenso Memory Station 2.5" (0x13fd:0x1840)
+
+  [CF] Don't report failed self-tests outdated by a newer successful
+       extended self-test as errors (ticket #147).
+       This affects smartctl exit status and smartd syslog output and
+       warning email.  Only implemented for ATA.
+
+  [CF] os_linux.cpp: Don't use buffer of size PATH_MAX for the result
+       of realpath().  This also fixes compilation on Debian Lenny.
+
+  [CF] smartd man pages: Add some missing [ATA only].
+
+  [CF] os_linux.cpp: Dereference symlinks before guess of device type
+       (ticket #146).  Minor rework of autodetect_smart_device().
+
+  [CF] smartctl -l scterc: Don't get ERC if only set is requested.
+       This prevent misleading error messages if ATA output registers
+       are not supported.
+
+  [CF] Windows: Prevent warnings from gcc 4.5.1.
+
+  [CF] os_netbsd.cpp, os_openbsd.cpp: Add missing <errno.h>
+
+  [CF] os_freebsd.cpp: Add missing <errno.h>
+
+  [CF] dev_legacy.cpp: Add missing <errno.h>
+
+  [CF] Linux megaraid: Fix pass-through of non-data ATA commands
+       (ticket #149).
+       Only reject commands which require ATA output registers.
+
+  [CF] configure.in: Remove '-fno-strict-aliasing' from CXXFLAGS.
+       This reverts r2992 (see ticket #23).
+
+  [CF] Linux megaraid: Avoid strict-aliasing warnings.
+       Patch was provided by Stanislav Brabec (2009-06-03).
+
+  [MS] Make functions without prototypes static.
+
+  [MS] Remove unnecessary includes, move inclusion of errno.h from scsicmds.h
+       to the appropriate *.cpp files. Add cciss.h to cciss.cpp.
+
+  [MS] os_linux.cpp: rename variables to please "-Wshadow"
+       utility.cpp: remove unused variable "start"
+       os_win32/syslogevt.c: plug resource leak
+
+  [CF] Rename variables to prevent warnings if '-Wshadow' is set.
+       Remove unnecessary includes.  Fix some comments.
+
+  [CF] drivedb.h updates:
+       - Intel X18-M/X25-M/X25-V G2 SSDs: Add firmware bug warning
+       - Samsung SpinPoint M6
+       - Samsung SpinPoint M7E (AFT)
+       - Samsung PM800 SSDs
+       - Samsung PM810 (470 series) SSDs
+
+  [CF] Windows: Add experimental CSMI support for disks behind Intel Matrix
+       RAID driver. Accessed through new device names '/dev/csmi[0-9],N'.
+       Experimental DEVICESCAN can be enabled by '-d csmi'.
+
+  [MS] - ataprint.cpp: adjust print format for insanely large
+           offline data collection times (e.g. WD drives).
+       - getopt: change config.h #include format from angle brackets to quotes
+
+  [MS] drivedb.h update:
+       - Fujitsu MJA2 BH series
+       - Toshiba MK..59GSXP series (Adv. Format)
+       - Toshiba MK..59GSM series (Adv. Format)
+       - Western Digital Caviar Blue SATA 3.0 variants
+       - Seagate Barracuda XT
+
+  [CF] smartctl: Print help message if no option is specified (ticket #39).
+       Don't issue any other ATA command if only '-n POWERMODE' is specified.
+
+  [CF] smartd: Output multiple lines via separate syslog(3) calls
+       (ticket #135).
+
+  [CF] smartctl: Add new ATA minor revisions and log addresses from ACS-2
+       revision 4a.  Replace runtime asserts by compile time asserts.
+
+  [CF] smartd: Remove "default: /var/log/messages" hint from warning mail.
+       This obsoletes Debian patch 60_remove-redhatism.diff.
+
+  [CF] Windows: Include USB devices in DEVICESCAN (ticket #116).
+
+  [CF] Windows: Use direct WMI access to detect USB IDs (ticket #115).
+       This replaces 'wmic' runs and speeds up USB detection.
+
+  [CF] configure.in: Rework platform-specific settings.
+
+  [CF] configure.in: Remove some no longer used settings:
+       -lselinux (duplicate), NEED_SOLARIS_ATA_CODE, OS_FREEBSD.
+
+  [CF] Makefile.am: Remove SUBDIRS. Recursive targets are no longer used.
+
+  [CF] Use log directory to check for old error and self-test log
+       support (ticket #89).
+
+  [CF] drivedb.h USB update:
+       - WD My Book Essential 3TB USB 3.0
+
+  [CF] Fix usb header includes for DragonFly BSD (ticket #141).
+
+  [CF] smartctl: Print physical and logical sector sizes (ticket #62).
+
+  [CF] drivedb.h updates:
+       - Fujitsu MHT: Add AC variant
+       - Fujitsu MHW2 AC
+       - Samsung SpinPoint T166: Needs '-v 197,increasing'
+       - Seagate Barracuda 7200.11: Add firmware SD81 as buggy
+       - WD Scorpio Blue EIDE: Add 320GB
+
+  [CF] drivedb.h USB updates:
+       - Samsung S2 Portable (ticket #136)
+       - Move Verbatim 0x152d:0x2351 to JMicron section
+
+  [AS] drivedb.h updates:
+       - Verbatim Portable Hard Drive eSATA & USB 2.0 Combo 500GB
+
+  [CF] Happy New Year! Update copyright year in version info.
+
+  [CF] drivedb.h updates:
+       - Hitachi Deskstar 7K3000
+       - Hitachi Travelstar 7K320: Add ...362 variant
+       - Seagate Maxtor DiamondMax 21: Add STM3250310AS
+       - Toshiba 2.5" HDD MK..65GSX
+       - WD Caviar Green (Adv. Format): Add 750GB, 2.5TB, 3TB
+
+  [CF] drivedb.h USB updates:
+       - Micron USB SSD (unsupported, ticket #133)
+       - Samsung G2 Portable (ticket #132)
+       - Samsung Story Station 3.0 (ticket #130)
+       - Seagate FreeAgent GoFlex (ticket #131)
+
+  [CF] update-smart-drivedb.in: Add workaround for OpenBSD shell bug:
+       'set -e; if eval false; ...' aborts script (ticket #128).
+
+  [CF] update-smart-drivedb.in: Add platform specific download tools:
+       'fetch' on FreeBSD (ticket #127), 'ftp' on OpenBSD.
+
+  [CF] drivedb.h USB updates:
+       - JMicron 0x152d:0x2509
+       - WD My Passport 0730
+
+  [CF] drivedb.h updates:
+       - Samsung SpinPoint F3 EG: Add 2TB
+       - SandForce Driven SSDs: Add ADATA S599, SuperTalent TeraDrive CT
+       - Seagate Constellation (SATA)
+       - Seagate Constellation ES (SATA)
+       - WDC My Passport: Add WD5000BMVW
+
+  [CF] drivedb.h update:
+       - Samsung SpinPoint F4 EG: Add 1.5TB, update firmware bug warning.
+
+  [DG] [SCSI] Fix log page sanity check problem if the DS bit set
+       in response. Caused '-l background' to fail.
+
+  [CF] drivedb.h updates:
+       - Samsung SpinPoint F4 EG: Warning about bad blocks
+
+  [CF] update-smart-drivedb.in: Replace ERE by BRE.  Script does no
+       longer require GNU sed (Ticket #126).
+
+  [DG] In '-r ioctl' show vendor specific SCSI commands as such rather
+       than 'unknown'.
+
+  [CF] Add check for CompactFlash Signature in ATA IDENTIFY data.
+       This avoids that older CF microdrives are detected as ATAPI
+       devices (Ticket #125).
+
+  [CF] drivedb.h updates:
+       - Apple SSDs TS*
+       - Crucial RealSSD C300 Series
+       - Kingston SSDNow V Series
+       - Indilinx Barefoot based SSDs: Add OCZ-ONYX
+       - SandForce Driven SSDs: Add OCZ VERTEX2-PRO
+       - Transcend CompactFlash Cards: Add TS4GCF133
+
+  [CF] Windows installer: Add missing quotes in smartctl-run.bat
+       and smartd-run.bat (Ticket #124).
+
+  [CF] OpenBSD: Fix DEVICESCAN for OpenBSD >= 4.8 (Ticket #123).
+
+  [CF] daemon_win32.cpp: Remove duplicate assignment (Ticket #120).
+
+  [CF] Makefile.am: Do not overwrite existing smartd.conf file
+       (Ticket #122).  If smartd.conf exists and differs from the
+       default then smartd.conf.sample is installed instead
+       If smartd.conf.sample exists on uninstall then smartd.conf is
+       preserved.
+
+  [CF] Linux megaraid: Fix segfault on non-data commands (Ticket #78).
+       The /dev/megaraid_sas_ioctl_node driver does not allow
+       sge_count = 1 and sgl[0].iov_len = 0.
+
+  [CF] Remove EXPERIMENTAL notes for features already present
+       in 5.39.
+
+  [CF] Rework '-d TYPE' documentation on man pages.
+
+  [CF] drivedb.h updates:
+       - Seagate Maxtor DiamondMax 21: Add 80GB
+       - Western Digital Caviar Black: Add 1TB/64MB
+
+  [CF] drivedb.h USB updates:
+       - iRiver iHP-120/140 (Ticket #119)
+       - ASMedia ASM1051
+
+  [CF] Makefile.am: Handle examplescripts in main Makefile.
+       Remove 'examplescripts/Makefile.am'.
+
+  [CF] configure.in: New option '--with-exampledir' allows to change
+       path of 'DOCDIR/examplescripts' directory.
+       (Debian package uses '/usr/share/doc/smartmontools/examples')
+
+  [CF] Replace global 'con->dont_print/...' variables by 'printing_is_*'.
+       Remove global 'con'trol pointer.  Remove file 'extern.h'.
+
+  [CF] Replace global 'con->reportata/scsiioctl' variables by '*_debugmode'.
+
+  [CF] Replace global 'con->conservative/permissive' variables by
+       'failuretest_*'.  Move failuretest() function to smartctl.cpp.
+
+  [CF] Remove unused CONTROLLER_* defines.
+
+  [CF] Remove unused controller support from dev_legacy adapter module.
+
+  [CF] Make 'debugmode' variable local to smartd.cpp.
+
+smartmontools 5.40 2010-10-16
+
+  [CF] examplescripts/Example3: Use stdin to pass message to 'wall'
+       command (ticket #114).
+
+  [CF] smartd: Fix setting of SMARTD_DEVICE and SMARTD_DEVICETYPE
+       environment variables (ticket #113).
+       Regression was introduced by rework of smartd data structures.
+       SMARTD_DEVICE is now set to the plain device name.
+       SMARTD_DEVICETYPE is now set to 'auto' if no '-d' directive is
+       specified.  Smartctl now accepts '-d auto' for this purpose.
+
+  [CF] Remove "Lifetime" from Min/Max temperature attribute output
+       (ticket #111).  Interval is device specific.
+
+  [CF] configure.in: Print resource/message compiler info for Windows only.
+
+  [CF] FreeBSD: Rework get_dev_names_cam() to support more than 26 devices.
+
+  [CF] drivedb.h updates:
+       - Seagate Barracuda 7200.10: Add 360GB
+       - USB: Iomega MDHD-UE
+       Patch provided by Rob Marissen.
+
+  [DL] Standby mode not detected properly on FreeBSD (ticket #91).
+
+  [MS] os_linux.cpp: fix "gcc -flto" build error by including stddef.h
+
+  [CF] drivedb.h update:
+       - Indilinx Barefoot based SSDs: Add OCZ-VERTEX 1199 and -TURBO
+
+  [CF] TODO file: Move open entries to tickets #106, #107, #108, #109, #110.
+       Remove outdated entries.
+
+  [CF] drivedb.h USB update:
+       - SunPlus 0x04fc:0x0c05
+
+  [CF] drivedb.h update:
+       - SandForce Driven SSDs: Add Corsair Force, fix typo
+
+  [CF] Print hex values of unknown self-test type or status.
+
+  [CF] drivedb.h updates:
+       - SandForce Driven SSDs: Fix regex for Unigen UG99SGC
+       - Seagate Momentus XT series
+       - Quantum Bigfoot: Add 12.7GB
+
+  [CF] drivedb.h updates:
+       - SandForce Driven SSDs: Add 11 attributes of new FW,
+         add Unigen UG99PGC
+       - WD AV ATA family: Add 250GB, 320GB
+       - WD AV SATA family
+
+  [CF] Windows: Build syslogevt.exe with MinGW.  Now possible because
+       binutils provides windmc.
+
+  [CF] Makefile.am: Remove install message about smartd startup.
+       It might be misleading because it is not correct for all platforms.
+
+  [CF] configure.in: Minor fix of '--enable-drivedb' new defaults
+       detection.
+
+  [CF] Update links, configure and OS info in INSTALL file.
+       Replace tabs by spaces.
+
+  [CF] configure.in: Fix '--enable-sample' and '--with-selinux'.
+       Fix obsolete use of AC_DEFINE().
+
+  [CF] drivedb.h updates:
+       - IBM Deskstar 60GXP, 40GV & 75GXP: Update link (ticket #99)
+       - Seagate Barracuda 7200.12: Add ST31000523AS and others
+       - WD Caviar Black: Add 2TB
+       - WD VelociRaptor: Add 6 Gb/s models
+
+  [CF] Windows installer: Fix smartctl-run.bat for drive menu (ticket #31).
+
+  [CF] Windows: Create md5/sha1/sha256 checksums of the binaries.
+       Add checksums.txt file to binary distribution.
+
+  [CF] Windows: Include drivedb.h into binary distribution.
+
+  [CF] drivedb.h updates:
+       - Intel X18-M/X25-M/X25-V G2: Add X25-V 40GB
+       - Transcend CompactFlash Cards
+
+  [CF] drivedb.h updates:
+       - Seagate Momentus 7200 FDE.2: Add ST9160414ASG
+       - Seagate Pipeline HD 5900.1 and 5900.2
+       Based on patch provided by Marcin Falkiewicz.
+
+  [CF] Remove unused variable 'reportbug'.
+
+  [CF] Make function PrintOut() local to smartd.cpp, remove it from
+       smartctl.cpp.
+
+  [CF] Windows: Improve compatibility with MinGW variants.
+       Add configure check for DDK include files.
+       Drop support for '-mno-cygwin' from old Cygwin gcc.
+
+  [AS] smartctl.8.in minor update: adding FreeBSD ahci/scsi device hints
+
+  [CF] Fix build if SVN Id keywords are not expanded (ticket #94).
+
+  [CF] Windows: Remove "." from DLL search path to prevent DLL
+       preloading attacks.
+
+  [CF] drivedb.h USB update:
+       - JMicron 0x152d:0x0551 (ticket #95)
+       Add note about port multipliers to smartctl man page.
+
+  [CF] drivedb.h updates:
+       - SandForce Driven SSDs: Add Unigen drives
+       - Indilinx Barefoot based SSDs: Add ASAX Leopard Hunt II
+
+  [CF] drivedb.h update:
+       - Intel X18-M/X25-M G2: Add names of timed workload attributes.
+       Document attribute clear command '-t vendor,0x40' on smartctl
+       man page.
+
+       Thanks to Artem Danielov from Intel for providing the
+       required information and drives for testing.
+
+  [CF] drivedb.h update:
+       - SandForce Driven SSDs: Add OCZ drives with form factor info.
+
+  [CF] drivedb.h update:
+       - Intel X25-E, X18-M/X25-M (add X18-M, update attributes)
+
+  [CF] configure.in: '--enable-drivedb' is now the default.
+
+  [CF] drivedb.h update:
+       - Indilinx Barefoot based SSDs
+         (combine and update 5 SSD entries using this controller)
+
+  [CF] drivedb.h update:
+       - SandForce Driven SSDs (Demo Drive, OCZ-Agility2/Vertex2/Vertex-LE)
+
+       Thanks to Jeremy Werner (jwerner@sandforce.com) from SandForce for
+       providing the required information and a demo drive for testing.
+
+  [CF] drivedb.h update:
+       - Add 1.5TB drive to SAMSUNG SpinPoint F3 EG series
+
+  [CF] Add print formats '-v ID,msec24hour32' and '-v ID,raw24/raw32'.
+       Used by SSDs with SandForce controller.
+
+  [CF] Allow SMART threshold entries at positions different from
+       attribute table. This fixes attribute output for recent
+       SSDs with SandForce controller.
+
+  [CF] smartctl: Add option '-t vendor,N' to issue ATA
+       command SMART EXECUTE OFF-LINE IMMEDIATE with
+       a vendor specific subcommand.
+
+  [CF] drivedb.h update:
+       - SAMSUNG SpinPoint V80 series (ticket #85)
+
+  [CF] Linux: Support SATA drives on LSI 3ware 9750 controllers.
+       Patch provided by Victor Payno (ticket #86).
+       Modified to avoid duplicate code.
+
+  [CF] drivedb.h update:
+       - SAMSUNG SpinPoint M7 series
+
+  [CF] drivedb.h USB update:
+       - Buffalo JustStore Portable HD-PVU2
+
   [CF] drivedb.h USB updates:
        - Iomega LDHD-UP (ticket #83)
        - WD Elements Desktop 2TB
diff --git a/INSTALL b/INSTALL
index 0fd6a4c84f7157eec417c3ab582582e5e00b3bf4..316f3fed642224c09d0fa3585ce5f5d2762a1aee 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -1,7 +1,7 @@
 Smartmontools installation instructions
 =======================================
 
-$Id: INSTALL 3074 2010-03-05 23:00:30Z chrfranke $
+$Id: INSTALL 3205 2010-11-15 18:32:55Z chrfranke $
 
 Please also see the smartmontools home page:
 http://smartmontools.sourceforge.net/
@@ -45,17 +45,12 @@ Table of contents:
     smartmontools will "mostly" work.  The things that don't work will
     give you harmless warning messages.
 
-    Although "not officially supported" by the developers, smartmontools
-    has also been successfully build and run on a legacy Linux system
-    with kernel 2.0.33 and libc.so.5. On such systems, the restrictions
-    above apply.
-
     For item (1) above, any 2.4 or 2.6 series kernel will provide
     HDIO_DRIVE_TASK support.  Some 2.2.20 and later kernels also
     provide this support IF they're properly patched and
     configured. [Andre Hedrick's IDE patches may be found at
-    http://www.funet.fi/pub/linux/kernel/people/hedrick/ide-2.2.20/ or
-    are available from your local kernel.org mirror.  They are not
+    http://www.nic.funet.fi/pub/linux/kernel/people/hedrick/ide-2.2.20/
+    or are available from your local kernel.org mirror.  They are not
     updated for 2.2.21 or later, and may contain a few bugs.].
     If the configuration option CONFIG_IDE_TASK_IOCTL
     exists in your 2.2.X kernel source code tree, then your 2.2.X
@@ -102,11 +97,8 @@ Table of contents:
 
     E) Cygwin
 
-    The code was tested on Cygwin 1.5.25-15 and 1.7.0-62. It should also
-    work on other recent releases.
-
-    Release 1.5.15 or later is recommended for Cygwin smartd. Older versions
-    do not provide syslogd support.
+    The code was tested on Cygwin 1.7.7-1. It should also work on other
+    recent releases.
 
     Both Cygwin and Windows versions of smartmontools share the same code
     to access the IDE/ATA or SCSI devices. The information in the "Windows"
@@ -115,7 +107,7 @@ Table of contents:
     F) Windows
 
     The code was tested on Windows 98SE, ME, NT4(SP5,SP6), 2000(SP4),
-    XP(up to SP3), 2003 and Vista.
+    XP(up to SP3), 2003, Vista and Windows 7.
 
     -- Windows 9x/ME
 
@@ -142,7 +134,7 @@ Table of contents:
     (http://www.adaptec.com/en-US/support/_eol/scsi_sw/ASPI-4.70/)
     Links to other ASPI drivers can be found at http://www.nu2.nu/aspi/.
 
-    -- Windows NT4/2000/XP/2003/Vista
+    -- Windows NT4/2000/XP/2003/Vista/Win7
 
     ATA or SATA devices are supported if the device driver implements
     the SMART IOCTLs or IOCTL_IDE_PASS_THROUGH or IOCTL_ATA_PASS_THROUGH.
@@ -222,8 +214,8 @@ Table of contents:
     SVN. You need GNU Autoconf (version 2.50 or greater), GNU Automake
     (version 1.7 or greater) and their dependencies installed in order
     to run it.  You can get these here:
-    http://www.gnu.org/directory/GNU/autoconf.html
-    http://www.gnu.org/directory/GNU/automake.html
+    http://directory.fsf.org/project/autoconf/
+    http://directory.fsf.org/project/automake/
 
 [3] Installing from the source tarball
 ======================================
@@ -237,14 +229,20 @@ Table of contents:
     make install (you may need to be root to do this)
 
     As shown (with no options to ./configure) this defaults to the
-    following set of installation directories:   
+    following set of installation directories:
     --prefix=/usr/local
     --sbindir=/usr/local/sbin
     --sysconfdir=/usr/local/etc
     --mandir=/usr/local/share/man
-    --with-docdir=/usr/local/share/doc/smartmontools
+    --[with-]docdir=/usr/local/share/doc/smartmontools
+    --with-drivedbdir=/usr/local/share/smartmontools
     --with-initscriptdir=/usr/local/etc/rc.d/init.d
+    --enable-drivedb
+    --disable-attributelog
     --disable-sample
+    --disable-savestates
+    --with-libcap-ng=auto
+    --without-selinux
 
     These will usually not overwrite existing "distribution" installations on
     Linux Systems since the FHS reserves this area for use by the system
@@ -253,10 +251,10 @@ Table of contents:
     For different installation locations or distributions, simply add
     arguments to ./configure as shown in [4] below.
 
-    If you wish to alter the default C compiler flags, set an
-    environment variable CFLAGS='your options' before doing
+    If you wish to alter the default C++ compiler flags, set an
+    environment variable CXXFLAGS='your options' before doing
     ./configure, or else do:
-    make CFLAGS='your options'
+    make CXXFLAGS='your options'
 
     The first output line of smartctl and smartd provides information
     about release number, last SVN checkin date and revison, platform,
@@ -283,10 +281,10 @@ Filesystem Hierarchy Standard (FHS, http://www.pathname.com/fhs/):
 
 Red Hat:
   ./configure --sbindir=/usr/sbin                               \
-             --sysconfdir=/etc                                 \
-             --mandir=/usr/share/man                           \
-             --with-initscriptdir=/etc/rc.d/init.d             \
-             --with-docdir=/usr/share/doc/smartmontools-VERSION
+              --sysconfdir=/etc                                 \
+              --mandir=/usr/share/man                           \
+              --with-initscriptdir=/etc/rc.d/init.d             \
+              --with-docdir=/usr/share/doc/smartmontools-VERSION
 
 Slackware:
   If you don't want to overwrite any "distribution" package, use:
@@ -331,13 +329,13 @@ SuSE:
   ./configure --prefix=/usr/local                                      \
               --with-initscriptdir=/usr/local/etc/rc.d/                \
               --with-docdir=/usr/local/share/doc/smartmontools-VERSION \
-             --enable-sample
+              --enable-sample
 
   NOTE: --enable-sample will cause the smartd.conf and smartd RC files to
   be installed with the string '.sample' append to the name, so you will end
   up with the following:
-       /usr/local/etc/smartd.conf.sample
-       /usr/local/etc/rc.d/smartd.sample
+        /usr/local/etc/smartd.conf.sample
+        /usr/local/etc/rc.d/smartd.sample
 
 
 [6] Guidelines for Darwin
@@ -349,12 +347,12 @@ SuSE:
 
   CXX='g++ -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386' \
     ./configure --host=i386-apple-darwin \
-               --with-initscriptdir=/Library/StartupItems
+                --with-initscriptdir=/Library/StartupItems
 
 [7] Guidelines for NetBSD/OpenBSD
 =================================
   ./configure --prefix=/usr/pkg                                       \
-             --with-docdir=/usr/pkg/share/doc/smartmontools
+              --with-docdir=/usr/pkg/share/doc/smartmontools
 
   On OpenBSD, it is important that you use GNU make (gmake from 
   /usr/ports/devel/gmake) to build smartmontools, as the BSD make doesn't
@@ -387,10 +385,10 @@ SuSE:
 
     To start the script automatically on bootup, create hardlinks that
     indicate when to start/stop in:
-                   /etc/rc[S0123].d/
+                    /etc/rc[S0123].d/
     pointing to /etc/init.d/smartd. Create:
-           K<knum>smartd in rcS.d, rc0.d, rc1.d, rc2.d
-           S<snum>smartd in rc3.d
+            K<knum>smartd in rcS.d, rc0.d, rc1.d, rc2.d
+            S<snum>smartd in rc3.d
     where <knum> is related to <snum> such that the higher snum is the
     lower knum must be.
 
@@ -443,28 +441,36 @@ To compile the Windows release with MinGW gcc on MSYS, use:
   Instead of using "make install", copy the .exe files into
   some directory in the PATH.
 
-To compile on Cygwin with MinGW gcc 3.x (option '-mno-cygwin'):
-
-  ./configure --build=i686-pc-mingw32 \
-               CC=gcc-3               \
-              CXX=g++-3
-
-To cross-compile on Debian Linux with gcc-mingw32:
+Cross-compile statically linked 32-bit version with MinGW-w64:
 
   ./configure --build=$(./config.guess) \
-              --host=i686-pc-mingw32    \
-               CC=i586-mingw32msvc-gcc  \
-              CXX=i586-mingw32msvc-g++
+              --host=i686-w64-mingw32 \
+              LDFLAGS=-static
 
-To compile statically linked 64-bit version with MinGW-w64:
+  Tested on Cygwin and Debian Linux.
 
-  ./configure --build=$(./config.guess)  \
-              --host=x86_64-w64-mingw32   \
+Cross-compile statically linked 64-bit version with MinGW-w64:
+
+  ./configure --build=$(./config.guess) \
+              --host=x86_64-w64-mingw32 \
               LDFLAGS=-static
 
-  Tested on Cygwin and Linux with MinGW-w64 from
+  Tested on Cygwin and Debian Linux with MinGW-w64 from
   http://mingw-w64.sourceforge.net/.
-  WARNING: 64-bit version is still EXPERIMENTAL.
+
+WARNING: The smartmontools version for 64-bit Windows is still EXPERIMENTAL.
+
+Cross-compile on Cygwin with old gcc-mingw 3.x:
+
+  ./configure --build=$(./config.guess) \
+              --host=i686-pc-mingw32 \
+               CC='gcc-3 -mno-cygwin' \
+              CXX='g++-3 -mno-cygwin'
+
+Cross-compile on Debian Linux with gcc-mingw32:
+
+  ./configure --build=$(./config.guess) \
+              --host=i586-mingw32msvc
 
 
 To build the Windows binary distribution, use:
@@ -508,10 +514,16 @@ To both create and run the (interactive) installer, use:
   or a native Win32 release of Info-ZIP, http://www.info-zip.org) are
   necessary but may be not installed by Cygwin's default settings.
 
-To prepare os_win32 directory for MSVC8, use the following on Cygwin:
+  The event message file tool syslogevt.exe (see smartd man page) is
+  included in the binary distribution if message compiler (windmc)
+  and resource compiler (windres) are available. This may be disabled
+  by passing 'WINDMC=no' to configure.
+
+To prepare os_win32 directory for MSVC8, use the following on MSYS
+or Cygwin:
 
   mkdir vctmp && cd vctmp
-  ../configure --build=mingw32
+  ../configure [... any MinGW option set from above ...]
   make config-vc8
 
   The MSVC8 project files (os_win32/smartmontools_vc8.sln,
@@ -521,10 +533,6 @@ To prepare os_win32 directory for MSVC8, use the following on Cygwin:
   ./{config,svnversion}.h. The configure skript must be run outside
   of the source directory to avoid inclusion of the original config.h.
 
-  Unlike MinGW, MSVC can also be used to build the syslog message file
-  tool syslogevt.exe. See smartd man page for usage information about
-  this tool.
-
 
 [11] Guidelines for OS/2, eComStation
 =====================================
@@ -541,10 +549,10 @@ To compile the OS/2 code, please run
   the following:
 
   ./configure --prefix=/usr/local                                      \
-             --sysconfdir=/etc
+              --sysconfdir=/etc
               --with-initscriptdir=/usr/local/share/doc/smartmontools-VERSION \
               --with-docdir=/usr/local/share/doc/smartmontools-VERSION \
-             --enable-sample
+              --enable-sample
 
   It is important that you use GNU make (gmake from /usr/ports/devel/gmake)
   to build smartmontools, as the default OpenBSD make doesn't know how to build
@@ -558,8 +566,8 @@ To compile the OS/2 code, please run
   NOTE2: --enable-sample will cause the smartd.conf and smartd RC files to
   be installed with the string '.sample' append to the name, so you will end
   up with the following:
-       /usr/local/etc/smartd.conf.sample
-       /usr/local/etc/rc.d/smartd.sample
+        /usr/local/etc/smartd.conf.sample
+        /usr/local/etc/rc.d/smartd.sample
 
 [13] Comments
 ============
@@ -595,31 +603,37 @@ Note that the default location for the manual pages are
 them, you may need to add /usr/share/man to your MANPATH environment
 variable.
 
-Source and binary RPM packages are available at
-http://sourceforge.net/project/showfiles.php?group_id=64297
+Source and binary packages for Windows are available at
+http://sourceforge.net/projects/smartmontools/files/
 
-Refer to http://smartmontools.sourceforge.net/index.html#howtodownload
+Refer to http://sourceforge.net/apps/trac/smartmontools/wiki/Download
 for any additional download and installation instructions.
 
 The following files are installed if ./configure has no options:
 
-/usr/local/sbin/smartd                                  [Executable daemon]
 /usr/local/sbin/smartctl                                [Executable command-line utility]
+/usr/local/sbin/smartd                                  [Executable daemon]
+/usr/local/sbin/update-smart-drivedb                    [Drive database update script]
 /usr/local/etc/smartd.conf                              [Configuration file for smartd daemon]
 /usr/local/etc/rc.d/init.d/smartd                       [Init/Startup script for smartd]
 /usr/local/share/man/man5/smartd.conf.5                 [Manual page]
 /usr/local/share/man/man8/smartctl.8                    [Manual page]
 /usr/local/share/man/man8/smartd.8                      [Manual page]
-/usr/local/share/doc/smartmontools-5.X/AUTHORS          [Information about the authors and developers]
-/usr/local/share/doc/smartmontools-5.X/CHANGELOG        [A log of changes. Also see SVN]
-/usr/local/share/doc/smartmontools-5.X/COPYING          [GNU General Public License Version 2]
-/usr/local/share/doc/smartmontools-5.X/INSTALL          [Installation instructions: what you're reading!]
-/usr/local/share/doc/smartmontools-5.X/NEWS             [Significant bugs discovered in old versions]
-/usr/local/share/doc/smartmontools-5.X/README           [Overview]
-/usr/local/share/doc/smartmontools-5.X/TODO             [Things that need to be done/fixed]
-/usr/local/share/doc/smartmontools-5.X/WARNINGS         [Systems where lockups or other serious problems were reported]
-/usr/local/share/doc/smartmontools-5.X/smartd.conf      [Example configuration file for smartd]
-/usr/local/share/doc/smartmontools-5.X/examplescripts   [Executable scripts for -M exec of smartd.conf (4 files)]
+/usr/local/share/doc/smartmontools/AUTHORS              [Information about the authors and developers]
+/usr/local/share/doc/smartmontools/CHANGELOG            [A log of changes. Also see SVN]
+/usr/local/share/doc/smartmontools/COPYING              [GNU General Public License Version 2]
+/usr/local/share/doc/smartmontools/INSTALL              [Installation instructions: what you're reading!]
+/usr/local/share/doc/smartmontools/NEWS                 [Significant bugs discovered in old versions]
+/usr/local/share/doc/smartmontools/README               [Overview]
+/usr/local/share/doc/smartmontools/TODO                 [Things that need to be done/fixed]
+/usr/local/share/doc/smartmontools/WARNINGS             [Systems where lockups or other serious problems were reported]
+/usr/local/share/doc/smartmontools/smartd.conf          [Example configuration file for smartd]
+/usr/local/share/doc/smartmontools/examplescripts/      [Executable scripts for -M exec of smartd.conf (4 files)]
+/usr/local/share/smartmontools/drivedb.h                [Drive database]
+
+If /usr/local/etc/smartd.conf exists and differs from the
+default then the default configuration file is installed as
+/usr/local/etc/smartd.conf.sample instead.
 
 The commands:
 
@@ -675,14 +689,15 @@ OPTIONS              DEFAULT                                      AFFECTS
                                                                   Directory for rc.d/init.d/smartd init script
 --with-initscriptdir  ${sysconfdir}/init.d/rc.d                   Location of init scripts
 --with-docdir         ${prefix}/share/doc/smartmontools           Location of the documentation
+--with-exampledir     ${docdir}/examplescripts                    Location of example scripts
 --enable-sample       --disable-sample                            Adds the string '.sample' to the names of the smartd.conf file and the smartd RC file
 --with-os-deps        os_<guessed>.o                              OS dependent module(s)
---with-selinux        <not set>                                   Enables SELinux support.  If smartmontools has to create the /dev/tw[ae] device
+--with-selinux        --without-selinux                           Enables SELinux support.  If smartmontools has to create the /dev/tw[ae] device
                                                                   nodes for 3ware/AMCC controllers, this option ensures that the nodes are created
                                                                   with correct SELinux file contexts.
---with-libcap-ng     --with-libcap-ng=auto                        Enables/disables libcap-ng support. If enabled and libcap-ng is
+--with-libcap-ng      --with-libcap-ng=auto                       Enables/disables libcap-ng support. If enabled and libcap-ng is
                                                                   available, option --capabilities is added to smartd.
---enable-drivedb      --disable-drivedb                           Enables default drive database file '${drivedbdir}/drivedb.h'
+--disable-drivedb     --enable-drivedb                            Disables default drive database file '${drivedbdir}/drivedb.h'
 --with-drivedbdir     ${prefix}/share/smartmontools               Directory for 'drivedb.h' (implies --enable-drivedb)
 --enable-savestates   --disable-savestates                        Enables default smartd state files '${savestates}MODEL-SERIAL.ata.state'
 --with-savestates     ${prefix}/var/lib/smartmontools/smartd.     Prefix for smartd state files (implies --enable-savestates)
@@ -735,14 +750,14 @@ no other options specified (see above for details)
 Case 1:
 --enable-sample provided
 ==> Files installed are:
-       /usr/local/etc/smartd.conf.sample
-       /usr/local/etc/rc.d/init.d/smartd.sample
+        /usr/local/etc/smartd.conf.sample
+        /usr/local/etc/rc.d/init.d/smartd.sample
 
 Case 2:
 --disable-sample provided or parameter left out
 ==> Files installed are:
-       /usr/local/etc/smartd.conf
-       /usr/local/etc/rc.d/init.d/smartd
+        /usr/local/etc/smartd.conf
+        /usr/local/etc/rc.d/init.d/smartd
 
 Additional information about using configure can be found here:
-http://www.gnu.org/software/autoconf/manual/autoconf-2.57/html_mono/autoconf.html#SEC139
+http://www.gnu.org/software/autoconf/manual/autoconf.html#Running-configure-Scripts
index 021ea30ad0510cd6b6e2213fd20388481ff6907a..6661801eee3037e790f551ccfaa08d1fccf16d2e 100644 (file)
@@ -1,6 +1,6 @@
 ## Process this file with automake to produce Makefile.in
 #
-# $Id: Makefile.am 3115 2010-06-02 17:23:05Z chrfranke $
+# $Id: Makefile.am 3296 2011-03-16 22:17:51Z chrfranke $
 #
 
 @SET_MAKE@
@@ -33,8 +33,11 @@ sbin_PROGRAMS = smartd       \
                smartctl
 
 if ENABLE_DRIVEDB
+if OS_WIN32_MINGW
+else
 sbin_SCRIPTS = update-smart-drivedb
 endif
+endif
 
 
 smartd_SOURCES =  smartd.cpp      \
@@ -48,7 +51,6 @@ smartd_SOURCES =  smartd.cpp      \
                   dev_interface.h     \
                   dev_tunnelled.h     \
                   drivedb.h           \
-                  extern.h        \
                   int64.h         \
                   knowndrives.cpp \
                   knowndrives.h   \
@@ -111,7 +113,6 @@ smartctl_SOURCES= smartctl.cpp    \
                   dev_interface.h     \
                   dev_tunnelled.h     \
                   drivedb.h           \
-                  extern.h        \
                   int64.h         \
                   knowndrives.cpp \
                   knowndrives.h   \
@@ -186,6 +187,23 @@ EXTRA_smartd_SOURCES += \
 
 endif
 
+if OS_WIN32
+
+smartctl_SOURCES += \
+        csmisas.h \
+        os_win32/wmiquery.cpp \
+        os_win32/wmiquery.h
+
+smartd_SOURCES += \
+        csmisas.h \
+        os_win32/wmiquery.cpp \
+        os_win32/wmiquery.h
+
+smartctl_LDADD += -lole32 -loleaut32
+smartd_LDADD   += -lole32 -loleaut32
+
+endif
+
 if OS_SOLARIS
 # This block is required because Solaris uses manual page section 1m
 # for administrative command (linux/freebsd use section 8) and Solaris
@@ -255,25 +273,66 @@ docs_DATA = AUTHORS     \
             WARNINGS    \
             smartd.conf
 
-sysconf_DATA = smartd.conf$(smartd_suffix)
-
-if SMARTD_SUFFIX
-smartd.conf$(smartd_suffix): smartd.conf
-       cp ${srcdir}/smartd.conf smartd.conf$(smartd_suffix)
-endif
-
-EXTRA_DIST = smartd.initd.in                       \
-             smartd.8.in                           \
-             smartctl.8.in                         \
-             smartd.conf.5.in                      \
-             smartd.conf                           \
-             autogen.sh                            \
-             update-smart-drivedb.in               \
-             os_darwin/SMART.in                    \
-             os_darwin/StartupParameters.plist     \
-             os_darwin/English_Localizable.strings \
-             os_win32/installer.nsi                \
-             $(docs_DATA)
+examplesdir=$(exampledir)
+examples_DATA = \
+        examplescripts/README
+examples_SCRIPTS = \
+        examplescripts/Example1 \
+        examplescripts/Example2 \
+        examplescripts/Example3 \
+        examplescripts/Example4
+
+sysconf_DATA = smartd.conf
+
+# If modified smartd.conf exists install smartd.conf.sample instead
+install-sysconfDATA: $(sysconf_DATA)
+       $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+       @s="$(srcdir)/smartd.conf"; \
+       f="$(DESTDIR)$(sysconfdir)/smartd.conf$(smartd_suffix)"; \
+       if test -z "$(smartd_suffix)" && test -f "$$f"; then \
+         if cmp "$$s" "$$f" >/dev/null 2>/dev/null; then :; else \
+           echo "************************************************************"; \
+           echo "*** $$f preserved"; \
+           echo "*** installing smartd.conf.sample instead"; \
+           echo "************************************************************"; \
+           f="$$f".sample; \
+         fi; \
+       fi; \
+       echo " $(INSTALL_DATA) $$s $$f"; \
+       $(INSTALL_DATA) "$$s" "$$f"
+
+# If smartd.conf.sample exists preserve smartd.conf
+uninstall-sysconfDATA:
+       @f="$(DESTDIR)$(sysconfdir)/smartd.conf$(smartd_suffix)"; \
+       if test -z "$(smartd_suffix)" && test -f "$$f".sample; then \
+         echo "************************************************************"; \
+         echo "*** $$f preserved"; \
+         echo "*** removing smartd.conf.sample instead"; \
+         echo "************************************************************"; \
+         f="$$f".sample; \
+       fi; \
+       echo " rm -f $$f"; \
+       rm -f "$$f"
+
+EXTRA_DIST = \
+        smartd.initd.in \
+        smartd.8.in \
+        smartctl.8.in \
+        smartd.conf.5.in \
+        smartd.conf \
+        autogen.sh \
+        update-smart-drivedb.in \
+        os_darwin/SMART.in \
+        os_darwin/StartupParameters.plist \
+        os_darwin/English_Localizable.strings \
+        os_win32/installer.nsi \
+        os_win32/syslogevt.c \
+        os_win32/syslogevt.mc \
+        os_win32/update-smart-drivedb.nsi \
+        os_win32/wbemcli_small.h \
+        $(docs_DATA) \
+        $(examples_DATA) \
+        $(examples_SCRIPTS)
 
 CLEANFILES = smartd.conf.5      \
              smartd.conf.4      \
@@ -292,10 +351,6 @@ CLEANFILES = smartd.conf.5      \
              update-smart-drivedb \
              SMART
 
-if SMARTD_SUFFIX
-CLEANFILES += smartd.conf$(smartd_suffix)
-endif
-
 # 'make maintainer-clean' also removes files generated by './autogen.sh'
 MAINTAINERCLEANFILES = \
         $(srcdir)/Makefile.in \
@@ -391,13 +446,6 @@ install-initdDATA-darwin: $(initd_DATA)
          $(INSTALL_DATA) $(srcdir)/os_darwin/$${i}_Localizable.strings \
            $$RDIR/Localizable.strings ; \
        done
-       @echo -e "\n\n####################################################################\n#"
-       @echo -e "#                       PLEASE READ THIS BOX!\n#"
-       @echo -e "#   To manually start the smartd daemon, run:\n#   ${initddir}/SMART/SMART start\n#"
-       @echo -e "#   To automatically start smartd on bootup, add the line:\n#   SMARTd=-YES-\n#   to /etc/hostconfig\n#"
-       @echo -e "#   smartd can now use a configuration file ${sysconfdir}/smartd.conf. Do:\n#   man smartd"
-       @echo -e "#   to learn about it. A sample configuration file can be found in:\n#   ${docdir}\n#"
-       @echo -e "####################################################################\n\n"
 
 uninstall-initdDATA-darwin:
        rm -rf $(DESTDIR)$(initddir)/$(initd_install_name)
@@ -417,13 +465,6 @@ initd_DATA_uninstall = uninstall-initdDATA-generic
 install-initdDATA-generic: $(initd_DATA)
        $(mkinstalldirs) $(DESTDIR)$(initddir)
        $(INSTALL_SCRIPT) $(top_builddir)/smartd.initd $(DESTDIR)$(initddir)/smartd$(smartd_suffix)
-       @echo -e "\n\n####################################################################\n#"
-       @echo -e "#                       PLEASE READ THIS BOX!\n#"
-       @echo -e "#   To manually start the smartd daemon, run:\n#   ${initddir}/smartd start\n#"
-       @echo -e "#   To automatically start smartd on bootup, run:\n#   /sbin/chkconfig --add smartd\n#"
-       @echo -e "#   smartd can now use a configuration file ${sysconfdir}/smartd.conf. Do:\n#   man smartd"
-       @echo -e "#   to learn about it. A sample configuration file can be found in:\n#   ${docdir}\n#"
-       @echo -e "####################################################################\n\n"
 
 
 uninstall-initdDATA-generic:
@@ -473,7 +514,9 @@ MAN_FILTER = \
          s|/usr/local/share/man/|$(mandir)/|g; \
          s|/usr/local/sbin/|$(sbindir)/|g; \
          s|/usr/local/etc/rc\\.d/init.d/|$(initddir)/|g; \
-         s|/usr/local/share/doc/smartmontools/|$(docsdir)/|g;  \
+         s|/usr/local/share/doc/smartmontools/examplescripts/|!exampledir!|g; \
+         s|/usr/local/share/doc/smartmontools/|$(docsdir)/|g; \
+         s|!exampledir!|$(exampledir)/|g; \
          s|/usr/local/etc/smartd\\.conf|$(sysconfdir)/smartd.conf|g; \
          s|/usr/local/etc/smart_drivedb\\.h|$(sysconfdir)/smart_drivedb\\.h|g" | \
     $(MAN_CAPABILITIES) | \
@@ -558,28 +601,54 @@ distinst_win32 = $(PACKAGE)-$(VERSION).win$(win_bits)-setup.exe
 exedir_win32 = $(distdir_win32)/bin
 docdir_win32 = $(distdir_win32)/doc
 
-FILES_WIN32 = $(exedir_win32)/smartctl.exe \
-              $(exedir_win32)/smartctl-nc.exe \
-              $(exedir_win32)/smartd.exe \
-              $(docdir_win32)/AUTHORS.txt \
-              $(docdir_win32)/CHANGELOG.txt \
-              $(docdir_win32)/COPYING.txt \
-              $(docdir_win32)/INSTALL.txt \
-              $(docdir_win32)/NEWS.txt \
-              $(docdir_win32)/README.txt \
-              $(docdir_win32)/TODO.txt \
-              $(docdir_win32)/WARNINGS.txt \
-              $(docdir_win32)/smartd.conf \
-              $(docdir_win32)/smartctl.8.html \
-              $(docdir_win32)/smartctl.8.txt \
-              $(docdir_win32)/smartd.8.html \
-              $(docdir_win32)/smartd.8.txt \
-              $(docdir_win32)/smartd.conf.5.html \
-              $(docdir_win32)/smartd.conf.5.txt
-
-CLEANFILES += $(FILES_WIN32) $(exedir_win32)/syslogevt.exe \
-              smartctl-nc.exe smartctl-nc.exe.tmp \
-              distdir.mkdir syslogevt.check
+EXEFILES_WIN32 = \
+        $(exedir_win32)/smartctl.exe \
+        $(exedir_win32)/smartctl-nc.exe \
+        $(exedir_win32)/smartd.exe
+
+if OS_WIN32_WINDMC
+EXEFILES_WIN32 += \
+        $(exedir_win32)/syslogevt.exe
+endif
+
+if ENABLE_DRIVEDB
+if OS_WIN32_NSIS
+EXEFILES_WIN32 += \
+        $(exedir_win32)/update-smart-drivedb.exe
+endif
+endif
+
+FILES_WIN32 = \
+        $(EXEFILES_WIN32) \
+        $(docdir_win32)/AUTHORS.txt \
+        $(docdir_win32)/CHANGELOG.txt \
+        $(docdir_win32)/COPYING.txt \
+        $(docdir_win32)/INSTALL.txt \
+        $(docdir_win32)/NEWS.txt \
+        $(docdir_win32)/README.txt \
+        $(docdir_win32)/TODO.txt \
+        $(docdir_win32)/WARNINGS.txt \
+        $(docdir_win32)/checksums.txt \
+        $(docdir_win32)/smartd.conf \
+        $(docdir_win32)/smartctl.8.html \
+        $(docdir_win32)/smartctl.8.txt \
+        $(docdir_win32)/smartd.8.html \
+        $(docdir_win32)/smartd.8.txt \
+        $(docdir_win32)/smartd.conf.5.html \
+        $(docdir_win32)/smartd.conf.5.txt
+
+if ENABLE_DRIVEDB
+FILES_WIN32 += \
+        $(exedir_win32)/drivedb.h
+endif
+
+CLEANFILES += \
+        $(FILES_WIN32) \
+        smartctl-nc.exe smartctl-nc.exe.tmp \
+        syslogevt.exe syslogevt.h syslogevt.o \
+        syslogevt.res.o syslogevt.rc syslogevt_*.bin \
+        update-smart-drivedb.exe \
+        distdir.mkdir
 
 # Textfile converter from package cygutils or tofrodos
 # Note: Only use without options to be compatible with both packages
@@ -595,50 +664,59 @@ install-win32: $(distinst_win32)
 
 installer-win32: $(distinst_win32)
 
-distdir-win32: distdir.mkdir $(FILES_WIN32) syslogevt.check
+distdir-win32: distdir.mkdir $(FILES_WIN32)
 
-$(distzip_win32): distdir.mkdir $(FILES_WIN32) syslogevt.check
+$(distzip_win32): distdir.mkdir $(FILES_WIN32)
        @rm -fv $(distzip_win32)
-       cd $(distdir_win32) && zip -9Dr ../$(distzip_win32) .
+       cd $(distdir_win32) && zip -9 ../$(distzip_win32) bin/* doc/*
+       md5sum $@ > $@.md5
+       sha1sum $@ > $@.sha1
+       sha256sum $@ > $@.sha256
 
-# Build NSIS installer, try to locate makensis in default location first
+if OS_WIN32_NSIS
+# Build NSIS installer
 # Note: Only option character '-' is also compatible with Linux version of makensis
-$(distinst_win32): $(srcdir)/os_win32/installer.nsi distdir.mkdir $(FILES_WIN32) syslogevt.check
-       @makensis="$(MAKENSIS)"; if [ -z "$$makensis" ]; then \
-         if [ ! -z "$$PROGRAMFILES" ] && "$$PROGRAMFILES/NSIS/makensis" -VERSION >/dev/null 2>&1; then \
-           makensis="$$PROGRAMFILES/NSIS/makensis"; \
-         elif makensis -VERSION >/dev/null 2>&1; then \
-           makensis=makensis; \
-         else \
-           echo 'makensis: command not found. Please download and install NSIS' 1>&2; \
-           echo 'from http://nsis.sourceforge.net/Download' 1>&2; exit 1; \
-         fi; \
-       fi; \
-       date=`sed -n 's,^.*DATE[^"]*"\([^"]*\)".*$$,\1,p' svnversion.h`; \
+$(distinst_win32): os_win32/installer.nsi distdir.mkdir $(FILES_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=$(distinst_win32) -DVERSTR='$$verstr' $(srcdir)/os_win32/installer.nsi"; \
-       "$$makensis" -V2 -NOCD -DINPDIR="$(distdir_win32)" -DOUTFILE="$(distinst_win32)" -DVERSTR="$$verstr" "$(srcdir)/os_win32/installer.nsi"
+       echo "'$(MAKENSIS)' -V2 -NOCD -DINPDIR=$(distdir_win32) -DOUTFILE=$@ -DVERSTR='$$verstr' $<"; \
+       '$(MAKENSIS)' -V2 -NOCD -DINPDIR=$(distdir_win32) -DOUTFILE=$@ -DVERSTR="$$verstr" $<
+       md5sum $@ > $@.md5
+       sha1sum $@ > $@.sha1
+       sha256sum $@ > $@.sha256
+
+# Build drivedb.h update tool
+update-smart-drivedb.exe: os_win32/update-smart-drivedb.nsi
+       "$(MAKENSIS)" -V2 -NOCD -DBRANCH=$(DRIVEDB_BRANCH) $<
+
+else
+$(distinst_win32):
+       @echo "makensis: command not found. Please install NSIS from http://nsis.sourceforge.net/" 1>&2
+       @exit 1
+endif
 
 cleandist-win32:
-       rm -rf $(distdir_win32) distdir.mkdir syslogevt.check
+       rm -rf $(distdir_win32) distdir.mkdir
 
 distdir.mkdir:
        @test -d $(exedir_win32) || mkdir -pv $(exedir_win32)
        @test -d $(docdir_win32) || mkdir -pv $(docdir_win32)
        touch $@
 
-syslogevt.check:
-       @if [ -f $(srcdir)/os_win32/syslogevt.exe ]; then \
-         cp -pv $(srcdir)/os_win32/syslogevt.exe $(exedir_win32)/syslogevt.exe; \
-        else echo "Warning: $(srcdir)/os_win32/syslogevt.exe missing."; fi
-       touch $@
-
 $(exedir_win32)/%.exe: %.exe
        cp -p $< $@
        if test -n '$(STRIP)'; then $(STRIP) -s $@; else strip -s $@; fi
        touch -r $< $@
 
+# strip would break NSIS integrity check
+$(exedir_win32)/update-smart-drivedb.exe: update-smart-drivedb.exe
+       cp -p $< $@
+
+$(exedir_win32)/%.h: $(srcdir)/%.h
+       $(UNIX2DOS) < $< > $@
+       touch -r $< $@
+
 $(docdir_win32)/%.html: %.html
        $(UNIX2DOS) < $< > $@
        touch -r $< $@
@@ -655,6 +733,10 @@ $(docdir_win32)/%.conf: $(srcdir)/%.conf
        $(UNIX2DOS) < $< > $@
        touch -r $< $@
 
+$(docdir_win32)/checksums.txt: $(EXEFILES_WIN32)
+       (cd $(exedir_win32) && md5sum *.exe && sha1sum *.exe && sha256sum *.exe) \
+       | $(UNIX2DOS) > $@
+
 # Build non-console version of smartctl for GSmartControl.
 # The script below changes the word at offset 220 (Subsystem) from 3
 # (Console) to 2 (GUI) in a copy of smartctl.exe.
@@ -671,19 +753,32 @@ smartctl-nc.exe: smartctl.exe
          else echo "EXE patch failed"; exit 1; fi
        mv -f $@.tmp $@
 
+if OS_WIN32_WINDMC
+# Build syslogevt.exe event message file tool
+
+syslogevt.exe: syslogevt.o syslogevt.res.o
+       $(LINK) $^
+
+syslogevt.o: os_win32/syslogevt.c syslogevt.rc
+       $(CC) -c -I. -Os -o $@ $<
+
+syslogevt.res.o: syslogevt.rc
+       $(WINDRES) $< $@
+
+syslogevt.rc: os_win32/syslogevt.mc
+       $(WINDMC) -b $<
+endif
 
 # Build {config,svnversion}_vc8.h for MSVC8 from MinGW {config,svnversion}.h
 
 config-vc8: $(srcdir)/os_win32/config_vc8.h  $(srcdir)/os_win32/svnversion_vc8.h
 
-$(srcdir)/os_win32/config_vc8.h: config.h
+$(srcdir)/os_win32/config_vc8.h: config.h Makefile
        sed '1i/* config_vc8.h.  Generated from config.h by Makefile.  */' $< | \
-       sed 's,^#define HAVE_\(ATTR_PACKED\|INTTYPES_H\|STDINT_H\|STRINGS_H\|STRTOULL\|U*INT64_T\|UNISTD_H\|WORKING_SNPRINTF\) 1$$,/* #undef HAVE_\1 */,' | \
-       sed 's,i.86-pc-mingw32,i686-pc-win32vc8,' > $@
+       sed 's,^#define HAVE_\(ATTR_PACKED\|INTTYPES_H\|[DK_]*NTDDDISK_H\|STDINT_H\|STRINGS_H\|STRTOULL\|U*INT64_T\|UNISTD_H\|WORKING_SNPRINTF\) 1$$,/* #undef HAVE_\1 */,' | \
+       sed 's,^\(#define SMARTMONTOOLS_BUILD_HOST "[^-]*\)[^"]*,\1-pc-win32vc8,' > $@
 
 $(srcdir)/os_win32/svnversion_vc8.h: svnversion.h
        cp svnversion.h $@
 
 endif
-
-SUBDIRS= . examplescripts
diff --git a/NEWS b/NEWS
index 9c7327558a02f69bf55603bc623dde80e7c96cb2..4921cf04a21d39c8e9c4a85ee56727c5689d06f0 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,32 +1,68 @@
 smartmontools NEWS
 ------------------
-$Id: NEWS 3119 2010-06-11 16:21:25Z chrfranke $
+$Id: NEWS 3296 2011-03-16 22:17:51Z chrfranke $
 
 The most up-to-date version of this file is:
 http://smartmontools.svn.sourceforge.net/viewvc/smartmontools/trunk/smartmontools/NEWS?view=markup
 
 Date <Not released yet, please try current SVN>
+Summary: smartmontools release 5.41
+-----------------------------------------------------------
+- Failed self-tests outdated by a newer successful extended
+  self-test are no longer reported as errors.
+- smartctl prints physical and logical sector sizes.
+- 'smartctl --scan-open' can create a draft smartd.conf.
+- smartd logs identify information of each ATA device.
+- smartd logs warning from drive database if present.
+- smartd directive '-l scterc,READTIME,WRITETIME'.
+- smartd preserves last scheduled selective self-tests span.
+- configure option '--with-exampledir'.
+- 'make install' does no longer overwrite an existing
+  smartd.conf file.
+- 'update-smart-drivedb' does no longer require GNU sed.
+- Linux megaraid: Fix segfault on non-data SCSI commands.
+- Linux megaraid: Fix pass-through of non-data ATA commands.
+- FreeBSD: Use 'fetch' in 'update-smart-drivedb'.
+- OpenBSD: Use 'ftp' in 'update-smart-drivedb'.
+- OpenBSD: Workaround for shell bug.
+- OpenBSD: Fix DEVICESCAN for OpenBSD >= 4.8.
+- Windows: Experimental support for Intel Matrix RAID.
+- Windows: DEVICESCAN includes USB devices.
+- Windows: Faster USB ID detection.
+- Windows: update-smart-drivedb tool.
+- Windows: Add missing quotes in smartctl-run.bat and
+  smartd-run.bat
+
+Date 2010-10-16
 Summary: smartmontools release 5.40
 -----------------------------------------------------------
 - Other config entries may precede smartd DEVICESCAN.
 - Option '-v' allows to specify byte order of attribute raw value
 - configure: New default value for '--with-docdir'.
+- configure: '--enable-drivedb' is now the default.
+- Improved support for Intel SSDs.
+- Improved support for SandForce based SSDs.
 - Drive database is in a separate source file 'drivedb.h'
   which can be downloaded from SVN.
 - USB ID info is now included in 'drivedb.h'.
+- Many additions to drive database.
 - New script 'update-smart-drivedb'.
 - smartd libcap-ng support, option '-C, --capabilities'.
 - smartd directive '-l xerror' to check Extended Comprehensive
   SMART Error Log.
 - smartctl option '-l scterc[,...]' to get/set the
   SCT Error Recovery Control time limit.
+- smartctl option '-t vendor,N'.
 - smartctl options '--scan, --scan-open'.
 - Linux: Add '/dev/sd[a-c][a-z]' to smartd DEVICESCAN.
+- Linux: Support SATA drives on LSI 3ware 9750 controllers.
 - Windows: Read 'drivedb.h' and 'smartd.conf' from exe directory.
 - Windows: Support for 64-bit executables.
 - Windows: Support for cross compilation on Linux.
 - Fix regression in smartctl option '-t select,M-N'.
 - Fix SCT temperature table commands on big endian CPUs.
+- Fix regression in smartd SMARTD_DEVICE and SMARTD_DEVICETYPE
+  environment variables.
 
 Date 2010-01-28
 Summary: smartmontools release 5.39.1
diff --git a/TODO b/TODO
index caa27ef9ac1980e82e11c3cfb06c76779eaac265..22d63583ac838d8cfb66a717c46ff0bf9827567a 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,56 +1,4 @@
-TODO list for smartmontools:
+$Id: TODO 3175 2010-10-02 14:34:09Z chrfranke $
 
-$Id: TODO 3006 2009-12-19 21:04:17Z chrfranke $
-
-See also the list of active tickets:
-http://sourceforge.net/apps/trac/smartmontools/report/1
-
-USB devices under Linux
------------------------
-Some USB devices can hang smartctl or smartd.  This is because these
-devices fail to comply with SCSI specifications for their packet
-command sets.  Work on improving the detection and bail-out procedures
-for these flawed devices, so that the user sees an informative error
-message and smartd/smartctl don't hang.
-
-ATA-8
------
-Add ability to print counters/values from "Device Statistics" pages
-(General Purpose Log address 0x04).
-See ATA ACS-2 T13/2015-D Revision 1, Section A.5.
-
-smartctl: 
----------
-Parse and print additional Attribute flag meanings (IBM ones, eg
-performance etc).  These are now documented in atacmds.h -- we just
-need to modify the format of the Attribute table.
-
-Modify the SMART self-test log table printing so that we ALSO print
-the value of the self-test failure checkpoint byte, if it's one of the
-recognized values.  See routine SelfTestFailureCodeName and
-documentation in atacmds.h.
-
-smartd:
--------
-Perhaps change <nomailer> special argument to -m to have also
-<nomailer_fork> which would actually work with -M exec to run the
-executable/script in the background rather than in the foreground.
-But let's wait for someone to request this. At that point we should
-probably use fork/exec rather than system().
-
-Add ability to monitor "worst" value from attributes (sometimes it
-gets larger!) and to monitor the threshold value (sometimes it
-changes!).
-
-Add command line option that scans devices then WRITES
-/etc/smartd.conf, perhaps as /etc/smartd.conf.output, just for devices
-that can be monitored.
-
-Packaging
----------
-Under freebsd and solaris, the following are wrong:
-smartd.conf: has linux device paths
-smart*.in  : man pages have (mostly) linux device paths
-
-configure packages with --enable-drivedb (?)
-configure packages with --enable-savestates (?)
+This file is no longer maintained, please use the ticket reports:
+http://sourceforge.net/apps/trac/smartmontools/report
index 807300fb8b61f739ee0eabf2a6442f1bb232dcf0..90095b02bf8f68a6e3e7c5bb35c50e52c5a1f3cb 100644 (file)
@@ -3,8 +3,8 @@
  * 
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2002-10 Bruce Allen <smartmontools-support@lists.sourceforge.net>
- * Copyright (C) 2008-10 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2008-11 Christian Franke <smartmontools-support@lists.sourceforge.net>
  * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
  * Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org>
  *
 #include "config.h"
 #include "int64.h"
 #include "atacmds.h"
-#include "extern.h"
 #include "utility.h"
 #include "dev_ata_cmd_set.h" // for parsed_ata_device
 
-const char * atacmds_cpp_cvsid = "$Id: atacmds.cpp 3117 2010-06-08 15:41:04Z chrfranke $"
+const char * atacmds_cpp_cvsid = "$Id: atacmds.cpp 3288 2011-03-09 18:40:36Z chrfranke $"
                                  ATACMDS_H_CVSID;
 
-// for passing global control variables
-extern smartmonctrl *con;
+// Print ATA debug messages?
+unsigned char ata_debugmode = 0;
+
+// Suppress serial number?
+// (also used in scsiprint.cpp)
+bool dont_print_serial_number = false;
+
 
 #define SMART_CYL_LOW  0x4F
 #define SMART_CYL_HI   0xC2
@@ -147,6 +151,10 @@ static const int actual_ver[] = {
   6             /* 0x0022       WARNING:        */
 };
 
+// Compile time check of above array sizes
+typedef char assert_sizeof_minor_str [sizeof(minor_str) /sizeof(minor_str[0])  == MINOR_MAX+1 ? 1 : -1];
+typedef char assert_sizeof_actual_ver[sizeof(actual_ver)/sizeof(actual_ver[0]) == MINOR_MAX+1 ? 1 : -1];
+
 // Get ID and increase flag of current pending or offline
 // uncorrectable attribute.
 unsigned char get_unc_attr_id(bool offline, const ata_vendor_attr_defs & defs,
@@ -208,10 +216,12 @@ const format_name_entry format_names[] = {
   {"hex64"          , RAWFMT_HEX64},
   {"raw16(raw16)"   , RAWFMT_RAW16_OPT_RAW16},
   {"raw16(avg16)"   , RAWFMT_RAW16_OPT_AVG16},
-  {"raw24/raw24"    , RAWFMT_RAW24_RAW24},
+  {"raw24/raw24"    , RAWFMT_RAW24_DIV_RAW24},
+  {"raw24/raw32"    , RAWFMT_RAW24_DIV_RAW32},
   {"sec2hour"       , RAWFMT_SEC2HOUR},
   {"min2hour"       , RAWFMT_MIN2HOUR},
   {"halfmin2hour"   , RAWFMT_HALFMIN2HOUR},
+  {"msec24hour32"   , RAWFMT_MSEC24_HOUR32},
   {"tempminmax"     , RAWFMT_TEMPMINMAX},
   {"temp10x"        , RAWFMT_TEMP10X},
 };
@@ -421,7 +431,7 @@ static const char * preg(const ata_register & r, char * buf)
   sprintf(buf, "0x%02x", r.val()); return buf;
 }
 
-void print_regs(const char * prefix, const ata_in_regs & r, const char * suffix = "\n")
+static void print_regs(const char * prefix, const ata_in_regs & r, const char * suffix = "\n")
 {
   char bufs[7][4+1+13];
   pout("%s FR=%s, SC=%s, LL=%s, LM=%s, LH=%s, DEV=%s, CMD=%s%s", prefix,
@@ -430,7 +440,7 @@ void print_regs(const char * prefix, const ata_in_regs & r, const char * suffix
     preg(r.command, bufs[6]), suffix);
 }
 
-void print_regs(const char * prefix, const ata_out_regs & r, const char * suffix = "\n")
+static void print_regs(const char * prefix, const ata_out_regs & r, const char * suffix = "\n")
 {
   char bufs[7][4+1+13];
   pout("%sERR=%s, SC=%s, LL=%s, LM=%s, LH=%s, DEV=%s, STS=%s%s", prefix,
@@ -474,7 +484,7 @@ int smartcommandhandler(ata_device * device, smart_command_set command, int sele
   int sendsdata=(command==WRITE_LOG);
   
   // If reporting is enabled, say what the command will be before it's executed
-  if (con->reportataioctl){
+  if (ata_debugmode) {
           // conditional is true for commands that use parameters
           int usesparam=(command==READ_LOG || 
                          command==AUTO_OFFLINE || 
@@ -506,7 +516,7 @@ int smartcommandhandler(ata_device * device, smart_command_set command, int sele
 
 
   // if requested, pretty-print the input data structure
-  if (con->reportataioctl>1 && sendsdata)
+  if (ata_debugmode > 1 && sendsdata)
     //pout("REPORT-IOCTL: Device=%s Command=%s\n", device->get_dev_name(), commandstrings[command]);
     prettyprint((unsigned char *)data, commandstrings[command]);
 
@@ -589,7 +599,7 @@ int smartcommandhandler(ata_device * device, smart_command_set command, int sele
         return -1;
     }
 
-    if (con->reportataioctl)
+    if (ata_debugmode)
       print_regs(" Input:  ", in.in_regs,
         (in.direction==ata_cmd_in::data_in ? " IN\n":
          in.direction==ata_cmd_in::data_out ? " OUT\n":"\n"));
@@ -597,7 +607,7 @@ int smartcommandhandler(ata_device * device, smart_command_set command, int sele
     ata_cmd_out out;
     bool ok = device->ata_pass_through(in, out);
 
-    if (con->reportataioctl && out.out_regs.is_set())
+    if (ata_debugmode && out.out_regs.is_set())
       print_regs(" Output: ", out.out_regs);
 
     if (ok) switch (command) {
@@ -619,12 +629,12 @@ int smartcommandhandler(ata_device * device, smart_command_set command, int sele
           retval = 1;
         else if (out.out_regs.lba_mid == SMART_CYL_LOW) {
           retval = 0;
-          if (con->reportataioctl)
+          if (ata_debugmode)
             pout("SMART STATUS RETURN: half healthy response sequence, "
                  "probable SAT/USB truncation\n");
           } else if (out.out_regs.lba_mid == SRET_STATUS_MID_EXCEEDED) {
           retval = 1;
-          if (con->reportataioctl)
+          if (ata_debugmode)
             pout("SMART STATUS RETURN: half unhealthy response sequence, "
                  "probable SAT/USB truncation\n");
         } else {
@@ -641,11 +651,11 @@ int smartcommandhandler(ata_device * device, smart_command_set command, int sele
   }
 
   // If requested, invalidate serial number before any printing is done
-  if ((command == IDENTIFY || command == PIDENTIFY) && !retval && con->dont_print_serial)
+  if ((command == IDENTIFY || command == PIDENTIFY) && !retval && dont_print_serial_number)
     invalidate_serno((ata_identify_device *)data);
 
   // If reporting is enabled, say what output was produced by the command
-  if (con->reportataioctl){
+  if (ata_debugmode) {
     if (device->get_errno())
       pout("REPORT-IOCTL: Device=%s Command=%s returned %d errno=%d [%s]\n",
            device->get_dev_name(), commandstrings[command], retval,
@@ -655,7 +665,7 @@ int smartcommandhandler(ata_device * device, smart_command_set command, int sele
            device->get_dev_name(), commandstrings[command], retval);
     
     // if requested, pretty-print the output data structure
-    if (con->reportataioctl>1 && getsdata) {
+    if (ata_debugmode > 1 && getsdata) {
       if (command==CHECK_POWER_MODE)
        pout("Sector Count Register (BASE-16): %02x\n", (unsigned char)(*data));
       else
@@ -750,11 +760,12 @@ static void trim(char * out, const char * in)
 }
 
 // Convenience function for formatting strings from ata_identify_device
-void format_ata_string(char * out, const char * in, int n, bool fix_swap)
+void ata_format_id_string(char * out, const unsigned char * in, int n)
 {
-  bool must_swap = !fix_swap;
+  bool must_swap = true;
 #ifdef __NetBSD__
   /* NetBSD kernel delivers IDENTIFY data in host byte order (but all else is LE) */
+  // TODO: Handle NetBSD case in os_netbsd.cpp
   if (isbigendian())
     must_swap = !must_swap;
 #endif
@@ -762,9 +773,9 @@ void format_ata_string(char * out, const char * in, int n, bool fix_swap)
   char tmp[65];
   n = n > 64 ? 64 : n;
   if (!must_swap)
-    strncpy(tmp, in, n);
+    strncpy(tmp, (const char *)in, n);
   else
-    swapbytes(tmp, in, n);
+    swapbytes(tmp, (const char *)in, n);
   tmp[n] = '\0';
   trim(out, tmp);
 }
@@ -796,23 +807,37 @@ int ataCheckPowerMode(ata_device * device) {
 // capable).  The value of the integer helps identify the type of
 // Packet device, which is useful so that the user can connect the
 // formal device number with whatever object is inside their computer.
-int ataReadHDIdentity (ata_device * device, struct ata_identify_device *buf){
+int ata_read_identity(ata_device * device, ata_identify_device * buf, bool fix_swapped_id)
+{
   unsigned short *rawshort=(unsigned short *)buf;
   unsigned char  *rawbyte =(unsigned char  *)buf;
 
   // See if device responds either to IDENTIFY DEVICE or IDENTIFY
   // PACKET DEVICE
+  bool packet = false;
   if ((smartcommandhandler(device, IDENTIFY, 0, (char *)buf))){
     if (smartcommandhandler(device, PIDENTIFY, 0, (char *)buf)){
       return -1; 
     }
+    packet = true;
+  }
+
+  unsigned i;
+  if (fix_swapped_id) {
+    // Swap ID strings
+    for (i = 0; i < sizeof(buf->serial_no)-1; i += 2)
+      swap2((char *)(buf->serial_no+i));
+    for (i = 0; i < sizeof(buf->fw_rev)-1; i += 2)
+      swap2((char *)(buf->fw_rev+i));
+    for (i = 0; i < sizeof(buf->model)-1; i += 2)
+      swap2((char *)(buf->model+i));
   }
 
 #ifndef __NetBSD__
   // if machine is big-endian, swap byte order as needed
   // NetBSD kernel delivers IDENTIFY data in host byte order
+  // TODO: Handle NetBSD case in os_netbsd.cpp
   if (isbigendian()){
-    int i;
     
     // swap various capability words that are needed
     for (i=0; i<33; i++)
@@ -829,7 +854,31 @@ int ataReadHDIdentity (ata_device * device, struct ata_identify_device *buf){
   // If there is a checksum there, validate it
   if ((rawshort[255] & 0x00ff) == 0x00a5 && checksum(rawbyte))
     checksumwarning("Drive Identity Structure");
-  
+
+  // AT Attachment 8 - ATA/ATAPI Command Set (ATA8-ACS)
+  // T13/1699-D Revision 6a (Final Draft), September 6, 2008.
+  // Sections 7.16.7 and 7.17.6:
+  //
+  // Word 0 of IDENTIFY DEVICE data:
+  // Bit 15 = 0 : ATA device
+  //
+  // Word 0 of IDENTIFY PACKET DEVICE data:
+  // Bits 15:14 = 10b : ATAPI device
+  // Bits 15:14 = 11b : Reserved
+  // Bits 12:8        : Device type (SPC-4, e.g 0x05 = CD/DVD)
+
+  // CF+ and CompactFlash Specification Revision 4.0, May 24, 2006.
+  // Section 6.2.1.6:
+  //
+  // Word 0 of IDENTIFY DEVICE data:
+  // 848Ah = Signature for CompactFlash Storage Card
+  // 044Ah = Alternate value turns on ATA device while preserving all retired bits
+  // 0040h = Alternate value turns on ATA device while zeroing all retired bits
+
+  // Assume ATA if IDENTIFY DEVICE returns CompactFlash Signature
+  if (!packet && rawbyte[1] == 0x84 && rawbyte[0] == 0x8a)
+    return 0;
+
   // If this is a PACKET DEVICE, return device type
   if (rawbyte[1] & 0x80)
     return 1+(rawbyte[1] & 0x1f);
@@ -844,23 +893,6 @@ int ataReadHDIdentity (ata_device * device, struct ata_identify_device *buf){
 // the version number.  See notes above.
 int ataVersionInfo(const char ** description, const ata_identify_device * drive, unsigned short * minor)
 {
-  // check that arrays at the top of this file are defined
-  // consistently
-  if (sizeof(minor_str) != sizeof(char *)*(1+MINOR_MAX)){
-    pout("Internal error in ataVersionInfo().  minor_str[] size %d\n"
-         "is not consistent with value of MINOR_MAX+1 = %d\n", 
-         (int)(sizeof(minor_str)/sizeof(char *)), MINOR_MAX+1);
-    fflush(NULL);
-    abort();
-  }
-  if (sizeof(actual_ver) != sizeof(int)*(1+MINOR_MAX)){
-    pout("Internal error in ataVersionInfo().  actual_ver[] size %d\n"
-         "is not consistent with value of MINOR_MAX = %d\n",
-         (int)(sizeof(actual_ver)/sizeof(int)), MINOR_MAX+1);
-    fflush(NULL);
-    abort();
-  }
-
   // get major and minor ATA revision numbers
   unsigned short major = drive->major_rev_num;
   *minor=drive->minor_rev_num;
@@ -880,18 +912,21 @@ int ataVersionInfo(const char ** description, const ata_identify_device * drive,
     }
   }
 
-  // Try new ATA-8 minor revision numbers (Table 31 of T13/1699-D Revision 6)
+  // Try new ATA-8 ACS minor revision numbers.
+  // Table 55 of T13/2015-D Revision 4a (ACS-2), December 9, 2010.
   // (not in actual_ver/minor_str to avoid large sparse tables)
   const char *desc;
   switch (*minor) {
     case 0x0027: desc = "ATA-8-ACS revision 3c"; break;
     case 0x0028: desc = "ATA-8-ACS revision 6"; break;
     case 0x0029: desc = "ATA-8-ACS revision 4"; break;
+    case 0x0031: desc = "ACS-2 revision 2"; break;
     case 0x0033: desc = "ATA-8-ACS revision 3e"; break;
     case 0x0039: desc = "ATA-8-ACS revision 4c"; break;
     case 0x0042: desc = "ATA-8-ACS revision 3f"; break;
     case 0x0052: desc = "ATA-8-ACS revision 3b"; break;
     case 0x0107: desc = "ATA-8-ACS revision 2d"; break;
+    case 0x0110: desc = "ACS-2 revision 3"; break;
     default:     desc = 0; break;
   }
   if (desc) {
@@ -1168,7 +1203,8 @@ int ataReadSelectiveSelfTestLog(ata_device * device, struct ata_selective_self_t
 
 // Writes the selective self-test log (log #9)
 int ataWriteSelectiveSelfTestLog(ata_device * device, ata_selective_selftest_args & args,
-                                 const ata_smart_values * sv, uint64_t num_sectors)
+                                 const ata_smart_values * sv, uint64_t num_sectors,
+                                 const ata_selective_selftest_args * prev_args)
 {
   // Disk size must be known
   if (!num_sectors) {
@@ -1212,6 +1248,17 @@ int ataWriteSelectiveSelfTestLog(ata_device * device, ata_selective_selftest_arg
           break;
       }
     }
+
+    if (   (mode == SEL_REDO || mode == SEL_NEXT)
+        && prev_args && i < prev_args->num_spans
+        && !data->span[i].start && !data->span[i].end) {
+      // Some drives do not preserve the selective self-test log accross
+      // power-cyles.  If old span on drive is cleared use span provided
+      // by caller.  This is used by smartd (first span only).
+      data->span[i].start = prev_args->span[i].start;
+      data->span[i].end   = prev_args->span[i].end;
+    }
+
     switch (mode) {
       case SEL_RANGE: // -t select,START-END
         break;
@@ -1312,9 +1359,9 @@ int ataWriteSelectiveSelfTestLog(ata_device * device, ata_selective_selftest_arg
   // swap endian order if needed
   if (isbigendian()){
     swap2((char *)&(data->logversion));
-    for (int i=0;i<5;i++){
-      swap8((char *)&(data->span[i].start));
-      swap8((char *)&(data->span[i].end));
+    for (int b = 0; b < 5; b++) {
+      swap8((char *)&(data->span[b].start));
+      swap8((char *)&(data->span[b].end));
     }
     swap8((char *)&(data->currentlba));
     swap2((char *)&(data->currentspan));
@@ -1557,7 +1604,7 @@ int ataSmartTest(ata_device * device, int testtype, const ata_selective_selftest
   else if ((select=(testtype==SELECTIVE_SELF_TEST || testtype==SELECTIVE_CAPTIVE_SELF_TEST)))
     type="Selective self-test";
   else
-    type="[Unrecognized] self-test";
+    type = 0;
   
   // If doing a selective self-test, first use WRITE_LOG to write the
   // selective self-test log.
@@ -1571,6 +1618,8 @@ int ataSmartTest(ata_device * device, int testtype, const ata_selective_selftest
   //  Print ouf message that we are sending the command to test
   if (testtype==ABORT_SELF_TEST)
     sprintf(cmdmsg,"Abort SMART off-line mode self-test routine");
+  else if (!type)
+    sprintf(cmdmsg, "SMART EXECUTE OFF-LINE IMMEDIATE subcommand 0x%02x", testtype);
   else
     sprintf(cmdmsg,"Execute SMART %s routine immediately in %s mode",type,captive);
   pout("Sending command: \"%s\".\n",cmdmsg);
@@ -1598,8 +1647,11 @@ int ataSmartTest(ata_device * device, int testtype, const ata_selective_selftest
   // Since the command succeeded, tell user
   if (testtype==ABORT_SELF_TEST)
     pout("Self-testing aborted!\n");
-  else
-    pout("Drive command \"%s\" successful.\nTesting has begun.\n",cmdmsg);
+  else {
+    pout("Drive command \"%s\" successful.\n", cmdmsg);
+    if (type)
+      pout("Testing has begun.\n");
+  }
   return 0;
 }
 
@@ -1736,8 +1788,10 @@ int isSupportSelectiveSelfTest(const ata_smart_values * data)
 
 // Get attribute state
 ata_attr_state ata_get_attr_state(const ata_smart_attribute & attr,
-                                  const ata_smart_threshold_entry & thre,
-                                  const ata_vendor_attr_defs & defs)
+                                  int attridx,
+                                  const ata_smart_threshold_entry * thresholds,
+                                  const ata_vendor_attr_defs & defs,
+                                  unsigned char * threshval /* = 0 */)
 {
   if (!attr.id)
     return ATTRSTATE_NON_EXISTING;
@@ -1748,27 +1802,35 @@ ata_attr_state ata_get_attr_state(const ata_smart_attribute & attr,
   if (defs[attr.id].flags & ATTRFLAG_NO_NORMVAL)
     return ATTRSTATE_NO_NORMVAL;
 
-  // No threshold if thresholds cannot be read.
-  if (!thre.id && !thre.threshold)
-    return ATTRSTATE_NO_THRESHOLD;
+  // Normally threshold is at same index as attribute
+  int i = attridx;
+  if (thresholds[i].id != attr.id) {
+    // Find threshold id in table
+    for (i = 0; thresholds[i].id != attr.id; ) {
+      if (++i >= NUMBER_ATA_SMART_ATTRIBUTES)
+        // Threshold id missing or thresholds cannot be read
+        return ATTRSTATE_NO_THRESHOLD;
+    }
+  }
+  unsigned char threshold = thresholds[i].threshold;
 
-  // Bad threshold if id's don't match
-  if (attr.id != thre.id)
-    return ATTRSTATE_BAD_THRESHOLD;
+  // Return threshold if requested
+  if (threshval)
+    *threshval = threshold;
 
   // Don't report a failed attribute if its threshold is 0.
   // ATA-3 (X3T13/2008D Revision 7b) declares 0x00 as the "always passing"
   // threshold (Later ATA versions declare all thresholds as "obsolete").
   // In practice, threshold value 0 is often used for usage attributes.
-  if (!thre.threshold)
+  if (!threshold)
     return ATTRSTATE_OK;
 
   // Failed now if current value is below threshold
-  if (attr.current <= thre.threshold)
+  if (attr.current <= threshold)
     return ATTRSTATE_FAILED_NOW;
 
   // Failed in the past if worst value is below threshold
-  if (!(defs[attr.id].flags & ATTRFLAG_NO_WORSTVAL) && attr.worst <= thre.threshold)
+  if (!(defs[attr.id].flags & ATTRFLAG_NO_WORSTVAL) && attr.worst <= threshold)
     return ATTRSTATE_FAILED_PAST;
 
   return ATTRSTATE_OK;
@@ -1803,10 +1865,16 @@ uint64_t ata_get_attr_raw_value(const ata_smart_attribute & attr,
   // Use default byteorder if not specified
   const char * byteorder = def.byteorder;
   if (!*byteorder) {
-    if (def.raw_format == RAWFMT_RAW64 || def.raw_format == RAWFMT_HEX64)
-      byteorder = "543210wv";
-    else
-      byteorder = "543210";
+    switch (def.raw_format) {
+      case RAWFMT_RAW64:
+      case RAWFMT_HEX64:
+        byteorder = "543210wv"; break;
+      case RAWFMT_RAW24_DIV_RAW32:
+      case RAWFMT_MSEC24_HOUR32:
+        byteorder = "r543210"; break;
+      default:
+        byteorder = "543210"; break;
+    }
   }
 
   // Build 64-bit value from selected bytes
@@ -1840,6 +1908,7 @@ std::string ata_format_attr_raw_value(const ata_smart_attribute & attr,
   uint64_t rawvalue = ata_get_attr_raw_value(attr, defs);
 
   // Get 16 bit words
+  // TODO: rebuild raw[6] from rawvalue
   const unsigned char * raw = attr.raw;
   unsigned word[3];
   word[0] = raw[0] | (raw[1] << 8);
@@ -1888,10 +1957,14 @@ std::string ata_format_attr_raw_value(const ata_smart_attribute & attr,
       s += strprintf(" (Average %u)", word[1]);
     break;
 
-  case RAWFMT_RAW24_RAW24:
-    s = strprintf("%d/%d",
-      raw[0] | (raw[1]<<8) | (raw[2]<<16),
-      raw[3] | (raw[4]<<8) | (raw[5]<<16));
+  case RAWFMT_RAW24_DIV_RAW24:
+    s = strprintf("%u/%u",
+      (unsigned)(rawvalue >> 24), (unsigned)(rawvalue & 0x00ffffffULL));
+    break;
+
+  case RAWFMT_RAW24_DIV_RAW32:
+    s = strprintf("%u/%u",
+      (unsigned)(rawvalue >> 32), (unsigned)(rawvalue & 0xffffffffULL));
     break;
 
   case RAWFMT_MIN2HOUR:
@@ -1925,6 +1998,17 @@ std::string ata_format_attr_raw_value(const ata_smart_attribute & attr,
     }
     break;
 
+  case RAWFMT_MSEC24_HOUR32:
+    {
+      // hours + milliseconds
+      unsigned hours = (unsigned)(rawvalue & 0xffffffffULL);
+      unsigned milliseconds = (unsigned)(rawvalue >> 32);
+      unsigned seconds = milliseconds / 1000;
+      s = strprintf("%uh+%02um+%02u.%03us",
+        hours, seconds / 60, seconds % 60, milliseconds % 1000);
+    }
+    break;
+
   case RAWFMT_TEMPMINMAX:
     // Temperature
     s = strprintf("%u", word[0]);
@@ -1942,7 +2026,7 @@ std::string ata_format_attr_raw_value(const ata_smart_attribute & attr,
         unsigned t = lo; lo = hi; hi = t;
       }
       if (lo <= word[0] && word[0] <= hi)
-        s += strprintf(" (Lifetime Min/Max %u/%u)", lo, hi);
+        s += strprintf(" (Min/Max %u/%u)", lo, hi);
       else
         s += strprintf(" (%d %d %d %d)", raw[5], raw[4], raw[3], raw[2]);
     }
@@ -2364,7 +2448,8 @@ static int ataGetSetSCTErrorRecoveryControltime(ata_device * device, unsigned ty
 
   ata_cmd_out out;
   if (!device->ata_pass_through(in, out)) {
-    pout("Error Write SCT Error Recovery Control Command failed: %s\n", device->get_errmsg());
+    pout("Error Write SCT (%cet) Error Recovery Control Command failed: %s\n",
+      (!set ? 'G' : 'S'), device->get_errmsg());
     return -1;
   }
 
@@ -2407,14 +2492,34 @@ int ataSetSCTErrorRecoveryControltime(ata_device * device, unsigned type, unsign
 
 
 // Print one self-test log entry.
-// Returns true if self-test showed an error.
-bool ataPrintSmartSelfTestEntry(unsigned testnum, unsigned char test_type,
-                                unsigned char test_status,
-                                unsigned short timestamp,
-                                uint64_t failing_lba,
-                                bool print_error_only, bool & print_header)
-{
-  const char * msgtest;
+// Returns:
+// -1: self-test failed
+//  1: extended self-test completed without error
+//  0: otherwise
+int ataPrintSmartSelfTestEntry(unsigned testnum, unsigned char test_type,
+                               unsigned char test_status,
+                               unsigned short timestamp,
+                               uint64_t failing_lba,
+                               bool print_error_only, bool & print_header)
+{
+  // Check status and type for return value
+  int retval = 0;
+  switch (test_status >> 4) {
+    case 0x0:
+      if ((test_type & 0x0f) == 0x02)
+        retval = 1; // extended self-test completed without error
+      break;
+    case 0x3: case 0x4:
+    case 0x5: case 0x6:
+    case 0x7: case 0x8:
+      retval = -1; // self-test failed
+      break;
+  }
+
+  if (retval >= 0 && print_error_only)
+    return retval;
+
+  std::string msgtest;
   switch (test_type) {
     case 0x00: msgtest = "Offline";            break;
     case 0x01: msgtest = "Short offline";      break;
@@ -2428,30 +2533,26 @@ bool ataPrintSmartSelfTestEntry(unsigned testnum, unsigned char test_type,
     case 0x84: msgtest = "Selective captive";  break;
     default:
       if ((0x40 <= test_type && test_type <= 0x7e) || 0x90 <= test_type)
-        msgtest = "Vendor offline";
+        msgtest = strprintf("Vendor (0x%02x)", test_type);
       else
-        msgtest = "Reserved offline";
+        msgtest = strprintf("Reserved (0x%02x)", test_type);
   }
 
-  bool is_error = false;
-  const char * msgstat;
+  std::string msgstat;
   switch (test_status >> 4) {
     case 0x0: msgstat = "Completed without error";       break;
     case 0x1: msgstat = "Aborted by host";               break;
     case 0x2: msgstat = "Interrupted (host reset)";      break;
-    case 0x3: msgstat = "Fatal or unknown error";        is_error = true; break;
-    case 0x4: msgstat = "Completed: unknown failure";    is_error = true; break;
-    case 0x5: msgstat = "Completed: electrical failure"; is_error = true; break;
-    case 0x6: msgstat = "Completed: servo/seek failure"; is_error = true; break;
-    case 0x7: msgstat = "Completed: read failure";       is_error = true; break;
-    case 0x8: msgstat = "Completed: handling damage??";  is_error = true; break;
+    case 0x3: msgstat = "Fatal or unknown error";        break;
+    case 0x4: msgstat = "Completed: unknown failure";    break;
+    case 0x5: msgstat = "Completed: electrical failure"; break;
+    case 0x6: msgstat = "Completed: servo/seek failure"; break;
+    case 0x7: msgstat = "Completed: read failure";       break;
+    case 0x8: msgstat = "Completed: handling damage??";  break;
     case 0xf: msgstat = "Self-test routine in progress"; break;
-    default:  msgstat = "Unknown/reserved test status";
+    default:  msgstat = strprintf("Unknown status (0x%x)", test_status >> 4);
   }
 
-  if (!is_error && print_error_only)
-    return false;
-
   // Print header once
   if (print_header) {
     print_header = false;
@@ -2459,15 +2560,15 @@ bool ataPrintSmartSelfTestEntry(unsigned testnum, unsigned char test_type,
   }
 
   char msglba[32];
-  if (is_error && failing_lba < 0xffffffffffffULL)
+  if (retval < 0 && failing_lba < 0xffffffffffffULL)
     snprintf(msglba, sizeof(msglba), "%"PRIu64, failing_lba);
   else
     strcpy(msglba, "-");
 
-  pout("#%2u  %-19s %-29s %1d0%%  %8u         %s\n", testnum, msgtest, msgstat,
-       test_status & 0x0f, timestamp, msglba);
+  pout("#%2u  %-19s %-29s %1d0%%  %8u         %s\n", testnum,
+       msgtest.c_str(), msgstat.c_str(), test_status & 0x0f, timestamp, msglba);
 
-  return is_error;
+  return retval;
 }
 
 // Print Smart self-test log, used by smartctl and smartd.
@@ -2488,7 +2589,8 @@ int ataPrintSmartSelfTestlog(const ata_smart_selftestlog * data, bool allentries
   }
 
   bool noheaderprinted = true;
-  int retval=0, hours=0, testno=0;
+  int errcnt = 0, hours = 0, igncnt = 0;
+  int testno = 0, ext_ok_testno = -1;
 
   // print log
   for (int i = 20; i >= 0; i--) {
@@ -2516,24 +2618,38 @@ int ataPrintSmartSelfTestlog(const ata_smart_selftestlog * data, bool allentries
       uint64_t lba48 = (log->lbafirstfailure < 0xffffffff ? log->lbafirstfailure : 0xffffffffffffULL);
 
       // Print entry
-      if (ataPrintSmartSelfTestEntry(testno,
-            log->selftestnumber, log->selfteststatus,
-            log->timestamp, lba48, !allentries, noheaderprinted)) {
+      int state = ataPrintSmartSelfTestEntry(testno,
+        log->selftestnumber, log->selfteststatus,
+        log->timestamp, lba48, !allentries, noheaderprinted);
 
+      if (state < 0) {
         // Self-test showed an error
-        retval++;
+        if (ext_ok_testno < 0) {
+          errcnt++;
 
-        // keep track of time of most recent error
-        if (!hours)
-          hours = log->timestamp;
+          // keep track of time of most recent error
+          if (!hours)
+            hours = log->timestamp;
+        }
+        else
+          // Newer successful extended self-test exits
+          igncnt++;
+      }
+      else if (state > 0 && ext_ok_testno < 0) {
+        // Latest successful extended self-test
+        ext_ok_testno = testno;
       }
     }
   }
-  if (!allentries && retval)
+
+  if (igncnt)
+    pout("%d of %d failed self-tests are outdated by newer successful extended offline self-test #%2d\n",
+      igncnt, igncnt+errcnt, ext_ok_testno);
+
+  if (!allentries && !noheaderprinted)
     pout("\n");
 
-  hours = hours << 8;
-  return (retval | hours);
+  return ((hours << 8) | errcnt);
 }
 
 
@@ -2678,9 +2794,7 @@ bool parsed_ata_device::open()
   ")"; // )
 
   // Compile regex
-  regular_expression regex;
-  if (!regex.compile(pattern, REG_EXTENDED))
-    return set_err(EIO, "invalid regex");
+  const regular_expression regex(pattern, REG_EXTENDED);
 
   // Parse buffer
   const char * errmsg = 0;
index 8dc913a875a023e2af862723f4caa89889bfc362..7730e943f56803485ea4295e53b932fa5cdc18ce 100644 (file)
--- a/atacmds.h
+++ b/atacmds.h
@@ -26,7 +26,7 @@
 #ifndef ATACMDS_H_
 #define ATACMDS_H_
 
-#define ATACMDS_H_CVSID "$Id: atacmds.h 3065 2010-02-10 22:16:50Z chrfranke $"
+#define ATACMDS_H_CVSID "$Id: atacmds.h 3288 2011-03-09 18:40:36Z chrfranke $"
 
 #include "dev_interface.h" // ata_device
 
@@ -660,10 +660,12 @@ enum ata_attr_raw_format
   RAWFMT_HEX64,
   RAWFMT_RAW16_OPT_RAW16,
   RAWFMT_RAW16_OPT_AVG16,
-  RAWFMT_RAW24_RAW24,
+  RAWFMT_RAW24_DIV_RAW24,
+  RAWFMT_RAW24_DIV_RAW32,
   RAWFMT_SEC2HOUR,
   RAWFMT_MIN2HOUR,
   RAWFMT_HALFMIN2HOUR,
+  RAWFMT_MSEC24_HOUR32,
   RAWFMT_TEMPMINMAX,
   RAWFMT_TEMP10X,
 };
@@ -705,8 +707,14 @@ private:
 };
 
 
+// Print ATA debug messages?
+extern unsigned char ata_debugmode;
+
+// Suppress serial number?
+extern bool dont_print_serial_number;
+
 // Get information from drive
-int ataReadHDIdentity(ata_device * device, struct ata_identify_device *buf);
+int ata_read_identity(ata_device * device, ata_identify_device * buf, bool fix_swapped_id);
 int ataCheckPowerMode(ata_device * device);
 
 /* Read S.M.A.R.T information from drive */
@@ -764,7 +772,8 @@ int ataSmartShortCapSelfTest (ata_device * device);
 int ataSmartExtendCapSelfTest (ata_device * device);
 int ataSmartSelfTestAbort (ata_device * device);
 int ataWriteSelectiveSelfTestLog(ata_device * device, ata_selective_selftest_args & args,
-                                 const ata_smart_values * sv, uint64_t num_sectors);
+                                 const ata_smart_values * sv, uint64_t num_sectors,
+                                 const ata_selective_selftest_args * prev_spans = 0);
 
 // Returns the latest compatibility of ATA/ATAPI Version the device
 // supports. Returns -1 if Version command is not supported
@@ -826,7 +835,6 @@ enum ata_attr_state
 {
   ATTRSTATE_NON_EXISTING,   // No such Attribute
   ATTRSTATE_NO_NORMVAL,     // Normalized value not valid
-  ATTRSTATE_BAD_THRESHOLD,  // Threshold not valid
   ATTRSTATE_NO_THRESHOLD,   // Unknown or no threshold
   ATTRSTATE_OK,             // Never failed
   ATTRSTATE_FAILED_PAST,    // Failed in the past
@@ -835,8 +843,10 @@ enum ata_attr_state
 
 // Get attribute state
 ata_attr_state ata_get_attr_state(const ata_smart_attribute & attr,
-                                  const ata_smart_threshold_entry & thre,
-                                  const ata_vendor_attr_defs & defs);
+                                  int attridx,
+                                  const ata_smart_threshold_entry * thresholds,
+                                  const ata_vendor_attr_defs & defs,
+                                  unsigned char * threshval = 0);
 
 // Get attribute raw value.
 uint64_t ata_get_attr_raw_value(const ata_smart_attribute & attr,
@@ -910,11 +920,15 @@ std::string create_vendor_attribute_arg_list();
 int smartcommandhandler(ata_device * device, smart_command_set command, int select, char *data);
 
 // Print one self-test log entry.
-bool ataPrintSmartSelfTestEntry(unsigned testnum, unsigned char test_type,
-                                unsigned char test_status,
-                                unsigned short timestamp,
-                                uint64_t failing_lba,
-                                bool print_error_only, bool & print_header);
+// Returns:
+// -1: failed self-test
+//  1: extended self-test completed without error
+//  0: otherwise
+int ataPrintSmartSelfTestEntry(unsigned testnum, unsigned char test_type,
+                               unsigned char test_status,
+                               unsigned short timestamp,
+                               uint64_t failing_lba,
+                               bool print_error_only, bool & print_header);
 
 // Print Smart self-test log, used by smartctl and smartd.
 int ataPrintSmartSelfTestlog(const ata_smart_selftestlog * data, bool allentries,
@@ -924,9 +938,7 @@ int ataPrintSmartSelfTestlog(const ata_smart_selftestlog * data, bool allentries
 uint64_t get_num_sectors(const ata_identify_device * drive);
 
 // Convenience function for formatting strings from ata_identify_device.
-void format_ata_string(char * out, const char * in, int n, bool fix_swap);
-inline void format_ata_string(char * out, const unsigned char * in, int n, bool fix_swap)
-  { format_ata_string(out, (const char *)in, n, fix_swap); }
+void ata_format_id_string(char * out, const unsigned char * in, int n);
 
 // Utility routines.
 unsigned char checksum(const void * data);
index 92903edd4d30e95ed01d93c6f195a2d41c76b89c..4c3ae28479390f99782800dfa5b2e9772ceb6bd2 100644 (file)
@@ -3,8 +3,8 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2002-10 Bruce Allen <smartmontools-support@lists.sourceforge.net>
- * Copyright (C) 2008-10 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2008-11 Christian Franke <smartmontools-support@lists.sourceforge.net>
  * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
  *
  * This program is free software; you can redistribute it and/or modify
 #include "dev_interface.h"
 #include "ataprint.h"
 #include "smartctl.h"
-#include "extern.h"
 #include "utility.h"
 #include "knowndrives.h"
 
-const char * ataprint_cpp_cvsid = "$Id: ataprint.cpp 3081 2010-04-03 19:39:11Z chrfranke $"
+const char * ataprint_cpp_cvsid = "$Id: ataprint.cpp 3288 2011-03-09 18:40:36Z chrfranke $"
                                   ATAPRINT_H_CVSID;
 
-// for passing global control variables
-extern smartmonctrl *con;
 
 static const char * infofound(const char *output) {
   return (*output ? output : "[No Information Found]");
 }
 
+// Return true if '-T permissive' is specified,
+// used to ignore missing capabilities
+static bool is_permissive()
+{
+  if (!failuretest_permissive)
+    return false;
+  failuretest_permissive--;
+  return true;
+}
 
 /* For the given Command Register (CR) and Features Register (FR), attempts
  * to construct a string that describes the contents of the Status
@@ -457,30 +463,70 @@ static uint64_t determine_capacity(const ata_identify_device * drive, char * pst
   return retval;
 }
 
-static bool PrintDriveInfo(const ata_identify_device * drive, bool fix_swapped_id)
+// Get sector sizes and offset.
+// Return physical sector size if valid else return 0.
+static unsigned determine_sector_sizes(const ata_identify_device * id,
+  unsigned & log_sector_size, unsigned & log_sector_offset)
 {
-  // format drive information (with byte swapping as needed)
-  char model[64], serial[64], firm[64];
-  format_ata_string(model, drive->model, 40, fix_swapped_id);
-  format_ata_string(serial, drive->serial_no, 20, fix_swapped_id);
-  format_ata_string(firm, drive->fw_rev, 8, fix_swapped_id);
+  unsigned short word106 = id->words088_255[106-88];
+  if ((word106 & 0xc000) != 0x4000)
+    return 0; // word not valid
+
+  log_sector_size = 512;
+  if (word106 & 0x1000)
+    // logical sector size is specified in 16-bit words
+    log_sector_size = ((id->words088_255[118-88] << 16) | id->words088_255[117-88]) << 1;
+
+  unsigned phy_sector_size = log_sector_size;
+  if (word106 & 0x2000)
+    // physical sector size is multiple of logical sector size
+    phy_sector_size <<= (word106 & 0x0f);
+
+  unsigned short word209 = id->words088_255[209-88];
+  log_sector_offset = 0;
+  if ((word209 & 0xc000) == 0x4000)
+    log_sector_offset = (word209 & 0x3fff) * log_sector_size;
+
+  return phy_sector_size;
+}
 
-  // print out model, serial # and firmware versions  (byte-swap ASCI strings)
-  const drive_settings * dbentry = lookup_drive(model, firm);
+static void print_drive_info(const ata_identify_device * drive,
+                             const drive_settings * dbentry)
+{
+  // format drive information (with byte swapping as needed)
+  char model[40+1], serial[20+1], firmware[8+1];
+  ata_format_id_string(model, drive->model, sizeof(model)-1);
+  ata_format_id_string(serial, drive->serial_no, sizeof(serial)-1);
+  ata_format_id_string(firmware, drive->fw_rev, sizeof(firmware)-1);
 
   // Print model family if known
   if (dbentry && *dbentry->modelfamily)
     pout("Model Family:     %s\n", dbentry->modelfamily);
 
   pout("Device Model:     %s\n", infofound(model));
-  if (!con->dont_print_serial)
+  if (!dont_print_serial_number)
     pout("Serial Number:    %s\n", infofound(serial));
-  pout("Firmware Version: %s\n", infofound(firm));
+  pout("Firmware Version: %s\n", infofound(firmware));
 
   char capacity[64];
   if (determine_capacity(drive, capacity))
     pout("User Capacity:    %s bytes\n", capacity);
-  
+
+  // Print sector sizes.
+  // Don't print if drive reports the default values.
+  // Some from 4KiB sector drives report 512 bytes in IDENTIFY word 106
+  // (e.g. Samsung HD204UI).
+  unsigned log_sector_size = 0, log_sector_offset = 0;
+  unsigned phy_sector_size = determine_sector_sizes(drive, log_sector_size,
+    log_sector_offset);
+  if (phy_sector_size && !(phy_sector_size == 512 && log_sector_size == 512)) {
+    pout("Sector Sizes:     %u bytes physical, %u bytes logical",
+         phy_sector_size, log_sector_size);
+    if (log_sector_offset)
+      pout(" (offset %u bytes)", log_sector_offset);
+    pout("\n");
+  }
+
   // See if drive is recognized
   pout("Device is:        %s\n", !dbentry ?
        "Not in smartctl database [for details use: -P showall]":
@@ -522,11 +568,10 @@ static bool PrintDriveInfo(const ata_identify_device * drive, bool fix_swapped_i
     pout("\n==> WARNING: %s\n\n", dbentry->warningmsg);
 
   if (!version || version >= 3)
-    return !!dbentry;
+    return;
   
   pout("SMART is only available in ATA Version 3 Revision 3 or greater.\n");
   pout("We will try to proceed in spite of this.\n");
-  return !!dbentry;
 }
 
 static const char *OfflineDataCollectionStatus(unsigned char status_byte)
@@ -664,7 +709,7 @@ static void PrintSmartSelfExecStatus(const ata_smart_values * data,
 static void PrintSmartTotalTimeCompleteOffline (const ata_smart_values * data)
 {
   pout("Total time to complete Offline \n");
-  pout("data collection: \t\t (%4d) seconds.\n", 
+  pout("data collection: \t\t(%5d) seconds.\n", 
        (int)data->total_time_to_complete_off_line);
 }
 
@@ -786,8 +831,7 @@ static int find_failed_attr(const ata_smart_values * data,
   for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
     const ata_smart_attribute & attr = data->vendor_attributes[i];
 
-    ata_attr_state state = ata_get_attr_state(attr,
-                             thresholds->thres_entries[i], defs);
+    ata_attr_state state = ata_get_attr_state(attr, i, thresholds->thres_entries, defs);
 
     if (!onlyfailed) {
       if (state >= ATTRSTATE_FAILED_PAST)
@@ -814,10 +858,10 @@ static void PrintSmartAttribWithThres(const ata_smart_values * data,
   // step through all vendor attributes
   for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
     const ata_smart_attribute & attr = data->vendor_attributes[i];
-    const ata_smart_threshold_entry & thre = thresholds->thres_entries[i];
 
     // Check attribute and threshold
-    ata_attr_state state = ata_get_attr_state(attr, thre, defs);
+    unsigned char threshold = 0;
+    ata_attr_state state = ata_get_attr_state(attr, i, thresholds->thres_entries, defs, &threshold);
     if (state == ATTRSTATE_NON_EXISTING)
       continue;
 
@@ -849,7 +893,7 @@ static void PrintSmartAttribWithThres(const ata_smart_values * data,
     else
       worstr = "---";
     if (state > ATTRSTATE_NO_THRESHOLD)
-      threstr = strprintf("%.3d", thre.threshold);
+      threstr = strprintf("%.3d", threshold);
     else
       threstr = "---";
 
@@ -864,14 +908,6 @@ static void PrintSmartAttribWithThres(const ata_smart_values * data,
           state == ATTRSTATE_FAILED_PAST ? "In_the_past" :
                                            "    -"        ),
          ata_format_attr_raw_value(attr, defs).c_str());
-
-    // Print a warning if there is inconsistency here
-    if (state == ATTRSTATE_BAD_THRESHOLD) {
-      pout("%3d %-24s<== Data Page      |  WARNING: PREVIOUS ATTRIBUTE HAS TWO\n",
-           attr.id, attrname.c_str());
-      pout("%3d %-24s<== Threshold Page |  INCONSISTENT IDENTITIES IN THE DATA\n",
-           thre.id, ata_get_smart_attr_name(thre.id, defs).c_str());
-    }
   }
   if (!needheader) pout("\n");
 }
@@ -942,7 +978,7 @@ static unsigned GetNumLogSectors(const ata_smart_log_directory * logdir, unsigne
 }
 
 // Get name of log.
-// Table A.2 of T13/1699-D Revision 6
+// Table A.2 of T13/2015-D Revision 4a (ACS-2), December 9, 2010.
 static const char * GetLogName(unsigned logaddr)
 {
     switch (logaddr) {
@@ -951,9 +987,12 @@ static const char * GetLogName(unsigned logaddr)
       case 0x02: return "Comprehensive SMART error log";
       case 0x03: return "Ext. Comprehensive SMART error log";
       case 0x04: return "Device Statistics";
+      case 0x05: return "Reserved for the CFA"; // ACS-2
       case 0x06: return "SMART self-test log";
       case 0x07: return "Extended self-test log";
+      case 0x08: return "Power Conditions"; // ACS-2
       case 0x09: return "Selective self-test log";
+      case 0x0d: return "LPS Mis-alignment log"; // ACS-2
       case 0x10: return "NCQ Command Error";
       case 0x11: return "SATA Phy Event Counters";
       case 0x20: return "Streaming performance log"; // Obsolete
@@ -1129,7 +1168,7 @@ static int PrintSmartErrorlog(const ata_smart_errorlog *data,
     pout("No Errors Logged\n\n");
     return 0;
   }
-  PRINT_ON(con);
+  print_on();
   // If log pointer out of range, return
   if (data->error_log_pointer>5){
     pout("Invalid Error Log index = 0x%02x (T13/1321D rev 1c "
@@ -1150,7 +1189,7 @@ static int PrintSmartErrorlog(const ata_smart_errorlog *data,
   else
     pout( "ATA Error Count: %d (device log contains only the most recent five errors)\n",
            (int)data->ata_error_count);
-  PRINT_OFF(con);
+  print_off();
   pout("\tCR = Command Register [HEX]\n"
        "\tFR = Features Register [HEX]\n"
        "\tSC = Sector Count Register [HEX]\n"
@@ -1180,10 +1219,10 @@ static int PrintSmartErrorlog(const ata_smart_errorlog *data,
       int days = (int)summary->timestamp/24;
 
       // See table 42 of ATA5 spec
-      PRINT_ON(con);
+      print_on();
       pout("Error %d occurred at disk power-on lifetime: %d hours (%d days + %d hours)\n",
              (int)(data->ata_error_count+k-4), (int)summary->timestamp, days, (int)(summary->timestamp-24*days));
-      PRINT_OFF(con);
+      print_off();
       pout("  When the command that caused the error occurred, the device was %s.\n\n",msgstate);
       pout("  After command completion occurred, registers were:\n"
            "  ER ST SC SN CL CH DH\n"
@@ -1232,10 +1271,10 @@ static int PrintSmartErrorlog(const ata_smart_errorlog *data,
       pout("\n");
     }
   }
-  PRINT_ON(con);
-  if (con->printing_switchable)
+  print_on();
+  if (printing_is_switchable)
     pout("\n");
-  PRINT_OFF(con);
+  print_off();
   return data->ata_error_count;  
 }
 
@@ -1250,7 +1289,7 @@ static int PrintSmartExtErrorLog(const ata_smart_exterrlog * log,
     pout("No Errors Logged\n\n");
     return 0;
   }
-  PRINT_ON(con);
+  print_on();
 
   // Check index
   unsigned nentries = nsectors * 4;
@@ -1285,7 +1324,7 @@ static int PrintSmartExtErrorLog(const ata_smart_exterrlog * log,
   if (max_errors < errcnt)
     errcnt = max_errors;
 
-  PRINT_OFF(con);
+  print_off();
   pout("\tCR     = Command Register\n"
        "\tFEATR  = Features Register\n"
        "\tCOUNT  = Count (was: Sector Count) Register\n"
@@ -1314,11 +1353,11 @@ static int PrintSmartExtErrorLog(const ata_smart_exterrlog * log,
     }
 
     // Print error information
-    PRINT_ON(con);
+    print_on();
     const ata_smart_exterrlog_error & err = entry.error;
     pout("Error %u [%u] occurred at disk power-on lifetime: %u hours (%u days + %u hours)\n",
          errnum, erridx, err.timestamp, err.timestamp / 24, err.timestamp % 24);
-    PRINT_OFF(con);
+    print_off();
 
     pout("  When the command that caused the error occurred, the device was %s.\n\n",
       get_error_log_state_desc(err.state));
@@ -1384,23 +1423,23 @@ static int PrintSmartExtErrorLog(const ata_smart_exterrlog * log,
     pout("\n");
   }
 
-  PRINT_ON(con);
-  if (con->printing_switchable)
+  print_on();
+  if (printing_is_switchable)
     pout("\n");
-  PRINT_OFF(con);
+  print_off();
   return log->device_error_count;
 }
 
 // Print SMART Extended Self-test Log (GP Log 0x07)
-static bool PrintSmartExtSelfTestLog(const ata_smart_extselftestlog * log,
-                                     unsigned nsectors, unsigned max_entries)
+static int PrintSmartExtSelfTestLog(const ata_smart_extselftestlog * log,
+                                    unsigned nsectors, unsigned max_entries)
 {
   pout("SMART Extended Self-test Log Version: %u (%u sectors)\n",
        log->version, nsectors);
 
   if (!log->log_desc_index){
     pout("No self-tests have been logged.  [To run self-tests, use: smartctl -t]\n\n");
-    return true;
+    return 0;
   }
 
   // Check index
@@ -1408,7 +1447,7 @@ static bool PrintSmartExtSelfTestLog(const ata_smart_extselftestlog * log,
   unsigned logidx = log->log_desc_index;
   if (logidx > nentries) {
     pout("Invalid Self-test Log index = 0x%04x (reserved = 0x%02x)\n", logidx, log->reserved1);
-    return false;
+    return 0;
   }
 
   // Index base is not clearly specified by ATA8-ACS (T13/1699-D Revision 6a),
@@ -1416,6 +1455,8 @@ static bool PrintSmartExtSelfTestLog(const ata_smart_extselftestlog * log,
   logidx--;
 
   bool print_header = true;
+  int errcnt = 0, igncnt = 0;
+  int ext_ok_testnum = -1;
 
   // Iterate through circular buffer in reverse direction
   for (unsigned i = 0, testnum = 1;
@@ -1438,12 +1479,31 @@ static bool PrintSmartExtSelfTestLog(const ata_smart_extselftestlog * log,
         | ((uint64_t)b[5] << 40);
 
     // Print entry
-    ataPrintSmartSelfTestEntry(testnum++, entry.self_test_type,
+    int state = ataPrintSmartSelfTestEntry(testnum, entry.self_test_type,
       entry.self_test_status, entry.timestamp, lba48,
       false /*!print_error_only*/, print_header);
+
+    if (state < 0) {
+      // Self-test showed an error
+      if (ext_ok_testnum < 0)
+        errcnt++;
+      else
+        // Newer successful extended self-test exits
+        igncnt++;
+    }
+    else if (state > 0 && ext_ok_testnum < 0) {
+      // Latest successful extended self-test
+      ext_ok_testnum = testnum;
+    }
+    testnum++;
   }
+
+  if (igncnt)
+    pout("%d of %d failed self-tests are outdated by newer successful extended offline self-test #%2d\n",
+      igncnt, igncnt+errcnt, ext_ok_testnum);
+
   pout("\n");
-  return true;
+  return errcnt;
 }
 
 static void ataPrintSelectiveSelfTestLog(const ata_selective_self_test_log * log, const ata_smart_values * sv)
@@ -1702,9 +1762,9 @@ static int ataPrintSCTTempHist(const ata_sct_temperature_history_table * tmh)
 }
 
 // Print SCT Error Recovery Control timers
-static void ataPrintSCTErrorRecoveryControl(unsigned short read_timer, unsigned short write_timer)
+static void ataPrintSCTErrorRecoveryControl(bool set, unsigned short read_timer, unsigned short write_timer)
 {
-  pout("SCT Error Recovery Control:\n");
+  pout("SCT Error Recovery Control%s:\n", (set ? " set to" : ""));
   if (!read_timer)
     pout("           Read: Disabled\n");
   else
@@ -1716,35 +1776,8 @@ static void ataPrintSCTErrorRecoveryControl(unsigned short read_timer, unsigned
 }
 
 
-// Compares failure type to policy in effect, and either exits or
-// simply returns to the calling routine.
-void failuretest(int type, int returnvalue){
-
-  // If this is an error in an "optional" SMART command
-  if (type==OPTIONAL_CMD){
-    if (con->conservative){
-      pout("An optional SMART command failed: exiting.  Remove '-T conservative' option to continue.\n");
-      EXIT(returnvalue);
-    }
-    return;
-  }
-
-  // If this is an error in a "mandatory" SMART command
-  if (type==MANDATORY_CMD){
-    if (con->permissive--)
-      return;
-    pout("A mandatory SMART command failed: exiting. To continue, add one or more '-T permissive' options.\n");
-    EXIT(returnvalue);
-  }
-
-  pout("Smartctl internal error in failuretest(type=%d). Please contact developers at " PACKAGE_HOMEPAGE "\n",type);
-  EXIT(returnvalue|FAILCMD);
-}
-
 int ataPrintMain (ata_device * device, const ata_print_options & options)
 {
-  int returnval = 0;
-
   // If requested, check power mode first
   const char * powername = 0;
   bool powerchg = false;
@@ -1754,7 +1787,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
     switch (powermode) {
       case -1:
         if (errno == ENOSYS) {
-          pout("CHECK POWER STATUS not implemented, ignoring -n Option\n"); break;
+          pout("CHECK POWER MODE not implemented, ignoring -n option\n"); break;
         }
         powername = "SLEEP";   powerlimit = 2;
         break;
@@ -1765,7 +1798,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
       case 0xff:
         powername = "ACTIVE or IDLE"; break;
       default:
-        pout("CHECK POWER STATUS returned %d, not ATA compliant, ignoring -n Option\n", powermode);
+        pout("CHECK POWER MODE returned unknown value 0x%02x, ignoring -n option\n", powermode);
         break;
     }
     if (powername) {
@@ -1806,9 +1839,49 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
        || options.smart_disable
   );
 
+  // SMART and GP log directories needed ?
+  bool need_smart_logdir = options.smart_logdir;
+
+  bool need_gp_logdir  = (
+          options.gp_logdir
+       || options.smart_ext_error_log
+       || options.smart_ext_selftest_log
+       || options.sataphy
+  );
+
+  unsigned i;
+  for (i = 0; i < options.log_requests.size(); i++) {
+    if (options.log_requests[i].gpl)
+      need_gp_logdir = true;
+    else
+      need_smart_logdir = true;
+  }
+
+  // SCT commands needed ?
+  bool need_sct_support = (
+          options.sct_temp_sts
+       || options.sct_temp_hist
+       || options.sct_temp_int
+       || options.sct_erc_get
+       || options.sct_erc_set
+  );
+
+  // Exit if no further options specified
+  if (!(   options.drive_info || need_smart_support
+        || need_smart_logdir  || need_gp_logdir
+        || need_sct_support                        )) {
+    if (powername)
+      pout("Device is in %s mode\n", powername);
+    else
+      pout("ATA device successfully opened\n\n"
+           "Use 'smartctl -a' (or '-x') to print SMART (and more) information\n\n");
+    return 0;
+  }
+
   // Start by getting Drive ID information.  We need this, to know if SMART is supported.
+  int returnval = 0;
   ata_identify_device drive; memset(&drive, 0, sizeof(drive));
-  int retid = ataReadHDIdentity(device,&drive);
+  int retid = ata_read_identity(device, &drive, options.fix_swapped_id);
   if (retid < 0) {
     pout("Smartctl: Device Read Identity Failed (not an ATA/ATAPI device)\n\n");
     failuretest(MANDATORY_CMD, returnval|=FAILID);
@@ -1816,21 +1889,22 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
 
   // If requested, show which presets would be used for this drive and exit.
   if (options.show_presets) {
-    show_presets(&drive, options.fix_swapped_id);
+    show_presets(&drive);
     return 0;
   }
 
   // Use preset vendor attribute options unless user has requested otherwise.
   ata_vendor_attr_defs attribute_defs = options.attribute_defs;
   unsigned char fix_firmwarebug = options.fix_firmwarebug;
+  const drive_settings * dbentry = 0;
   if (!options.ignore_presets)
-    apply_presets(&drive, attribute_defs, fix_firmwarebug, options.fix_swapped_id);
+    dbentry = lookup_drive_apply_presets(&drive, attribute_defs,
+      fix_firmwarebug);
 
   // Print most drive identity information if requested
-  bool known = false;
   if (options.drive_info) {
     pout("=== START OF INFORMATION SECTION ===\n");
-    known = PrintDriveInfo(&drive, options.fix_swapped_id);
+    print_drive_info(&drive, dbentry);
   }
 
   // Check and print SMART support and state
@@ -1859,7 +1933,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
             smart_supported = smart_enabled = 1;
         }
       }
-      else if (smart_supported < 0 && (smart_enabled > 0 || known))
+      else if (smart_supported < 0 && (smart_enabled > 0 || dbentry))
         // Assume supported if enabled or in drive database
         smart_supported = 1;
 
@@ -2034,7 +2108,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
         if (options.smart_vendor_attrib)
           pout("See vendor-specific Attribute list for marginal Attributes.\n\n");
         else {
-          PRINT_ON(con);
+          print_on();
           pout("Please note the following marginal Attributes:\n");
           PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, 2);
         } 
@@ -2046,16 +2120,16 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
       
     case 1:
       // The case where the disk health is NOT OK
-      PRINT_ON(con);
+      print_on();
       pout("SMART overall-health self-assessment test result: FAILED!\n"
            "Drive failure expected in less than 24 hours. SAVE ALL DATA.\n");
-      PRINT_OFF(con);
+      print_off();
       if (smart_thres_ok && find_failed_attr(&smartval, &smartthres, attribute_defs, 1)) {
         returnval|=FAILATTR;
         if (options.smart_vendor_attrib)
           pout("See vendor-specific Attribute list for failed Attributes.\n\n");
         else {
-          PRINT_ON(con);
+          print_on();
           pout("Failed Attributes:\n");
           PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, 1);
         }
@@ -2063,7 +2137,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
       else
         pout("No failed Attributes found.\n\n");   
       returnval|=FAILSTATUS;
-      PRINT_OFF(con);
+      print_off();
       break;
 
     case -1:
@@ -2074,21 +2148,21 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
       // return the registers values.
       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
       if (!(smart_val_ok && smart_thres_ok)) {
-        PRINT_ON(con);
+        print_on();
         pout("SMART overall-health self-assessment test result: UNKNOWN!\n"
              "SMART Status, Attributes and Thresholds cannot be read.\n\n");
       }
       else if (find_failed_attr(&smartval, &smartthres, attribute_defs, 1)) {
-        PRINT_ON(con);
+        print_on();
         pout("SMART overall-health self-assessment test result: FAILED!\n"
              "Drive failure expected in less than 24 hours. SAVE ALL DATA.\n");
-        PRINT_OFF(con);
+        print_off();
         returnval|=FAILATTR;
         returnval|=FAILSTATUS;
         if (options.smart_vendor_attrib)
           pout("See vendor-specific Attribute list for failed Attributes.\n\n");
         else {
-          PRINT_ON(con);
+          print_on();
           pout("Failed Attributes:\n");
           PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, 1);
         }
@@ -2100,7 +2174,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
           if (options.smart_vendor_attrib)
             pout("See vendor-specific Attribute list for marginal Attributes.\n\n");
           else {
-            PRINT_ON(con);
+            print_on();
             pout("Please note the following marginal Attributes:\n");
             PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, 2);
           } 
@@ -2109,11 +2183,11 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
         else
           pout("\n");
       } 
-      PRINT_OFF(con);
+      print_off();
       break;
     } // end of switch statement
     
-    PRINT_OFF(con);
+    print_off();
   } // end of checking SMART Status
   
   // Print general SMART values
@@ -2122,113 +2196,93 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
 
   // Print vendor-specific attributes
   if (smart_val_ok && options.smart_vendor_attrib) {
-    PRINT_ON(con);
+    print_on();
     PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs,
-                              (con->printing_switchable ? 2 : 0));
-    PRINT_OFF(con);
+                              (printing_is_switchable ? 2 : 0));
+    print_off();
   }
 
-  // Print SMART and/or GP log Directory and/or logs
-  // Get #pages for extended SMART logs
+  // If GP Log is supported use smart log directory for
+  // error and selftest log support check.
+  if (   isGeneralPurposeLoggingCapable(&drive)
+      && (   options.smart_error_log || options.smart_selftest_log
+          || options.retry_error_log || options.retry_selftest_log))
+    need_smart_logdir = true;
+
   ata_smart_log_directory smartlogdir_buf, gplogdir_buf;
   const ata_smart_log_directory * smartlogdir = 0, * gplogdir = 0;
 
-  if (   options.gp_logdir
-      || options.smart_logdir
-      || options.smart_ext_error_log
-      || options.smart_ext_selftest_log
-      || options.sataphy
-      || !options.log_requests.empty() ) {
-    if (isGeneralPurposeLoggingCapable(&drive))
-      pout("General Purpose Logging (GPL) feature set supported\n");
-
-    // Detect directories needed
-    bool need_smart_logdir = options.smart_logdir;
-    bool need_gp_logdir    = (   options.gp_logdir
-                              || options.smart_ext_error_log
-                              || options.smart_ext_selftest_log
-                              || options.sataphy               );
-    unsigned i;
-    for (i = 0; i < options.log_requests.size(); i++) {
-      if (options.log_requests[i].gpl)
-        need_gp_logdir = true;
-      else
-        need_smart_logdir = true;
-    }
-
-    // Read SMART Log directory
-    if (need_smart_logdir) {
-      if (ataReadLogDirectory(device, &smartlogdir_buf, false)){
-        pout("Read SMART Log Directory failed.\n\n");
-        failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
-      }
-      else
-        smartlogdir = &smartlogdir_buf;
+  // Read SMART Log directory
+  if (need_smart_logdir) {
+    if (ataReadLogDirectory(device, &smartlogdir_buf, false)) {
+      pout("Read SMART Log Directory failed.\n\n");
+      failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
     }
+    else
+      smartlogdir = &smartlogdir_buf;
+  }
 
-    // Read GP Log directory
-    if (need_gp_logdir) {
-      if (ataReadLogDirectory(device, &gplogdir_buf, true)){
-        pout("Read GP Log Directory failed.\n\n");
-        failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
-      }
-      else
-        gplogdir = &gplogdir_buf;
+  // Read GP Log directory
+  if (need_gp_logdir) {
+    if (ataReadLogDirectory(device, &gplogdir_buf, true)) {
+      pout("Read GP Log Directory failed.\n\n");
+      failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
     }
+    else
+      gplogdir = &gplogdir_buf;
+  }
 
-    // Print log directories
-    if ((options.gp_logdir && gplogdir) || (options.smart_logdir && smartlogdir))
-      PrintLogDirectories(gplogdir, smartlogdir);
+  // Print log directories
+  if ((options.gp_logdir && gplogdir) || (options.smart_logdir && smartlogdir))
+    PrintLogDirectories(gplogdir, smartlogdir);
 
-    // Print log pages
-    for (i = 0; i < options.log_requests.size(); i++) {
-      const ata_log_request & req = options.log_requests[i];
+  // Print log pages
+  for (i = 0; i < options.log_requests.size(); i++) {
+    const ata_log_request & req = options.log_requests[i];
 
-      const char * type;
-      unsigned max_nsectors;
-      if (req.gpl) {
-        type = "General Purpose";
-        max_nsectors = GetNumLogSectors(gplogdir, req.logaddr, true);
-      }
-      else {
-        type = "SMART";
-        max_nsectors = GetNumLogSectors(smartlogdir, req.logaddr, false);
-      }
+    const char * type;
+    unsigned max_nsectors;
+    if (req.gpl) {
+      type = "General Purpose";
+      max_nsectors = GetNumLogSectors(gplogdir, req.logaddr, true);
+    }
+    else {
+      type = "SMART";
+      max_nsectors = GetNumLogSectors(smartlogdir, req.logaddr, false);
+    }
 
-      if (!max_nsectors) {
-        if (!con->permissive) {
-          pout("%s Log 0x%02x does not exist (override with '-T permissive' option)\n", type, req.logaddr);
-          continue;
-        }
-        con->permissive--;
-        max_nsectors = req.page+1;
-      }
-      if (max_nsectors <= req.page) {
-        pout("%s Log 0x%02x has only %u sectors, output skipped\n", type, req.logaddr, max_nsectors);
+    if (!max_nsectors) {
+      if (!is_permissive()) {
+        pout("%s Log 0x%02x does not exist (override with '-T permissive' option)\n", type, req.logaddr);
         continue;
       }
+      max_nsectors = req.page+1;
+    }
+    if (max_nsectors <= req.page) {
+      pout("%s Log 0x%02x has only %u sectors, output skipped\n", type, req.logaddr, max_nsectors);
+      continue;
+    }
 
-      unsigned ns = req.nsectors;
-      if (ns > max_nsectors - req.page) {
-        if (req.nsectors != ~0U) // "FIRST-max"
-          pout("%s Log 0x%02x has only %u sectors, output truncated\n", type, req.logaddr, max_nsectors);
-        ns = max_nsectors - req.page;
-      }
+    unsigned ns = req.nsectors;
+    if (ns > max_nsectors - req.page) {
+      if (req.nsectors != ~0U) // "FIRST-max"
+        pout("%s Log 0x%02x has only %u sectors, output truncated\n", type, req.logaddr, max_nsectors);
+      ns = max_nsectors - req.page;
+    }
 
-      // SMART log don't support sector offset, start with first sector
-      unsigned offs = (req.gpl ? 0 : req.page);
+    // SMART log don't support sector offset, start with first sector
+    unsigned offs = (req.gpl ? 0 : req.page);
 
-      raw_buffer log_buf((offs + ns) * 512);
-      bool ok;
-      if (req.gpl)
-        ok = ataReadLogExt(device, req.logaddr, 0x00, req.page, log_buf.data(), ns);
-      else
-        ok = ataReadSmartLog(device, req.logaddr, log_buf.data(), offs + ns);
-      if (!ok)
-        failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
-      else
-        PrintLogPages(type, log_buf.data() + offs*512, req.logaddr, req.page, ns, max_nsectors);
-    }
+    raw_buffer log_buf((offs + ns) * 512);
+    bool ok;
+    if (req.gpl)
+      ok = ataReadLogExt(device, req.logaddr, 0x00, req.page, log_buf.data(), ns);
+    else
+      ok = ataReadSmartLog(device, req.logaddr, log_buf.data(), offs + ns);
+    if (!ok)
+      failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
+    else
+      PrintLogPages(type, log_buf.data() + offs*512, req.logaddr, req.page, ns, max_nsectors);
   }
 
   // Print SMART Extendend Comprehensive Error Log
@@ -2246,7 +2300,8 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
       if (!ataReadExtErrorLog(device, log_03, nsectors))
         failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
       else {
-        PrintSmartExtErrorLog(log_03, nsectors, options.smart_ext_error_log);
+        if (PrintSmartExtErrorLog(log_03, nsectors, options.smart_ext_error_log))
+          returnval |= FAILERR;
         ok = true;
       }
     }
@@ -2261,20 +2316,23 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
 
   // Print SMART error log
   if (do_smart_error_log) {
-    if (!isSmartErrorLogCapable(&smartval, &drive)){
-      pout("Warning: device does not support Error Logging\n");
-      failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
-    }
-    ata_smart_errorlog smarterror; memset(&smarterror, 0, sizeof(smarterror));
-    if (ataReadErrorLog(device, &smarterror, fix_firmwarebug)){
-      pout("Smartctl: SMART Error Log Read Failed\n");
-      failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
+    if (!(   ( smartlogdir && GetNumLogSectors(smartlogdir, 0x01, false))
+          || (!smartlogdir && isSmartErrorLogCapable(&smartval, &drive) )
+          || is_permissive()                                             )) {
+      pout("SMART Error Log not supported\n");
     }
     else {
-      // quiet mode is turned on inside ataPrintSmartErrorLog()
-      if (PrintSmartErrorlog(&smarterror, fix_firmwarebug))
-       returnval|=FAILERR;
-      PRINT_OFF(con);
+      ata_smart_errorlog smarterror; memset(&smarterror, 0, sizeof(smarterror));
+      if (ataReadErrorLog(device, &smarterror, fix_firmwarebug)) {
+        pout("Smartctl: SMART Error Log Read Failed\n");
+        failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
+      }
+      else {
+        // quiet mode is turned on inside PrintSmartErrorLog()
+        if (PrintSmartErrorlog(&smarterror, fix_firmwarebug))
+         returnval|=FAILERR;
+        print_off();
+      }
     }
   }
 
@@ -2293,10 +2351,9 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
       if (!ataReadExtSelfTestLog(device, log_07, nsectors))
         failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
       else {
-        if (!PrintSmartExtSelfTestLog(log_07, nsectors, options.smart_ext_selftest_log))
+        if (PrintSmartExtSelfTestLog(log_07, nsectors, options.smart_ext_selftest_log))
           returnval |= FAILLOG;
-        else
-          ok = true;
+        ok = true;
       }
     }
 
@@ -2310,21 +2367,24 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
 
   // Print SMART self-test log
   if (do_smart_selftest_log) {
-    if (!isSmartTestLogCapable(&smartval, &drive)){
-      pout("Warning: device does not support Self Test Logging\n");
-      failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
-    }    
-    ata_smart_selftestlog smartselftest; memset(&smartselftest, 0, sizeof(smartselftest));
-    if(ataReadSelfTestLog(device, &smartselftest, fix_firmwarebug)){
-      pout("Smartctl: SMART Self Test Log Read Failed\n");
-      failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
+    if (!(   ( smartlogdir && GetNumLogSectors(smartlogdir, 0x06, false))
+          || (!smartlogdir && isSmartTestLogCapable(&smartval, &drive)  )
+          || is_permissive()                                             )) {
+      pout("SMART Self-test Log not supported\n");
     }
     else {
-      PRINT_ON(con);
-      if (ataPrintSmartSelfTestlog(&smartselftest, !con->printing_switchable, fix_firmwarebug))
-       returnval|=FAILLOG;
-      PRINT_OFF(con);
-      pout("\n");
+      ata_smart_selftestlog smartselftest; memset(&smartselftest, 0, sizeof(smartselftest));
+      if (ataReadSelfTestLog(device, &smartselftest, fix_firmwarebug)) {
+        pout("Smartctl: SMART Self Test Log Read Failed\n");
+        failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
+      }
+      else {
+        print_on();
+        if (ataPrintSmartSelfTestlog(&smartselftest, !printing_is_switchable, fix_firmwarebug))
+          returnval |= FAILLOG;
+        print_off();
+        pout("\n");
+      }
     }
   }
 
@@ -2339,20 +2399,20 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
     }
     else {
-      PRINT_ON(con);
+      print_on();
       // If any errors were found, they are logged in the SMART Self-test log.
       // So there is no need to print the Selective Self Test log in silent
       // mode.
-      if (!con->printing_switchable) ataPrintSelectiveSelfTestLog(&log, &smartval);
-      PRINT_OFF(con);
+      if (!printing_is_switchable)
+        ataPrintSelectiveSelfTestLog(&log, &smartval);
+      print_off();
       pout("\n");
     }
   }
 
   // SCT commands
   bool sct_ok = false;
-  if (   options.sct_temp_sts || options.sct_temp_hist || options.sct_temp_int
-      || options.sct_erc_get  || options.sct_erc_set                          ) {
+  if (need_sct_support) {
     if (!isSCTCapable(&drive)) {
       pout("Warning: device does not support SCT Commands\n");
       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
@@ -2424,12 +2484,15 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
         if (   ataSetSCTErrorRecoveryControltime(device, 1, options.sct_erc_readtime )
             || ataSetSCTErrorRecoveryControltime(device, 2, options.sct_erc_writetime)) {
           pout("Warning: device does not support SCT (Set) Error Recovery Control command\n");
-          pout("Suggest common arguments: scterc,70,70 to enable ERC or sct,0,0 to disable\n");
+          if (!(   (options.sct_erc_readtime == 70 && options.sct_erc_writetime == 70)
+                || (options.sct_erc_readtime ==  0 && options.sct_erc_writetime ==  0)))
+            pout("Retry with: 'scterc,70,70' to enable ERC or 'scterc,0,0' to disable\n");
           failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
           sct_erc_get = false;
         }
-        else
-          sct_erc_get = true;
+        else if (!sct_erc_get)
+          ataPrintSCTErrorRecoveryControl(true, options.sct_erc_readtime,
+            options.sct_erc_writetime);
       }
 
       if (sct_erc_get) {
@@ -2438,12 +2501,15 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
         if (   ataGetSCTErrorRecoveryControltime(device, 1, read_timer )
             || ataGetSCTErrorRecoveryControltime(device, 2, write_timer)) {
           pout("Warning: device does not support SCT (Get) Error Recovery Control command\n");
-          if (options.sct_erc_set)
+          if (options.sct_erc_set) {
             pout("The previous SCT (Set) Error Recovery Control command succeeded\n");
+            ataPrintSCTErrorRecoveryControl(true, options.sct_erc_readtime,
+              options.sct_erc_writetime);
+          }
           failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
         }
         else
-          ataPrintSCTErrorRecoveryControl(read_timer, write_timer);
+          ataPrintSCTErrorRecoveryControl(false, read_timer, write_timer);
       }
       pout("\n");
     }
@@ -2504,9 +2570,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
     }
     break;
   default:
-    pout("Internal error in smartctl: smart_test_type==%d not recognized\n", options.smart_selftest_type);
-    pout("Please contact smartmontools developers at %s.\n", PACKAGE_BUGREPORT);
-    EXIT(returnval|=FAILCMD);
+    break; // Vendor specific type
   }
 
   // Now do the test.  Note ataSmartTest prints its own error/success
index 0194cca9bee546004a24d0ca464c37b66ffb8bf5..ce93477a487d8862f5fd9f74dd1563a911e2c74e 100644 (file)
@@ -26,7 +26,7 @@
 #ifndef ATAPRINT_H_
 #define ATAPRINT_H_
 
-#define ATAPRINT_H_CVSID "$Id: ataprint.h 3065 2010-02-10 22:16:50Z chrfranke $\n"
+#define ATAPRINT_H_CVSID "$Id: ataprint.h 3196 2010-10-28 21:31:49Z chrfranke $\n"
 
 #include <vector>
 
@@ -44,7 +44,6 @@ struct ata_log_request
 };
 
 // Options for ataPrintMain
-// TODO: Move remaining options from con->* to here.
 struct ata_print_options
 {
   bool drive_info;
index be136af1f07ad89da76636c52c0aa454cae906c1..1f5f2e7105da40c9fb1b2df1526b066dd4857870 100644 (file)
--- a/cciss.cpp
+++ b/cciss.cpp
@@ -1,6 +1,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <sys/types.h>
+#include <errno.h>
 
 #include "config.h"
 
 #endif
 
 #ifdef _HAVE_CCISS
+#include "cciss.h"
 #include "int64.h"
 #include "scsicmds.h"
 #include "utility.h"
 
-const char *cciss_c_cvsid="$Id: cciss.cpp,v 1.9 2008/07/30 20:42:53 chrfranke Exp $"
-CONFIG_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
+const char * cciss_cpp_cvsid = "$Id: cciss.cpp 3266 2011-02-21 16:33:04Z chrfranke $"
+  CCISS_H_CVSID;
 
 typedef struct _ReportLUNdata_struct
 {
index e932446389eda6757431cc86d958ae49365afbd7..b9d5e7c18db1f1b15bde28030bcc65ec4c680a64 100644 (file)
@@ -1,15 +1,15 @@
 #
-# $Id: configure.in 3116 2010-06-03 11:03:29Z chrfranke $
+# $Id: configure.in 3296 2011-03-16 22:17:51Z chrfranke $
 #
 dnl Process this file with autoconf to produce a configure script.
 AC_PREREQ(2.50)
-AC_INIT(smartmontools, 5.40, smartmontools-support@lists.sourceforge.net)
+AC_INIT(smartmontools, 5.41, smartmontools-support@lists.sourceforge.net)
 AC_CONFIG_SRCDIR(smartctl.cpp)
 
 smartmontools_configure_date=`date -u +'%Y-%m-%d %T %Z'`
-smartmontools_cvs_tag=`echo '$Id: configure.in 3116 2010-06-03 11:03:29Z chrfranke $'`
-smartmontools_release_date=2009-12-09
-smartmontools_release_time="21:00:32 UTC"
+smartmontools_cvs_tag=`echo '$Id: configure.in 3296 2011-03-16 22:17:51Z chrfranke $'`
+smartmontools_release_date=2010-10-16
+smartmontools_release_time="16:34:38 UTC"
 
 AC_DEFINE_UNQUOTED(SMARTMONTOOLS_CONFIGURE_ARGS, "$ac_configure_args",            [smartmontools Configure Arguments])
 AC_DEFINE_UNQUOTED(SMARTMONTOOLS_CONFIGURE_DATE, "$smartmontools_configure_date", [smartmontools Configure Date])
@@ -30,32 +30,37 @@ AC_PROG_CXX
 AM_PROG_AS
 AC_PROG_INSTALL
 
+AC_ARG_VAR(WINDMC, [Windows message compiler command])
+AC_ARG_VAR(WINDRES, [Windows resource compiler command])
+AC_ARG_VAR(MAKENSIS, [NSIS compiler command])
+
 AC_CANONICAL_HOST
 dnl Set flags which may affect AC_CHECK_*.
 case "${host}" in
-       *-*-mingw*)
-               # If building on Cygwin and not cross-compiling add '-mno-cygwin'
-               # to select MinGW gcc. This does no longer work for gcc 4.x.
-               if test "${build}" = "${host}" && test -x /usr/bin/uname && \
-                  /usr/bin/uname | grep -i '^CYGWIN' >/dev/null; then
-                 AC_MSG_CHECKING([whether $CC and $CXX support -mno-cygwin])
-                 gcc_support_m_no_cygwin=no
-                 if $CC  -v -mno-cygwin >/dev/null 2>&1 && \
-                    $CXX -v -mno-cygwin >/dev/null 2>&1; then
-                   gcc_support_m_no_cygwin=yes
-                 fi
-                 AC_MSG_RESULT([$gcc_support_m_no_cygwin])
-                 if test "$gcc_support_m_no_cygwin" != "yes"; then
-                   AC_MSG_ERROR([$CC and $CXX do not support -mno-cygwin, see INSTALL file for details.])
-                 fi
-                 CPPFLAGS="$CPPFLAGS -mno-cygwin"
-                 LDFLAGS="$LDFLAGS -mno-cygwin"
-               fi
-               CPPFLAGS="$CPPFLAGS -I$srcdir/os_win32"
-               ;;
-       *-*-freebsd*)
-               CPPFLAGS="$CPPFLAGS -I/usr/src/sys"
-               ;;
+  *-*-mingw*)
+    # Cygwin gcc 4.x does no longer support '-mno-cygwin' to select MinGW gcc.
+    if test "${build}" = "${host}" && test -x /usr/bin/uname && \
+    /usr/bin/uname | grep -i '^CYGWIN' >/dev/null; then
+      AC_MSG_ERROR([Build with MinGW on Cygwin requires cross-compilation, see INSTALL file.])
+    fi
+    AC_CHECK_PROGS(WINDMC, [${host}-windmc windmc])
+    AC_CHECK_PROGS(WINDRES, [${host}-windres windres])
+
+    AC_MSG_CHECKING([checking for makensis])
+    if test -z "$MAKENSIS"; then
+      if test -n "$PROGRAMFILES" && "$PROGRAMFILES/NSIS/makensis" -VERSION >/dev/null 2>&1; then
+        MAKENSIS="$PROGRAMFILES/NSIS/makensis"
+      elif makensis -VERSION >/dev/null 2>&1; then
+        MAKENSIS=makensis
+      fi
+    fi
+    AC_MSG_RESULT([${MAKENSIS:-no}])
+
+    CPPFLAGS="$CPPFLAGS -I$srcdir/os_win32"
+    ;;
+  *-*-freebsd*)
+    CPPFLAGS="$CPPFLAGS -I/usr/src/sys"
+    ;;
 esac
 
 # Check for SVN.
@@ -102,6 +107,11 @@ AC_CHECK_HEADERS([linux/cciss_ioctl.h], [], [], [AC_INCLUDES_DEFAULT
 # include <linux/compiler.h>
 #endif
 ])
+dnl Check for Windows DDK and WMI header files
+AC_CHECK_HEADERS([ntdddisk.h ddk/ntdddisk.h], [], [], [AC_INCLUDES_DEFAULT
+#include <windows.h>
+])
+AC_CHECK_HEADERS([wbemcli.h])
 
 dnl Checks for typedefs, structures, and compiler characteristics.
 AC_CHECK_TYPES([int64_t, uint64_t])
@@ -124,21 +134,19 @@ AC_CHECK_FUNCS([uname])
 AC_C_BIGENDIAN
 
 # Check whether snprintf appends null char and returns expected length on overflow
-AH_TEMPLATE(HAVE_WORKING_SNPRINTF, [Define to 1 if the `snprintf' function is sane])
 AC_MSG_CHECKING([for working snprintf])
 AC_RUN_IFELSE([AC_LANG_PROGRAM([[#include <stdio.h>]], [[ char buf[]="ABCDEFGHI";
                int i=snprintf(buf,8,"12345678"); return !(!buf[7] && i==8); ]])],
               [libc_have_working_snprintf=yes],
-             [libc_have_working_snprintf=no],
-             [libc_have_working_snprintf=no])
+              [libc_have_working_snprintf=no],
+              [libc_have_working_snprintf=unknown])
 AC_SUBST(libc_have_working_snprintf)
 if test "$libc_have_working_snprintf" = "yes"; then
-  AC_DEFINE(HAVE_WORKING_SNPRINTF)
+  AC_DEFINE(HAVE_WORKING_SNPRINTF, 1, [Define to 1 if the `snprintf' function is sane])
 fi
 AC_MSG_RESULT([$libc_have_working_snprintf])
 
 # check for __attribute__((packed))
-AH_TEMPLATE(HAVE_ATTR_PACKED, [Define to 1 if C++ compiler supports __attribute__((packed))])
 AC_MSG_CHECKING([whether $CXX supports __attribute__((packed))])
 AC_COMPILE_IFELSE([AC_LANG_PROGRAM(, [[struct a { int b; } __attribute__((packed));]])],
                   [gcc_have_attr_packed=yes], [gcc_have_attr_packed=no])
@@ -148,7 +156,7 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM(, [[#if defined(__SUNPRO_C) || defined(__SUNP
                   [true], [gcc_have_attr_packed=no])
 AC_SUBST(gcc_have_attr_packed)
 if test "$gcc_have_attr_packed" = "yes"; then
-  AC_DEFINE(HAVE_ATTR_PACKED)
+  AC_DEFINE(HAVE_ATTR_PACKED, 1, [Define to 1 if C++ compiler supports __attribute__((packed))])
 fi
 AC_MSG_RESULT([$gcc_have_attr_packed])
 
@@ -156,34 +164,34 @@ AC_SUBST(CPPFLAGS)
 AC_SUBST(LDFLAGS)
 AC_SUBST(ASFLAGS)
 
-AC_SUBST([exampledir], ['${docdir}/examplescripts'])
-
 AC_ARG_WITH(initscriptdir,
   [AC_HELP_STRING([--with-initscriptdir=DIR],[Location of init scripts [SYSCONFDIR/rc.d/init.d]])],
   [initddir="$withval"],[initddir='${sysconfdir}/rc.d/init.d'])
 AC_SUBST(initddir)
 AM_CONDITIONAL(INSTALL_INITSCRIPT, [test "$with_initscriptdir" != "no"])
 
-docdir_is_default=no
 AC_ARG_WITH(docdir,
   [AC_HELP_STRING([--with-docdir=DIR],[Location of documentation [DATADIR/doc/smartmontools]])],
   [docdir="$withval"],
   [ if test -z "$docdir"; then
       # autoconf 2.5x without '--docdir' support
       docdir='${datadir}/doc/${PACKAGE}'
-      docdir_is_default=yes
-    elif test "$docdir" = '${datarootdir}/doc/${PACKAGE_TARNAME}'; then
-      # autoconf 2.6x '--docdir' default
-      docdir_is_default=yes
     fi
   ])
 AC_SUBST(docdir)
 
-AC_ARG_ENABLE(drivedb, [AC_HELP_STRING([--enable-drivedb],[Enables drive database file])])
+AC_ARG_WITH(exampledir,
+  [AC_HELP_STRING([--with-exampledir=DIR],[Location of example scripts [DOCDIR/examplescripts]])],
+  [exampledir="$withval"], [exampledir='${docdir}/examplescripts'])
+AC_SUBST(exampledir)
+
+AC_ARG_ENABLE(drivedb,
+  [AC_HELP_STRING([--disable-drivedb],[Disables drive database file])],
+  [], [enable_drivedb=yes])
 
 AC_ARG_WITH(drivedbdir,
   [AC_HELP_STRING([--with-drivedbdir=DIR],[Location of drive database file (implies --enable-drivedb) [DATADIR/smartmontools]])],
-  [drivedbdir="$withval"; enable_drivedb="yes"],
+  [drivedbdir="$withval"; enable_drivedb=yes],
   [drivedbdir=; test "$enable_drivedb" = "yes" && drivedbdir='${datadir}/${PACKAGE}'])
 AC_SUBST(drivedbdir)
 AM_CONDITIONAL(ENABLE_DRIVEDB, [test "$enable_drivedb" = "yes"])
@@ -210,9 +218,11 @@ AC_SUBST(attributelog)
 AC_SUBST(attributelogdir)
 AM_CONDITIONAL(ENABLE_ATTRIBUTELOG, [test "$enable_attributelog" = "yes"])
 
-AC_ARG_ENABLE(sample,[AC_HELP_STRING([--enable-sample],[Enables appending .sample to the installed smartd rc script and configuration file])],[smartd_suffix='.sample'],[smartd_suffix=''])
+AC_ARG_ENABLE(sample,
+  [AC_HELP_STRING([--enable-sample],[Enables appending .sample to the installed smartd rc script and configuration file])],
+  [smartd_suffix=; test "$enableval" = "yes" && smartd_suffix=".sample"],
+  [smartd_suffix=;])
 AC_SUBST(smartd_suffix)
-AM_CONDITIONAL(SMARTD_SUFFIX, test $smartd_suffix)
 
 AC_ARG_WITH(os-deps,
   [AC_HELP_STRING([--with-os-deps='os_module.o ...'],[Specify OS dependent module(s) [guessed]])],
@@ -224,18 +234,20 @@ AC_ARG_WITH(os-deps,
     done
   ],[])
 
-AC_ARG_WITH(selinux,[AC_HELP_STRING([--with-selinux],[Enables SELinux support])],
-       [
-               AC_CHECK_HEADERS([selinux/selinux.h], [], [echo "*** Error: Missing SELinux header files";exit 1])
-               AC_CHECK_LIB(selinux, matchpathcon, [with_selinux=yes], [echo "*** Error: Missing or incorrect SELinux library files"; exit 1],)
-       ],[])
+AC_ARG_WITH(selinux,
+  [AC_HELP_STRING([--with-selinux@<:@=yes|no@:>@],[Enables SELinux support [no]])],
+  [ if test "$withval" = "yes"; then
+      AC_CHECK_HEADERS([selinux/selinux.h], [], [AC_MSG_ERROR([Missing SELinux header files])])
+      AC_CHECK_LIB(selinux, matchpathcon, [], [AC_MSG_ERROR([Missing or incorrect SELinux library files])])
+    fi
+  ],[])
 AC_SUBST(with_selinux)
 if test "$with_selinux" = "yes"; then
-       AC_DEFINE(WITH_SELINUX, [1], [Define to 1 if SELinux support is enabled])
+  AC_DEFINE(WITH_SELINUX, 1, [Define to 1 if SELinux support is enabled])
 fi
 
 AC_ARG_WITH(libcap-ng,
-  [AC_HELP_STRING([--with-libcap-ng=[auto|yes|no]], [Add Libcap-ng support to smartd [auto]])],
+  [AC_HELP_STRING([--with-libcap-ng@<:@=auto|yes|no@:>@],[Add Libcap-ng support to smartd [auto]])],
   [with_libcap_ng="$withval"],
   [with_libcap_ng=auto])
 
@@ -268,69 +280,74 @@ AC_SUBST(releaseversion,['${PACKAGE}-${VERSION}'])
 AC_SUBST(smartmontools_release_date)
 AC_SUBST(smartmontools_release_time)
 
-AC_MSG_CHECKING([for OS dependent modules and libraries])
-dnl if OS not recognized, then use the os_generic modules
+# Set platform-specific modules and symbols
+os_libs=
+os_dltools='curl wget lynx'
+os_mailer=
+os_darwin=no
+os_solaris=no
+os_win32=no
+os_win32_mingw=no
 os_win64=no
 case "${host}" in
-       *-*-linux*)
-               AC_SUBST([os_deps], ['os_linux.o cciss.o']) 
-               if test "$with_selinux" = "yes"; then
-                       AC_SUBST([os_libs], ['-lselinux'])
-               else
-                       AC_SUBST([os_libs], [''])
-               fi;;
-       *-*-freebsd*|*-*-dragonfly*|*-*-kfreebsd*-gnu*)
-               AC_SUBST([os_deps], ['os_freebsd.o cciss.o']) 
-               AC_SUBST([os_libs], ['-lcam'])
-               AC_CHECK_LIB(usb, libusb20_dev_get_device_desc)
-               ;;
-       sparc-*-solaris*) 
-               AC_DEFINE_UNQUOTED(DEFAULT_MAILER, "mailx", [use mailx as default mailer])
-               AC_DEFINE_UNQUOTED(NEED_SOLARIS_ATA_CODE, "os_solaris_ata.s", [need assembly code os_solaris_ata.s])
-               AC_SUBST([os_deps], ['os_solaris.o os_solaris_ata.o']) 
-               AC_SUBST([os_libs], ['']) ;;
-       *-pc-solaris*) 
-               AC_DEFINE_UNQUOTED(DEFAULT_MAILER, "mailx", [use mailx as default mailer]) 
-               AC_SUBST([os_deps], ['os_solaris.o']) 
-               AC_SUBST([os_libs], ['']) ;;
-       *-*-netbsd*)
-               AC_SUBST([os_deps], ['os_netbsd.o']) 
-               AC_SUBST([os_libs], ['-lutil']) ;;
-       *-*-openbsd*)
-               AC_SUBST([os_deps], ['os_openbsd.o'])
-               AC_SUBST([os_libs], ['-lutil']) ;;
-       *-*-cygwin*)
-               AC_SUBST([os_deps], ['os_win32.o'])
-               AC_SUBST([os_libs], ['']) ;;
-       *-*-mingw*)
-               AC_SUBST([os_deps], ['os_win32.o'])
-               AC_SUBST([os_libs], [''])
-               test "$host_cpu" = "x86_64" && os_win64=yes ;;
-       *-*-darwin*)
-               AC_SUBST([os_deps], ['os_darwin.o'])
-               AC_SUBST([os_libs], ['-framework CoreFoundation -framework IOKit']) ;;
-       *-*-nto-qnx*)
-               AC_SUBST([os_deps], ['os_qnxnto.o'])
-               AC_SUBST([os_libs], ['']) ;;
-               
-       *)
-               AC_SUBST([os_deps], ['os_generic.o']) 
-               AC_SUBST([os_libs], ['']) ;;
+  *-*-linux*)
+    os_deps='os_linux.o cciss.o'
+    ;;
+  *-*-freebsd*|*-*-dragonfly*|*-*-kfreebsd*-gnu*)
+    os_deps='os_freebsd.o cciss.o'
+    os_libs='-lcam'
+    os_dltools='curl wget lynx fetch'
+    AC_CHECK_LIB(usb, libusb20_dev_get_device_desc)
+    ;;
+  sparc-*-solaris*)
+    os_deps='os_solaris.o os_solaris_ata.o'
+    os_mailer='mailx'
+    os_solaris=yes
+    ;;
+  *-pc-solaris*)
+    os_deps='os_solaris.o'
+    os_mailer='mailx'
+    os_solaris=yes
+    ;;
+  *-*-netbsd*)
+    os_deps='os_netbsd.o'
+    os_libs='-lutil'
+    ;;
+  *-*-openbsd*)
+    os_deps='os_openbsd.o'
+    os_libs='-lutil'
+    os_dltools='curl wget lynx ftp'
+    ;;
+  *-*-cygwin*)
+    os_deps='os_win32.o'
+    os_win32=yes
+    ;;
+  x86_64-*-mingw*)
+    os_deps='os_win32.o'
+    os_win32=yes
+    os_win32_mingw=yes
+    os_win64=yes
+    ;;
+  *-*-mingw*)
+    os_deps='os_win32.o'
+    os_win32=yes
+    os_win32_mingw=yes
+    ;;
+  *-*-darwin*)
+    os_deps='os_darwin.o'
+    os_libs='-framework CoreFoundation -framework IOKit'
+    os_darwin=yes
+    ;;
+  *-*-nto-qnx*)
+    os_deps='os_qnxnto.o'
+    ;;
+  *)
+    os_deps='os_generic.o'
+    ;;
 esac
 
 # Replace if '--with-os-deps' was specified
 test -z "$with_os_deps" || os_deps="$with_os_deps"
-AC_MSG_RESULT([$os_deps $os_libs])
-
-# Define symbols for optional functions in OS specific module
-case "${os_deps}" in
-  os_win32*)
-    AC_DEFINE(HAVE_ATA_IDENTIFY_IS_CACHED, 1, [Define to 1 if you have the `ata_identify_is_cached' function in os_*.c.]) ;;
-esac
-case "${os_deps}" in
-  os_win32*)
-    AC_DEFINE(HAVE_GET_OS_VERSION_STR, 1, [Define to 1 if you have the `get_os_version_str' function in os_*.c.]) ;;
-esac
 
 # Check if we need adapter to old interface (dev_legacy.cpp)
 os_src=`echo "${os_deps}"|sed -n 's,^\([[^ .]]*\)\.o.*$,\1.cpp,p'`
@@ -344,12 +361,29 @@ else
 fi
 AC_MSG_RESULT([$os_new_interface])
 
-dnl Define platform-specific symbol.
-AM_CONDITIONAL(OS_DARWIN, [echo $host_os | grep '^darwin' > /dev/null])
-AM_CONDITIONAL(OS_SOLARIS, [echo $host_os | grep '^solaris' > /dev/null])
-AM_CONDITIONAL(OS_WIN32_MINGW, [echo $host_os | grep '^mingw' > /dev/null])
+AC_SUBST([os_deps])
+AC_SUBST([os_libs])
+AC_SUBST([os_dltools])
+if test -n "$os_mailer"; then
+  AC_DEFINE_UNQUOTED(DEFAULT_MAILER, "$os_mailer", [Default mailer if "mail" is unavailable])
+fi
+
+# Create drivedb.h update branch name from version: 5.41[.X] -> RELEASE_5_41_DRIVEDB
+DRIVEDB_BRANCH=`echo $VERSION | sed 's,^\([[0-9]]*\.[[0-9]]*\)\..*$,\1,' \
+                | sed -n 's,^\([[0-9]][[0-9]]*\)\.\([[0-9]][[0-9]]*\)$,RELEASE_\1_\2_DRIVEDB,p'`
+if test -z "$DRIVEDB_BRANCH"; then
+  AC_MSG_ERROR([Unable to create DRIVEDB_BRANCH from VERSION=$VERSION])
+fi
+AC_SUBST([DRIVEDB_BRANCH])
+
+# Enable platform-specific makefile sections
+AM_CONDITIONAL(OS_DARWIN, [test "$os_darwin" = "yes"])
+AM_CONDITIONAL(OS_SOLARIS, [test "$os_solaris" = "yes"])
+AM_CONDITIONAL(OS_WIN32, [test "$os_win32" = "yes"])
+AM_CONDITIONAL(OS_WIN32_MINGW, [test "$os_win32_mingw" = "yes"])
+AM_CONDITIONAL(OS_WIN32_NSIS, [test -n "$MAKENSIS"])
+AM_CONDITIONAL(OS_WIN32_WINDMC, [test -n "$WINDMC" && test "$WINDMC" != "no" && test -n "$WINDRES"])
 AM_CONDITIONAL(OS_WIN64, [test "$os_win64" = "yes"])
-AM_CONDITIONAL(OS_FREEBSD, [echo $host_os | grep '^freebsd' > /dev/null])
 
 dnl Add -Wall and -W if using g++ and its not already specified.
 if test "$GXX" = "yes"; then
@@ -366,20 +400,6 @@ if test "$GXX" = "yes"; then
       CXXFLAGS="$CXXFLAGS -Wno-format";;
   esac
 
-  # Disable strict aliasing rules by default (see ticket #23).
-  if test -z "`echo "$CXXFLAGS" | grep "\-f[[no-]]*strict-aliasing" 2> /dev/null`" ; then
-    AC_MSG_CHECKING([whether $CXX supports -fno-strict-aliasing])
-    ac_save_CXXFLAGS="$CXXFLAGS"
-    CXXFLAGS="-fno-strict-aliasing"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
-      [gcc_have_fno_strict_aliasing=yes], [gcc_have_fno_strict_aliasing=no])
-    CXXFLAGS="$ac_save_CXXFLAGS"
-    if test "$gcc_have_fno_strict_aliasing" = "yes"; then
-      CXXFLAGS="$CXXFLAGS -fno-strict-aliasing"
-    fi
-    AC_MSG_RESULT([$gcc_have_fno_strict_aliasing])
-  fi
-
 else
  dnl We are NOT using gcc, so enable host-specific compiler flags
  case "${host}" in
@@ -407,21 +427,31 @@ AC_DEFINE_UNQUOTED(SMARTMONTOOLS_BUILD_HOST,     "${host}",
 
 AC_SUBST(CXXFLAGS)
 
-AC_OUTPUT(Makefile examplescripts/Makefile)
+AC_CONFIG_FILES(Makefile)
+AC_OUTPUT
 AC_PROG_MAKE_SET
 
 echo "-----------------------------------------------------------------------------" >&AS_MESSAGE_FD
 echo "${PACKAGE}-${VERSION} configuration:" >&AS_MESSAGE_FD
 echo "host operating system:  $host" >&AS_MESSAGE_FD
 echo "C++ compiler:           $CXX" >&AS_MESSAGE_FD
+echo "C compiler:             $CC" >&AS_MESSAGE_FD
 echo "preprocessor flags:     $CPPFLAGS" >&AS_MESSAGE_FD
 echo "C++ compiler flags:     $CXXFLAGS" >&AS_MESSAGE_FD
+echo "C compiler flags:       $CFLAGS" >&AS_MESSAGE_FD
 echo "linker flags:           $LDFLAGS" >&AS_MESSAGE_FD
+echo "OS specific modules:    $os_deps $os_libs $LIBS" >&AS_MESSAGE_FD
 
 case "$host_os" in
   mingw*)
+    echo "resource compiler:      $WINDRES" >&AS_MESSAGE_FD
+    echo "message compiler:       $WINDMC" >&AS_MESSAGE_FD
+    echo "NSIS compiler:          $MAKENSIS" >&AS_MESSAGE_FD
     if test -n "$drivedbdir"; then
       echo "drive database file:    EXEDIR/drivedb.h" >&AS_MESSAGE_FD
+      if test -n "$MAKENSIS"; then
+        echo "database update tool:   EXEDIR/update-smart-drivedb.exe" >&AS_MESSAGE_FD
+      fi
     else
       echo "drive database file:    [[disabled]]" >&AS_MESSAGE_FD
     fi
@@ -437,15 +467,13 @@ case "$host_os" in
     echo "binary install path:    `eval eval eval echo $sbindir`" >&AS_MESSAGE_FD
     echo "man page install path:  `eval eval eval echo $mandir`" >&AS_MESSAGE_FD
     echo "doc file install path:  `eval eval eval echo $docdir`" >&AS_MESSAGE_FD
-    if test "$docdir_is_default" = "yes"; then
-      echo "(NOTE: old default was: `eval eval eval echo ${prefix}/share/doc/${PACKAGE}-${VERSION}`)" >&AS_MESSAGE_FD
-    fi
+    echo "examples install path:  `eval eval eval echo $exampledir`" >&AS_MESSAGE_FD
     if test -n "$drivedbdir"; then
       echo "drive database file:    `eval eval eval echo $drivedbdir`/drivedb.h" >&AS_MESSAGE_FD
       echo "database update script: `eval eval eval echo $sbindir`/update-smart-drivedb" >&AS_MESSAGE_FD
+      echo "download tools:         `eval eval eval echo $os_dltools`" >&AS_MESSAGE_FD
     else
       echo "drive database file:    [[disabled]]" >&AS_MESSAGE_FD
-      echo "database update script: [[disabled]]" >&AS_MESSAGE_FD
     fi
     echo "local drive database:   `eval eval eval echo $sysconfdir`/smart_drivedb.h" >&AS_MESSAGE_FD
     echo "smartd config file:     `eval eval eval echo $sysconfdir`/smartd.conf${smartd_suffix}" >&AS_MESSAGE_FD
diff --git a/csmisas.h b/csmisas.h
new file mode 100644 (file)
index 0000000..087fa78
--- /dev/null
+++ b/csmisas.h
@@ -0,0 +1,1858 @@
+/**************************************************************************
+
+Module Name:
+
+   CSMISAS.H
+
+
+Abstract:
+
+   This file contains constants and data structure definitions used by drivers
+   that support the Common Storage Management Interface specification for
+   SAS or SATA in either the Windows or Linux.
+
+   This should be considered as a reference implementation only.  Changes may
+   be necessary to accommodate a specific build environment or target OS.
+
+Revision History:
+
+   001  SEF   8/12/03  Initial release.
+   002  SEF   8/20/03  Cleanup to match documentation.
+   003  SEF   9/12/03  Additional cleanup, created combined header
+   004  SEF   9/23/03  Changed base types to match linux defaults
+                       Added RAID signature
+                       Added bControllerFlags to CSMI_SAS_CNTLR_CONFIG
+                       Changed CSMI_SAS_BEGIN_PACK to 8 for common structures
+                       Fixed other typos identified in first compilation test
+   005  SEF  10/03/03  Additions to match first version of CSMI document
+   006  SEF  10/14/03  Fixed typedef struct _CSMI_SAS_SMP_PASSTHRU_BUFFER
+                       Added defines for bConnectionRate
+   007  SEF  10/15/03  Added Firmware Download Control Code and support
+                       Added CSMI revision support
+   008  SEF  10/30/03  No functional change, just updated version to track
+                       spec changes
+   009  SEF  12/09/03  No functional change, just updated version to track
+                       spec changes
+   010  SEF   3/11/04  Fixed typedef struct CSMI_SAS_RAID_DRIVES to include the
+                       bFirmware member that is defined in the spec, but
+                       was missing in this file,
+                       added CC_CSMI_SAS_TASK_MANAGEMENT
+   011  SEF   4/02/04  No functional change, added comment line before
+                       CC_CSMI_SAS_TASK_MANAGEMENT
+   012  SEF   4/16/04  Added IOControllerNumber to linux header,
+                       Modified linux control codes to have upper word of
+                       0xCC77.... to indicate CSMI version 77
+                       Added bSignalClass to CC_CSMI_SET_PHY_INFO
+                       Added CC_CSMI_SAS_PHY_CONTROL support
+   013  SEF   5/14/04  Added CC_CSMI_SAS_GET_CONNECTOR_INFO support
+   014  SEF   5/24/04  No functional change, just updated version to track spec
+                       changes
+   015  SEF   6/16/04  changed bPinout to uPinout to reflect proper size,
+                       changed width of bLocation defines to reflect size
+   016  SEF   6/17/04  changed bLengthOfControls in CSMI_SAS_PHY_CONTROL
+                       to be proper size
+   017  SEF   9/17/04  added CSMI_SAS_SATA_PORT_SELECTOR,
+                       CSMI_SAS_LINK_VIRTUAL, CSMI_SAS_CON_NOT_PRESENT, and
+                       CSMI_SAS_CON_NOT_CONNECTED
+   018  SEF   9/20/04  added CSMI_SAS_PHY_USER_PATTERN,
+                       changed definition of CSMI_SAS_PHY_FIXED_PATTERN to not
+                       conflict with activate definition
+   019  SEF  12/06/04  added CSMI_SAS_GET_LOCATION
+                       added bSSPStatus to CSMI_SAS_SSP_PASSTHRU_STATUS
+                       structure
+   020  SEF   5/25/05  added CSMI_SAS_PHY_VIRTUAL_SMP, and changes to
+                       CSMI_SAS_GET_LOCATION
+   021  SEF  11/03/05  added new RAID creation functionality
+   022  SEF   2/01/06  corrected typo bNegotitiatedLInkRate
+                       Added two more RAID_TYPES, 7 and 8
+   023  SEF   4/04/06  added CSMI_RAID_TYPE_1E
+                       changed structures that contained surface scan
+                       to priority approach rather than time, causes
+                       0.89 to incompatible with 0.87, so a version
+                       check is necessary when interpreting the
+                       raid structures
+                       Added netware section
+   024 DRG    5/22/06  Added uFailureCode to CSMI_SAS_RAID_CONFIG and
+                       CSMI_SAS_RAID_FEATURES
+                       Changed __u64 fields to high and low __u32 fields in
+                       order to avoid backward compatibility issues with
+                       packing and alignment.
+                       Fixed alignment problem in CSMI_SAS_RAID_DRIVES.
+                       Added CSMI_SAS_CNTLR_SMART_ARRAY to uControllerFlags
+                       Reassigned the value of CSMI_SAS_CNTLR_RAID_CFG_SUPPORT
+                       to avoid a conflict.
+
+**************************************************************************/
+
+#ifndef _CSMI_SAS_H_
+#define _CSMI_SAS_H_
+
+// CSMI Specification Revision, the intent is that all versions of the
+// specification will be backward compatible after the 1.00 release.
+// Major revision number, corresponds to xxxx. of CSMI specification
+// Minor revision number, corresponds to .xxxx of CSMI specification
+#define CSMI_MAJOR_REVISION   0
+#define CSMI_MINOR_REVISION   90
+
+/*************************************************************************/
+/* PATCHES FOR TYPOS                                                     */
+/*************************************************************************/
+
+#define bNegotitiatedLInkRate bNegotiatedLinkRate
+
+/*************************************************************************/
+/* TARGET OS LINUX SPECIFIC CODE                                         */
+/*************************************************************************/
+
+// EDM #ifdef _linux
+#ifdef __KERNEL__
+
+// Linux base types
+
+#include <linux/types.h>
+
+#define __i8    char
+
+// pack definition
+
+// EDM #define CSMI_SAS_BEGIN_PACK(x)    pack(x)
+// EDM #define CSMI_SAS_END_PACK         pack()
+
+// IOCTL Control Codes
+// (IoctlHeader.ControlCode)
+
+// Control Codes prior to 0.77
+
+// Control Codes requiring CSMI_ALL_SIGNATURE
+
+// #define CC_CSMI_SAS_GET_DRIVER_INFO    0x12345678
+// #define CC_CSMI_SAS_GET_CNTLR_CONFIG   0x23456781
+// #define CC_CSMI_SAS_GET_CNTLR_STATUS   0x34567812
+// #define CC_CSMI_SAS_FIRMWARE_DOWNLOAD  0x92345678
+
+// Control Codes requiring CSMI_RAID_SIGNATURE
+
+// #define CC_CSMI_SAS_GET_RAID_INFO      0x45678123
+// #define CC_CSMI_SAS_GET_RAID_CONFIG    0x56781234
+
+// Control Codes requiring CSMI_SAS_SIGNATURE
+
+// #define CC_CSMI_SAS_GET_PHY_INFO       0x67812345
+// #define CC_CSMI_SAS_SET_PHY_INFO       0x78123456
+// #define CC_CSMI_SAS_GET_LINK_ERRORS    0x81234567
+// #define CC_CSMI_SAS_SMP_PASSTHRU       0xA1234567
+// #define CC_CSMI_SAS_SSP_PASSTHRU       0xB1234567
+// #define CC_CSMI_SAS_STP_PASSTHRU       0xC1234567
+// #define CC_CSMI_SAS_GET_SATA_SIGNATURE 0xD1234567
+// #define CC_CSMI_SAS_GET_SCSI_ADDRESS   0xE1234567
+// #define CC_CSMI_SAS_GET_DEVICE_ADDRESS 0xF1234567
+// #define CC_CSMI_SAS_TASK_MANAGEMENT    0xA2345678
+
+// Control Codes for 0.77 and later
+
+// Control Codes requiring CSMI_ALL_SIGNATURE
+
+#define CC_CSMI_SAS_GET_DRIVER_INFO    0xCC770001
+#define CC_CSMI_SAS_GET_CNTLR_CONFIG   0xCC770002
+#define CC_CSMI_SAS_GET_CNTLR_STATUS   0xCC770003
+#define CC_CSMI_SAS_FIRMWARE_DOWNLOAD  0xCC770004
+
+// Control Codes requiring CSMI_RAID_SIGNATURE
+
+#define CC_CSMI_SAS_GET_RAID_INFO      0xCC77000A
+#define CC_CSMI_SAS_GET_RAID_CONFIG    0xCC77000B
+#define CC_CSMI_SAS_GET_RAID_FEATURES  0xCC77000C
+#define CC_CSMI_SAS_SET_RAID_CONTROL   0xCC77000D
+#define CC_CSMI_SAS_GET_RAID_ELEMENT   0xCC77000E
+#define CC_CSMI_SAS_SET_RAID_OPERATION 0xCC77000F
+
+// Control Codes requiring CSMI_SAS_SIGNATURE
+
+#define CC_CSMI_SAS_GET_PHY_INFO       0xCC770014
+#define CC_CSMI_SAS_SET_PHY_INFO       0xCC770015
+#define CC_CSMI_SAS_GET_LINK_ERRORS    0xCC770016
+#define CC_CSMI_SAS_SMP_PASSTHRU       0xCC770017
+#define CC_CSMI_SAS_SSP_PASSTHRU       0xCC770018
+#define CC_CSMI_SAS_STP_PASSTHRU       0xCC770019
+#define CC_CSMI_SAS_GET_SATA_SIGNATURE 0xCC770020
+#define CC_CSMI_SAS_GET_SCSI_ADDRESS   0xCC770021
+#define CC_CSMI_SAS_GET_DEVICE_ADDRESS 0xCC770022
+#define CC_CSMI_SAS_TASK_MANAGEMENT    0xCC770023
+#define CC_CSMI_SAS_GET_CONNECTOR_INFO 0xCC770024
+#define CC_CSMI_SAS_GET_LOCATION       0xCC770025
+
+
+// Control Codes requiring CSMI_PHY_SIGNATURE
+
+#define CC_CSMI_SAS_PHY_CONTROL        0xCC77003C
+
+// EDM #pragma CSMI_SAS_BEGIN_PACK(8)
+#pragma pack(8)
+
+// IOCTL_HEADER
+typedef struct _IOCTL_HEADER {
+    __u32 IOControllerNumber;
+    __u32 Length;
+    __u32 ReturnCode;
+    __u32 Timeout;
+    __u16 Direction;
+} IOCTL_HEADER,
+  *PIOCTL_HEADER;
+
+// EDM #pragma CSMI_SAS_END_PACK
+#pragma pack()
+
+#endif
+
+/*************************************************************************/
+/* TARGET OS WINDOWS SPECIFIC CODE                                       */
+/*************************************************************************/
+
+#ifdef _WIN32
+
+// windows IOCTL definitions
+
+#if 0 // <ntddscsi.h> and CSMI_*_PACK are no longer needed
+
+#ifndef _NTDDSCSIH_
+#include <ntddscsi.h>
+#endif
+
+// pack definition
+
+#if defined _MSC_VER
+   #define CSMI_SAS_BEGIN_PACK(x)    pack(push,x)
+   #define CSMI_SAS_END_PACK         pack(pop)
+#elif defined __BORLANDC__
+   #define CSMI_SAS_BEGIN_PACK(x)    option -a##x
+   #define CSMI_SAS_END_PACK         option -a.
+#else
+   #error "CSMISAS.H - Must externally define a pack compiler designator."
+#endif
+
+#endif // #if 0
+
+// base types
+
+#define __u8    unsigned char
+#define __u16   unsigned short
+#define __u32   unsigned long
+#define __u64   unsigned __int64
+
+#define __i8    char
+
+// IOCTL Control Codes
+// (IoctlHeader.ControlCode)
+
+// Control Codes requiring CSMI_ALL_SIGNATURE
+
+#define CC_CSMI_SAS_GET_DRIVER_INFO    1
+#define CC_CSMI_SAS_GET_CNTLR_CONFIG   2
+#define CC_CSMI_SAS_GET_CNTLR_STATUS   3
+#define CC_CSMI_SAS_FIRMWARE_DOWNLOAD  4
+
+// Control Codes requiring CSMI_RAID_SIGNATURE
+
+#define CC_CSMI_SAS_GET_RAID_INFO      10
+#define CC_CSMI_SAS_GET_RAID_CONFIG    11
+#define CC_CSMI_SAS_GET_RAID_FEATURES  12
+#define CC_CSMI_SAS_SET_RAID_CONTROL   13
+#define CC_CSMI_SAS_GET_RAID_ELEMENT   14
+#define CC_CSMI_SAS_SET_RAID_OPERATION 15
+
+// Control Codes requiring CSMI_SAS_SIGNATURE
+
+#define CC_CSMI_SAS_GET_PHY_INFO       20
+#define CC_CSMI_SAS_SET_PHY_INFO       21
+#define CC_CSMI_SAS_GET_LINK_ERRORS    22
+#define CC_CSMI_SAS_SMP_PASSTHRU       23
+#define CC_CSMI_SAS_SSP_PASSTHRU       24
+#define CC_CSMI_SAS_STP_PASSTHRU       25
+#define CC_CSMI_SAS_GET_SATA_SIGNATURE 26
+#define CC_CSMI_SAS_GET_SCSI_ADDRESS   27
+#define CC_CSMI_SAS_GET_DEVICE_ADDRESS 28
+#define CC_CSMI_SAS_TASK_MANAGEMENT    29
+#define CC_CSMI_SAS_GET_CONNECTOR_INFO 30
+#define CC_CSMI_SAS_GET_LOCATION       31
+
+// Control Codes requiring CSMI_PHY_SIGNATURE
+
+#define CC_CSMI_SAS_PHY_CONTROL        60
+
+#define IOCTL_HEADER SRB_IO_CONTROL
+#define PIOCTL_HEADER PSRB_IO_CONTROL
+
+#endif
+
+/*************************************************************************/
+/* TARGET OS NETWARE SPECIFIC CODE                                       */
+/*************************************************************************/
+
+#ifdef _NETWARE
+
+// NetWare IOCTL definitions
+
+#define CSMI_SAS_BEGIN_PACK(x)    pack(x)
+#define CSMI_SAS_END_PACK         pack()
+
+#ifndef LONG
+typedef unsigned long LONG;
+#endif
+
+#ifndef WORD
+typedef unsigned short WORD;
+#endif
+
+#ifndef BYTE
+typedef unsigned char BYTE;
+#endif
+
+/* Need to have these definitions for Netware */
+#define __u8    unsigned char
+#define __u16   unsigned short
+#define __u32   unsigned long
+#define __u64   unsigned __int64
+
+#define __i8    char
+
+
+// EDM #pragma CSMI_SAS_BEGIN_PACK(8)
+#pragma pack(8)
+
+// IOCTL_HEADER
+typedef struct _IOCTL_HEADER {
+    __u32 Length;
+    __u32 ReturnCode;
+} IOCTL_HEADER,
+  *PIOCTL_HEADER;
+
+// EDM #pragma CSMI_SAS_END_PACK
+#pragma pack()
+
+// IOCTL Control Codes
+// (IoctlHeader.ControlCode)
+
+// Control Codes requiring CSMI_ALL_SIGNATURE
+
+#define CC_CSMI_SAS_GET_DRIVER_INFO    0x01FF0001
+#define CC_CSMI_SAS_GET_CNTLR_CONFIG   0x01FF0002
+#define CC_CSMI_SAS_GET_CNTLR_STATUS   0x01FF0003
+#define CC_CSMI_SAS_FIRMWARE_DOWNLOAD  0x01FF0004
+
+// Control Codes requiring CSMI_RAID_SIGNATURE
+
+#define CC_CSMI_SAS_GET_RAID_INFO      0x01FF000A
+#define CC_CSMI_SAS_GET_RAID_CONFIG    0x01FF000B
+#define CC_CSMI_SAS_GET_RAID_FEATURES  0x01FF000C
+#define CC_CSMI_SAS_SET_RAID_CONTROL   0x01FF000D
+#define CC_CSMI_SAS_GET_RAID_ELEMENT   0x01FF000E
+#define CC_CSMI_SAS_SET_RAID_OPERATION 0x01FF000F
+
+// Control Codes requiring CSMI_SAS_SIGNATURE
+
+#define CC_CSMI_SAS_GET_PHY_INFO       0x01FF0014
+#define CC_CSMI_SAS_SET_PHY_INFO       0x01FF0015
+#define CC_CSMI_SAS_GET_LINK_ERRORS    0x01FF0016
+#define CC_CSMI_SAS_SMP_PASSTHRU       0x01FF0017
+#define CC_CSMI_SAS_SSP_PASSTHRU       0x01FF0018
+#define CC_CSMI_SAS_STP_PASSTHRU       0x01FF0019
+#define CC_CSMI_SAS_GET_SATA_SIGNATURE 0x01FF001A
+#define CC_CSMI_SAS_GET_SCSI_ADDRESS   0x01FF001B
+#define CC_CSMI_SAS_GET_DEVICE_ADDRESS 0x01FF001C
+#define CC_CSMI_SAS_TASK_MANAGEMENT    0x01FF001D
+#define CC_CSMI_SAS_GET_CONNECTOR_INFO 0x01FF001E
+#define CC_CSMI_SAS_GET_LOCATION       0x01FF001F
+
+// Control Codes requiring CSMI_PHY_SIGNATURE
+
+#define CC_CSMI_SAS_PHY_CONTROL        60
+
+#endif
+
+/*************************************************************************/
+/* TARGET OS NOT DEFINED ERROR                                           */
+/*************************************************************************/
+
+// EDM
+//#if (!_WIN32 && !_linux && !_NETWARE)
+//   #error "Unknown target OS."
+//#endif
+
+/*************************************************************************/
+/* OS INDEPENDENT CODE                                                   */
+/*************************************************************************/
+
+/* * * * * * * * * * Class Independent IOCTL Constants * * * * * * * * * */
+
+// Return codes for all IOCTL's regardless of class
+// (IoctlHeader.ReturnCode)
+
+#define CSMI_SAS_STATUS_SUCCESS              0
+#define CSMI_SAS_STATUS_FAILED               1
+#define CSMI_SAS_STATUS_BAD_CNTL_CODE        2
+#define CSMI_SAS_STATUS_INVALID_PARAMETER    3
+#define CSMI_SAS_STATUS_WRITE_ATTEMPTED      4
+
+// Signature value
+// (IoctlHeader.Signature)
+
+#define CSMI_ALL_SIGNATURE    "CSMIALL"
+
+// Timeout value default of 60 seconds
+// (IoctlHeader.Timeout)
+
+#define CSMI_ALL_TIMEOUT      60
+
+//  Direction values for data flow on this IOCTL
+// (IoctlHeader.Direction, Linux only)
+#define CSMI_SAS_DATA_READ    0
+#define CSMI_SAS_DATA_WRITE   1
+
+// I/O Bus Types
+// ISA and EISA bus types are not supported
+// (bIoBusType)
+
+#define CSMI_SAS_BUS_TYPE_PCI       3
+#define CSMI_SAS_BUS_TYPE_PCMCIA    4
+
+// Controller Status
+// (uStatus)
+
+#define CSMI_SAS_CNTLR_STATUS_GOOD     1
+#define CSMI_SAS_CNTLR_STATUS_FAILED   2
+#define CSMI_SAS_CNTLR_STATUS_OFFLINE  3
+#define CSMI_SAS_CNTLR_STATUS_POWEROFF 4
+
+// Offline Status Reason
+// (uOfflineReason)
+
+#define CSMI_SAS_OFFLINE_REASON_NO_REASON             0
+#define CSMI_SAS_OFFLINE_REASON_INITIALIZING          1
+#define CSMI_SAS_OFFLINE_REASON_BACKSIDE_BUS_DEGRADED 2
+#define CSMI_SAS_OFFLINE_REASON_BACKSIDE_BUS_FAILURE  3
+
+// Controller Class
+// (bControllerClass)
+
+#define CSMI_SAS_CNTLR_CLASS_HBA    5
+
+// Controller Flag bits
+// (uControllerFlags)
+
+#define CSMI_SAS_CNTLR_SAS_HBA          0x00000001
+#define CSMI_SAS_CNTLR_SAS_RAID         0x00000002
+#define CSMI_SAS_CNTLR_SATA_HBA         0x00000004
+#define CSMI_SAS_CNTLR_SATA_RAID        0x00000008
+#define CSMI_SAS_CNTLR_SMART_ARRAY      0x00000010
+
+// for firmware download
+#define CSMI_SAS_CNTLR_FWD_SUPPORT      0x00010000
+#define CSMI_SAS_CNTLR_FWD_ONLINE       0x00020000
+#define CSMI_SAS_CNTLR_FWD_SRESET       0x00040000
+#define CSMI_SAS_CNTLR_FWD_HRESET       0x00080000
+#define CSMI_SAS_CNTLR_FWD_RROM         0x00100000
+
+// for RAID configuration supported
+#define CSMI_SAS_CNTLR_RAID_CFG_SUPPORT 0x01000000
+
+// Download Flag bits
+// (uDownloadFlags)
+#define CSMI_SAS_FWD_VALIDATE       0x00000001
+#define CSMI_SAS_FWD_SOFT_RESET     0x00000002
+#define CSMI_SAS_FWD_HARD_RESET     0x00000004
+
+// Firmware Download Status
+// (usStatus)
+#define CSMI_SAS_FWD_SUCCESS        0
+#define CSMI_SAS_FWD_FAILED         1
+#define CSMI_SAS_FWD_USING_RROM     2
+#define CSMI_SAS_FWD_REJECT         3
+#define CSMI_SAS_FWD_DOWNREV        4
+
+// Firmware Download Severity
+// (usSeverity>
+#define CSMI_SAS_FWD_INFORMATION    0
+#define CSMI_SAS_FWD_WARNING        1
+#define CSMI_SAS_FWD_ERROR          2
+#define CSMI_SAS_FWD_FATAL          3
+
+/* * * * * * * * * * SAS RAID Class IOCTL Constants  * * * * * * * * */
+
+// Return codes for the RAID IOCTL's regardless of class
+// (IoctlHeader.ReturnCode)
+
+#define CSMI_SAS_RAID_SET_OUT_OF_RANGE       1000
+#define CSMI_SAS_RAID_SET_BUFFER_TOO_SMALL   1001
+#define CSMI_SAS_RAID_SET_DATA_CHANGED       1002
+
+// Signature value
+// (IoctlHeader.Signature)
+
+#define CSMI_RAID_SIGNATURE    "CSMIARY"
+
+// Timeout value default of 60 seconds
+// (IoctlHeader.Timeout)
+
+#define CSMI_RAID_TIMEOUT      60
+
+// RAID Types
+// (bRaidType)
+#define CSMI_SAS_RAID_TYPE_NONE     0
+#define CSMI_SAS_RAID_TYPE_0        1
+#define CSMI_SAS_RAID_TYPE_1        2
+#define CSMI_SAS_RAID_TYPE_10       3
+#define CSMI_SAS_RAID_TYPE_5        4
+#define CSMI_SAS_RAID_TYPE_15       5
+#define CSMI_SAS_RAID_TYPE_6        6
+#define CSMI_SAS_RAID_TYPE_50       7
+#define CSMI_SAS_RAID_TYPE_VOLUME   8
+#define CSMI_SAS_RAID_TYPE_1E       9
+#define CSMI_SAS_RAID_TYPE_OTHER    255
+// the last value 255 was already defined for other
+// so end is defined as 254
+#define CSMI_SAS_RAID_TYPE_END      254
+
+// RAID Status
+// (bStatus)
+#define CSMI_SAS_RAID_SET_STATUS_OK             0
+#define CSMI_SAS_RAID_SET_STATUS_DEGRADED       1
+#define CSMI_SAS_RAID_SET_STATUS_REBUILDING     2
+#define CSMI_SAS_RAID_SET_STATUS_FAILED         3
+#define CSMI_SAS_RAID_SET_STATUS_OFFLINE        4
+#define CSMI_SAS_RAID_SET_STATUS_TRANSFORMING   5
+#define CSMI_SAS_RAID_SET_STATUS_QUEUED_FOR_REBUILD         6
+#define CSMI_SAS_RAID_SET_STATUS_QUEUED_FOR_TRANSFORMATION  7
+
+// RAID Drive Count
+// (bDriveCount, 0xF1 to 0xFF are reserved)
+#define CSMI_SAS_RAID_DRIVE_COUNT_TOO_BIG   0xF1
+#define CSMI_SAS_RAID_DRIVE_COUNT_SUPRESSED 0xF2
+
+// RAID Data Type
+// (bDataType)
+#define CSMI_SAS_RAID_DATA_DRIVES           0
+#define CSMI_SAS_RAID_DATA_DEVICE_ID        1
+#define CSMI_SAS_RAID_DATA_ADDITIONAL_DATA  2
+
+// RAID Drive Status
+// (bDriveStatus)
+#define CSMI_SAS_DRIVE_STATUS_OK          0
+#define CSMI_SAS_DRIVE_STATUS_REBUILDING  1
+#define CSMI_SAS_DRIVE_STATUS_FAILED      2
+#define CSMI_SAS_DRIVE_STATUS_DEGRADED    3
+#define CSMI_SAS_DRIVE_STATUS_OFFLINE     4
+#define CSMI_SAS_DRIVE_STATUS_QUEUED_FOR_REBUILD 5
+
+// RAID Drive Usage
+// (bDriveUsage)
+#define CSMI_SAS_DRIVE_CONFIG_NOT_USED      0
+#define CSMI_SAS_DRIVE_CONFIG_MEMBER        1
+#define CSMI_SAS_DRIVE_CONFIG_SPARE         2
+#define CSMI_SAS_DRIVE_CONFIG_SPARE_ACTIVE  3
+
+// RAID Drive Type
+// (bDriveType)
+#define CSMI_SAS_DRIVE_TYPE_UNKNOWN         0
+#define CSMI_SAS_DRIVE_TYPE_SINGLE_PORT_SAS 1
+#define CSMI_SAS_DRIVE_TYPE_DUAL_PORT_SAS   2
+#define CSMI_SAS_DRIVE_TYPE_SATA            3
+#define CSMI_SAS_DRIVE_TYPE_SATA_PS         4
+#define CSMI_SAS_DRIVE_TYPE_OTHER           255
+
+// RAID Write Protect
+// (bWriteProtect)
+#define CSMI_SAS_RAID_SET_WRITE_PROTECT_UNKNOWN     0
+#define CSMI_SAS_RAID_SET_WRITE_PROTECT_UNCHANGED   0
+#define CSMI_SAS_RAID_SET_WRITE_PROTECT_ENABLED     1
+#define CSMI_SAS_RAID_SET_WRITE_PROTECT_DISABLED    2
+
+// RAID Cache Setting
+// (bCacheSetting)
+#define CSMI_SAS_RAID_SET_CACHE_UNKNOWN             0
+#define CSMI_SAS_RAID_SET_CACHE_UNCHANGED           0
+#define CSMI_SAS_RAID_SET_CACHE_ENABLED             1
+#define CSMI_SAS_RAID_SET_CACHE_DISABLED            2
+#define CSMI_SAS_RAID_SET_CACHE_CORRUPT             3
+
+// RAID Features
+// (uFeatures)
+#define CSMI_SAS_RAID_FEATURE_TRANSFORMATION    0x00000001
+#define CSMI_SAS_RAID_FEATURE_REBUILD           0x00000002
+#define CSMI_SAS_RAID_FEATURE_SPLIT_MIRROR      0x00000004
+#define CSMI_SAS_RAID_FEATURE_MERGE_MIRROR      0x00000008
+#define CSMI_SAS_RAID_FEATURE_LUN_RENUMBER      0x00000010
+#define CSMI_SAS_RAID_FEATURE_SURFACE_SCAN      0x00000020
+#define CSMI_SAS_RAID_FEATURE_SPARES_SHARED     0x00000040
+
+// RAID Priority
+// (bDefaultTransformPriority, etc.)
+#define CSMI_SAS_PRIORITY_UNKNOWN   0
+#define CSMI_SAS_PRIORITY_UNCHANGED 0
+#define CSMI_SAS_PRIORITY_AUTO      1
+#define CSMI_SAS_PRIORITY_OFF       2
+#define CSMI_SAS_PRIORITY_LOW       3
+#define CSMI_SAS_PRIORITY_MEDIUM    4
+#define CSMI_SAS_PRIORITY_HIGH      5
+
+// RAID Transformation Rules
+// (uRaidSetTransformationRules)
+#define CSMI_SAS_RAID_RULE_AVAILABLE_MEMORY     0x00000001
+#define CSMI_SAS_RAID_RULE_OVERLAPPED_EXTENTS   0x00000002
+
+// RAID Cache Ratios Supported
+// (bCacheRatiosSupported)
+// from 0 to 100 defines the write to read ratio, 0 is 100% write
+#define CSMI_SAS_RAID_CACHE_RATIO_RANGE     101
+#define CSMI_SAS_RAID_CACHE_RATIO_FIXED     102
+#define CSMI_SAS_RAID_CACHE_RATIO_AUTO      103
+#define CSMI_SAS_RAID_CACHE_RATIO_END       255
+
+// RAID Cache Ratio Flag
+// (bCacheRatioFlag)
+#define CSMI_SAS_RAID_CACHE_RATIO_DISABLE   0
+#define CSMI_SAS_RAID_CACHE_RATIO_ENABLE    1
+
+// RAID Clear Configuration Signature
+// (bClearConfiguration)
+#define CSMI_SAS_RAID_CLEAR_CONFIGURATION_SIGNATURE "RAIDCLR"
+
+// RAID Failure Codes
+// (uFailureCode)
+#define CSMI_SAS_FAIL_CODE_OK                           0
+#define CSMI_SAS_FAIL_CODE_PARAMETER_INVALID            1000
+#define CSMI_SAS_FAIL_CODE_TRANSFORM_PRIORITY_INVALID   1001
+#define CSMI_SAS_FAIL_CODE_REBUILD_PRIORITY_INVALID     1002
+#define CSMI_SAS_FAIL_CODE_CACHE_RATIO_INVALID          1003
+#define CSMI_SAS_FAIL_CODE_SURFACE_SCAN_INVALID         1004
+#define CSMI_SAS_FAIL_CODE_CLEAR_CONFIGURATION_INVALID  1005
+#define CSMI_SAS_FAIL_CODE_ELEMENT_INDEX_INVALID        1006
+#define CSMI_SAS_FAIL_CODE_SUBELEMENT_INDEX_INVALID     1007
+#define CSMI_SAS_FAIL_CODE_EXTENT_INVALID               1008
+#define CSMI_SAS_FAIL_CODE_BLOCK_COUNT_INVALID          1009
+#define CSMI_SAS_FAIL_CODE_DRIVE_INDEX_INVALID          1010
+#define CSMI_SAS_FAIL_CODE_EXISTING_LUN_INVALID         1011
+#define CSMI_SAS_FAIL_CODE_RAID_TYPE_INVALID            1012
+#define CSMI_SAS_FAIL_CODE_STRIPE_SIZE_INVALID          1013
+#define CSMI_SAS_FAIL_CODE_TRANSFORMATION_INVALID       1014
+#define CSMI_SAS_FAIL_CODE_CHANGE_COUNT_INVALID         1015
+#define CSMI_SAS_FAIL_CODE_ENUMERATION_TYPE_INVALID     1016
+
+#define CSMI_SAS_FAIL_CODE_EXCEEDED_RAID_SET_COUNT      2000
+#define CSMI_SAS_FAIL_CODE_DUPLICATE_LUN                2001
+
+#define CSMI_SAS_FAIL_CODE_WAIT_FOR_OPERATION           3000
+
+// RAID Enumeration Types
+// (uEnumerationType)
+#define CSMI_SAS_RAID_ELEMENT_TYPE_DRIVE                0
+#define CSMI_SAS_RAID_ELEMENT_TYPE_MODULE               1
+#define CSMI_SAS_RAID_ELEMENT_TYPE_DRIVE_RAID_SET       2
+#define CSMI_SAS_RAID_ELEMENT_TYPE_EXTENT_DRIVE         3
+
+// RAID Extent Types
+// (bExtentType)
+#define CSMI_SAS_RAID_EXTENT_RESERVED       0
+#define CSMI_SAS_RAID_EXTENT_METADATA       1
+#define CSMI_SAS_RAID_EXTENT_ALLOCATED      2
+#define CSMI_SAS_RAID_EXTENT_UNALLOCATED    3
+
+// RAID Operation Types
+// (uOperationType)
+#define CSMI_SAS_RAID_SET_CREATE            0
+#define CSMI_SAS_RAID_SET_LABEL             1
+#define CSMI_SAS_RAID_SET_TRANSFORM         2
+#define CSMI_SAS_RAID_SET_DELETE            3
+#define CSMI_SAS_RAID_SET_WRITE_PROTECT     4
+#define CSMI_SAS_RAID_SET_CACHE             5
+#define CSMI_SAS_RAID_SET_ONLINE_STATE      6
+#define CSMI_SAS_RAID_SET_SPARE             7
+
+// RAID Transform Types
+// (bTransformType)
+#define CSMI_SAS_RAID_SET_TRANSFORM_SPLIT_MIRROR    0
+#define CSMI_SAS_RAID_SET_TRANSFORM_MERGE_RAID_0    1
+#define CSMI_SAS_RAID_SET_TRANSFORM_LUN_RENUMBER    2
+#define CSMI_SAS_RAID_SET_TRANSFORM_RAID_SET        3
+
+// RAID Online State
+// (bOnlineState)
+#define CSMI_SAS_RAID_SET_STATE_UNKNOWN     0
+#define CSMI_SAS_RAID_SET_STATE_ONLINE      1
+#define CSMI_SAS_RAID_SET_STATE_OFFLINE     2
+
+/* * * * * * * * * * SAS HBA Class IOCTL Constants * * * * * * * * * */
+
+// Return codes for SAS IOCTL's
+// (IoctlHeader.ReturnCode)
+
+#define CSMI_SAS_PHY_INFO_CHANGED            CSMI_SAS_STATUS_SUCCESS
+#define CSMI_SAS_PHY_INFO_NOT_CHANGEABLE     2000
+#define CSMI_SAS_LINK_RATE_OUT_OF_RANGE      2001
+
+#define CSMI_SAS_PHY_DOES_NOT_EXIST          2002
+#define CSMI_SAS_PHY_DOES_NOT_MATCH_PORT     2003
+#define CSMI_SAS_PHY_CANNOT_BE_SELECTED      2004
+#define CSMI_SAS_SELECT_PHY_OR_PORT          2005
+#define CSMI_SAS_PORT_DOES_NOT_EXIST         2006
+#define CSMI_SAS_PORT_CANNOT_BE_SELECTED     2007
+#define CSMI_SAS_CONNECTION_FAILED           2008
+
+#define CSMI_SAS_NO_SATA_DEVICE              2009
+#define CSMI_SAS_NO_SATA_SIGNATURE           2010
+#define CSMI_SAS_SCSI_EMULATION              2011
+#define CSMI_SAS_NOT_AN_END_DEVICE           2012
+#define CSMI_SAS_NO_SCSI_ADDRESS             2013
+#define CSMI_SAS_NO_DEVICE_ADDRESS           2014
+
+// Signature value
+// (IoctlHeader.Signature)
+
+#define CSMI_SAS_SIGNATURE    "CSMISAS"
+
+// Timeout value default of 60 seconds
+// (IoctlHeader.Timeout)
+
+#define CSMI_SAS_TIMEOUT      60
+
+// Device types
+// (bDeviceType)
+
+#define CSMI_SAS_PHY_UNUSED               0x00
+#define CSMI_SAS_NO_DEVICE_ATTACHED       0x00
+#define CSMI_SAS_END_DEVICE               0x10
+#define CSMI_SAS_EDGE_EXPANDER_DEVICE     0x20
+#define CSMI_SAS_FANOUT_EXPANDER_DEVICE   0x30
+
+// Protocol options
+// (bInitiatorPortProtocol, bTargetPortProtocol)
+
+#define CSMI_SAS_PROTOCOL_SATA   0x01
+#define CSMI_SAS_PROTOCOL_SMP    0x02
+#define CSMI_SAS_PROTOCOL_STP    0x04
+#define CSMI_SAS_PROTOCOL_SSP    0x08
+
+// Negotiated and hardware link rates
+// (bNegotiatedLinkRate, bMinimumLinkRate, bMaximumLinkRate)
+
+#define CSMI_SAS_LINK_RATE_UNKNOWN  0x00
+#define CSMI_SAS_PHY_DISABLED       0x01
+#define CSMI_SAS_LINK_RATE_FAILED   0x02
+#define CSMI_SAS_SATA_SPINUP_HOLD   0x03
+#define CSMI_SAS_SATA_PORT_SELECTOR 0x04
+#define CSMI_SAS_LINK_RATE_1_5_GBPS 0x08
+#define CSMI_SAS_LINK_RATE_3_0_GBPS 0x09
+#define CSMI_SAS_LINK_VIRTUAL       0x10
+
+// Discover state
+// (bAutoDiscover)
+
+#define CSMI_SAS_DISCOVER_NOT_SUPPORTED   0x00
+#define CSMI_SAS_DISCOVER_NOT_STARTED     0x01
+#define CSMI_SAS_DISCOVER_IN_PROGRESS     0x02
+#define CSMI_SAS_DISCOVER_COMPLETE        0x03
+#define CSMI_SAS_DISCOVER_ERROR           0x04
+
+// Phy features
+
+#define CSMI_SAS_PHY_VIRTUAL_SMP          0x01
+
+// Programmed link rates
+// (bMinimumLinkRate, bMaximumLinkRate)
+// (bProgrammedMinimumLinkRate, bProgrammedMaximumLinkRate)
+
+#define CSMI_SAS_PROGRAMMED_LINK_RATE_UNCHANGED 0x00
+#define CSMI_SAS_PROGRAMMED_LINK_RATE_1_5_GBPS  0x08
+#define CSMI_SAS_PROGRAMMED_LINK_RATE_3_0_GBPS  0x09
+
+// Link rate
+// (bNegotiatedLinkRate in CSMI_SAS_SET_PHY_INFO)
+
+#define CSMI_SAS_LINK_RATE_NEGOTIATE      0x00
+#define CSMI_SAS_LINK_RATE_PHY_DISABLED   0x01
+
+// Signal class
+// (bSignalClass in CSMI_SAS_SET_PHY_INFO)
+
+#define CSMI_SAS_SIGNAL_CLASS_UNKNOWN     0x00
+#define CSMI_SAS_SIGNAL_CLASS_DIRECT      0x01
+#define CSMI_SAS_SIGNAL_CLASS_SERVER      0x02
+#define CSMI_SAS_SIGNAL_CLASS_ENCLOSURE   0x03
+
+// Link error reset
+// (bResetCounts)
+
+#define CSMI_SAS_LINK_ERROR_DONT_RESET_COUNTS   0x00
+#define CSMI_SAS_LINK_ERROR_RESET_COUNTS        0x01
+
+// Phy identifier
+// (bPhyIdentifier)
+
+#define CSMI_SAS_USE_PORT_IDENTIFIER   0xFF
+
+// Port identifier
+// (bPortIdentifier)
+
+#define CSMI_SAS_IGNORE_PORT           0xFF
+
+// Programmed link rates
+// (bConnectionRate)
+
+#define CSMI_SAS_LINK_RATE_NEGOTIATED  0x00
+#define CSMI_SAS_LINK_RATE_1_5_GBPS    0x08
+#define CSMI_SAS_LINK_RATE_3_0_GBPS    0x09
+
+// Connection status
+// (bConnectionStatus)
+
+#define CSMI_SAS_OPEN_ACCEPT                          0
+#define CSMI_SAS_OPEN_REJECT_BAD_DESTINATION          1
+#define CSMI_SAS_OPEN_REJECT_RATE_NOT_SUPPORTED       2
+#define CSMI_SAS_OPEN_REJECT_NO_DESTINATION           3
+#define CSMI_SAS_OPEN_REJECT_PATHWAY_BLOCKED          4
+#define CSMI_SAS_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED   5
+#define CSMI_SAS_OPEN_REJECT_RESERVE_ABANDON          6
+#define CSMI_SAS_OPEN_REJECT_RESERVE_CONTINUE         7
+#define CSMI_SAS_OPEN_REJECT_RESERVE_INITIALIZE       8
+#define CSMI_SAS_OPEN_REJECT_RESERVE_STOP             9
+#define CSMI_SAS_OPEN_REJECT_RETRY                    10
+#define CSMI_SAS_OPEN_REJECT_STP_RESOURCES_BUSY       11
+#define CSMI_SAS_OPEN_REJECT_WRONG_DESTINATION        12
+
+// SSP Status
+// (bSSPStatus)
+
+#define CSMI_SAS_SSP_STATUS_UNKNOWN     0x00
+#define CSMI_SAS_SSP_STATUS_WAITING     0x01
+#define CSMI_SAS_SSP_STATUS_COMPLETED   0x02
+#define CSMI_SAS_SSP_STATUS_FATAL_ERROR 0x03
+#define CSMI_SAS_SSP_STATUS_RETRY       0x04
+#define CSMI_SAS_SSP_STATUS_NO_TAG      0x05
+
+// SSP Flags
+// (uFlags)
+
+#define CSMI_SAS_SSP_READ           0x00000001
+#define CSMI_SAS_SSP_WRITE          0x00000002
+#define CSMI_SAS_SSP_UNSPECIFIED    0x00000004
+
+#define CSMI_SAS_SSP_TASK_ATTRIBUTE_SIMPLE         0x00000000
+#define CSMI_SAS_SSP_TASK_ATTRIBUTE_HEAD_OF_QUEUE  0x00000010
+#define CSMI_SAS_SSP_TASK_ATTRIBUTE_ORDERED        0x00000020
+#define CSMI_SAS_SSP_TASK_ATTRIBUTE_ACA            0x00000040
+
+// SSP Data present
+// (bDataPresent)
+
+#define CSMI_SAS_SSP_NO_DATA_PRESENT         0x00
+#define CSMI_SAS_SSP_RESPONSE_DATA_PRESENT   0x01
+#define CSMI_SAS_SSP_SENSE_DATA_PRESENT      0x02
+
+// STP Flags
+// (uFlags)
+
+#define CSMI_SAS_STP_READ           0x00000001
+#define CSMI_SAS_STP_WRITE          0x00000002
+#define CSMI_SAS_STP_UNSPECIFIED    0x00000004
+#define CSMI_SAS_STP_PIO            0x00000010
+#define CSMI_SAS_STP_DMA            0x00000020
+#define CSMI_SAS_STP_PACKET         0x00000040
+#define CSMI_SAS_STP_DMA_QUEUED     0x00000080
+#define CSMI_SAS_STP_EXECUTE_DIAG   0x00000100
+#define CSMI_SAS_STP_RESET_DEVICE   0x00000200
+
+// Task Management Flags
+// (uFlags)
+
+#define CSMI_SAS_TASK_IU               0x00000001
+#define CSMI_SAS_HARD_RESET_SEQUENCE   0x00000002
+#define CSMI_SAS_SUPPRESS_RESULT       0x00000004
+
+// Task Management Functions
+// (bTaskManagement)
+
+#define CSMI_SAS_SSP_ABORT_TASK           0x01
+#define CSMI_SAS_SSP_ABORT_TASK_SET       0x02
+#define CSMI_SAS_SSP_CLEAR_TASK_SET       0x04
+#define CSMI_SAS_SSP_LOGICAL_UNIT_RESET   0x08
+#define CSMI_SAS_SSP_CLEAR_ACA            0x40
+#define CSMI_SAS_SSP_QUERY_TASK           0x80
+
+// Task Management Information
+// (uInformation)
+
+#define CSMI_SAS_SSP_TEST           1
+#define CSMI_SAS_SSP_EXCEEDED       2
+#define CSMI_SAS_SSP_DEMAND         3
+#define CSMI_SAS_SSP_TRIGGER        4
+
+// Connector Pinout Information
+// (uPinout)
+
+#define CSMI_SAS_CON_UNKNOWN              0x00000001
+#define CSMI_SAS_CON_SFF_8482             0x00000002
+#define CSMI_SAS_CON_SFF_8470_LANE_1      0x00000100
+#define CSMI_SAS_CON_SFF_8470_LANE_2      0x00000200
+#define CSMI_SAS_CON_SFF_8470_LANE_3      0x00000400
+#define CSMI_SAS_CON_SFF_8470_LANE_4      0x00000800
+#define CSMI_SAS_CON_SFF_8484_LANE_1      0x00010000
+#define CSMI_SAS_CON_SFF_8484_LANE_2      0x00020000
+#define CSMI_SAS_CON_SFF_8484_LANE_3      0x00040000
+#define CSMI_SAS_CON_SFF_8484_LANE_4      0x00080000
+
+// Connector Location Information
+// (bLocation)
+
+// same as uPinout above...
+// #define CSMI_SAS_CON_UNKNOWN              0x01
+#define CSMI_SAS_CON_INTERNAL             0x02
+#define CSMI_SAS_CON_EXTERNAL             0x04
+#define CSMI_SAS_CON_SWITCHABLE           0x08
+#define CSMI_SAS_CON_AUTO                 0x10
+#define CSMI_SAS_CON_NOT_PRESENT          0x20
+#define CSMI_SAS_CON_NOT_CONNECTED        0x80
+
+// Device location identification
+// (bIdentify)
+
+#define CSMI_SAS_LOCATE_UNKNOWN           0x00
+#define CSMI_SAS_LOCATE_FORCE_OFF         0x01
+#define CSMI_SAS_LOCATE_FORCE_ON          0x02
+
+// Location Valid flags
+// (uLocationFlags)
+
+#define CSMI_SAS_LOCATE_SAS_ADDRESS_VALID           0x00000001
+#define CSMI_SAS_LOCATE_SAS_LUN_VALID               0x00000002
+#define CSMI_SAS_LOCATE_ENCLOSURE_IDENTIFIER_VALID  0x00000004
+#define CSMI_SAS_LOCATE_ENCLOSURE_NAME_VALID        0x00000008
+#define CSMI_SAS_LOCATE_BAY_PREFIX_VALID            0x00000010
+#define CSMI_SAS_LOCATE_BAY_IDENTIFIER_VALID        0x00000020
+#define CSMI_SAS_LOCATE_LOCATION_STATE_VALID        0x00000040
+
+/* * * * * * * * SAS Phy Control Class IOCTL Constants * * * * * * * * */
+
+// Return codes for SAS Phy Control IOCTL's
+// (IoctlHeader.ReturnCode)
+
+// Signature value
+// (IoctlHeader.Signature)
+
+#define CSMI_PHY_SIGNATURE    "CSMIPHY"
+
+// Phy Control Functions
+// (bFunction)
+
+// values 0x00 to 0xFF are consistent in definition with the SMP PHY CONTROL
+// function defined in the SAS spec
+#define CSMI_SAS_PC_NOP                   0x00000000
+#define CSMI_SAS_PC_LINK_RESET            0x00000001
+#define CSMI_SAS_PC_HARD_RESET            0x00000002
+#define CSMI_SAS_PC_PHY_DISABLE           0x00000003
+// 0x04 to 0xFF reserved...
+#define CSMI_SAS_PC_GET_PHY_SETTINGS      0x00000100
+
+// Link Flags
+#define CSMI_SAS_PHY_ACTIVATE_CONTROL     0x00000001
+#define CSMI_SAS_PHY_UPDATE_SPINUP_RATE   0x00000002
+#define CSMI_SAS_PHY_AUTO_COMWAKE         0x00000004
+
+// Device Types for Phy Settings
+// (bType)
+#define CSMI_SAS_UNDEFINED 0x00
+#define CSMI_SAS_SATA      0x01
+#define CSMI_SAS_SAS       0x02
+
+// Transmitter Flags
+// (uTransmitterFlags)
+#define CSMI_SAS_PHY_PREEMPHASIS_DISABLED    0x00000001
+
+// Receiver Flags
+// (uReceiverFlags)
+#define CSMI_SAS_PHY_EQUALIZATION_DISABLED   0x00000001
+
+// Pattern Flags
+// (uPatternFlags)
+// #define CSMI_SAS_PHY_ACTIVATE_CONTROL     0x00000001
+#define CSMI_SAS_PHY_DISABLE_SCRAMBLING      0x00000002
+#define CSMI_SAS_PHY_DISABLE_ALIGN           0x00000004
+#define CSMI_SAS_PHY_DISABLE_SSC             0x00000008
+
+#define CSMI_SAS_PHY_FIXED_PATTERN           0x00000010
+#define CSMI_SAS_PHY_USER_PATTERN            0x00000020
+
+// Fixed Patterns
+// (bFixedPattern)
+#define CSMI_SAS_PHY_CJPAT                   0x00000001
+#define CSMI_SAS_PHY_ALIGN                   0x00000002
+
+// Type Flags
+// (bTypeFlags)
+#define CSMI_SAS_PHY_POSITIVE_DISPARITY      0x01
+#define CSMI_SAS_PHY_NEGATIVE_DISPARITY      0x02
+#define CSMI_SAS_PHY_CONTROL_CHARACTER       0x04
+
+// Miscellaneous
+#define SLOT_NUMBER_UNKNOWN   0xFFFF
+
+/*************************************************************************/
+/* DATA STRUCTURES                                                       */
+/*************************************************************************/
+
+/* * * * * * * * * * Class Independent Structures * * * * * * * * * */
+
+// EDM #pragma CSMI_SAS_BEGIN_PACK(8)
+#pragma pack(8)
+
+// CC_CSMI_SAS_DRIVER_INFO
+
+typedef struct _CSMI_SAS_DRIVER_INFO {
+   __u8  szName[81];
+   __u8  szDescription[81];
+   __u16 usMajorRevision;
+   __u16 usMinorRevision;
+   __u16 usBuildRevision;
+   __u16 usReleaseRevision;
+   __u16 usCSMIMajorRevision;
+   __u16 usCSMIMinorRevision;
+} CSMI_SAS_DRIVER_INFO,
+  *PCSMI_SAS_DRIVER_INFO;
+
+typedef struct _CSMI_SAS_DRIVER_INFO_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_DRIVER_INFO Information;
+} CSMI_SAS_DRIVER_INFO_BUFFER,
+  *PCSMI_SAS_DRIVER_INFO_BUFFER;
+
+// CC_CSMI_SAS_CNTLR_CONFIGURATION
+
+typedef struct _CSMI_SAS_PCI_BUS_ADDRESS {
+   __u8  bBusNumber;
+   __u8  bDeviceNumber;
+   __u8  bFunctionNumber;
+   __u8  bReserved;
+} CSMI_SAS_PCI_BUS_ADDRESS,
+  *PCSMI_SAS_PCI_BUS_ADDRESS;
+
+typedef union _CSMI_SAS_IO_BUS_ADDRESS {
+   CSMI_SAS_PCI_BUS_ADDRESS PciAddress;
+   __u8  bReserved[32];
+} CSMI_SAS_IO_BUS_ADDRESS,
+  *PCSMI_SAS_IO_BUS_ADDRESS;
+
+typedef struct _CSMI_SAS_CNTLR_CONFIG {
+   __u32 uBaseIoAddress;
+   struct {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } BaseMemoryAddress;
+   __u32 uBoardID;
+   __u16 usSlotNumber;
+   __u8  bControllerClass;
+   __u8  bIoBusType;
+   CSMI_SAS_IO_BUS_ADDRESS BusAddress;
+   __u8  szSerialNumber[81];
+   __u16 usMajorRevision;
+   __u16 usMinorRevision;
+   __u16 usBuildRevision;
+   __u16 usReleaseRevision;
+   __u16 usBIOSMajorRevision;
+   __u16 usBIOSMinorRevision;
+   __u16 usBIOSBuildRevision;
+   __u16 usBIOSReleaseRevision;
+   __u32 uControllerFlags;
+   __u16 usRromMajorRevision;
+   __u16 usRromMinorRevision;
+   __u16 usRromBuildRevision;
+   __u16 usRromReleaseRevision;
+   __u16 usRromBIOSMajorRevision;
+   __u16 usRromBIOSMinorRevision;
+   __u16 usRromBIOSBuildRevision;
+   __u16 usRromBIOSReleaseRevision;
+   __u8  bReserved[7];
+} CSMI_SAS_CNTLR_CONFIG,
+  *PCSMI_SAS_CNTLR_CONFIG;
+
+typedef struct _CSMI_SAS_CNTLR_CONFIG_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_CNTLR_CONFIG Configuration;
+} CSMI_SAS_CNTLR_CONFIG_BUFFER,
+  *PCSMI_SAS_CNTLR_CONFIG_BUFFER;
+
+// CC_CSMI_SAS_CNTLR_STATUS
+
+typedef struct _CSMI_SAS_CNTLR_STATUS {
+   __u32 uStatus;
+   __u32 uOfflineReason;
+   __u8  bReserved[28];
+} CSMI_SAS_CNTLR_STATUS,
+  *PCSMI_SAS_CNTLR_STATUS;
+
+typedef struct _CSMI_SAS_CNTLR_STATUS_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_CNTLR_STATUS Status;
+} CSMI_SAS_CNTLR_STATUS_BUFFER,
+  *PCSMI_SAS_CNTLR_STATUS_BUFFER;
+
+// CC_CSMI_SAS_FIRMWARE_DOWNLOAD
+
+typedef struct _CSMI_SAS_FIRMWARE_DOWNLOAD {
+   __u32 uBufferLength;
+   __u32 uDownloadFlags;
+   __u8  bReserved[32];
+   __u16 usStatus;
+   __u16 usSeverity;
+} CSMI_SAS_FIRMWARE_DOWNLOAD,
+  *PCSMI_SAS_FIRMWARE_DOWNLOAD;
+
+typedef struct _CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_FIRMWARE_DOWNLOAD Information;
+   __u8  bDataBuffer[1];
+} CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER,
+  *PCSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER;
+
+// CC_CSMI_SAS_RAID_INFO
+
+typedef struct _CSMI_SAS_RAID_INFO {
+   __u32 uNumRaidSets;
+   __u32 uMaxDrivesPerSet;
+   __u32 uMaxRaidSets;
+   __u8  bMaxRaidTypes;
+   __u8  bReservedByteFields[7];
+   struct
+   {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } ulMinRaidSetBlocks;
+   struct
+   {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } ulMaxRaidSetBlocks;
+   __u32 uMaxPhysicalDrives;
+   __u32 uMaxExtents;
+   __u32 uMaxModules;
+   __u32 uMaxTransformationMemory;
+   __u32 uChangeCount;
+   __u8  bReserved[44];
+} CSMI_SAS_RAID_INFO,
+  *PCSMI_SAS_RAID_INFO;
+
+typedef struct _CSMI_SAS_RAID_INFO_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_RAID_INFO Information;
+} CSMI_SAS_RAID_INFO_BUFFER,
+  *PCSMI_SAS_RAID_INFO_BUFFER;
+
+// CC_CSMI_SAS_GET_RAID_CONFIG
+
+typedef struct _CSMI_SAS_RAID_DRIVES {
+   __u8  bModel[40];
+   __u8  bFirmware[8];
+   __u8  bSerialNumber[40];
+   __u8  bSASAddress[8];
+   __u8  bSASLun[8];
+   __u8  bDriveStatus;
+   __u8  bDriveUsage;
+   __u16 usBlockSize;
+   __u8  bDriveType;
+   __u8  bReserved[15];
+   __u32 uDriveIndex;
+   struct
+   {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } ulTotalUserBlocks;
+} CSMI_SAS_RAID_DRIVES,
+  *PCSMI_SAS_RAID_DRIVES;
+
+typedef struct _CSMI_SAS_RAID_DEVICE_ID {
+   __u8  bDeviceIdentificationVPDPage[1];
+} CSMI_SAS_RAID_DEVICE_ID,
+  *PCSMI_SAS_RAID_DEVICE_ID;
+
+typedef struct _CSMI_SAS_RAID_SET_ADDITIONAL_DATA {
+   __u8  bLabel[16];
+   __u8  bRaidSetLun[8];
+   __u8  bWriteProtection;
+   __u8  bCacheSetting;
+   __u8  bCacheRatio;
+   __u16 usBlockSize;
+   __u8  bReservedBytes[11];
+   struct
+   {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } ulRaidSetExtentOffset;
+   struct
+   {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } ulRaidSetBlocks;
+   __u32 uStripeSizeInBlocks;
+   __u32 uSectorsPerTrack;
+   __u8  bApplicationScratchPad[16];
+   __u32 uNumberOfHeads;
+   __u32 uNumberOfTracks;
+   __u8  bReserved[24];
+} CSMI_SAS_RAID_SET_ADDITIONAL_DATA,
+  *PCSMI_SAS_RAID_SET_ADDITIONAL_DATA;
+
+typedef struct _CSMI_SAS_RAID_CONFIG {
+   __u32 uRaidSetIndex;
+   __u32 uCapacity;
+   __u32 uStripeSize;
+   __u8  bRaidType;
+   __u8  bStatus;
+   __u8  bInformation;
+   __u8  bDriveCount;
+   __u8  bDataType;
+   __u8  bReserved[11];
+   __u32 uFailureCode;
+   __u32 uChangeCount;
+   union {
+      CSMI_SAS_RAID_DRIVES Drives[1];
+      CSMI_SAS_RAID_DEVICE_ID DeviceId[1];
+      CSMI_SAS_RAID_SET_ADDITIONAL_DATA Data[1];
+   };
+} CSMI_SAS_RAID_CONFIG,
+   *PCSMI_SAS_RAID_CONFIG;
+
+typedef struct _CSMI_SAS_RAID_CONFIG_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_RAID_CONFIG Configuration;
+} CSMI_SAS_RAID_CONFIG_BUFFER,
+  *PCSMI_SAS_RAID_CONFIG_BUFFER;
+
+// CC_CSMI_SAS_GET_RAID_FEATURES
+
+typedef struct _CSMI_SAS_RAID_TYPE_DESCRIPTION {
+  __u8  bRaidType;
+  __u8  bReservedBytes[7];
+  __u32 uSupportedStripeSizeMap;
+  __u8  bReserved[24];
+} CSMI_SAS_RAID_TYPE_DESCRIPTION,
+  *PCSMI_SAS_RAID_TYPE_DESCRIPTION;
+
+typedef struct _CSMI_SAS_RAID_FEATURES {
+   __u32 uFeatures;
+   __u8  bReservedFeatures[32];
+   __u8  bDefaultTransformPriority;
+   __u8  bTransformPriority;
+   __u8  bDefaultRebuildPriority;
+   __u8  bRebuildPriority;
+   __u8  bDefaultSurfaceScanPriority;
+   __u8  bSurfaceScanPriority;
+   __u16 usReserved;
+   __u32 uRaidSetTransformationRules;
+   __u32 uReserved[11];
+   CSMI_SAS_RAID_TYPE_DESCRIPTION RaidType[24];
+   __u8  bCacheRatiosSupported[104];
+   __u32 uChangeCount;
+   __u32 uFailureCode;
+   __u8  bReserved[120];
+} CSMI_SAS_RAID_FEATURES,
+  *PCSMI_SAS_RAID_FEATURES;
+
+typedef struct _CSMI_SAS_RAID_FEATURES_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_RAID_FEATURES Information;
+} CSMI_SAS_RAID_FEATURES_BUFFER,
+  *PCSMI_SAS_RAID_FEATURES_BUFFER;
+
+// CC_CSMI_SAS_SET_RAID_CONTROL
+
+typedef struct _CSMI_SAS_RAID_CONTROL {
+   __u8  bTransformPriority;
+   __u8  bRebuildPriority;
+   __u8  bCacheRatioFlag;
+   __u8  bCacheRatio;
+   __u8  bSurfaceScanPriority;
+   __u8  bReservedBytes[15];
+   __u8  bClearConfiguration[8];
+   __u32 uChangeCount;
+   __u8  bReserved[88];
+   __u32 uFailureCode;
+   __u8  bFailureDescription[80];
+} CSMI_SAS_RAID_CONTROL,
+  *PCSMI_SAS_RAID_CONTROL;
+
+typedef struct _CSMI_SAS_RAID_CONTROL_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_RAID_CONTROL Information;
+} CSMI_SAS_RAID_CONTROL_BUFFER,
+  *PCSMI_SAS_RAID_CONTROL_BUFFER;
+
+// CC_CSMI_SAS_GET_RAID_ELEMENT
+
+typedef struct _CSMI_SAS_DRIVE_EXTENT_INFO {
+   __u32 uDriveIndex;
+   __u8  bExtentType;
+   __u8  bReservedBytes[7];
+   struct
+   {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } ulExtentOffset;
+   struct
+   {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } ulExtentBlocks;
+   __u32 uRaidSetIndex;
+   __u8  bReserved[96];
+} CSMI_SAS_DRIVE_EXTENT_INFO,
+  *PCSMI_SAS_DRIVE_EXTENT_INFO;
+
+typedef struct _CSMI_SAS_RAID_MODULE_INFO {
+   __u8  bReserved[128];
+} CSMI_SAS_RAID_MODULE_INFO,
+  *PCSMI_SAS_RAID_MODULE_INFO;
+
+typedef struct _CSMI_SAS_DRIVE_LOCATION {
+   __u8  bConnector[16];
+   __u8  bBoxName[16];
+   __u32 uBay;
+   __u8  bReservedBytes[4];
+   __u8  bAttachedSASAddress[8];
+   __u8  bAttachedPhyIdentifier;
+   __u8  bReserved[79];
+} CSMI_SAS_DRIVE_LOCATION,
+  *PCSMI_SAS_DRIVE_LOCATION;
+
+typedef struct _CSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA {
+   __u8  bNegotiatedLinkRate[2];
+   __u8  bReserved[126];
+} CSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA,
+  *PCSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA;
+
+typedef struct _CSMI_SAS_DRIVE_INFO {
+   CSMI_SAS_RAID_DRIVES Device;
+   CSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA Data;
+   CSMI_SAS_DRIVE_LOCATION Location;
+   __u8  bReserved[16];
+} CSMI_SAS_DRIVE_INFO,
+  *PCSMI_SAS_DRIVE_INFO;
+
+typedef struct _CSMI_SAS_RAID_ELEMENT {
+   __u32 uEnumerationType;
+   __u32 uElementIndex;
+   __u32 uNumElements;
+   __u32 uChangeCount;
+   __u32 uSubElementIndex;
+   __u8  bReserved[32];
+   __u32 uFailureCode;
+   __u8  bFailureDescription[80];
+   union {
+       CSMI_SAS_DRIVE_INFO Drive;
+       CSMI_SAS_RAID_MODULE_INFO Module;
+       CSMI_SAS_DRIVE_EXTENT_INFO Extent;
+   } Element;
+} CSMI_SAS_RAID_ELEMENT,
+  *PCSMI_SAS_RAID_ELEMENT;
+
+typedef struct _CSMI_SAS_RAID_ELEMENT_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_RAID_ELEMENT Information;
+} CSMI_SAS_RAID_ELEMENT_BUFFER,
+  *PCSMI_SAS_RAID_ELEMENT_BUFFER;
+
+// CC_CSMI_SAS_SET_RAID_OPERATION
+
+typedef struct _CSMI_SAS_RAID_SET_LIST {
+   __u32 uRaidSetIndex;
+   __u8  bExistingLun[8];
+   __u8  bNewLun[8];
+   __u8  bReserved[12];
+} CSMI_SAS_RAID_SET_LIST,
+  *PCSMI_SAS_RAID_SET_LIST;
+
+typedef struct _CSMI_SAS_RAID_SET_DRIVE_LIST {
+   __u32 uDriveIndex;
+   __u8  bDriveUsage;
+   __u8  bReserved[27];
+} CSMI_SAS_RAID_SET_DRIVE_LIST,
+  *PCSMI_SAS_RAID_SET_DRIVE_LIST;
+
+typedef struct _CSMI_SAS_RAID_SET_SPARE_INFO {
+   __u32 uRaidSetIndex;
+   __u32 uDriveCount;
+   __u8  bApplicationScratchPad[16];
+   __u8  bReserved[104];
+} CSMI_SAS_RAID_SET_SPARE_INFO,
+  *PCSMI_SAS_RAID_SET_SPARE_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_ONLINE_STATE_INFO {
+   __u32 uRaidSetIndex;
+   __u8  bOnlineState;
+   __u8  bReserved[123];
+} CSMI_SAS_RAID_SET_ONLINE_STATE_INFO,
+  *PCSMI_SAS_RAID_SET_ONLINE_STATE_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_CACHE_INFO {
+   __u32 uRaidSetIndex;
+   __u8  bCacheSetting;
+   __u8  bCacheRatioFlag;
+   __u8  bCacheRatio;
+   __u8  bReserved[121];
+} CSMI_SAS_RAID_SET_CACHE_INFO,
+  *PCSMI_SAS_RAID_SET_CACHE_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_WRITE_PROTECT_INFO {
+   __u32 uRaidSetIndex;
+   __u8  bWriteProtectSetting;
+   __u8  bReserved[123];
+} CSMI_SAS_RAID_SET_WRITE_PROTECT_INFO,
+  *PCSMI_SAS_RAID_SET_WRITE_PROTECT_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_DELETE_INFO {
+   __u32 uRaidSetIndex;
+   __u8  bReserved[124];
+} CSMI_SAS_RAID_SET_DELETE_INFO,
+  *PCSMI_SAS_RAID_SET_DELETE_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_MODIFY_INFO {
+   __u8  bRaidType;
+   __u8  bReservedBytes[7];
+   __u32 uStripeSize;
+   struct
+   {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } ulRaidSetBlocks;
+   struct
+   {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } ulRaidSetExtentOffset;
+   __u32 uDriveCount;
+   __u8  bReserved[96];
+} CSMI_SAS_RAID_SET_MODIFY_INFO,
+  *PCSMI_SAS_RAID_SET_MODIFY_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_TRANSFORM_INFO {
+   __u8  bTransformType;
+   __u8  bReservedBytes[3];
+   __u32 uRaidSetIndex;
+   __u8  bRaidType;
+   __u8  bReservedBytes2[11];
+   __u32 uAdditionalRaidSetIndex;
+   __u32 uRaidSetCount;
+   __u8  bApplicationScratchPad[16];
+   CSMI_SAS_RAID_SET_MODIFY_INFO Modify;
+   __u8  bReserved[80];
+} CSMI_SAS_RAID_SET_TRANSFORM_INFO,
+  *PCSMI_SAS_RAID_SET_TRANSFORM_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_LABEL_INFO {
+   __u32 uRaidSetIndex;
+   __u8  bLabel[16];
+   __u8  bReserved[108];
+} CSMI_SAS_RAID_SET_LABEL_INFO,
+  *PCSMI_SAS_RAID_SET_LABEL_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_CREATE_INFO {
+   __u8  bRaidType;
+   __u8  bReservedBytes[7];
+   __u32 uStripeSize;
+   __u32 uTrackSectorCount;
+   struct
+   {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } ulRaidSetBlocks;
+   struct
+   {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } ulRaidSetExtentOffset;
+   __u32 uDriveCount;
+   __u8  bLabel[16];
+   __u32 uRaidSetIndex;
+   __u8  bApplicationScratchPad[16];
+   __u32 uNumberOfHeads;
+   __u32 uNumberOfTracks;
+   __u8  bReserved[48];
+} CSMI_SAS_RAID_SET_CREATE_INFO,
+  *PCSMI_SAS_RAID_SET_CREATE_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_OPERATION {
+   __u32 uOperationType;
+   __u32 uChangeCount;
+   __u32 uFailureCode;
+   __u8  bFailureDescription[80];
+   __u8  bReserved[28];
+   union {
+       CSMI_SAS_RAID_SET_CREATE_INFO Create;
+       CSMI_SAS_RAID_SET_LABEL_INFO Label;
+       CSMI_SAS_RAID_SET_TRANSFORM_INFO Transform;
+       CSMI_SAS_RAID_SET_DELETE_INFO Delete;
+       CSMI_SAS_RAID_SET_WRITE_PROTECT_INFO Protect;
+       CSMI_SAS_RAID_SET_CACHE_INFO Cache;
+       CSMI_SAS_RAID_SET_ONLINE_STATE_INFO State;
+       CSMI_SAS_RAID_SET_SPARE_INFO Spare;
+   } Operation;
+   union {
+       CSMI_SAS_RAID_SET_DRIVE_LIST DriveList[1];
+       CSMI_SAS_RAID_SET_LIST RaidSetList[1];
+   } Parameters;
+} CSMI_SAS_RAID_SET_OPERATION,
+  *PCSMI_SAS_RAID_SET_OPERATION;
+
+typedef struct _CSMI_SAS_RAID_SET_OPERATION_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_RAID_SET_OPERATION Information;
+} CSMI_SAS_RAID_SET_OPERATION_BUFFER,
+  *PCSMI_SAS_RAID_SET_OPERATION_BUFFER;
+
+/* * * * * * * * * * SAS HBA Class Structures * * * * * * * * * */
+
+// CC_CSMI_SAS_GET_PHY_INFO
+
+typedef struct _CSMI_SAS_IDENTIFY {
+   __u8  bDeviceType;
+   __u8  bRestricted;
+   __u8  bInitiatorPortProtocol;
+   __u8  bTargetPortProtocol;
+   __u8  bRestricted2[8];
+   __u8  bSASAddress[8];
+   __u8  bPhyIdentifier;
+   __u8  bSignalClass;
+   __u8  bReserved[6];
+} CSMI_SAS_IDENTIFY,
+  *PCSMI_SAS_IDENTIFY;
+
+typedef struct _CSMI_SAS_PHY_ENTITY {
+   CSMI_SAS_IDENTIFY Identify;
+   __u8  bPortIdentifier;
+   __u8  bNegotiatedLinkRate;
+   __u8  bMinimumLinkRate;
+   __u8  bMaximumLinkRate;
+   __u8  bPhyChangeCount;
+   __u8  bAutoDiscover;
+   __u8  bPhyFeatures;
+   __u8  bReserved;
+   CSMI_SAS_IDENTIFY Attached;
+} CSMI_SAS_PHY_ENTITY,
+  *PCSMI_SAS_PHY_ENTITY;
+
+typedef struct _CSMI_SAS_PHY_INFO {
+   __u8  bNumberOfPhys;
+   __u8  bReserved[3];
+   CSMI_SAS_PHY_ENTITY Phy[32];
+} CSMI_SAS_PHY_INFO,
+  *PCSMI_SAS_PHY_INFO;
+
+typedef struct _CSMI_SAS_PHY_INFO_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_PHY_INFO Information;
+} CSMI_SAS_PHY_INFO_BUFFER,
+  *PCSMI_SAS_PHY_INFO_BUFFER;
+
+// CC_CSMI_SAS_SET_PHY_INFO
+
+typedef struct _CSMI_SAS_SET_PHY_INFO {
+   __u8  bPhyIdentifier;
+   __u8  bNegotiatedLinkRate;
+   __u8  bProgrammedMinimumLinkRate;
+   __u8  bProgrammedMaximumLinkRate;
+   __u8  bSignalClass;
+   __u8  bReserved[3];
+} CSMI_SAS_SET_PHY_INFO,
+  *PCSMI_SAS_SET_PHY_INFO;
+
+typedef struct _CSMI_SAS_SET_PHY_INFO_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_SET_PHY_INFO Information;
+} CSMI_SAS_SET_PHY_INFO_BUFFER,
+  *PCSMI_SAS_SET_PHY_INFO_BUFFER;
+
+// CC_CSMI_SAS_GET_LINK_ERRORS
+
+typedef struct _CSMI_SAS_LINK_ERRORS {
+   __u8  bPhyIdentifier;
+   __u8  bResetCounts;
+   __u8  bReserved[2];
+   __u32 uInvalidDwordCount;
+   __u32 uRunningDisparityErrorCount;
+   __u32 uLossOfDwordSyncCount;
+   __u32 uPhyResetProblemCount;
+} CSMI_SAS_LINK_ERRORS,
+  *PCSMI_SAS_LINK_ERRORS;
+
+typedef struct _CSMI_SAS_LINK_ERRORS_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_LINK_ERRORS Information;
+} CSMI_SAS_LINK_ERRORS_BUFFER,
+  *PCSMI_SAS_LINK_ERRORS_BUFFER;
+
+// CC_CSMI_SAS_SMP_PASSTHRU
+
+typedef struct _CSMI_SAS_SMP_REQUEST {
+   __u8  bFrameType;
+   __u8  bFunction;
+   __u8  bReserved[2];
+   __u8  bAdditionalRequestBytes[1016];
+} CSMI_SAS_SMP_REQUEST,
+  *PCSMI_SAS_SMP_REQUEST;
+
+typedef struct _CSMI_SAS_SMP_RESPONSE {
+   __u8  bFrameType;
+   __u8  bFunction;
+   __u8  bFunctionResult;
+   __u8  bReserved;
+   __u8  bAdditionalResponseBytes[1016];
+} CSMI_SAS_SMP_RESPONSE,
+  *PCSMI_SAS_SMP_RESPONSE;
+
+typedef struct _CSMI_SAS_SMP_PASSTHRU {
+   __u8  bPhyIdentifier;
+   __u8  bPortIdentifier;
+   __u8  bConnectionRate;
+   __u8  bReserved;
+   __u8  bDestinationSASAddress[8];
+   __u32 uRequestLength;
+   CSMI_SAS_SMP_REQUEST Request;
+   __u8  bConnectionStatus;
+   __u8  bReserved2[3];
+   __u32 uResponseBytes;
+   CSMI_SAS_SMP_RESPONSE Response;
+} CSMI_SAS_SMP_PASSTHRU,
+  *PCSMI_SAS_SMP_PASSTHRU;
+
+typedef struct _CSMI_SAS_SMP_PASSTHRU_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_SMP_PASSTHRU Parameters;
+} CSMI_SAS_SMP_PASSTHRU_BUFFER,
+  *PCSMI_SAS_SMP_PASSTHRU_BUFFER;
+
+// CC_CSMI_SAS_SSP_PASSTHRU
+
+typedef struct _CSMI_SAS_SSP_PASSTHRU {
+   __u8  bPhyIdentifier;
+   __u8  bPortIdentifier;
+   __u8  bConnectionRate;
+   __u8  bReserved;
+   __u8  bDestinationSASAddress[8];
+   __u8  bLun[8];
+   __u8  bCDBLength;
+   __u8  bAdditionalCDBLength;
+   __u8  bReserved2[2];
+   __u8  bCDB[16];
+   __u32 uFlags;
+   __u8  bAdditionalCDB[24];
+   __u32 uDataLength;
+} CSMI_SAS_SSP_PASSTHRU,
+  *PCSMI_SAS_SSP_PASSTHRU;
+
+typedef struct _CSMI_SAS_SSP_PASSTHRU_STATUS {
+   __u8  bConnectionStatus;
+   __u8  bSSPStatus;
+   __u8  bReserved[2];
+   __u8  bDataPresent;
+   __u8  bStatus;
+   __u8  bResponseLength[2];
+   __u8  bResponse[256];
+   __u32 uDataBytes;
+} CSMI_SAS_SSP_PASSTHRU_STATUS,
+  *PCSMI_SAS_SSP_PASSTHRU_STATUS;
+
+typedef struct _CSMI_SAS_SSP_PASSTHRU_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_SSP_PASSTHRU Parameters;
+   CSMI_SAS_SSP_PASSTHRU_STATUS Status;
+   __u8  bDataBuffer[1];
+} CSMI_SAS_SSP_PASSTHRU_BUFFER,
+  *PCSMI_SAS_SSP_PASSTHRU_BUFFER;
+
+// CC_CSMI_SAS_STP_PASSTHRU
+
+typedef struct _CSMI_SAS_STP_PASSTHRU {
+   __u8  bPhyIdentifier;
+   __u8  bPortIdentifier;
+   __u8  bConnectionRate;
+   __u8  bReserved;
+   __u8  bDestinationSASAddress[8];
+   __u8  bReserved2[4];
+   __u8  bCommandFIS[20];
+   __u32 uFlags;
+   __u32 uDataLength;
+} CSMI_SAS_STP_PASSTHRU,
+  *PCSMI_SAS_STP_PASSTHRU;
+
+typedef struct _CSMI_SAS_STP_PASSTHRU_STATUS {
+   __u8  bConnectionStatus;
+   __u8  bReserved[3];
+   __u8  bStatusFIS[20];
+   __u32 uSCR[16];
+   __u32 uDataBytes;
+} CSMI_SAS_STP_PASSTHRU_STATUS,
+  *PCSMI_SAS_STP_PASSTHRU_STATUS;
+
+typedef struct _CSMI_SAS_STP_PASSTHRU_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_STP_PASSTHRU Parameters;
+   CSMI_SAS_STP_PASSTHRU_STATUS Status;
+   __u8  bDataBuffer[1];
+} CSMI_SAS_STP_PASSTHRU_BUFFER,
+  *PCSMI_SAS_STP_PASSTHRU_BUFFER;
+
+// CC_CSMI_SAS_GET_SATA_SIGNATURE
+
+typedef struct _CSMI_SAS_SATA_SIGNATURE {
+   __u8  bPhyIdentifier;
+   __u8  bReserved[3];
+   __u8  bSignatureFIS[20];
+} CSMI_SAS_SATA_SIGNATURE,
+  *PCSMI_SAS_SATA_SIGNATURE;
+
+typedef struct _CSMI_SAS_SATA_SIGNATURE_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_SATA_SIGNATURE Signature;
+} CSMI_SAS_SATA_SIGNATURE_BUFFER,
+  *PCSMI_SAS_SATA_SIGNATURE_BUFFER;
+
+// CC_CSMI_SAS_GET_SCSI_ADDRESS
+
+typedef struct _CSMI_SAS_GET_SCSI_ADDRESS_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   __u8  bSASAddress[8];
+   __u8  bSASLun[8];
+   __u8  bHostIndex;
+   __u8  bPathId;
+   __u8  bTargetId;
+   __u8  bLun;
+} CSMI_SAS_GET_SCSI_ADDRESS_BUFFER,
+   *PCSMI_SAS_GET_SCSI_ADDRESS_BUFFER;
+
+// CC_CSMI_SAS_GET_DEVICE_ADDRESS
+
+typedef struct _CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   __u8  bHostIndex;
+   __u8  bPathId;
+   __u8  bTargetId;
+   __u8  bLun;
+   __u8  bSASAddress[8];
+   __u8  bSASLun[8];
+} CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER,
+  *PCSMI_SAS_GET_DEVICE_ADDRESS_BUFFER;
+
+// CC_CSMI_SAS_TASK_MANAGEMENT
+
+typedef struct _CSMI_SAS_SSP_TASK_IU {
+   __u8  bHostIndex;
+   __u8  bPathId;
+   __u8  bTargetId;
+   __u8  bLun;
+   __u32 uFlags;
+   __u32 uQueueTag;
+   __u32 uReserved;
+   __u8  bTaskManagementFunction;
+   __u8  bReserved[7];
+   __u32 uInformation;
+} CSMI_SAS_SSP_TASK_IU,
+  *PCSMI_SAS_SSP_TASK_IU;
+
+typedef struct _CSMI_SAS_SSP_TASK_IU_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_SSP_TASK_IU Parameters;
+   CSMI_SAS_SSP_PASSTHRU_STATUS Status;
+} CSMI_SAS_SSP_TASK_IU_BUFFER,
+  *PCSMI_SAS_SSP_TASK_IU_BUFFER;
+
+// CC_CSMI_SAS_GET_CONNECTOR_INFO
+
+typedef struct _CSMI_SAS_GET_CONNECTOR_INFO {
+   __u32 uPinout;
+   __u8  bConnector[16];
+   __u8  bLocation;
+   __u8  bReserved[15];
+} CSMI_SAS_CONNECTOR_INFO,
+  *PCSMI_SAS_CONNECTOR_INFO;
+
+typedef struct _CSMI_SAS_CONNECTOR_INFO_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_CONNECTOR_INFO Reference[32];
+} CSMI_SAS_CONNECTOR_INFO_BUFFER,
+  *PCSMI_SAS_CONNECTOR_INFO_BUFFER;
+
+// CC_CSMI_SAS_GET_LOCATION
+
+typedef struct _CSMI_SAS_LOCATION_IDENTIFIER {
+   __u32 bLocationFlags;
+   __u8  bSASAddress[8];
+   __u8  bSASLun[8];
+   __u8  bEnclosureIdentifier[8];
+   __u8  bEnclosureName[32];
+   __u8  bBayPrefix[32];
+   __u8  bBayIdentifier;
+   __u8  bLocationState;
+   __u8  bReserved[2];
+} CSMI_SAS_LOCATION_IDENTIFIER,
+  *PCSMI_SAS_LOCATION_IDENTIFIER;
+
+typedef struct _CSMI_SAS_GET_LOCATION_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   __u8  bHostIndex;
+   __u8  bPathId;
+   __u8  bTargetId;
+   __u8  bLun;
+   __u8  bIdentify;
+   __u8  bNumberOfLocationIdentifiers;
+   __u8  bLengthOfLocationIdentifier;
+   CSMI_SAS_LOCATION_IDENTIFIER Location[1];
+} CSMI_SAS_GET_LOCATION_BUFFER,
+  *PCSMI_SAS_GET_LOCATION_BUFFER;
+
+// CC_CSMI_SAS_PHY_CONTROL
+
+typedef struct _CSMI_SAS_CHARACTER {
+   __u8  bTypeFlags;
+   __u8  bValue;
+} CSMI_SAS_CHARACTER,
+  *PCSMI_SAS_CHARACTER;
+
+typedef struct _CSMI_SAS_PHY_CONTROL {
+   __u8  bType;
+   __u8  bRate;
+   __u8  bReserved[6];
+   __u32 uVendorUnique[8];
+   __u32 uTransmitterFlags;
+   __i8  bTransmitAmplitude;
+   __i8  bTransmitterPreemphasis;
+   __i8  bTransmitterSlewRate;
+   __i8  bTransmitterReserved[13];
+   __u8  bTransmitterVendorUnique[64];
+   __u32 uReceiverFlags;
+   __i8  bReceiverThreshold;
+   __i8  bReceiverEqualizationGain;
+   __i8  bReceiverReserved[14];
+   __u8  bReceiverVendorUnique[64];
+   __u32 uPatternFlags;
+   __u8  bFixedPattern;
+   __u8  bUserPatternLength;
+   __u8  bPatternReserved[6];
+   CSMI_SAS_CHARACTER UserPatternBuffer[16];
+} CSMI_SAS_PHY_CONTROL,
+  *PCSMI_SAS_PHY_CONTROL;
+
+typedef struct _CSMI_SAS_PHY_CONTROL_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   __u32 uFunction;
+   __u8  bPhyIdentifier;
+   __u16 usLengthOfControl;
+   __u8  bNumberOfControls;
+   __u8  bReserved[4];
+   __u32 uLinkFlags;
+   __u8  bSpinupRate;
+   __u8  bLinkReserved[7];
+   __u32 uVendorUnique[8];
+   CSMI_SAS_PHY_CONTROL Control[1];
+} CSMI_SAS_PHY_CONTROL_BUFFER,
+  *PCSMI_SAS_PHY_CONTROL_BUFFER;
+
+//EDM #pragma CSMI_SAS_END_PACK
+#pragma pack()
+
+#endif // _CSMI_SAS_H_
index 01dc01fe2384f8bb1d11591218f46493d39d7523..8b800fa7c03671d6104a2702a3b7f0276eaf842a 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2008-9 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2008-11 Christian Franke <smartmontools-support@lists.sourceforge.net>
  *
  * 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
 
 #include "config.h"
 #include "int64.h"
-#include "atacmds.h"
-#include "scsicmds.h"
 #include "dev_interface.h"
 #include "dev_tunnelled.h"
 #include "utility.h"
 
+#include <errno.h>
+#include <stdarg.h>
 #include <stdexcept>
 
-const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp 3015 2009-12-30 16:25:59Z chrfranke $"
+const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp 3256 2011-02-08 22:13:41Z chrfranke $"
   DEV_INTERFACE_H_CVSID;
 
 /////////////////////////////////////////////////////////////////////////////
@@ -280,14 +280,18 @@ const char * smart_interface::get_msg_for_errno(int no)
 smart_device * smart_interface::get_smart_device(const char * name, const char * type)
 {
   clear_err();
+
+  // Call platform specific autodetection if no device type specified
+  smart_device * dev;
   if (!type || !*type) {
-    smart_device * dev = autodetect_smart_device(name);
+    dev = autodetect_smart_device(name);
     if (!dev && !get_errno())
       set_err(EINVAL, "Unable to detect device type");
     return dev;
   }
 
-  smart_device * dev = get_custom_smart_device(name, type);
+  // First check for platform specific device types
+  dev = get_custom_smart_device(name, type);
   if (dev || get_errno())
     return dev;
 
index 44940d4a1a0d9682bbcd339f271b93b8d9bc9975..716252f566a6647a895fb8cad7c4f4ed9eeaf32f 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2008-9 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2008-11 Christian Franke <smartmontools-support@lists.sourceforge.net>
  *
  * 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
@@ -18,9 +18,8 @@
 #ifndef DEV_INTERFACE_H
 #define DEV_INTERFACE_H
 
-#define DEV_INTERFACE_H_CVSID "$Id: dev_interface.h 3015 2009-12-30 16:25:59Z chrfranke $\n"
+#define DEV_INTERFACE_H_CVSID "$Id: dev_interface.h 3256 2011-02-08 22:13:41Z chrfranke $\n"
 
-#include <stdarg.h>
 #include <stdexcept>
 #include <string>
 #include <vector>
@@ -111,7 +110,7 @@ public:
   /// Downcast to SCSI device.
   scsi_device * to_scsi()
     { return m_scsi_ptr; }
-  /// Downcast to ATA device (const).
+  /// Downcast to SCSI device (const).
   const scsi_device * to_scsi() const
     { return m_scsi_ptr; }
 
@@ -237,7 +236,7 @@ private:
 /////////////////////////////////////////////////////////////////////////////
 // ATA specific interface
 
-/// ATA register value and info whether is has been ever set
+/// ATA register value and info whether it has ever been set
 // (Automatically set by first assignment)
 class ata_register
 {
@@ -245,8 +244,8 @@ public:
   ata_register()
     : m_val(0x00), m_is_set(false) { }
 
-  ata_register & operator=(unsigned char val)
-    { m_val = val; m_is_set = true; return * this; }
+  ata_register & operator=(unsigned char x)
+    { m_val = x; m_is_set = true; return * this; }
 
   unsigned char val() const
     { return m_val; }
@@ -306,9 +305,9 @@ public:
   ata_reg_alias_16(ata_register & lo, ata_register & hi)
     : m_lo(lo), m_hi(hi) { }
 
-  ata_reg_alias_16 & operator=(unsigned short val)
-    { m_lo = (unsigned char) val;
-      m_hi = (unsigned char)(val >> 8);
+  ata_reg_alias_16 & operator=(unsigned short x)
+    { m_lo = (unsigned char) x;
+      m_hi = (unsigned char)(x >> 8);
       return * this;                   }
 
   unsigned short val() const
@@ -335,14 +334,14 @@ public:
       m_hl(hl), m_hm(hm), m_hh(hh)
     { }
 
-  ata_reg_alias_48 & operator=(uint64_t val)
+  ata_reg_alias_48 & operator=(uint64_t x)
     {
-      m_ll = (unsigned char) val;
-      m_lm = (unsigned char)(val >>  8);
-      m_lh = (unsigned char)(val >> 16);
-      m_hl = (unsigned char)(val >> 24);
-      m_hm = (unsigned char)(val >> 32);
-      m_hh = (unsigned char)(val >> 40);
+      m_ll = (unsigned char) x;
+      m_lm = (unsigned char)(x >>  8);
+      m_lh = (unsigned char)(x >> 16);
+      m_hl = (unsigned char)(x >> 24);
+      m_hm = (unsigned char)(x >> 32);
+      m_hh = (unsigned char)(x >> 40);
       return * this;
     }
 
@@ -600,8 +599,8 @@ public:
         if (m_base_dev && m_dev->owns(m_base_dev))
           m_dev->release(m_base_dev);
         delete m_dev;
+        m_dev = 0;
       }
-      m_dev = 0;
     }
 
   /// Return the pointer and release ownership.
@@ -796,7 +795,7 @@ public:
   /// Default implementation selects between ata, scsi and custom device.
   virtual smart_device * get_smart_device(const char * name, const char * type);
 
-  /// Fill 'devlist' with devices of some 'type' with devices names.
+  /// Fill 'devlist' with devices of some 'type' with device names
   /// specified by some optional 'pattern'.
   /// Return false on error.
   virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
index df8e7fc361674fed8e6ea53ece6c202bbc8afee6..ca4575bcd5d287ccc01e94519633ac00c5f5fd24 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2008-10 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2008-11 Christian Franke <smartmontools-support@lists.sourceforge.net>
  *
  * 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
 
 #include "config.h"
 #include "int64.h"
-#include "extern.h"
 #include "utility.h"
 #include "atacmds.h"
 #include "scsicmds.h"
 #include "dev_interface.h"
 #include "dev_ata_cmd_set.h"
 
-const char * dev_legacy_cpp_cvsid = "$Id: dev_legacy.cpp 3098 2010-04-30 17:35:35Z chrfranke $"
-  DEV_INTERFACE_H_CVSID;
+#include <errno.h>
 
-extern smartmonctrl * con; // con->reportscsiioctl
+const char * dev_legacy_cpp_cvsid = "$Id: dev_legacy.cpp 3263 2011-02-20 18:32:56Z chrfranke $"
+  DEV_INTERFACE_H_CVSID;
 
 /////////////////////////////////////////////////////////////////////////////
 
@@ -38,19 +37,9 @@ int guess_device_type(const char * dev_name);
 int make_device_names (char ***devlist, const char* name);
 int deviceopen(const char *pathname, char *type);
 int deviceclose(int fd);
-#ifdef HAVE_GET_OS_VERSION_STR
-const char * get_os_version_str(void);
-#endif
 
 // from atacmds.h:
 int ata_command_interface(int device, smart_command_set command, int select, char *data);
-int escalade_command_interface(int fd, int escalade_port, int escalade_type, smart_command_set command, int select, char *data);
-int marvell_command_interface(int device, smart_command_set command, int select, char *data);
-int highpoint_command_interface(int device, smart_command_set command, int select, char *data);
-int areca_command_interface(int fd, int disknum, smart_command_set command, int select, char *data);
-#ifdef HAVE_ATA_IDENTIFY_IS_CACHED
-int ata_identify_is_cached(int fd);
-#endif
 
 // from scsicmds.h:
 int do_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report);
@@ -105,7 +94,7 @@ bool legacy_smart_device::is_open() const
 
 bool legacy_smart_device::open()
 {
-  m_fd = ::deviceopen(get_dev_name(), (char*)m_mode);
+  m_fd = ::deviceopen(get_dev_name(), const_cast<char*>(m_mode));
   if (m_fd < 0) {
     set_err((errno==ENOENT || errno==ENOTDIR) ? ENODEV : errno);
     return false;
@@ -133,10 +122,6 @@ class legacy_ata_device
 public:
   legacy_ata_device(smart_interface * intf, const char * dev_name, const char * req_type);
 
-#ifdef HAVE_ATA_IDENTIFY_IS_CACHED
-  virtual bool ata_identify_is_cached() const;
-#endif
-
 protected:
   virtual int ata_command_interface(smart_command_set command, int select, char * data);
 };
@@ -152,148 +137,6 @@ int legacy_ata_device::ata_command_interface(smart_command_set command, int sele
   return ::ata_command_interface(get_fd(), command, select, data);
 }
 
-#ifdef HAVE_ATA_IDENTIFY_IS_CACHED
-bool legacy_ata_device::ata_identify_is_cached() const
-{
-  return !!::ata_identify_is_cached(get_fd());
-}
-#endif
-
-
-/////////////////////////////////////////////////////////////////////////////
-/// Implement AMCC/3ware RAID support with old functions
-
-class legacy_escalade_device
-: public /*implements*/ ata_device_with_command_set,
-  public /*extends*/ legacy_smart_device
-{
-public:
-  legacy_escalade_device(smart_interface * intf, const char * dev_name,
-    int escalade_type, int disknum);
-
-protected:
-  virtual int ata_command_interface(smart_command_set command, int select, char * data);
-
-private:
-  int m_escalade_type; ///< Type string for escalade_command_interface().
-  int m_disknum; ///< Disk number.
-};
-
-legacy_escalade_device::legacy_escalade_device(smart_interface * intf, const char * dev_name,
-    int escalade_type, int disknum)
-: smart_device(intf, dev_name, "3ware", "3ware"),
-  legacy_smart_device(
-    escalade_type==CONTROLLER_3WARE_9000_CHAR ? "ATA_3WARE_9000" :
-    escalade_type==CONTROLLER_3WARE_678K_CHAR ? "ATA_3WARE_678K" :
-    /*             CONTROLLER_3WARE_678K     */ "ATA"             ),
-  m_escalade_type(escalade_type), m_disknum(disknum)
-{
-  set_info().info_name = strprintf("%s [3ware_disk_%02d]", dev_name, disknum);
-}
-
-int legacy_escalade_device::ata_command_interface(smart_command_set command, int select, char * data)
-{
-  return ::escalade_command_interface(get_fd(), m_disknum, m_escalade_type, command, select, data);
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-/// Implement Areca RAID support with old functions
-
-class legacy_areca_device
-: public /*implements*/ ata_device_with_command_set,
-  public /*extends*/ legacy_smart_device
-{
-public:
-  legacy_areca_device(smart_interface * intf, const char * dev_name, int disknum);
-
-protected:
-  virtual int ata_command_interface(smart_command_set command, int select, char * data);
-
-private:
-  int m_disknum; ///< Disk number.
-};
-
-legacy_areca_device::legacy_areca_device(smart_interface * intf, const char * dev_name, int disknum)
-: smart_device(intf, dev_name, "areca", "areca"),
-  legacy_smart_device("ATA_ARECA"),
-  m_disknum(disknum)
-{
-  set_info().info_name = strprintf("%s [areca_%02d]", dev_name, disknum);
-}
-
-int legacy_areca_device::ata_command_interface(smart_command_set command, int select, char * data)
-{
-  return ::areca_command_interface(get_fd(), m_disknum, command, select, data);
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-/// Implement Marvell support with old functions
-
-class legacy_marvell_device
-: public /*implements*/ ata_device_with_command_set,
-  public /*extends*/ legacy_smart_device
-{
-public:
-  legacy_marvell_device(smart_interface * intf, const char * dev_name, const char * req_type);
-
-protected:
-  virtual int ata_command_interface(smart_command_set command, int select, char * data);
-};
-
-
-legacy_marvell_device::legacy_marvell_device(smart_interface * intf,
-  const char * dev_name, const char * req_type)
-: smart_device(intf, dev_name, "marvell", req_type),
-  legacy_smart_device("ATA")
-{
-}
-
-int legacy_marvell_device::ata_command_interface(smart_command_set command, int select, char * data)
-{
-  return ::marvell_command_interface(get_fd(), command, select, data);
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-/// Implement Highpoint RAID support with old functions
-
-class legacy_highpoint_device
-: public /*implements*/ ata_device_with_command_set,
-  public /*extends*/ legacy_smart_device
-{
-public:
-  legacy_highpoint_device(smart_interface * intf, const char * dev_name,
-    unsigned char controller, unsigned char channel, unsigned char port);
-
-protected:
-  virtual int ata_command_interface(smart_command_set command, int select, char * data);
-
-private:
-  unsigned char m_hpt_data[3]; ///< controller/channel/port
-};
-
-
-legacy_highpoint_device::legacy_highpoint_device(smart_interface * intf, const char * dev_name,
-  unsigned char controller, unsigned char channel, unsigned char port)
-: smart_device(intf, dev_name, "hpt", "hpt"),
-  legacy_smart_device("ATA")
-{
-  m_hpt_data[0] = controller; m_hpt_data[1] = channel; m_hpt_data[2] = port;
-  set_info().info_name = strprintf("%s [hpt_disk_%u/%u/%u]", dev_name, m_hpt_data[0], m_hpt_data[1], m_hpt_data[2]);
-}
-
-int legacy_highpoint_device::ata_command_interface(smart_command_set command, int select, char * data)
-{
-  unsigned char old_hpt_data[3];
-  memcpy(old_hpt_data, con->hpt_data, 3);
-  memcpy(con->hpt_data, m_hpt_data, 3);
-  int status = ::highpoint_command_interface(get_fd(), command, select, data);
-  memcpy(con->hpt_data, old_hpt_data, 3);
-  return status;
-}
-
 
 /////////////////////////////////////////////////////////////////////////////
 /// Implement standard SCSI support with old functions
@@ -319,51 +162,7 @@ legacy_scsi_device::legacy_scsi_device(smart_interface * intf,
 
 bool legacy_scsi_device::scsi_pass_through(scsi_cmnd_io * iop)
 {
-  unsigned char oldtype = con->controller_type, oldport = con->controller_port;
-  con->controller_type = CONTROLLER_SCSI; con->controller_port = 0;
-  int status = ::do_scsi_cmnd_io(get_fd(), iop, con->reportscsiioctl);
-  con->controller_type = oldtype; con->controller_port = oldport;
-  if (status < 0) {
-      set_err(-status);
-      return false;
-  }
-  return true;
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-/// Implement CCISS RAID support with old functions
-
-class legacy_cciss_device
-: public /*implements*/ scsi_device,
-  public /*extends*/ legacy_smart_device
-{
-public:
-  legacy_cciss_device(smart_interface * intf, const char * name, unsigned char disknum);
-
-  virtual bool scsi_pass_through(scsi_cmnd_io * iop);
-
-private:
-  unsigned char m_disknum; ///< Disk number.
-};
-
-
-legacy_cciss_device::legacy_cciss_device(smart_interface * intf,
-  const char * dev_name, unsigned char disknum)
-: smart_device(intf, dev_name, "cciss", "cciss"),
-  legacy_smart_device("SCSI"),
-  m_disknum(disknum)
-{
-  set_info().info_name = strprintf("%s [cciss_disk_%02d]", dev_name, disknum);
-}
-
-bool legacy_cciss_device::scsi_pass_through(scsi_cmnd_io * iop)
-{
-  // See os_linux.cpp
-  unsigned char oldtype = con->controller_type, oldport = con->controller_port;
-  con->controller_type = CONTROLLER_CCISS; con->controller_port = m_disknum+1;
-  int status = ::do_scsi_cmnd_io(get_fd(), iop, con->reportscsiioctl);
-  con->controller_type = oldtype; con->controller_port = oldport;
+  int status = ::do_scsi_cmnd_io(get_fd(), iop, scsi_debugmode);
   if (status < 0) {
       set_err(-status);
       return false;
@@ -409,31 +208,6 @@ smart_device * legacy_scsi_device::autodetect_open()
 
   // Use INQUIRY to detect type
 
-  // 3ware ?
-  if (!memcmp(req_buff + 8, "3ware", 5) || !memcmp(req_buff + 8, "AMCC", 4)) {
-    close();
-#if defined(_WIN32) || defined(__CYGWIN__)
-    set_err(EINVAL, "AMCC/3ware controller, please try changing device to %s,N", get_dev_name());
-#else
-    set_err(EINVAL, "AMCC/3ware controller, please try adding '-d 3ware,N',\n"
-                    "you may need to replace %s with /dev/twaN or /dev/tweN", get_dev_name());
-#endif
-    return this;
-  }
-
-  // Marvell ?
-  if (len >= 42 && !memcmp(req_buff + 36, "MVSATA", 6)) { // TODO: Linux-specific?
-    //pout("Device %s: using '-d marvell' for ATA disk with Marvell driver\n", get_dev_name());
-    close();
-    smart_device_auto_ptr newdev(
-      new legacy_marvell_device(smi(), get_dev_name(), get_req_type()),
-      this
-    );
-    newdev->open(); // TODO: Can possibly pass open fd
-    delete this;
-    return newdev.release();
-  }
-
   // SAT or USB ?
   {
     smart_device * newdev = smi()->autodetect_sat_device(this, req_buff, len);
@@ -454,10 +228,6 @@ class legacy_smart_interface
 : public /*implements*/ smart_interface
 {
 public:
-#ifdef HAVE_GET_OS_VERSION_STR
-  virtual std::string get_os_version_str();
-#endif
-
   virtual std::string get_app_examples(const char * appname);
 
   virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
@@ -469,22 +239,11 @@ 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();
 };
 
 
 //////////////////////////////////////////////////////////////////////
 
-#ifdef HAVE_GET_OS_VERSION_STR
-std::string legacy_smart_interface::get_os_version_str()
-{
-  return ::get_os_version_str();
-}
-#endif
-
 std::string legacy_smart_interface::get_app_examples(const char * appname)
 {
   if (!strcmp(appname, "smartctl"))
@@ -516,7 +275,7 @@ smart_device * legacy_smart_interface::autodetect_smart_device(const char * name
 
 static void free_devnames(char * * devnames, int numdevs)
 {
-  static const char version[] = "$Id: dev_legacy.cpp 3098 2010-04-30 17:35:35Z chrfranke $";
+  static const char version[] = "$Id: dev_legacy.cpp 3263 2011-02-20 18:32:56Z chrfranke $";
   for (int i = 0; i < numdevs; i++)
     FreeNonZero(devnames[i], -1,__LINE__, version);
   FreeNonZero(devnames, (sizeof (char*) * numdevs),__LINE__, version);
@@ -552,7 +311,7 @@ bool legacy_smart_interface::scan_smart_devices(smart_device_list & devlist,
 
   // Add to devlist
   int i;
-  if (type==NULL)
+  if (!type)
     type="";
   for (i = 0; i < numata; i++) {
     ata_device * atadev = get_ata_device(atanames[i], type);
@@ -570,90 +329,6 @@ bool legacy_smart_interface::scan_smart_devices(smart_device_list & devlist,
   return true;
 }
 
-
-smart_device * legacy_smart_interface::get_custom_smart_device(const char * name, const char * type)
-{
-  // Marvell ?
-  if (!strcmp(type, "marvell"))
-    return new legacy_marvell_device(this, name, type);
-
-  // 3Ware ?
-  int disknum = -1, n1 = -1, n2 = -1;
-  if (sscanf(type, "3ware,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) {
-    if (n2 != (int)strlen(type)) {
-      set_err(EINVAL, "Option -d 3ware,N requires N to be a non-negative integer");
-      return 0;
-    }
-    if (!(0 <= disknum && disknum <= 127)) {
-      set_err(EINVAL, "Option -d 3ware,N (N=%d) must have 0 <= N <= 127", disknum);
-      return 0;
-    }
-    int contr = ::guess_device_type(name);
-    if (contr != CONTROLLER_3WARE_9000_CHAR && contr != CONTROLLER_3WARE_678K_CHAR)
-      contr = CONTROLLER_3WARE_678K;
-    return new legacy_escalade_device(this, name, contr, disknum);
-  }
-
-  // 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");
-      return 0;
-    }
-    if (!(1 <= disknum && disknum <= 24)) {
-      set_err(EINVAL, "Option -d areca,N (N=%d) must have 1 <= N <= 24", disknum);
-      return 0;
-    }
-    return new legacy_areca_device(this, name, disknum);
-  }
-
-  // Highpoint ?
-  int controller = -1, channel = -1; disknum = 1;
-  n1 = n2 = -1; int n3 = -1;
-  if (sscanf(type, "hpt,%n%d/%d%n/%d%n", &n1, &controller, &channel, &n2, &disknum, &n3) >= 2 || n1 == 4) {
-    int len = strlen(type);
-    if (!(n2 == len || n3 == len)) {
-      set_err(EINVAL, "Option '-d hpt,L/M/N' supports 2-3 items");
-      return 0;
-    }
-    if (!(1 <= controller && controller <= 8)) {
-      set_err(EINVAL, "Option '-d hpt,L/M/N' invalid controller id L supplied");
-      return 0;
-    }
-    if (!(1 <= channel && channel <= 8)) {
-      set_err(EINVAL, "Option '-d hpt,L/M/N' invalid channel number M supplied");
-      return 0;
-    }
-    if (!(1 <= disknum && disknum <= 15)) {
-      set_err(EINVAL, "Option '-d hpt,L/M/N' invalid pmport number N supplied");
-      return 0;
-    }
-    return new legacy_highpoint_device(this, name, controller, channel, disknum);
-  }
-
-  // CCISS ?
-  disknum = n1 = n2 = -1;
-  if (sscanf(type, "cciss,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) {
-    if (n2 != (int)strlen(type)) {
-      set_err(EINVAL, "Option -d cciss,N requires N to be a non-negative integer");
-      return 0;
-    }
-    if (!(0 <= disknum && disknum <= 127)) {
-      set_err(EINVAL, "Option -d cciss,N (N=%d) must have 0 <= N <= 127", disknum);
-      return 0;
-    }
-    return new legacy_cciss_device(this, name, disknum);
-  }
-
-  return 0;
-}
-
-std::string legacy_smart_interface::get_valid_custom_dev_types_str()
-{
-  return "marvell, areca,N, 3ware,N, hpt,L/M/N, cciss,N";
-}
-
 } // namespace
 
 
index 967f9b7ce4d766a77307b7e1e0c27324e2d4efb7..66c6fc76f2f87d67957cf3da64b829728f5ef7cf 100755 (executable)
@@ -1,10 +1,10 @@
 #!/bin/bash
 #
 # do a smartmontools release
-# (C) 2003-9 Bruce Allen <ballen4705@users.sourceforge.net>,
-#            Guido Guenther <agx@sigxcpu.org>
-#            Christian Franke <smartmontools-support@lists.sourceforge.net>
-# $Id: do_release 2997 2009-12-11 21:25:59Z chrfranke $
+# (C) 2003-11 Bruce Allen <ballen4705@users.sourceforge.net>,
+#             Guido Guenther <agx@sigxcpu.org>
+#             Christian Franke <smartmontools-support@lists.sourceforge.net>
+# $Id: do_release 3282 2011-03-04 19:26:59Z chrfranke $
 
 # Notes on generating releases:
 # (1) update NEWS
@@ -15,6 +15,9 @@
 
 set -e
 
+# Smartmontools Signing Key (through 2012)
+KEYID=0x2753E77A
+
 inc_release()
 {
   MINOR=`echo $VERSION | cut -d. -f2`
@@ -59,10 +62,10 @@ if [ -n "${REV//[0-9]/}" ]; then
 fi
 
 (cd $WDROOT && svn status) | while read s; do
-  case "$s" in
-    "M       "$DIRPAT/smartmontools/CHANGELOG)    echo "$s: OK";;
-    "M       "$DIRPAT/smartmontools/NEWS)         echo "$s: OK";;
-    "M       "$DIRPAT/smartmontools/configure.in) echo "$s: OK";;
+  case "`echo $s | tr -s ' '`" in
+    "M "$DIRPAT/smartmontools/CHANGELOG)    echo "$s: OK";;
+    "M "$DIRPAT/smartmontools/NEWS)         echo "$s: OK";;
+    "M "$DIRPAT/smartmontools/configure.in) echo "$s: OK";;
     *) echo "$s: not allowed"; exit 1;;
   esac
 done
@@ -126,7 +129,6 @@ mv -f build/smartmontools-$VERSION.tar.gz $TARFILE
 rm -rvf build
 
 md5sum $TARFILE > $TARFILE.md5
-sha1sum $TARFILE > $TARFILE.sha1
 
 # Increase release number
 if [ -z "$RC" -a "$DIRPAT" = "trunk" ]; then
@@ -137,3 +139,8 @@ if [ -z "$RC" -a "$DIRPAT" = "trunk" ]; then
   fi
 fi
 
+# Sign tarball
+if [ -n "$KEYID" ] && gpg --list-secret-keys $KEYID >/dev/null 2>/dev/null; then
+  gpg --default-key $KEYID --armor --detach-sign ./smartmontools-$VERSIONRC.tar.gz
+fi
+
index 4334e80e9b9f424de89b43a5574dd5c331750c5a..1b4ace5e7aaffb2cbbd763dec088b04f06c01c7e 100644 (file)
--- a/drivedb.h
+++ b/drivedb.h
@@ -3,8 +3,8 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2003-10 Philip Williams, Bruce Allen
- * Copyright (C) 2008-10 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2003-11 Philip Williams, Bruce Allen
+ * Copyright (C) 2008-11 Christian Franke <smartmontools-support@lists.sourceforge.net>
  *
  * 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
 /*
 const drive_settings builtin_knowndrives[] = {
  */
-  { "$Id: drivedb.h 3124 2010-07-12 19:21:00Z chrfranke $",
+  { "$Id: drivedb.h 3290 2011-03-09 20:40:36Z chrfranke $",
     "-", "-",
     "This is a dummy entry to hold the SVN-Id of drivedb.h",
     ""
   },
-  { "Apple SSD SM128",
+  { "Apple SSD SM128", // Samsung?
     "APPLE SSD SM128",
     "", "", ""
   },
+  { "Apple SSD TS*", // Toshiba?
+      // tested with APPLE SSD TS064C/CJAA0201
+    "APPLE SSD TS.*",
+    "", "",
+    "-v 10,raw48,Unknown_Attribute "
+    "-v 240,raw48,Unknown_Attribute"
+  },
   { "Asus-Phison SSD",
     "ASUS-PHISON SSD",
     "", "", ""
   },
-  { "SuperTalent UltraDrive GX SSD",
-    "STT_FT[MD](28|32|56|64)GX25H",
-    "", "",
-    " -v 1,raw64"
-    " -v 9,raw64"
-    " -v 12,raw64"
-    " -v 184,raw64,Initial_Bad_Block_Count"
-    " -v 195,raw64,Program_Failure_Blk_Ct"
-    " -v 196,raw64,Erase_Failure_Blk_Ct"
-    " -v 197,raw64,Read_Failure_Blk_Ct"
-    " -v 198,raw64,Read_Sectors_Tot_Ct"
-    " -v 199,raw64,Write_Sectors_Tot_Ct"
-    " -v 200,raw64,Read_Commands_Tot_Ct"
-    " -v 201,raw64,Write_Commands_Tot_Ct"
-    " -v 202,raw64,Error_Bits_Flash_Tot_Ct"
-    " -v 203,raw64,Corr_Read_Errors_Tot_Ct"
-    " -v 204,raw64,Bad_Block_Full_Flag"
-    " -v 205,raw64,Max_PE_Count_Spec"
-    " -v 206,raw64,Min_Erase_Count"
-    " -v 207,raw64,Max_Erase_Count"
-    " -v 208,raw64,Average_Erase_Count"
-    " -v 209,raw64,Remaining_Lifetime_Perc"
-    " -v 210,raw64"
-    " -v 211,raw64"
-    " -v 212,raw64"
-    " -v 213,raw64"
-  },
-  { "Patriot Torqx SSD",
-    "Patriot[ -]Torqx.*",
+  { "Crucial RealSSD C300 Series", // tested with C300-CTFDDAC128MAG/0002
+    "C300-CTFDDA[AC](064|128|256)MAG",
     "", "",
-    " -v 1,raw64"
-    " -v 9,raw64"
-    " -v 12,raw64"
-    " -v 184,raw64,Initial_Bad_Block_Count"
-    " -v 195,raw64,Program_Failure_Blk_Ct"
-    " -v 196,raw64,Erase_Failure_Blk_Ct"
-    " -v 197,raw64,Read_Failure_Blk_Ct"
-    " -v 198,raw64,Read_Sectors_Tot_Ct"
-    " -v 199,raw64,Write_Sectors_Tot_Ct"
-    " -v 200,raw64,Read_Commands_Tot_Ct"
-    " -v 201,raw64,Write_Commands_Tot_Ct"
-    " -v 202,raw64,Error_Bits_Flash_Tot_Ct"
-    " -v 203,raw64,Corr_Read_Errors_Tot_Ct"
-    " -v 204,raw64,Bad_Block_Full_Flag"
-    " -v 205,raw64,Max_PE_Count_Spec"
-    " -v 206,raw64,Min_Erase_Count"
-    " -v 207,raw64,Max_Erase_Count"
-    " -v 208,raw64,Average_Erase_Count"
-    " -v 209,raw64,Remaining_Lifetime_Perc"
-    " -v 210,raw64"
-    " -v 211,raw64"
-    " -v 212,raw64"
-    " -v 213,raw64"
-  },
-  { "OCZ Vertex SSD",
-    "OCZ[ -]VERTEX.*",
+    "-v 189,raw48,Unknown_Attribute "
+    "-v 202,raw48,Unknown_Attribute "
+    "-v 206,raw48,Unknown_Attribute"
+  },
+  { "SandForce Driven SSDs",
+    "SandForce 1st Ed\\.|" // Demo Drive, tested with firmware 320A13F0
+    "ADATA SSD S599 ...GB|" // tested with ADATA SSD S599 256GB/3.1.0
+    "Corsair CSSD-F(40|60|80|120|160|240)GBP?2.*|" // Corsair Force, tested with
+      // Corsair CSSD-F40GB2/1.1
+    "FTM(06|12|24|48)CT25H|" // Supertalent TeraDrive CT, tested with
+      // FTM24CT25H/STTMP2P1
+    "OCZ[ -](AGILITY2|VERTEX2(-PRO)?|VERTEX-LE)( .*)?|" // tested with
+      // OCZ-VERTEX2/1.11, OCZ-VERTEX2 3.5/1.11
+      // OCZ VERTEX2-PRO/1.10 (Bogus thresholds for attribute 232 and 235)
+    "UGB(88P|99S)GC...H[BF].", // Unigen, tested with
+      // UGB88PGC100HF2/MP Rev2, UGB99SGC100HB3/RC Rev3
     "", "",
-    " -v 1,raw64"
-    " -v 9,raw64"
-    " -v 12,raw64"
-    " -v 184,raw64,Initial_Bad_Block_Count"
-    " -v 195,raw64,Program_Failure_Blk_Ct"
-    " -v 196,raw64,Erase_Failure_Blk_Ct"
-    " -v 197,raw64,Read_Failure_Blk_Ct"
-    " -v 198,raw64,Read_Sectors_Tot_Ct"
-    " -v 199,raw64,Write_Sectors_Tot_Ct"
-    " -v 200,raw64,Read_Commands_Tot_Ct"
-    " -v 201,raw64,Write_Commands_Tot_Ct"
-    " -v 202,raw64,Error_Bits_Flash_Tot_Ct"
-    " -v 203,raw64,Corr_Read_Errors_Tot_Ct"
-    " -v 204,raw64,Bad_Block_Full_Flag"
-    " -v 205,raw64,Max_PE_Count_Spec"
-    " -v 206,raw64,Min_Erase_Count"
-    " -v 207,raw64,Max_Erase_Count"
-    " -v 208,raw64,Average_Erase_Count"
-    " -v 209,raw64,Remaining_Lifetime_Perc"
-    " -v 210,raw64"
-    " -v 211,raw64"
-    " -v 212,raw64"
-    " -v 213,raw64"
-  },
-  { "OCZ Agility SSD",
-    "OCZ[ -]AGILITY.*",
+    "-v 1,raw24/raw32,Raw_Read_Error_Rate "
+    "-v 5,raw48,Retired_Block_Count "
+    "-v 9,msec24hour32,Power_On_Hours_and_Msec "
+  //"-v 12,raw48,Power_Cycle_Count "
+    "-v 13,raw24/raw32,Soft_Read_Error_Rate "
+    "-v 100,raw48,Gigabytes_Erased "
+    "-v 170,raw48,Reserve_Block_Count "
+    "-v 171,raw48,Program_Fail_Count "
+    "-v 172,raw48,Erase_Fail_Count "
+    "-v 174,raw48,Unexpect_Power_Loss_Ct "
+    "-v 177,raw48,Wear_Range_Delta "
+    "-v 181,raw48,Program_Fail_Count "
+    "-v 182,raw48,Erase_Fail_Count "
+    "-v 184,raw48,IO_Error_Detect_Code_Ct "
+  //"-v 187,raw48,Reported_Uncorrect "
+  //"-v 194,tempminmax,Temperature_Celsius "
+    "-v 195,raw24/raw32,ECC_Uncorr_Error_Count "
+  //"-v 196,raw48,Reallocated_Event_Count "
+    "-v 198,hex48,Uncorrectable_Sector_Ct "
+    "-v 199,raw48,SATA_CRC_Error_Count "
+    "-v 201,raw24/raw32,Unc_Soft_Read_Err_Rate "
+    "-v 204,raw24/raw32,Soft_ECC_Correct_Rate "
+    "-v 230,raw48,Life_Curve_Status "
+    "-v 231,raw48,SSD_Life_Left "
+  //"-v 232,raw48,Available_Reservd_Space "
+    "-v 233,raw48,SandForce_Internal "
+    "-v 234,raw48,SandForce_Internal "
+    "-v 235,raw48,SuperCap_Health "
+    "-v 241,raw48,Lifetime_Writes_GiB "
+    "-v 242,raw48,Lifetime_Reads_GiB"
+  },
+  { "Indilinx Barefoot based SSDs",
+    "CRUCIAL_CT(64|128|256)M225|" // tested with CRUCIAL_CT64M225/1571
+    "OCZ[ -](AGILITY|ONYX|VERTEX( 1199|-TURBO)?)|" // tested with
+      // OCZ-ONYX/1.6, OCZ-VERTEX 1199/00.P97, OCZ-VERTEX/1.30, OCZ VERTEX-TURBO/1.5
+    "Patriot[ -]Torqx.*|"
+    "STT_FT[MD](28|32|56|64)GX25H|" // Super Talent Ultradrive, tested with STT_FTM64GX25H/1916
+    "TS(18|25)M(64|128)MLC(16|32|64|128|256|512)GSSD", // ASAX Leopard Hunt II, tested with TS25M64MLC64GSSD/0.1
     "", "",
-    " -v 1,raw64"
-    " -v 9,raw64"
-    " -v 12,raw64"
-    " -v 184,raw64,Initial_Bad_Block_Count"
-    " -v 195,raw64,Program_Failure_Blk_Ct"
-    " -v 196,raw64,Erase_Failure_Blk_Ct"
-    " -v 197,raw64,Read_Failure_Blk_Ct"
-    " -v 198,raw64,Read_Sectors_Tot_Ct"
-    " -v 199,raw64,Write_Sectors_Tot_Ct"
-    " -v 200,raw64,Read_Commands_Tot_Ct"
-    " -v 201,raw64,Write_Commands_Tot_Ct"
-    " -v 202,raw64,Error_Bits_Flash_Tot_Ct"
-    " -v 203,raw64,Corr_Read_Errors_Tot_Ct"
-    " -v 204,raw64,Bad_Block_Full_Flag"
-    " -v 205,raw64,Max_PE_Count_Spec"
-    " -v 206,raw64,Min_Erase_Count"
-    " -v 207,raw64,Max_Erase_Count"
-    " -v 208,raw64,Average_Erase_Count"
-    " -v 209,raw64,Remaining_Lifetime_Perc"
-    " -v 210,raw64"
-    " -v 211,raw64"
-    " -v 212,raw64"
-    " -v 213,raw64"
-  },
-  { "Crucial M225 SSD",
-    "CRUCIAL_CT(64|128|256)M225",
-    "", "",
-    " -v 1,raw64"
-    " -v 9,raw64"
-    " -v 12,raw64"
-    " -v 184,raw64,Initial_Bad_Block_Count"
-    " -v 195,raw64,Program_Failure_Blk_Ct"
-    " -v 196,raw64,Erase_Failure_Blk_Ct"
-    " -v 197,raw64,Read_Failure_Blk_Ct"
-    " -v 198,raw64,Read_Sectors_Tot_Ct"
-    " -v 199,raw64,Write_Sectors_Tot_Ct"
-    " -v 200,raw64,Read_Commands_Tot_Ct"
-    " -v 201,raw64,Write_Commands_Tot_Ct"
-    " -v 202,raw64,Error_Bits_Flash_Tot_Ct"
-    " -v 203,raw64,Corr_Read_Errors_Tot_Ct"
-    " -v 204,raw64,Bad_Block_Full_Flag"
-    " -v 205,raw64,Max_PE_Count_Spec"
-    " -v 206,raw64,Min_Erase_Count"
-    " -v 207,raw64,Max_Erase_Count"
-    " -v 208,raw64,Average_Erase_Count"
-    " -v 209,raw64,Remaining_Lifetime_Perc"
-    " -v 210,raw64"
-    " -v 211,raw64"
-    " -v 212,raw64"
-    " -v 213,raw64"
-  },
-  { "Intel X25-E SSD",
+    "-v 1,raw64 " // Raw_Read_Error_Rate
+    "-v 9,raw64 " // Power_On_Hours
+    "-v 12,raw64 " // Power_Cycle_Count
+    "-v 184,raw64,Initial_Bad_Block_Count "
+    "-v 195,raw64,Program_Failure_Blk_Ct "
+    "-v 196,raw64,Erase_Failure_Blk_Ct "
+    "-v 197,raw64,Read_Failure_Blk_Ct "
+    "-v 198,raw64,Read_Sectors_Tot_Ct "
+    "-v 199,raw64,Write_Sectors_Tot_Ct "
+    "-v 200,raw64,Read_Commands_Tot_Ct "
+    "-v 201,raw64,Write_Commands_Tot_Ct "
+    "-v 202,raw64,Error_Bits_Flash_Tot_Ct "
+    "-v 203,raw64,Corr_Read_Errors_Tot_Ct "
+    "-v 204,raw64,Bad_Block_Full_Flag "
+    "-v 205,raw64,Max_PE_Count_Spec "
+    "-v 206,raw64,Min_Erase_Count "
+    "-v 207,raw64,Max_Erase_Count "
+    "-v 208,raw64,Average_Erase_Count "
+    "-v 209,raw64,Remaining_Lifetime_Perc "
+    "-v 210,raw64,Indilinx_Internal "
+    "-v 211,raw64,SATA_Error_Ct_CRC "
+    "-v 212,raw64,SATA_Error_Ct_Handshake "
+    "-v 213,raw64,Indilinx_Internal"
+  },
+  { "Intel X25-E SSDs",
     "SSDSA2SH(032|064)G1.* INTEL",  // G1 = first generation
     "", "",
-    "-v 225,raw48,Host_Writes_Count"
-  },
-  { "Intel X25-M SSD",
-    "INTEL SSDSA2MH(080|160)G1.*",  // G1 = first generation, 50nm
+  //"-v 3,raw48,Spin_Up_Time "
+  //"-v 4,raw48,Start_Stop_Count "
+  //"-v 5,raw48,Reallocated_Sector_Ct "
+  //"-v 9,raw48,Power_On_Hours "
+  //"-v 12,raw48,Power_Cycle_Count "
+    "-v 192,raw48,Unsafe_Shutdown_Count "
+    "-v 225,raw48,Host_Writes_32MiB "
+    "-v 226,raw48,Intel_Internal "
+    "-v 227,raw48,Intel_Internal "
+    "-v 228,raw48,Intel_Internal "
+  //"-v 232,raw48,Available_Reservd_Space "
+  //"-v 233,raw48,Media_Wearout_Indicator"
+  },
+  { "Intel X18-M/X25-M G1 SSDs",
+    "INTEL SSDSA[12]MH(080|160)G1.*",  // G1 = first generation, 50nm
     "", "",
-    "-v 225,raw48,Host_Writes_Count"
-  },
-  { "Intel X25-M SSD",
-    "INTEL SSDSA2M(080|160)G2.*",  // G2 = second generation, 34nm
+  //"-v 3,raw48,Spin_Up_Time "
+  //"-v 4,raw48,Start_Stop_Count "
+  //"-v 5,raw48,Reallocated_Sector_Ct "
+  //"-v 9,raw48,Power_On_Hours "
+  //"-v 12,raw48,Power_Cycle_Count "
+    "-v 192,raw48,Unsafe_Shutdown_Count "
+    "-v 225,raw48,Host_Writes_32MiB "
+    "-v 226,raw48,Intel_Internal "
+    "-v 227,raw48,Intel_Internal "
+    "-v 228,raw48,Intel_Internal "
+  //"-v 232,raw48,Available_Reservd_Space "
+  //"-v 233,raw48,Media_Wearout_Indicator"
+  },
+  { "Intel X18-M/X25-M/X25-V G2 SSDs", // fixed firmware
+      // tested with INTEL SSDSA2M(080|160)G2GC/2CV102J8 (X25-M)
+    "INTEL SSDSA[12]M(040|080|160)G2.*",  // G2 = second generation, 34nm
+    "2CV102(J[89A-Z]|[K-Z].)", // >= "2CV102J8"
+    "",
+  //"-v 3,raw48,Spin_Up_Time "
+  //"-v 4,raw48,Start_Stop_Count "
+  //"-v 5,raw48,Reallocated_Sector_Ct "
+  //"-v 9,raw48,Power_On_Hours "
+  //"-v 12,raw48,Power_Cycle_Count "
+  //"-v 184,raw48,End-to-End_Error " // G2 only
+    "-v 192,raw48,Unsafe_Shutdown_Count "
+    "-v 225,raw48,Host_Writes_32MiB "
+    "-v 226,raw48,Workld_Media_Wear_Indic " // Timed Workload Media Wear Indicator (percent*1024)
+    "-v 227,raw48,Workld_Host_Reads_Perc "  // Timed Workload Host Reads Percentage
+    "-v 228,raw48,Workload_Minutes " // 226,227,228 can be reset by 'smartctl -t vendor,0x40'
+  //"-v 232,raw48,Available_Reservd_Space "
+  //"-v 233,raw48,Media_Wearout_Indicator"
+  },
+  { "Intel X18-M/X25-M/X25-V G2 SSDs", // buggy or unknown firmware
+      // tested with INTEL SSDSA2M040G2GC/2CV102HD (X25-V)
+    "INTEL SSDSA[12]M(040|080|160)G2.*",
+    "",
+    "This drive may require a firmware update to\n"
+    "fix possible drive hangs when reading SMART self-test log:\n"
+    "http://downloadcenter.intel.com/Detail_Desc.aspx?DwnldID=18363",
+    "-v 192,raw48,Unsafe_Shutdown_Count "
+    "-v 225,raw48,Host_Writes_32MiB "
+    "-v 226,raw48,Workld_Media_Wear_Indic "
+    "-v 227,raw48,Workld_Host_Reads_Perc "
+    "-v 228,raw48,Workload_Minutes"
+  },
+  { "Kingston SSDNow V Series", // tested with KINGSTON SNV425S264GB/C091126a
+    "KINGSTON SNV425S2(64|128)GB",
     "", "",
-    "-v 225,raw48,Host_Writes_Count"
+    "-v 3,raw48,Unknown_Attribute "
+    "-v 7,raw48,Unknown_Attribute "
+    "-v 8,raw48,Unknown_Attribute "
+    "-v 10,raw48,Unknown_Attribute "
+    "-v 240,raw48,Unknown_Attribute"
   },
   { "Transcend IDE Solid State Drive",
     "TS(8|16|32|64|128)GSSD25-(M|S)",
@@ -255,6 +268,12 @@ const drive_settings builtin_knowndrives[] = {
     "TS(60|120)GSSD25D-M",
     "", "", ""
   },
+  { "Transcend CompactFlash Cards", // tested with TRANSCEND/20080820, TS4GCF133/20100709
+    "TRANSCEND|TS4GCF133",
+    "", "",
+    "-v 7,raw48,Unknown_Attribute "
+    "-v 8,raw48,Unknown_Attribute"
+  },
   { "Marvell SSD SD88SA024BA0 (SUN branded)",
     "MARVELL SD88SA024BA0 SUN24G 0902M0054V",
     "", "", ""
@@ -276,7 +295,7 @@ const drive_settings builtin_knowndrives[] = {
     "(IBM-|Hitachi )?IC35L0[12346]0AVER07.*",
     "",
     "IBM Deskstar 60GXP drives may need upgraded SMART firmware.\n"
-    "Please see http://www.geocities.com/dtla_update/index.html#rel and\n"
+    "Please see http://haque.net/dtla_update/ and\n"
     "http://www.ibm.com/pc/support/site.wss/MIGR-42215.html",
     ""
   },
@@ -289,7 +308,7 @@ const drive_settings builtin_knowndrives[] = {
     "(IBM-)?DTLA-30[57]0[123467][05].*",
     "",
     "IBM Deskstar 40GV and 75GXP drives may need upgraded SMART firmware.\n"
-    "Please see http://www.geocities.com/dtla_update/ and\n"
+    "Please see http://haque.net/dtla_update/ and\n"
     "http://www.ibm.com/pc/support/site.wss/MIGR-42215.html",
     ""
   },
@@ -368,8 +387,8 @@ const drive_settings builtin_knowndrives[] = {
     "-v 198,offlinescanuncsectorct -v 200,writeerrorcount "
     "-v 201,detectedtacount"
   },
-  { "Fujitsu MHT series",
-    "FUJITSU MHT2...(AH|AS|AT|BH)U?.*",
+  { "Fujitsu MHT", // tested with FUJITSU MHT2030AC/909B
+    "FUJITSU MHT2...(AC|AH|AS|AT|BH)U?.*",
     "",
     "",
     "-v 9,seconds"
@@ -397,6 +416,10 @@ const drive_settings builtin_knowndrives[] = {
     "", "",
     "-v 240,raw48,Transfer_Error_Rate"
   },
+  { "Fujitsu MHW2 AC", // tested with FUJITSU MHW2060AC/00900004
+    "FUJITSU MHW20(40|60)AC",
+    "", "", ""
+  },
   { "Fujitsu MHW2 BH series",
     "FUJITSU MHW2(04|06|08|10|12|16)0BH.*",
     "", "", ""
@@ -423,6 +446,10 @@ const drive_settings builtin_knowndrives[] = {
     "FUJITSU MHZ2(08|12|16|25)0BK.*",
     "", "", ""
   },
+  { "Fujitsu MJA2 BH series",
+    "FUJITSU MJA2(08|12|16|25|32|40|50)0BH.*",
+    "", "", ""
+  },
   { "", // Samsung SV4012H (known firmware)
     "SAMSUNG SV4012H",
     "RM100-08",
@@ -463,6 +490,12 @@ const drive_settings builtin_knowndrives[] = {
     "SAMSUNG SV0322A",
     "", "", ""
   },
+  { "SAMSUNG SpinPoint V80 series", // tested with SV1604N/TR100-23
+    "SAMSUNG SV(0211|0401|0612|0802|1203|1604)N",
+    "",
+    "",
+    "-v 9,halfminutes -F samsung2"
+  },
   { "", // SAMSUNG SP40A2H with RR100-07 firmware
     "SAMSUNG SP40A2H",
     "RR100-07",
@@ -497,10 +530,22 @@ const drive_settings builtin_knowndrives[] = {
     "SAMSUNG HD(502H|754J|103S)J",
     "", "", ""
   },
-  { "SAMSUNG SpinPoint F3 EG series", // tested with HD503HI/1AJ100E4
-    "SAMSUNG HD(253G|(324|503)H|754J|105S)I",
+  { "SAMSUNG SpinPoint F3 EG series", // tested with HD503HI/1AJ100E4, HD153WI/1AN10002
+    "SAMSUNG HD(253G|(324|503)H|754J|105S|(153|203)W)I",
     "", "", ""
   },
+  { "SAMSUNG SpinPoint F4 EG (AFT)",// tested with HD204UI/1AQ10001(buggy|fixed)
+    "SAMSUNG HD(155|204)UI",
+    "", // 1AQ10001
+    "Using smartmontools or hdparm with this\n"
+    "drive may result in data loss due to a firmware bug.\n"
+    "****** THIS DRIVE MAY OR MAY NOT BE AFFECTED! ******\n"
+    "Buggy and fixed firmware report same version number!\n"
+    "See the following web pages for details:\n"
+    "http://www.samsung.com/global/business/hdd/faqView.do?b2b_bbs_msg_id=386\n"
+    "http://sourceforge.net/apps/trac/smartmontools/wiki/SamsungF4EGBadBlocks",
+    ""
+  },
   { "SAMSUNG SpinPoint S250 series", // tested with HD200HJ/KF100-06
     "SAMSUNG HD(162|200|250)HJ",
     "", "", ""
@@ -509,9 +554,10 @@ const drive_settings builtin_knowndrives[] = {
     "SAMSUNG HD(250KD|(30[01]|320|40[01])L[DJ])",
     "", "", ""
   },
-  { "SAMSUNG SpinPoint T166 series", // tested with HD501LJ/CR100-10
+  { "SAMSUNG SpinPoint T166", // tested with HD501LJ/CR100-1[01]
     "SAMSUNG HD(080G|160H|32[01]K|403L|50[01]L)J",
-    "", "", ""
+    "", "",
+    "-v 197,increasing" // at least HD501LJ/CR100-11
   },
   { "SAMSUNG SpinPoint P120 series", // VF100-37 firmware, tested with SP2514N/VF100-37
     "SAMSUNG SP(16[01]3|2[05][01]4)[CN]",
@@ -572,12 +618,32 @@ const drive_settings builtin_knowndrives[] = {
     "SAMSUNG HM((061|080)G|(121|160)H|250J)I",
     "", "", ""
   },
+  { "SAMSUNG SpinPoint M6", // tested with HM320JI/2SS00_01 M6
+    "SAMSUNG HM(251J|320[HJ]|[45]00L)I",
+    "", "", ""
+  },
+  { "SAMSUNG SpinPoint M7 series", // tested with HM500JI/2AC101C4
+    "SAMSUNG HM(250H|320I|[45]00J)I",
+    "", "", ""
+  },
+  { "SAMSUNG SpinPoint M7E (AFT)", // tested with HM321HI/2AJ10001, HM641JI/2AJ10001
+    "SAMSUNG HM(161G|(251|321)H|501I|641J)I",
+    "", "", ""
+  },
   { "SAMSUNG SpinPoint M series", // tested with MP0402H/UC100-11
     "SAMSUNG MP0(302|402|603|804)H",
     "",
     "",
     "-v 9,halfminutes"
   },
+  { "SAMSUNG PM800 SSDs", // tested with SAMSUNG SSD PM800 TH 64GB/VBM25D1Q
+    "SAMSUNG SSD PM800 .*GB",
+    "", "", ""
+  },
+  { "SAMSUNG PM810 (470 series) SSDs", // tested with SAMSUNG SSD PM810 2.5" 128GB/AXM06D1Q
+    "SAMSUNG SSD PM810 .*GB",
+    "", "", ""
+  },
 /*
   // TODO: Make the entries below more specific.
   // These entries produce misleading results, because newer
@@ -793,8 +859,8 @@ const drive_settings builtin_knowndrives[] = {
     "MAXTOR STM3(40|80|160)[28]1[12]0?AS?",
     "", "", ""
   },
-  { "Seagate Maxtor DiamondMax 21",
-    "MAXTOR STM3(160215|(250|320)820|320620|500630)AS?",
+  { "Seagate Maxtor DiamondMax 21", // tested with MAXTOR STM3250310AS/3.AAF
+    "MAXTOR STM3(80815|160215|250310|(250|320)820|320620|500630)AS?",
     "", "", ""
   },
   { "Seagate Maxtor DiamondMax 22", // fixed firmware
@@ -996,8 +1062,9 @@ const drive_settings builtin_knowndrives[] = {
     "(Hitachi )?HTS7220(80|10|12|16|20)K9(A3|SA)00",
     "", "", ""
   },
-  { "Hitachi Travelstar 7K320", // tested with HTS723225L9A360/FCDOC30F
-    "(Hitachi )?HT[ES]7232(80|12|16|25|32)L9(A300|A360|SA61)",
+  { "Hitachi Travelstar 7K320", // tested with
+    // HTS723225L9A360/FCDOC30F, HTS723216L9A362/FC2OC39F
+    "(Hitachi )?HT[ES]7232(80|12|16|25|32)L9(A300|A36[02]|SA61)",
     "", "", ""
   },
   { "Hitachi Travelstar 7K500",
@@ -1076,6 +1143,10 @@ const drive_settings builtin_knowndrives[] = {
     "Hitachi HDS722020ALA330",
     "", "", ""
   },
+  { "Hitachi Deskstar 7K3000", // tested with HDS723030ALA640/MKAOA3B0
+    "Hitachi HDS7230((15|20)BLA642|30ALA640)",
+    "", "", ""
+  },
   { "Hitachi Ultrastar 7K1000",
     "(Hitachi )?HUA7210(50|75|10)KLA330",
     "", "", ""
@@ -1100,6 +1171,18 @@ const drive_settings builtin_knowndrives[] = {
     "TOSHIBA MK(80|12|16|25|32)52GSX",
     "", "", ""
   },
+  { "Toshiba 2.5\" HDD MK..59GSXP series", // Adv. Format
+    "TOSHIBA MK(32|50|64|75)59GSXP?",
+    "", "", ""
+  },
+  { "Toshiba 2.5\" HDD MK..59GSM series", // Adv. Format
+    "TOSHIBA MK(75|10)59GSM",
+    "", "", ""
+  },
+  { "Toshiba 2.5\" HDD MK..65GSX series", // tested with TOSHIBA MK5065GSX/GJ003A
+    "TOSHIBA MK(16|25|32|50|64)65GSX",
+    "", "", ""
+  },
   { "Toshiba 1.8\" HDD series",
     "TOSHIBA MK[23468]00[4-9]GA[HL]",
     "", "", ""
@@ -1173,7 +1256,11 @@ const drive_settings builtin_knowndrives[] = {
     "", "", ""
   },
   { "Seagate Momentus 7200 FDE.2 series",
-    "ST9((160413|25041[12]|320426|50042[12])AS|(16041[89]|2504[16]4|32042[67]|500426)ASG)",
+    "ST9((160413|25041[12]|320426|50042[12])AS|(16041[489]|2504[16]4|32042[67]|500426)ASG)",
+    "", "", ""
+  },
+  { "Seagate Momentus XT series", // tested with ST95005620AS/SD22
+    "ST9(2505610|3205620|5005620)AS",
     "", "", ""
   },
   { "Seagate Medalist 1010, 1720, 1721, 2120, 3230 and 4340",  // ATA2, with -t permissive
@@ -1253,7 +1340,7 @@ const drive_settings builtin_knowndrives[] = {
     "", "", ""
   },
   { "Seagate Barracuda 7200.10 family",
-    "ST3((80|160)[28]15|200820|250[34]10|(250|300|320|400)[68]20|500[68]30|750[68]40)AS?",
+    "ST3((80|160)[28]15|200820|250[34]10|(250|300|320|400)[68]20|360320|500[68]30|750[68]40)AS?",
     "", "", ""
   },
   { "Seagate Barracuda 7200.11 family", // unaffected firmware
@@ -1273,7 +1360,7 @@ const drive_settings builtin_knowndrives[] = {
   },
   { "Seagate Barracuda 7200.11 family", // buggy firmware
     "ST3(500[368]20|640[35]30|750[36]30|1000340)AS?",
-    "(AD14|SD1[5-9])",
+    "(AD14|SD1[5-9]|SD81)",
     "There are known problems with these drives,\n"
     "AND THIS FIRMWARE VERSION IS AFFECTED,\n"
     "see the following Seagate web pages:\n"
@@ -1292,7 +1379,7 @@ const drive_settings builtin_knowndrives[] = {
     ""
   },
   { "Seagate Barracuda 7200.12 family",
-    "ST3((160|250)318|(320|500)418|500410|(750|1000)528)AS",
+    "ST3(160318|25031[18]|320418|50041[08]|750(518|52[38])|100052[38])AS",
     "", "", ""
   },
   { "Seagate Barracuda ES",
@@ -1317,6 +1404,26 @@ const drive_settings builtin_knowndrives[] = {
     "ST3(500412|1000520|1500541|2000542)AS",
     "", "", ""
   },
+  { "Seagate Barracuda XT",
+    "ST32000641AS",
+    "", "", ""
+  },
+  { "Seagate Constellation (SATA)", // tested with ST9500530NS/SN03
+    "ST9(160511|500530)NS",
+    "", "", ""
+  },
+  { "Seagate Constellation ES (SATA)", // tested with ST31000524NS/SN11
+    "ST3(50051|100052|200064)4NS",
+    "", "", ""
+  },
+  { "Seagate Pipeline HD 5900.1 family",
+    "ST3(160310|320[34]10|500(321|422))CS",
+    "", "", ""
+  },
+  { "Seagate Pipeline HD 5900.2 family", // tested with ST31000322CS/SC13
+    "ST3(160316|250[34]12|320(311|413)|500(312|414)|1000(322|424))CS",
+    "", "", ""
+  },
   { "Seagate Medalist 17240, 13030, 10231, 8420, and 4310",
     "ST3(17240|13030|10231|8420|4310)A",
     "", "", ""
@@ -1427,11 +1534,15 @@ const drive_settings builtin_knowndrives[] = {
   },
   { "Western Digital Caviar Blue Serial ATA family",  // WD Caviar SE Serial ATA family
     /* not completely accurate: at least also WD800BD, (4|8)00JD sold as Caviar Blue */
-    "WDC WD((8|12|16|25|32)00AABS|(12|16|25|32|40|50)00AAJS)-.*",
+    "WDC WD((8|12|16|25|32)00AABS|(8|12|16|25|32|40|50)00AAJS)-.*",
     "", "", ""
   },
   { "Western Digital Caviar Blue Serial ATA family",  // WD Caviar SE16 Serial ATA family
-    "WDC WD(16|20|25|32|40|50|64|75)00AAKS-.*",
+    "WDC WD((16|20|25|32|40|50|64|75)00AAKS|10EALS)-.*",
+    "", "", ""
+  },
+  { "Western Digital Caviar Blue Serial ATA family",  // SATA 3.0 variants
+    "WDC WD((25|32|50)00AAKX|7500AALX|10EALX)-.*",
     "", "", ""
   },
   { "Western Digital RE Serial ATA family",
@@ -1455,15 +1566,19 @@ const drive_settings builtin_knowndrives[] = {
     "", "", ""
   },
   { "Western Digital Caviar Green (Adv. Format) family",
-    "WDC WD((64|80)00A|(10|15|20)E)ARS-.*",
+    "WDC WD((64|75|80)00AA|(10|15|20)EA|(25|30)EZ)RS-.*",
     "", "", ""
   },
   { "Western Digital Caviar Black family",
-    "WDC WD((500|640|750)1AA|1001FA)LS-.*",
+    "WDC WD((500|640|750)1AAL|1001FA[EL]|2001FAS)S-.*",
     "", "", ""
   },
-  { "Western Digital AV ATA family",
-    "WDC WD(8|16|50)00AV(B|J)B-.*",
+  { "Western Digital AV ATA family", // tested with WDC WD3200AVJB-63J5A0/01.03E01
+    "WDC WD(8|16|25|32|50)00AV[BJ]B-.*",
+    "", "", ""
+  },
+  { "Western Digital AV SATA family",
+    "WDC WD(16|25|32)00AVJS-.*",
     "", "", ""
   },
   { "Western Digital AV-GP family",
@@ -1479,15 +1594,15 @@ const drive_settings builtin_knowndrives[] = {
     "", "", ""
   },
   { "Western Digital VelociRaptor family",
-    "WDC WD(800H|(1500|3000)[BH]|1600H|3000G)LFS-.*",
+    "WDC WD(((800H|(1500|3000)[BH]|1600H|3000G)LFS)|((4500|6000)[BH]LHX))-.*",
     "", "", ""
   },
   { "Western Digital Scorpio EIDE family",
     "WDC WD(4|6|8|10|12|16)00(UE|VE)-.*",
     "", "", ""
   },
-  { "Western Digital Scorpio Blue EIDE family",
-    "WDC WD(4|6|8|10|12|16|25)00BEVE-.*",
+  { "Western Digital Scorpio Blue EIDE", // tested with WDC WD3200BEVE-00A0HT0/11.01A11
+    "WDC WD(4|6|8|10|12|16|25|32)00BEVE-.*",
     "", "", ""
   },
   { "Western Digital Scorpio Serial ATA family",
@@ -1510,12 +1625,13 @@ const drive_settings builtin_knowndrives[] = {
     "WDC WD(7500K|10T)MVV-.*",
     "", "", ""
   },
-  { "Western Digital My Passport hard drive (USB interface)",
-    "WDC WD3200BMVV-.*",
+  { "Western Digital My Passport hard drive (USB interface)", // tested with
+      // WDC WD5000BMVW-11AMCS0/01.01A01
+    "WDC WD(3200BMVV|5000BMVW)-.*",
     "", "", ""
   },
-  { "Quantum Bigfoot series",
-    "QUANTUM BIGFOOT TS10.0A",
+  { "Quantum Bigfoot series", // tested with TS10.0A/A21.0G00, TS12.7A/A21.0F00
+    "QUANTUM BIGFOOT TS(10\\.0|12\\.7)A",
     "", "", ""
   },
   { "Quantum Fireball lct15 series",
@@ -1574,6 +1690,27 @@ const drive_settings builtin_knowndrives[] = {
     "",
     "" // unsupported
   },
+  // VIA
+  { "USB: Connectland BE-USB2-35BP-LCM; VIA VT6204",
+    "0x040d:0x6204",
+    "",
+    "",
+    "" // unsupported
+  },
+  // Buffalo / Melco
+  { "USB: Buffalo JustStore Portable HD-PVU2; ",
+    "0x0411:0x0181",
+    "",
+    "",
+    "-d sat"
+  },
+  // Toshiba
+  { "USB: Toshiba Canvio 500GB; ",
+    "0x0480:0xa004",
+    "",
+    "",
+    "-d usbsunplus"
+  },
   // Cypress
   { "USB: ; Cypress CY7C68300A (AT2)",
     "0x04b4:0x6830",
@@ -1590,27 +1727,51 @@ const drive_settings builtin_knowndrives[] = {
   // Myson Century
   { "USB: ; Myson Century CS8818",
     "0x04cf:0x8818",
-    "0xb007",
+    "", // 0xb007
     "",
     "" // unsupported
   },
   // Samsung
+  { "USB: Samsung S2 Portable; JMicron",
+    "0x04e8:0x1f0[68]",
+    "",
+    "",
+    "-d usbjmicron"
+  },
   { "USB: Samsung Story Station; ",
     "0x04e8:0x5f06",
     "",
     "",
     "-d sat"
   },
+  { "USB: Samsung G2 Portable; JMicron",
+    "0x04e8:0x6032",
+    "",
+    "",
+    "-d usbjmicron"
+  },
+  { "USB: Samsung Story Station 3.0; ",
+    "0x04e8:0x6054",
+    "",
+    "",
+    "-d sat"
+  },
   // Sunplus
+  { "USB: ; SunPlus",
+    "0x04fc:0x0c05",
+    "",
+    "",
+    "-d usbsunplus"
+  },
   { "USB: ; SunPlus SPDIF215",
     "0x04fc:0x0c15",
-    "0xf615",
+    "", // 0xf615
     "",
     "-d usbsunplus"
   },
   { "USB: ; SunPlus SPDIF225", // USB+SATA->SATA
     "0x04fc:0x0c25",
-    "0x0103",
+    "", // 0x0103
     "",
     "-d usbsunplus"
   },
@@ -1623,10 +1784,16 @@ const drive_settings builtin_knowndrives[] = {
   },
   { "USB: Iomega MDHD500-U; ",
     "0x059b:0x0275",
-    "0x0001",
+    "", // 0x0001
     "",
     "" // unsupported
   },
+  { "USB: Iomega MDHD-UE; ",
+    "0x059b:0x0277",
+    "",
+    "",
+    "-d usbjmicron"
+  },
   { "USB: Iomega LDHD-UP; Sunplus",
     "0x059b:0x0370",
     "",
@@ -1660,14 +1827,20 @@ const drive_settings builtin_knowndrives[] = {
   },
   { "USB: LaCie Rugged Hard Drive; JMicron",
     "0x059f:0x101d",
-    "0x0001",
+    "", // 0x0001
+    "",
+    "-d usbjmicron,x"
+  },
+  { "USB: Lacie rikiki; JMicron",
+    "0x059f:0x102a",
+    "",
     "",
     "-d usbjmicron,x"
   },
   // In-System Design
   { "USB: ; In-System/Cypress ISD-300A1",
     "0x05ab:0x0060",
-    "0x1101",
+    "", // 0x1101
     "",
     "-d usbcypress"
   },
@@ -1680,10 +1853,17 @@ const drive_settings builtin_knowndrives[] = {
   },
   { "USB: ; Genesys Logic", // TODO: requires '-T permissive'
     "0x05e3:0x0718",
-    "0x0041",
+    "", // 0x0041
     "",
     "-d sat"
   },
+  // Micron
+  { "USB: Micron USB SSD; ",
+    "0x0634:0x0655",
+    "",
+    "",
+    "" // unsupported
+  },
   // Prolific
   { "USB: ; Prolific PL2507", // USB->PATA
     "0x067b:0x2507",
@@ -1693,17 +1873,29 @@ const drive_settings builtin_knowndrives[] = {
   },
   { "USB: ; Prolific PL3507", // USB+IEE1394->PATA
     "0x067b:0x3507",
-    "0x0001",
+    "", // 0x0001
     "",
     "" // unsupported
   },
   // Freecom
   { "USB: Freecom Hard Drive XS; Sunplus",
     "0x07ab:0xfc8e",
-    "0x010f",
+    "", // 0x010f
     "",
     "-d usbsunplus"
   },
+  { "USB: Freecom Classic HD 120GB; ",
+    "0x07ab:0xfccd",
+    "",
+    "",
+    "" // unsupported
+  },
+  { "USB: Freecom HD 500GB; JMicron",
+    "0x07ab:0xfcda",
+    "",
+    "",
+    "-d usbjmicron"
+  },
   // Toshiba
   { "USB: Toshiba PX1270E-1G16; Sunplus",
     "0x0930:0x0b03",
@@ -1717,6 +1909,12 @@ const drive_settings builtin_knowndrives[] = {
     "",
     "-d usbsunplus"
   },
+  { "USB: Toshiba Stor.E Steel series; Sunplus",
+    "0x0930:0x0b11",
+    "",
+    "",
+    "-d usbsunplus"
+  },
   // Seagate
   { "USB: Seagate FreeAgent Go; ",
     "0x0bc2:0x2(000|100|101)",
@@ -1748,127 +1946,158 @@ const drive_settings builtin_knowndrives[] = {
     "",
     "-d sat"
   },
+  { "USB: Seagate FreeAgent Go Flex; ",
+    "0x0bc2:0x5021",
+    "",
+    "",
+    "-d sat"
+  },
+  { "USB: Seagate FreeAgent Go Flex Desk USB 3.0; ",
+    "0x0bc2:0x50a1",
+    "",
+    "",
+    "-d sat,12"
+  },
   // Dura Micro
   { "USB: Dura Micro 509; Sunplus",
     "0x0c0b:0xb159",
-    "0x0103",
+    "", // 0x0103
     "",
     "-d usbsunplus"
   },
   // Maxtor
   { "USB: Maxtor OneTouch; ",
     "0x0d49:0x7300",
-    "0x0121",
+    "", // 0x0121
     "",
     "-d sat"
   },
   { "USB: Maxtor OneTouch 4; ",
     "0x0d49:0x7310",
-    "0x0125",
+    "", // 0x0125
     "",
     "-d sat"
   },
   { "USB: Maxtor OneTouch 4 Mini; ",
     "0x0d49:0x7350",
-    "0x0125",
+    "", // 0x0125
     "",
     "-d sat"
   },
   { "USB: Maxtor Basics Desktop; ",
     "0x0d49:0x7410",
-    "0x0122",
+    "", // 0x0122
     "",
     "-d sat"
   },
   { "USB: Maxtor Basics Portable; ",
     "0x0d49:0x7450",
-    "0x0122",
+    "", // 0x0122
     "",
     "-d sat"
   },
+  // iRiver
+  { "USB: iRiver iHP-120/140 MP3 Player; Cypress",
+    "0x1006:0x3002",
+    "", // 0x0100
+    "",
+    "-d usbcypress"
+  },
   // Western Digital
   { "USB: WD My Passport (IDE); Cypress",
     "0x1058:0x0701",
-    "0x0240",
+    "", // 0x0240
     "",
     "-d usbcypress"
   },
   { "USB: WD My Passport Portable; ",
     "0x1058:0x0702",
-    "0x0102",
+    "", // 0x0102
     "",
     "-d sat"
   },
   { "USB: WD My Passport Essential; ",
     "0x1058:0x0704",
-    "0x0175",
+    "", // 0x0175
     "",
     "-d sat"
   },
   { "USB: WD My Passport Elite; ",
     "0x1058:0x0705",
-    "0x0175",
+    "", // 0x0175
     "",
     "-d sat"
   },
   { "USB: WD My Passport 070A; ",
     "0x1058:0x070a",
-    "0x1028",
+    "", // 0x1028
+    "",
+    "-d sat"
+  },
+  { "USB: WD My Passport 0730; ",
+    "0x1058:0x0730",
+    "", // 0x1008
     "",
     "-d sat"
   },
   { "USB: WD My Book ES; ",
     "0x1058:0x0906",
-    "0x0012",
+    "", // 0x0012
     "",
     "-d sat"
   },
   { "USB: WD Elements Desktop; ",
     "0x1058:0x1001",
-    "0x0104",
+    "", // 0x0104
     "",
     "-d sat"
   },
   { "USB: WD Elements Desktop WDE1UBK...; ",
     "0x1058:0x1003",
-    "0x0175",
+    "", // 0x0175
     "",
     "-d sat"
   },
   { "USB: WD Elements; ",
     "0x1058:0x1010",
-    "0x0105",
+    "", // 0x0105
     "",
     "-d sat"
   },
   { "USB: WD Elements Desktop; ", // 2TB
     "0x1058:0x1021",
-    "0x2002",
+    "", // 0x2002
     "",
     "-d sat"
   },
   { "USB: WD My Book Essential; ",
     "0x1058:0x1100",
-    "0x0165",
+    "", // 0x0165
     "",
     "-d sat"
   },
   { "USB: WD My Book; ",
     "0x1058:0x1102",
-    "0x1028",
+    "", // 0x1028
     "",
     "-d sat"
   },
   { "USB: WD My Book Essential; ",
     "0x1058:0x1110",
-    "0x1030",
+    "", // 0x1030
+    "",
+    "-d sat"
+  },
+  { "USB: WD My Book Essential USB 3.0; ", // 3TB
+    "0x1058:0x1130",
+    "", // 0x1012
     "",
     "-d sat"
   },
   // A-DATA
   { "USB: A-DATA SH93; Cypress",
     "0x125f:0xa93a",
-    "0x0150",
+    "", // 0x0150
     "",
     "-d usbcypress"
   },
@@ -1881,51 +2110,108 @@ const drive_settings builtin_knowndrives[] = {
   },
   { "USB: ; Initio", // USB->SATA
     "0x13fd:0x1240",
-    "0x0104",
+    "", // 0x0104
     "",
     "-d sat"
   },
   { "USB: ; Initio", // USB+SATA->SATA
     "0x13fd:0x1340",
-    "0x0208",
+    "", // 0x0208
+    "",
+    "-d sat"
+  },
+  { "USB: Intenso Memory Station 2,5\"; Initio",
+    "0x13fd:0x1840",
+    "",
     "",
     "-d sat"
   },
+  // Super Top
+  { "USB: Super Top generic enclosure; Cypress",
+    "0x14cd:0x6116",
+    "",
+    "",
+    "-d usbcypress"
+  },
   // JMicron
+  { "USB: ; JMicron ", // USB->SATA->4xSATA (port multiplier)
+    "0x152d:0x0551",
+    "", // 0x0100
+    "",
+    "-d usbjmicron,x"
+  },
+  { "USB: OCZ THROTTLE OCZESATATHR8G; JMicron JMF601",
+    "0x152d:0x0602",
+    "",
+    "",
+    "" // unsupported
+  },
   { "USB: ; JMicron JM20329", // USB->SATA
     "0x152d:0x2329",
-    "0x0100",
+    "", // 0x0100
     "",
     "-d usbjmicron"
   },
   { "USB: ; JMicron JM20336", // USB+SATA->SATA, USB->2xSATA
     "0x152d:0x2336",
-    "0x0100",
+    "", // 0x0100
     "",
     "-d usbjmicron,x"
   },
+  { "USB: Generic JMicron adapter; JMicron",
+    "0x152d:0x2337",
+    "",
+    "",
+    "-d usbjmicron"
+  },
   { "USB: ; JMicron JM20337/8", // USB->SATA+PATA, USB+SATA->PATA
     "0x152d:0x2338",
-    "0x0100",
+    "", // 0x0100
     "",
     "-d usbjmicron"
   },
   { "USB: ; JMicron JM20339", // USB->SATA
     "0x152d:0x2339",
-    "0x0100",
+    "", // 0x0100
     "",
     "-d usbjmicron,x"
   },
+  { "USB: ; JMicron", // USB+SATA->SATA
+    "0x152d:0x2351",  // e.g. Verbatim Portable Hard Drive 500Gb
+    "", // 0x0100
+    "",
+    "-d sat"
+  },
   { "USB: ; JMicron", // USB->SATA
     "0x152d:0x2352",
-    "0x0100",
+    "", // 0x0100
+    "",
+    "-d usbjmicron,x"
+  },
+  { "USB: ; JMicron", // USB->SATA
+    "0x152d:0x2509",
+    "", // 0x0100
     "",
     "-d usbjmicron,x"
   },
+  // ASMedia
+  { "USB: ; ASMedia ASM1051",
+    "0x174c:0x5106",
+    "",
+    "",
+    "-d sat"
+  },
+  // LucidPort
+  { "USB: RaidSonic ICY BOX IB-110StU3-B; LucidPORT USB300",
+    "0x1759:0x500[02]",
+    "",
+    "",
+    "-d sat"
+  },
   // Verbatim
   { "USB: Verbatim FW/USB160; Oxford OXUF934SSA-LQAG", // USB+IEE1394->SATA
     "0x18a5:0x0215",
-    "0x0001",
+    "", // 0x0001
     "",
     "-d sat"
   },
@@ -1935,6 +2221,13 @@ const drive_settings builtin_knowndrives[] = {
     "",
     "-d usbsunplus"
   },
+  // Silicon Image
+  { "USB: Vantec NST-400MX-SR; Silicon Image 5744",
+    "0x1a4a:0x1670",
+    "",
+    "",
+    "" // unsupported
+  },
   // SunplusIT
   { "USB: ; SunplusIT",
     "0x1bcf:0x0c31",
@@ -1952,7 +2245,7 @@ const drive_settings builtin_knowndrives[] = {
   // OnSpec
   { "USB: ; OnSpec", // USB->PATA
     "0x55aa:0x2b00",
-    "0x0100",
+    "", // 0x0100
     "",
     "" // unsupported
   },
index 6a1b11cdfef8cf821ad5f732adcbab67623cd516..cda752a1fe0463fdbb6f5b00af2fc389b5446588 100755 (executable)
@@ -8,12 +8,14 @@
 # Please see man 8 smartd or man 5 smartd.conf for further
 # information.
 #
-# $Id: Example3,v 1.4 2003/08/17 09:15:56 ballen4705 Exp $
+# $Id: Example3 3187 2010-10-16 13:34:18Z chrfranke $
 
 # Warn all users of a problem     
-wall 'Problem detected with disk: ' "$SMARTD_DEVICESTRING"    
-wall 'Warning message from smartd is: ' "$SMARTD_MESSAGE"      
-wall 'Shutting down machine in 30 seconds... '
+wall <<EOF
+Problem detected with disk: $SMARTD_DEVICESTRING
+Warning message from smartd is: $SMARTD_MESSAGE
+Shutting down machine in 30 seconds...
+EOF
 
 # Wait half a minute
 sleep 30 
diff --git a/examplescripts/Makefile.am b/examplescripts/Makefile.am
deleted file mode 100644 (file)
index 1667f25..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-## Process this file with automake to produce Makefile.in
-#
-# $Id: Makefile.am 2846 2009-07-18 14:18:51Z chrfranke $
-#
-
-examplesdir=$(exampledir)
-
-examples_DATA = README
-
-examples_SCRIPTS = Example1     \
-                   Example2     \
-                   Example3     \
-                   Example4
-
-EXTRA_DIST = $(examples_SCRIPTS)
-
-MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
diff --git a/extern.h b/extern.h
deleted file mode 100644 (file)
index a1b067e..0000000
--- a/extern.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * extern.h
- *
- * Home page of code is: http://smartmontools.sourceforge.net
- *
- * Copyright (C) 2002-9 Bruce Allen <smartmontools-support@lists.sourceforge.net>
- * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
- *
- * 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 Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * You should have received a copy of the GNU General Public License
- * (for example COPYING); if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * This code was originally developed as a Senior Thesis by Michael Cornwell
- * at the Concurrent Systems Laboratory (now part of the Storage Systems
- * Research Center), Jack Baskin School of Engineering, University of
- * California, Santa Cruz. http://ssrc.soe.ucsc.edu/
- *
- */
-
-#ifndef EXTERN_H_
-#define EXTERN_H_
-
-#define EXTERN_H_CVSID "$Id: extern.h,v 1.63 2009/07/07 19:28:29 chrfranke Exp $\n"
-
-// Block used for global control/communications.  If you need more
-// global variables, this should be the only place that you need to
-// add them.
-typedef struct smartmonctrl_s {
-  bool printing_switchable;
-  bool dont_print;
-  bool dont_print_serial;
-  unsigned char permissive;
-  bool conservative;
-  unsigned char reportataioctl;
-  unsigned char reportscsiioctl;
-#ifdef OLD_INTERFACE
-  // 3Ware controller type, but also extensible to other contoller types
-  unsigned char controller_type; // TODO: Only needed for os_linux.cpp
-  // For 3Ware controllers, nonzero value is 1 plus the disk number
-  unsigned char controller_port;  // TODO: Only needed for os_linux.cpp
-  // combined controller/channle/pmport for highpoint rocketraid controller
-  unsigned char hpt_data[3]; // TODO: Only needed for os_linux.cpp
-#endif
-} smartmonctrl;
-
-#endif
index 289d137e20babf967f75a5baa19c904b2ff5b68a..2aad1f2ec0f4efe63d444ce14e56a8d7d220cf79 100644 (file)
@@ -28,7 +28,7 @@
 #endif
 
 #ifdef HAVE_CONFIG_H
-# include <config.h>
+# include "config.h"
 #endif
 
 #if !defined __STDC__ || !__STDC__
index ad06cc7f9e84b3ee030c454f85805dbd290e06cf..07e55318ca35d57521f20382ec0943f7317fd183 100644 (file)
@@ -19,7 +19,7 @@
    02111-1307 USA.  */
 \f
 #ifdef HAVE_CONFIG_H
-#include <config.h>
+#include "config.h"
 #endif
 
 #ifdef _LIBC
index 6ffa3f5ae193c7872ea7c2fbd789cf2151471041..1f2e73470de6889b53fcc4ef6a200315861a1bb4 100644 (file)
@@ -4,8 +4,8 @@
  * Home page of code is: http://smartmontools.sourceforge.net
  * Address of support mailing list: smartmontools-support@lists.sourceforge.net
  *
- * Copyright (C) 2003-10 Philip Williams, Bruce Allen
- * Copyright (C) 2008-10 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2003-11 Philip Williams, Bruce Allen
+ * Copyright (C) 2008-11 Christian Franke <smartmontools-support@lists.sourceforge.net>
  *
  * 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
@@ -22,7 +22,6 @@
 #include "int64.h"
 #include <stdio.h>
 #include "atacmds.h"
-#include "extern.h"
 #include "knowndrives.h"
 #include "utility.h"
 
@@ -35,7 +34,7 @@
 
 #include <stdexcept>
 
-const char * knowndrives_cpp_cvsid = "$Id: knowndrives.cpp 3093 2010-04-30 09:57:36Z chrfranke $"
+const char * knowndrives_cpp_cvsid = "$Id: knowndrives.cpp 3289 2011-03-09 19:52:04Z chrfranke $"
                                      KNOWNDRIVES_H_CVSID;
 
 #define MODEL_STRING_LENGTH                         40
@@ -177,7 +176,7 @@ static bool match(const char * pattern, const char * str)
 // string.  If either the drive's model or firmware strings are not set by the
 // manufacturer then values of NULL may be used.  Returns the entry of the
 // first match in knowndrives[] or 0 if no match if found.
-const drive_settings * lookup_drive(const char * model, const char * firmware)
+static const drive_settings * lookup_drive(const char * model, const char * firmware)
 {
   if (!model)
     model = "";
@@ -289,7 +288,6 @@ int lookup_usb_device(int vendor_id, int product_id, int bcd_device,
     bcd_dev_str[0] = 0;
 
   int found = 0;
-  bool bcd_match = false;
   for (unsigned i = 0; i < knowndrives.size(); i++) {
     const drive_settings & dbentry = knowndrives[i];
 
@@ -309,18 +307,25 @@ int lookup_usb_device(int vendor_id, int product_id, int bcd_device,
 
     // If two entries with same vendor:product ID have different
     // types, use bcd_device (if provided by OS) to select entry.
-    bool bm = (   *bcd_dev_str && *dbentry.firmwareregexp
-               && match(dbentry.firmwareregexp, bcd_dev_str));
-
-    if (found == 0 || bm > bcd_match) {
+    if (  *dbentry.firmwareregexp && *bcd_dev_str
+        && match(dbentry.firmwareregexp, bcd_dev_str)) {
+      // Exact match including bcd_device
+      info = d; found = 1;
+      break;
+    }
+    else if (!found) {
+      // First match without bcd_device
       info = d; found = 1;
-      bcd_match = bm;
     }
-    else if (info.usb_type != d.usb_type && bm == bcd_match) {
-      // two different entries found
+    else if (info.usb_type != d.usb_type) {
+      // Another possible match with different type
       info2 = d; found = 2;
       break;
     }
+
+    // Stop search at first matching entry with empty bcd_device
+    if (!*dbentry.firmwareregexp)
+      break;
   }
 
   return found;
@@ -482,14 +487,14 @@ int showmatchingpresets(const char *model, const char *firmware)
 }
 
 // Shows the presets (if any) that are available for the given drive.
-void show_presets(const ata_identify_device * drive, bool fix_swapped_id)
+void show_presets(const ata_identify_device * drive)
 {
   char model[MODEL_STRING_LENGTH+1], firmware[FIRMWARE_STRING_LENGTH+1];
 
   // get the drive's model/firmware strings
-  format_ata_string(model, drive->model, MODEL_STRING_LENGTH, fix_swapped_id);
-  format_ata_string(firmware, drive->fw_rev, FIRMWARE_STRING_LENGTH, fix_swapped_id);
-  
+  ata_format_id_string(model, drive->model, sizeof(model)-1);
+  ata_format_id_string(firmware, drive->fw_rev, sizeof(firmware)-1);
+
   // and search to see if they match values in the table
   const drive_settings * dbentry = lookup_drive(model, firmware);
   if (!dbentry) {
@@ -512,29 +517,30 @@ void show_presets(const ata_identify_device * drive, bool fix_swapped_id)
   showonepreset(dbentry);
 }
 
-// Sets preset vendor attribute options in opts by finding the entry
-// (if any) for the given drive in knowndrives[].  Values that have
-// already been set in opts will not be changed.  Returns false if drive
-// not recognized.
-bool apply_presets(const ata_identify_device *drive, ata_vendor_attr_defs & defs,
-                   unsigned char & fix_firmwarebug, bool fix_swapped_id)
+// Searches drive database and sets preset vendor attribute
+// options in defs and fix_firmwarebug.
+// Values that have already been set will not be changed.
+// Returns pointer to database entry or nullptr if none found
+const drive_settings * lookup_drive_apply_presets(
+  const ata_identify_device * drive, ata_vendor_attr_defs & defs,
+  unsigned char & fix_firmwarebug)
 {
   // get the drive's model/firmware strings
   char model[MODEL_STRING_LENGTH+1], firmware[FIRMWARE_STRING_LENGTH+1];
-  format_ata_string(model, drive->model, MODEL_STRING_LENGTH, fix_swapped_id);
-  format_ata_string(firmware, drive->fw_rev, FIRMWARE_STRING_LENGTH, fix_swapped_id);
-  
+  ata_format_id_string(model, drive->model, sizeof(model)-1);
+  ata_format_id_string(firmware, drive->fw_rev, sizeof(firmware)-1);
+
   // Look up the drive in knowndrives[].
   const drive_settings * dbentry = lookup_drive(model, firmware);
   if (!dbentry)
-    return false;
+    return 0;
 
   if (*dbentry->presets) {
     // Apply presets
     if (!parse_presets(dbentry->presets, defs, fix_firmwarebug))
       pout("Syntax error in preset option string \"%s\"\n", dbentry->presets);
   }
-  return true;
+  return dbentry;
 }
 
 
index da38e4c846cbee944cfb980d2b02eee966c15ab2..457884988369c8e7960cc09b93f3b8ac432df308 100644 (file)
@@ -4,8 +4,8 @@
  * Home page of code is: http://smartmontools.sourceforge.net
  * Address of support mailing list: smartmontools-support@lists.sourceforge.net
  *
- * Copyright (C) 2003-10 Philip Williams, Bruce Allen
- * Copyright (C) 2008-10 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2003-11 Philip Williams, Bruce Allen
+ * Copyright (C) 2008-11 Christian Franke <smartmontools-support@lists.sourceforge.net>
  *
  * 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
@@ -21,7 +21,7 @@
 #ifndef KNOWNDRIVES_H_
 #define KNOWNDRIVES_H_
 
-#define KNOWNDRIVES_H_CVSID "$Id: knowndrives.h 3093 2010-04-30 09:57:36Z chrfranke $\n"
+#define KNOWNDRIVES_H_CVSID "$Id: knowndrives.h 3288 2011-03-09 18:40:36Z chrfranke $\n"
 
 // Structure to store drive database entries, see drivedb.h for a description.
 struct drive_settings {
@@ -32,10 +32,6 @@ struct drive_settings {
   const char * presets;
 };
 
-// Searches knowndrives[] for a drive with the given model number and firmware
-// string.
-const drive_settings * lookup_drive(const char * model, const char * firmware);
-
 // info returned by lookup_usb_device()
 struct usb_dev_info
 {
@@ -49,7 +45,7 @@ int lookup_usb_device(int vendor_id, int product_id, int bcd_device,
                       usb_dev_info & info, usb_dev_info & info2);
 
 // Shows the presets (if any) that are available for the given drive.
-void show_presets(const ata_identify_device * drive, bool fix_swapped_id);
+void show_presets(const ata_identify_device * drive);
 
 // Shows all presets for drives in knowndrives[].
 // Returns #syntax errors.
@@ -59,12 +55,13 @@ int showallpresets();
 // Returns # matching entries.
 int showmatchingpresets(const char *model, const char *firmware);
 
-// Sets preset vendor attribute options in opts by finding the entry
-// (if any) for the given drive in knowndrives[].  Values that have
-// already been set in opts will not be changed.  Also sets options in
-// con.  Returns false if drive not recognized.
-bool apply_presets(const ata_identify_device * drive, ata_vendor_attr_defs & defs,
-                   unsigned char & fix_firmwarebug, bool fix_swapped_id);
+// Searches drive database and sets preset vendor attribute
+// options in defs and fix_firmwarebug.
+// Values that have already been set will not be changed.
+// Returns pointer to database entry or nullptr if none found.
+const drive_settings * lookup_drive_apply_presets(
+  const ata_identify_device * drive, ata_vendor_attr_defs & defs,
+  unsigned char & fix_firmwarebug);
 
 // Get path for additional database file
 const char * get_drivedb_path_add();
index 2b5b6db5601950b83772ab34f9cfaecffef9230d..b1f398d63acaaf312e5f35bfef0a8450588b4425 100644 (file)
@@ -219,6 +219,7 @@ struct megasas_iocpacket {
        union {
                u8 raw[128];
                struct megasas_header hdr;
+               struct megasas_pthru_frame pthru;
        } frame;
 
        struct iovec sgl[MAX_IOCTL_SGE];
index 25c3a1a9fc6c6cdb2fbfcb7b697307fc4cd6c854..1a11c2977ad6b8839d31c314b3c3921ecaa5abbb 100644 (file)
@@ -20,6 +20,7 @@
 #include <dirent.h>
 #include <fcntl.h>
 #include <err.h>
+#include <errno.h>
 #include <camlib.h>
 #include <cam/scsi/scsi_message.h>
 #include <cam/scsi/scsi_pass.h>
@@ -41,7 +42,6 @@
 #include "scsicmds.h"
 #include "cciss.h"
 #include "utility.h"
-#include "extern.h"
 #include "os_freebsd.h"
 
 #include "dev_interface.h"
@@ -59,6 +59,9 @@
 #if (FREEBSDVER >= 800000)
 #include <libusb20_desc.h>
 #include <libusb20.h>
+#elif defined(__DragonFly__)
+#include <bus/usb/usb.h>
+#include <bus/usb/usbhid.h>
 #else
 #include <dev/usb/usb.h>
 #include <dev/usb/usbhid.h>
 #define PATHINQ_SETTINGS_SIZE   128
 #endif
 
-static __unused const char *filenameandversion="$Id: os_freebsd.cpp 3098 2010-04-30 17:35:35Z chrfranke $";
-
-const char *os_XXXX_c_cvsid="$Id: os_freebsd.cpp 3098 2010-04-30 17:35:35Z chrfranke $" \
+const char *os_XXXX_c_cvsid="$Id: os_freebsd.cpp 3264 2011-02-21 15:52:04Z chrfranke $" \
 ATACMDS_H_CVSID CCISS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_FREEBSD_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
 
-extern smartmonctrl * con;
-
 #define NO_RETURN 0
 #define BAD_SMART 1
 #define NO_DISK_3WARE 2
@@ -121,11 +120,6 @@ void printwarning(int msgNo, const char* extra) {
 // global variable holding byte count of allocated memory
 long long bytes;
 
-const char * dev_freebsd_cpp_cvsid = "$Id: os_freebsd.cpp 3098 2010-04-30 17:35:35Z chrfranke $"
-  DEV_INTERFACE_H_CVSID;
-
-extern smartmonctrl * con; // con->reportscsiioctl
-
 /////////////////////////////////////////////////////////////////////////////
 
 namespace os_freebsd { // No need to publish anything, name provided for Doxygen
@@ -404,7 +398,10 @@ int freebsd_atacam_device::do_cmd( struct ata_ioc_request* request)
                  request->timeout * 1000); // timeout in seconds
 
   // ata_28bit_cmd
-  ccb.ataio.cmd.flags = 0;
+  if (request->flags == ATA_CMD_CONTROL)
+    ccb.ataio.cmd.flags = CAM_ATAIO_NEEDRESULT;
+  else
+    ccb.ataio.cmd.flags = 0;
   ccb.ataio.cmd.command = request->u.ata.command;
   ccb.ataio.cmd.features = request->u.ata.feature;
   ccb.ataio.cmd.lba_low = request->u.ata.lba;
@@ -420,11 +417,13 @@ int freebsd_atacam_device::do_cmd( struct ata_ioc_request* request)
     return -1;
   }
 
-  if ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
-    return 0;
+  if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+    cam_error_print(m_camdev, &ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
+    return -1;
+  }
 
-  cam_error_print(m_camdev, &ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
-  return -1;
+  request->u.ata.count = ccb.ataio.res.sector_count;
+  return 0;
 }
 
 #endif
@@ -961,7 +960,7 @@ freebsd_scsi_device::freebsd_scsi_device(smart_interface * intf,
 
 bool freebsd_scsi_device::scsi_pass_through(scsi_cmnd_io * iop)
 {
-  int report=con->reportscsiioctl;
+  int report=scsi_debugmode;
   union ccb *ccb;
 
   if (report > 0) {
@@ -1098,7 +1097,7 @@ freebsd_cciss_device::freebsd_cciss_device(smart_interface * intf,
 bool freebsd_cciss_device::scsi_pass_through(scsi_cmnd_io * iop)
 {
 #ifdef HAVE_DEV_CISS_CISSIO_H
-  int status = cciss_io_interface(get_fd(), m_disknum, iop, con->reportscsiioctl);
+  int status = cciss_io_interface(get_fd(), m_disknum, iop, scsi_debugmode);
   if (status < 0)
       return set_err(-status);
   return true;
@@ -1244,38 +1243,19 @@ scsi_device * freebsd_smart_interface::get_scsi_device(const char * name, const
 // -1:   error
 // >=0: number of discovered devices
 
-int get_dev_names_cam(char*** names, bool show_all) {
-  int n = 0;
-  char** mp = NULL;
-  unsigned int i;
-  union ccb ccb;
-  int bufsize, fd = -1;
-  int skip_device = 0, skip_bus = 0, changed = 0;
-  char *devname = NULL;
-  int serrno=-1;
-
-  // in case of non-clean exit
-  *names=NULL;
-  ccb.cdm.matches = NULL;
+bool get_dev_names_cam(std::vector<std::string> & names, bool show_all)
+{
+  int fd;
   if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
     if (errno == ENOENT) /* There are no CAM device on this computer */
       return 0;
-    serrno = errno;
+    int serrno = errno;
     pout("%s control device couldn't opened: %s\n", XPT_DEVICE, strerror(errno));
-    n = -1;
-    goto end;
+    errno = serrno;
+    return false;
   }
 
-  // allocate space for up to MAX_NUM_DEV number of ATA devices
-  mp =  (char **)calloc(MAX_NUM_DEV, sizeof(char*));
-  if (mp == NULL) {
-    serrno=errno;
-    pout("Out of memory constructing scan device list (on line %d)\n", __LINE__);
-    n = -1;
-    goto end;
-  };
-
+  union ccb ccb;
   bzero(&ccb, sizeof(union ccb));
 
   ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
@@ -1283,14 +1263,13 @@ int get_dev_names_cam(char*** names, bool show_all) {
   ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
 
   ccb.ccb_h.func_code = XPT_DEV_MATCH;
-  bufsize = sizeof(struct dev_match_result) * MAX_NUM_DEV;
+  int bufsize = sizeof(struct dev_match_result) * MAX_NUM_DEV;
   ccb.cdm.match_buf_len = bufsize;
+  // TODO: Use local buffer instead of malloc() if possible
   ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
   if (ccb.cdm.matches == NULL) {
-    serrno = errno;
-    pout("can't malloc memory for matches on line %d\n", __LINE__);
-    n = -1;
-    goto end;
+    close(fd);
+    throw std::bad_alloc();
   }
   ccb.cdm.num_matches = 0;
   ccb.cdm.num_patterns = 0;
@@ -1300,24 +1279,29 @@ int get_dev_names_cam(char*** names, bool show_all) {
    * We do the ioctl multiple times if necessary, in case there are
    * more than MAX_NUM_DEV nodes in the EDT.
    */
+  int skip_device = 0, skip_bus = 0, changed = 0; // TODO: bool
+  std::string devname;
   do {
     if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
-      serrno = errno;
+      int serrno = errno;
       pout("error sending CAMIOCOMMAND ioctl: %s\n", strerror(errno));
-      n = -1;
-      break;
+      free(ccb.cdm.matches);
+      close(fd);
+      errno = serrno;
+      return false;
     }
 
     if ((ccb.ccb_h.status != CAM_REQ_CMP)
       || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
       && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
       pout("got CAM error %#x, CDM error %d\n", ccb.ccb_h.status, ccb.cdm.status);
-      serrno = ENXIO;
-      n = -1;
-      goto end;
+      free(ccb.cdm.matches);
+      close(fd);
+      errno = ENXIO;
+      return false;
     }
 
-    for (i = 0; i < ccb.cdm.num_matches && n < MAX_NUM_DEV; i++) {
+    for (unsigned i = 0; i < ccb.cdm.num_matches; i++) {
       struct bus_match_result *bus_result;
       struct device_match_result *dev_result;
       struct periph_match_result *periph_result;
@@ -1349,51 +1333,24 @@ int get_dev_names_cam(char*** names, bool show_all) {
         * We are searching for latest name
         */
         periph_result =  &ccb.cdm.matches[i].result.periph_result;
-        free(devname);
-        asprintf(&devname, "%s%s%d", _PATH_DEV, periph_result->periph_name, periph_result->unit_number);
-        if (devname == NULL) {
-          serrno=errno;
-          pout("Out of memory constructing scan SCSI device list (on line %d)\n", __LINE__);
-          n = -1;
-          goto end;
-        };
+        devname = strprintf("%s%s%d", _PATH_DEV, periph_result->periph_name, periph_result->unit_number);
         changed = 0;
       };
-      if ((changed == 1 || show_all) && devname != NULL) {
-        mp[n] = devname;
-        devname = NULL;
-        bytes+=1+strlen(mp[n]);
-        n++;
+      if ((changed == 1 || show_all) && !devname.empty()) {
+        names.push_back(devname);
+        devname.erase();
         changed = 0;
       };
     }
 
-  } while ((ccb.ccb_h.status == CAM_REQ_CMP) && (ccb.cdm.status == CAM_DEV_MATCH_MORE) && n < MAX_NUM_DEV);
+  } while ((ccb.ccb_h.status == CAM_REQ_CMP) && (ccb.cdm.status == CAM_DEV_MATCH_MORE));
 
-  if (devname != NULL) {
-    mp[n] = devname;
-    devname = NULL;
-    bytes+=1+strlen(mp[n]);
-    n++;
-  };
-
-  mp = (char **)reallocf(mp,n*(sizeof (char*))); // shrink to correct size
-  bytes += (n)*(sizeof(char*)); // and set allocated byte count
+  if (!devname.empty())
+    names.push_back(devname);
 
-end:
   free(ccb.cdm.matches);
-  if (fd>-1)
-    close(fd);
-  if (n <= 0) {
-    free(mp);
-    mp = NULL;
-  }
-
-  *names=mp;
-
-  if (serrno>-1)
-    errno=serrno;
-  return(n);
+  close(fd);
+  return true;
 }
 
 // we are using ATA subsystem enumerator to found all ATA devices on system
@@ -1504,11 +1461,10 @@ bool freebsd_smart_interface::scan_smart_devices(smart_device_list & devlist,
     }
   }
 
-  char * * scsinames = 0; int numscsi = 0;
+  std::vector<std::string> scsinames;
   if (!type || !strcmp(type, "scsi")) { // do not export duplicated names
-    numscsi = get_dev_names_cam(&scsinames,0);
-    if (numscsi < 0) {
-      set_err(ENOMEM);
+    if (!get_dev_names_cam(scsinames, false)) {
+      set_err(errno);
       return false;
     }
   }
@@ -1523,14 +1479,14 @@ bool freebsd_smart_interface::scan_smart_devices(smart_device_list & devlist,
       devlist.push_back(atadev);
   }
 
-  for (i = 0; i < numscsi; i++) {
+  for (i = 0; i < (int)scsinames.size(); i++) {
     if(!*type) { // try USB autodetection if no type specified
-      smart_device * smartdev = autodetect_smart_device(scsinames[i]);
+      smart_device * smartdev = autodetect_smart_device(scsinames[i].c_str());
       if(smartdev)
         devlist.push_back(smartdev);
     }
     else {
-      scsi_device * scsidev = get_scsi_device(scsinames[i], type);
+      scsi_device * scsidev = get_scsi_device(scsinames[i].c_str(), type);
       if (scsidev)
         devlist.push_back(scsidev);
     }
@@ -1703,12 +1659,13 @@ smart_device * freebsd_smart_interface::autodetect_smart_device(const char * nam
   }
 
   // check CAM
-  char * * scsinames = 0; int numscsi = 0;
-  numscsi = get_dev_names_cam(&scsinames, 1);
-  if (numscsi > 0) {
+  std::vector<std::string> scsinames;
+  if (!get_dev_names_cam(scsinames, true))
+    pout("Unable to get CAM device list\n");
+  else if (!scsinames.empty()) {
     // check all devices on CAM bus
-    for (i = 0; i < numscsi; i++) {
-      if(strcmp(scsinames[i],name)==0)
+    for (i = 0; i < (int)scsinames.size(); i++) {
+      if(strcmp(scsinames[i].c_str(), name)==0)
       { // our disk device is CAM
         if ((cam_dev = cam_open_device(name, O_RDWR)) == NULL) {
           // open failure
@@ -1750,9 +1707,6 @@ smart_device * freebsd_smart_interface::autodetect_smart_device(const char * nam
         return new freebsd_scsi_device(this, name, "");      
       }
     }
-  } // numscsi > 0
-  else {
-    if(numscsi<0) pout("Unable to get CAM device list\n");
   }
   // device type unknown
   return 0;
index fc6665dbe3b84ed5a6b2b5f5c84592f0ac0d3c2a..d00e9f657ef21c9beeded2d3eaf3b163b93f15f6 100644 (file)
@@ -82,7 +82,7 @@
 #ifndef OS_FREEBSD_H_
 #define OS_FREEBSD_H_
 
-#define OS_FREEBSD_H_CVSID "$Id: os_freebsd.h,v 1.26 2009/01/14 02:39:00 sxzzsf Exp $\n"
+#define OS_FREEBSD_H_CVSID "$Id: os_freebsd.h 3266 2011-02-21 16:33:04Z chrfranke $"
 
 #define MAX_NUM_DEV 26
 
index d733147e22eb35e763b82c4a4ab972336c9dd821..e4b79995fba5d57f6c257cdf7ca2be6751615a09 100644 (file)
@@ -82,7 +82,7 @@
 // should have one *_H_CVSID macro appearing below for each file
 // appearing with #include "*.h" above.  Please list these (below) in
 // alphabetic/dictionary order.
-const char *os_XXXX_c_cvsid="$Id: os_generic.cpp 2915 2009-09-18 21:17:37Z chrfranke $" \
+const char *os_XXXX_c_cvsid="$Id: os_generic.cpp 3191 2010-10-27 19:55:33Z chrfranke $" \
 ATACMDS_H_CVSID CONFIG_H_CVSID OS_GENERIC_H_CVSID UTILITY_H_CVSID;
 
 // This is here to prevent compiler warnings for unused arguments of
@@ -106,8 +106,6 @@ static void unsupported(){
 
   if (!warninggiven) {
     char *osname;
-    extern unsigned char debugmode;
-    unsigned char savedebugmode=debugmode;
     
 #ifdef HAVE_UNAME
     struct utsname ostype;
@@ -117,14 +115,12 @@ static void unsupported(){
     osname="host's";
 #endif
 
-    debugmode=1;
     pout("\n"
          "############################################################################\n"
          "WARNING: smartmontools has not been ported to the %s Operating System.\n"
          "Please see the files os_generic.cpp and os_generic.h for porting instructions.\n"
          "############################################################################\n\n",
          osname);
-    debugmode=savedebugmode;
     warninggiven=1;
   }
   
index c6c0e9f99b436b0d1a36afc9999cf5b3bbebd8d5..0dfea39a83847d115b20059305ea3e899b5b032d 100644 (file)
@@ -3,11 +3,11 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2003-10 Bruce Allen <smartmontools-support@lists.sourceforge.net>
- * Copyright (C) 2003-10 Doug Gilbert <dgilbert@interlog.com>
+ * Copyright (C) 2003-11 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2003-11 Doug Gilbert <dgilbert@interlog.com>
  * Copyright (C) 2008    Hank Wu <hank@areca.com.tw>
  * Copyright (C) 2008    Oliver Bock <brevilo@users.sourceforge.net>
- * Copyright (C) 2008-10 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2008-11 Christian Franke <smartmontools-support@lists.sourceforge.net>
  * Copyright (C) 2008    Jordan Hargrave <jordan_hargrave@dell.com>
  *
  *  Parts of this file are derived from code that was
@@ -60,8 +60,9 @@
 #include <string.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
-#include <sys/file.h>
+#include <sys/utsname.h>
 #include <unistd.h>
+#include <stddef.h>  // for offsetof()
 #include <sys/uio.h>
 #include <sys/types.h>
 #ifndef makedev // old versions of types.h do not include sysmacros.h
 
 #include "int64.h"
 #include "atacmds.h"
-#include "extern.h"
 #include "os_linux.h"
 #include "scsicmds.h"
 #include "utility.h"
-#include "extern.h"
 #include "cciss.h"
 #include "megaraid.h"
 
 
 #define ARGUSED(x) ((void)(x))
 
-const char *os_XXXX_c_cvsid="$Id: os_linux.cpp 3098 2010-04-30 17:35:35Z chrfranke $" \
-ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_LINUX_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
-
-/* for passing global control variables */
-// (con->reportscsiioctl only)
-extern smartmonctrl *con;
+const char * os_linux_cpp_cvsid = "$Id: os_linux.cpp 3293 2011-03-09 21:55:15Z chrfranke $"
+  OS_LINUX_H_CVSID;
 
 
 namespace os_linux { // No need to publish anything, name provided for Doxygen
@@ -196,6 +191,7 @@ static const char  smartctl_examples[] =
                  "  smartctl --all --device=3ware,2 /dev/sda\n"
                  "  smartctl --all --device=3ware,2 /dev/twe0\n"
                  "  smartctl --all --device=3ware,2 /dev/twa0\n"
+                 "  smartctl --all --device=3ware,2 /dev/twl0\n"
                  "          (Prints all SMART info for 3rd ATA disk on 3ware RAID controller)\n"
                  "  smartctl --all --device=hpt,1/1/3 /dev/sda\n"
                  "          (Prints all SMART info for the SATA disk attached to the 3rd PMPort\n"
@@ -855,7 +851,7 @@ linux_scsi_device::linux_scsi_device(smart_interface * intf,
 
 bool linux_scsi_device::scsi_pass_through(scsi_cmnd_io * iop)
 {
-  int status = do_normal_scsi_cmnd_io(get_fd(), iop, con->reportscsiioctl);
+  int status = do_normal_scsi_cmnd_io(get_fd(), iop, scsi_debugmode);
   if (status < 0)
       return set_err(-status);
   return true;
@@ -913,7 +909,7 @@ linux_megaraid_device::~linux_megaraid_device() throw()
 
 smart_device * linux_megaraid_device::autodetect_open()
 {
-  int report = con->reportscsiioctl; 
+  int report = scsi_debugmode;
 
   // Open device
   if (!open())
@@ -938,7 +934,7 @@ smart_device * linux_megaraid_device::autodetect_open()
       return this;
 
   if (report)
-    printf("Got MegaRAID inquiry.. %s\n", req_buff+8);
+    pout("Got MegaRAID inquiry.. %s\n", req_buff+8);
 
   // Use INQUIRY to detect type
   {
@@ -959,7 +955,7 @@ bool linux_megaraid_device::open()
   char line[128];
   int   mjr, n1;
   FILE *fp;
-  int report = con->reportscsiioctl; 
+  int report = scsi_debugmode;
 
   if (!linux_smart_device::open())
     return false;
@@ -982,14 +978,14 @@ bool linux_megaraid_device::open()
        if (sscanf(line, "%d megaraid_sas_ioctl%n", &mjr, &n1) == 1 && n1 == 22) {
           n1=mknod("/dev/megaraid_sas_ioctl_node", S_IFCHR, makedev(mjr, 0));
           if(report > 0)
-            printf("Creating /dev/megaraid_sas_ioctl_node = %d\n", n1 >= 0 ? 0 : errno);
+            pout("Creating /dev/megaraid_sas_ioctl_node = %d\n", n1 >= 0 ? 0 : errno);
           if (n1 >= 0 || errno == EEXIST)
              break;
        }
        else if (sscanf(line, "%d megadev%n", &mjr, &n1) == 1 && n1 == 11) {
           n1=mknod("/dev/megadev0", S_IFCHR, makedev(mjr, 0));
           if(report > 0)
-            printf("Creating /dev/megadev0 = %d\n", n1 >= 0 ? 0 : errno);
+            pout("Creating /dev/megadev0 = %d\n", n1 >= 0 ? 0 : errno);
           if (n1 >= 0 || errno == EEXIST)
              break;
        }
@@ -1022,7 +1018,7 @@ bool linux_megaraid_device::close()
 
 bool linux_megaraid_device::scsi_pass_through(scsi_cmnd_io *iop)
 {
-  int report = con->reportscsiioctl; 
+  int report = scsi_debugmode;
 
   if (report > 0) {
         int k, j;
@@ -1050,23 +1046,14 @@ bool linux_megaraid_device::scsi_pass_through(scsi_cmnd_io *iop)
         pout("%s", buff);
   }
 
-  /* Controller rejects Enable SMART and Test Unit Ready */
+  // Controller rejects Test Unit Ready
   if (iop->cmnd[0] == 0x00)
     return true;
-  if (iop->cmnd[0] == 0x85 && iop->cmnd[1] == 0x06) {
-    if(report > 0)
-      pout("Rejecting SMART/ATA command to controller\n");
-    // Emulate SMART STATUS CHECK drive reply
-    // smartctl fail to work without this
-    if(iop->cmnd[2]==0x2c) {
-      iop->resp_sense_len=22; // copied from real response
-      iop->sensep[0]=0x72; // descriptor format
-      iop->sensep[7]=0x0e; // additional length
-      iop->sensep[8]=0x09; // description pointer
-      iop->sensep[17]=0x4f; // low cylinder GOOD smart status
-      iop->sensep[19]=0xc2; // high cylinder GOOD smart status
-    }
-    return true;
+
+  if (iop->cmnd[0] == 0xa1 || iop->cmnd[0] == 0x85) { // SAT_ATA_PASSTHROUGH_12/16
+    // Controller does not return ATA output registers in SAT sense data
+    if (iop->cmnd[2] & (1 << 5)) // chk_cond
+      return set_err(ENOSYS, "ATA return descriptor not supported by controller firmware");
   }
 
   if (pt_cmd == NULL)
@@ -1086,7 +1073,7 @@ bool linux_megaraid_device::megasas_cmd(int cdbLen, void *cdb,
   int rc;
 
   memset(&uio, 0, sizeof(uio));
-  pthru = (struct megasas_pthru_frame *)uio.frame.raw;
+  pthru = &uio.frame.pthru;
   pthru->cmd = MFI_CMD_PD_SCSI_IO;
   pthru->cmd_status = 0xFF;
   pthru->scsi_status = 0x0;
@@ -1095,17 +1082,21 @@ bool linux_megaraid_device::megasas_cmd(int cdbLen, void *cdb,
   pthru->cdb_len = cdbLen;
   pthru->timeout = 0;
   pthru->flags = MFI_FRAME_DIR_READ;
-  pthru->sge_count = 1;
-  pthru->data_xfer_len = dataLen;
-  pthru->sgl.sge32[0].phys_addr = (intptr_t)data;
-  pthru->sgl.sge32[0].length = (uint32_t)dataLen;
+  if (dataLen > 0) {
+    pthru->sge_count = 1;
+    pthru->data_xfer_len = dataLen;
+    pthru->sgl.sge32[0].phys_addr = (intptr_t)data;
+    pthru->sgl.sge32[0].length = (uint32_t)dataLen;
+  }
   memcpy(pthru->cdb, cdb, cdbLen);
 
   uio.host_no = m_hba;
-  uio.sge_count = 1;
-  uio.sgl_off = offsetof(struct megasas_pthru_frame, sgl);
-  uio.sgl[0].iov_base = data;
-  uio.sgl[0].iov_len = dataLen;
+  if (dataLen > 0) {
+    uio.sge_count = 1;
+    uio.sgl_off = offsetof(struct megasas_pthru_frame, sgl);
+    uio.sgl[0].iov_base = data;
+    uio.sgl[0].iov_len = dataLen;
+  }
 
   rc = 0;
   errno = 0;
@@ -1197,7 +1188,7 @@ linux_cciss_device::linux_cciss_device(smart_interface * intf,
 
 bool linux_cciss_device::scsi_pass_through(scsi_cmnd_io * iop)
 {
-  int status = cciss_io_interface(get_fd(), m_disknum, iop, con->reportscsiioctl);
+  int status = cciss_io_interface(get_fd(), m_disknum, iop, scsi_debugmode);
   if (status < 0)
       return set_err(-status);
   return true;
@@ -1216,7 +1207,8 @@ public:
   enum escalade_type_t {
     AMCC_3WARE_678K,
     AMCC_3WARE_678K_CHAR,
-    AMCC_3WARE_9000_CHAR
+    AMCC_3WARE_9000_CHAR,
+    AMCC_3WARE_9700_CHAR
   };
 
   linux_escalade_device(smart_interface * intf, const char * dev_name,
@@ -1244,7 +1236,8 @@ linux_escalade_device::linux_escalade_device(smart_interface * intf, const char
 #define MAJOR_STRING_LENGTH 3
 #define DEVICE_STRING_LENGTH 32
 #define NODE_STRING_LENGTH 16
-int setup_3ware_nodes(const char *nodename, const char *driver_name) {
+static int setup_3ware_nodes(const char *nodename, const char *driver_name)
+{
   int              tw_major      = 0;
   int              index         = 0;
   char             majorstring[MAJOR_STRING_LENGTH+1];
@@ -1389,12 +1382,17 @@ int setup_3ware_nodes(const char *nodename, const char *driver_name) {
 
 bool linux_escalade_device::open()
 {
-  if (m_escalade_type == AMCC_3WARE_9000_CHAR || m_escalade_type == AMCC_3WARE_678K_CHAR) {
+  if (m_escalade_type == AMCC_3WARE_9700_CHAR || m_escalade_type == AMCC_3WARE_9000_CHAR ||
+      m_escalade_type == AMCC_3WARE_678K_CHAR) {
     // the device nodes for these controllers are dynamically assigned,
     // so we need to check that they exist with the correct major
     // numbers and if not, create them
-    const char * node   = (m_escalade_type == AMCC_3WARE_9000_CHAR ? "twa"    : "twe"    );
-    const char * driver = (m_escalade_type == AMCC_3WARE_9000_CHAR ? "3w-9xxx": "3w-xxxx");
+    const char * node   = (m_escalade_type == AMCC_3WARE_9700_CHAR ? "twl"     :
+                           m_escalade_type == AMCC_3WARE_9000_CHAR ? "twa"     :
+                                                                     "twe"      );
+    const char * driver = (m_escalade_type == AMCC_3WARE_9700_CHAR ? "3w-sas"  :
+                           m_escalade_type == AMCC_3WARE_9000_CHAR ? "3w-9xxx" :
+                                                                     "3w-xxxx"  );
     if (setup_3ware_nodes(node, driver))
       return set_err((errno ? errno : ENXIO), "setup_3ware_nodes(\"%s\", \"%s\") failed", node, driver);
   }
@@ -1461,7 +1459,7 @@ bool linux_escalade_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out
   memset(ioctl_buffer, 0, TW_IOCTL_BUFFER_SIZE);
 
   // TODO: Handle controller differences by different classes
-  if (m_escalade_type==AMCC_3WARE_9000_CHAR) {
+  if (m_escalade_type == AMCC_3WARE_9700_CHAR || m_escalade_type == AMCC_3WARE_9000_CHAR) {
     tw_ioctl_apache                               = (TW_Ioctl_Buf_Apache *)ioctl_buffer;
     tw_ioctl_apache->driver_command.control_code  = TW_IOCTL_FIRMWARE_PASS_THROUGH;
     tw_ioctl_apache->driver_command.buffer_length = 512; /* payload size */
@@ -1523,7 +1521,8 @@ bool linux_escalade_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out
     // in dwords by 1 to account for the 64-bit single sgl 'address'
     // field. Note that this doesn't agree with the typedefs but it's
     // right (agree with kernel driver behavior/typedefs).
-    if (m_escalade_type==AMCC_3WARE_9000_CHAR && sizeof(long)==8)
+    if ((m_escalade_type == AMCC_3WARE_9700_CHAR || m_escalade_type == AMCC_3WARE_9000_CHAR)
+        && sizeof(long) == 8)
       passthru->size++;
   }
   else if (in.direction == ata_cmd_in::no_data) {
@@ -1535,7 +1534,7 @@ bool linux_escalade_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out
     passthru->sector_count = 0x0;
   }
   else if (in.direction == ata_cmd_in::data_out) {
-    if (m_escalade_type == AMCC_3WARE_9000_CHAR)
+    if (m_escalade_type == AMCC_3WARE_9700_CHAR || m_escalade_type == AMCC_3WARE_9000_CHAR)
       memcpy(tw_ioctl_apache->data_buffer, in.buffer, in.size);
     else if (m_escalade_type == AMCC_3WARE_678K_CHAR)
       memcpy(tw_ioctl_char->data_buffer,   in.buffer, in.size);
@@ -1548,7 +1547,8 @@ bool linux_escalade_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out
     passthru->byte0.sgloff = 0x5;
     passthru->size         = 0x7;  // TODO: Other value for multi-sector ?
     passthru->param        = 0xF;  // PIO data write
-    if (m_escalade_type==AMCC_3WARE_9000_CHAR && sizeof(long)==8)
+    if ((m_escalade_type == AMCC_3WARE_9700_CHAR || m_escalade_type == AMCC_3WARE_9000_CHAR)
+        && sizeof(long) == 8)
       passthru->size++;
   }
   else
@@ -1556,7 +1556,7 @@ bool linux_escalade_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out
 
   // Now send the command down through an ioctl()
   int ioctlreturn;
-  if (m_escalade_type==AMCC_3WARE_9000_CHAR)
+  if (m_escalade_type == AMCC_3WARE_9700_CHAR || m_escalade_type == AMCC_3WARE_9000_CHAR)
     ioctlreturn=ioctl(get_fd(), TW_IOCTL_FIRMWARE_PASS_THROUGH, tw_ioctl_apache);
   else if (m_escalade_type==AMCC_3WARE_678K_CHAR)
     ioctlreturn=ioctl(get_fd(), TW_CMD_PACKET_WITH_DATA, tw_ioctl_char);
@@ -1607,7 +1607,7 @@ bool linux_escalade_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out
 
   // If this is a read data command, copy data to output buffer
   if (readdata) {
-    if (m_escalade_type==AMCC_3WARE_9000_CHAR)
+    if (m_escalade_type == AMCC_3WARE_9700_CHAR || m_escalade_type == AMCC_3WARE_9000_CHAR)
       memcpy(in.buffer, tw_ioctl_apache->data_buffer, in.size);
     else if (m_escalade_type==AMCC_3WARE_678K_CHAR)
       memcpy(in.buffer, tw_ioctl_char->data_buffer, in.size);
@@ -1712,8 +1712,8 @@ typedef struct _SRB_BUFFER
 
 // Looks in /proc/scsi to suggest correct areca devices
 // If hint not NULL, return device path guess
-int find_areca_in_proc(char *hint) {
+static int find_areca_in_proc(char *hint)
+{
     const char* proc_format_string="host\tchan\tid\tlun\ttype\topens\tqdepth\tbusy\tonline\n";
 
     // check data formwat
@@ -1763,8 +1763,9 @@ int find_areca_in_proc(char *hint) {
 }
 
 
+#if 0 // For debugging areca code
 
-void dumpdata( unsigned char *block, int len)
+static void dumpdata(unsigned char *block, int len)
 {
        int ln = (len / 16) + 1;         // total line#
        unsigned char c;
@@ -1811,9 +1812,9 @@ void dumpdata( unsigned char *block, int len)
        printf("=====================================================================\n");
 }
 
+#endif
 
-
-int arcmsr_command_handler(int fd, unsigned long arcmsr_cmd, unsigned char *data, int data_len, void *ext_data /* reserved for further use */)
+static int arcmsr_command_handler(int fd, unsigned long arcmsr_cmd, unsigned char *data, int data_len, void *ext_data /* reserved for further use */)
 {
        ARGUSED(ext_data);
 
@@ -1935,14 +1936,14 @@ int arcmsr_command_handler(int fd, unsigned long arcmsr_cmd, unsigned char *data
        // Deal with the different error cases
        if ( ioctlreturn )
        {
-               printf("do_scsi_cmnd_io with write buffer failed code = %x\n", ioctlreturn);
+               pout("do_scsi_cmnd_io with write buffer failed code = %x\n", ioctlreturn);
                return -2;
        }
 
 
        if ( io_hdr.scsi_status )
        {
-               printf("io_hdr.scsi_status with write buffer failed code = %x\n", io_hdr.scsi_status);
+               pout("io_hdr.scsi_status with write buffer failed code = %x\n", io_hdr.scsi_status);
                return -3;
        }
 
@@ -2508,17 +2509,17 @@ int linux_highpoint_device::ata_command_interface(smart_command_set command, int
 
   if (command==WRITE_LOG) {
     unsigned char task[4*sizeof(int)+sizeof(ide_task_request_t)+512];
-    unsigned int *hpt = (unsigned int *)task;
+    unsigned int *hpt_tf = (unsigned int *)task;
     ide_task_request_t *reqtask = (ide_task_request_t *)(&task[4*sizeof(int)]);
     task_struct_t *taskfile = (task_struct_t *)reqtask->io_ports;
     int retval;
 
     memset(task, 0, sizeof(task));
 
-    hpt[0] = m_hpt_data[0]; // controller id
-    hpt[1] = m_hpt_data[1]; // channel number
-    hpt[3] = m_hpt_data[2]; // pmport number
-    hpt[2] = HDIO_DRIVE_TASKFILE; // real hd ioctl
+    hpt_tf[0] = m_hpt_data[0]; // controller id
+    hpt_tf[1] = m_hpt_data[1]; // channel number
+    hpt_tf[3] = m_hpt_data[2]; // pmport number
+    hpt_tf[2] = HDIO_DRIVE_TASKFILE; // real hd ioctl
 
     taskfile->data           = 0;
     taskfile->feature        = ATA_SMART_WRITE_LOG_SECTOR;
@@ -2585,13 +2586,13 @@ int linux_highpoint_device::ata_command_interface(smart_command_set command, int
 #if 1
   if (command==IDENTIFY || command==PIDENTIFY) {
     unsigned char deviceid[4*sizeof(int)+512*sizeof(char)];
-    unsigned int *hpt = (unsigned int *)deviceid;
+    unsigned int *hpt_id = (unsigned int *)deviceid;
 
-    hpt[0] = m_hpt_data[0]; // controller id
-    hpt[1] = m_hpt_data[1]; // channel number
-    hpt[3] = m_hpt_data[2]; // pmport number
+    hpt_id[0] = m_hpt_data[0]; // controller id
+    hpt_id[1] = m_hpt_data[1]; // channel number
+    hpt_id[3] = m_hpt_data[2]; // pmport number
 
-    hpt[2] = HDIO_GET_IDENTITY;
+    hpt_id[2] = HDIO_GET_IDENTITY;
     if (!ioctl(get_fd(), HPTIO_CTL, deviceid) && (deviceid[4*sizeof(int)] & 0x8000))
       buff[0]=(command==IDENTIFY)?ATA_IDENTIFY_PACKET_DEVICE:ATA_IDENTIFY_DEVICE;
   }
@@ -2695,7 +2696,7 @@ smart_device * linux_scsi_device::autodetect_open()
     if (!memcmp(req_buff + 8, "3ware", 5) || !memcmp(req_buff + 8, "AMCC", 4)) {
       close();
       set_err(EINVAL, "AMCC/3ware controller, please try adding '-d 3ware,N',\n"
-                      "you may need to replace %s with /dev/twaN or /dev/tweN", get_dev_name());
+                      "you may need to replace %s with /dev/twlN, /dev/twaN or /dev/tweN", get_dev_name());
       return this;
     }
 
@@ -2785,7 +2786,7 @@ static bool get_usb_id(const char * name, unsigned short & vendor_id,
         && read_id(dir + "/bcdDevice", version)   ))
     return false;
 
-  if (con->reportscsiioctl > 1)
+  if (scsi_debugmode > 1)
     pout("USB ID = 0x%04x:0x%04x (0x%03x)\n", vendor_id, product_id, version);
   return true;
 }
@@ -2798,6 +2799,8 @@ class linux_smart_interface
 : public /*implements*/ smart_interface
 {
 public:
+  virtual std::string get_os_version_str();
+
   virtual std::string get_app_examples(const char * appname);
 
   virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
@@ -2821,6 +2824,13 @@ private:
   smart_device * missing_option(const char * opt);
 };
 
+std::string linux_smart_interface::get_os_version_str()
+{
+  struct utsname u;
+  return strprintf("%s-%s", SMARTMONTOOLS_BUILD_HOST,
+    (!uname(&u) ? u.release : "?"));
+}
+
 std::string linux_smart_interface::get_app_examples(const char * appname)
 {
   if (!strcmp(appname, "smartctl"))
@@ -2981,76 +2991,71 @@ smart_device * linux_smart_interface::missing_option(const char * opt)
 }
 
 // Return true if STR starts with PREFIX.
-static bool str_starts_with(const char * str, const char * 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()
+{
+  struct utsname u;
+  if (uname(&u))
+    return 0;
+  unsigned x = 0, y = 0, z = 0;
+  if (!(sscanf(u.release, "%u.%u.%u", &x, &y, &z) == 3
+        && x < 100 && y < 100 && z < 1000             ))
+    return 0;
+  return x * 100000 + y * 1000 + z;
+}
+
 // Guess device type (ata or scsi) based on device name (Linux
 // specific) SCSI device name in linux can be sd, sr, scd, st, nst,
 // osst, nosst and sg.
-static const char * lin_dev_prefix = "/dev/";
-static const char * lin_dev_ata_disk_plus = "h";
-static const char * lin_dev_ata_devfs_disk_plus = "ide/";
-static const char * lin_dev_scsi_devfs_disk_plus = "scsi/";
-static const char * lin_dev_scsi_disk_plus = "s";
-static const char * lin_dev_scsi_tape1 = "ns";
-static const char * lin_dev_scsi_tape2 = "os";
-static const char * lin_dev_scsi_tape3 = "nos";
-static const char * lin_dev_3ware_9000_char = "twa";
-static const char * lin_dev_3ware_678k_char = "twe";
-static const char * lin_dev_cciss_dir = "cciss/";
-static const char * lin_dev_areca = "sg";
-
 smart_device * linux_smart_interface::autodetect_smart_device(const char * name)
 {
-  const char * dev_name = name; // TODO: Remove this hack
-  int dev_prefix_len = strlen(lin_dev_prefix);
+  const char * test_name = name;
 
-  // if dev_name null, or string length zero
-  int len;
-  if (!dev_name || !(len = strlen(dev_name)))
-    return 0;
-
-  // Dereference if /dev/disk/by-*/* symlink
-  char linkbuf[100];
-  if (   str_starts_with(dev_name, "/dev/disk/by-")
-      && readlink(dev_name, linkbuf, sizeof(linkbuf)) > 0
-      && str_starts_with(linkbuf, "../../")) {
-    dev_name = linkbuf + sizeof("../../")-1;
+  // Dereference symlinks
+  struct stat st;
+  std::string pathbuf;
+  if (!lstat(name, &st) && S_ISLNK(st.st_mode)) {
+    char * p = realpath(name, (char *)0);
+    if (p) {
+      pathbuf = p;
+      free(p);
+      test_name = pathbuf.c_str();
+    }
   }
+
   // Remove the leading /dev/... if it's there
-  else if (!strncmp(lin_dev_prefix, dev_name, dev_prefix_len)) {
-    if (len <= dev_prefix_len)
-      // if nothing else in the string, unrecognized
-      return 0;
-    // else advance pointer to following characters
-    dev_name += dev_prefix_len;
-  }
+  static const char dev_prefix[] = "/dev/";
+  if (str_starts_with(test_name, dev_prefix))
+    test_name += strlen(dev_prefix);
 
   // form /dev/h* or h*
-  if (!strncmp(lin_dev_ata_disk_plus, dev_name,
-               strlen(lin_dev_ata_disk_plus)))
+  if (str_starts_with(test_name, "h"))
     return new linux_ata_device(this, name, "");
 
   // form /dev/ide/* or ide/*
-  if (!strncmp(lin_dev_ata_devfs_disk_plus, dev_name,
-               strlen(lin_dev_ata_devfs_disk_plus)))
+  if (str_starts_with(test_name, "ide/"))
     return new linux_ata_device(this, name, "");
 
   // form /dev/s* or s*
-  if (!strncmp(lin_dev_scsi_disk_plus, dev_name,
-               strlen(lin_dev_scsi_disk_plus))) {
+  if (str_starts_with(test_name, "s")) {
 
     // Try to detect possible USB->(S)ATA bridge
     unsigned short vendor_id = 0, product_id = 0, version = 0;
-    if (get_usb_id(dev_name, vendor_id, product_id, version)) {
+    if (get_usb_id(test_name, vendor_id, product_id, version)) {
       const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id, version);
       if (!usbtype)
         return 0;
-      // Linux USB layer does not support 16 byte SAT pass through command
-      if (!strcmp(usbtype, "sat"))
+
+      // Kernels before 2.6.29 do not support the sense data length
+      // required for SAT ATA PASS-THROUGH(16)
+      if (!strcmp(usbtype, "sat") && get_kernel_release() < 206029)
         usbtype = "sat,12";
+
       // Return SAT/USB device for this type
       // (Note: linux_scsi_device::autodetect_open() will not be called in this case)
       return get_sat_device(usbtype, new linux_scsi_device(this, name, ""));
@@ -3061,45 +3066,29 @@ smart_device * linux_smart_interface::autodetect_smart_device(const char * name)
   }
 
   // form /dev/scsi/* or scsi/*
-  if (!strncmp(lin_dev_scsi_devfs_disk_plus, dev_name,
-               strlen(lin_dev_scsi_devfs_disk_plus)))
+  if (str_starts_with(test_name, "scsi/"))
     return new linux_scsi_device(this, name, "");
 
   // form /dev/ns* or ns*
-  if (!strncmp(lin_dev_scsi_tape1, dev_name,
-               strlen(lin_dev_scsi_tape1)))
+  if (str_starts_with(test_name, "ns"))
     return new linux_scsi_device(this, name, "");
 
   // form /dev/os* or os*
-  if (!strncmp(lin_dev_scsi_tape2, dev_name,
-               strlen(lin_dev_scsi_tape2)))
+  if (str_starts_with(test_name, "os"))
     return new linux_scsi_device(this, name, "");
 
   // form /dev/nos* or nos*
-  if (!strncmp(lin_dev_scsi_tape3, dev_name,
-               strlen(lin_dev_scsi_tape3)))
+  if (str_starts_with(test_name, "nos"))
     return new linux_scsi_device(this, name, "");
 
-  // form /dev/twa*
-  if (!strncmp(lin_dev_3ware_9000_char, dev_name,
-               strlen(lin_dev_3ware_9000_char)))
-    return missing_option("-d 3ware,N");
-
-  // form /dev/twe*
-  if (!strncmp(lin_dev_3ware_678k_char, dev_name,
-               strlen(lin_dev_3ware_678k_char)))
+  // form /dev/tw[ael]* or tw[ael]*
+  if (str_starts_with(test_name, "tw") && strchr("ael", test_name[2]))
     return missing_option("-d 3ware,N");
 
-  // form /dev/cciss*
-  if (!strncmp(lin_dev_cciss_dir, dev_name,
-               strlen(lin_dev_cciss_dir)))
+  // form /dev/cciss/* or cciss/*
+  if (str_starts_with(test_name, "cciss/"))
     return missing_option("-d cciss,N");
 
-  // form /dev/sg*
-  if ( !strncmp(lin_dev_areca, dev_name,
-                strlen(lin_dev_areca)) )
-    return missing_option("-d areca,N");
-
   // we failed to recognize any of the forms
   return 0;
 }
@@ -3122,7 +3111,9 @@ smart_device * linux_smart_interface::get_custom_smart_device(const char * name,
       return 0;
     }
 
-    if (!strncmp(name, "/dev/twa", 8))
+    if (!strncmp(name, "/dev/twl", 8))
+      return new linux_escalade_device(this, name, linux_escalade_device::AMCC_3WARE_9700_CHAR, disknum);
+    else if (!strncmp(name, "/dev/twa", 8))
       return new linux_escalade_device(this, name, linux_escalade_device::AMCC_3WARE_9000_CHAR, disknum);
     else if (!strncmp(name, "/dev/twe", 8))
       return new linux_escalade_device(this, name, linux_escalade_device::AMCC_3WARE_678K_CHAR, disknum);
index 5f41b6f7f6f9a2c01e7baf467d15d93a3d8aba21..09d4a7ef88d7a787d0c8252cbcb2c64424331cc3 100644 (file)
 #include "scsicmds.h"
 #include "utility.h"
 #include "os_netbsd.h"
+
+#include <errno.h>
 #include <unistd.h>
 
-const char *os_XXXX_c_cvsid = "$Id: os_netbsd.cpp,v 1.25 2008/06/12 21:46:31 ballen4705 Exp $" \
-ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_NETBSD_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
+const char * os_netbsd_cpp_cvsid = "$Id: os_netbsd.cpp 3265 2011-02-21 16:21:14Z chrfranke $"
+  OS_NETBSD_H_CVSID;
 
 /* global variable holding byte count of allocated memory */
 extern long long bytes;
index e0d572073d4b1209ad4050e622f296399f5dacc7..7acf85aa81a27a498a46b28d8cc43a2ca0e1ec4a 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2004-8 David Snyder <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2004-10 David Snyder <smartmontools-support@lists.sourceforge.net>
  *
  * Derived from os_netbsd.cpp by Sergey Svishchev <smartmontools-support@lists.sourceforge.net>, Copyright (C) 2003-8 
  *
 #include "utility.h"
 #include "os_openbsd.h"
 
-const char *os_XXXX_c_cvsid = "$Id: os_openbsd.cpp,v 1.17 2008/06/12 21:46:31 ballen4705 Exp $" \
-ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_OPENBSD_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
+#include <errno.h>
+
+const char * os_openbsd_cpp_cvsid = "$Id: os_openbsd.cpp 3265 2011-02-21 16:21:14Z chrfranke $"
+  OS_OPENBSD_H_CVSID;
 
 /* global variable holding byte count of allocated memory */
 extern long long bytes;
@@ -121,6 +123,9 @@ get_dev_names(char ***names, const char *prefix)
     if (strncmp(p, prefix, strlen(prefix))) {
       continue;
     }
+    char * u = strchr(p, ':');
+    if (u)
+      *u = 0;
     mp[n] = (char *)malloc(strlen(net_dev_prefix) + strlen(p) + 2);
     if (!mp[n]) {
       pout("Out of memory constructing scan device list\n");
index a17417002e9ed776b3257bb708a4e5686e4a469f..16f4e2e6b262c31a732943be34d26e6da993ab57 100644 (file)
@@ -31,7 +31,7 @@
 #include "os_os2.h"
 
 // Needed by '-V' option (CVS versioning) of smartd/smartctl
-const char *os_XXXX_c_cvsid="$Id: os_os2.cpp,v 1.9 2008/06/12 21:46:31 ballen4705 Exp $" \
+const char *os_XXXX_c_cvsid="$Id: os_os2.cpp 3191 2010-10-27 19:55:33Z chrfranke $" \
 ATACMDS_H_CVSID OS_XXXX_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
 
 // global handle to device driver
@@ -65,7 +65,6 @@ static void unsupported(int which){
 
   if (!warninggiven[which]) {
     char msg;
-    debugmode=1;
     warninggiven[which]=1;
 
     switch (which) {
index e9333810a781143449191659915171f90a9ea30f..7dbcafee96f4960b24fb1169ca9b5c7a4968159a 100644 (file)
@@ -18,7 +18,7 @@
 // should have one *_H_CVSID macro appearing below for each file
 // appearing with #include "*.h" above.  Please list these (below) in
 // alphabetic/dictionary order.
-const char *os_XXXX_c_cvsid="$Id: os_qnxnto.cpp 3110 2010-05-24 20:38:38Z chrfranke $" \
+const char *os_XXXX_c_cvsid="$Id: os_qnxnto.cpp 3191 2010-10-27 19:55:33Z chrfranke $" \
 ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_QNXNTO_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
 
 
@@ -48,8 +48,6 @@ static void unsupported(){
 
   if (!warninggiven) {
     char *osname;
-    extern unsigned char debugmode;
-    unsigned char savedebugmode=debugmode;
 
 #ifdef HAVE_UNAME
     struct utsname ostype;
@@ -59,14 +57,12 @@ static void unsupported(){
     osname="host's";
 #endif
 
-    debugmode=1;
     pout("\n"
          "############################################################################\n"
          "WARNING: smartmontools has not been ported to the %s Operating System.\n"
          "Please see the files os_generic.cpp and os_generic.h for porting instructions.\n"
          "############################################################################\n\n",
          osname);
-    debugmode=savedebugmode;
     warninggiven=1;
   }
 
index 579022460e0bf05a9101728e0b9572e747263453..1989af1de0854a451e965b368db28d34375dc045 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2004-10 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2004-11 Christian Franke <smartmontools-support@lists.sourceforge.net>
  *
  * 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
  */
 
 #include "config.h"
-#define _WIN32_WINNT 0x0510
+#define WINVER 0x0502
+#define _WIN32_WINNT WINVER
 
 #include "int64.h"
 #include "atacmds.h"
-#include "extern.h"
-extern smartmonctrl * con; // con->permissive,reportataioctl
 #include "scsicmds.h"
 #include "utility.h"
+#include "smartctl.h" // TODO: Do not use smartctl only variables here
 
 #include "dev_interface.h"
 #include "dev_ata_cmd_set.h"
 
+#include "os_win32/wmiquery.h"
+
 #include <errno.h>
 
 #ifdef _DEBUG
@@ -37,22 +39,36 @@ extern smartmonctrl * con; // con->permissive,reportataioctl
 #define assert(x) /* */
 #endif
 
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
 #include <stddef.h> // offsetof()
 #include <io.h> // access()
 
-// TODO: Add a configure test
-#if defined(__CYGWIN__) || (defined(__MINGW32__) && !defined(__MINGW64__))
+// WIN32_LEAN_AND_MEAN may be required to prevent inclusion of <winioctl.h>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#if HAVE_NTDDDISK_H
+// i686-w64-mingw32, x86_64-w64-mingw32
+// (Missing: FILE_DEVICE_SCSI)
+#include <devioctl.h>
+#include <ntdddisk.h>
+#include <ntddscsi.h>
+#include <ntddstor.h>
+#elif HAVE_DDK_NTDDDISK_H
+// i686-pc-cygwin, i686-pc-mingw32, i586-mingw32msvc
+// (Missing: IOCTL_IDE_PASS_THROUGH, IOCTL_ATA_PASS_THROUGH, FILE_DEVICE_SCSI)
 #include <ddk/ntdddisk.h>
 #include <ddk/ntddscsi.h>
 #include <ddk/ntddstor.h>
 #else
-// Win SDK, no DDK
-#include <winioctl.h>
+// MSVC8, older MinGW
+// (Missing: IOCTL_STORAGE_QUERY_PROPERTY, FILE_DEVICE_SCSI)
 #include <ntddscsi.h>
+#include <winioctl.h>
 #endif
 
+// CSMI support
+#include "csmisas.h"
+
 #ifdef __CYGWIN__
 #include <cygwin/version.h> // CYGWIN_VERSION_DLL_MAJOR
 #endif
@@ -69,7 +85,7 @@ extern smartmonctrl * con; // con->permissive,reportataioctl
 #define SELECT_WIN_32_64(x32, x64) (x64)
 #endif
 
-const char * os_win32_cpp_cvsid = "$Id: os_win32.cpp 3118 2010-06-08 17:30:46Z chrfranke $";
+const char * os_win32_cpp_cvsid = "$Id: os_win32.cpp 3292 2011-03-09 21:12:03Z chrfranke $";
 
 // Disable Win9x/ME specific code if no longer supported by compiler.
 #ifdef _WIN64
@@ -283,6 +299,14 @@ typedef struct _SENDCMDINPARAMS_EX {
 ASSERT_SIZEOF(GETVERSIONINPARAMS_EX, sizeof(GETVERSIONINPARAMS));
 ASSERT_SIZEOF(SENDCMDINPARAMS_EX, sizeof(SENDCMDINPARAMS));
 
+
+// CSMI structs
+
+ASSERT_SIZEOF(IOCTL_HEADER, sizeof(SRB_IO_CONTROL));
+ASSERT_SIZEOF(CSMI_SAS_DRIVER_INFO_BUFFER, 204);
+ASSERT_SIZEOF(CSMI_SAS_PHY_INFO_BUFFER, 2080);
+ASSERT_SIZEOF(CSMI_SAS_STP_PASSTHRU_BUFFER, 168);
+
 } // extern "C"
 
 /////////////////////////////////////////////////////////////////////////////
@@ -404,6 +428,82 @@ private:
 
 #endif // WIN9X_SUPPORT
 
+
+//////////////////////////////////////////////////////////////////////
+
+class csmi_device
+: virtual public /*extends*/ smart_device
+{
+public:
+  /// Get phy info
+  bool get_phy_info(CSMI_SAS_PHY_INFO & phy_info);
+
+  /// Check physical drive existence
+  bool check_phy(const CSMI_SAS_PHY_INFO & phy_info, unsigned phy_no);
+
+protected:
+  csmi_device()
+    : smart_device(never_called)
+    { memset(&m_phy_ent, 0, sizeof(m_phy_ent)); }
+
+  /// Select physical drive
+  bool select_phy(unsigned phy_no);
+
+  /// Get info for selected physical drive
+  const CSMI_SAS_PHY_ENTITY & get_phy_ent() const
+    { return m_phy_ent; }
+
+  /// Call platform-specific CSMI ioctl
+  virtual bool csmi_ioctl(unsigned code, IOCTL_HEADER * csmi_buffer,
+    unsigned csmi_bufsiz) = 0;
+
+private:
+  CSMI_SAS_PHY_ENTITY m_phy_ent; ///< CSMI info for this phy
+};
+
+
+class csmi_ata_device
+: virtual public /*extends*/ csmi_device,
+  virtual public /*implements*/ ata_device
+{
+public:
+  virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
+
+protected:
+  csmi_ata_device()
+    : smart_device(never_called) { }
+};
+
+
+//////////////////////////////////////////////////////////////////////
+
+class win_csmi_device
+: public /*implements*/ csmi_ata_device
+{
+public:
+  win_csmi_device(smart_interface * intf, const char * dev_name,
+    const char * req_type);
+
+  virtual ~win_csmi_device() throw();
+
+  virtual bool open();
+
+  virtual bool close();
+
+  virtual bool is_open() const;
+
+  bool open_scsi();
+
+protected:
+  virtual bool csmi_ioctl(unsigned code, IOCTL_HEADER * csmi_buffer,
+    unsigned csmi_bufsiz);
+
+private:
+  HANDLE m_fh; ///< Controller device handle
+  unsigned m_phy_no; ///< Physical drive number
+};
+
+
 //////////////////////////////////////////////////////////////////////
 
 class win_tw_cli_device
@@ -440,8 +540,8 @@ public:
 
   virtual std::string get_app_examples(const char * appname);
 
-  virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
-    const char * pattern = 0);
+//virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
+//  const char * pattern = 0);
 
 protected:
   virtual ata_device * get_ata_device(const char * name, const char * type);
@@ -449,10 +549,6 @@ protected:
 //virtual scsi_device * get_scsi_device(const char * name, const char * type);
 
   virtual smart_device * autodetect_smart_device(const char * name);
-
-  virtual bool ata_scan(smart_device_list & devlist) = 0;
-
-  virtual bool scsi_scan(smart_device_list & devlist) = 0;
 };
 
 #if WIN9X_SUPPORT
@@ -465,12 +561,16 @@ public:
   win9x_smart_interface()
     { win9x = true; }
 
+  virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
+    const char * pattern = 0);
+
 protected:
   virtual scsi_device * get_scsi_device(const char * name, const char * type);
 
-  virtual bool ata_scan(smart_device_list & devlist);
+private:
+  bool ata_scan(smart_device_list & devlist);
 
-  virtual bool scsi_scan(smart_device_list & devlist);
+  bool scsi_scan(smart_device_list & devlist);
 };
 
 #endif // WIN9X_SUPPORT
@@ -479,14 +579,14 @@ protected:
 class winnt_smart_interface
 : public /*extends*/ win_smart_interface
 {
+public:
+  virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
+    const char * pattern = 0);
+
 protected:
   virtual scsi_device * get_scsi_device(const char * name, const char * type);
 
   virtual smart_device * autodetect_smart_device(const char * name);
-
-  virtual bool ata_scan(smart_device_list & devlist);
-
-  virtual bool scsi_scan(smart_device_list & devlist);
 };
 
 
@@ -496,11 +596,9 @@ protected:
 // Running on 64-bit Windows as 32-bit app ?
 static bool is_wow64()
 {
-  HMODULE hk = GetModuleHandleA("kernel32");
-  if (!hk)
-    return false;
   BOOL (WINAPI * IsWow64Process_p)(HANDLE, PBOOL) =
-    (BOOL (WINAPI *)(HANDLE, PBOOL))GetProcAddress(hk, "IsWow64Process");
+    (BOOL (WINAPI *)(HANDLE, PBOOL))
+    GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
   if (!IsWow64Process_p)
     return false;
   BOOL w64 = FALSE;
@@ -582,6 +680,7 @@ std::string win_smart_interface::get_os_version_str()
 enum win_dev_type { DEV_UNKNOWN = 0, DEV_ATA, DEV_SCSI, DEV_USB };
 
 static win_dev_type get_phy_drive_type(int drive);
+static win_dev_type get_phy_drive_type(int drive, GETVERSIONINPARAMS_EX * ata_version_ex);
 static win_dev_type get_log_drive_type(int drive);
 static bool get_usb_id(int drive, unsigned short & vendor_id,
                        unsigned short & product_id);
@@ -591,11 +690,11 @@ static const char * ata_get_def_options(void);
 
 static int is_permissive()
 {
-  if (!con->permissive) {
+  if (!failuretest_permissive) {
     pout("To continue, add one or more '-T permissive' options.\n");
     return 0;
   }
-  con->permissive--;
+  failuretest_permissive--;
   return 1;
 }
 
@@ -620,6 +719,8 @@ static const char * skipdev(const char * s)
 ata_device * win_smart_interface::get_ata_device(const char * name, const char * type)
 {
   const char * testname = skipdev(name);
+  if (!strncmp(testname, "csmi", 4))
+    return new win_csmi_device(this, name, type);
   if (!strncmp(testname, "tw_cli", 6))
     return new win_tw_cli_device(this, name, type);
   return new win_ata_device(this, name, type);
@@ -695,6 +796,9 @@ smart_device * winnt_smart_interface::autodetect_smart_device(const char * name)
   if (dev)
     return dev;
 
+  if (!strncmp(skipdev(name), "csmi", 4))
+    return new win_csmi_device(this, name, "");
+
   int phydrive = -1;
   win_dev_type type = get_dev_type(name, phydrive);
 
@@ -722,8 +826,11 @@ smart_device * winnt_smart_interface::autodetect_smart_device(const char * name)
 }
 
 
-// makes a list of ATA or SCSI devices for the DEVICESCAN directive
-bool win_smart_interface::scan_smart_devices(smart_device_list & devlist,
+#if WIN9X_SUPPORT
+
+// Scan for devices on Win9x/ME
+
+bool win9x_smart_interface::scan_smart_devices(smart_device_list & devlist,
   const char * type, const char * pattern /* = 0*/)
 {
   if (pattern) {
@@ -743,6 +850,132 @@ bool win_smart_interface::scan_smart_devices(smart_device_list & devlist,
   return true;
 }
 
+#endif  // WIN9X_SUPPORT
+
+
+// Scan for devices
+
+bool winnt_smart_interface::scan_smart_devices(smart_device_list & devlist,
+  const char * type, const char * pattern /* = 0*/)
+{
+  if (pattern) {
+    set_err(EINVAL, "DEVICESCAN with pattern not implemented yet");
+    return false;
+  }
+
+  // Set valid types
+  bool ata, scsi, usb, csmi;
+  if (!type) {
+    ata = scsi = usb = csmi = true;
+  }
+  else {
+    ata = scsi = usb = csmi = false;
+    if (!strcmp(type, "ata"))
+      ata = true;
+    else if (!strcmp(type, "scsi"))
+      scsi = true;
+    else if (!strcmp(type, "usb"))
+      usb = true;
+    else if (!strcmp(type, "csmi"))
+      csmi = true;
+    else {
+      set_err(EINVAL, "Invalid type '%s', valid arguments are: ata, scsi, usb, csmi", type);
+      return false;
+    }
+  }
+
+  // Scan up to 10 drives and 2 3ware controllers
+  const int max_raid = 2;
+  bool raid_seen[max_raid] = {false, false};
+
+  char name[20];
+  for (int i = 0; i <= 9; i++) {
+    sprintf(name, "/dev/sd%c", 'a'+i);
+    GETVERSIONINPARAMS_EX vers_ex;
+
+    switch (get_phy_drive_type(i, (ata ? &vers_ex : 0))) {
+      case DEV_ATA:
+        // Driver supports SMART_GET_VERSION or STORAGE_QUERY_PROPERTY returned ATA/SATA
+        if (!ata)
+          continue;
+
+        // Interpret RAID drive map if present
+        if (vers_ex.wIdentifier == SMART_VENDOR_3WARE) {
+          // Skip if too many controllers or logical drive from this controller already seen
+          if (!(vers_ex.wControllerId < max_raid && !raid_seen[vers_ex.wControllerId]))
+            continue;
+          raid_seen[vers_ex.wControllerId] = true;
+          // Add physical drives
+          int len = strlen(name);
+          for (int pi = 0; pi < 32; pi++) {
+            if (vers_ex.dwDeviceMapEx & (1L << pi)) {
+              sprintf(name+len, ",%u", pi);
+              devlist.push_back( new win_ata_device(this, name, "ata") );
+            }
+          }
+        }
+        else {
+          devlist.push_back( new win_ata_device(this, name, "ata") );
+        }
+        break;
+
+      case DEV_SCSI:
+        // STORAGE_QUERY_PROPERTY returned SCSI/SAS/...
+        if (!scsi)
+          continue;
+        devlist.push_back( new win_scsi_device(this, name, "scsi") );
+        break;
+
+      case DEV_USB:
+        // STORAGE_QUERY_PROPERTY returned USB
+        if (!usb)
+          continue;
+        {
+          // TODO: Use common function for this and autodetect_smart_device()
+          // Get USB bridge ID
+          unsigned short vendor_id = 0, product_id = 0;
+          if (!get_usb_id(i, vendor_id, product_id))
+            continue;
+          // Get type name for this ID
+          const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id);
+          if (!usbtype)
+            continue;
+          // Return SAT/USB device for this type
+          ata_device * dev = get_sat_device(usbtype, new win_scsi_device(this, name, ""));
+          if (!dev)
+            continue;
+          devlist.push_back(dev);
+        }
+        break;
+
+      default:
+        // Unknown type
+        break;
+    }
+  }
+
+  if (csmi) {
+    // Scan CSMI devices
+    for (int i = 0; i <= 9; i++) {
+      snprintf(name, sizeof(name)-1, "/dev/csmi%d,0", i);
+      win_csmi_device test_dev(this, name, "");
+      if (!test_dev.open_scsi())
+        continue;
+      CSMI_SAS_PHY_INFO phy_info;
+      if (!test_dev.get_phy_info(phy_info))
+        continue;
+
+      for (int pi = 0; pi < phy_info.bNumberOfPhys; pi++) {
+        if (!test_dev.check_phy(phy_info, pi))
+          continue;
+        snprintf(name, sizeof(name)-1, "/dev/csmi%d,%d", i, pi);
+        devlist.push_back( new win_csmi_device(this, name, "ata") );
+      }
+    }
+  }
+  return true;
+}
+
 
 // get examples for smartctl
 std::string win_smart_interface::get_app_examples(const char * appname)
@@ -816,14 +1049,14 @@ static int smart_get_version(HANDLE hdevice, GETVERSIONINPARAMS_EX * ata_version
 
   if (!DeviceIoControl(hdevice, SMART_GET_VERSION,
     NULL, 0, &vers, sizeof(vers), &num_out, NULL)) {
-    if (con->reportataioctl)
+    if (ata_debugmode)
       pout("  SMART_GET_VERSION failed, Error=%ld\n", GetLastError());
     errno = ENOSYS;
     return -1;
   }
   assert(num_out == sizeof(GETVERSIONINPARAMS));
 
-  if (con->reportataioctl > 1) {
+  if (ata_debugmode > 1) {
     pout("  SMART_GET_VERSION suceeded, bytes returned: %lu\n"
          "    Vers = %d.%d, Caps = 0x%lx, DeviceMap = 0x%02x\n",
       num_out, vers.bVersion, vers.bRevision,
@@ -889,7 +1122,7 @@ static int smart_ioctl(HANDLE hdevice, int drive, IDEREGS * regs, char * data, u
     outbuf, sizeof(SENDCMDOUTPARAMS)-1 + size_out, &num_out, NULL)) {
     // CAUTION: DO NOT change "regs" Parameter in this case, see ata_command_interface()
     long err = GetLastError();
-    if (con->reportataioctl && (err != ERROR_INVALID_PARAMETER || con->reportataioctl > 1)) {
+    if (ata_debugmode && (err != ERROR_INVALID_PARAMETER || ata_debugmode > 1)) {
       pout("  %s failed, Error=%ld\n", name, err);
       print_ide_regs_io(regs, NULL);
     }
@@ -903,7 +1136,7 @@ static int smart_ioctl(HANDLE hdevice, int drive, IDEREGS * regs, char * data, u
   outpar = (const SENDCMDOUTPARAMS *)outbuf;
 
   if (outpar->DriverStatus.bDriverError) {
-    if (con->reportataioctl) {
+    if (ata_debugmode) {
       pout("  %s failed, DriverError=0x%02x, IDEError=0x%02x\n", name,
         outpar->DriverStatus.bDriverError, outpar->DriverStatus.bIDEError);
       print_ide_regs_io(regs, NULL);
@@ -912,7 +1145,7 @@ static int smart_ioctl(HANDLE hdevice, int drive, IDEREGS * regs, char * data, u
     return -1;
   }
 
-  if (con->reportataioctl > 1) {
+  if (ata_debugmode > 1) {
     pout("  %s suceeded, bytes returned: %lu (buffer %lu)\n", name,
       num_out, outpar->cBufferSize);
     print_ide_regs_io(regs, (regs->bFeaturesReg == ATA_SMART_STATUS ?
@@ -923,9 +1156,9 @@ static int smart_ioctl(HANDLE hdevice, int drive, IDEREGS * regs, char * data, u
     memcpy(data, outpar->bBuffer, 512);
   else if (regs->bFeaturesReg == ATA_SMART_STATUS) {
     if (nonempty(outpar->bBuffer, sizeof(IDEREGS)))
-      *regs = *(const IDEREGS *)(outpar->bBuffer);
+      memcpy(regs, outpar->bBuffer, sizeof(IDEREGS));
     else {  // Workaround for driver not returning regs
-      if (con->reportataioctl)
+      if (ata_debugmode)
         pout("  WARNING: driver does not return ATA registers in output buffer!\n");
       *regs = inpar.irDriveRegs;
     }
@@ -965,7 +1198,7 @@ static int ide_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, u
   if (!DeviceIoControl(hdevice, IOCTL_IDE_PASS_THROUGH,
     buf, size, buf, size, &num_out, NULL)) {
     long err = GetLastError();
-    if (con->reportataioctl) {
+    if (ata_debugmode) {
       pout("  IOCTL_IDE_PASS_THROUGH failed, Error=%ld\n", err);
       print_ide_regs_io(regs, NULL);
     }
@@ -976,7 +1209,7 @@ static int ide_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, u
 
   // Check ATA status
   if (buf->IdeReg.bCommandReg/*Status*/ & 0x01) {
-    if (con->reportataioctl) {
+    if (ata_debugmode) {
       pout("  IOCTL_IDE_PASS_THROUGH command failed:\n");
       print_ide_regs_io(regs, &buf->IdeReg);
     }
@@ -989,7 +1222,7 @@ static int ide_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, u
   if (datasize) {
     if (   num_out != size
         || (buf->DataBuffer[0] == magic && !nonempty(buf->DataBuffer+1, datasize-1))) {
-      if (con->reportataioctl) {
+      if (ata_debugmode) {
         pout("  IOCTL_IDE_PASS_THROUGH output data missing (%lu, %lu)\n",
           num_out, buf->DataBufferSize);
         print_ide_regs_io(regs, &buf->IdeReg);
@@ -1001,7 +1234,7 @@ static int ide_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, u
     memcpy(data, buf->DataBuffer, datasize);
   }
 
-  if (con->reportataioctl > 1) {
+  if (ata_debugmode > 1) {
     pout("  IOCTL_IDE_PASS_THROUGH suceeded, bytes returned: %lu (buffer %lu)\n",
       num_out, buf->DataBufferSize);
     print_ide_regs_io(regs, &buf->IdeReg);
@@ -1086,7 +1319,7 @@ static int ata_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, IDEREGS * prev
   if (!DeviceIoControl(hdevice, IOCTL_ATA_PASS_THROUGH,
     &ab, size, &ab, size, &num_out, NULL)) {
     long err = GetLastError();
-    if (con->reportataioctl) {
+    if (ata_debugmode) {
       pout("  IOCTL_ATA_PASS_THROUGH failed, Error=%ld\n", err);
       print_ide_regs_io(regs, NULL);
     }
@@ -1096,7 +1329,7 @@ static int ata_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, IDEREGS * prev
 
   // Check ATA status
   if (ctfregs->bCommandReg/*Status*/ & (0x01/*Err*/|0x08/*DRQ*/)) {
-    if (con->reportataioctl) {
+    if (ata_debugmode) {
       pout("  IOCTL_ATA_PASS_THROUGH command failed:\n");
       print_ide_regs_io(regs, ctfregs);
     }
@@ -1108,7 +1341,7 @@ static int ata_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, IDEREGS * prev
   if (datasize > 0) {
     if (   num_out != size
         || (ab.ucDataBuf[0] == magic && !nonempty(ab.ucDataBuf+1, datasize-1))) {
-      if (con->reportataioctl) {
+      if (ata_debugmode) {
         pout("  IOCTL_ATA_PASS_THROUGH output data missing (%lu)\n", num_out);
         print_ide_regs_io(regs, ctfregs);
       }
@@ -1118,7 +1351,7 @@ static int ata_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, IDEREGS * prev
     memcpy(data, ab.ucDataBuf, datasize);
   }
 
-  if (con->reportataioctl > 1) {
+  if (ata_debugmode > 1) {
     pout("  IOCTL_ATA_PASS_THROUGH suceeded, bytes returned: %lu\n", num_out);
     print_ide_regs_io(regs, ctfregs);
   }
@@ -1185,7 +1418,7 @@ static int ata_via_scsi_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char
   if (!DeviceIoControl(hdevice, IOCTL_SCSI_PASS_THROUGH,
     &sb, size, &sb, size, &num_out, NULL)) {
     long err = GetLastError();
-    if (con->reportataioctl)
+    if (ata_debugmode)
       pout("  ATA via IOCTL_SCSI_PASS_THROUGH failed, Error=%ld\n", err);
     errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
     return -1;
@@ -1197,7 +1430,7 @@ static int ata_via_scsi_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char
   if (datasize) {
     if (   num_out != size
         || (sb.ucDataBuf[0] == magic && !nonempty(sb.ucDataBuf+1, datasize-1))) {
-      if (con->reportataioctl) {
+      if (ata_debugmode) {
         pout("  ATA via IOCTL_SCSI_PASS_THROUGH output data missing (%lu)\n", num_out);
         print_ide_regs_io(regs, NULL);
       }
@@ -1207,7 +1440,7 @@ static int ata_via_scsi_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char
     memcpy(data, sb.ucDataBuf, datasize);
   }
 
-  if (con->reportataioctl > 1) {
+  if (ata_debugmode > 1) {
     pout("  ATA via IOCTL_SCSI_PASS_THROUGH suceeded, bytes returned: %lu\n", num_out);
     print_ide_regs_io(regs, NULL);
   }
@@ -1306,7 +1539,7 @@ static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice, IDEREGS * regs, cha
   if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
     &sb, size, &sb, size, &num_out, NULL)) {
     long err = GetLastError();
-    if (con->reportataioctl) {
+    if (ata_debugmode) {
       pout("  IOCTL_SCSI_MINIPORT_%s failed, Error=%ld\n", name, err);
       print_ide_regs_io(regs, NULL);
     }
@@ -1316,7 +1549,7 @@ static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice, IDEREGS * regs, cha
 
   // Check result
   if (sb.srbc.ReturnCode) {
-    if (con->reportataioctl) {
+    if (ata_debugmode) {
       pout("  IOCTL_SCSI_MINIPORT_%s failed, ReturnCode=0x%08lx\n", name, sb.srbc.ReturnCode);
       print_ide_regs_io(regs, NULL);
     }
@@ -1325,7 +1558,7 @@ static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice, IDEREGS * regs, cha
   }
 
   if (sb.params.out.DriverStatus.bDriverError) {
-    if (con->reportataioctl) {
+    if (ata_debugmode) {
       pout("  IOCTL_SCSI_MINIPORT_%s failed, DriverError=0x%02x, IDEError=0x%02x\n", name,
         sb.params.out.DriverStatus.bDriverError, sb.params.out.DriverStatus.bIDEError);
       print_ide_regs_io(regs, NULL);
@@ -1334,7 +1567,7 @@ static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice, IDEREGS * regs, cha
     return -1;
   }
 
-  if (con->reportataioctl > 1) {
+  if (ata_debugmode > 1) {
     pout("  IOCTL_SCSI_MINIPORT_%s suceeded, bytes returned: %lu (buffer %lu)\n", name,
       num_out, sb.params.out.cBufferSize);
     print_ide_regs_io(regs, (code == IOCTL_SCSI_MINIPORT_RETURN_STATUS ?
@@ -1344,7 +1577,7 @@ static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice, IDEREGS * regs, cha
   if (datasize > 0)
     memcpy(data, sb.params.out.bBuffer, datasize);
   else if (datasize == 0 && code == IOCTL_SCSI_MINIPORT_RETURN_STATUS)
-    *regs = *(const IDEREGS *)(sb.params.out.bBuffer);
+    memcpy(regs, sb.params.out.bBuffer, sizeof(IDEREGS));
 
   return 0;
 }
@@ -1381,7 +1614,7 @@ static int ata_via_3ware_miniport_ioctl(HANDLE hdevice, IDEREGS * regs, char * d
   if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
     &sb, sizeof(sb), &sb, sizeof(sb), &num_out, NULL)) {
     long err = GetLastError();
-    if (con->reportataioctl) {
+    if (ata_debugmode) {
       pout("  ATA via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err);
       print_ide_regs_io(regs, NULL);
     }
@@ -1390,7 +1623,7 @@ static int ata_via_3ware_miniport_ioctl(HANDLE hdevice, IDEREGS * regs, char * d
   }
 
   if (sb.srbc.ReturnCode) {
-    if (con->reportataioctl) {
+    if (ata_debugmode) {
       pout("  ATA via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08lx\n", sb.srbc.ReturnCode);
       print_ide_regs_io(regs, NULL);
     }
@@ -1402,7 +1635,7 @@ static int ata_via_3ware_miniport_ioctl(HANDLE hdevice, IDEREGS * regs, char * d
   if (datasize > 0)
     memcpy(data, sb.buffer, datasize);
 
-  if (con->reportataioctl > 1) {
+  if (ata_debugmode > 1) {
     pout("  ATA via IOCTL_SCSI_MINIPORT suceeded, bytes returned: %lu\n", num_out);
     print_ide_regs_io(regs, &sb.regs);
   }
@@ -1432,18 +1665,18 @@ static int update_3ware_devicemap_ioctl(HANDLE hdevice)
   if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
     &srbc, sizeof(srbc), &srbc, sizeof(srbc), &num_out, NULL)) {
     long err = GetLastError();
-    if (con->reportataioctl)
+    if (ata_debugmode)
       pout("  UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err);
     errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
     return -1;
   }
   if (srbc.ReturnCode) {
-    if (con->reportataioctl)
+    if (ata_debugmode)
       pout("  UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08lx\n", srbc.ReturnCode);
     errno = EIO;
     return -1;
   }
-  if (con->reportataioctl > 1)
+  if (ata_debugmode > 1)
     pout("  UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT suceeded\n");
   return 0;
 }
@@ -1588,7 +1821,7 @@ bool win_tw_cli_device::open()
     // tw_cli/cx/py => read output from "tw_cli /cx/py show all"
     char cmd[100];
     snprintf(cmd, sizeof(cmd), "tw_cli /%s show all", name+n1);
-    if (con->reportataioctl > 1)
+    if (ata_debugmode > 1)
       pout("%s: Run: \"%s\"\n", name, cmd);
     size = run_cmd(cmd, buffer, sizeof(buffer));
   }
@@ -1596,7 +1829,7 @@ bool win_tw_cli_device::open()
     return set_err(EINVAL);
   }
 
-  if (con->reportataioctl > 1)
+  if (ata_debugmode > 1)
     pout("%s: Read %d bytes\n", name, size);
   if (size <= 0)
     return set_err(ENOENT);
@@ -1604,7 +1837,7 @@ bool win_tw_cli_device::open()
     return set_err(EIO);
 
   buffer[size] = 0;
-  if (con->reportataioctl > 1)
+  if (ata_debugmode > 1)
     pout("[\n%.100s%s\n]\n", buffer, (size>100?"...":""));
 
   // Fake identify sector
@@ -1727,13 +1960,13 @@ static int storage_query_property_ioctl(HANDLE hdevice, STORAGE_DEVICE_DESCRIPTO
   DWORD num_out;
   if (!DeviceIoControl(hdevice, IOCTL_STORAGE_QUERY_PROPERTY,
     &query, sizeof(query), data, sizeof(*data), &num_out, NULL)) {
-    if (con->reportataioctl > 1 || con->reportscsiioctl > 1)
+    if (ata_debugmode > 1 || scsi_debugmode > 1)
       pout("  IOCTL_STORAGE_QUERY_PROPERTY failed, Error=%ld\n", GetLastError());
     errno = ENOSYS;
     return -1;
   }
 
-  if (con->reportataioctl > 1 || con->reportscsiioctl > 1) {
+  if (ata_debugmode > 1 || scsi_debugmode > 1) {
     pout("  IOCTL_STORAGE_QUERY_PROPERTY returns:\n"
          "    Vendor:   \"%s\"\n"
          "    Product:  \"%s\"\n"
@@ -1765,13 +1998,13 @@ static int storage_predict_failure_ioctl(HANDLE hdevice, char * data = 0)
   DWORD num_out;
   if (!DeviceIoControl(hdevice, IOCTL_STORAGE_PREDICT_FAILURE,
     0, 0, &pred, sizeof(pred), &num_out, NULL)) {
-    if (con->reportataioctl > 1)
+    if (ata_debugmode > 1)
       pout("  IOCTL_STORAGE_PREDICT_FAILURE failed, Error=%ld\n", GetLastError());
     errno = ENOSYS;
     return -1;
   }
 
-  if (con->reportataioctl > 1) {
+  if (ata_debugmode > 1) {
     pout("  IOCTL_STORAGE_PREDICT_FAILURE returns:\n"
          "    PredictFailure: 0x%08lx\n"
          "    VendorSpecific: 0x%02x,0x%02x,0x%02x,...,0x%02x\n",
@@ -1802,15 +2035,15 @@ static win_dev_type get_controller_type(HANDLE hdevice, bool admin, GETVERSIONIN
     return DEV_UNKNOWN;
 
   // Newer BusType* values are missing in older includes
-  switch (data.desc.BusType) {
+  switch ((int)data.desc.BusType) {
     case BusTypeAta:
-    case (STORAGE_BUS_TYPE)0x0b: // BusTypeSata
+    case 0x0b: // BusTypeSata
       if (ata_version_ex)
         memset(ata_version_ex, 0, sizeof(*ata_version_ex));
       return DEV_ATA;
     case BusTypeScsi:
-    case (STORAGE_BUS_TYPE)0x09: // BusTypeiScsi
-    case (STORAGE_BUS_TYPE)0x0a: // BusTypeSas
+    case 0x09: // BusTypeiScsi
+    case 0x0a: // BusTypeSas
       return DEV_SCSI;
     case BusTypeUsb:
       return DEV_USB;
@@ -1833,7 +2066,7 @@ static win_dev_type get_controller_type(const char * path, GETVERSIONINPARAMS_EX
     if (h == INVALID_HANDLE_VALUE)
       return DEV_UNKNOWN;
   }
-  if (con->reportataioctl > 1 || con->reportscsiioctl > 1)
+  if (ata_debugmode > 1 || scsi_debugmode > 1)
     pout(" %s: successfully opened%s\n", path, (!admin ? " (without admin rights)" :""));
   win_dev_type type = get_controller_type(h, admin, ata_version_ex);
   CloseHandle(h);
@@ -1904,129 +2137,121 @@ static int get_identify_from_device_property(HANDLE hdevice, ata_identify_device
 /////////////////////////////////////////////////////////////////////////////
 // USB ID detection using WMI
 
-// Run a command, split stdout into lines.
-// Return number of lines read, -1 on error.
-static int run_cmd(std::vector<std::string> & lines, const char * cmd, ...)
-{
-  lines.clear();
-
-  va_list ap; va_start(ap, cmd);
-  std::string cmdline = vstrprintf(cmd, ap);
-  va_end(ap);
-
-  if (con->reportscsiioctl > 1)
-    pout("Run: \"%s\"\n", cmdline.c_str());
-
-  char buffer[16*1024];
-  int size = run_cmd(cmdline.c_str(), buffer, sizeof(buffer));
-
-  if (con->reportscsiioctl > 1)
-    pout("Read %d bytes\n", size);
-  if (!(0 < size && size < (int)sizeof(buffer)-1))
-    return -1;
-
-  buffer[size] = 0;
-
-  for (int i = 0; buffer[i]; ) {
-      int len = strcspn(buffer+i, "\r\n");
-      lines.push_back(std::string(buffer+i, len));
-      i += len;
-      i += strspn(buffer+i, "\r\n");
-  }
-  if (con->reportscsiioctl > 1) {
-    for (unsigned i = 0; i < lines.size(); i++)
-      printf("'%s'\n", lines[i].c_str());
-  }
-  return lines.size();
-}
-
-// Quote string for WMI
-static std::string wmi_quote(const char * s, int len)
+// Return true if STR starts with PREFIX.
+static inline bool str_starts_with(const std::string & str, const char * prefix)
 {
-  std::string r;
-  for (int i = 0; i < len; i++) {
-    char c = s[i];
-    if (c == '\\')
-      r += '\\';
-    r += c;
-  }
-  return r;
+  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)
 {
+  bool debug = (scsi_debugmode > 1);
+
+  wbem_services ws;
+  if (!ws.connect()) {
+    if (debug)
+      pout("WMI connect failed\n");
+    return false;
+  }
+
   // Get device name
-  std::vector<std::string> result;
-  if (run_cmd(result,
-        "wmic PATH Win32_DiskDrive WHERE DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\" GET Model",
-        drive) != 2)
+  wbem_object wo;
+  if (!ws.query1(wo, "SELECT Model FROM Win32_DiskDrive WHERE DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", drive))
     return false;
 
-  std::string name = result[1];
+  std::string name = wo.get_str("Model");
+  if (debug)
+    pout("PhysicalDrive%d, \"%s\":\n", drive, name.c_str());
 
   // Get USB_CONTROLLER -> DEVICE associations
-  std::vector<std::string> assoc;
-  int n = run_cmd(assoc, "wmic PATH Win32_USBControllerDevice GET Antecedent,Dependent");
-  if (n < 2)
+  wbem_enumerator we;
+  if (!ws.query(we, "SELECT Antecedent,Dependent FROM Win32_USBControllerDevice"))
     return false;
 
-  regular_expression regex("^([^ ]+) .*Win32_PnPEntity.DeviceID=\"(USBSTOR\\\\[^\"]*)\" *$",
-                           REG_EXTENDED);
-  if (regex.empty()) // TODO: throw in constructor?
-    return false;
+  std::string usb_devid;
+  std::string prev_usb_ant, prev_usb_devid;
+  std::string prev_ant, ant, dep;
 
-  int usbstoridx = -1;
-  std::string usbcontr;
-  for (int i = 2; i < n; i++) {
-    // Find next 'USB_CONTROLLER  USBSTORAGE_DEVICE' pair
-    regmatch_t match[3];
-    const char * s = assoc[i].c_str();
-    if (!regex.execute(s, 3, match))
-      continue;
+  const regular_expression regex("^.*PnPEntity\\.DeviceID=\"([^\"]*)\"", REG_EXTENDED);
 
-    // USBSTOR device found, compare Name
-    if (run_cmd(result,
-          "wmic PATH Win32_PnPEntity WHERE DeviceID=\"%s\" GET Name",
-          wmi_quote(s + match[2].rm_so, match[2].rm_eo - match[2].rm_so).c_str()
-          ) != 2)
-      continue;
-    if (result[1] != name)
+  while (we.next(wo)) {
+    prev_ant = ant;
+    // Find next 'USB_CONTROLLER, DEVICE' pair
+    ant = wo.get_str("Antecedent");
+    dep = wo.get_str("Dependent");
+
+    if (debug && ant != prev_ant)
+      pout(" %s:\n", ant.c_str());
+
+    // Extract DeviceID
+    regmatch_t match[2];
+    if (!(regex.execute(dep.c_str(), 2, match) && match[1].rm_so >= 0)) {
+      if (debug)
+        pout("  | (\"%s\")\n", dep.c_str());
       continue;
+    }
 
-    // Name must be uniqe
-    if (usbstoridx >= 0)
-      return false;
+    std::string devid(dep.c_str()+match[1].rm_so, match[1].rm_eo-match[1].rm_so);
 
-    usbstoridx = i;
-    usbcontr.assign(s + match[1].rm_so, match[1].rm_eo - match[1].rm_so);
-  }
+    if (str_starts_with(devid, "USB\\\\VID_")) {
+      // USB bridge entry, save CONTROLLER, ID
+      if (debug)
+        pout("  +-> \"%s\"\n", devid.c_str());
+      prev_usb_ant = ant;
+      prev_usb_devid = devid;
+      continue;
+    }
+    else if (str_starts_with(devid, "USBSTOR\\\\")) {
+      // USBSTOR device found
+      if (debug)
+        pout("  +--> \"%s\"\n", devid.c_str());
+
+      // Retrieve name
+      wbem_object wo2;
+      if (!ws.query1(wo2, "SELECT Name FROM Win32_PnPEntity WHERE DeviceID=\"%s\"", devid.c_str()))
+        continue;
+      std::string name2 = wo2.get_str("Name");
 
-  // Found ?
-  if (usbstoridx <= 0)
-    return false;
+      // Continue if not name of physical disk drive
+      if (name2 != name) {
+        if (debug)
+          pout("  |    (Name: \"%s\")\n", name2.c_str());
+        continue;
+      }
+      if (debug)
+        pout("  |    Name: \"%s\"\n", name2.c_str());
+
+      // Fail if previos USB bridge is associated to other controller
+      if (ant != prev_usb_ant)
+        return false;
+
+      // Handle multiple devices with same name
+      if (!usb_devid.empty()) {
+        // Fail if multiple devices with same name have different USB bridge types
+        if (usb_devid != prev_usb_devid)
+          return false;
+        continue;
+      }
 
-  // The entry preceding USBSTOR should be the USB bridge device
-  regex.compile("^([^ ]+) .*Win32_PnPEntity.DeviceID=\"USB\\\\VID_(....&PID_....)[^\"]*\" *$",
-                REG_EXTENDED);
-  if (regex.empty())
-    return false;
-  regmatch_t match[3];
-  const char * s = assoc[usbstoridx-1].c_str();
-  if (!regex.execute(s, 3, match))
-    return false;
+      // Found
+      usb_devid = prev_usb_devid;
 
-  // Both devices must be associated to same controller
-  if (usbcontr != std::string(s + match[1].rm_so, match[1].rm_eo - match[1].rm_so))
-    return false;
+      // Continue to check for duplicate names ...
+    }
+    else {
+      if (debug)
+        pout("  |   \"%s\"\n", devid.c_str());
+    }
+  }
 
   // Parse USB ID
   int nc = -1;
-  if (!(sscanf(s + match[2].rm_so, "%4hx&PID_%4hx%n",
-               &vendor_id, &product_id, &nc) == 2 && nc == 4+5+4))
+  if (!(sscanf(usb_devid.c_str(), "USB\\\\VID_%4hx&PID_%4hx%n",
+               &vendor_id, &product_id, &nc) == 2 && nc == 9+4+5+4))
     return false;
 
-  if (con->reportscsiioctl > 1)
+  if (debug)
     pout("USB ID = 0x%04x:0x%04x\n", vendor_id, product_id);
   return true;
 }
@@ -2040,35 +2265,27 @@ static bool get_usb_id(int drive, unsigned short & vendor_id, unsigned short & p
 
 static int get_device_power_state(HANDLE hdevice)
 {
-  static HINSTANCE h_kernel_dll = 0;
+  static bool unsupported = false;
+  if (unsupported) {
+    errno = ENOSYS;
+    return -1;
+  }
+
 #ifdef __CYGWIN__
   static DWORD kernel_dll_pid = 0;
 #endif
   static BOOL (WINAPI * GetDevicePowerState_p)(HANDLE, BOOL *) = 0;
 
-  BOOL state = TRUE;
-
   if (!GetDevicePowerState_p
 #ifdef __CYGWIN__
       || kernel_dll_pid != GetCurrentProcessId() // detect fork()
 #endif
      ) {
-    if (h_kernel_dll == INVALID_HANDLE_VALUE) {
-      errno = ENOSYS;
-      return -1;
-    }
-    if (!(h_kernel_dll = LoadLibraryA("KERNEL32.DLL"))) {
-      pout("Cannot load KERNEL32.DLL, Error=%ld\n", GetLastError());
-      h_kernel_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
-      errno = ENOSYS;
-      return -1;
-    }
     if (!(GetDevicePowerState_p = (BOOL (WINAPI *)(HANDLE, BOOL *))
-                                  GetProcAddress(h_kernel_dll, "GetDevicePowerState"))) {
-      if (con->reportataioctl)
+          GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetDevicePowerState"))) {
+      if (ata_debugmode)
         pout("  GetDevicePowerState() not found, Error=%ld\n", GetLastError());
-      FreeLibrary(h_kernel_dll);
-      h_kernel_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
+      unsupported = true;
       errno = ENOSYS;
       return -1;
     }
@@ -2077,9 +2294,10 @@ static int get_device_power_state(HANDLE hdevice)
 #endif
   }
 
+  BOOL state = TRUE;
   if (!GetDevicePowerState_p(hdevice, &state)) {
     long err = GetLastError();
-    if (con->reportataioctl)
+    if (ata_debugmode)
       pout("  GetDevicePowerState() failed, Error=%ld\n", err);
     errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
     // TODO: This may not work as expected on transient errors,
@@ -2087,7 +2305,7 @@ static int get_device_power_state(HANDLE hdevice)
     return -1;
   }
 
-  if (con->reportataioctl > 1)
+  if (ata_debugmode > 1)
     pout("  GetDevicePowerState() succeeded, state=%d\n", state);
   return state;
 }
@@ -2289,7 +2507,7 @@ bool win_ata_device::open(int phydrive, int logdrive, const char * options, int
     }
   }
 
-  if (con->reportataioctl > 1)
+  if (ata_debugmode > 1)
     pout("%s: successfully opened%s\n", devpath, (!m_admin ? " (without admin rights)" :""));
 
   m_usr_options = false;
@@ -2385,7 +2603,7 @@ bool win9x_smart_interface::ata_scan(smart_device_list & devlist)
   HANDLE h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,
     FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
   if (h == INVALID_HANDLE_VALUE) {
-    if (con->reportataioctl > 1)
+    if (ata_debugmode > 1)
       pout(" %s: Open failed, Error=%ld\n", devpath, GetLastError());
     return true; // SMARTVSD.VXD missing or no ATA devices
   }
@@ -2411,44 +2629,6 @@ bool win9x_smart_interface::ata_scan(smart_device_list & devlist)
 #endif // WIN9X_SUPPORT
 
 
-// Scan for ATA drives
-
-bool winnt_smart_interface::ata_scan(smart_device_list & devlist)
-{
-  const int max_raid = 2;
-  bool raid_seen[max_raid] = {false, false};
-
-  char name[20];
-  for (int i = 0; i <= 9; i++) {
-    GETVERSIONINPARAMS_EX vers_ex;
-    if (get_phy_drive_type(i, &vers_ex) != DEV_ATA)
-      continue;
-
-    // Interpret RAID drive map if present
-    if (vers_ex.wIdentifier == SMART_VENDOR_3WARE) {
-      // Skip if more than 2 controllers or logical drive from this controller already seen
-      if (vers_ex.wControllerId >= max_raid || raid_seen[vers_ex.wControllerId])
-        continue;
-      raid_seen[vers_ex.wControllerId] = true;
-      // Add physical drives
-      for (int pi = 0; pi < 32; pi++) {
-        if (vers_ex.dwDeviceMapEx & (1L << pi)) {
-            sprintf(name, "/dev/sd%c,%u", 'a'+i, pi);
-            devlist.push_back( new win_ata_device(this, name, "ata") );
-        }
-      }
-      continue;
-    }
-
-    // Driver supports SMART_GET_VERSION or STORAGE_QUERY_PROPERTY returns ATA/SATA
-    sprintf(name, "/dev/sd%c", 'a'+i);
-    devlist.push_back( new win_ata_device(this, name, "ata") );
-  }
-
-  return true;
-}
-
-
 /////////////////////////////////////////////////////////////////////////////
 
 // Interface to ATA devices
@@ -2642,12 +2822,12 @@ bool win_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
         if (!m_smartver_state) {
           assert(m_port == -1);
           if (smart_get_version(get_fh()) < 0) {
-            if (!con->permissive) {
+            if (!failuretest_permissive) {
               m_smartver_state = 2;
               rc = -1; errno = ENOSYS;
               break;
             }
-            con->permissive--;
+            failuretest_permissive--;
           }
           m_smartver_state = 1;
         }
@@ -2774,6 +2954,328 @@ bool win_ata_device::ata_identify_is_cached() const
 }
 
 
+//////////////////////////////////////////////////////////////////////
+// csmi_ata_device
+
+bool csmi_device::get_phy_info(CSMI_SAS_PHY_INFO & phy_info)
+{
+  // Get driver info to check CSMI support
+  CSMI_SAS_DRIVER_INFO_BUFFER driver_info_buf;
+  memset(&driver_info_buf, 0, sizeof(driver_info_buf));
+  if (!csmi_ioctl(CC_CSMI_SAS_GET_DRIVER_INFO, &driver_info_buf.IoctlHeader, sizeof(driver_info_buf)))
+    return false;
+
+  if (scsi_debugmode > 1) {
+    const CSMI_SAS_DRIVER_INFO & driver_info = driver_info_buf.Information;
+    pout("CSMI_SAS_DRIVER_INFO:\n");
+    pout("  Name:        \"%.81s\"\n", driver_info.szName);
+    pout("  Description: \"%.81s\"\n", driver_info.szDescription);
+    pout("  Revision:    %d.%d\n", driver_info.usMajorRevision, driver_info.usMinorRevision);
+  }
+
+  // Get Phy info
+  CSMI_SAS_PHY_INFO_BUFFER phy_info_buf;
+  memset(&phy_info_buf, 0, sizeof(phy_info_buf));
+  if (!csmi_ioctl(CC_CSMI_SAS_GET_PHY_INFO, &phy_info_buf.IoctlHeader, sizeof(phy_info_buf)))
+    return false;
+
+  phy_info = phy_info_buf.Information;
+  if (phy_info.bNumberOfPhys > sizeof(phy_info.Phy)/sizeof(phy_info.Phy[0]))
+    return set_err(EIO, "CSMI_SAS_PHY_INFO: Bogus NumberOfPhys=%d", phy_info.bNumberOfPhys);
+
+  if (scsi_debugmode > 1) {
+    pout("CSMI_SAS_PHY_INFO: NumberOfPhys=%d\n", phy_info.bNumberOfPhys);
+    for (int i = 0; i < phy_info.bNumberOfPhys; i++) {
+      const CSMI_SAS_PHY_ENTITY & pe = phy_info.Phy[i];
+      const CSMI_SAS_IDENTIFY & id = pe.Identify, & at = pe.Attached;
+      pout("Phy[%d] Port:   0x%02x\n", i, pe.bPortIdentifier);
+      pout("  Type:        0x%02x, 0x%02x\n", id.bDeviceType, at.bDeviceType);
+      pout("  InitProto:   0x%02x, 0x%02x\n", id.bInitiatorPortProtocol, at.bInitiatorPortProtocol);
+      pout("  TargetProto: 0x%02x, 0x%02x\n", id.bTargetPortProtocol, at.bTargetPortProtocol);
+      pout("  PhyIdent:    0x%02x, 0x%02x\n", id.bPhyIdentifier, at.bPhyIdentifier);
+      const unsigned char * b = id.bSASAddress;
+      pout("  SASAddress:  %02x %02x %02x %02x %02x %02x %02x %02x, ",
+        b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
+      b = at.bSASAddress;
+      pout(               "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+        b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
+    }
+  }
+
+  return true;
+}
+
+bool csmi_device::check_phy(const CSMI_SAS_PHY_INFO & phy_info, unsigned phy_no)
+{
+  // Check Phy presence
+  if (phy_no >= phy_info.bNumberOfPhys)
+    return set_err(ENOENT, "Port %u does not exist (#ports: %d)", phy_no,
+      phy_info.bNumberOfPhys);
+
+  const CSMI_SAS_PHY_ENTITY & phy_ent = phy_info.Phy[phy_no];
+  if (phy_ent.Attached.bDeviceType == CSMI_SAS_NO_DEVICE_ATTACHED)
+    return set_err(ENOENT, "No device on port %u", phy_no);
+
+  switch (phy_ent.Attached.bTargetPortProtocol) {
+    case CSMI_SAS_PROTOCOL_SATA:
+    case CSMI_SAS_PROTOCOL_STP:
+      break;
+    default:
+      return set_err(ENOENT, "No SATA device on port %u (protocol: %u)",
+        phy_no, phy_ent.Attached.bTargetPortProtocol);
+  }
+
+  return true;
+}
+
+bool csmi_device::select_phy(unsigned phy_no)
+{
+  CSMI_SAS_PHY_INFO phy_info;
+  if (!get_phy_info(phy_info))
+    return false;
+
+
+  if (!check_phy(phy_info, phy_no))
+    return false;
+
+  m_phy_ent = phy_info.Phy[phy_no];
+  return true;
+}
+
+
+bool csmi_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
+{
+  if (!ata_cmd_is_ok(in,
+    true, // data_out_support
+    true, // multi_sector_support
+    true) // ata_48bit_support
+  )
+    return false;
+
+  // Create buffer with appropriate size
+  raw_buffer pthru_raw_buf(sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER) + in.size);
+  CSMI_SAS_STP_PASSTHRU_BUFFER * pthru_buf = (CSMI_SAS_STP_PASSTHRU_BUFFER *)pthru_raw_buf.data();
+
+  // Set addresses from Phy info
+  CSMI_SAS_STP_PASSTHRU & pthru = pthru_buf->Parameters;
+  const CSMI_SAS_PHY_ENTITY & phy_ent = get_phy_ent();
+  pthru.bPhyIdentifier = phy_ent.Identify.bPhyIdentifier;
+  pthru.bPortIdentifier = phy_ent.bPortIdentifier;
+  memcpy(pthru.bDestinationSASAddress, phy_ent.Attached.bSASAddress,
+    sizeof(pthru.bDestinationSASAddress));
+  pthru.bConnectionRate = CSMI_SAS_LINK_RATE_NEGOTIATED;
+
+  // Set transfer mode
+  switch (in.direction) {
+    case ata_cmd_in::no_data:
+      pthru.uFlags = CSMI_SAS_STP_PIO | CSMI_SAS_STP_UNSPECIFIED;
+      break;
+    case ata_cmd_in::data_in:
+      pthru.uFlags = CSMI_SAS_STP_PIO | CSMI_SAS_STP_READ;
+      pthru.uDataLength = in.size;
+      break;
+    case ata_cmd_in::data_out:
+      pthru.uFlags = CSMI_SAS_STP_PIO | CSMI_SAS_STP_WRITE;
+      pthru.uDataLength = in.size;
+      memcpy(pthru_buf->bDataBuffer, in.buffer, in.size);
+      break;
+    default:
+      return set_err(EINVAL, "csmi_ata_device::ata_pass_through: invalid direction=%d",
+        (int)in.direction);
+  }
+
+  // Set host-to-device FIS
+  {
+    unsigned char * fis = pthru.bCommandFIS;
+    const ata_in_regs & lo = in.in_regs;
+    const ata_in_regs & hi = in.in_regs.prev;
+    fis[ 0] = 0x27; // Type: host-to-device FIS
+    fis[ 1] = 0x80; // Bit7: Update command register
+    fis[ 2] = lo.command;
+    fis[ 3] = lo.features;
+    fis[ 4] = lo.lba_low;
+    fis[ 5] = lo.lba_mid;
+    fis[ 6] = lo.lba_high;
+    fis[ 7] = lo.device;
+    fis[ 8] = hi.lba_low;
+    fis[ 9] = hi.lba_mid;
+    fis[10] = hi.lba_high;
+    fis[11] = hi.features;
+    fis[12] = lo.sector_count;
+    fis[13] = hi.sector_count;
+  }
+
+  // Call ioctl
+  if (!csmi_ioctl(CC_CSMI_SAS_STP_PASSTHRU, &pthru_buf->IoctlHeader, pthru_raw_buf.size())) {
+    return false;
+  }
+
+  // Get device-to-host FIS
+  {
+    const unsigned char * fis = pthru_buf->Status.bStatusFIS;
+    ata_out_regs & lo = out.out_regs;
+    lo.status       = fis[ 2];
+    lo.error        = fis[ 3];
+    lo.lba_low      = fis[ 4];
+    lo.lba_mid      = fis[ 5];
+    lo.lba_high     = fis[ 6];
+    lo.device       = fis[ 7];
+    lo.sector_count = fis[12];
+    if (in.in_regs.is_48bit_cmd()) {
+      ata_out_regs & hi = out.out_regs.prev;
+      hi.lba_low      = fis[ 8];
+      hi.lba_mid      = fis[ 9];
+      hi.lba_high     = fis[10];
+      hi.sector_count = fis[13];
+    }
+  }
+
+  // Get data
+  if (in.direction == ata_cmd_in::data_in)
+    // TODO: Check ptru_buf->Status.uDataBytes
+    memcpy(in.buffer, pthru_buf->bDataBuffer, in.size);
+
+  return true;
+}
+
+
+//////////////////////////////////////////////////////////////////////
+// win_csmi_device
+
+win_csmi_device::win_csmi_device(smart_interface * intf, const char * dev_name,
+  const char * req_type)
+: smart_device(intf, dev_name, "ata", req_type),
+  m_fh(INVALID_HANDLE_VALUE), m_phy_no(0)
+{
+}
+
+win_csmi_device::~win_csmi_device() throw()
+{
+  if (m_fh != INVALID_HANDLE_VALUE)
+    CloseHandle(m_fh);
+}
+
+bool win_csmi_device::is_open() const
+{
+  return (m_fh != INVALID_HANDLE_VALUE);
+}
+
+bool win_csmi_device::close()
+{
+  if (m_fh == INVALID_HANDLE_VALUE)
+    return true;
+  BOOL rc = CloseHandle(m_fh);
+  m_fh = INVALID_HANDLE_VALUE;
+  return !!rc;
+}
+
+
+bool win_csmi_device::open_scsi()
+{
+  // Parse name
+  unsigned contr_no = ~0, phy_no = ~0; int nc = -1;
+  const char * name = skipdev(get_dev_name());
+  if (!(   sscanf(name, "csmi%u,%u%n", &contr_no, &phy_no, &nc) >= 0
+        && nc == (int)strlen(name) && contr_no <= 9 && phy_no < 32)  )
+    return set_err(EINVAL);
+
+  // Open controller handle
+  char devpath[30];
+  snprintf(devpath, sizeof(devpath)-1, "\\\\.\\Scsi%u:", contr_no);
+
+  HANDLE h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,
+    FILE_SHARE_READ|FILE_SHARE_WRITE,
+    (SECURITY_ATTRIBUTES *)0, OPEN_EXISTING, 0, 0);
+
+  if (h == INVALID_HANDLE_VALUE) {
+    long err = GetLastError();
+    if (err == ERROR_FILE_NOT_FOUND)
+      set_err(ENOENT, "%s: not found", devpath);
+    else if (err == ERROR_ACCESS_DENIED)
+      set_err(EACCES, "%s: access denied", devpath);
+    else
+      set_err(EIO, "%s: Error=%ld", devpath, err);
+    return false;
+  }
+
+  if (scsi_debugmode > 1)
+    pout(" %s: successfully opened\n", devpath);
+
+  m_fh = h;
+  m_phy_no = phy_no;
+  return true;
+}
+
+
+bool win_csmi_device::open()
+{
+  if (!open_scsi())
+    return false;
+
+  // Get Phy info for this drive
+  if (!select_phy(m_phy_no)) {
+    close();
+    return false;
+  }
+
+  return true;
+}
+
+
+bool win_csmi_device::csmi_ioctl(unsigned code, IOCTL_HEADER * csmi_buffer,
+  unsigned csmi_bufsiz)
+{
+  // Determine signature
+  const char * sig;
+  switch (code) {
+    case CC_CSMI_SAS_GET_DRIVER_INFO:
+      sig = CSMI_ALL_SIGNATURE; break;
+    case CC_CSMI_SAS_GET_PHY_INFO:
+    case CC_CSMI_SAS_STP_PASSTHRU:
+      sig = CSMI_SAS_SIGNATURE; break;
+    default:
+      return set_err(ENOSYS, "Unknown CSMI code=%u", code);
+  }
+
+  // Set header
+  csmi_buffer->HeaderLength = sizeof(IOCTL_HEADER);
+  strncpy((char *)csmi_buffer->Signature, sig, sizeof(csmi_buffer->Signature));
+  csmi_buffer->Timeout = CSMI_SAS_TIMEOUT;
+  csmi_buffer->ControlCode = code;
+  csmi_buffer->ReturnCode = 0;
+  csmi_buffer->Length = csmi_bufsiz - sizeof(IOCTL_HEADER);
+
+  // Call function
+  DWORD num_out = 0;
+  if (!DeviceIoControl(m_fh, IOCTL_SCSI_MINIPORT,
+    csmi_buffer, csmi_bufsiz, csmi_buffer, csmi_bufsiz, &num_out, (OVERLAPPED*)0)) {
+    long err = GetLastError();
+    if (scsi_debugmode)
+      pout("  IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, Error=%ld\n", code, err);
+    if (   err == ERROR_INVALID_FUNCTION
+        || err == ERROR_NOT_SUPPORTED
+        || err == ERROR_DEV_NOT_EXIST)
+      return set_err(ENOSYS, "CSMI is not supported (Error=%ld)", err);
+    else
+      return set_err(EIO, "CSMI(%u) failed with Error=%ld", code, err);
+  }
+
+  // Check result
+  if (csmi_buffer->ReturnCode) {
+    if (scsi_debugmode) {
+      pout("  IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, ReturnCode=%lu\n",
+        code, csmi_buffer->ReturnCode);
+    }
+    return set_err(EIO, "CSMI(%u) failed with ReturnCode=%lu", code, csmi_buffer->ReturnCode);
+  }
+
+  if (scsi_debugmode > 1)
+    pout("  IOCTL_SCSI_MINIPORT(CC_CSMI_%u) succeeded, bytes returned: %lu\n", code, num_out);
+
+  return true;
+}
+
+
 /////////////////////////////////////////////////////////////////////////////
 // ASPI Interface (for SCSI devices on 9x/ME)
 /////////////////////////////////////////////////////////////////////////////
@@ -2911,7 +3413,7 @@ static int aspi_call(ASPI_SRB * srb)
       errno = EIO;
       return -1;
     }
-    if (con->reportscsiioctl > 1)
+    if (scsi_debugmode > 1)
       pout("ASPI Adapter %u: Waiting (%d) ...\n", srb->h.adapter, i);
     Sleep(100);
   }
@@ -2972,7 +3474,7 @@ static int aspi_open_dll(int verbose)
     errno = ENOENT;
     return -1;
   }
-  if (con->reportscsiioctl > 1) {
+  if (scsi_debugmode > 1) {
     // Print full path of WNASPI32.DLL
     char path[MAX_PATH];
     if (!GetModuleFileName(h_aspi_dll, path, sizeof(path)))
@@ -2988,7 +3490,7 @@ static int aspi_open_dll(int verbose)
 
   // Init ASPI manager and get number of adapters
   info = (aspi_info)();
-  if (con->reportscsiioctl > 1)
+  if (scsi_debugmode > 1)
     pout("GetASPI32SupportInfo() returns 0x%04x\n", info);
   rc = (info >> 8) & 0xff;
   if (rc == ASPI_STATUS_NO_ADAPTERS) {
@@ -3007,7 +3509,7 @@ static int aspi_open_dll(int verbose)
     return -1;
   }
 
-  if (con->reportscsiioctl)
+  if (scsi_debugmode)
     pout("%u ASPI Adapter%s detected\n",num_aspi_adapters, (num_aspi_adapters!=1?"s":""));
 
 #ifdef __CYGWIN__
@@ -3099,7 +3601,7 @@ bool win_aspi_device::open()
     if (!is_permissive())
       return set_err(srb.h.status == ASPI_STATUS_INVALID_TARGET ? ENOENT : EIO);
   }
-  else if (con->reportscsiioctl)
+  else if (scsi_debugmode)
     pout("ASPI Adapter %u, ID %u: Device Type=0x%02x\n", adapter, id, srb.t.devtype);
 
   m_adapter = (int)adapter; m_id = (unsigned char)id;
@@ -3119,7 +3621,7 @@ bool win_aspi_device::close()
 bool win9x_smart_interface::scsi_scan(smart_device_list & devlist)
 {
   if (!aspi_entry_valid()) {
-    if (aspi_open_dll(con->reportscsiioctl/*default is quiet*/))
+    if (aspi_open_dll(scsi_debugmode/*default is quiet*/))
       return true;
   }
 
@@ -3127,7 +3629,7 @@ bool win9x_smart_interface::scsi_scan(smart_device_list & devlist)
     ASPI_SRB srb;
 
     if (ad > 9) {
-      if (con->reportscsiioctl)
+      if (scsi_debugmode)
         pout(" ASPI Adapter %u: Ignored\n", ad);
       continue;
     }
@@ -3140,12 +3642,12 @@ bool win9x_smart_interface::scsi_scan(smart_device_list & devlist)
       break;
 
     if (srb.h.status != ASPI_STATUS_NO_ERROR) {
-      if (con->reportscsiioctl)
+      if (scsi_debugmode)
         pout(" ASPI Adapter %u: Status=0x%02x\n", ad, srb.h.status);
       continue;
     }
 
-    if (con->reportscsiioctl) {
+    if (scsi_debugmode) {
       for (int i = 1; i < 16 && srb.q.adapter_id[i]; i++)
         if (!(' ' <= srb.q.adapter_id[i] && srb.q.adapter_id[i] <= '~'))
           srb.q.adapter_id[i] = '?';
@@ -3162,19 +3664,19 @@ bool win9x_smart_interface::scsi_scan(smart_device_list & devlist)
       if (aspi_call(&srb))
         return 0;
       if (srb.h.status != ASPI_STATUS_NO_ERROR) {
-        if (con->reportscsiioctl > 1)
+        if (scsi_debugmode > 1)
           pout("  ID %u: No such device (Status=0x%02x)\n", id, srb.h.status);
         continue;
       }
 
       if (!ignore && srb.t.devtype == 0x00/*HDD*/) {
-        if (con->reportscsiioctl)
+        if (scsi_debugmode)
           pout("  ID %u: Device Type=0x%02x\n", id, srb.t.devtype);
         char name[20];
         sprintf(name, "/dev/scsi%u%u", ad, id);
         devlist.push_back( new win_aspi_device(this, name, "scsi") );
       }
-      else if (con->reportscsiioctl)
+      else if (scsi_debugmode)
         pout("  ID %u: Device Type=0x%02x (ignored)\n", id, srb.t.devtype);
     }
   }
@@ -3185,7 +3687,7 @@ bool win9x_smart_interface::scsi_scan(smart_device_list & devlist)
 // Interface to ASPI SCSI devices
 bool win_aspi_device::scsi_pass_through(scsi_cmnd_io * iop)
 {
-  int report = con->reportscsiioctl; // TODO
+  int report = scsi_debugmode; // TODO
 
   if (m_adapter < 0) {
     set_err(EBADF);
@@ -3388,20 +3890,6 @@ bool win_scsi_device::open(int pd_num, int ld_num, int tape_num, int /*sub_addr*
 }
 
 
-bool winnt_smart_interface::scsi_scan(smart_device_list & devlist)
-{
-  char name[20];
-  for (int i = 0; i <= 9; i++) {
-    if (get_phy_drive_type(i) != DEV_SCSI)
-      continue;
-    // STORAGE_QUERY_PROPERTY returned SCSI/SAS/...
-    sprintf(name, "/dev/sd%c", 'a'+i);
-    devlist.push_back( new win_scsi_device(this, name, "scsi") );
-  }
-  return true;
-}
-
-
 typedef struct {
   SCSI_PASS_THROUGH_DIRECT spt;
   ULONG           Filler;
@@ -3458,7 +3946,7 @@ static long scsi_pass_through_indirect(HANDLE h,
 // Interface to SPT SCSI devices.  See scsicmds.h and os_linux.c
 bool win_scsi_device::scsi_pass_through(struct scsi_cmnd_io * iop)
 {
-  int report = con->reportscsiioctl; // TODO
+  int report = scsi_debugmode; // TODO
 
   if (report > 0) {
     int k, j;
@@ -3587,6 +4075,15 @@ bool win_scsi_device::scsi_pass_through(struct scsi_cmnd_io * iop)
 // Initialize platform interface and register with smi()
 void smart_interface::init()
 {
+  {
+    // Remove "." from DLL search path if supported
+    // to prevent DLL preloading attacks
+    BOOL (WINAPI * SetDllDirectoryA_p)(LPCSTR) = (BOOL (WINAPI *)(LPCSTR))
+      GetProcAddress(GetModuleHandleA("kernel32.dll"), "SetDllDirectoryA");
+    if (SetDllDirectoryA_p)
+      SetDllDirectoryA_p("");
+  }
+
   // Select interface for Windows flavor
   if (GetVersion() & 0x80000000) {
 #if WIN9X_SUPPORT
index f9e2842152a88aa982292ffa57eaa6358ce80035..ccda10182867775eedaea744d0c3038a2c2e9657 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2004-8 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2004-10 Christian Franke <smartmontools-support@lists.sourceforge.net>
  *
  * 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
  *
  */
 
+// Need MB_SERVICE_NOTIFICATION (NT4/2000/XP), IsDebuggerPresent() (Win98/ME/NT4/2000/XP)
+#define WINVER 0x0400
+#define _WIN32_WINNT WINVER
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <signal.h>
 #include <io.h>
 
 #define WIN32_LEAN_AND_MEAN
-// Need MB_SERVICE_NOTIFICATION (NT4/2000/XP), IsDebuggerPresent() (Win98/ME/NT4/2000/XP)
-#define _WIN32_WINNT 0x0400 
 #include <windows.h>
 #ifdef _DEBUG
 #include <crtdbg.h>
@@ -31,8 +33,8 @@
 
 #include "daemon_win32.h"
 
-const char *daemon_win32_c_cvsid = "$Id: daemon_win32.cpp,v 1.12 2008/03/04 22:09:48 ballen4705 Exp $"
-DAEMON_WIN32_H_CVSID;
+const char * daemon_win32_cpp_cvsid = "$Id: daemon_win32.cpp 3267 2011-02-21 17:14:25Z chrfranke $"
+  DAEMON_WIN32_H_CVSID;
 
 
 /////////////////////////////////////////////////////////////////////////////
@@ -525,7 +527,7 @@ int daemon_messagebox(int system, const char * title, const char * text)
        mb.mode = MB_OK|MB_ICONWARNING
                 |(svc_mode?MB_SERVICE_NOTIFICATION:0)
                 |(system?MB_SYSTEMMODAL:MB_APPLMODAL);
-       mb.title = title; mb.text = text;
+       mb.title = title;
        mb.text = text;
        if (!(ht = CreateThread(NULL, 0, mbox_thread, &mb, 0, &tid)))
                return -1;
index 064add38b18b2342e3af8e9f944f6efaf08a28a1..85ff8163ca955bd2345d6ff57606832898681dc1 100644 (file)
@@ -1,20 +1,25 @@
 ;
-; installer.nsi - NSIS install script for smartmontools
+; smartmontools install NSIS script
 ;
-; Copyright (C) 2006-9 Christian Franke <smartmontools-support@lists.sourceforge.net>
+; Home page of code is: http://smartmontools.sourceforge.net
 ;
-; Project home page is: http://smartmontools.sourceforge.net
+; Copyright (C) 2006-11 Christian Franke <smartmontools-support@lists.sourceforge.net>
 ;
-; Download and install NSIS from: http://nsis.sourceforge.net/Download
-; Process with makensis to create installer (tested with NSIS 2.45)
+; 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 Software Foundation; either version 2, or (at your option)
+; any later version.
 ;
-; $Id: installer.nsi 2878 2009-08-26 20:03:06Z chrfranke $
+; You should have received a copy of the GNU General Public License
+; (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
+;
+; $Id: installer.nsi 3296 2011-03-16 22:17:51Z chrfranke $
 ;
 
 
 ;--------------------------------------------------------------------
 ; Command line arguments:
-; makensis /DINPDIR=<input-dir> /DOUTFILE=<output-file> /DVERSTR=<version-string> installer.nsi
+; makensis -DINPDIR=<input-dir> -DOUTFILE=<output-file> -DVERSTR=<version-string> installer.nsi
 
 !ifndef INPDIR
   !define INPDIR "."
@@ -115,6 +120,16 @@ SectionGroup "!Program files"
 
   SectionEnd
 
+  Section "drivedb.h (Drive Database)" DRIVEDB_SECTION
+
+    SectionIn 1 2
+
+    SetOutPath "$INSTDIR\bin"
+    File "${INPDIR}\bin\drivedb.h"
+    File "${INPDIR}\bin\update-smart-drivedb.exe"
+
+  SectionEnd
+
 SectionGroupEnd
 
 Section "!Documentation" DOC_SECTION
@@ -130,6 +145,7 @@ Section "!Documentation" DOC_SECTION
   File "${INPDIR}\doc\README.txt"
   File "${INPDIR}\doc\TODO.txt"
   File "${INPDIR}\doc\WARNINGS.txt"
+  File "${INPDIR}\doc\checksums.txt"
   File "${INPDIR}\doc\smartctl.8.html"
   File "${INPDIR}\doc\smartctl.8.txt"
   File "${INPDIR}\doc\smartd.8.html"
@@ -205,7 +221,7 @@ Section "Start Menu Shortcuts" MENU_SECTION
     SetOutPath "$INSTDIR\bin"
     DetailPrint "Create file: $INSTDIR\bin\smartd-run.bat"
     FileOpen $0 "$INSTDIR\bin\smartd-run.bat" "w"
-    FileWrite $0 "@echo off$\r$\necho smartd %1 %2 %3 %4 %5$\r$\nsmartd %1 %2 %3 %4 %5$\r$\npause$\r$\n"
+    FileWrite $0 '@echo off$\r$\necho smartd %1 %2 %3 %4 %5$\r$\n"$INSTDIR\bin\smartd" %1 %2 %3 %4 %5$\r$\npause$\r$\n'
     FileClose $0
     CreateDirectory "$SMPROGRAMS\smartmontools\smartd Examples"
     CreateShortCut "$SMPROGRAMS\smartmontools\smartd Examples\Daemon start, smartd.log.lnk" "$INSTDIR\bin\smartd-run.bat" "-l local0"
@@ -244,8 +260,11 @@ Section "Start Menu Shortcuts" MENU_SECTION
     CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\smartctl manual page (txt).lnk"     "$INSTDIR\doc\smartctl.8.txt"
     CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\smartd manual page (txt).lnk"       "$INSTDIR\doc\smartd.8.txt"
     CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\smartd.conf manual page (txt).lnk"  "$INSTDIR\doc\smartd.conf.5.txt"
-    IfFileExists "$WINDIR\notepad.exe" 0 +2
+    IfFileExists "$WINDIR\notepad.exe" 0 +5
       CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\smartd.conf sample.lnk" "$WINDIR\notepad.exe" "$INSTDIR\doc\smartd.conf"
+      IfFileExists "$INSTDIR\bin\drivedb.h" 0 +3
+        CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\drivedb.h (view).lnk" "$WINDIR\notepad.exe" "$INSTDIR\bin\drivedb.h"
+        CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\drivedb-add.h (create, edit).lnk" "$WINDIR\notepad.exe" "$INSTDIR\bin\drivedb-add.h"
     CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\AUTHORS.lnk"   "$INSTDIR\doc\AUTHORS.txt"
     CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\CHANGELOG.lnk" "$INSTDIR\doc\CHANGELOG.txt"
     CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\COPYING.lnk"   "$INSTDIR\doc\COPYING.txt"
@@ -260,6 +279,10 @@ Section "Start Menu Shortcuts" MENU_SECTION
   ; Homepage
   CreateShortCut "$SMPROGRAMS\smartmontools\smartmontools Home Page.lnk" "http://smartmontools.sourceforge.net/"
 
+  ; drivedb.h update
+  IfFileExists "$INSTDIR\bin\update-smart-drivedb.exe" 0 +2
+    CreateShortCut "$SMPROGRAMS\smartmontools\drivedb.h update.lnk" "$INSTDIR\bin\update-smart-drivedb.exe"
+
   ; Uninstall
   IfFileExists "$INSTDIR\uninst-smartmontools.exe" 0 +2
     CreateShortCut "$SMPROGRAMS\smartmontools\Uninstall smartmontools.lnk" "$INSTDIR\uninst-smartmontools.exe"
@@ -296,6 +319,7 @@ SectionGroup "Add smartctl to drive menu"
 !macro DriveSection id name args
   Section 'smartctl ${args} ...' DRIVE_${id}_SECTION
     SectionIn 3
+    Call CheckSmartctlBat
     DetailPrint 'Add drive menu entry "${name}": smartctl ${args} ...'
     WriteRegStr HKCR "Drive\shell\smartctl${id}" "" "${name}"
     WriteRegStr HKCR "Drive\shell\smartctl${id}\command" "" '"$INSTDIR\bin\smartctl-run.bat" ${args} %L'
@@ -374,7 +398,7 @@ Section "Uninstall"
   DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools"
   DeleteRegKey HKLM "Software\smartmontools"
 
-  ; Remove conf and log file
+  ; Remove conf file ?
   IfFileExists "$INSTDIR\bin\smartd.conf" 0 noconf
     ; Assume unchanged if timestamp is equal to sample file
     GetFileTime "$INSTDIR\bin\smartd.conf" $0 $1
@@ -384,15 +408,26 @@ Section "Uninstall"
         Delete "$INSTDIR\bin\smartd.conf"
   noconf:
 
+  ; Remove log file ?
   IfFileExists "$INSTDIR\bin\smartd.log" 0 +3
     MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2  "Delete log file$\n$INSTDIR\bin\smartd.log ?" IDYES 0 IDNO +2
       Delete "$INSTDIR\bin\smartd.log"
 
+  ; Remove drivedb-add file ?
+  IfFileExists "$INSTDIR\bin\drivedb-add.h" 0 +3
+    MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2  "Delete local drive database file$\n$INSTDIR\bin\drivedb-add.h ?" IDYES 0 IDNO +2
+      Delete "$INSTDIR\bin\drivedb-add.h"
+
   ; Remove files
   Delete "$INSTDIR\bin\smartctl.exe"
   Delete "$INSTDIR\bin\smartctl-nc.exe"
   Delete "$INSTDIR\bin\smartd.exe"
   Delete "$INSTDIR\bin\syslogevt.exe"
+  Delete "$INSTDIR\bin\drivedb.h"
+  Delete "$INSTDIR\bin\drivedb.h.error"
+  Delete "$INSTDIR\bin\drivedb.h.lastcheck"
+  Delete "$INSTDIR\bin\drivedb.h.old"
+  Delete "$INSTDIR\bin\update-smart-drivedb.exe"
   Delete "$INSTDIR\bin\smartctl-run.bat"
   Delete "$INSTDIR\bin\smartd-run.bat"
   Delete "$INSTDIR\bin\net-run.bat"
@@ -404,6 +439,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\smartctl.8.html"
   Delete "$INSTDIR\doc\smartctl.8.txt"
   Delete "$INSTDIR\doc\smartd.8.html"
@@ -477,6 +513,7 @@ 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}
@@ -517,12 +554,23 @@ Function CreateSmartctlBat
   FileWrite $0 'echo See man page (smartctl.8.*) for further info.$\r$\n'
   FileWrite $0 'goto end$\r$\n:run$\r$\n'
   FileWrite $0 'echo smartctl %1 %2 %3 %4 %5$\r$\n'
-  FileWrite $0 'smartctl %1 %2 %3 %4 %5$\r$\n'
+  FileWrite $0 '"$INSTDIR\bin\smartctl" %1 %2 %3 %4 %5$\r$\n'
   FileWrite $0 'pause$\r$\n:end$\r$\n'
   FileClose $0
   Pop $0
 FunctionEnd
 
+; Create smartctl-run.bat if missing
+
+Function CheckSmartctlBat
+  IfFileExists "$INSTDIR\bin\smartctl-run.bat" done 0
+    SetOutPath "$INSTDIR\bin"
+    DetailPrint "Create file: $INSTDIR\bin\smartctl-run.bat"
+    Push "$INSTDIR\bin\smartctl-run.bat"
+    Call CreateSmartctlBat
+  done:
+FunctionEnd
+
 
 ;--------------------------------------------------------------------
 ; Path functions
index 0c19af6957b66a68fe8d3a6755d78cd8a7702e87..0e8496a5702cc803b7c50776bb1dded47f245afd 100644 (file)
@@ -40,7 +40,7 @@
                        <Tool
                                Name="VCCLCompilerTool"
                                Optimization="0"
-                               AdditionalIncludeDirectories=".,..\getopt,..\regex"
+                               AdditionalIncludeDirectories=".,..\getopt,..\regex,$(IntDir)"
                                PreprocessorDefinitions="_DEBUG;HAVE_CONFIG_H;_ERRCODE_DEFINED;errno_t=int;_USE_32BIT_TIME_T;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE"
                                MinimalRebuild="true"
                                BasicRuntimeChecks="3"
                        />
                        <Tool
                                Name="VCCLCompilerTool"
-                               AdditionalIncludeDirectories=".,..\getopt,..\regex"
+                               AdditionalIncludeDirectories=".,..\getopt,..\regex,$(IntDir)"
                                PreprocessorDefinitions="NDEBUG;HAVE_CONFIG_H;_ERRCODE_DEFINED;errno_t=int;_USE_32BIT_TIME_T;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE"
                                RuntimeLibrary="2"
                                UsePrecompiledHeader="0"
                                        />
                                </FileConfiguration>
                        </File>
+                       <File
+                               RelativePath=".\update-smart-drivedb.nsi"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\wbemcli_small.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\wmiquery.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\wmiquery.h"
+                               >
+                       </File>
                </Filter>
                <Filter
                        Name="regex"
                                >
                                <Tool
                                        Name="VCCustomBuildTool"
-                                       Description="Copy $(InputPath) config.h"
-                                       CommandLine="copy $(InputPath) config.h&#x0D;&#x0A;"
-                                       Outputs="config.h"
+                                       Description="Copy $(InputPath) $(IntDir)\config.h"
+                                       CommandLine="copy $(InputPath) $(IntDir)\config.h&#x0D;&#x0A;"
+                                       Outputs="$(IntDir)\config.h"
                                />
                        </FileConfiguration>
                        <FileConfiguration
                                >
                                <Tool
                                        Name="VCCustomBuildTool"
-                                       Description="Copy $(InputPath) config.h"
-                                       CommandLine="copy $(InputPath) config.h&#x0D;&#x0A;"
-                                       Outputs="config.h"
+                                       Description="Copy $(InputPath) $(IntDir)\config.h"
+                                       CommandLine="copy $(InputPath) $(IntDir)\config.h&#x0D;&#x0A;"
+                                       Outputs="$(IntDir)\config.h"
                                />
                        </FileConfiguration>
                </File>
                        RelativePath="..\configure.in"
                        >
                </File>
+               <File
+                       RelativePath="..\csmisas.h"
+                       >
+               </File>
                <File
                        RelativePath="..\dev_ata_cmd_set.cpp"
                        >
                        RelativePath="..\drivedb.h"
                        >
                </File>
-               <File
-                       RelativePath="..\extern.h"
-                       >
-               </File>
                <File
                        RelativePath="..\INSTALL"
                        >
                        RelativePath="..\Makefile.am"
                        >
                </File>
+               <File
+                       RelativePath="..\megaraid.h"
+                       >
+                       <FileConfiguration
+                               Name="Debug|Win32"
+                               ExcludedFromBuild="true"
+                               >
+                               <Tool
+                                       Name="VCCustomBuildTool"
+                               />
+                       </FileConfiguration>
+                       <FileConfiguration
+                               Name="Release|Win32"
+                               ExcludedFromBuild="true"
+                               >
+                               <Tool
+                                       Name="VCCustomBuildTool"
+                               />
+                       </FileConfiguration>
+               </File>
                <File
                        RelativePath="..\NEWS"
                        >
index b3d91324b0af42aa5dfc418c957f425a43cda3d3..eb9d10ccc54815c12daa313c7d6cb25f0974fc48 100644 (file)
@@ -40,7 +40,7 @@
                        <Tool
                                Name="VCCLCompilerTool"
                                Optimization="0"
-                               AdditionalIncludeDirectories=".,..\getopt,..\regex"
+                               AdditionalIncludeDirectories=".,..\getopt,..\regex,$(IntDir)"
                                PreprocessorDefinitions="_DEBUG;HAVE_CONFIG_H;_ERRCODE_DEFINED;errno_t=int;_USE_32BIT_TIME_T;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE"
                                MinimalRebuild="true"
                                BasicRuntimeChecks="3"
                        />
                        <Tool
                                Name="VCCLCompilerTool"
-                               AdditionalIncludeDirectories=".,..\getopt,..\regex"
+                               AdditionalIncludeDirectories=".,..\getopt,..\regex,$(IntDir)"
                                PreprocessorDefinitions="NDEBUG;HAVE_CONFIG_H;_ERRCODE_DEFINED;errno_t=int;_USE_32BIT_TIME_T;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE"
                                RuntimeLibrary="2"
                                UsePrecompiledHeader="0"
                                RelativePath=".\syslog_win32.cpp"
                                >
                        </File>
+                       <File
+                               RelativePath=".\update-smart-drivedb.nsi"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\wbemcli_small.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\wmiquery.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\wmiquery.h"
+                               >
+                       </File>
                </Filter>
                <Filter
                        Name="regex"
                                        Name="VCCLCompilerTool"
                                />
                        </FileConfiguration>
+                       <FileConfiguration
+                               Name="Release|Win32"
+                               ExcludedFromBuild="true"
+                               >
+                               <Tool
+                                       Name="VCCLCompilerTool"
+                               />
+                       </FileConfiguration>
                </File>
                <File
                        RelativePath="..\ataprint.h"
                                        Name="VCCustomBuildTool"
                                />
                        </FileConfiguration>
+                       <FileConfiguration
+                               Name="Release|Win32"
+                               ExcludedFromBuild="true"
+                               >
+                               <Tool
+                                       Name="VCCustomBuildTool"
+                               />
+                       </FileConfiguration>
                </File>
                <File
                        RelativePath="..\AUTHORS"
                                >
                                <Tool
                                        Name="VCCustomBuildTool"
-                                       Description="Copy $(InputPath) config.h"
-                                       CommandLine="copy $(InputPath) config.h&#x0D;&#x0A;"
-                                       Outputs="config.h"
+                                       Description="Copy $(InputPath) $(IntDir)\config.h"
+                                       CommandLine="copy $(InputPath) $(IntDir)\config.h&#x0D;&#x0A;"
+                                       Outputs="$(IntDir)\config.h"
                                />
                        </FileConfiguration>
                        <FileConfiguration
                                >
                                <Tool
                                        Name="VCCustomBuildTool"
-                                       Description="Copy $(InputPath) config.h"
-                                       CommandLine="copy $(InputPath) config.h&#x0D;&#x0A;"
-                                       Outputs="config.h"
+                                       Description="Copy $(InputPath) $(IntDir)\config.h"
+                                       CommandLine="copy $(InputPath) $(IntDir)\config.h&#x0D;&#x0A;"
+                                       Outputs="$(IntDir)\config.h"
                                />
                        </FileConfiguration>
                </File>
                        RelativePath="..\configure.in"
                        >
                </File>
+               <File
+                       RelativePath="..\csmisas.h"
+                       >
+               </File>
                <File
                        RelativePath="..\dev_ata_cmd_set.cpp"
                        >
                        RelativePath="..\drivedb.h"
                        >
                </File>
-               <File
-                       RelativePath="..\extern.h"
-                       >
-               </File>
                <File
                        RelativePath="..\INSTALL"
                        >
                        RelativePath="..\Makefile.am"
                        >
                </File>
+               <File
+                       RelativePath="..\megaraid.h"
+                       >
+                       <FileConfiguration
+                               Name="Debug|Win32"
+                               ExcludedFromBuild="true"
+                               >
+                               <Tool
+                                       Name="VCCustomBuildTool"
+                               />
+                       </FileConfiguration>
+                       <FileConfiguration
+                               Name="Release|Win32"
+                               ExcludedFromBuild="true"
+                               >
+                               <Tool
+                                       Name="VCCustomBuildTool"
+                               />
+                       </FileConfiguration>
+               </File>
                <File
                        RelativePath="..\NEWS"
                        >
                                        Name="VCCLCompilerTool"
                                />
                        </FileConfiguration>
+                       <FileConfiguration
+                               Name="Release|Win32"
+                               ExcludedFromBuild="true"
+                               >
+                               <Tool
+                                       Name="VCCLCompilerTool"
+                               />
+                       </FileConfiguration>
                </File>
                <File
                        RelativePath="..\scsiprint.h"
                                        Name="VCCustomBuildTool"
                                />
                        </FileConfiguration>
+                       <FileConfiguration
+                               Name="Release|Win32"
+                               ExcludedFromBuild="true"
+                               >
+                               <Tool
+                                       Name="VCCustomBuildTool"
+                               />
+                       </FileConfiguration>
                </File>
                <File
                        RelativePath="..\smartctl.8.in"
index 73e1230d1f7a8edb538984d08d61c1435a20a0e9..08019fec17fe8dcf0ec9cf75d7dcbe5b150f911d 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2004-8 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2004-10 Christian Franke <smartmontools-support@lists.sourceforge.net>
  *
  * 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
@@ -16,7 +16,7 @@
  *
  */
 
-static char rcsid[] = "$Id: syslogevt.c,v 1.5 2008/03/04 22:09:48 ballen4705 Exp $";
+static char rcsid[] = "$Id: syslogevt.c 3257 2011-02-14 22:19:42Z manfred99 $";
 
 #include <stdio.h>
 #include <string.h>
@@ -25,15 +25,17 @@ static char rcsid[] = "$Id: syslogevt.c,v 1.5 2008/03/04 22:09:48 ballen4705 Exp
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 
-#ifdef _DEBUG
 #include "syslogevt.h"
-#endif
+// Compile time check for Message Ids, see also syslog_win32.cpp
+typedef assert_msg_syslog   [MSG_SYSLOG    ==  0 ? 1 : -1];
+typedef assert_msg_syslog_01[MSG_SYSLOG_01 ==  1 ? 1 : -1];
+typedef assert_msg_syslog_10[MSG_SYSLOG_10 == 10 ? 1 : -1];
 
 
 static int usage()
 {
        puts(
-               "syslogevt $Revision: 1.5 $ Copyright (C) 2004-8 Christian Franke\n"
+               "syslogevt $Revision: 3257 $ Copyright (C) 2004-10 Christian Franke\n"
                "Home page is http://smartmontools.sourceforge.net/\n"
                "\n"
                "Usage: syslogevt [-ru] name [ident ...]\n"
@@ -67,12 +69,6 @@ main(int argc, char ** argv)
        const char * ident;
        FILE * f1, * f2;
 
-#ifdef _DEBUG
-       if (!(MSG_SYSLOG == 0 && MSG_SYSLOG_01 == 1 && MSG_SYSLOG_10 == 10)) {
-               puts("Internal error: MSG_SYSLOG_n != n"); return 1;
-       }
-#endif
-
        if (argc < 2)
                return usage();
 
@@ -106,7 +102,7 @@ main(int argc, char ** argv)
                perror(name1); return 1;
        }
        if (!(f2 = fopen(name2, "w"))) {
-               perror(name2); unlink(name1); return 1;
+               perror(name2); fclose(f1); unlink(name1); return 1;
        }
 
        fputs("REGEDIT4\n\n", f1);
index a1d421dce490cc9595c74c1fac5a614d86369306..c477ec668f9f83528ba7fae335bcfb3194744d83 100644 (file)
@@ -3,7 +3,7 @@
 ; *
 ; * Home page of code is: http://smartmontools.sourceforge.net
 ; *
-; * Copyright (C) 2004-8 Christian Franke <smartmontools-support@lists.sourceforge.net>
+; * Copyright (C) 2004-10 Christian Franke <smartmontools-support@lists.sourceforge.net>
 ; *
 ; * 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
 ; *
 ; */
 ;
-;// $Id: syslogevt.mc,v 1.5 2008/03/04 22:09:48 ballen4705 Exp $
+;// $Id: syslogevt.mc 3166 2010-09-24 19:43:31Z chrfranke $
 ;
-;// Use message compiler "mc" to generate
+;// Use message compiler "mc" or "windmc" to generate
 ;//   syslogevt.rc, syslogevt.h, msg00001.bin
 ;// from this file.
 ;// MSG_SYSLOG in syslogmsg.h must be zero
 ;// MSG_SYSLOG_nn must be == nn
 ;
-;
+;// MS and binutils message compiler defaults for FacilityNames differ:
+;// mc:     Application = 0x000
+;// windmc: Application = 0xfff
+FacilityNames = (Application = 0x000)
 
 MessageId=0x0
 Severity=Success
diff --git a/os_win32/update-smart-drivedb.nsi b/os_win32/update-smart-drivedb.nsi
new file mode 100644 (file)
index 0000000..11c9243
--- /dev/null
@@ -0,0 +1,141 @@
+;
+; smartmontools drive database update NSIS script
+;
+; Home page of code is: http://smartmontools.sourceforge.net
+;
+; Copyright (C) 2011 Christian Franke <smartmontools-support@lists.sourceforge.net>
+;
+; 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 Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; You should have received a copy of the GNU General Public License
+; (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
+;
+; $Id: update-smart-drivedb.nsi 3296 2011-03-16 22:17:51Z chrfranke $
+;
+
+
+;--------------------------------------------------------------------
+; Command line arguments:
+; makensis -DBRANCH=<svn-branch-name> update-smart-drivedb.nsi
+
+!include "FileFunc.nsh"
+
+Name "update-smart-drivedb"
+Caption "Update smartmontools drivedb.h"
+OutFile "update-smart-drivedb.exe"
+
+SetCompressor /solid lzma
+
+XPStyle on
+InstallColors /windows
+
+Page instfiles
+
+Section ""
+
+  SetOutPath $INSTDIR
+
+!ifdef BRANCH
+  StrCpy $0 "branches/${BRANCH}"
+  Push $0
+  Call Download
+  IfErrors 0 endload
+!endif
+
+  StrCpy $0 "trunk"
+  Push $0
+  Call Download
+  IfErrors 0 endload
+    MessageBox MB_OK "Download failed"
+    Abort "Download failed"
+  endload:
+
+  ; Check syntax
+  Delete "drivedb.h.error"
+  IfFileExists "smartctl-nc.exe" 0 endsyntax
+    ExecWait '.\smartctl-nc.exe -B drivedb.h.new -P showall' $1
+    StrCmp $1 "0" endsyntax
+      Rename "drivedb.h.new" "drivedb.h.error"
+      MessageBox MB_OK "drivedb.h.error: rejected by smartctl, probably no longer compatible"
+      Abort "drivedb.h.error: rejected by smartctl, probably no longer compatible"
+  endsyntax:
+
+  ; Keep old file if identical
+  Delete "drivedb.h.lastcheck"
+  IfFileExists "drivedb.h" 0 endcomp
+    Call Cmp
+    IfErrors changed 0
+      DetailPrint "drivedb.h is already up to date"
+      MessageBox MB_OK "$INSTDIR\drivedb.h is already up to date"
+      Delete "drivedb.h.new"
+      DetailPrint "Create file: drivedb.h.lastcheck"
+      FileOpen $1 "drivedb.h.lastcheck" w
+      FileClose $1
+      Return
+    changed:
+    Delete "drivedb.h.old"
+    Rename "drivedb.h" "drivedb.h.old"
+
+  endcomp:
+  Rename "drivedb.h.new" "drivedb.h"
+  MessageBox MB_OK "$INSTDIR\drivedb.h updated from $0"
+
+SectionEnd
+
+Function .onInit
+  ; Install in same directory
+  ${GetExePath} $INSTDIR
+FunctionEnd
+
+; Download from branch or trunk on stack, SetErrors on error
+Function Download
+  Pop $R0
+  DetailPrint "Download from $R0"
+
+  ; Trac repository browser (does not return HTTP 404 errors)
+  StrCpy $R1 "http://sourceforge.net/apps/trac/smartmontools/export/HEAD/$R0/smartmontools/drivedb.h"
+  ; ViewVC repository browser (does not return ContentLength required for NSISdl::download)
+  ;StrCpy $R1 "http://smartmontools.svn.sourceforge.net/viewvc/smartmontools/$R0/smartmontools/drivedb.h?revision=HEAD"
+  DetailPrint "($R1)"
+
+  NSISdl::download $R1 "drivedb.h.new"
+  Pop $R0
+  DetailPrint "Download: $R0"
+  ClearErrors
+  StrCmp $R0 "success" 0 err
+
+  ; File must start with comment
+  FileOpen $R0 "drivedb.h.new" r
+  FileReadByte $R0 $R1
+  FileClose $R0
+  ClearErrors
+  StrCmp $R1 "47" 0 +2
+    Return
+  DetailPrint "drivedb.h.new: syntax error ($R1)"
+
+err:
+  Delete "drivedb.h.new"
+  SetErrors
+FunctionEnd
+
+; Compare drivedb.h drivedb.h.new, SetErrors if different
+; TODO: ignore differences in Id string
+Function Cmp
+    ClearErrors
+    FileOpen $R0 "drivedb.h" r
+    FileOpen $R1 "drivedb.h.new" r
+    readloop:
+      FileRead $R0 $R2
+      FileRead $R1 $R3
+      StrCmp $R2 $R3 0 +2
+    IfErrors 0 readloop
+    FileClose $R0
+    FileClose $R1
+    ClearErrors
+    StrCmp $R2 $R3 0 +2
+      Return
+    SetErrors
+FunctionEnd
diff --git a/os_win32/wbemcli_small.h b/os_win32/wbemcli_small.h
new file mode 100644 (file)
index 0000000..9732890
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * os_win32/wbemcli_small.h
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * This file was extracted from wbemcli.h of the w64 mingw-runtime package
+ * (http://mingw-w64.sourceforge.net/). See original copyright below.
+ */
+
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the w64 mingw-runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error This stub requires an updated version of <rpcndr.h>
+#endif
+
+#include "windows.h"
+#include "ole2.h"
+
+#ifndef __wbemcli_h__
+#define __wbemcli_h__
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#error C++ interfaces only
+#endif
+
+typedef struct IWbemQualifierSet IWbemQualifierSet;
+typedef struct IWbemObjectSink IWbemObjectSink;
+typedef struct IEnumWbemClassObject IEnumWbemClassObject;
+typedef struct IWbemCallResult IWbemCallResult;
+typedef struct IWbemContext IWbemContext;
+
+extern "C" {
+
+  typedef enum tag_WBEM_GENERIC_FLAG_TYPE {
+    WBEM_FLAG_RETURN_IMMEDIATELY = 0x10,WBEM_FLAG_RETURN_WBEM_COMPLETE = 0,WBEM_FLAG_BIDIRECTIONAL = 0,WBEM_FLAG_FORWARD_ONLY = 0x20,
+    WBEM_FLAG_NO_ERROR_OBJECT = 0x40,WBEM_FLAG_RETURN_ERROR_OBJECT = 0,WBEM_FLAG_SEND_STATUS = 0x80,WBEM_FLAG_DONT_SEND_STATUS = 0,
+    WBEM_FLAG_ENSURE_LOCATABLE = 0x100,WBEM_FLAG_DIRECT_READ = 0x200,WBEM_FLAG_SEND_ONLY_SELECTED = 0,WBEM_RETURN_WHEN_COMPLETE = 0,
+    WBEM_RETURN_IMMEDIATELY = 0x10,WBEM_MASK_RESERVED_FLAGS = 0x1f000,WBEM_FLAG_USE_AMENDED_QUALIFIERS = 0x20000,
+    WBEM_FLAG_STRONG_VALIDATION = 0x100000
+  } WBEM_GENERIC_FLAG_TYPE;
+
+  typedef long CIMTYPE;
+
+  struct IWbemClassObject : public IUnknown {
+  public:
+    virtual HRESULT WINAPI GetQualifierSet(IWbemQualifierSet **ppQualSet) = 0;
+    virtual HRESULT WINAPI Get(LPCWSTR wszName,long lFlags,VARIANT *pVal,CIMTYPE *pType,long *plFlavor) = 0;
+    virtual HRESULT WINAPI Put(LPCWSTR wszName,long lFlags,VARIANT *pVal,CIMTYPE Type) = 0;
+    virtual HRESULT WINAPI Delete(LPCWSTR wszName) = 0;
+    virtual HRESULT WINAPI GetNames(LPCWSTR wszQualifierName,long lFlags,VARIANT *pQualifierVal,SAFEARRAY **pNames) = 0;
+    virtual HRESULT WINAPI BeginEnumeration(long lEnumFlags) = 0;
+    virtual HRESULT WINAPI Next(long lFlags,BSTR *strName,VARIANT *pVal,CIMTYPE *pType,long *plFlavor) = 0;
+    virtual HRESULT WINAPI EndEnumeration(void) = 0;
+    virtual HRESULT WINAPI GetPropertyQualifierSet(LPCWSTR wszProperty,IWbemQualifierSet **ppQualSet) = 0;
+    virtual HRESULT WINAPI Clone(IWbemClassObject **ppCopy) = 0;
+    virtual HRESULT WINAPI GetObjectText(long lFlags,BSTR *pstrObjectText) = 0;
+    virtual HRESULT WINAPI SpawnDerivedClass(long lFlags,IWbemClassObject **ppNewClass) = 0;
+    virtual HRESULT WINAPI SpawnInstance(long lFlags,IWbemClassObject **ppNewInstance) = 0;
+    virtual HRESULT WINAPI CompareTo(long lFlags,IWbemClassObject *pCompareTo) = 0;
+    virtual HRESULT WINAPI GetPropertyOrigin(LPCWSTR wszName,BSTR *pstrClassName) = 0;
+    virtual HRESULT WINAPI InheritsFrom(LPCWSTR strAncestor) = 0;
+    virtual HRESULT WINAPI GetMethod(LPCWSTR wszName,long lFlags,IWbemClassObject **ppInSignature,IWbemClassObject **ppOutSignature) = 0;
+    virtual HRESULT WINAPI PutMethod(LPCWSTR wszName,long lFlags,IWbemClassObject *pInSignature,IWbemClassObject *pOutSignature) = 0;
+    virtual HRESULT WINAPI DeleteMethod(LPCWSTR wszName) = 0;
+    virtual HRESULT WINAPI BeginMethodEnumeration(long lEnumFlags) = 0;
+    virtual HRESULT WINAPI NextMethod(long lFlags,BSTR *pstrName,IWbemClassObject **ppInSignature,IWbemClassObject **ppOutSignature) = 0;
+    virtual HRESULT WINAPI EndMethodEnumeration(void) = 0;
+    virtual HRESULT WINAPI GetMethodQualifierSet(LPCWSTR wszMethod,IWbemQualifierSet **ppQualSet) = 0;
+    virtual HRESULT WINAPI GetMethodOrigin(LPCWSTR wszMethodName,BSTR *pstrClassName) = 0;
+  };
+
+  struct IWbemServices : public IUnknown {
+  public:
+    virtual HRESULT WINAPI OpenNamespace(const BSTR strNamespace,long lFlags,IWbemContext *pCtx,IWbemServices **ppWorkingNamespace,IWbemCallResult **ppResult) = 0;
+    virtual HRESULT WINAPI CancelAsyncCall(IWbemObjectSink *pSink) = 0;
+    virtual HRESULT WINAPI QueryObjectSink(long lFlags,IWbemObjectSink **ppResponseHandler) = 0;
+    virtual HRESULT WINAPI GetObject(const BSTR strObjectPath,long lFlags,IWbemContext *pCtx,IWbemClassObject **ppObject,IWbemCallResult **ppCallResult) = 0;
+    virtual HRESULT WINAPI GetObjectAsync(const BSTR strObjectPath,long lFlags,IWbemContext *pCtx,IWbemObjectSink *pResponseHandler) = 0;
+    virtual HRESULT WINAPI PutClass(IWbemClassObject *pObject,long lFlags,IWbemContext *pCtx,IWbemCallResult **ppCallResult) = 0;
+    virtual HRESULT WINAPI PutClassAsync(IWbemClassObject *pObject,long lFlags,IWbemContext *pCtx,IWbemObjectSink *pResponseHandler) = 0;
+    virtual HRESULT WINAPI DeleteClass(const BSTR strClass,long lFlags,IWbemContext *pCtx,IWbemCallResult **ppCallResult) = 0;
+    virtual HRESULT WINAPI DeleteClassAsync(const BSTR strClass,long lFlags,IWbemContext *pCtx,IWbemObjectSink *pResponseHandler) = 0;
+    virtual HRESULT WINAPI CreateClassEnum(const BSTR strSuperclass,long lFlags,IWbemContext *pCtx,IEnumWbemClassObject **ppEnum) = 0;
+    virtual HRESULT WINAPI CreateClassEnumAsync(const BSTR strSuperclass,long lFlags,IWbemContext *pCtx,IWbemObjectSink *pResponseHandler) = 0;
+    virtual HRESULT WINAPI PutInstance(IWbemClassObject *pInst,long lFlags,IWbemContext *pCtx,IWbemCallResult **ppCallResult) = 0;
+    virtual HRESULT WINAPI PutInstanceAsync(IWbemClassObject *pInst,long lFlags,IWbemContext *pCtx,IWbemObjectSink *pResponseHandler) = 0;
+    virtual HRESULT WINAPI DeleteInstance(const BSTR strObjectPath,long lFlags,IWbemContext *pCtx,IWbemCallResult **ppCallResult) = 0;
+    virtual HRESULT WINAPI DeleteInstanceAsync(const BSTR strObjectPath,long lFlags,IWbemContext *pCtx,IWbemObjectSink *pResponseHandler) = 0;
+    virtual HRESULT WINAPI CreateInstanceEnum(const BSTR strFilter,long lFlags,IWbemContext *pCtx,IEnumWbemClassObject **ppEnum) = 0;
+    virtual HRESULT WINAPI CreateInstanceEnumAsync(const BSTR strFilter,long lFlags,IWbemContext *pCtx,IWbemObjectSink *pResponseHandler) = 0;
+    virtual HRESULT WINAPI ExecQuery(const BSTR strQueryLanguage,const BSTR strQuery,long lFlags,IWbemContext *pCtx,IEnumWbemClassObject **ppEnum) = 0;
+    virtual HRESULT WINAPI ExecQueryAsync(const BSTR strQueryLanguage,const BSTR strQuery,long lFlags,IWbemContext *pCtx,IWbemObjectSink *pResponseHandler) = 0;
+    virtual HRESULT WINAPI ExecNotificationQuery(const BSTR strQueryLanguage,const BSTR strQuery,long lFlags,IWbemContext *pCtx,IEnumWbemClassObject **ppEnum) = 0;
+    virtual HRESULT WINAPI ExecNotificationQueryAsync(const BSTR strQueryLanguage,const BSTR strQuery,long lFlags,IWbemContext *pCtx,IWbemObjectSink *pResponseHandler) = 0;
+    virtual HRESULT WINAPI ExecMethod(const BSTR strObjectPath,const BSTR strMethodName,long lFlags,IWbemContext *pCtx,IWbemClassObject *pInParams,IWbemClassObject **ppOutParams,IWbemCallResult **ppCallResult) = 0;
+    virtual HRESULT WINAPI ExecMethodAsync(const BSTR strObjectPath,const BSTR strMethodName,long lFlags,IWbemContext *pCtx,IWbemClassObject *pInParams,IWbemObjectSink *pResponseHandler) = 0;
+  };
+
+  EXTERN_C const IID IID_IWbemLocator;
+  struct IWbemLocator : public IUnknown {
+  public:
+    virtual HRESULT WINAPI ConnectServer(const BSTR strNetworkResource,const BSTR strUser,const BSTR strPassword,const BSTR strLocale,long lSecurityFlags,const BSTR strAuthority,IWbemContext *pCtx,IWbemServices **ppNamespace) = 0;
+  };
+
+  struct IEnumWbemClassObject : public IUnknown {
+  public:
+    virtual HRESULT WINAPI Reset(void) = 0;
+    virtual HRESULT WINAPI Next(long lTimeout,ULONG uCount,IWbemClassObject **apObjects,ULONG *puReturned) = 0;
+    virtual HRESULT WINAPI NextAsync(ULONG uCount,IWbemObjectSink *pSink) = 0;
+    virtual HRESULT WINAPI Clone(IEnumWbemClassObject **ppEnum) = 0;
+    virtual HRESULT WINAPI Skip(long lTimeout,ULONG nCount) = 0;
+  };
+
+  EXTERN_C const CLSID CLSID_WbemLocator;
+
+  typedef enum tag_WBEM_CONNECT_OPTIONS {
+    WBEM_FLAG_CONNECT_REPOSITORY_ONLY = 0x40,WBEM_FLAG_CONNECT_USE_MAX_WAIT = 0x80,WBEM_FLAG_CONNECT_PROVIDERS = 0x100
+  } WBEM_CONNECT_OPTIONS;
+
+}
+#endif
diff --git a/os_win32/wmiquery.cpp b/os_win32/wmiquery.cpp
new file mode 100644 (file)
index 0000000..5181f92
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * os_win32/wmiquery.cpp
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2011 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ *
+ * 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 Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "config.h"
+#define WINVER 0x0400
+#define _WIN32_WINNT WINVER
+
+#include "wmiquery.h"
+
+#include <stdio.h>
+
+const char * wmiquery_cpp_cvsid = "$Id: wmiquery.cpp 3243 2011-01-19 20:03:47Z chrfranke $"
+  WMIQUERY_H_CVSID;
+
+
+/////////////////////////////////////////////////////////////////////////////
+// com_bstr
+
+com_bstr::com_bstr(const char * str)
+: m_bstr(0)
+{
+  int sz = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, (LPWSTR)0, 0);
+  if (sz <= 0)
+    return;
+  m_bstr = SysAllocStringLen((OLECHAR*)0, sz-1);
+  if (!m_bstr)
+    return; // throw std::bad_alloc
+  MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, m_bstr, sz);
+}
+
+bool com_bstr::to_str(const BSTR & bstr, std::string & str)
+{
+  if (!bstr)
+    return false;
+  int sz = WideCharToMultiByte(CP_ACP, 0, bstr, -1, (LPSTR)0, 0, (LPCSTR)0, (LPBOOL)0);
+  if (sz <= 0)
+    return false;
+  char * buf = new char[sz];
+  WideCharToMultiByte(CP_ACP, 0, bstr, -1, buf, sz, (LPCSTR)0, (LPBOOL)0);
+  str = buf;
+  delete [] buf;
+  return true;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// wbem_object
+
+std::string wbem_object::get_str(const char * name) /*const*/
+{
+  std::string s;
+  if (!m_intf)
+    return s;
+
+  VARIANT var; VariantInit(&var);
+  if (m_intf->Get(com_bstr(name), 0L, &var, (CIMTYPE*)0, (long*)0) /* != WBEM_S_NO_ERROR */)
+    return s;
+
+  if (var.vt == VT_BSTR)
+    com_bstr::to_str(var.bstrVal, s);
+  VariantClear(&var);
+  return s;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// wbem_enumerator
+
+bool wbem_enumerator::next(wbem_object & obj)
+{
+  if (!m_intf)
+    return false;
+
+  ULONG n = 0;
+  HRESULT rc = m_intf->Next(5000 /*5s*/, 1 /*count*/, obj.m_intf.replace(), &n);
+  if (FAILED(rc) || n != 1)
+    return false;
+  return true;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// wbem_services
+
+const CLSID xCLSID_WbemLocator = {0x4590f811, 0x1d3a, 0x11d0, {0x89, 0x1f, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24}};
+const IID   xIID_IWbemLocator  = {0xdc12a687, 0x737f, 0x11cf, {0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24}};
+
+bool wbem_services::connect()
+{
+  // Init COM during first call.
+  static HRESULT init_rc = -1;
+  static bool init_tried = false;
+  if (!init_tried) {
+    init_tried = true;
+    init_rc = CoInitialize((LPVOID)0);
+  }
+  if (!(init_rc == S_OK  || init_rc == S_FALSE))
+    return false;
+
+  /// Create locator.
+  com_intf_ptr<IWbemLocator> locator;
+  HRESULT rc = CoCreateInstance(xCLSID_WbemLocator, (LPUNKNOWN)0,
+    CLSCTX_INPROC_SERVER, xIID_IWbemLocator, (LPVOID*)locator.replace());
+  if (FAILED(rc))
+    return false;
+
+  // Set timeout flag if supported.
+  long flags = 0;
+  OSVERSIONINFOA ver; ver.dwOSVersionInfoSize = sizeof(ver);
+  if (GetVersionExA(&ver) && ver.dwPlatformId == VER_PLATFORM_WIN32_NT
+    && (    ver.dwMajorVersion >= 6 // Vista
+        || (ver.dwMajorVersion == 5 && ver.dwMinorVersion >= 1))) // XP
+    flags = WBEM_FLAG_CONNECT_USE_MAX_WAIT; // return in 2min or less
+
+  // Connect to local server.
+  rc = locator->ConnectServer(com_bstr("\\\\.\\root\\cimv2"),
+    (BSTR)0, (BSTR)0, (BSTR)0, // User, Password, Locale
+    flags, (BSTR)0, (IWbemContext*)0, m_intf.replace());
+  if (FAILED(rc))
+    return false;
+
+  // Set authentication information,
+  rc = CoSetProxyBlanket(m_intf.get(), RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+    (OLECHAR*)0, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE,
+    (RPC_AUTH_IDENTITY_HANDLE*)0, EOAC_NONE);
+  if (FAILED(rc)) {
+    m_intf.reset();
+    return false;
+  }
+
+  return true;
+}
+
+bool wbem_services::vquery(wbem_enumerator & result, const char * qstr, va_list args) /*const*/
+{
+  if (!m_intf)
+    return false;
+
+  char qline[1024];
+  vsnprintf(qline, sizeof(qline), qstr, args);
+  qline[sizeof(qline)-1] = 0;
+
+  HRESULT rc = m_intf->ExecQuery(
+    com_bstr("WQL"), com_bstr(qline),
+    WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
+    (IWbemContext*)0, result.m_intf.replace());
+  if (FAILED(rc))
+    return false;
+
+  return true;
+}
+
+bool wbem_services::vquery1(wbem_object & obj, const char * qstr, va_list args) /*const*/
+{
+  wbem_enumerator result;
+  if (!vquery(result, qstr, args))
+    return false;
+
+  if (!result.next(obj))
+    return false;
+
+  wbem_object peek;
+  if (result.next(peek))
+    return false;
+
+  return true;
+}
+
+bool wbem_services::query(wbem_enumerator & result, const char * qstr, ...) /*const*/
+{
+  va_list args; va_start(args, qstr);
+  bool ok = vquery(result, qstr, args);
+  va_end(args);
+  return ok;
+}
+
+bool wbem_services::query1(wbem_object & obj, const char * qstr, ...) /*const*/
+{
+  va_list args; va_start(args, qstr);
+  bool ok = vquery1(obj, qstr, args);
+  va_end(args);
+  return ok;
+}
diff --git a/os_win32/wmiquery.h b/os_win32/wmiquery.h
new file mode 100644 (file)
index 0000000..13dd988
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * os_win32/wmiquery.h
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2011 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ *
+ * 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 Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef WMIQUERY_H
+#define WMIQUERY_H
+
+#define WMIQUERY_H_CVSID "$Id: wmiquery.h 3243 2011-01-19 20:03:47Z chrfranke $"
+
+#ifdef HAVE_WBEMCLI_H
+#include <wbemcli.h>
+#else
+#include "wbemcli_small.h"
+#endif
+
+#include <string>
+
+#if !defined(__GNUC__) && !defined(__attribute__)
+#define __attribute__(x)  /**/
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// com_bstr
+
+/// Wrapper class for COM BSTR
+class com_bstr
+{
+public:
+  /// Construct from string.
+  com_bstr(const char * str);
+
+  /// Destructor frees BSTR.
+  ~com_bstr()
+    { SysFreeString(m_bstr); }
+
+  /// Implicit conversion to BSTR.
+  operator BSTR()
+    { return m_bstr; }
+
+  /// Convert BSTR back to std::string.
+  static bool to_str(const BSTR & bstr, std::string & str);
+
+private:
+  BSTR m_bstr;
+
+  com_bstr(const com_bstr &);
+  void operator=(const com_bstr &);
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+// com_intf_ptr
+
+/// Wrapper class for COM Interface pointer
+template <class T>
+class com_intf_ptr
+{
+public:
+  /// Construct empty object
+  com_intf_ptr()
+    : m_ptr(0) { }
+
+  /// Destructor releases the interface.
+  ~com_intf_ptr()
+    { reset(); }
+
+  /// Release interface and clear the pointer.
+  void reset()
+    {
+      if (m_ptr) {
+        m_ptr->Release(); m_ptr = 0;
+      }
+    }
+
+  /// Return the pointer.
+  T * get()
+    { return m_ptr; }
+
+  /// Pointer dereferencing.
+  T * operator->()
+    { return m_ptr; }
+
+  /// Return address of pointer for replacement.
+  T * * replace()
+    { reset(); return &m_ptr; }
+
+  /// For (ptr != 0) check.
+  operator bool() const
+    { return !!m_ptr; }
+
+  /// For (ptr == 0) check.
+  bool operator!() const
+    { return !m_ptr; }
+
+private:
+  T * m_ptr;
+
+  com_intf_ptr(const com_intf_ptr &);
+  void operator=(const com_intf_ptr &);
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+// wbem_object
+
+class wbem_enumerator;
+
+/// Wrapper class for IWbemClassObject
+class wbem_object
+{
+public:
+  /// Get string representation.
+  std::string get_str(const char * name) /*const*/;
+
+private:
+  /// Contents is set by wbem_enumerator.
+  friend class wbem_enumerator;
+  com_intf_ptr<IWbemClassObject> m_intf;
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+// wbem_enumerator
+
+class wbem_services;
+
+/// Wrapper class for IEnumWbemClassObject
+class wbem_enumerator
+{
+public:
+  /// Get next object, return false if none or error.
+  bool next(wbem_object & obj);
+
+private:
+  /// Contents is set by wbem_services.
+  friend class wbem_services;
+  com_intf_ptr<IEnumWbemClassObject> m_intf;
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+// wbem_services
+
+/// Wrapper class for IWbemServices
+class wbem_services
+{
+public:
+  /// Connect to service, return false on error.
+  bool connect();
+
+  /// Execute query, get result list.
+  /// Return false on error.
+  bool vquery(wbem_enumerator & result, const char * qstr, va_list args) /*const*/;
+
+  /// Execute query, get single result object.
+  /// Return false on error or result size != 1.
+  bool vquery1(wbem_object & obj, const char * qstr, va_list args) /*const*/;
+
+  /// Version of vquery() with printf() formatting.
+  bool query(wbem_enumerator & result, const char * qstr, ...) /*const*/
+       __attribute__ ((format (printf, 3, 4)));
+
+  /// Version of vquery1() with printf() formatting.
+  bool query1(wbem_object & obj, const char * qstr, ...) /*const*/
+       __attribute__ ((format (printf, 3, 4)));
+
+private:
+  com_intf_ptr<IWbemServices> m_intf;
+};
+
+#endif // WMIQUERY_H
index 2b876932907100e921cdc30f20a43fa458fba352..575161e05ec1b108b6115320c541b3eeba23acad 100644 (file)
 #include <string.h>
 #include <stdlib.h>
 #include <ctype.h>
+#include <errno.h>
 
 #include "config.h"
 #include "int64.h"
-#include "extern.h"
 #include "scsicmds.h"
 #include "atacmds.h" // ataReadHDIdentity()
 #include "knowndrives.h" // lookup_usb_device()
 #include "dev_ata_cmd_set.h" // ata_device_with_command_set
 #include "dev_tunnelled.h" // tunnelled_device<>
 
-const char * scsiata_cpp_cvsid = "$Id: scsiata.cpp 3095 2010-04-30 12:33:27Z dpgilbert $";
-
-/* for passing global control variables */
-extern smartmonctrl *con;
+const char * scsiata_cpp_cvsid = "$Id: scsiata.cpp 3258 2011-02-14 22:31:01Z manfred99 $";
 
 /* This is a slightly stretched SCSI sense "descriptor" format header.
    The addition is to allow the 0x70 and 0x71 response codes. The idea
@@ -339,7 +336,7 @@ bool sat_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
 
     scsi_device * scsidev = get_tunnel_dev();
     if (!scsidev->scsi_pass_through(&io_hdr)) {
-        if (con->reportscsiioctl > 0)
+        if (scsi_debugmode > 0)
             pout("sat_device::ata_pass_through: scsi_pass_through() failed, "
                  "errno=%d [%s]\n", scsidev->get_errno(), scsidev->get_errmsg());
         return set_err(scsidev->get_err());
@@ -363,10 +360,10 @@ bool sat_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
         scsi_do_sense_disect(&io_hdr, &sinfo);
         status = scsiSimpleSenseFilter(&sinfo);
         if (0 != status) {
-            if (con->reportscsiioctl > 0) {
+            if (scsi_debugmode > 0) {
                 pout("sat_device::ata_pass_through: scsi error: %s\n",
                      scsiErrString(status));
-                if (ardp && (con->reportscsiioctl > 1)) {
+                if (ardp && (scsi_debugmode > 1)) {
                     pout("Values from ATA Return Descriptor are:\n");
                     dStrHex((const char *)ardp, ard_len, 1);
                 }
@@ -379,7 +376,7 @@ bool sat_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
     if (ck_cond) {     /* expecting SAT specific sense data */
         if (have_sense) {
             if (ardp) {
-                if (con->reportscsiioctl > 1) {
+                if (scsi_debugmode > 1) {
                     pout("Values from ATA Return Descriptor are:\n");
                     dStrHex((const char *)ardp, ard_len, 1);
                 }
@@ -412,7 +409,7 @@ bool sat_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
                 (0 == ssh.asc) &&
                 (SCSI_ASCQ_ATA_PASS_THROUGH == ssh.ascq)) {
                 if (ardp) {
-                    if (con->reportscsiioctl > 0) {
+                    if (scsi_debugmode > 0) {
                         pout("Values from ATA Return Descriptor are:\n");
                         dStrHex((const char *)ardp, ard_len, 1);
                     }
@@ -524,7 +521,7 @@ static bool scsi_pass_through_and_check(scsi_device * scsidev,  scsi_cmnd_io * i
 
   // Run cmd
   if (!scsidev->scsi_pass_through(iop)) {
-    if (con->reportscsiioctl > 0)
+    if (scsi_debugmode > 0)
       pout("%sscsi_pass_through() failed, errno=%d [%s]\n",
            msg, scsidev->get_errno(), scsidev->get_errmsg());
     return false;
@@ -535,7 +532,7 @@ static bool scsi_pass_through_and_check(scsi_device * scsidev,  scsi_cmnd_io * i
   scsi_do_sense_disect(iop, &sinfo);
   int err = scsiSimpleSenseFilter(&sinfo);
   if (err) {
-    if (con->reportscsiioctl > 0)
+    if (scsi_debugmode > 0)
       pout("%sscsi error: %s\n", msg, scsiErrString(err));
     return scsidev->set_err(EIO, "scsi error %s", scsiErrString(err));
   }
@@ -743,7 +740,7 @@ int usbcypress_device::ata_command_interface(smart_command_set command, int sele
 
     scsi_device * scsidev = get_tunnel_dev();
     if (!scsidev->scsi_pass_through(&io_hdr)) {
-        if (con->reportscsiioctl > 0)
+        if (scsi_debugmode > 0)
             pout("usbcypress_device::ata_command_interface: scsi_pass_through() failed, "
                  "errno=%d [%s]\n", scsidev->get_errno(), scsidev->get_errmsg());
         set_err(scsidev->get_err());
@@ -785,7 +782,7 @@ int usbcypress_device::ata_command_interface(smart_command_set command, int sele
 
 
         if (!scsidev->scsi_pass_through(&io_hdr)) {
-            if (con->reportscsiioctl > 0)
+            if (scsi_debugmode > 0)
                 pout("usbcypress_device::ata_command_interface: scsi_pass_through() failed, "
                      "errno=%d [%s]\n", scsidev->get_errno(), scsidev->get_errmsg());
             set_err(scsidev->get_err());
@@ -799,7 +796,7 @@ int usbcypress_device::ata_command_interface(smart_command_set command, int sele
         }
 
 
-        if (con->reportscsiioctl > 1) {
+        if (scsi_debugmode > 1) {
             pout("Values from ATA Return Descriptor are:\n");
             dStrHex((const char *)ardp, ard_len, 1);
         }
index 3eabe4b46b49961aead9b859ee2ee73fa501b85e..fb4d33272e24b4d526edf1274d1f4449d5cdd592 100644 (file)
 
 #include <stdio.h>
 #include <string.h>
+#include <errno.h>
 
 #include "config.h"
 #include "int64.h"
-#include "extern.h"
 #include "scsicmds.h"
 #include "atacmds.h" // FIXME: for smart_command_set only
 #include "dev_interface.h"
 #include "utility.h"
 
-const char *scsicmds_c_cvsid="$Id: scsicmds.cpp 3096 2010-04-30 14:32:49Z chrfranke $"
-CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
+const char *scsicmds_c_cvsid="$Id: scsicmds.cpp 3258 2011-02-14 22:31:01Z manfred99 $"
+  SCSICMDS_H_CVSID;
 
-/* for passing global control variables */
-extern smartmonctrl *con;
+// Print SCSI debug messages?
+unsigned char scsi_debugmode = 0;
 
 /* output binary in hex and optionally ascii */
 void dStrHex(const char* str, int len, int no_ascii)
@@ -120,23 +120,33 @@ static struct scsi_opcode_name opcode_name_arr[] = {
     {INQUIRY, "inquiry"},                       /* 0x12 */
     {MODE_SELECT, "mode select(6)"},            /* 0x15 */
     {MODE_SENSE, "mode sense(6)"},              /* 0x1a */
+    {START_STOP_UNIT, "start stop unit"},       /* 0x1b */
     {RECEIVE_DIAGNOSTIC, "receive diagnostic"}, /* 0x1c */
     {SEND_DIAGNOSTIC, "send diagnostic"},       /* 0x1d */
+    {READ_CAPACITY_10, "read capacity(10)"},    /* 0x25 */
     {READ_DEFECT_10, "read defect list(10)"},   /* 0x37 */
     {LOG_SELECT, "log select"},                 /* 0x4c */
     {LOG_SENSE, "log sense"},                   /* 0x4d */
     {MODE_SELECT_10, "mode select(10)"},        /* 0x55 */
     {MODE_SENSE_10, "mode sense(10)"},          /* 0x5a */
     {SAT_ATA_PASSTHROUGH_16, "ata pass-through(16)"}, /* 0x85 */
+    {READ_CAPACITY_16, "read capacity(16)"},    /* 0x9e,0x10 */
+    {REPORT_LUNS, "report luns"},               /* 0xa0 */
     {SAT_ATA_PASSTHROUGH_12, "ata pass-through(12)"}, /* 0xa1 */
 };
 
+static const char * vendor_specific = "<vendor specific>";
+
+/* Need to expand to take service action into account. For commands
+ * of interest the service action is in the 2nd command byte */
 const char * scsi_get_opcode_name(UINT8 opcode)
 {
     int k;
     int len = sizeof(opcode_name_arr) / sizeof(opcode_name_arr[0]);
     struct scsi_opcode_name * onp;
 
+    if (opcode >= 0xc0)
+       return vendor_specific;
     for (k = 0; k < len; ++k) {
         onp = &opcode_name_arr[k];
         if (opcode == onp->opcode)
@@ -296,7 +306,7 @@ int scsiLogSense(scsi_device * device, int pagenum, int subpagenum, UINT8 *pBuf,
         if ((res = scsiSimpleSenseFilter(&sinfo)))
             return res;
         /* sanity check on response */
-        if ((SUPPORTED_LPAGES != pagenum) && (pBuf[0] != pagenum))
+        if ((SUPPORTED_LPAGES != pagenum) && ((pBuf[0] & 0x3f) != pagenum))
             return SIMPLE_ERR_BAD_RESP;
         if (0 == ((pBuf[2] << 8) + pBuf[3]))
             return SIMPLE_ERR_BAD_RESP;
@@ -332,7 +342,7 @@ int scsiLogSense(scsi_device * device, int pagenum, int subpagenum, UINT8 *pBuf,
     if (0 != status)
         return status;
     /* sanity check on response */
-    if ((SUPPORTED_LPAGES != pagenum) && (pBuf[0] != pagenum))
+    if ((SUPPORTED_LPAGES != pagenum) && ((pBuf[0] & 0x3f) != pagenum))
         return SIMPLE_ERR_BAD_RESP;
     if (0 == ((pBuf[2] << 8) + pBuf[3]))
         return SIMPLE_ERR_BAD_RESP;
@@ -859,7 +869,7 @@ int scsiModePageOffset(const UINT8 * resp, int len, int modese_len)
                  "resp_len=%d bd_len=%d\n", offset, resp_len, bd_len);
             offset = -1;
         } else if ((offset + 2) > resp_len) {
-             if ((resp_len > 2) || con->reportscsiioctl)
+             if ((resp_len > 2) || scsi_debugmode)
                 pout("scsiModePageOffset: response length too short, "
                      "resp_len=%d offset=%d bd_len=%d\n", resp_len,
                      offset, bd_len);
@@ -996,7 +1006,7 @@ int scsiSetExceptionControlAndWarning(scsi_device * device, int enabled,
     sp = (rout[offset] & 0x80) ? 1 : 0; /* PS bit becomes 'SELECT's SP bit */
     if (enabled) {
         rout[offset + 2] = SCSI_IEC_MP_BYTE2_ENABLED;
-        if (con->reportscsiioctl > 2)
+        if (scsi_debugmode > 2)
             rout[offset + 2] |= SCSI_IEC_MP_BYTE2_TEST_MASK;
         rout[offset + 3] = SCSI_IEC_MP_MRIE;
         rout[offset + 4] = (SCSI_IEC_MP_INTERVAL_T >> 24) & 0xff;
@@ -1018,7 +1028,7 @@ int scsiSetExceptionControlAndWarning(scsi_device * device, int enabled,
             }
         }
         if (0 == memcmp(&rout[offset + 2], &iecp->raw_chg[offset + 2], 10)) {
-            if (con->reportscsiioctl > 0)
+            if (scsi_debugmode > 0)
                 pout("scsiSetExceptionControlAndWarning: already enabled\n");
             return 0;
         }
@@ -1026,7 +1036,7 @@ int scsiSetExceptionControlAndWarning(scsi_device * device, int enabled,
         eCEnabled = (rout[offset + 2] & DEXCPT_ENABLE) ? 0 : 1;
         wEnabled = (rout[offset + 2] & EWASC_ENABLE) ? 1 : 0;
         if ((! eCEnabled) && (! wEnabled)) {
-            if (con->reportscsiioctl > 0)
+            if (scsi_debugmode > 0)
                 pout("scsiSetExceptionControlAndWarning: already disabled\n");
             return 0;   /* nothing to do, leave other setting alone */
         }
index 559bac9c89d1b1cc49b7f25db98807dba298b548..4ba1a3b073c0473017cd799c58407cc9ca302a04 100644 (file)
 #ifndef SCSICMDS_H_
 #define SCSICMDS_H_
 
-#define SCSICMDS_H_CVSID "$Id: scsicmds.h 3095 2010-04-30 12:33:27Z dpgilbert $\n"
+#define SCSICMDS_H_CVSID "$Id: scsicmds.h 3258 2011-02-14 22:31:01Z manfred99 $\n"
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <errno.h>
 
 /* #define SCSI_DEBUG 1 */ /* Comment out to disable command debugging */
 
 #ifndef READ_DEFECT_10
 #define READ_DEFECT_10  0x37
 #endif
+#ifndef START_STOP_UNIT
+#define START_STOP_UNIT  0x1b
+#endif
+#ifndef REPORT_LUNS
+#define REPORT_LUNS  0xa0
+#endif
+#ifndef READ_CAPACITY_10
+#define READ_CAPACITY_10  0x25
+#endif
+#ifndef READ_CAPACITY_16
+#define READ_CAPACITY_16  0x9e /* service action 0x10 */
+#endif
 
 #ifndef SAT_ATA_PASSTHROUGH_12
 #define SAT_ATA_PASSTHROUGH_12 0xa1
@@ -284,6 +295,9 @@ Documentation, see http://www.storage.ibm.com/techsup/hddtech/prodspecs.htm */
 
 class scsi_device;
 
+// Print SCSI debug messages?
+extern unsigned char scsi_debugmode;
+
 void scsi_do_sense_disect(const struct scsi_cmnd_io * in,
                           struct scsi_sense_disect * out);
 
index fbb12829230756e1ee588ca0af5f367542552eb6..f10d0ebe858f1bf588bababa2c5bc1fe599e6733 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2002-9 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net>
  * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
  *
  * Additional SCSI work:
@@ -33,7 +33,6 @@
 
 #include "config.h"
 #include "int64.h"
-#include "extern.h"
 #include "scsicmds.h"
 #include "atacmds.h" // smart_command_set
 #include "dev_interface.h"
 
 #define GBUF_SIZE 65535
 
-const char * scsiprint_c_cvsid = "$Id: scsiprint.cpp 3095 2010-04-30 12:33:27Z dpgilbert $"
+const char * scsiprint_c_cvsid = "$Id: scsiprint.cpp 3256 2011-02-08 22:13:41Z chrfranke $"
                                  SCSIPRINT_H_CVSID;
 
-// control block which points to external global control variables
-extern smartmonctrl *con;
 
 UINT8 gBuf[GBUF_SIZE];
 #define LOG_RESP_LEN 252
@@ -76,17 +73,13 @@ static int gIecMPage = 1;     /* N.B. assume it until we know otherwise */
 /* Remember last successful mode sense/select command */
 static int modese_len = 0;
 
-// Compares failure type to policy in effect, and either exits or
-// simply returns to the calling routine.
-extern void failuretest(int type, int returnvalue);
-
 static void scsiGetSupportedLogPages(scsi_device * device)
 {
     int i, err;
 
     if ((err = scsiLogSense(device, SUPPORTED_LPAGES, 0, gBuf,
                             LOG_RESP_LEN, 0))) {
-        if (con->reportscsiioctl > 0)
+        if (scsi_debugmode > 0)
             pout("Log Sense for supported pages failed [%s]\n", 
                  scsiErrString(err)); 
         return;
@@ -154,20 +147,20 @@ static int scsiGetSmartData(scsi_device * device, bool attribs)
     const char * cp;
     int err = 0;
 
-    PRINT_ON(con);
+    print_on();
     if (scsiCheckIE(device, gSmartLPage, gTempLPage, &asc, &ascq,
                     &currenttemp, &triptemp)) {
         /* error message already announced */
-        PRINT_OFF(con);
+        print_off();
         return -1;
     }
-    PRINT_OFF(con);
+    print_off();
     cp = scsiGetIEString(asc, ascq);
     if (cp) {
         err = -2;
-        PRINT_ON(con);
+        print_on();
         pout("SMART Health Status: %s [asc=%x, ascq=%x]\n", cp, asc, ascq); 
-        PRINT_OFF(con);
+        print_off();
     } else if (gIecMPage)
         pout("SMART Health Status: OK\n");
 
@@ -200,16 +193,16 @@ static int scsiGetTapeAlertsData(scsi_device * device, int peripheral_type)
     const char *ts;
     int failures = 0;
 
-    PRINT_ON(con);
+    print_on();
     if ((err = scsiLogSense(device, TAPE_ALERTS_LPAGE, 0, gBuf,
                         LOG_RESP_TAPE_ALERT_LEN, LOG_RESP_TAPE_ALERT_LEN))) {
         pout("scsiGetTapesAlertData Failed [%s]\n", scsiErrString(err));
-        PRINT_OFF(con);
+        print_off();
         return -1;
     }
     if (gBuf[0] != 0x2e) {
         pout("TapeAlerts Log Sense Failed\n");
-        PRINT_OFF(con);
+        print_off();
         return -1;
     }
     pagelength = (unsigned short) gBuf[2] << 8 | gBuf[3];
@@ -231,7 +224,7 @@ static int scsiGetTapeAlertsData(scsi_device * device, int peripheral_type)
             }
         }
     }
-    PRINT_OFF(con);
+    print_off();
 
     if (! failures)
         pout("TapeAlert: OK\n");
@@ -247,24 +240,24 @@ static void scsiGetStartStopData(scsi_device * device)
 
     if ((err = scsiLogSense(device, STARTSTOP_CYCLE_COUNTER_LPAGE, 0, gBuf,
                             LOG_RESP_LEN, 0))) {
-        PRINT_ON(con);
+        print_on();
         pout("scsiGetStartStopData Failed [%s]\n", scsiErrString(err));
-        PRINT_OFF(con);
+        print_off();
         return;
     }
     if ((gBuf[0] & 0x3f) != STARTSTOP_CYCLE_COUNTER_LPAGE) {
-        PRINT_ON(con);
+        print_on();
         pout("StartStop Log Sense Failed, page mismatch\n");
-        PRINT_OFF(con);
+        print_off();
         return;
     }
     len = ((gBuf[2] << 8) | gBuf[3]);
     ucp = gBuf + 4;
     for (k = len; k > 0; k -= extra, ucp += extra) {
         if (k < 3) {
-            PRINT_ON(con);
+            print_on();
             pout("StartStop Log Sense Failed: short\n");
-            PRINT_OFF(con);
+            print_off();
             return;
         }
         extra = ucp[3] + 4;
@@ -322,17 +315,17 @@ static void scsiPrintGrownDefectListLen(scsi_device * device)
     memset(gBuf, 0, 4);
     if ((err = scsiReadDefect10(device, 0 /* req_plist */, 1 /* req_glist */,
                                 4 /* bytes from index */, gBuf, 4))) {
-        if (con->reportscsiioctl > 0) {
-            PRINT_ON(con);
+        if (scsi_debugmode > 0) {
+            print_on();
             pout("Read defect list (10) Failed: %s\n", scsiErrString(err));
-            PRINT_OFF(con);
+            print_off();
         }
         return;
     }
     if (0x8 != (gBuf[1] & 0x18)) {
-        PRINT_ON(con);
+        print_on();
         pout("Read defect list: asked for grown list but didn't get it\n");
-        PRINT_OFF(con);
+        print_off();
         return;
     }
     div = 0;
@@ -347,9 +340,9 @@ static void scsiPrintGrownDefectListLen(scsi_device * device)
             div = 8;
             break;
         default:
-            PRINT_ON(con);
+            print_on();
             pout("defect list format %d unknown\n", dl_format);
-            PRINT_OFF(con);
+            print_off();
             break;
     }
     dl_len = (gBuf[2] << 8) + gBuf[3];
@@ -373,15 +366,15 @@ static void scsiPrintSeagateCacheLPage(scsi_device * device)
 
     if ((err = scsiLogSense(device, SEAGATE_CACHE_LPAGE, 0, gBuf,
                             LOG_RESP_LEN, 0))) {
-        PRINT_ON(con);
+        print_on();
         pout("Seagate Cache Log Sense Failed: %s\n", scsiErrString(err));
-        PRINT_OFF(con);
+        print_off();
         return;
     }
     if ((gBuf[0] & 0x3f) != SEAGATE_CACHE_LPAGE) {
-        PRINT_ON(con);
+        print_on();
         pout("Seagate Cache Log Sense Failed, page mismatch\n");
-        PRINT_OFF(con);
+        print_off();
         return;
     }
     len = ((gBuf[2] << 8) | gBuf[3]) + 4;
@@ -394,11 +387,11 @@ static void scsiPrintSeagateCacheLPage(scsi_device * device)
         case 0: case 1: case 2: case 3: case 4:
             break;
         default: 
-            if (con->reportscsiioctl > 0) {
-                PRINT_ON(con);
+            if (scsi_debugmode > 0) {
+                print_on();
                 pout("Vendor (Seagate) cache lpage has unexpected parameter"
                      ", skip\n");
-                PRINT_OFF(con);
+                print_off();
             }
             return;
         }
@@ -448,15 +441,15 @@ static void scsiPrintSeagateFactoryLPage(scsi_device * device)
 
     if ((err = scsiLogSense(device, SEAGATE_FACTORY_LPAGE, 0, gBuf,
                             LOG_RESP_LEN, 0))) {
-        PRINT_ON(con);
+        print_on();
         pout("scsiPrintSeagateFactoryLPage Failed [%s]\n", scsiErrString(err));
-        PRINT_OFF(con);
+        print_off();
         return;
     }
     if ((gBuf[0] & 0x3f) != SEAGATE_FACTORY_LPAGE) {
-        PRINT_ON(con);
+        print_on();
         pout("Seagate/Hitachi Factory Log Sense Failed, page mismatch\n");
-        PRINT_OFF(con);
+        print_off();
         return;
     }
     len = ((gBuf[2] << 8) | gBuf[3]) + 4;
@@ -479,11 +472,11 @@ static void scsiPrintSeagateFactoryLPage(scsi_device * device)
         ucp += pl;
     }
     if ((good < 2) || (bad > 4)) {  /* heuristic */
-        if (con->reportscsiioctl > 0) {
-            PRINT_ON(con);
+        if (scsi_debugmode > 0) {
+            print_on();
             pout("\nVendor (Seagate/Hitachi) factory lpage has too many "
                  "unexpected parameters, skip\n");
-            PRINT_OFF(con);
+            print_off();
         }
         return;
     }
@@ -502,11 +495,11 @@ static void scsiPrintSeagateFactoryLPage(scsi_device * device)
             good = 1;
             break;
         default:
-            if (con->reportscsiioctl > 0) {
-                PRINT_ON(con);
+            if (scsi_debugmode > 0) {
+                print_on();
                 pout("Vendor (Seagate/Hitachi) factory lpage: "
                      "unknown parameter code [0x%x]\n", pc);
-                PRINT_OFF(con);
+                print_off();
             }
             break;
         }
@@ -540,7 +533,6 @@ static void scsiPrintErrorCounterLog(scsi_device * device)
     struct scsiNonMediumError nme;
     int found[3] = {0, 0, 0};
     const char * pageNames[3] = {"read:   ", "write:  ", "verify: "};
-    int k;
     double processed_gb;
 
     if (gReadECounterLPage && (0 == scsiLogSense(device,
@@ -557,7 +549,7 @@ static void scsiPrintErrorCounterLog(scsi_device * device)
                 VERIFY_ERROR_COUNTER_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) {
         scsiDecodeErrCounterPage(gBuf, &errCounterArr[2]);
         ecp = &errCounterArr[2];
-        for (k = 0; k < 7; ++k) {
+        for (int k = 0; k < 7; ++k) {
             if (ecp->gotPC[k] && ecp->counter[k]) {
                 found[2] = 1;
                 break;
@@ -572,7 +564,7 @@ static void scsiPrintErrorCounterLog(scsi_device * device)
              "algorithm      processed    uncorrected\n");
         pout("           fast | delayed   rewrites  corrected  "
              "invocations   [10^9 bytes]  errors\n");
-        for (k = 0; k < 3; ++k) {
+        for (int k = 0; k < 3; ++k) {
             if (! found[k])
                 continue;
             ecp = &errCounterArr[k];
@@ -599,26 +591,23 @@ static void scsiPrintErrorCounterLog(scsi_device * device)
     }
     if (gLastNErrorLPage && (0 == scsiLogSense(device,
                 LAST_N_ERROR_LPAGE, 0, gBuf, LOG_RESP_LONG_LEN, 0))) {
-        unsigned char * ucp;
-        int num, k, pc, pl, truncated;
-
-        num = (gBuf[2] << 8) + gBuf[3] + 4;
-        truncated = (num > LOG_RESP_LONG_LEN) ? num : 0;
+        int num = (gBuf[2] << 8) + gBuf[3] + 4;
+        int truncated = (num > LOG_RESP_LONG_LEN) ? num : 0;
         if (truncated)
             num = LOG_RESP_LONG_LEN;
-        ucp = gBuf + 4;
+        unsigned char * ucp = gBuf + 4;
         num -= 4;
         if (num < 4)
             pout("\nNo error events logged\n");
         else {
             pout("\nLast n error events log page\n");
-            for (k = num; k > 0; k -= pl, ucp += pl) {
+            for (int k = num, pl; k > 0; k -= pl, ucp += pl) {
                 if (k < 3) {
                     pout("  <<short Last n error events log page>>\n");
                     break;
                 }
                 pl = ucp[3] + 4;
-                pc = (ucp[0] << 8) + ucp[1];
+                int pc = (ucp[0] << 8) + ucp[1];
                 if (pl > 4) {
                     if ((ucp[2] & 0x1) && (ucp[2] & 0x2)) {
                         pout("  Error event %d:\n", pc);
@@ -628,7 +617,7 @@ static void scsiPrintErrorCounterLog(scsi_device * device)
                         pout("  Error event %d:\n", pc);
                         pout("    %.*s\n", pl - 4, (const char *)(ucp + 4));
                     } else {
-                        if (con->reportscsiioctl > 0) {
+                        if (scsi_debugmode > 0) {
                             pout("  Error event %d:\n", pc);
                             pout("    [data counter??]:\n");
                             dStrHex((const char *)ucp + 4, pl - 4, 1);
@@ -687,24 +676,24 @@ static int scsiPrintSelfTest(scsi_device * device)
 
     if ((err = scsiLogSense(device, SELFTEST_RESULTS_LPAGE, 0, gBuf,
                             LOG_RESP_SELF_TEST_LEN, 0))) {
-        PRINT_ON(con);
+        print_on();
         pout("scsiPrintSelfTest Failed [%s]\n", scsiErrString(err));
-        PRINT_OFF(con);
+        print_off();
         return FAILSMART;
     }
     if ((gBuf[0] & 0x3f) != SELFTEST_RESULTS_LPAGE) {
-        PRINT_ON(con);
+        print_on();
         pout("Self-test Log Sense Failed, page mismatch\n");
-        PRINT_OFF(con);
+        print_off();
         return FAILSMART;
     }
     // compute page length
     num = (gBuf[2] << 8) + gBuf[3];
     // Log sense page length 0x190 bytes
     if (num != 0x190) {
-        PRINT_ON(con);
+        print_on();
         pout("Self-test Log Sense length is 0x%x not 0x190 bytes\n",num);
-        PRINT_OFF(con);
+        print_off();
         return FAILSMART;
     }
     // loop through the twenty possible entries
@@ -860,24 +849,24 @@ static int scsiPrintBackgroundResults(scsi_device * device)
 
     if ((err = scsiLogSense(device, BACKGROUND_RESULTS_LPAGE, 0, gBuf,
                             LOG_RESP_LONG_LEN, 0))) {
-        PRINT_ON(con);
+        print_on();
         pout("scsiPrintBackgroundResults Failed [%s]\n", scsiErrString(err));
-        PRINT_OFF(con);
+        print_off();
         return FAILSMART;
     }
     if ((gBuf[0] & 0x3f) != BACKGROUND_RESULTS_LPAGE) {
-        PRINT_ON(con);
+        print_on();
         pout("Background scan results Log Sense Failed, page mismatch\n");
-        PRINT_OFF(con);
+        print_off();
         return FAILSMART;
     }
     // compute page length
     num = (gBuf[2] << 8) + gBuf[3] + 4;
     if (num < 20) {
-        PRINT_ON(con);
+        print_on();
         pout("Background scan results Log Sense length is %d, no scan "
              "status\n", num);
-        PRINT_OFF(con);
+        print_off();
         return FAILSMART;
     }
     truncated = (num > LOG_RESP_LONG_LEN) ? num : 0;
@@ -1248,32 +1237,32 @@ static int scsiPrintSasPhy(scsi_device * device, int reset)
 
     if ((err = scsiLogSense(device, PROTOCOL_SPECIFIC_LPAGE, 0, gBuf,
                             LOG_RESP_LONG_LEN, 0))) {
-        PRINT_ON(con);
+        print_on();
         pout("scsiPrintSasPhy Log Sense Failed [%s]\n", scsiErrString(err));
-        PRINT_OFF(con);
+        print_off();
         return FAILSMART;
     }
     if ((gBuf[0] & 0x3f) != PROTOCOL_SPECIFIC_LPAGE) {
-        PRINT_ON(con);
+        print_on();
         pout("Protocol specific Log Sense Failed, page mismatch\n");
-        PRINT_OFF(con);
+        print_off();
         return FAILSMART;
     }
     // compute page length
     num = (gBuf[2] << 8) + gBuf[3];
     if (1 != show_protocol_specific_page(gBuf, num + 4)) {
-        PRINT_ON(con);
+        print_on();
         pout("Only support protocol specific log page on SAS devices\n");
-        PRINT_OFF(con);
+        print_off();
         return FAILSMART;
     }
     if (reset) {
         if ((err = scsiLogSelect(device, 1 /* pcr */, 0 /* sp */, 0 /* pc */,
                                  PROTOCOL_SPECIFIC_LPAGE, 0, NULL, 0))) {
-            PRINT_ON(con);
+            print_on();
             pout("scsiPrintSasPhy Log Select (reset) Failed [%s]\n",
                  scsiErrString(err));
-            PRINT_OFF(con);
+            print_off();
             return FAILSMART;
         }
     }
@@ -1335,17 +1324,17 @@ static int scsiGetDriveInfo(scsi_device * device, UINT8 * peripheral_type, bool
     memset(gBuf, 0, 96);
     req_len = 36;
     if ((err = scsiStdInquiry(device, gBuf, req_len))) {
-        PRINT_ON(con);
+        print_on();
         pout("Standard Inquiry (36 bytes) failed [%s]\n", scsiErrString(err));
         pout("Retrying with a 64 byte Standard Inquiry\n");
-        PRINT_OFF(con);
+        print_off();
         /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */
         req_len = 64;
         if ((err = scsiStdInquiry(device, gBuf, req_len))) {
-            PRINT_ON(con);
+            print_on();
             pout("Standard Inquiry (64 bytes) failed [%s]\n",
                  scsiErrString(err));
-            PRINT_OFF(con);
+            print_off();
             return 1;
         }
     }
@@ -1356,9 +1345,9 @@ static int scsiGetDriveInfo(scsi_device * device, UINT8 * peripheral_type, bool
         *peripheral_type = peri_dt;
 
     if (len < 36) {
-        PRINT_ON(con);
+        print_on();
         pout("Short INQUIRY response, skip product id\n");
-        PRINT_OFF(con);
+        print_off();
         return 1;
     }
     memset(manufacturer, 0, sizeof(manufacturer));
@@ -1387,14 +1376,14 @@ static int scsiGetDriveInfo(scsi_device * device, UINT8 * peripheral_type, bool
         if (SIMPLE_ERR_BAD_RESP == iec_err) {
             pout(">> Terminate command early due to bad response to IEC "
                  "mode page\n");
-            PRINT_OFF(con);
+            print_off();
             gIecMPage = 0;
             return 1;
         }
     } else
         modese_len = iec.modese_len;
 
-    if (!con->dont_print_serial) {
+    if (!dont_print_serial_number) {
         if (0 == (err = scsiInquiryVpd(device, 0x80, gBuf, 64))) {
             /* should use VPD page 0x83 and fall back to this page (0x80)
              * if 0x83 not supported. NAA requires a lot of decoding code */
@@ -1402,13 +1391,13 @@ static int scsiGetDriveInfo(scsi_device * device, UINT8 * peripheral_type, bool
             gBuf[4 + len] = '\0';
             pout("Serial number: %s\n", &gBuf[4]);
         }
-        else if (con->reportscsiioctl > 0) {
-            PRINT_ON(con);
+        else if (scsi_debugmode > 0) {
+            print_on();
             if (SIMPLE_ERR_BAD_RESP == err)
                 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
             else
                 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err);
-            PRINT_OFF(con);
+            print_off();
         }
     }
 
@@ -1434,37 +1423,37 @@ static int scsiGetDriveInfo(scsi_device * device, UINT8 * peripheral_type, bool
     // See if unit accepts SCSI commmands from us
     if ((err = scsiTestUnitReady(device))) {
         if (SIMPLE_ERR_NOT_READY == err) {
-            PRINT_ON(con);
+            print_on();
             if (!is_tape)
                 pout("device is NOT READY (e.g. spun down, busy)\n");
             else
                 pout("device is NOT READY (e.g. no tape)\n");
-            PRINT_OFF(con);
+            print_off();
          } else if (SIMPLE_ERR_NO_MEDIUM == err) {
-            PRINT_ON(con);
+            print_on();
             pout("NO MEDIUM present on device\n");
-            PRINT_OFF(con);
+            print_off();
          } else if (SIMPLE_ERR_BECOMING_READY == err) {
-            PRINT_ON(con);
+            print_on();
             pout("device becoming ready (wait)\n");
-            PRINT_OFF(con);
+            print_off();
         } else {
-            PRINT_ON(con);
+            print_on();
             pout("device Test Unit Ready  [%s]\n", scsiErrString(err));
-            PRINT_OFF(con);
+            print_off();
         }
         failuretest(MANDATORY_CMD, returnval|=FAILID);
     }
    
     if (iec_err) {
         if (!is_tape) {
-            PRINT_ON(con);
+            print_on();
             pout("Device does not support SMART");
-            if (con->reportscsiioctl > 0)
+            if (scsi_debugmode > 0)
                 pout(" [%s]\n", scsiErrString(iec_err));
             else
                 pout("\n");
-            PRINT_OFF(con);
+            print_off();
         }
         gIecMPage = 0;
         return 0;
@@ -1485,19 +1474,19 @@ static int scsiSmartEnable(scsi_device * device)
     int err;
 
     if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
-        PRINT_ON(con);
+        print_on();
         pout("unable to fetch IEC (SMART) mode page [%s]\n", 
              scsiErrString(err));
-        PRINT_OFF(con);
+        print_off();
         return 1;
     } else
         modese_len = iec.modese_len;
 
     if ((err = scsiSetExceptionControlAndWarning(device, 1, &iec))) {
-        PRINT_ON(con);
+        print_on();
         pout("unable to enable Exception control and warning [%s]\n",
              scsiErrString(err));
-        PRINT_OFF(con);
+        print_off();
         return 1;
     }
     /* Need to refetch 'iec' since could be modified by previous call */
@@ -1521,19 +1510,19 @@ static int scsiSmartDisable(scsi_device * device)
     int err;
 
     if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
-        PRINT_ON(con);
+        print_on();
         pout("unable to fetch IEC (SMART) mode page [%s]\n", 
              scsiErrString(err));
-        PRINT_OFF(con);
+        print_off();
         return 1;
     } else
         modese_len = iec.modese_len;
 
     if ((err = scsiSetExceptionControlAndWarning(device, 0, &iec))) {
-        PRINT_ON(con);
+        print_on();
         pout("unable to disable Exception control and warning [%s]\n",
              scsiErrString(err));
-        PRINT_OFF(con);
+        print_off();
         return 1;
     }
     /* Need to refetch 'iec' since could be modified by previous call */
@@ -1577,22 +1566,27 @@ int scsiPrintMain(scsi_device * device, const scsi_print_options & options)
     int returnval = 0;
     int res, durationSec;
 
+    bool any_output = options.drive_info;
+
     res = scsiGetDriveInfo(device, &peripheral_type, options.drive_info);
     if (res) {
         if (2 == res)
             return 0;
         else
             failuretest(MANDATORY_CMD, returnval |= FAILID);
+       any_output = true;
     }
 
     if (options.smart_enable) {
         if (scsiSmartEnable(device))
             failuretest(MANDATORY_CMD, returnval |= FAILSMART);
+       any_output = true;
     }
 
     if (options.smart_disable) {
         if (scsiSmartDisable(device))
             failuretest(MANDATORY_CMD,returnval |= FAILSMART);
+       any_output = true;
     }
     
     if (options.smart_auto_save_enable) {
@@ -1600,6 +1594,7 @@ int scsiPrintMain(scsi_device * device, const scsi_print_options & options)
         pout("Enable autosave (clear GLTSD bit) failed\n");
         failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
       }
+      any_output = true;
     }
     
     if (options.smart_auto_save_disable) {
@@ -1607,6 +1602,7 @@ int scsiPrintMain(scsi_device * device, const scsi_print_options & options)
         pout("Disable autosave (set GLTSD bit) failed\n");
         failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
       }
+      any_output = true;
     }
     
     if (options.smart_check_status) {
@@ -1630,6 +1626,7 @@ int scsiPrintMain(scsi_device * device, const scsi_print_options & options)
                     returnval |= FAILSMART;
             }
         }
+        any_output = true;
     }   
     if (options.smart_vendor_attrib) {
         if (! checkedSupportedLogPages)
@@ -1648,6 +1645,7 @@ int scsiPrintMain(scsi_device * device, const scsi_print_options & options)
             if (gSeagateFactoryLPage)
                 scsiPrintSeagateFactoryLPage(device);
         }
+        any_output = true;
     }
     if (options.smart_error_log) {
         if (! checkedSupportedLogPages)
@@ -1656,6 +1654,7 @@ int scsiPrintMain(scsi_device * device, const scsi_print_options & options)
         if (1 == scsiFetchControlGLTSD(device, modese_len, 1))
             pout("\n[GLTSD (Global Logging Target Save Disable) set. "
                  "Enable Save with '-S on']\n");
+        any_output = true;
     }
     if (options.smart_selftest_log) {
         if (! checkedSupportedLogPages)
@@ -1669,6 +1668,7 @@ int scsiPrintMain(scsi_device * device, const scsi_print_options & options)
         }
         if (0 != res)
             failuretest(OPTIONAL_CMD, returnval|=res);
+        any_output = true;
     }
     if (options.smart_background_log) {
         if (! checkedSupportedLogPages)
@@ -1682,22 +1682,26 @@ int scsiPrintMain(scsi_device * device, const scsi_print_options & options)
         }
         if (0 != res)
             failuretest(OPTIONAL_CMD, returnval|=res);
+        any_output = true;
     }
     if (options.smart_default_selftest) {
         if (scsiSmartDefaultSelfTest(device))
             return returnval | FAILSMART;
         pout("Default Self Test Successful\n");
+        any_output = true;
     }
     if (options.smart_short_cap_selftest) {
         if (scsiSmartShortCapSelfTest(device))
             return returnval | FAILSMART;
         pout("Short Foreground Self Test Successful\n");
+        any_output = true;
     }
     if (options.smart_short_selftest) {
         if (scsiSmartShortSelfTest(device))
             return returnval | FAILSMART;
         pout("Short Background Self Test has begun\n");
         pout("Use smartctl -X to abort test\n");
+        any_output = true;
     }
     if (options.smart_extend_selftest) {
         if (scsiSmartExtendSelfTest(device))
@@ -1713,6 +1717,7 @@ int scsiPrintMain(scsi_device * device, const scsi_print_options & options)
             pout("Estimated completion time: %s\n", ctime(&t));
         }
         pout("Use smartctl -X to abort test\n");        
+        any_output = true;
     }
     if (options.smart_extend_cap_selftest) {
         if (scsiSmartExtendCapSelfTest(device))
@@ -1723,10 +1728,17 @@ int scsiPrintMain(scsi_device * device, const scsi_print_options & options)
         if (scsiSmartSelfTestAbort(device))
             return returnval | FAILSMART;
         pout("Self Test returned without error\n");
+        any_output = true;
     }           
     if (options.sasphy) {
         if (scsiPrintSasPhy(device, options.sasphy_reset))
             return returnval | FAILSMART;
+        any_output = true;
     }           
+
+    if (!any_output)
+      pout("SCSI device successfully opened\n\n"
+           "Use 'smartctl -a' (or '-x') to print SMART (and more) information\n\n");
+
     return returnval;
 }
index ee9ddc38044cdc32d042538088a8f85045002ff6..638674f81044e47938131f5be57b4399c727fe02 100644 (file)
 #ifndef SCSI_PRINT_H_
 #define SCSI_PRINT_H_
 
-#define SCSIPRINT_H_CVSID "$Id: scsiprint.h 3096 2010-04-30 14:32:49Z chrfranke $\n"
+#define SCSIPRINT_H_CVSID "$Id: scsiprint.h 3196 2010-10-28 21:31:49Z chrfranke $\n"
 
 // Options for scsiPrintMain
-// TODO: Move remaining options from con->* to here.
 struct scsi_print_options
 {
   bool drive_info;
index 1efb5656bc29cc52d85a7b52f3857bff107c06eb..10ae9e7ea4ccb352abb1f7ddeced08114719a957 100644 (file)
@@ -1,7 +1,7 @@
 .ig
  Copyright (C) 2002-10 Bruce Allen <smartmontools-support@lists.sourceforge.net>
 
- $Id: smartctl.8.in 3119 2010-06-11 16:21:25Z chrfranke $
+ $Id: smartctl.8.in 3283 2011-03-04 20:13:57Z 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
@@ -65,7 +65,7 @@ Changers with TapeAlert support use the devices \fB"/dev/nst*"\fP and
 \fB"/dev/sg*"\fP.  For SATA disks accessed with libata, use
 \fB"/dev/sd[a\-z]"\fP and append \fB"\-d ata"\fP. For disks behind
 3ware controllers you may need \fB"/dev/sd[a\-z]"\fP or
-\fB"/dev/twe[0\-9]"\fP or \fB"/dev/twa[0\-9]"\fP: see details
+\fB"/dev/twe[0\-9]"\fP, \fB"/dev/twa[0\-9]"\fP or \fB"/dev/twl[0\-9]"\fP: see details
 below. For disks behind HighPoint RocketRAID controllers you may need
 \fB"/dev/sd[a\-z]"\fP.  For disks behind Areca SATA RAID controllers,
 you need \fB"/dev/sg[2\-9]"\fP (note that smartmontools interacts with
@@ -77,7 +77,8 @@ Use the forms \fB/dev/disk[0\-9]\fP or equivalently \fBdisk[0\-9]\fP or equivale
 examples. Note that there is currently no Darwin SCSI support.
 .IP \fBFREEBSD\fP: 9
 Use the forms \fB"/dev/ad[0\-9]+"\fP for IDE/ATA
-devices and \fB"/dev/da[0\-9]+"\fP for SCSI devices.
+devices and \fB"/dev/da[0\-9]+"\fP or \fB"/dev/pass[0\-9]+"\fP for SCSI devices.
+For SATA devices on AHCI bus use \fB"/dev/ada[0\-9]+"\fP format.
 .IP \fBNETBSD/OPENBSD\fP: 9
 Use the form \fB"/dev/wd[0\-9]+c"\fP for IDE/ATA
 devices.  For SCSI disk and tape devices, use the device names
@@ -93,7 +94,7 @@ accessed via SMARTVSD.VXD, and \fB"/dev/hd[e\-h]"\fP for additional devices
 accessed via a patched SMARTVSE.VXD (see INSTALL file for details).
 Use the form \fB"/dev/scsi[0\-9][0\-f]"\fP for SCSI devices via an aspi dll
 on ASPI adapter 0\-9, ID 0\-15. The prefix \fB"/dev/"\fP is optional.
-.IP \fBWINDOWS\ NT4/2000/XP/2003/Vista\fP: 9
+.IP \fBWINDOWS\ NT4/2000/XP/2003/Vista/Win7/2008\fP: 9
 Use the forms \fB"/dev/sd[a\-z]"\fP for IDE/(S)ATA and SCSI disks
 "\\\\.\\PhysicalDrive[0\-25]" (where "a" maps to "0").
 These disks can also be referred to as \fB"/dev/pd[0\-255]"\fP for
@@ -116,9 +117,13 @@ monitoring (\'\-i\', \'\-c\', \'\-A\' below) if SMART support is missing
 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]:".
 The prefix \fB"/dev/"\fP is optional.
 .IP \fBCYGWIN\fP: 9
-See "WINDOWS NT4/2000/XP/2003/Vista" above.
+See "WINDOWS NT4/2000/XP/2003/Vista/Win7/2008" above.
 .IP \fBOS/2,eComStation\fP: 9
 Use the form \fB"/dev/hd[a\-z]"\fP for IDE/ATA devices.
 .PP
@@ -204,6 +209,13 @@ Same as \-\-scan, but also tries to open each device before printing
 device info.  The device open may change the device type due
 to autodetection (see also \'\-d test\').
 
+This option can be used to create a draft \fBsmartd.conf\fP file.
+All options after \'\-\-\' are appended to each output line.
+For example:
+.nf
+smartctl --scan-open -- -a -W 4,45,50 -m admin@work > smartd.conf
+.fi
+
 .TP
 .B RUN\-TIME BEHAVIOR OPTIONS:
 .TP
@@ -228,72 +240,92 @@ use the exit status of \fBsmartctl\fP (see RETURN VALUES below).
 \- Do not print the serial number of the device.
 .TP
 .B \-d TYPE, \-\-device=TYPE
-Specifies the type of the device.  The valid arguments to this option
-are \fIata\fP, \fIscsi\fP, \fIsat\fP, \fImarvell\fP, \fI3ware,N\fP,
-\fIareca,N\fP, \fIusbcypress\fP, \fIusbjmicron\fP, \fIusbsunplus\fP,
-\fIcciss,N\fP, \fIhpt,L/M\fP (or \fIhpt,L/M/N\fP), and \fItest\fP.
-
-If this option is not used then \fBsmartctl\fP will attempt to guess
-the device type from the device name or from controller type info
-provided by the operating system.
-
-If \'test\' is used as the TYPE name, \fBsmartctl\fP prints the guessed
-TYPE name, then opens the device and prints the (possibly changed) TYPE
-name and then exists without performing any further commands.
+Specifies the type of the device.
+The valid arguments to this option are:
 
-The \'sat\' device type is for ATA disks that have a SCSI to ATA
-Translation (SAT) Layer (SATL) between the disk and the operating system.
+.I auto
+- attempt to guess the device type from the device name or from
+controller type info provided by the operating system or from
+a matching USB ID entry in the drive database.
+This is the default.
+
+.I test
+- prints the guessed type, then opens the device and prints the
+(possibly changed) TYPE name and then exists without performing
+any further commands.
+
+.I ata
+\- the device type is ATA.  This prevents
+\fBsmartctl\fP
+from issuing SCSI commands to an ATA device.
+
+.I scsi
+\- the device type is SCSI.  This prevents
+\fBsmartctl\fP
+from issuing ATA commands to a SCSI device.
+
+.I sat
+\- the device type is SCSI to ATA Translation (SAT).
+This is for ATA disks that have a SCSI to ATA Translation (SAT) Layer
+(SATL) between the disk and the operating system.
 SAT defines two ATA PASS THROUGH SCSI commands, one 12 bytes long and
-the other 16 bytes long that \fBsmartctl\fP will utilize when this device
-type is selected. The default is the 16 byte variant which can be
+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\'.
 
-The \'usbcypress\' device type is for ATA disks that are behind a Cypress
-usb-pata bridge. This will use the ATACB proprietary scsi pass through command. There is no autodetection at the moment. The best way to know if your device support it, is to check your device usb id (most Cypress usb ata bridge got vid=0x04b4, pid=0x6830) or to try it (if the usb device doesn't support ATACB, smartmontools print an error).
-The default scsi operation code is 0x24, but although it can be overridden
-with \'\-d usbcypress,0xn\', where n is the scsi operation code,
+.I usbcypress
+\- this device type is for ATA disks that are behind a Cypress USB to PATA
+bridge.  This will use the ATACB proprietary scsi pass through command.
+The default SCSI operation code is 0x24, but although it can be overridden
+with \'\-d usbcypress,0xN\', where N is the scsi operation code,
 you're running the risk of damage to the device or filesystems on it.
 
-[NEW EXPERIMENTAL SMARTCTL FEATURE] The \'usbjmicron\' device type is for
-SATA disks that are behind a JMicron USB to PATA/SATA bridge. The 48-bit
-ATA commands (required e.g. for \'\-l xerror\', see below) do not work with
-all of these bridges and are therefore disabled by default. These commands
-can be enabled by \'\-d usbjmicron,x\'. CAUTION: Specifying \',x\' for a
-device which do not support it results in I/O errors and may disconnect
-the drive. The port can be specified by \'\-d usbjmicron[,x],PORT\' where
-PORT is 0 (master) or 1 (slave). This is not necessary if only one disk is
-connected to the USB bridge. If two disks are connected, an error message
-is printed if no PORT is specified.
-
-[NEW EXPERIMENTAL SMARTCTL FEATURE] The \'usbsunplus\' device type is for
-SATA disks that are behind a SunplusIT USB to SATA bridge.
-
-Under Linux, to look at SATA disks behind Marvell SATA controllers
-(using Marvell's \'linuxIAL\' driver rather than libata driver) use \'\-d marvell\'. Such
-controllers show up as Marvell Technology Group Ltd. SATA I or II controllers
-using lspci, or using lspci \-n show a vendor ID 0x11ab and a device ID of
-either 0x5040, 0x5041, 0x5080, 0x5081, 0x6041 or 0x6081. The \'linuxIAL\' driver
-seems not (yet?) available in the Linux kernel source tree, but should be available
-from system vendors (ftp://ftp.aslab.com/ is known to provide a patch with the driver).
-
-Under Linux , to look at SCSI/SAS disks behind LSI MegaRAID controllers,
-use syntax such as:
+.I usbjmicron
+- this device type is for SATA disks that are behind a JMicron USB to
+PATA/SATA bridge.  The 48-bit ATA commands (required e.g. for \'\-l xerror\',
+see below) do not work with all of these bridges and are therefore disabled by
+default.  These commands can be enabled by \'\-d usbjmicron,x\'.
+If two disks are connected to a bridge with two ports, an error message is printed
+if no PORT is specified.
+The port can be specified by \'\-d usbjmicron[,x],PORT\' where PORT is 0
+(master) or 1 (slave).  This is not necessary if the device uses a port
+multiplier to connect multiple disks to one port.  The disks appear under
+separate /dev/ice names then.
+CAUTION: Specifying \',x\' for a device which does not support it results
+in I/O errors and may disconnect the drive.  The same applies if the specified
+PORT does not exist or is not connected to a disk.
+
+.I usbsunplus
+\- this device type is for SATA disks that are behind a SunplusIT USB to SATA
+bridge.
+
+.I marvell
+\- [Linux only] interact with SATA disks behind Marvell chip-set
+controllers (using the Marvell rather than libata driver).
+
+.I megaraid,N
+\- [Linux only] the device consists of one or more SCSI/SAS disks connected
+to a MegaRAID controller.  The non-negative integer N (in the range of 0 to
+127 inclusive) denotes which disk on the controller is monitored.
+Use syntax such as:
 .nf
 \fBsmartctl \-a \-d megaraid,2 /dev/sda\fP
 .fi
 .nf
 \fBsmartctl \-a \-d megaraid,0 /dev/sdb\fP
 .fi
-where in the argument \fImegaraid,N\fP, the integer N is the physical disk
-number within the MegaRAID controller.  This interface will also work for
-Dell PERC controllers.  The following /dev/XXX entry must exist:
+This interface will also work for Dell PERC controllers.
+The following /dev/XXX entry must exist:
 .fi
 For PERC2/3/4 controllers: \fB/dev/megadev0\fP
 .fi
 For PERC5/6 controllers: \fB/dev/megaraid_sas_ioctl_node\fP
 
-Under Linux and FreeBSD, to look at ATA disks behind 3ware SCSI RAID controllers,
-use syntax such as:
+.I 3ware,N
+\- [FreeBSD and Linux only] the device consists of one or more ATA disks
+connected to a 3ware RAID controller.  The non-negative integer N
+(in the range from 0 to 127 inclusive) denotes which disk on the controller
+is monitored.
+Use syntax such as:
 .nf
 \fBsmartctl \-a \-d 3ware,2 /dev/sda\fP
 .fi
@@ -303,23 +335,29 @@ use syntax such as:
 .nf
 \fBsmartctl \-a \-d 3ware,1 /dev/twa0\fP
 .fi
-where in the argument \fI3ware,N\fP, the integer N is the disk number
-(3ware \'port\') within the 3ware ATA RAID controller.  The allowed
-values of N are from 0 to 127 inclusive.  The first two forms, which
-refer to devices /dev/sda\-z and /dev/twe0\-15, may be used with 3ware
-series 6000, 7000, and 8000 series controllers that use the 3x\-xxxx
-driver.  \fBNote that the /dev/sda\-z form is deprecated\fP starting
-with the Linux 2.6 kernel series and may not be supported by the Linux
-kernel in the near future. The final form, which refers to devices
+.nf
+\fBsmartctl \-a \-d 3ware,1 /dev/twl0\fP
+.fi
+The first two forms, which refer to devices /dev/sda\-z and /dev/twe0\-15,
+may be used with 3ware series 6000, 7000, and 8000 series controllers
+that use the 3x\-xxxx driver.
+\fBNote that the /dev/sda\-z form is deprecated\fP starting with
+the Linux 2.6 kernel series and may not be supported by the Linux
+kernel in the near future.  The final form, which refers to devices
 /dev/twa0\-15, must be used with 3ware 9000 series controllers, which
 use the 3w\-9xxx driver.
 
-Note that if the special character device nodes /dev/twa? and
-/dev/twe? do not exist, or exist with the incorrect major or minor
+The devices /dev/twl0\-15 must be used with the 3ware/LSI 9750 series
+controllers which use the 3w-sas driver.
+
+Note that if the special character device nodes /dev/twl?, /dev/twa?
+and /dev/twe? do not exist, or exist with the incorrect major or minor
 numbers, smartctl will recreate them on the fly.  Typically /dev/twa0
 refers to the first 9000\-series controller, /dev/twa1 refers to the
-second 9000 series controller, and so on. Likewise /dev/twe0 refers to
-the first 6/7/8000\-series controller, /dev/twa1 refers to the second
+second 9000 series controller, and so on.  The /dev/twl0 devices refers
+to the first 9750 series controller, /dev/twl1 resfers to the second
+9750 series controller, and so on.  Likewise /dev/twe0 refers to
+the first 6/7/8000\-series controller, /dev/twe1 refers to the second
 6/7/8000 series controller, and so on.
 
 Note that for the 6/7/8000 controllers, \fBany\fP of the physical
@@ -340,7 +378,7 @@ the 3ware controller, or to a port that does not physically have a
 disk attached to it, the behavior of \fBsmartctl\fP depends upon the
 specific controller model, firmware, Linux kernel and platform.  In
 some cases you will get a warning message that the device does not
-exist. In other cases you will be presented with \'void\' data for a
+exist.  In other cases you will be presented with \'void\' data for a
 non\-existent device.
 
 Note that if the /dev/sd? addressing form is used, then older 3w\-xxxx
@@ -348,46 +386,59 @@ drivers do not pass the "Enable Autosave"
 (\'\fB\-S on\fP\') and "Enable Automatic Offline" (\'\fB\-o on\fP\')
 commands to the disk, and produce these types of harmless syslog error
 messages instead: "\fB3w\-xxxx: tw_ioctl(): Passthru size (123392) too
-big\fP". This can be fixed by upgrading to version 1.02.00.037 or
+big\fP".  This can be fixed by upgrading to version 1.02.00.037 or
 later of the 3w\-xxxx driver, or by applying a patch to older
-versions. See \fBhttp://smartmontools.sourceforge.net/\fP for
-instructions.  Alternatively, use the character device /dev/twe0\-15 interface.
+versions.  Alternatively, use the character device /dev/twe0\-15 interface.
 
 The selective self\-test functions (\'\-t select,A\-B\') are only supported
-using the character device interface /dev/twa0\-15 and /dev/twe0\-15.
+using the character device interface /dev/twl0\-15, /dev/twa0\-15 and /dev/twe0\-15.
 The necessary WRITE LOG commands can not be passed through the SCSI
 interface.
 
-.B Areca SATA RAID controllers are currently supported under Linux only.
-To look at SATA disks behind Areca RAID controllers, use syntax such
-as:
+.I areca,N
+\- [Linux 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.
+Use syntax such as:
 .nf
 \fBsmartctl \-a \-d areca,2 /dev/sg2\fP
 .fi
 .nf
 \fBsmartctl \-a \-d areca,3 /dev/sg3\fP
 .fi
-where in the argument \fIareca,N\fP, the integer N is the disk number
-(Areca \'port\') within the Areca SATA RAID controller.  The allowed
-values of N are from 1 to 24 inclusive.  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
+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.  To help identify the correct device, use the command:
 .nf
 \fBcat /proc/scsi/sg/device_hdr /proc/scsi/sg/devices\fP
 .fi
 to show the SCSI generic devices (one per line, starting with
-/dev/sg0). The correct SCSI generic devices to address for
+/dev/sg0).  The correct SCSI generic devices to address for
 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.
 
 Important: the Areca controller must have firmware version 1.46 or
-later. Lower-numbered firmware versions will give (harmless) SCSI
+later.  Lower-numbered firmware versions will give (harmless) SCSI
 error messages and no SMART information.
 
-To look at (S)ATA disks behind HighPoint RocketRAID controllers, use syntax
-such as:
+.I cciss,N
+\- [FreeBSD and Linux only] the device consists of one or more SCSI/SAS disks
+connected to a cciss RAID controller.  The non-negative integer N (in the range
+from 0 to 15 inclusive) denotes which disk on the controller is monitored.
+
+If the controller firmware or driver provides a SAT Layer it may be possible
+to monitor also SATA disks by specifiying \'\-d sat+cciss,N\'.
+
+.I hpt,L/M/N
+\- [FreeBSD and Linux only] the device consists of one or more ATA disks
+connected to a HighPoint RocketRAID controller.  The integer L is the
+controller id, the integer M is the channel number, and the integer N
+is the PMPort number if it is available.  The allowed values of L are
+from 1 to 4 inclusive, M are from 1 to 8 inclusive and N from 1 to 4
+if PMPort available.  And also these values are limited by the model
+of the HighPoint RocketRAID controller.
+Use syntax such as:
 .nf
 \fBsmartctl \-a \-d hpt,1/3 /dev/sda\fP    (under Linux)
 .fi
@@ -400,19 +451,10 @@ such as:
 .nf
 \fBsmartctl \-a \-d hpt,1/2/3 /dev/hptrr\fP    (under FreeBSD)
 .fi
-where in the argument \fIhpt,L/M\fP or \fIhpt,L/M/N\fP, the integer L is the
-controller id, the integer M is the channel number, and the integer N is the
-PMPort number if it is available. The allowed values of L are from 1 to 4
-inclusive, M are from 1 to 8 inclusive and N from 1 to 5 if PMPort available.
 Note that the /dev/sda\-z form should be the device node which stands for
 the disks derived from the HighPoint RocketRAID controllers under Linux and
 under FreeBSD, it is the character device which the driver registered (eg,
-/dev/hptrr, /dev/hptmv6).  And also these values are limited by the model
-of the HighPoint RocketRAID controller.
-
-.B HighPoint RocketRAID controllers are currently ONLY supported under Linux and FreeBSD.
-
-.B cciss controllers are currently ONLY supported under Linux and FreeBSD.
+/dev/hptrr, /dev/hptmv6).
 .TP
 .B \-T TYPE, \-\-tolerance=TYPE
 [ATA only] Specifies how tolerant \fBsmartctl\fP should be of ATA and SMART
@@ -512,7 +554,14 @@ behaviour. This is does not work for SCSI devices yet.
 [ATA only] Specifies if \fBsmartctl\fP should exit before performing any
 checks when the device is in a low\-power mode. It may be used to prevent
 a disk from being spun\-up by \fBsmartctl\fP. The power mode is ignored by
-default. The allowed values of POWERMODE are:
+default.  A nonzero exit status is returned if the device is in one of the
+specified low\-power modes (see RETURN VALUES below).
+
+Note: If this option is used it may also be necessary to specify the device
+type with the \'-d\' option.  Otherwise the device may spin up due to
+commands issued during device type autodetection.
+
+The valid arguments to this option are:
 
 .I never
 \- check the device always, but print the power mode if \'\-i\' is
@@ -854,15 +903,14 @@ receives a command which is not implemented or is not valid.
 The verify row is only output if it has an element other than zero.
 
 .I xerror[,NUM][,error]
-\- [ATA only] [NEW EXPERIMENTAL SMARTCTL FEATURE] prints the Extended
-Comprehensive SMART error log (General Purpose Log address 0x03).
-Unlike the Summary SMART error log (see \'\-l error\' above),
-it provides sufficient space to log the contents of the 48-bit
-LBA register set introduced with ATA-6.  It also supports logs
-with more than one sector.  Each sector holds up to 4 log entries.
-The actual number of log sectors is vendor specific, typical values
-for HDD are 2 (Samsung), 5 (Seagate) or 6 (WD). Some recent SSD devices
-have much larger error logs.
+\- [ATA only] prints the Extended Comprehensive SMART error log
+(General Purpose Log address 0x03).  Unlike the Summary SMART error
+log (see \'\-l error\' above), it provides sufficient space to log
+the contents of the 48-bit LBA register set introduced with ATA-6.
+It also supports logs with more than one sector.  Each sector holds
+up to 4 log entries. The actual number of log sectors is vendor
+specific, typical values for HDD are 2 (Samsung), 5 (Seagate) or
+6 (WD).  Some recent SSD devices have much larger error logs.
 
 Only the 8 most recent error log entries are printed by default.
 This number can be changed by the optional parameter NUM.
@@ -912,12 +960,11 @@ can be run using the \'\-t\' option described below (using the ATA
 test terminology).
 
 .I xselftest[,NUM][,selftest]
-\- [ATA only] [NEW EXPERIMENTAL SMARTCTL FEATURE] prints the Extended
-SMART self\-test log (General Purpose Log address 0x07). Unlike the SMART
-self\-test log (see \'\-l selftest\' above), it supports 48-bit LBA
-and logs with more than one sector.  Each sector holds up to 19 log
-entries. The actual number of log sectors is vendor specific, typical
-values are 1 (Seagate) or 2 (Samsung).
+\- [ATA only] prints the Extended SMART self\-test log (General Purpose
+Log address 0x07). Unlike the SMART self\-test log (see \'\-l selftest\'
+above), it supports 48-bit LBA and logs with more than one sector.
+Each sector holds up to 19 log entries. The actual number of log sectors
+is vendor specific, typical values are 1 (Seagate) or 2 (Samsung).
 
 Only the 25 most recent log entries are printed by default. This number
 can be changed by the optional parameter NUM.
@@ -992,30 +1039,26 @@ supported. For RAID configurations, this is typically set to
 70,70 deciseconds.
 
 .I sataphy[,reset]
-\- [SATA only] [NEW EXPERIMENTAL SMARTCTL FEATURE] prints values
-and descriptions of the SATA Phy Event Counters (General Purpose Log
-address 0x11). If \'\-l sataphy,reset\' is specified, all counters
-are reset after reading the values.
+\- [SATA only] prints values and descriptions of the SATA Phy Event
+Counters (General Purpose Log address 0x11).  If \'\-l sataphy,reset\'
+is specified, all counters are reset after reading the values.
 
 .I sasphy[,reset]
-\- [SAS (SCSI) only] [NEW EXPERIMENTAL SMARTCTL FEATURE] prints values
-and descriptions of the SAS (SSP) Protocol Specific log page (log page
-0x18). If \'\-l sasphy,reset\' is specified, all counters
-are reset after reading the values.
+\- [SAS (SCSI) only] prints values and descriptions of the SAS (SSP)
+Protocol Specific log page (log page 0x18).  If \'\-l sasphy,reset\'
+is specified, all counters are reset after reading the values.
 
 .I gplog,ADDR[,FIRST[\-LAST|+SIZE]]
-\- [ATA only] [NEW EXPERIMENTAL SMARTCTL FEATURE] prints a hex dump
-of any log accessible via General Purpose Logging (GPL) feature.
-The log address ADDR is the hex address listed in the log directory
-(see \'\-l directory\' above). The range of log sectors (pages) can
-be specified by decimal values FIRST\-LAST or FIRST+SIZE. FIRST
-defaults to 0, SIZE defaults to 1. LAST can be set to \'max\' to
-specify the last page of the log.
+\- [ATA only] prints a hex dump of any log accessible via General
+Purpose Logging (GPL) feature.  The log address ADDR is the hex address
+listed in the log directory (see \'\-l directory\' above).
+The range of log sectors (pages) can be specified by decimal values
+FIRST\-LAST or FIRST+SIZE.  FIRST defaults to 0, SIZE defaults to 1.
+LAST can be set to \'max\' to specify the last page of the log.
 
 .I smartlog,ADDR[,FIRST[\-LAST|+SIZE]]
-\- [ATA only] [NEW EXPERIMENTAL SMARTCTL FEATURE] prints a hex dump
-of any log accessible via SMART Read Log command. See
-\'\-l gplog,...\' above for parameter syntax.
+\- [ATA only] prints a hex dump of any log accessible via SMART Read
+Log command.  See \'\-l gplog,...\' above for parameter syntax.
 
 For example, all these commands:
 .nf
@@ -1046,8 +1089,8 @@ set \'012345rvwz\'. The characters \'0\' to \'5\' select the byte 0
 to 5 from the 48\-bit raw value, \'r\' selects the reserved byte of
 the attribute data block, \'v\' selects the normalized value, \'w\'
 selects the worst value and \'z\' inserts a zero byte.
-The default BYTEORDER is \'543210\' for all 48-bit formats,
-and \'543210wv\' for the 64-bit formats.
+The default BYTEORDER is \'543210\' for all 48\-bit formats, \'r543210\'
+for the 54\-bit formats, and \'543210wv\' for the 64\-bit formats.
 For example, \'\-v 5,raw48:012345\' prints the raw value of
 attribute 5 with big endian instead of little endian
 byte ordering.
@@ -1106,10 +1149,18 @@ will be displayed in the form "Xh+Ym".  Here X is hours, and Y is
 minutes in the range 0\-59 inclusive.  Y is always printed with two
 digits, for example "06" or "31" or "00".
 
+.I msec24hour32
+\- Raw Attribute is power\-on time measured in 32\-bit hours and 24\-bit
+milliseconds since last hour update.  It will be displayed in the form
+"Xh+Ym+Z.Ms".  Here X is hours, Y is minutes, Z is seconds and M is
+milliseconds.
+
 .I tempminmax
 \- Raw Attribute is the disk temperature in Celsius.  Info about
-Lifetime Min/Max temperature is printed if available.  This is the
-default for Attributes 190 and 194.
+Min/Max temperature is printed if available.  This is the default
+for Attributes 190 and 194.  The recording interval (lifetime,
+last power cycle, last soft reset) of the min/max values is device
+specific.
 
 .I temp10x
 \- Raw Attribute is ten times the disk temperature in Celsius.
@@ -1133,6 +1184,10 @@ unload). As a rule of thumb, the mechanical stress created by one
 emergency unload is equivalent to that created by one hundred normal
 unloads.
 
+.I raw24/raw32
+\- Raw attribute is an error rate which consists of a 24\-bit error
+count and a 32\-bit total count.
+
 The following old arguments to \'\-v\' are also still valid:
 
 .I 9,minutes
@@ -1306,9 +1361,9 @@ lists all entries matching MODEL, and the command:
 lists all entries for this MODEL and a specific FIRMWARE version.
 .TP
 .B \-B [+]FILE, \-\-drivedb=[+]FILE
-[ATA only] [NEW EXPERIMENTAL SMARTCTL FEATURE] Read the drive database from
-FILE.  The new database replaces the built in database by default. If \'+\' is
-specified, then the new entries prepend the built in entries.
+[ATA only] Read the drive database from FILE.  The new database replaces
+the built in database by default.  If \'+\' is specified, then the new
+entries prepend the built in entries.
 
 If this option is not specified, optional entries are read from the file
 \fB/usr/local/etc/smart_drivedb.h\fP (Windows: \fBEXEDIR/drivedb-add.h\fP).
@@ -1549,6 +1604,20 @@ cycles. Otherwise, the setting is volatile and will be reverted to
 default (1 minute), or last non-volatile setting by the next hard reset.
 This command also clears the temperature history table. See
 \'\-l scttemp\' above for more information about SCT temperature logging.
+
+.I vendor,N
+\- [ATA only] issues the ATA command SMART EXECUTE OFF-LINE IMMEDIATE
+with subcommand N in LBA LOW register. The subcommand is specified as
+a hex value in the range 0x00 to 0xff. Subcommands 0x40-0x7f and
+0x90-0xff are reserved for vendor specific use, see table 61 of
+T13/1699-D Revision 6a (ATA8-ACS).
+
+\fBWARNING: Only run subcommands documented by the vendor of the
+device.\fP
+
+Example for Intel X18\-M/X25\-M G2 SSDs only: The subcommand 0x40
+(\'\-t vendor,0x40\') clears the timed workload related SMART
+attributes (226, 227, 228).
 .TP
 .B \-C, \-\-captive
 [ATA] Runs self\-tests in captive mode.  This has no effect with \'\-t
@@ -1619,7 +1688,7 @@ typically an ATA (IDE) or SATA disk in Linux.
 .nf
 .B smartctl \-a /dev/sdb
 .fi
-Print a large amount of SMART information for drive /dev/sda . This may
+Print a large amount of SMART information for drive /dev/sdb . This may
 be a SCSI disk or an ATA (SATA) disk.
 .PP
 .nf
@@ -1688,8 +1757,14 @@ RAID 6000/7000/8000 controller card.
 .nf
 .B smartctl \-a \-d 3ware,0 /dev/twa0
 .fi
-Examine all SMART data for the first ATA disk connected to a 3ware
-RAID 9000 controller card.
+Examine all SMART data for the first ATA disk connected to a
+3ware RAID 9000 controller card.
+.PP
+.nf
+.B smartctl \-a \-d 3ware,0 /dev/twl0
+.fi
+Examine all SMART data for the first SATA (not SAS) disk connected to a
+3ware RAID 9750 controller card.
 .PP
 .nf
 .B smartctl \-t short \-d 3ware,3 /dev/sdb
@@ -1745,7 +1820,8 @@ may also be returned for SCSI disks.
 Command line did not parse.
 .TP
 .B Bit 1:
-Device open failed, or device did not return an IDENTIFY DEVICE structure. 
+Device open failed, device did not return an IDENTIFY DEVICE structure,
+or device is in a low-power mode (see \'\-n\' option above).
 .TP
 .B Bit 2:
 Some SMART command to the disk failed, or there was a checksum error
@@ -1767,6 +1843,8 @@ The device error log contains records of errors.
 .TP
 .B Bit 7:
 The device self\-test log contains records of errors.
+[ATA only] Failed self-tests outdated by a newer successful extended
+self\-test are ignored.
 
 To test within the shell for whether or not the different bits are
 turned on or off, you can use the following type of construction (this
@@ -1792,7 +1870,7 @@ condition.
 \fBBruce Allen\fP smartmontools\-support@lists.sourceforge.net
 .fi
 University of Wisconsin \- Milwaukee Physics Department
+
 .PP
 .SH CONTRIBUTORS
 The following have made large contributions to smartmontools:
@@ -1861,4 +1939,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 3119 2010-06-11 16:21:25Z chrfranke $
+$Id: smartctl.8.in 3283 2011-03-04 20:13:57Z chrfranke $
index 7ec2f136957db8eeb5c87f9326fbb2d607f97f56..c12120a2626bf77005e46a30387eaa9ca8a5a92b 100644 (file)
@@ -3,8 +3,8 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2002-10 Bruce Allen <smartmontools-support@lists.sourceforge.net>
- * Copyright (C) 2008-10 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2008-11 Christian Franke <smartmontools-support@lists.sourceforge.net>
  * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
  *
  * This program is free software; you can redistribute it and/or modify
 #include "atacmds.h"
 #include "dev_interface.h"
 #include "ataprint.h"
-#include "extern.h"
 #include "knowndrives.h"
 #include "scsicmds.h"
 #include "scsiprint.h"
 #include "smartctl.h"
 #include "utility.h"
 
-const char * smartctl_cpp_cvsid = "$Id: smartctl.cpp 3119 2010-06-11 16:21:25Z chrfranke $"
-                                  CONFIG_H_CVSID EXTERN_H_CVSID SMARTCTL_H_CVSID;
+const char * smartctl_cpp_cvsid = "$Id: smartctl.cpp 3283 2011-03-04 20:13:57Z chrfranke $"
+  CONFIG_H_CVSID SMARTCTL_H_CVSID;
 
-// This is a block containing all the "control variables".  We declare
-// this globally in this file, and externally in other files.
-smartmonctrl *con=NULL;
+// Globals to control printing
+bool printing_is_switchable = false;
+bool printing_is_off = false;
 
 static void printslogan()
 {
   pout("%s\n", format_version_info("smartctl").c_str());
 }
 
-void UsageSummary(){
+static void UsageSummary()
+{
   pout("\nUse smartctl -h to get a usage summary\n\n");
   return;
 }
@@ -76,7 +76,8 @@ void UsageSummary(){
 static std::string getvalidarglist(char opt);
 
 /*  void prints help information for command syntax */
-void Usage (void){
+static void Usage()
+{
   printf("Usage: smartctl [options] device\n\n");
   printf(
 "============================================ SHOW INFORMATION OPTIONS =====\n\n"
@@ -156,7 +157,7 @@ void Usage (void){
          "]\n\n"
 "============================================ DEVICE SELF-TEST OPTIONS =====\n\n"
 "  -t TEST, --test=TEST\n"
-"        Run test. TEST: offline short long conveyance select,M-N\n"
+"        Run test. TEST: offline short long conveyance vendor,N select,M-N\n"
 "                        pending,N afterselect,[on|off] scttempint,N[,p]\n\n"
 "  -C, --captive\n"
 "        Do test in captive mode (along with -t)\n\n"
@@ -176,7 +177,7 @@ static std::string getvalidarglist(char opt)
   case 'q':
     return "errorsonly, silent, noserial";
   case 'd':
-    return smi()->get_valid_dev_types_str() + ", test";
+    return smi()->get_valid_dev_types_str() + ", auto, test";
   case 'T':
     return "normal, conservative, permissive, verypermissive";
   case 'b':
@@ -194,7 +195,8 @@ static std::string getvalidarglist(char opt)
   case 'P':
     return "use, ignore, show, showall";
   case 't':
-    return "offline, short, long, conveyance, select,M-N, pending,N, afterselect,[on|off], scttempint,N[,p]";
+    return "offline, short, long, conveyance, vendor,N, select,M-N, "
+           "pending,N, afterselect,[on|off], scttempint,N[,p]";
   case 'F':
     return "none, samsung, samsung2, samsung3, swapid";
   case 'n':
@@ -207,8 +209,8 @@ static std::string getvalidarglist(char opt)
 
 /* Prints the message "=======> VALID ARGUMENTS ARE: <LIST> \n", where
    <LIST> is the list of valid arguments for option opt. */
-void printvalidarglistmessage(char opt) {
+static void printvalidarglistmessage(char opt)
+{
   if (opt=='v'){
     pout("=======> VALID ARGUMENTS ARE:\n\thelp\n%s\n<=======\n",
          create_vendor_attribute_arg_list().c_str());
@@ -231,10 +233,10 @@ enum checksum_err_mode_t {
 
 static checksum_err_mode_t checksum_err_mode = CHECKSUM_ERR_WARN;
 
-static void scan_devices(const char * type, bool with_open, const char * pattern);
+static void scan_devices(const char * type, bool with_open, char ** argv);
 
 /*      Takes command options and sets features to be run */    
-const char * parse_options(int argc, char** argv,
+static const char * parse_options(int argc, char** argv,
                            ata_print_options & ataopts,
                            scsi_print_options & scsiopts)
 {
@@ -278,7 +280,6 @@ const char * parse_options(int argc, char** argv,
 
   char extraerror[256];
   memset(extraerror, 0, sizeof(extraerror));
-  memset(con,0,sizeof(*con));
   opterr=optopt=0;
 
   const char * type = 0; // set to -d optarg
@@ -293,37 +294,37 @@ const char * parse_options(int argc, char** argv,
   while ((optchar = getopt_long(argc, argv, shortopts, longopts, 0)) != -1) {
     switch (optchar){
     case 'V':
-      con->dont_print = false;
+      printing_is_off = false;
       pout("%s", format_version_info("smartctl", true /*full*/).c_str());
       EXIT(0);
       break;
     case 'q':
       if (!strcmp(optarg,"errorsonly")) {
-        con->printing_switchable = true;
-        con->dont_print = false;
+        printing_is_switchable = true;
+        printing_is_off = false;
       } else if (!strcmp(optarg,"silent")) {
-        con->printing_switchable = false;
-        con->dont_print = true;
+        printing_is_switchable = false;
+        printing_is_off = true;
       } else if (!strcmp(optarg,"noserial")) {
-        con->dont_print_serial = true;
+        dont_print_serial_number = true;
       } else {
         badarg = true;
       }
       break;
     case 'd':
-      type = optarg;
+      type = (strcmp(optarg, "auto") ? optarg : (char *)0);
       break;
     case 'T':
       if (!strcmp(optarg,"normal")) {
-        con->conservative = false;
-        con->permissive   = 0;
+        failuretest_conservative = false;
+        failuretest_permissive   = 0;
       } else if (!strcmp(optarg,"conservative")) {
-        con->conservative = true;
+        failuretest_conservative = true;
       } else if (!strcmp(optarg,"permissive")) {
-        if (con->permissive<0xff)
-          con->permissive++;
+        if (failuretest_permissive < 0xff)
+          failuretest_permissive++;
       } else if (!strcmp(optarg,"verypermissive")) {
-        con->permissive = 0xff;
+        failuretest_permissive = 0xff;
       } else {
         badarg = true;
       }
@@ -352,11 +353,11 @@ const char * parse_options(int argc, char** argv,
         if (split_report_arg(s, &i)) {
           badarg = true;
         } else if (!strcmp(s,"ioctl")) {
-          con->reportataioctl  = con->reportscsiioctl = i;
+          ata_debugmode  = scsi_debugmode = i;
         } else if (!strcmp(s,"ataioctl")) {
-          con->reportataioctl = i;
+          ata_debugmode = i;
         } else if (!strcmp(s,"scsiioctl")) {
-          con->reportscsiioctl = i;
+          scsi_debugmode = i;
         } else {
           badarg = true;
         }
@@ -561,7 +562,7 @@ const char * parse_options(int argc, char** argv,
     case 'v':
       // parse vendor-specific definitions of attributes
       if (!strcmp(optarg,"help")) {
-        con->dont_print = false;
+        printing_is_off = false;
         printslogan();
         pout("The valid arguments to -v are:\n\thelp\n%s\n",
              create_vendor_attribute_arg_list().c_str());
@@ -662,6 +663,15 @@ const char * parse_options(int argc, char** argv,
         }
         ataopts.sct_temp_int = interval;
         ataopts.sct_temp_int_pers = (n2 == len);
+      } else if (!strncmp(optarg, "vendor,", sizeof("vendor,")-1)) {
+        unsigned subcmd = ~0U; int n = -1;
+        if (!(   sscanf(optarg, "%*[a-z],0x%x%n", &subcmd, &n) == 1
+              && subcmd <= 0xff && n == (int)strlen(optarg))) {
+          strcpy(extraerror, "Option -t vendor,0xNN syntax error\n");
+          badarg = true;
+        }
+        else
+          ataopts.smart_selftest_type = subcmd;
       } else {
         badarg = true;
       }
@@ -699,7 +709,7 @@ const char * parse_options(int argc, char** argv,
       }
       break;
     case 'h':
-      con->dont_print = false;
+      printing_is_off = false;
       printslogan();
       Usage();
       EXIT(0);  
@@ -712,7 +722,7 @@ const char * parse_options(int argc, char** argv,
 
     case '?':
     default:
-      con->dont_print = false;
+      printing_is_off = false;
       printslogan();
       // Point arg to the argument in which this option was found.
       arg = argv[optind-1];
@@ -764,19 +774,22 @@ const char * parse_options(int argc, char** argv,
 
   // Special handling of --scan, --scanopen
   if (scan) {
-    scan_devices(type, (scan == opt_scan_open), argv[optind]);
+    // Read or init drive database to allow USB ID check.
+    if (!no_defaultdb && !read_default_drive_databases())
+      EXIT(FAILCMD);
+    scan_devices(type, (scan == opt_scan_open), argv + optind);
     EXIT(0);
   }
 
   // At this point we have processed all command-line options.  If the
   // print output is switchable, then start with the print output
   // turned off
-  if (con->printing_switchable)
-    con->dont_print = true;
+  if (printing_is_switchable)
+    printing_is_off = true;
 
   // error message if user has asked for more than one test
   if (testcnt > 1) {
-    con->dont_print = false;
+    printing_is_off = false;
     printslogan();
     pout("\nERROR: smartctl can only run a single test type (or abort) at a time.\n");
     UsageSummary();
@@ -787,7 +800,7 @@ const char * parse_options(int argc, char** argv,
   // asking for a selective self-test
   if (   (ataopts.smart_selective_args.pending_time || ataopts.smart_selective_args.scan_after_select)
       && !ataopts.smart_selective_args.num_spans) {
-    con->dont_print = false;
+    printing_is_off = false;
     printslogan();
     if (ataopts.smart_selective_args.pending_time)
       pout("\nERROR: smartctl -t pending,N must be used with -t select,N-M.\n");
@@ -846,7 +859,7 @@ const char * parse_options(int argc, char** argv,
   return type;
 }
 
-// Printing function (controlled by global con->dont_print) 
+// Printing function (controlled by global printing_is_off)
 // [From GLIBC Manual: Since the prototype doesn't specify types for
 // optional arguments, in a call to a variadic function the default
 // argument promotions are performed on the optional argument
@@ -858,7 +871,7 @@ void pout(const char *fmt, ...){
   
   // initialize variable argument list 
   va_start(ap,fmt);
-  if (con->dont_print){
+  if (printing_is_off) {
     va_end(ap);
     return;
   }
@@ -870,19 +883,32 @@ void pout(const char *fmt, ...){
   return;
 }
 
-// This function is used by utility.cpp to report LOG_CRIT errors.
-// The smartctl version prints to stdout instead of syslog().
-void PrintOut(int priority, const char *fmt, ...) {
-  va_list ap;
+// Globals to set failuretest() policy
+bool failuretest_conservative = false;
+unsigned char failuretest_permissive = 0;
 
-  // avoid warning message about unused variable from gcc -W: just
-  // change value of local copy.
-  priority=0;
+// Compares failure type to policy in effect, and either exits or
+// simply returns to the calling routine.
+// Used in ataprint.cpp and scsiprint.cpp.
+void failuretest(failure_type type, int returnvalue)
+{
+  // If this is an error in an "optional" SMART command
+  if (type == OPTIONAL_CMD) {
+    if (!failuretest_conservative)
+      return;
+    pout("An optional SMART command failed: exiting. Remove '-T conservative' option to continue.\n");
+    EXIT(returnvalue);
+  }
 
-  va_start(ap,fmt);
-  vprintf(fmt,ap);
-  va_end(ap);
-  return;
+  // If this is an error in a "mandatory" SMART command
+  if (type == MANDATORY_CMD) {
+    if (failuretest_permissive--)
+      return;
+    pout("A mandatory SMART command failed: exiting. To continue, add one or more '-T permissive' options.\n");
+    EXIT(returnvalue);
+  }
+
+  throw std::logic_error("failuretest: Unknown type");
 }
 
 // Used to warn users about invalid checksums. Called from atacmds.cpp.
@@ -912,45 +938,58 @@ static const char * get_protocol_info(const smart_device * dev)
 }
 
 // Device scan
-// smartctl [-d type] --scan[-open] [PATTERN]
-void scan_devices(const char * type, bool with_open, const char * pattern)
+// smartctl [-d type] --scan[-open] -- [PATTERN] [smartd directive ...]
+void scan_devices(const char * type, bool with_open, char ** argv)
 {
-  bool dont_print = !(con->reportataioctl || con->reportscsiioctl);
-  smart_device_list devlist;
+  bool dont_print = !(ata_debugmode || scsi_debugmode);
+
+  const char * pattern = 0;
+  int ai = 0;
+  if (argv[ai] && argv[ai][0] != '-')
+    pattern = argv[ai++];
 
-  con->dont_print = dont_print;
+  smart_device_list devlist;
+  printing_is_off = dont_print;
   bool ok = smi()->scan_smart_devices(devlist, type , pattern);
-  con->dont_print = false;
+  printing_is_off = false;
 
   if (!ok) {
-    pout("scan_smart_devices: %s\n", smi()->get_errmsg());
+    pout("scan_smart_devices: %s\n", smi()->get_errmsg());
     return;
   }
 
   for (unsigned i = 0; i < devlist.size(); i++) {
-    smart_device * dev = devlist.at(i);
+    smart_device_auto_ptr dev( devlist.release(i) );
 
-    std::string openmsg;
     if (with_open) {
-      con->dont_print = dont_print;
-      dev = dev->autodetect_open();
-      con->dont_print = false;
+      printing_is_off = dont_print;
+      dev.replace ( dev->autodetect_open() );
+      printing_is_off = false;
+
+      if (!dev->is_open()) {
+        pout("# %s -d %s # %s, %s device open failed: %s\n", dev->get_dev_name(),
+          dev->get_dev_type(), dev->get_info_name(),
+          get_protocol_info(dev.get()), dev->get_errmsg());
+        continue;
+      }
+    }
 
-      if (dev->is_open())
-        openmsg = " (opened)";
-      else
-        openmsg = strprintf(" (open failed: %s)", dev->get_errmsg());
+    pout("%s -d %s", dev->get_dev_name(), dev->get_dev_type());
+    if (!argv[ai])
+      pout(" # %s, %s device\n", dev->get_info_name(), get_protocol_info(dev.get()));
+    else {
+      for (int j = ai; argv[j]; j++)
+        pout(" %s", argv[j]);
+      pout("\n");
     }
 
-    pout("%s -d %s [%s]%s\n", dev->get_info_name(), dev->get_dev_type(),
-         get_protocol_info(dev), openmsg.c_str());
     if (dev->is_open())
       dev->close();
   }
 }
 
 // Main program without exception handling
-int main_worker(int argc, char **argv)
+static int main_worker(int argc, char **argv)
 {
   // Throw if CPU endianess does not match compile time test.
   check_endianness();
@@ -960,10 +999,6 @@ int main_worker(int argc, char **argv)
   if (!smi())
     return 1;
 
-  // define control block for external functions
-  smartmonctrl control;
-  con=&control;
-
   // Parse input arguments
   ata_print_options ataopts;
   scsi_print_options scsiopts;
index 51686e2fd28a3762dfb78056b5b92f28271457f5..3ec3e086f6f417f6b62bcc890b829951a7bd73cf 100644 (file)
@@ -3,7 +3,8 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2002-9 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2002-10 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2008-10 Christian Franke <smartmontools-support@lists.sourceforge.net>
  * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -25,7 +26,7 @@
 #ifndef SMARTCTL_H_
 #define SMARTCTL_H_
 
-#define SMARTCTL_H_CVSID "$Id: smartctl.h,v 1.27 2009/06/20 19:11:04 chrfranke Exp $\n"
+#define SMARTCTL_H_CVSID "$Id: smartctl.h 3196 2010-10-28 21:31:49Z chrfranke $\n"
 
 // Return codes (bitmask)
 
 // command set."  The 'mandatory' S.M.A.R.T.  commands are: (1)
 // Enable/Disable Attribute Autosave, (2) Enable/Disable S.M.A.R.T.,
 // and (3) S.M.A.R.T. Return Status.  All others are optional.
-#define OPTIONAL_CMD 1
-#define MANDATORY_CMD 2
-
-// Moved to C++ interface
-//void print_smartctl_examples();
+enum failure_type {
+  OPTIONAL_CMD,
+  MANDATORY_CMD,
+};
+
+// Globals to set failuretest() policy
+extern bool failuretest_conservative;
+extern unsigned char failuretest_permissive;
+
+// Compares failure type to policy in effect, and either exits or
+// simply returns to the calling routine.
+void failuretest(failure_type type, int returnvalue);
+
+// Globals to control printing
+extern bool printing_is_switchable;
+extern bool printing_is_off;
+
+// Printing control functions
+inline void print_on()
+{
+  if (printing_is_switchable)
+    printing_is_off = false;
+}
+inline void print_off()
+{
+  if (printing_is_switchable)
+    printing_is_off = true;
+}
 
 #endif
index d07b3f8539a4b41fbd1b4e7bbf6ff1b08bb818dd..43c773f24090188596ad6b389d528adf51494c1a 100644 (file)
@@ -1,7 +1,7 @@
 .ig
 Copyright (C) 2002-10 Bruce Allen <smartmontools-support@lists.sourceforge.net>
  
-$Id: smartd.8.in 3117 2010-06-08 15:41:04Z chrfranke $
+$Id: smartd.8.in 3284 2011-03-04 21:33:35Z 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
@@ -107,7 +107,7 @@ Examine all entries \fB"/dev/hd[a-d]"\fP (bitmask
 from "\\\\.\\SMARTVSD") for IDE/ATA devices.
 Examine all entries \fB"/dev/scsi[0\-9][0\-f]"\fP for SCSI devices 
 on ASPI adapter 0\-9, ID 0\-15.
-.IP \fBWINDOWS\ NT4/2000/XP/2003/Vista\fP: 9
+.IP \fBWINDOWS\ NT4/2000/XP/2003/Vista/Win7/2008\fP: 9
 Examine all entries \fB"/dev/sd[a-j]"\fP ("\\\\.\\PhysicalDrive[0-9]")
 for IDE/(S)ATA and SCSI disk devices 
 
@@ -115,8 +115,12 @@ If a 3ware 9000 controller is installed, examine all entries
 \fB"/dev/sdX,N"\fP for the first logical drive (\'unit\'
 \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.
 .IP \fBCYGWIN\fP: 9
-See "WINDOWS NT4/2000/XP/2003/Vista" above.
+See "WINDOWS NT4/2000/XP/2003/Vista/Win7/2008" above.
 .IP \fBOS/2,eComStation\fP: 9
 Use the form \fB"/dev/hd[a\-z]"\fP for IDE/ATA devices.
 .PP
@@ -130,12 +134,11 @@ OPTIONS
 
 .TP
 .B \-A PREFIX, \-\-attributelog=PREFIX
-[NEW EXPERIMENTAL SMARTD FEATURE] [ATA ONLY]
-Writes \fBsmartd\fP attribute information (normalized and raw attribute values)
-to files \'PREFIX\'\'MODEL\-SERIAL.ata.csv\'. At each check cycle attributes
-are logged as a line of semicolon separated triplets of the form
-"attribute-ID;attribute-norm-value;attribute-raw-value;". Each line is
-led by a date string of the form "yyyy-mm-dd HH:MM:SS" (in UTC).
+[ATA only] Writes \fBsmartd\fP attribute information (normalized and raw
+attribute values) to files \'PREFIX\'\'MODEL\-SERIAL.ata.csv\'.  At each
+check cycle attributes are logged as a line of semicolon separated triplets
+of the form "attribute-ID;attribute-norm-value;attribute-raw-value;".
+Each line is led by a date string of the form "yyyy-mm-dd HH:MM:SS" (in UTC).
 
 .\" BEGIN ENABLE_ATTRIBUTELOG
 If this option is not specified, attribute information is written to files
@@ -153,9 +156,9 @@ then files 'nameMODEL\-SERIAL.ata.csv' are created in directory '/path/'.
 The path must be absolute, except if debug mode is enabled.
 .TP
 .B \-B [+]FILE, \-\-drivedb=[+]FILE
-[NEW EXPERIMENTAL SMARTD FEATURE] Read the drive database from FILE.
-The new database replaces the built in database by default. If \'+\' is
-specified, then the new entries prepend the built in entries.
+[ATA only] Read the drive database from FILE.  The new database replaces
+the built in database by default.  If \'+\' is specified, then the new entries
+prepend the built in entries.
 Please see the \fBsmartctl\fP(8) man page for further details.
 .TP
 .B \-c FILE, \-\-configfile=FILE
@@ -385,8 +388,7 @@ The default level is 1, so \'\-r ataioctl,1\' and \'\-r ataioctl\' are
 equivalent.
 .TP
 .B \-s PREFIX, \-\-savestates=PREFIX
-[NEW EXPERIMENTAL SMARTD FEATURE] [ATA ONLY]
-Reads/writes \fBsmartd\fP state information from/to files
+[ATA only] Reads/writes \fBsmartd\fP state information from/to files
 \'PREFIX\'\'MODEL\-SERIAL.ata.state\'. This preserves SMART attributes, drive
 min and max temperatures (\-W directive), info about last sent warning email
 (\-m directive), and the time of next check of the self-test REGEXP
@@ -600,12 +602,19 @@ Section below!
 .B #
 .nf
 .B # Two ATA disks on a 3ware 9000 controller.
-.B # Start long self-tests Sundays between  midnight and 
+.B # Start long self-tests Sundays between midnight and
 .B # 1am and 2-3 am
 .B \ \ /dev/twa0 -d 3ware,0 -a -s L/../../7/00
 .B \ \ /dev/twa0 -d 3ware,1 -a -s L/../../7/02
 .B #
 .nf
+.B # Two SATA (not SAS) disks on a 3ware 9750 controller.
+.B # Start long self-tests Sundays between midnight and
+.B # 1am and 2-3 am
+.B \ \ /dev/twl0 -d 3ware,0 -a -s L/../../7/00
+.B \ \ /dev/twl0 -d 3ware,1 -a -s L/../../7/02
+.B #
+.nf
 .B # Three SATA disks on a HighPoint RocketRAID controller.
 .B # Start short self-tests daily between 1-2, 2-3, and
 .B # 3-4 am.
@@ -695,11 +704,11 @@ indicates a disk failure or problem, if the SCSI inquiry about disk
 status fails, or if new errors appear in the self-test log.
 
 .B If a 3ware controller is used
-then the corresponding SCSI (/dev/sd?) or character device (/dev/twe?
-or /dev/twa?) must be listed, along with the \'\-d 3ware,N\' Directive
-(see below).  The individual ATA disks hosted by the 3ware controller
-appear to \fBsmartd\fP as normal ATA devices.  Hence all the ATA
-directives can be used for these disks (but see note below).
+then the corresponding SCSI (/dev/sd?) or character device (/dev/twe?,
+/dev/twa? or /dev/twl?) must be listed, along with the \'\-d 3ware,N\'
+Directive (see below).  The individual ATA disks hosted by the 3ware
+controller appear to \fBsmartd\fP as normal ATA devices.  Hence all
+the ATA directives can be used for these disks (but see note below).
 
 .B If an Areca controller is used
 then the corresponding SCSI generic device (/dev/sg?)  must be listed,
@@ -711,22 +720,14 @@ smartmontools must be used; Please see the \fBsmartctl\fP(8) man page
 for further details.
 .TP
 .B \-d TYPE
-Specifies the type of the device.  This Directive may be used multiple
-times for one device, but the arguments \fIata\fP, \fIscsi\fP,
-\fIsat\fP, \fImarvell\fP, \fIcciss,N\fP, \fIareca,N\fP, \fImegaraid,N\fP
-and \fI3ware,N\fP are mutually-exclusive. If more than one is given then
-\fBsmartd\fP will use the last one which appears.
-
-If none of these three arguments is given, then \fBsmartd\fP will
-first attempt to guess the device type by looking at whether the sixth
-character in the device name is an \'s\' or an \'h\'.  This will work for
-device names like /dev/hda or /dev/sdb, and corresponds to choosing
-\fIata\fP or \fIscsi\fP respectively. If
-\fBsmartd\fP
-can\'t guess from this sixth character, then it will simply try to
-access the device using first ATA and then SCSI ioctl()s.
+Specifies the type of the device.
+The valid arguments to this directive are:
 
-The valid arguments to this Directive are:
+.I auto
+- attempt to guess the device type from the device name or from
+controller type info provided by the operating system or from
+a matching USB ID entry in the drive database.
+This is the default.
 
 .I ata
 \- the device type is ATA.  This prevents
@@ -740,95 +741,93 @@ from issuing ATA commands to a SCSI device.
 
 .I sat
 \- the device type is SCSI to ATA Translation (SAT).
-\fBsmartd\fP
-will generate ATA (smart) commands and then package them in
-the SAT defined ATA PASS THROUGH SCSI commands. The commands
-are then routed through the SCSI pass through interface to the
-operating system. There are two types of ATA PASS THROUGH
-SCSI commands: a 12 byte and 16 byte variant.
-\fBsmartd\fP
-can use either and defaults to the 16 byte variant. This can
-be overridden with this syntax: \'\-d sat,12\' or \'\-d sat,16\'.
+This is for ATA disks that have a SCSI to ATA Translation (SAT) Layer
+(SATL) between the disk and the operating system.
+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\'.
+
+.I usbcypress
+\- this device type is for ATA disks that are behind a Cypress USB to PATA
+bridge.  This will use the ATACB proprietary scsi pass through command.
+The default SCSI operation code is 0x24, but although it can be overridden
+with \'\-d usbcypress,0xN\', where N is the scsi operation code,
+you're running the risk of damage to the device or filesystems on it.
+
+.I usbjmicron
+- this device type is for SATA disks that are behind a JMicron USB to
+PATA/SATA bridge.  The 48-bit ATA commands (required e.g. for \'\-l xerror\',
+see below) do not work with all of these bridges and are therefore disabled by
+default.  These commands can be enabled by \'\-d usbjmicron,x\'.
+If two disks are connected to a bridge with two ports, an error message is printed
+if no PORT is specified.
+The port can be specified by \'\-d usbjmicron[,x],PORT\' where PORT is 0
+(master) or 1 (slave).  This is not necessary if the device uses a port
+multiplier to connect multiple disks to one port.  The disks appear under
+separate /dev/ice names then.
+CAUTION: Specifying \',x\' for a device which does not support it results
+in I/O errors and may disconnect the drive.  The same applies if the specified
+PORT does not exist or is not connected to a disk.
+
+.I usbsunplus
+\- this device type is for SATA disks that are behind a SunplusIT USB to SATA
+bridge.
 
 .I marvell
-\- Under Linux, interact with SATA disks behind Marvell chip-set
+\- [Linux only] interact with SATA disks behind Marvell chip-set
 controllers (using the Marvell rather than libata driver).
 
 .I megaraid,N
-\- the device consists of one or more SCSI/SAS/SATA disks connected
-to a MegaRAID controller.  The non-negative integer N (in the range
-of 0 to 127 inclusive) denotes which disk on the controller is monitored.
+\- [Linux only] the device consists of one or more SCSI/SAS disks connected
+to a MegaRAID controller.  The non-negative integer N (in the range of 0 to
+127 inclusive) denotes which disk on the controller is monitored.
+This interface will also work for Dell PERC controllers.
 In log files and email messages this disk will be identified as
 megaraid_disk_XXX with XXX in the range from 000 to 127 inclusive.
+Please see the \fBsmartctl\fP(8) man page for further details.
 
 .I 3ware,N
-\- the device consists of one or more ATA disks connected to a 3ware
-RAID controller. The non-negative integer N (in the range from 0 to 127 
-inclusive) denotes which disk on the controller is monitored.  In log
-files and email messages this disk will be identified as 3ware_disk_XXX
+\- [FreeBSD and Linux only] the device consists of one or more ATA disks
+connected to a 3ware RAID controller.  The non-negative integer N
+(in the range from 0 to 127 inclusive) denotes which disk on the controller
+is monitored.
+In log files and email messages this disk will be identified as 3ware_disk_XXX
 with XXX in the range from 000 to 127 inclusive.
 
-This Directive may at first appear confusing, because the 3ware
-controller is a SCSI device (such as /dev/sda) and should be listed as
-such in the the configuration file.
-However when the \'\-d 3ware,N\'
-Directive is used, then the corresponding disk is addressed using
-native ATA commands which are \'passed through\' the SCSI driver. All
-ATA Directives listed in this man page may be used.  Note that while
-you may use \fBany\fP of the 3ware SCSI logical devices /dev/sd? to
-address \fBany\fP of the physical disks (3ware ports), error and log
+Note that while you may use \fBany\fP of the 3ware SCSI logical devices /dev/tw*
+to address \fBany\fP of the physical disks (3ware ports), error and log
 messages will make the most sense if you always list the 3ware SCSI
-logical device corresponding to the particular physical disks.  Please
-see the \fBsmartctl\fP(8) man page for further details.
-
-ATA disks behind 3ware controllers may alternatively be accessed via a
-character device interface /dev/twe0-15 (3ware 6000/7000/8000
-controllers) and /dev/twa0-15 (3ware 9000 series controllers).  Note
-that the 9000 series controllers may \fBonly\fP be accessed using the
-character device interface /dev/twa0-15 and not the SCSI device
-interface /dev/sd?.  Please see the \fBsmartctl\fP(8) man page for
-further details.
-
-Note that older 3w-xxxx drivers do not pass the \'Enable Autosave\'
-(\fB-S on\fP) and \'Enable Automatic Offline\' (\fB-o on\fP) commands
-to the disk, if the SCSI interface is used, and produce these types of
-harmless syslog error messages instead: \fB\'3w-xxxx: tw_ioctl():
-Passthru size (123392) too big\'\fP. This can be fixed by upgrading to
-version 1.02.00.037 or later of the 3w-xxxx driver, or by applying a
-patch to older versions.  See
-\fBhttp://smartmontools.sourceforge.net/\fP for instructions.
-Alternatively use the character device interfaces /dev/twe0-15 (3ware
-6/7/8000 series controllers) or /dev/twa0-15 (3ware 9000 series
-controllers).
+logical device corresponding to the particular physical disks.
+Please see the \fBsmartctl\fP(8) man page for further details.
 
 .I areca,N
-\- 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
+\- [Linux 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.
 
 .I cciss,N
-\- the device consists of one or more SCSI disks connected to a cciss
-RAID controller. The non-negative integer N (in the range from 0 to 15
-inclusive) denotes which disk on the controller is monitored.  In log
-files and email messages this disk will be identified as cciss_disk_XX
+\- [FreeBSD and Linux only] the device consists of one or more SCSI/SAS disks
+connected to a cciss RAID controller.  The non-negative integer N (in the range
+from 0 to 15 inclusive) denotes which disk on the controller is monitored.
+In log files and email messages this disk will be identified as cciss_disk_XX
 with XX in the range from 00 to 15 inclusive.
-
-.B 3ware, MegaRAID, Areca and cciss controllers are currently ONLY supported under Linux.
+Please see the \fBsmartctl\fP(8) man page for further details.
 
 .I hpt,L/M/N
-\- the device consists of one or more ATA disks connected to a HighPoint
-RocketRAID controller.  The integer L is the controller id, the integer M
-is the channel number, and the integer N is the PMPort number if it is
-available. The allowed values of L are from 1 to 4 inclusive, M are from
-1 to 8 inclusive and N from 1 to 4 if PMPort available.  And also these
-values are limited by the model of the HighPoint RocketRAID controller.
+\- [FreeBSD and Linux only] the device consists of one or more ATA disks
+connected to a HighPoint RocketRAID controller.  The integer L is the
+controller id, the integer M is the channel number, and the integer N
+is the PMPort number if it is available.  The allowed values of L are
+from 1 to 4 inclusive, M are from 1 to 8 inclusive and N from 1 to 4
+if PMPort available.  And also these values are limited by the model
+of the HighPoint RocketRAID controller.
 In log files and email messages this disk will be identified as
 hpt_X/X/X and X/X/X is the same as L/M/N, note if no N indicated, N set
 to the default value 1.
-
-.B HighPoint RocketRAID controllers are currently ONLY supported under Linux and FreeBSD.
+Please see the \fBsmartctl\fP(8) man page for further details.
 
 .I removable
 \- the device or its media is removable.  This indicates to
@@ -839,8 +838,8 @@ behavior) if the device does not appear to be present when
 with the other \'\-d\' Directives.
 .TP
 .B \-n POWERMODE[,N][,q]
-This \'nocheck\' Directive is used to prevent a disk from being
-spun-up when it is periodically polled by \fBsmartd\fP.
+[ATA only] This \'nocheck\' Directive is used to prevent a disk from
+being spun-up when it is periodically polled by \fBsmartd\fP.
 
 ATA disks have five different power states. In order of increasing
 power consumption they are: \'OFF\', \'SLEEP\', \'STANDBY\', \'IDLE\',
@@ -917,7 +916,7 @@ self\-test logging.
 [Please see the \fBsmartctl \-T\fP command-line option.]
 .TP
 .B \-o VALUE
-Enables or disables SMART Automatic Offline Testing when
+[ATA only] Enables or disables SMART Automatic Offline Testing when
 \fBsmartd\fP
 starts up and has no further effect.  The valid arguments to this
 Directive are \fIon\fP and \fIoff\fP.
@@ -938,7 +937,7 @@ Directive are \fIon\fP and \fIoff\fP.  Also affects SCSI devices.
 [Please see the \fBsmartctl \-S\fP command-line option.]
 .TP
 .B \-H
-Check the SMART health status of the disk.  If any Prefailure
+[ATA only] Check the SMART health status of the disk.  If any Prefailure
 Attributes are less than or equal to their threshold values, then disk
 failure is predicted in less than 24 hours, and a message at loglevel
 .B \'LOG_CRIT\'
@@ -951,13 +950,13 @@ Reports increases in the number of errors in one of three SMART logs.  The
 valid arguments to this Directive are:
 
 .I error
-\- report if the number of ATA errors reported in the Summary SMART error log
-has increased since the last check.
+\- [ATA only] report if the number of ATA errors reported in the Summary SMART
+error log has increased since the last check.
 
 .I xerror
-\- [NEW EXPERIMENTAL SMARTD FEATURE] report if the number of ATA errors
-reported in the Extended Comprehensive SMART error log has increased since
-the last check.
+\- [ATA only] [NEW EXPERIMENTAL SMARTD FEATURE] report if the number of ATA
+errors reported in the Extended Comprehensive SMART error log has increased
+since the last check.
 
 If both \'\-l error\' and \'\-l xerror\' are specified, smartd checks
 the maximum of both values.
@@ -974,10 +973,22 @@ disk (and it fails a test!).  Self-Tests can be run automatically by
 Self-Tests can also be run manually by using the \fB\'\-t\ short\'\fP
 and \fB\'\-t\ long\'\fP options of \fBsmartctl\fP and the results of
 the testing can be observed using the \fBsmartctl \'\-l\ selftest\'\fP
-command-line option.]
-
+command-line option.
 [Please see the \fBsmartctl \-l\fP and \fB\-t\fP command-line
 options.]
+
+[ATA only] Failed self-tests outdated by a newer successful extended
+self\-test are ignored.
+
+.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.
+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.
+[Please see the \fBsmartctl \-l scterc\fP command-line option.]
+
 .TP
 .B \-s REGEXP
 Run Self-Tests or Offline Immediate Tests, at scheduled times.  A
@@ -993,14 +1004,18 @@ only), and \'O\' for an \fBO\fPffline Immediate Test (ATA only).  As
 soon as a match is found, the test will be started and no additional
 matches will be sought for that device and that polling cycle.
 
-[NEW EXPERIMENTAL SMARTD FEATURE] To run scheduled Selective
-Self-Tests, use \'n\' for \fBn\fPext span, \'r\' to \fBr\fPedo last
-span, or \'c\' to \fBc\fPontinue with next span or redo last span
-based on status of last test. The LBA range is based on the first
-span from the last test.
+To run scheduled Selective Self-Tests, use \'n\' for \fBn\fPext span,
+\'r\' to \fBr\fPedo last span, or \'c\' to \fBc\fPontinue with next span
+or redo last span based on status of last test.
+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.
+
 .IP \fBMM\fP 4
 is the month of the year, expressed with two decimal digits.  The
 range is from 01 (January) to 12 (December) inclusive.  Do \fBnot\fP
@@ -1188,11 +1203,12 @@ three):
 
 .I once
 \- send only one warning email for each type of disk problem detected.  This
-is the default.
+is the default unless state persistence (\'\-s\' option) is enabled.
 
 .I daily
 \- send additional warning reminder emails, once per day, for each type
-of disk problem detected.
+of disk problem detected.  This is the default if state persistence
+(\'\-s\' option) is enabled.
 
 .I diminishing
 \- send additional warning reminder emails, after a one-day interval,
@@ -1246,10 +1262,8 @@ is set to the argument of \-M exec, if present or else to \'mail\'
 .IP \fBSMARTD_DEVICE\fP 4
 is set to the device path (examples: /dev/hda, /dev/sdb).
 .IP \fBSMARTD_DEVICETYPE\fP 4
-is set to the device type (possible values: ata, scsi, 3ware,N,
-areca,N, hpt,L/M/N).  Here N=0,...,127 denotes the ATA disk behind a
-3ware RAID controller and L/M/N denotes the SATA disk behind a
-HighPoint RocketRAID controller.
+is set to the device type specified by \'-d\' directive or
+\'auto\' if none.
 .IP \fBSMARTD_DEVICESTRING\fP 4
 is set to the device description.  For SMARTD_DEVICETYPE of ata or
 scsi, this is the same as SMARTD_DEVICE.  For 3ware RAID controllers,
@@ -1383,32 +1397,32 @@ Directive are given below. Some sample scripts are also included in
 /usr/local/share/doc/smartmontools/examplescripts/.
 .TP
 .B \-f
-Check for \'failure\' of any Usage Attributes.  If these Attributes are
-less than or equal to the threshold, it does NOT indicate imminent
-disk failure.  It "indicates an advisory condition where the usage or
-age of the device has exceeded its intended design life period."
+[ATA only] Check for \'failure\' of any Usage Attributes.  If these
+Attributes are less than or equal to the threshold, it does NOT indicate
+imminent disk failure.  It "indicates an advisory condition where the usage
+or age of the device has exceeded its intended design life period."
 [Please see the \fBsmartctl \-A\fP command-line option.]
 .TP
 .B \-p
-Report anytime that a Prefail Attribute has changed
+[ATA only] Report anytime that a Prefail Attribute has changed
 its value since the last check, 30 minutes ago. [Please see the
 .B smartctl \-A
 command-line option.]
 .TP
 .B \-u
-Report anytime that a Usage Attribute has changed its value
+[ATA only] Report anytime that a Usage Attribute has changed its value
 since the last check, 30 minutes ago. [Please see the
 .B smartctl \-A
 command-line option.]
 .TP
 .B \-t
-Equivalent to turning on the two previous flags \'\-p\' and \'\-u\'.
+[ATA only] Equivalent to turning on the two previous flags \'\-p\' and \'\-u\'.
 Tracks changes in \fIall\fP device Attributes (both Prefailure and
 Usage). [Please see the \fBsmartctl\fP \-A command-line option.]
 .TP
 .B \-i ID
-Ignore device Attribute number \fBID\fP when checking for failure of
-Usage Attributes.  \fBID\fP must be a decimal integer in the range
+[ATA only] Ignore device Attribute number \fBID\fP when checking for failure
+of Usage Attributes.  \fBID\fP must be a decimal integer in the range
 from 1 to 255.  This Directive modifies the behavior of the \'\-f\'
 Directive and has no effect without it.
 
@@ -1418,7 +1432,7 @@ want to keep getting messages about the hours-on-lifetime Attribute
 times for a single device, if you want to ignore multiple Attributes.
 .TP
 .B \-I ID
-Ignore device Attribute \fBID\fP when tracking changes in the
+[ATA only] Ignore device Attribute \fBID\fP when tracking changes in the
 Attribute values.  \fBID\fP must be a decimal integer in the range
 from 1 to 255.  This Directive modifies the behavior of the \'\-p\',
 \'\-u\', and \'\-t\' tracking Directives and has no effect without one
@@ -1430,9 +1444,9 @@ each time the temperature changes.  This Directive may appear multiple
 times for a single device, if you want to ignore multiple Attributes.
 .TP
 .B \-r ID[!]
-When tracking, report the \fIRaw\fP value of Attribute \fBID\fP along
-with its (normally reported) \fINormalized\fP value.  \fBID\fP must be
-a decimal integer in the range from 1 to 255.  This Directive modifies
+[ATA only] When tracking, report the \fIRaw\fP value of Attribute \fBID\fP
+along with its (normally reported) \fINormalized\fP value.  \fBID\fP must
+be a decimal integer in the range from 1 to 255.  This Directive modifies
 the behavior of the \'\-p\', \'\-u\', and \'\-t\' tracking Directives
 and has no effect without one of them.  This Directive may be given
 multiple times.
@@ -1445,7 +1459,7 @@ value is considered critical.  The report will be logged as LOG_CRIT
 and a warning email will be sent if \'-m\' is specified.
 .TP
 .B \-R ID[!]
-When tracking, report whenever the \fIRaw\fP value of Attribute
+[ATA only] When tracking, report whenever the \fIRaw\fP value of Attribute
 \fBID\fP changes.  (Normally \fBsmartd\fP only tracks/reports changes
 of the \fINormalized\fP Attribute values.)  \fBID\fP must be a decimal
 integer in the range from 1 to 255.  This Directive modifies the
@@ -1614,10 +1628,9 @@ reset if uncorrectable sector are reallocated.  This sets \'-U 198+\'
 if no other \'-U\' directive is specified.
 .TP
 .B \-P TYPE
-Specifies whether
-\fBsmartd\fP
-should use any preset options that are available for this drive.  The
-valid arguments to this Directive are:
+[ATA only] Specifies whether \fBsmartd\fP should use any preset options
+that are available for this drive.
+The valid arguments to this Directive are:
 
 .I use
 \- use any presets that are available for this drive.  This is the default.
@@ -2059,4 +2072,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 3117 2010-06-08 15:41:04Z chrfranke $
+$Id: smartd.8.in 3284 2011-03-04 21:33:35Z chrfranke $
index 7ad83a8a83cc3bd144e1322598023312f8305da8..7605d5c7c8126937e4fba1d2b1f8866832dbe561 100644 (file)
@@ -2,7 +2,7 @@
 
 # Home page is: http://smartmontools.sourceforge.net
 
-# $Id: smartd.conf,v 1.45 2006/11/12 23:39:04 dpgilbert Exp $
+# $Id: smartd.conf 3128 2010-07-27 13:08:31Z chrfranke $
 
 # smartd will re-read the configuration file if it receives a HUP
 # signal
@@ -76,12 +76,18 @@ DEVICESCAN
 #/dev/sdc -d 3ware,2 -a -s L/../../7/03
 #/dev/sdc -d 3ware,3 -a -s L/../../7/04
 
-# Monitor 2 ATA disks connected to a 3ware 9000 controller which uses
-# the 3w-9xxx driver (Linux, FreeBSD). Start long self-tests Tuesdays
+# Monitor 2 ATA disks connected to a 3ware 9000 controller which
+# uses the 3w-9xxx driver (Linux, FreeBSD). Start long self-tests Tuesdays
 # between 1-2 and 3-4 am.
 #/dev/twa0 -d 3ware,0 -a -s L/../../2/01
 #/dev/twa0 -d 3ware,1 -a -s L/../../2/03
 
+# Monitor 2 SATA (not SAS) disks connected to a 3ware 9000 controller which
+# uses the 3w-sas driver (Linux, FreeBSD). Start long self-tests Tuesdays
+# between 1-2 and 3-4 am.
+#/dev/twl0 -d 3ware,0 -a -s L/../../2/01
+#/dev/twa0 -d 3ware,1 -a -s L/../../2/03
+
 # Same as above for Windows. Option '-d 3ware,N' is not necessary,
 # disk (port) number is specified in device name.
 # NOTE: On Windows, DEVICESCAN works also for 3ware controllers.
index 103b9e5240bb06a80f8d9497ea678bacb81f2a6f..caa91a660bf97fbf19c3a7a777339655f9c1e23f 100644 (file)
@@ -1,7 +1,7 @@
 .ig
 Copyright (C) 2002-10 Bruce Allen <smartmontools-support@lists.sourceforge.net>
 
-$Id: smartd.conf.5.in 3117 2010-06-08 15:41:04Z chrfranke $
+$Id: smartd.conf.5.in 3284 2011-03-04 21:33:35Z 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
@@ -176,12 +176,19 @@ Section below!
 .B #
 .nf
 .B # Two ATA disks on a 3ware 9000 controller.
-.B # Start long self-tests Sundays between  midnight and 
+.B # Start long self-tests Sundays between midnight and
 .B # 1am and 2-3 am
 .B \ \ /dev/twa0 -d 3ware,0 -a -s L/../../7/00
 .B \ \ /dev/twa0 -d 3ware,1 -a -s L/../../7/02
 .B #
 .nf
+.B # Two SATA (not SAS) disks on a 3ware 9750 controller.
+.B # Start long self-tests Sundays between midnight and
+.B # 1am and 2-3 am
+.B \ \ /dev/twl0 -d 3ware,0 -a -s L/../../7/00
+.B \ \ /dev/twl0 -d 3ware,1 -a -s L/../../7/02
+.B #
+.nf
 .B # Three SATA disks on a HighPoint RocketRAID controller.
 .B # Start short self-tests daily between 1-2, 2-3, and
 .B # 3-4 am.
@@ -271,11 +278,11 @@ indicates a disk failure or problem, if the SCSI inquiry about disk
 status fails, or if new errors appear in the self-test log.
 
 .B If a 3ware controller is used
-then the corresponding SCSI (/dev/sd?) or character device (/dev/twe?
-or /dev/twa?) must be listed, along with the \'\-d 3ware,N\' Directive
-(see below).  The individual ATA disks hosted by the 3ware controller
-appear to \fBsmartd\fP as normal ATA devices.  Hence all the ATA
-directives can be used for these disks (but see note below).
+then the corresponding SCSI (/dev/sd?) or character device (/dev/twe?,
+/dev/twa? or /dev/twl?) must be listed, along with the \'\-d 3ware,N\'
+Directive (see below).  The individual ATA disks hosted by the 3ware
+controller appear to \fBsmartd\fP as normal ATA devices.  Hence all
+the ATA directives can be used for these disks (but see note below).
 
 .B If an Areca controller is used
 then the corresponding SCSI generic device (/dev/sg?)  must be listed,
@@ -287,22 +294,14 @@ smartmontools must be used; Please see the \fBsmartctl\fP(8) man page
 for further details.
 .TP
 .B \-d TYPE
-Specifies the type of the device.  This Directive may be used multiple
-times for one device, but the arguments \fIata\fP, \fIscsi\fP,
-\fIsat\fP, \fImarvell\fP, \fIcciss,N\fP, \fIareca,N\fP, \fImegaraid,N\fP
-and \fI3ware,N\fP are mutually-exclusive. If more than one is given then
-\fBsmartd\fP will use the last one which appears.
-
-If none of these three arguments is given, then \fBsmartd\fP will
-first attempt to guess the device type by looking at whether the sixth
-character in the device name is an \'s\' or an \'h\'.  This will work for
-device names like /dev/hda or /dev/sdb, and corresponds to choosing
-\fIata\fP or \fIscsi\fP respectively. If
-\fBsmartd\fP
-can\'t guess from this sixth character, then it will simply try to
-access the device using first ATA and then SCSI ioctl()s.
+Specifies the type of the device.
+The valid arguments to this directive are:
 
-The valid arguments to this Directive are:
+.I auto
+- attempt to guess the device type from the device name or from
+controller type info provided by the operating system or from
+a matching USB ID entry in the drive database.
+This is the default.
 
 .I ata
 \- the device type is ATA.  This prevents
@@ -316,95 +315,93 @@ from issuing ATA commands to a SCSI device.
 
 .I sat
 \- the device type is SCSI to ATA Translation (SAT).
-\fBsmartd\fP
-will generate ATA (smart) commands and then package them in
-the SAT defined ATA PASS THROUGH SCSI commands. The commands
-are then routed through the SCSI pass through interface to the
-operating system. There are two types of ATA PASS THROUGH
-SCSI commands: a 12 byte and 16 byte variant.
-\fBsmartd\fP
-can use either and defaults to the 16 byte variant. This can
-be overridden with this syntax: \'\-d sat,12\' or \'\-d sat,16\'.
+This is for ATA disks that have a SCSI to ATA Translation (SAT) Layer
+(SATL) between the disk and the operating system.
+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\'.
+
+.I usbcypress
+\- this device type is for ATA disks that are behind a Cypress USB to PATA
+bridge.  This will use the ATACB proprietary scsi pass through command.
+The default SCSI operation code is 0x24, but although it can be overridden
+with \'\-d usbcypress,0xN\', where N is the scsi operation code,
+you're running the risk of damage to the device or filesystems on it.
+
+.I usbjmicron
+- this device type is for SATA disks that are behind a JMicron USB to
+PATA/SATA bridge.  The 48-bit ATA commands (required e.g. for \'\-l xerror\',
+see below) do not work with all of these bridges and are therefore disabled by
+default.  These commands can be enabled by \'\-d usbjmicron,x\'.
+If two disks are connected to a bridge with two ports, an error message is printed
+if no PORT is specified.
+The port can be specified by \'\-d usbjmicron[,x],PORT\' where PORT is 0
+(master) or 1 (slave).  This is not necessary if the device uses a port
+multiplier to connect multiple disks to one port.  The disks appear under
+separate /dev/ice names then.
+CAUTION: Specifying \',x\' for a device which does not support it results
+in I/O errors and may disconnect the drive.  The same applies if the specified
+PORT does not exist or is not connected to a disk.
+
+.I usbsunplus
+\- this device type is for SATA disks that are behind a SunplusIT USB to SATA
+bridge.
 
 .I marvell
-\- Under Linux, interact with SATA disks behind Marvell chip-set
+\- [Linux only] interact with SATA disks behind Marvell chip-set
 controllers (using the Marvell rather than libata driver).
 
 .I megaraid,N
-\- the device consists of one or more SCSI/SAS/SATA disks connected
-to a MegaRAID controller.  The non-negative integer N (in the range
-of 0 to 127 inclusive) denotes which disk on the controller is monitored.
+\- [Linux only] the device consists of one or more SCSI/SAS disks connected
+to a MegaRAID controller.  The non-negative integer N (in the range of 0 to
+127 inclusive) denotes which disk on the controller is monitored.
+This interface will also work for Dell PERC controllers.
 In log files and email messages this disk will be identified as
 megaraid_disk_XXX with XXX in the range from 000 to 127 inclusive.
+Please see the \fBsmartctl\fP(8) man page for further details.
 
 .I 3ware,N
-\- the device consists of one or more ATA disks connected to a 3ware
-RAID controller. The non-negative integer N (in the range from 0 to 127 
-inclusive) denotes which disk on the controller is monitored.  In log
-files and email messages this disk will be identified as 3ware_disk_XXX
+\- [FreeBSD and Linux only] the device consists of one or more ATA disks
+connected to a 3ware RAID controller.  The non-negative integer N
+(in the range from 0 to 127 inclusive) denotes which disk on the controller
+is monitored.
+In log files and email messages this disk will be identified as 3ware_disk_XXX
 with XXX in the range from 000 to 127 inclusive.
 
-This Directive may at first appear confusing, because the 3ware
-controller is a SCSI device (such as /dev/sda) and should be listed as
-such in the the configuration file.
-However when the \'\-d 3ware,N\'
-Directive is used, then the corresponding disk is addressed using
-native ATA commands which are \'passed through\' the SCSI driver. All
-ATA Directives listed in this man page may be used.  Note that while
-you may use \fBany\fP of the 3ware SCSI logical devices /dev/sd? to
-address \fBany\fP of the physical disks (3ware ports), error and log
+Note that while you may use \fBany\fP of the 3ware SCSI logical devices /dev/tw*
+to address \fBany\fP of the physical disks (3ware ports), error and log
 messages will make the most sense if you always list the 3ware SCSI
-logical device corresponding to the particular physical disks.  Please
-see the \fBsmartctl\fP(8) man page for further details.
-
-ATA disks behind 3ware controllers may alternatively be accessed via a
-character device interface /dev/twe0-15 (3ware 6000/7000/8000
-controllers) and /dev/twa0-15 (3ware 9000 series controllers).  Note
-that the 9000 series controllers may \fBonly\fP be accessed using the
-character device interface /dev/twa0-15 and not the SCSI device
-interface /dev/sd?.  Please see the \fBsmartctl\fP(8) man page for
-further details.
-
-Note that older 3w-xxxx drivers do not pass the \'Enable Autosave\'
-(\fB-S on\fP) and \'Enable Automatic Offline\' (\fB-o on\fP) commands
-to the disk, if the SCSI interface is used, and produce these types of
-harmless syslog error messages instead: \fB\'3w-xxxx: tw_ioctl():
-Passthru size (123392) too big\'\fP. This can be fixed by upgrading to
-version 1.02.00.037 or later of the 3w-xxxx driver, or by applying a
-patch to older versions.  See
-\fBhttp://smartmontools.sourceforge.net/\fP for instructions.
-Alternatively use the character device interfaces /dev/twe0-15 (3ware
-6/7/8000 series controllers) or /dev/twa0-15 (3ware 9000 series
-controllers).
+logical device corresponding to the particular physical disks.
+Please see the \fBsmartctl\fP(8) man page for further details.
 
 .I areca,N
-\- 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
+\- [Linux 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.
 
 .I cciss,N
-\- the device consists of one or more SCSI disks connected to a cciss
-RAID controller. The non-negative integer N (in the range from 0 to 15
-inclusive) denotes which disk on the controller is monitored.  In log
-files and email messages this disk will be identified as cciss_disk_XX
+\- [FreeBSD and Linux only] the device consists of one or more SCSI/SAS disks
+connected to a cciss RAID controller.  The non-negative integer N (in the range
+from 0 to 15 inclusive) denotes which disk on the controller is monitored.
+In log files and email messages this disk will be identified as cciss_disk_XX
 with XX in the range from 00 to 15 inclusive.
-
-.B 3ware, MegaRAID, Areca and cciss controllers are currently ONLY supported under Linux.
+Please see the \fBsmartctl\fP(8) man page for further details.
 
 .I hpt,L/M/N
-\- the device consists of one or more ATA disks connected to a HighPoint
-RocketRAID controller.  The integer L is the controller id, the integer M
-is the channel number, and the integer N is the PMPort number if it is
-available. The allowed values of L are from 1 to 4 inclusive, M are from
-1 to 8 inclusive and N from 1 to 4 if PMPort available.  And also these
-values are limited by the model of the HighPoint RocketRAID controller.
+\- [FreeBSD and Linux only] the device consists of one or more ATA disks
+connected to a HighPoint RocketRAID controller.  The integer L is the
+controller id, the integer M is the channel number, and the integer N
+is the PMPort number if it is available.  The allowed values of L are
+from 1 to 4 inclusive, M are from 1 to 8 inclusive and N from 1 to 4
+if PMPort available.  And also these values are limited by the model
+of the HighPoint RocketRAID controller.
 In log files and email messages this disk will be identified as
 hpt_X/X/X and X/X/X is the same as L/M/N, note if no N indicated, N set
 to the default value 1.
-
-.B HighPoint RocketRAID controllers are currently ONLY supported under Linux and FreeBSD.
+Please see the \fBsmartctl\fP(8) man page for further details.
 
 .I removable
 \- the device or its media is removable.  This indicates to
@@ -415,8 +412,8 @@ behavior) if the device does not appear to be present when
 with the other \'\-d\' Directives.
 .TP
 .B \-n POWERMODE[,N][,q]
-This \'nocheck\' Directive is used to prevent a disk from being
-spun-up when it is periodically polled by \fBsmartd\fP.
+[ATA only] This \'nocheck\' Directive is used to prevent a disk from
+being spun-up when it is periodically polled by \fBsmartd\fP.
 
 ATA disks have five different power states. In order of increasing
 power consumption they are: \'OFF\', \'SLEEP\', \'STANDBY\', \'IDLE\',
@@ -493,7 +490,7 @@ self\-test logging.
 [Please see the \fBsmartctl \-T\fP command-line option.]
 .TP
 .B \-o VALUE
-Enables or disables SMART Automatic Offline Testing when
+[ATA only] Enables or disables SMART Automatic Offline Testing when
 \fBsmartd\fP
 starts up and has no further effect.  The valid arguments to this
 Directive are \fIon\fP and \fIoff\fP.
@@ -514,7 +511,7 @@ Directive are \fIon\fP and \fIoff\fP.  Also affects SCSI devices.
 [Please see the \fBsmartctl \-S\fP command-line option.]
 .TP
 .B \-H
-Check the SMART health status of the disk.  If any Prefailure
+[ATA only] Check the SMART health status of the disk.  If any Prefailure
 Attributes are less than or equal to their threshold values, then disk
 failure is predicted in less than 24 hours, and a message at loglevel
 .B \'LOG_CRIT\'
@@ -527,13 +524,13 @@ Reports increases in the number of errors in one of three SMART logs.  The
 valid arguments to this Directive are:
 
 .I error
-\- report if the number of ATA errors reported in the Summary SMART error log
-has increased since the last check.
+\- [ATA only] report if the number of ATA errors reported in the Summary SMART
+error log has increased since the last check.
 
 .I xerror
-\- [NEW EXPERIMENTAL SMARTD FEATURE] report if the number of ATA errors
-reported in the Extended Comprehensive SMART error log has increased since
-the last check.
+\- [ATA only] [NEW EXPERIMENTAL SMARTD FEATURE] report if the number of ATA
+errors reported in the Extended Comprehensive SMART error log has increased
+since the last check.
 
 If both \'\-l error\' and \'\-l xerror\' are specified, smartd checks
 the maximum of both values.
@@ -550,10 +547,22 @@ disk (and it fails a test!).  Self-Tests can be run automatically by
 Self-Tests can also be run manually by using the \fB\'\-t\ short\'\fP
 and \fB\'\-t\ long\'\fP options of \fBsmartctl\fP and the results of
 the testing can be observed using the \fBsmartctl \'\-l\ selftest\'\fP
-command-line option.]
-
+command-line option.
 [Please see the \fBsmartctl \-l\fP and \fB\-t\fP command-line
 options.]
+
+[ATA only] Failed self-tests outdated by a newer successful extended
+self\-test are ignored.
+
+.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.
+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.
+[Please see the \fBsmartctl \-l scterc\fP command-line option.]
+
 .TP
 .B \-s REGEXP
 Run Self-Tests or Offline Immediate Tests, at scheduled times.  A
@@ -569,14 +578,18 @@ only), and \'O\' for an \fBO\fPffline Immediate Test (ATA only).  As
 soon as a match is found, the test will be started and no additional
 matches will be sought for that device and that polling cycle.
 
-[NEW EXPERIMENTAL SMARTD FEATURE] To run scheduled Selective
-Self-Tests, use \'n\' for \fBn\fPext span, \'r\' to \fBr\fPedo last
-span, or \'c\' to \fBc\fPontinue with next span or redo last span
-based on status of last test. The LBA range is based on the first
-span from the last test.
+To run scheduled Selective Self-Tests, use \'n\' for \fBn\fPext span,
+\'r\' to \fBr\fPedo last span, or \'c\' to \fBc\fPontinue with next span
+or redo last span based on status of last test.
+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.
+
 .IP \fBMM\fP 4
 is the month of the year, expressed with two decimal digits.  The
 range is from 01 (January) to 12 (December) inclusive.  Do \fBnot\fP
@@ -764,11 +777,12 @@ three):
 
 .I once
 \- send only one warning email for each type of disk problem detected.  This
-is the default.
+is the default unless state persistence (\'\-s\' option) is enabled.
 
 .I daily
 \- send additional warning reminder emails, once per day, for each type
-of disk problem detected.
+of disk problem detected.  This is the default if state persistence
+(\'\-s\' option) is enabled.
 
 .I diminishing
 \- send additional warning reminder emails, after a one-day interval,
@@ -822,10 +836,8 @@ is set to the argument of \-M exec, if present or else to \'mail\'
 .IP \fBSMARTD_DEVICE\fP 4
 is set to the device path (examples: /dev/hda, /dev/sdb).
 .IP \fBSMARTD_DEVICETYPE\fP 4
-is set to the device type (possible values: ata, scsi, 3ware,N,
-areca,N, hpt,L/M/N).  Here N=0,...,127 denotes the ATA disk behind a
-3ware RAID controller and L/M/N denotes the SATA disk behind a
-HighPoint RocketRAID controller.
+is set to the device type specified by \'-d\' directive or
+\'auto\' if none.
 .IP \fBSMARTD_DEVICESTRING\fP 4
 is set to the device description.  For SMARTD_DEVICETYPE of ata or
 scsi, this is the same as SMARTD_DEVICE.  For 3ware RAID controllers,
@@ -959,32 +971,32 @@ Directive are given below. Some sample scripts are also included in
 /usr/local/share/doc/smartmontools/examplescripts/.
 .TP
 .B \-f
-Check for \'failure\' of any Usage Attributes.  If these Attributes are
-less than or equal to the threshold, it does NOT indicate imminent
-disk failure.  It "indicates an advisory condition where the usage or
-age of the device has exceeded its intended design life period."
+[ATA only] Check for \'failure\' of any Usage Attributes.  If these
+Attributes are less than or equal to the threshold, it does NOT indicate
+imminent disk failure.  It "indicates an advisory condition where the usage
+or age of the device has exceeded its intended design life period."
 [Please see the \fBsmartctl \-A\fP command-line option.]
 .TP
 .B \-p
-Report anytime that a Prefail Attribute has changed
+[ATA only] Report anytime that a Prefail Attribute has changed
 its value since the last check, 30 minutes ago. [Please see the
 .B smartctl \-A
 command-line option.]
 .TP
 .B \-u
-Report anytime that a Usage Attribute has changed its value
+[ATA only] Report anytime that a Usage Attribute has changed its value
 since the last check, 30 minutes ago. [Please see the
 .B smartctl \-A
 command-line option.]
 .TP
 .B \-t
-Equivalent to turning on the two previous flags \'\-p\' and \'\-u\'.
+[ATA only] Equivalent to turning on the two previous flags \'\-p\' and \'\-u\'.
 Tracks changes in \fIall\fP device Attributes (both Prefailure and
 Usage). [Please see the \fBsmartctl\fP \-A command-line option.]
 .TP
 .B \-i ID
-Ignore device Attribute number \fBID\fP when checking for failure of
-Usage Attributes.  \fBID\fP must be a decimal integer in the range
+[ATA only] Ignore device Attribute number \fBID\fP when checking for failure
+of Usage Attributes.  \fBID\fP must be a decimal integer in the range
 from 1 to 255.  This Directive modifies the behavior of the \'\-f\'
 Directive and has no effect without it.
 
@@ -994,7 +1006,7 @@ want to keep getting messages about the hours-on-lifetime Attribute
 times for a single device, if you want to ignore multiple Attributes.
 .TP
 .B \-I ID
-Ignore device Attribute \fBID\fP when tracking changes in the
+[ATA only] Ignore device Attribute \fBID\fP when tracking changes in the
 Attribute values.  \fBID\fP must be a decimal integer in the range
 from 1 to 255.  This Directive modifies the behavior of the \'\-p\',
 \'\-u\', and \'\-t\' tracking Directives and has no effect without one
@@ -1006,9 +1018,9 @@ each time the temperature changes.  This Directive may appear multiple
 times for a single device, if you want to ignore multiple Attributes.
 .TP
 .B \-r ID[!]
-When tracking, report the \fIRaw\fP value of Attribute \fBID\fP along
-with its (normally reported) \fINormalized\fP value.  \fBID\fP must be
-a decimal integer in the range from 1 to 255.  This Directive modifies
+[ATA only] When tracking, report the \fIRaw\fP value of Attribute \fBID\fP
+along with its (normally reported) \fINormalized\fP value.  \fBID\fP must
+be a decimal integer in the range from 1 to 255.  This Directive modifies
 the behavior of the \'\-p\', \'\-u\', and \'\-t\' tracking Directives
 and has no effect without one of them.  This Directive may be given
 multiple times.
@@ -1021,7 +1033,7 @@ value is considered critical.  The report will be logged as LOG_CRIT
 and a warning email will be sent if \'-m\' is specified.
 .TP
 .B \-R ID[!]
-When tracking, report whenever the \fIRaw\fP value of Attribute
+[ATA only] When tracking, report whenever the \fIRaw\fP value of Attribute
 \fBID\fP changes.  (Normally \fBsmartd\fP only tracks/reports changes
 of the \fINormalized\fP Attribute values.)  \fBID\fP must be a decimal
 integer in the range from 1 to 255.  This Directive modifies the
@@ -1190,10 +1202,9 @@ reset if uncorrectable sector are reallocated.  This sets \'-U 198+\'
 if no other \'-U\' directive is specified.
 .TP
 .B \-P TYPE
-Specifies whether
-\fBsmartd\fP
-should use any preset options that are available for this drive.  The
-valid arguments to this Directive are:
+[ATA only] Specifies whether \fBsmartd\fP should use any preset options
+that are available for this drive.
+The valid arguments to this Directive are:
 
 .I use
 \- use any presets that are available for this drive.  This is the default.
@@ -1401,4 +1412,4 @@ SEE ALSO:
 
 .SH
 SVN ID OF THIS PAGE:
-$Id: smartd.conf.5.in 3117 2010-06-08 15:41:04Z chrfranke $
+$Id: smartd.conf.5.in 3284 2011-03-04 21:33:35Z chrfranke $
index 2241a7974ce6e3358e87acc333d898c551c6db5b..0ab6de736c68c322cb5cebe3e61d8a5e87ba6119 100644 (file)
@@ -1,10 +1,10 @@
 /*
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2002-10 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net>
  * Copyright (C) 2000    Michael Cornwell <cornwell@acm.org>
  * Copyright (C) 2008    Oliver Bock <brevilo@users.sourceforge.net>
- * Copyright (C) 2008-10 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2008-11 Christian Franke <smartmontools-support@lists.sourceforge.net>
  *
  * 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 +85,6 @@ extern "C" int __stdcall FreeConsole(void);
 #include "int64.h"
 #include "atacmds.h"
 #include "dev_interface.h"
-#include "extern.h"
 #include "knowndrives.h"
 #include "scsicmds.h"
 #include "utility.h"
@@ -126,12 +125,8 @@ extern "C" int getdomainname(char *, int); // no declaration in header files!
 
 #define ARGUSED(x) ((void)(x))
 
-const char * smartd_cpp_cvsid = "$Id: smartd.cpp 3101 2010-05-04 16:03:18Z chrfranke $"
-                                CONFIG_H_CVSID EXTERN_H_CVSID;
-
-extern const char *reportbug;
-
-extern unsigned char debugmode;
+const char * smartd_cpp_cvsid = "$Id: smartd.cpp 3288 2011-03-09 18:40:36Z chrfranke $"
+  CONFIG_H_CVSID;
 
 // smartd exit codes
 #define EXIT_BADCMD    1   // command line did not parse
@@ -149,6 +144,10 @@ extern unsigned char debugmode;
 
 #define EXIT_SIGNAL    254 // abort on signal
 
+
+// command-line: 1=debug mode, 2=print presets
+static unsigned char debugmode = 0;
+
 // command-line: how long to sleep between checks
 #define CHECKTIME 1800
 static int checktime=CHECKTIME;
@@ -193,23 +192,29 @@ static bool do_fork=true;
 static bool enable_capabilities = false;
 #endif
 
-// used for control of printing, passing arguments to atacmds.c
-smartmonctrl *con=NULL;
+#if defined(_WIN32) || defined(__CYGWIN__)
+// TODO: This smartctl only variable is also used in os_win32.cpp
+unsigned char failuretest_permissive = 0;
+#endif
 
 // set to one if we catch a USR1 (check devices now)
-volatile int caughtsigUSR1=0;
+static volatile int caughtsigUSR1=0;
 
 #ifdef _WIN32
 // set to one if we catch a USR2 (toggle debug mode)
-volatile int caughtsigUSR2=0;
+static volatile int caughtsigUSR2=0;
 #endif
 
 // set to one if we catch a HUP (reload config file). In debug mode,
 // set to two, if we catch INT (also reload config file).
-volatile int caughtsigHUP=0;
+static volatile int caughtsigHUP=0;
 
 // set to signal value if we catch INT, QUIT, or TERM
-volatile int caughtsigEXIT=0;
+static volatile int caughtsigEXIT=0;
+
+// This function prints either to stdout or to the syslog as needed.
+static void PrintOut(int priority, const char *fmt, ...)
+                     __attribute__ ((format(printf, 2, 3)));
 
 // Attribute monitoring flags.
 // See monitor_attr_flags below.
@@ -248,7 +253,8 @@ private:
 struct dev_config
 {
   int lineno;                             // Line number of entry in file
-  std::string name;                       // Device name
+  std::string name;                       // Device name (with optional extra info)
+  std::string dev_name;                   // Device name (plain, for SMARTD_DEVICE variable)
   std::string dev_type;                   // Device type argument from -d directive, empty if none
   std::string state_file;                 // Path of the persistent state file, empty if none
   std::string attrlog_file;               // Path of the persistent attrlog file, empty if none
@@ -280,6 +286,10 @@ struct dev_config
   bool emailtest;                         // Send test email?
 
   // ATA ONLY
+  bool sct_erc_set;                       // set SCT ERC to:
+  unsigned short sct_erc_readtime;        // ERC read time (deciseconds)
+  unsigned short sct_erc_writetime;       // ERC write time (deciseconds)
+
   unsigned char curr_pending_id;          // ID of current pending sector count, 0 if none
   unsigned char offl_pending_id;          // ID of offline uncorrectable sector count, 0 if none
   bool curr_pending_incr, offl_pending_incr; // True if current/offline pending values increase
@@ -315,6 +325,8 @@ dev_config::dev_config()
   tempinfo(0), tempcrit(0),
   emailfreq(0),
   emailtest(false),
+  sct_erc_set(false),
+  sct_erc_readtime(0), sct_erc_writetime(0),
   curr_pending_id(0), offl_pending_id(0),
   curr_pending_incr(false), offl_pending_incr(false),
   curr_pending_set(false),  offl_pending_set(false)
@@ -323,9 +335,9 @@ dev_config::dev_config()
 
 
 // Number of allowed mail message types
-const int SMARTD_NMAIL = 13;
+static const int SMARTD_NMAIL = 13;
 // Type for '-M test' mails (state not persistent)
-const int MAILTYPE_TEST = 0;
+static const int MAILTYPE_TEST = 0;
 // TODO: Add const or enum for all mail types.
 
 struct mailinfo {
@@ -347,6 +359,9 @@ struct persistent_dev_state
 
   time_t scheduled_test_next_check;       // Time of next check for scheduled self-tests
 
+  uint64_t selective_test_last_start;     // Start LBA of last scheduled selective self-test
+  uint64_t selective_test_last_end;       // End LBA of last scheduled selective self-test
+
   mailinfo maillog[SMARTD_NMAIL];         // log info on when mail sent
 
   // ATA ONLY
@@ -358,8 +373,9 @@ struct persistent_dev_state
     unsigned char val;
     unsigned char worst; // Byte needed for 'raw64' attribute only.
     uint64_t raw;
+    unsigned char resvd;
 
-    ata_attribute() : id(0), val(0), worst(0), raw(0) { }
+    ata_attribute() : id(0), val(0), worst(0), raw(0), resvd(0) { }
   };
   ata_attribute ata_attributes[NUMBER_ATA_SMART_ATTRIBUTES];
 
@@ -371,6 +387,8 @@ persistent_dev_state::persistent_dev_state()
   selflogcount(0),
   selfloghour(0),
   scheduled_test_next_check(0),
+  selective_test_last_start(0),
+  selective_test_last_end(0),
   ataerrorcount(0)
 {
 }
@@ -400,7 +418,7 @@ struct temp_dev_state
                                           // know yet) 6 or 10
 
   // ATA ONLY
-  uint64_t num_sectors;                   // Number of sectors (for selective self-test only)
+  uint64_t num_sectors;                   // Number of sectors
   ata_smart_values smartval;              // SMART data
   ata_smart_thresholds_pvt smartthres;    // SMART thresholds
 
@@ -462,6 +480,7 @@ void dev_state::update_persistent_state()
            | ((uint64_t)ta.raw[3] << 24)
            | ((uint64_t)ta.raw[4] << 32)
            | ((uint64_t)ta.raw[5] << 40);
+    pa.resvd = ta.reserv;
   }
 }
 
@@ -485,41 +504,43 @@ void dev_state::update_temp_state()
     ta.raw[3] = (unsigned char)(pa.raw >> 24);
     ta.raw[4] = (unsigned char)(pa.raw >> 32);
     ta.raw[5] = (unsigned char)(pa.raw >> 40);
+    ta.reserv = pa.resvd;
   }
 }
 
 // Parse a line from a state file.
 static bool parse_dev_state_line(const char * line, persistent_dev_state & state)
 {
-  static regular_expression regex(
+  static const regular_expression regex(
     "^ *"
      "((temperature-min)" // (1 (2)
      "|(temperature-max)" // (3)
      "|(self-test-errors)" // (4)
      "|(self-test-last-err-hour)" // (5)
      "|(scheduled-test-next-check)" // (6)
-     "|(ata-error-count)"  // (7)
-     "|(mail\\.([0-9]+)\\." // (8 (9)
-       "((count)" // (10 (11)
-       "|(first-sent-time)" // (12)
-       "|(last-sent-time)" // (13)
-       ")" // 10)
-      ")" // 8)
-     "|(ata-smart-attribute\\.([0-9]+)\\." // (14 (15)
-       "((id)" // (16 (17)
-       "|(val)" // (18)
-       "|(worst)" // (19)
-       "|(raw)" // (20)
-       ")" // 16)
-      ")" // 14)
+     "|(selective-test-last-start)" // (7)
+     "|(selective-test-last-end)" // (8)
+     "|(ata-error-count)"  // (9)
+     "|(mail\\.([0-9]+)\\." // (10 (11)
+       "((count)" // (12 (13)
+       "|(first-sent-time)" // (14)
+       "|(last-sent-time)" // (15)
+       ")" // 12)
+      ")" // 10)
+     "|(ata-smart-attribute\\.([0-9]+)\\." // (16 (17)
+       "((id)" // (18 (19)
+       "|(val)" // (20)
+       "|(worst)" // (21)
+       "|(raw)" // (22)
+       "|(resvd)" // (23)
+       ")" // 18)
+      ")" // 16)
      ")" // 1)
-     " *= *([0-9]+)[ \n]*$", // (21)
+     " *= *([0-9]+)[ \n]*$", // (24)
     REG_EXTENDED
   );
-  if (regex.empty())
-    throw std::logic_error("parse_dev_state_line: invalid regex");
 
-  const int nmatch = 1+21;
+  const int nmatch = 1+24;
   regmatch_t match[nmatch];
   if (!regex.execute(line, nmatch, match))
     return false;
@@ -539,6 +560,10 @@ static bool parse_dev_state_line(const char * line, persistent_dev_state & state
     state.selfloghour = (unsigned short)val;
   else if (match[++m].rm_so >= 0)
     state.scheduled_test_next_check = (time_t)val;
+  else if (match[++m].rm_so >= 0)
+    state.selective_test_last_start = val;
+  else if (match[++m].rm_so >= 0)
+    state.selective_test_last_end = val;
   else if (match[++m].rm_so >= 0)
     state.ataerrorcount = (int)val;
   else if (match[m+=2].rm_so >= 0) {
@@ -568,6 +593,8 @@ static bool parse_dev_state_line(const char * line, persistent_dev_state & state
       state.ata_attributes[i].worst = (unsigned char)val;
     else if (match[++m].rm_so >= 0)
       state.ata_attributes[i].raw = val;
+    else if (match[++m].rm_so >= 0)
+      state.ata_attributes[i].resvd = (unsigned char)val;
     else
       return false;
   }
@@ -647,6 +674,8 @@ static bool write_dev_state(const char * path, const persistent_dev_state & stat
   write_dev_state_line(f, "self-test-errors", state.selflogcount);
   write_dev_state_line(f, "self-test-last-err-hour", state.selfloghour);
   write_dev_state_line(f, "scheduled-test-next-check", state.scheduled_test_next_check);
+  write_dev_state_line(f, "selective-test-last-start", state.selective_test_last_start);
+  write_dev_state_line(f, "selective-test-last-end", state.selective_test_last_end);
 
   int i;
   for (i = 0; i < SMARTD_NMAIL; i++) {
@@ -671,6 +700,7 @@ static bool write_dev_state(const char * path, const persistent_dev_state & stat
     write_dev_state_line(f, "ata-smart-attribute", i, "val", pa.val);
     write_dev_state_line(f, "ata-smart-attribute", i, "worst", pa.worst);
     write_dev_state_line(f, "ata-smart-attribute", i, "raw", pa.raw);
+    write_dev_state_line(f, "ata-smart-attribute", i, "resvd", pa.resvd);
   }
 
   return true;
@@ -738,7 +768,8 @@ static void write_all_dev_attrlogs(const dev_config_vector & configs,
 }
 
 // remove the PID file
-void RemovePidFile(){
+static void RemovePidFile()
+{
   if (!pid_file.empty()) {
     if (unlink(pid_file.c_str()))
       PrintOut(LOG_CRIT,"Can't unlink PID file %s (%s).\n", 
@@ -751,7 +782,8 @@ void RemovePidFile(){
 extern "C" { // signal handlers require C-linkage
 
 //  Note if we catch a SIGUSR1
-void USR1handler(int sig){
+static void USR1handler(int sig)
+{
   if (SIGUSR1==sig)
     caughtsigUSR1=1;
   return;
@@ -759,7 +791,8 @@ void USR1handler(int sig){
 
 #ifdef _WIN32
 //  Note if we catch a SIGUSR2
-void USR2handler(int sig){
+static void USR2handler(int sig)
+{
   if (SIGUSR2==sig)
     caughtsigUSR2=1;
   return;
@@ -767,7 +800,8 @@ void USR2handler(int sig){
 #endif
 
 // Note if we catch a HUP (or INT in debug mode)
-void HUPhandler(int sig){
+static void HUPhandler(int sig)
+{
   if (sig==SIGHUP)
     caughtsigHUP=1;
   else
@@ -776,7 +810,8 @@ void HUPhandler(int sig){
 }
 
 // signal handler for TERM, QUIT, and INT (if not in debug mode)
-void sighandler(int sig){
+static void sighandler(int sig)
+{
   if (!caughtsigEXIT)
     caughtsigEXIT=sig;
   return;
@@ -809,12 +844,14 @@ static int Goodbye(int status)
 // string can be freed if the environment variable is redefined or
 // deleted via another call to putenv(). So we keep these on the stack
 // as long as the popen() call is underway.
-int exportenv(char* stackspace, const char *name, const char *value){
+static int exportenv(char *stackspace, const char *name, const char *value)
+{
   snprintf(stackspace,ENVLENGTH, "%s=%s", name, value);
   return putenv(stackspace);
 }
 
-char* dnsdomain(const char* hostname) {
+static char *dnsdomain(const char *hostname)
+{
   char *p = NULL;
 #ifdef HAVE_GETADDRINFO
   static char canon_name[NI_MAXHOST];
@@ -1028,8 +1065,10 @@ static void MailWarning(const dev_config & cfg, dev_state & state, int which, co
     exportenv(environ_strings[6], "SMARTD_ADDRESS", address.c_str());
   exportenv(environ_strings[7], "SMARTD_DEVICESTRING", cfg.name.c_str());
 
-  exportenv(environ_strings[8], "SMARTD_DEVICETYPE", cfg.dev_type.c_str());
-  exportenv(environ_strings[9], "SMARTD_DEVICE", cfg.name.c_str());
+  // Allow 'smartctl ... -d $SMARTD_DEVICETYPE $SMARTD_DEVICE'
+  exportenv(environ_strings[8], "SMARTD_DEVICETYPE",
+            (!cfg.dev_type.empty() ? cfg.dev_type.c_str() : "auto"));
+  exportenv(environ_strings[9], "SMARTD_DEVICE", cfg.dev_name.c_str());
 
   snprintf(fullmessage, 1024,
              "This email was generated by the smartd daemon running on:\n\n"
@@ -1038,7 +1077,7 @@ static void MailWarning(const dev_config & cfg, dev_state & state, int which, co
              "  NIS domain: %s\n\n"
              "The following warning/error was logged by the smartd daemon:\n\n"
              "%s\n\n"
-             "For details see host's SYSLOG (default: /var/log/messages).\n\n"
+             "For details see host's SYSLOG.\n\n"
              "%s%s%s",
             hostname, domainname, nisdomain, message, further, original, additional);
   exportenv(environ_strings[10], "SMARTD_FULLMESSAGE", fullmessage);
@@ -1204,6 +1243,27 @@ static void MailWarning(const dev_config & cfg, dev_state & state, int which, co
   mail->logged++;
 }
 
+#ifndef _WIN32
+
+// Output multiple lines via separate syslog(3) calls.
+static void vsyslog_lines(int priority, const char * fmt, va_list ap)
+{
+  char buf[512+EBUFLEN]; // enough space for exec cmd output in MailWarning()
+  vsnprintf(buf, sizeof(buf), fmt, ap);
+
+  for (char * p = buf, * q; p && *p; p = q) {
+    if ((q = strchr(p, '\n')))
+      *q++ = 0;
+    if (*p)
+      syslog(priority, "%s\n", p);
+  }
+}
+
+#else  // _WIN32
+// os_win32/syslog_win32.cpp supports multiple lines.
+#define vsyslog_lines vsyslog
+#endif // _WIN32
+
 // Printing function for watching ataprint commands, or losing them
 // [From GLIBC Manual: Since the prototype doesn't specify types for
 // optional arguments, in a call to a variadic function the default
@@ -1218,7 +1278,7 @@ void pout(const char *fmt, ...){
   FixGlibcTimeZoneBug();
   // initialize variable argument list 
   va_start(ap,fmt);
-  // in debug==1 mode we will print the output from the ataprint.o functions!
+  // in debugmode==1 mode we will print the output from the ataprint.o functions!
   if (debugmode && debugmode!=2)
 #ifdef _WIN32
    if (facility == LOG_LOCAL1) // logging to stdout
@@ -1226,10 +1286,10 @@ void pout(const char *fmt, ...){
    else   
 #endif
     vprintf(fmt,ap);
-  // in debug==2 mode we print output from knowndrives.o functions
-  else if (debugmode==2 || con->reportataioctl || con->reportscsiioctl /*|| con->controller_port???*/) {
+  // in debugmode==2 mode we print output from knowndrives.o functions
+  else if (debugmode==2 || ata_debugmode || scsi_debugmode) {
     openlog("smartd", LOG_PID, facility);
-    vsyslog(LOG_INFO, fmt, ap);
+    vsyslog_lines(LOG_INFO, fmt, ap);
     closelog();
   }
   va_end(ap);
@@ -1238,8 +1298,7 @@ void pout(const char *fmt, ...){
 }
 
 // This function prints either to stdout or to the syslog as needed.
-// This function is also used by utility.cpp to report LOG_CRIT errors.
-void PrintOut(int priority, const char *fmt, ...){
+static void PrintOut(int priority, const char *fmt, ...){
   va_list ap;
   
   // get the correct time in syslog()
@@ -1255,7 +1314,7 @@ void PrintOut(int priority, const char *fmt, ...){
     vprintf(fmt,ap);
   else {
     openlog("smartd", LOG_PID, facility);
-    vsyslog(priority,fmt,ap);
+    vsyslog_lines(priority, fmt, ap);
     closelog();
   }
   va_end(ap);
@@ -1268,9 +1327,11 @@ void checksumwarning(const char * string)
   pout("Warning! %s error: invalid SMART checksum.\n", string);
 }
 
+#ifndef _WIN32
+
 // Wait for the pid file to show up, this makes sure a calling program knows
 // that the daemon is really up and running and has a pid to kill it
-bool WaitForPidFile()
+static bool WaitForPidFile()
 {
     int waited, max_wait = 10;
     struct stat stat_buf;
@@ -1287,12 +1348,14 @@ bool WaitForPidFile()
     return false;
 }
 
+#endif // _WIN32
 
 // Forks new process, closes ALL file descriptors, redirects stdin,
 // stdout, and stderr.  Not quite daemon().  See
 // http://www.linuxjournal.com/article/2335
 // for a good description of why we do things this way.
-void DaemonInit(){
+static void DaemonInit()
+{
 #ifndef _WIN32
   pid_t pid;
   int i;  
@@ -1402,10 +1465,11 @@ static void PrintHead()
 }
 
 // prints help info for configuration file Directives
-void Directives() {
+static void Directives()
+{
   PrintOut(LOG_INFO,
            "Configuration file (%s) Directives (after device name):\n"
-           "  -d TYPE Set the device type: %s\n"
+           "  -d TYPE Set the device type: %s, auto, removable\n"
            "  -T TYPE Set the tolerance to one of: normal, permissive\n"
            "  -o VAL  Enable/disable automatic offline tests (on/off)\n"
            "  -S VAL  Enable/disable attribute autosave (on/off)\n"
@@ -1413,6 +1477,7 @@ void Directives() {
            "  -H      Monitor SMART Health Status, report if failed\n"
            "  -s REG  Do Self-Test at time(s) given by regular expression REG\n"
            "  -l TYPE Monitor SMART log.  Type is one of: error, selftest, xerror\n"
+           "  -l scterc,R,W  Set SCT Error Recovery Control\n"
            "  -f      Monitor 'Usage' Attributes, report failures\n"
            "  -m ADD  Send email warning to address ADD\n"
            "  -M TYPE Modify email warning behavior (see man page)\n"
@@ -1441,7 +1506,8 @@ void Directives() {
 
 /* Returns a pointer to a static string containing a formatted list of the valid
    arguments to the option opt or NULL on failure. */
-const char *GetValidArgList(char opt) {
+static const char *GetValidArgList(char opt)
+{
   switch (opt) {
   case 'A':
   case 's':
@@ -1465,7 +1531,8 @@ const char *GetValidArgList(char opt) {
 }
 
 /* prints help information for command syntax */
-void Usage (void){
+static void Usage()
+{
   PrintOut(LOG_INFO,"Usage: smartd [options]\n\n");
   PrintOut(LOG_INFO,"  -A PREFIX, --attributelog=PREFIX\n");
   PrintOut(LOG_INFO,"        Log ATA attribute information to {PREFIX}MODEL-SERIAL.ata.csv\n");
@@ -1619,6 +1686,47 @@ static void log_self_test_exec_status(const char * name, unsigned char status)
              name, status);
 }
 
+// Check pending sector count id (-C, -U directives).
+static bool check_pending_id(const dev_config & cfg, const dev_state & state,
+                             unsigned char id, const char * msg)
+{
+  // Check attribute index
+  int i = ata_find_attr_index(id, state.smartval);
+  if (i < 0) {
+    PrintOut(LOG_INFO, "Device: %s, can't monitor %s count - no Attribute %d\n",
+             cfg.name.c_str(), msg, id);
+    return false;
+  }
+
+  // Check value
+  uint64_t rawval = ata_get_attr_raw_value(state.smartval.vendor_attributes[i],
+    cfg.attribute_defs);
+  if (rawval >= (state.num_sectors ? state.num_sectors : 0xffffffffULL)) {
+    PrintOut(LOG_INFO, "Device: %s, ignoring %s count - bogus Attribute %d value %"PRIu64" (0x%"PRIx64")\n",
+             cfg.name.c_str(), msg, id, rawval, rawval);
+    return false;
+  }
+
+  return true;
+}
+
+// Called by ATA/SCSIDeviceScan() after successful device check
+static void finish_device_scan(dev_config & cfg, dev_state & state)
+{
+  // Set cfg.emailfreq if user hasn't set it
+  if ((!cfg.emailaddress.empty() || !cfg.emailcmdline.empty()) && !cfg.emailfreq) {
+    // Avoid that emails are suppressed forever due to state persistence
+    if (cfg.state_file.empty())
+      cfg.emailfreq = 1; // '-M once'
+    else
+      cfg.emailfreq = 2; // '-M daily'
+  }
+
+  // Start self-test regex check now if time was not read from state file
+  if (!cfg.test_regex.empty() && !state.scheduled_test_next_check)
+    state.scheduled_test_next_check = time(0);
+}
+
 
 // TODO: Add '-F swapid' directive
 const bool fix_swapped_id = false;
@@ -1634,7 +1742,7 @@ static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atade
   // Device must be open
 
   // Get drive identity structure
-  if ((retid=ataReadHDIdentity (atadev, &drive))){
+  if ((retid = ata_read_identity(atadev, &drive, fix_swapped_id))) {
     if (retid<0)
       // Unable to read Identity structure
       PrintOut(LOG_INFO,"Device: %s, not ATA, no IDENTIFY DEVICE Structure\n",name);
@@ -1644,19 +1752,31 @@ static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atade
     CloseDevice(atadev, name);
     return 2; 
   }
-  // Store drive size (for selective self-test only)
+
+  // Log drive identity and size
+  char model[40+1], serial[20+1], firmware[8+1];
+  ata_format_id_string(model, drive.model, sizeof(model)-1);
+  ata_format_id_string(serial, drive.serial_no, sizeof(serial)-1);
+  ata_format_id_string(firmware, drive.fw_rev, sizeof(firmware)-1);
   state.num_sectors = get_num_sectors(&drive);
+  PrintOut(LOG_INFO, "Device: %s, %s, S/N:%s, FW:%s, %"PRIu64" sectors\n", name,
+           model, serial, firmware, state.num_sectors);
 
   // Show if device in database, and use preset vendor attribute
   // options unless user has requested otherwise.
   if (cfg.ignorepresets)
     PrintOut(LOG_INFO, "Device: %s, smartd database not searched (Directive: -P ignore).\n", name);
   else {
-    // do whatever applypresets decides to do.
-    if (!apply_presets(&drive, cfg.attribute_defs, cfg.fix_firmwarebug, fix_swapped_id))
+    // Apply vendor specific presets, print warning if present
+    const drive_settings * dbentry = lookup_drive_apply_presets(
+      &drive, cfg.attribute_defs, cfg.fix_firmwarebug);
+    if (!dbentry)
       PrintOut(LOG_INFO, "Device: %s, not found in smartd database.\n", name);
-    else
+    else {
       PrintOut(LOG_INFO, "Device: %s, found in smartd database.\n", name);
+      if (*dbentry->warningmsg)
+        PrintOut(LOG_CRIT, "Device: %s, WARNING: %s\n", name, dbentry->warningmsg);
+    }
   }
 
   // Set default '-C 197[+]' if no '-C ID' is specified.
@@ -1672,7 +1792,7 @@ static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atade
     PrintOut(LOG_INFO, "Device %s: presets are:\n", name);
     if (!debugmode)
       debugmode=2;
-    show_presets(&drive, false);
+    show_presets(&drive);
     debugmode=savedebugmode;
   }
 
@@ -1759,17 +1879,15 @@ static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atade
 
     // see if the necessary Attribute is there to monitor offline or
     // current pending sectors or temperature
-    if (cfg.curr_pending_id && ata_find_attr_index(cfg.curr_pending_id, state.smartval) < 0) {
-      PrintOut(LOG_INFO,"Device: %s, can't monitor Current Pending Sector count - no Attribute %d\n",
-               name, cfg.curr_pending_id);
+    if (   cfg.curr_pending_id
+        && !check_pending_id(cfg, state, cfg.curr_pending_id,
+              "Current_Pending_Sector"))
       cfg.curr_pending_id = 0;
-    }
-    
-    if (cfg.offl_pending_id && ata_find_attr_index(cfg.offl_pending_id, state.smartval) < 0) {
-      PrintOut(LOG_INFO,"Device: %s, can't monitor Offline Uncorrectable Sector count - no Attribute %d\n",
-               name, cfg.offl_pending_id);
+
+    if (   cfg.offl_pending_id
+        && !check_pending_id(cfg, state, cfg.offl_pending_id,
+              "Offline_Uncorrectable"))
       cfg.offl_pending_id = 0;
-    }
 
     if (   (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit)
         && !ata_return_temperature_value(&state.smartval, cfg.attribute_defs)) {
@@ -1795,57 +1913,80 @@ static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atade
         PrintOut(LOG_INFO,"Device: %s, %sd SMART Automatic Offline Testing.\n", name, what);
     }
   }
-  
+
+  // Read log directories if required for capability check
+  ata_smart_log_directory smart_logdir, gp_logdir;
+  bool smart_logdir_ok = false, gp_logdir_ok = false;
+
+  if (   isGeneralPurposeLoggingCapable(&drive)
+      && (cfg.errorlog || cfg.selftest)        ) {
+      if (!ataReadLogDirectory(atadev, &smart_logdir, false))
+        smart_logdir_ok = true;
+  }
+
+  if (cfg.xerrorlog) {
+    if (!ataReadLogDirectory(atadev, &gp_logdir, true))
+      gp_logdir_ok = true;
+  }
+
   // capability check: self-test-log
+  state.selflogcount = 0; state.selfloghour = 0;
   if (cfg.selftest) {
     int retval;
-    
-    // start with service disabled, and re-enable it if all works OK
-    cfg.selftest = false;
-    state.selflogcount = 0;
-    state.selfloghour = 0;
-
-    if (!smart_val_ok)
-      PrintOut(LOG_INFO, "Device: %s, no SMART Self-Test log (SMART READ DATA failed); disabling -l selftest\n", name);
-    else if (!cfg.permissive && !isSmartTestLogCapable(&state.smartval, &drive))
-      PrintOut(LOG_INFO, "Device: %s, appears to lack SMART Self-Test log; disabling -l selftest (override with -T permissive Directive)\n", name);
-    else if ((retval = SelfTestErrorCount(atadev, name, cfg.fix_firmwarebug)) < 0)
-      PrintOut(LOG_INFO, "Device: %s, no SMART Self-Test log; remove -l selftest Directive from smartd.conf\n", name);
+    if (!(   cfg.permissive
+          || ( smart_logdir_ok && smart_logdir.entry[0x06-1].numsectors)
+          || (!smart_logdir_ok && smart_val_ok && isSmartTestLogCapable(&state.smartval, &drive)))) {
+      PrintOut(LOG_INFO, "Device: %s, no SMART Self-test Log, ignoring -l selftest (override with -T permissive)\n", name);
+      cfg.selftest = false;
+    }
+    else if ((retval = SelfTestErrorCount(atadev, name, cfg.fix_firmwarebug)) < 0) {
+      PrintOut(LOG_INFO, "Device: %s, no SMART Self-test Log, ignoring -l selftest\n", name);
+      cfg.selftest = false;
+    }
     else {
-      cfg.selftest = true;
       state.selflogcount=SELFTEST_ERRORCOUNT(retval);
       state.selfloghour =SELFTEST_ERRORHOURS(retval);
     }
   }
   
   // capability check: ATA error log
-  if (cfg.errorlog || cfg.xerrorlog) {
+  state.ataerrorcount = 0;
+  if (cfg.errorlog) {
+    int errcnt1;
+    if (!(   cfg.permissive
+          || ( smart_logdir_ok && smart_logdir.entry[0x01-1].numsectors)
+          || (!smart_logdir_ok && smart_val_ok && isSmartErrorLogCapable(&state.smartval, &drive)))) {
+      PrintOut(LOG_INFO, "Device: %s, no SMART Error Log, ignoring -l error (override with -T permissive)\n", name);
+      cfg.errorlog = false;
+    }
+    else if ((errcnt1 = read_ata_error_count(atadev, name, cfg.fix_firmwarebug, false)) < 0) {
+      PrintOut(LOG_INFO, "Device: %s, no SMART Error Log, ignoring -l error\n", name);
+      cfg.errorlog = false;
+    }
+    else
+      state.ataerrorcount = errcnt1;
+  }
 
-    state.ataerrorcount=0;
-    if (!(cfg.permissive || (smart_val_ok && isSmartErrorLogCapable(&state.smartval, &drive)))) {
-      PrintOut(LOG_INFO, "Device: %s, no SMART Error Log (%s), ignoring -l [x]error (override with -T permissive)\n",
-               name, (!smart_val_ok ? "SMART READ DATA failed" : "capability missing"));
-      cfg.errorlog = cfg.xerrorlog = false;
+  if (cfg.xerrorlog) {
+    int errcnt2;
+    if (!(cfg.permissive || (gp_logdir_ok && gp_logdir.entry[0x03-1].numsectors))) {
+      PrintOut(LOG_INFO, "Device: %s, no Extended Comprehensive SMART Error Log, ignoring -l xerror (override with -T permissive)\n",
+               name);
+      cfg.xerrorlog = false;
     }
-    else {
-      int errcnt1 = -1, errcnt2 = -1;
-      if (cfg.errorlog && (errcnt1 = read_ata_error_count(atadev, name, cfg.fix_firmwarebug, false)) < 0) {
-        PrintOut(LOG_INFO, "Device: %s, no Summary SMART Error Log, ignoring -l error\n", name);
-        cfg.errorlog = false;
-      }
-      if (cfg.xerrorlog && (errcnt2 = read_ata_error_count(atadev, name, cfg.fix_firmwarebug, true)) < 0) {
-        PrintOut(LOG_INFO, "Device: %s, no Extended Comprehensive SMART Error Log, ignoring -l xerror\n", name);
-        cfg.xerrorlog = false;
-      }
-      if (cfg.errorlog || cfg.xerrorlog) {
-        if (cfg.errorlog && cfg.xerrorlog && errcnt1 != errcnt2) {
-          PrintOut(LOG_INFO, "Device: %s, SMART Error Logs report different error counts: %d != %d\n",
-                   name, errcnt1, errcnt2);
-        }
-        // Record max error count
-        state.ataerrorcount = (errcnt1 >= errcnt2 ? errcnt1 : errcnt2);
-      }
+    else if ((errcnt2 = read_ata_error_count(atadev, name, cfg.fix_firmwarebug, true)) < 0) {
+      PrintOut(LOG_INFO, "Device: %s, no Extended Comprehensive SMART Error Log, ignoring -l xerror\n", name);
+      cfg.xerrorlog = false;
     }
+    else if (cfg.errorlog && state.ataerrorcount != errcnt2) {
+      PrintOut(LOG_INFO, "Device: %s, SMART Error Logs report different error counts: %d != %d\n",
+               name, state.ataerrorcount, errcnt2);
+      // Record max error count
+      if (errcnt2 > state.ataerrorcount)
+        state.ataerrorcount = errcnt2;
+    }
+    else
+      state.ataerrorcount = errcnt2;
   }
   
   // capabilities check -- does it support powermode?
@@ -1863,6 +2004,19 @@ static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atade
     }
   }
 
+  // set SCT Error Recovery Control if requested
+  if (cfg.sct_erc_set) {
+    if (!isSCTErrorRecoveryControlCapable(&drive))
+      PrintOut(LOG_INFO, "Device: %s, no SCT Error Recovery Control support, ignoring -l scterc\n",
+               name);
+    else if (   ataSetSCTErrorRecoveryControltime(atadev, 1, cfg.sct_erc_readtime )
+             || ataSetSCTErrorRecoveryControltime(atadev, 2, cfg.sct_erc_writetime))
+      PrintOut(LOG_INFO, "Device: %s, set of SCT Error Recovery Control failed\n", name);
+    else
+      PrintOut(LOG_INFO, "Device: %s, SCT Error Recovery Control set to: Read: %u, Write: %u\n",
+               name, cfg.sct_erc_readtime, cfg.sct_erc_writetime);
+  }
+
   // If no tests available or selected, return
   if (!(   cfg.smartcheck  || cfg.selftest
         || cfg.errorlog    || cfg.xerrorlog
@@ -1875,18 +2029,11 @@ static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atade
   // tell user we are registering device
   PrintOut(LOG_INFO,"Device: %s, is SMART capable. Adding to \"monitor\" list.\n",name);
   
-  // record number of device, type of device, increment device count
-  if (cfg.dev_type.empty())
-    cfg.dev_type = "ata";
-  
   // close file descriptor
   CloseDevice(atadev, name);
 
   if (!state_path_prefix.empty() || !attrlog_path_prefix.empty()) {
     // Build file name for state file
-    char model[40+1], serial[20+1];
-    format_ata_string(model, drive.model, sizeof(model)-1, fix_swapped_id);
-    format_ata_string(serial, drive.serial_no, sizeof(serial)-1, fix_swapped_id);
     std::replace_if(model, model+strlen(model), not_allowed_in_filename, '_');
     std::replace_if(serial, serial+strlen(serial), not_allowed_in_filename, '_');
     if (!state_path_prefix.empty()) {
@@ -1902,9 +2049,7 @@ static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atade
       cfg.attrlog_file = strprintf("%s%s-%s.ata.csv", attrlog_path_prefix.c_str(), model, serial);
   }
 
-  // Start self-test regex check now if time was not read from state file
-  if (!cfg.test_regex.empty() && !state.scheduled_test_next_check)
-    state.scheduled_test_next_check = time(0);
+  finish_device_scan(cfg, state);
 
   return 0;
 }
@@ -1980,10 +2125,6 @@ static int SCSIDeviceScan(dev_config & cfg, dev_state & state, scsi_device * scs
     }   
   }
   
-  // record type of device
-  if (cfg.dev_type.empty())
-    cfg.dev_type = "scsi";
-  
   // Check if scsiCheckIE() is going to work
   {
     UINT8 asc = 0;
@@ -2050,9 +2191,7 @@ static int SCSIDeviceScan(dev_config & cfg, dev_state & state, scsi_device * scs
   // close file descriptor
   CloseDevice(scsidev, device);
 
-  // Start self-test regex check now if time was not read from state file
-  if (!cfg.test_regex.empty() && !state.scheduled_test_next_check)
-    state.scheduled_test_next_check = time(0);
+  finish_device_scan(cfg, state);
 
   return 0;
 }
@@ -2113,7 +2252,7 @@ static void CheckSelfTestLogs(const dev_config & cfg, dev_state & state, int new
 
 // Test types, ordered by priority.
 static const char test_type_chars[] = "LncrSCO";
-const unsigned num_test_types = sizeof(test_type_chars)-1;
+static const unsigned num_test_types = sizeof(test_type_chars)-1;
 
 // returns test type if time to do test of type testtype,
 // 0 if not time to do test.
@@ -2395,10 +2534,13 @@ static int DoATASelfTest(const dev_config & cfg, dev_state & state, ata_device *
 
   if (dotest == SELECTIVE_SELF_TEST) {
     // Set test span
-    ata_selective_selftest_args selargs;
+    ata_selective_selftest_args selargs, prev_args;
     selargs.num_spans = 1;
     selargs.span[0].mode = mode;
-    if (ataWriteSelectiveSelfTestLog(device, selargs, &data, state.num_sectors)) {
+    prev_args.num_spans = 1;
+    prev_args.span[0].start = state.selective_test_last_start;
+    prev_args.span[0].end   = state.selective_test_last_end;
+    if (ataWriteSelectiveSelfTestLog(device, selargs, &data, state.num_sectors, &prev_args)) {
       PrintOut(LOG_CRIT, "Device: %s, prepare %sTest failed\n", name, testname);
       return 1;
     }
@@ -2408,6 +2550,8 @@ static int DoATASelfTest(const dev_config & cfg, dev_state & state, ata_device *
       start, end, end - start + 1,
       (unsigned)((100 * start + state.num_sectors/2) / state.num_sectors),
       (unsigned)((100 * end   + state.num_sectors/2) / state.num_sectors));
+    state.selective_test_last_start = start;
+    state.selective_test_last_end = end;
   }
 
   // execute the test, and return status
@@ -2539,10 +2683,11 @@ static void CheckTemperature(const dev_config & cfg, dev_state & state, unsigned
 static void check_attribute(const dev_config & cfg, dev_state & state,
                             const ata_smart_attribute & attr,
                             const ata_smart_attribute & prev,
-                            const ata_smart_threshold_entry & thre)
+                            int attridx,
+                            const ata_smart_threshold_entry * thresholds)
 {
   // Check attribute and threshold
-  ata_attr_state attrstate = ata_get_attr_state(attr, thre, cfg.attribute_defs);
+  ata_attr_state attrstate = ata_get_attr_state(attr, attridx, thresholds, cfg.attribute_defs);
   if (attrstate == ATTRSTATE_NON_EXISTING)
     return;
 
@@ -2566,9 +2711,9 @@ static void check_attribute(const dev_config & cfg, dev_state & state,
     return;
 
   // Issue warning if they don't have the same ID in all structures.
-  if (attr.id != prev.id || attrstate == ATTRSTATE_BAD_THRESHOLD) {
-    PrintOut(LOG_INFO,"Device: %s, same Attribute has different ID numbers: %d = %d = %d\n",
-             cfg.name.c_str(), attr.id, prev.id, thre.id);
+  if (attr.id != prev.id) {
+    PrintOut(LOG_INFO,"Device: %s, same Attribute has different ID numbers: %d = %d\n",
+             cfg.name.c_str(), attr.id, prev.id);
     return;
   }
 
@@ -2773,7 +2918,7 @@ static int ATACheckDevice(const dev_config & cfg, dev_state & state, ata_device
           check_attribute(cfg, state,
                           curval.vendor_attributes[i],
                           state.smartval.vendor_attributes[i],
-                          state.smartthres.thres_entries[i]);
+                          i, state.smartthres.thres_entries);
         }
 
         if (cfg.selftest) {
@@ -2921,8 +3066,8 @@ static void CheckDevicesOnce(const dev_config_vector & configs, dev_state_vector
 static bool is_initialized = false;
 
 // Does initialization right after fork to daemon mode
-void Initialize(time_t *wakeuptime){
-
+static void Initialize(time_t *wakeuptime)
+{
   // Call Goodbye() on exit
   is_initialized = true;
   
@@ -3031,8 +3176,8 @@ static time_t dosleep(time_t wakeuptime, bool & sigwakeup)
 }
 
 // Print out a list of valid arguments for the Directive d
-void printoutvaliddirectiveargs(int priority, char d) {
-
+static void printoutvaliddirectiveargs(int priority, char d)
+{
   switch (d) {
   case 'n':
     PrintOut(priority, "never[,N][,q], sleep[,N][,q], standby[,N][,q], idle[,N][,q]");
@@ -3069,13 +3214,13 @@ void printoutvaliddirectiveargs(int priority, char d) {
 }
 
 // exits with an error message, or returns integer value of token
-int GetInteger(const char *arg, const char *name, const char *token, int lineno, const char *configfile,
+static int GetInteger(const char *arg, const char *name, const char *token, int lineno, const char *cfgfile,
                int min, int max, char * suffix = 0)
 {
   // make sure argument is there
   if (!arg) {
     PrintOut(LOG_CRIT,"File %s line %d (drive %s): Directive: %s takes integer argument from %d to %d.\n",
-             configfile, lineno, name, token, min, max);
+             cfgfile, lineno, name, token, min, max);
     return -1;
   }
   
@@ -3093,7 +3238,7 @@ int GetInteger(const char *arg, const char *name, const char *token, int lineno,
 
   if (!(!*endptr && min <= val && val <= max)) {
     PrintOut(LOG_CRIT,"File %s line %d (drive %s): Directive: %s has argument: %s; needs integer from %d to %d.\n",
-             configfile, lineno, name, token, arg, min, max);
+             cfgfile, lineno, name, token, arg, min, max);
     return -1;
   }
 
@@ -3103,13 +3248,14 @@ int GetInteger(const char *arg, const char *name, const char *token, int lineno,
 
 
 // Get 1-3 small integer(s) for '-W' directive
-int Get3Integers(const char *arg, const char *name, const char *token, int lineno, const char *configfile,
-                 unsigned char * val1, unsigned char * val2, unsigned char * val3){
+static int Get3Integers(const char *arg, const char *name, const char *token, int lineno, const char *cfgfile,
+                 unsigned char *val1, unsigned char *val2, unsigned char *val3)
+{
   unsigned v1 = 0, v2 = 0, v3 = 0;
   int n1 = -1, n2 = -1, n3 = -1, len;
   if (!arg) {
     PrintOut(LOG_CRIT,"File %s line %d (drive %s): Directive: %s takes 1-3 integer argument(s) from 0 to 255.\n",
-             configfile, lineno, name, token);
+             cfgfile, lineno, name, token);
     return -1;
   }
 
@@ -3117,7 +3263,7 @@ int Get3Integers(const char *arg, const char *name, const char *token, int linen
   if (!(   sscanf(arg, "%u%n,%u%n,%u%n", &v1, &n1, &v2, &n2, &v3, &n3) >= 1
         && (n1 == len || n2 == len || n3 == len) && v1 <= 255 && v2 <= 255 && v3 <= 255)) {
     PrintOut(LOG_CRIT,"File %s line %d (drive %s): Directive: %s has argument: %s; needs 1-3 integer(s) from 0 to 255.\n",
-             configfile, lineno, name, token, arg);
+             cfgfile, lineno, name, token, arg);
     return -1;
   }
   *val1 = (unsigned char)v1; *val2 = (unsigned char)v2; *val3 = (unsigned char)v3;
@@ -3196,6 +3342,8 @@ static int ParseToken(char * token, dev_config & cfg)
       missingarg = 1;
     } else if (!strcmp(arg, "removable")) {
       cfg.removable = true;
+    } else if (!strcmp(arg, "auto")) {
+      cfg.dev_type = "";
     } else {
       cfg.dev_type = arg;
     }
@@ -3250,6 +3398,17 @@ static int ParseToken(char * token, dev_config & cfg)
     } else if (!strcmp(arg, "xerror")) {
       // track changes in Extended Comprehensive SMART error log
       cfg.xerrorlog = true;
+    } else if (!strncmp(arg, "scterc,", sizeof("scterc,")-1)) {
+        // set SCT Error Recovery Control
+        unsigned rt = ~0, wt = ~0; int nc = -1;
+        sscanf(arg,"scterc,%u,%u%n", &rt, &wt, &nc);
+        if (nc == (int)strlen(arg) && rt <= 999 && wt <= 999) {
+          cfg.sct_erc_set = true;
+          cfg.sct_erc_readtime = rt;
+          cfg.sct_erc_writetime = wt;
+        }
+        else
+          badarg = 1;
     } else {
       badarg = 1;
     }
@@ -3513,7 +3672,8 @@ static int ParseConfigLine(dev_config_vector & conf_entries, int /*entry*/, int
   conf_entries.push_back( dev_config() );
   dev_config & cfg = conf_entries.back();
 
-  cfg.name = name;
+  cfg.name = name; // Later replaced by dev->get_info().info_name
+  cfg.dev_name = name; // If DEVICESCAN later replaced by get->dev_info().dev_name
 
   // Store line number, and by default check for both device types.
   cfg.lineno=lineno;
@@ -3576,10 +3736,6 @@ static int ParseConfigLine(dev_config_vector & conf_entries, int /*entry*/, int
     cfg.emailaddress.clear();
   }
 
-  // set cfg.emailfreq to 1 (once) if user hasn't set it
-  if ((!cfg.emailaddress.empty() || !cfg.emailcmdline.empty()) && !cfg.emailfreq)
-    cfg.emailfreq = 1;
-
   if (devscan)
     return -1;
   else
@@ -3729,7 +3885,8 @@ static int ParseConfigFile(dev_config_vector & conf_entries)
 
 /* Prints the message "=======> VALID ARGUMENTS ARE: <LIST>  <=======\n", where
    <LIST> is the list of valid arguments for option opt. */
-void PrintValidArgs(char opt) {
+static void PrintValidArgs(char opt)
+{
   const char *s;
 
   PrintOut(LOG_CRIT, "=======> VALID ARGUMENTS ARE: ");
@@ -3758,7 +3915,7 @@ static bool is_abs_path(const char * path)
 
 // Parses input line, prints usage message and
 // version/license/copyright messages
-void ParseOpts(int argc, char **argv)
+static void ParseOpts(int argc, char **argv)
 {
   // Init default configfile path
 #ifndef _WIN32
@@ -3911,11 +4068,11 @@ void ParseOpts(int argc, char **argv)
           PrintOut(LOG_CRIT, "======> LEVEL MUST BE INTEGER BETWEEN 1 AND 3<=======\n");
           EXIT(EXIT_BADCMD);
         } else if (!strcmp(s,"ioctl")) {
-          con->reportataioctl  = con->reportscsiioctl = i;
+          ata_debugmode = scsi_debugmode = i;
         } else if (!strcmp(s,"ataioctl")) {
-          con->reportataioctl = i;
+          ata_debugmode = i;
         } else if (!strcmp(s,"scsiioctl")) {
-          con->reportscsiioctl = i;
+          scsi_debugmode = i;
         } else {
           badarg = true;
         }
@@ -4100,6 +4257,7 @@ static int MakeConfigEntries(const dev_config & base_cfg,
     conf_entries.push_back(base_cfg);
     dev_config & cfg = conf_entries.back();
     cfg.name = dev->get_info().info_name;
+    cfg.dev_name = dev->get_info().dev_name;
     cfg.dev_type = type;
   }
   
@@ -4271,33 +4429,22 @@ static void RegisterDevices(const dev_config_vector & conf_entries, smart_device
 
 
 // Main program without exception handling
-int main_worker(int argc, char **argv)
+static int main_worker(int argc, char **argv)
 {
   // Initialize interface
   smart_interface::init();
   if (!smi())
     return 1;
 
-  // external control variables for ATA disks
-  smartmonctrl control;
-
   // is it our first pass through?
   bool firstpass = true;
 
   // next time to wake up
-  time_t wakeuptime;
-
-  // for simplicity, null all global communications variables/lists
-  con=&control;
-  memset(con,        0,sizeof(control));
+  time_t wakeuptime = 0;
 
   // parse input and print header and usage info if needed
   ParseOpts(argc,argv);
   
-  // do we mute printing from ataprint commands?
-  con->printing_switchable = false;
-  con->dont_print = !debugmode;
-  
   // Configuration for each device
   dev_config_vector configs;
   // Device states
index 467531abdce4137e9043ff193f7c2d402c22bec0..ca728e170820abe70e27f4ec56fab2d8c02c38cf 100644 (file)
@@ -2,7 +2,7 @@
 #
 # smartmontools drive database update script
 #
-# Copyright (C) 2010 Christian Franke <smartmontools-support@lists.sourceforge.net>
+# Copyright (C) 2010-11 Christian Franke <smartmontools-support@lists.sourceforge.net>
 #
 # 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
@@ -12,7 +12,7 @@
 # You should have received a copy of the GNU General Public License
 # (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
 #
-# $Id: update-smart-drivedb.in 3072 2010-03-04 21:56:41Z chrfranke $
+# $Id: update-smart-drivedb.in 3294 2011-03-16 21:36:58Z chrfranke $
 #
 
 set -e
@@ -27,6 +27,12 @@ datarootdir="@datarootdir@"
 datadir="@datadir@"
 drivedbdir="@drivedbdir@"
 
+# Download tools
+os_dltools="@os_dltools@"
+
+# drivedb.h update branch
+BRANCH="@DRIVEDB_BRANCH@"
+
 # Default drivedb location
 DEST="$drivedbdir/drivedb.h"
 
@@ -39,13 +45,6 @@ SMARTCTL="$sbindir/smartctl"
 # ViewVC repository browser
 SRCEXPR='http://smartmontools.svn.sourceforge.net/viewvc/smartmontools/$location/smartmontools/drivedb.h?revision=HEAD'
 
-# Convert version into branch name: 5.41[.X] -> "RELEASE_5_41_DRIVEDB"
-BRANCH="`echo $VERSION | sed -n 's|^\([0-9][0-9]*\)\.\([0-9][0-9]*\)\([^0-9].*\)\?$|RELEASE_\1_\2_DRIVEDB|p'`"
-
-if [ -z "$BRANCH" ]; then
-  echo "$0: syntax error in version number: $VERSION" >&2; exit 1
-fi
-
 
 # Parse options
 q="-q "
@@ -78,14 +77,21 @@ esac
 which which >/dev/null || exit 1
 
 # Find download tool
-if which curl >/dev/null 2>/dev/null; then
-  DOWNLOAD="curl ${q:+-s }"'-f -o "$DEST.new" "$SRC"'
-elif which wget >/dev/null 2>/dev/null; then
-  DOWNLOAD="wget $q"'-O "$DEST.new" "$SRC"'
-elif which lynx >/dev/null 2>/dev/null; then
-  DOWNLOAD='lynx -source "$SRC" >"$DEST.new"'
-else
-  echo "$0: curl, wget or lynx not available" >&2; exit 1
+DOWNLOAD=
+for t in $os_dltools; do
+  if which $t >/dev/null 2>/dev/null; then
+    case $t in
+      curl)  DOWNLOAD="curl ${q:+-s }"'-f -o "$DEST.new" "$SRC"' ;;
+      lynx)  DOWNLOAD='lynx -source "$SRC" >"$DEST.new"' ;;
+      wget)  DOWNLOAD="wget $q"'-O "$DEST.new" "$SRC"' ;;
+      fetch) DOWNLOAD='fetch -o "$DEST.new" "$SRC"' ;; # FreeBSD
+      ftp)   DOWNLOAD='ftp -o "$DEST.new" "$SRC"' ;; # OpenBSD
+    esac
+    break
+  fi
+done
+if [ -z "$DOWNLOAD" ]; then
+  echo "$0: found none of: $os_dltools" >&2; exit 1
 fi
 
 # Try possible branch first, then trunk
@@ -96,7 +102,7 @@ for location in "branches/$BRANCH" "trunk"; do
   rm -f "$DEST.new"
   SRC="`eval echo "$SRCEXPR"`"
 
-  if eval $DOWNLOAD; then :; else
+  if (eval $DOWNLOAD); then :; else
     errmsg="download from $location failed (HTTP error)"
     continue
   fi
index ab7f29fd35ef7c48905c5e35c55bcb885c1b16a8..62e5845522d7371c5d01e59180b1b134c71d7a39 100644 (file)
@@ -3,8 +3,8 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2002-10 Bruce Allen <smartmontools-support@lists.sourceforge.net>
- * Copyright (C) 2008-10 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2008-11 Christian Franke <smartmontools-support@lists.sourceforge.net>
  * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -50,7 +50,7 @@
 #include "atacmds.h"
 #include "dev_interface.h"
 
-const char * utility_cpp_cvsid = "$Id: utility.cpp 3090 2010-04-28 11:03:11Z chrfranke $"
+const char * utility_cpp_cvsid = "$Id: utility.cpp 3285 2011-03-04 22:08:49Z chrfranke $"
                                  UTILITY_H_CVSID INT64_H_CVSID;
 
 const char * packet_types[] = {
@@ -72,13 +72,6 @@ const char * packet_types[] = {
         "Optical card reader/writer"
 };
 
-// Whenever exit() status is EXIT_BADCODE, please print this message
-const char *reportbug="Please report this bug to the Smartmontools developers at " PACKAGE_BUGREPORT ".\n";
-
-
-// command-line argument: are we running in debug mode?.
-unsigned char debugmode = 0;
-
 // BUILD_INFO can be provided by package maintainers
 #ifndef BUILD_INFO
 #define BUILD_INFO "(local build)"
@@ -88,9 +81,14 @@ unsigned char debugmode = 0;
 std::string format_version_info(const char * prog_name, bool full /*= false*/)
 {
   std::string info = strprintf(
-    "%s "PACKAGE_VERSION" "SMARTMONTOOLS_SVN_DATE" r"SMARTMONTOOLS_SVN_REV
+    "%s "PACKAGE_VERSION" "
+#ifdef SMARTMONTOOLS_SVN_REV
+      SMARTMONTOOLS_SVN_DATE" r"SMARTMONTOOLS_SVN_REV
+#else
+      "(build date "__DATE__")" // checkout without expansion of Id keywords
+#endif
       " [%s] "BUILD_INFO"\n"
-    "Copyright (C) 2002-10 by Bruce Allen, http://smartmontools.sourceforge.net\n",
+    "Copyright (C) 2002-11 by Bruce Allen, http://smartmontools.sourceforge.net\n",
     prog_name, smi()->get_os_version_str().c_str()
   );
   if (!full)
@@ -108,8 +106,12 @@ std::string format_version_info(const char * prog_name, bool full /*= false*/)
   info += strprintf(
     "smartmontools release "PACKAGE_VERSION
       " dated "SMARTMONTOOLS_RELEASE_DATE" at "SMARTMONTOOLS_RELEASE_TIME"\n"
+#ifdef SMARTMONTOOLS_SVN_REV
     "smartmontools SVN rev "SMARTMONTOOLS_SVN_REV
       " dated "SMARTMONTOOLS_SVN_DATE" at "SMARTMONTOOLS_SVN_TIME"\n"
+#else
+    "smartmontools SVN rev is unknown\n"
+#endif
     "smartmontools build host: "SMARTMONTOOLS_BUILD_HOST"\n"
     "smartmontools build configured: "SMARTMONTOOLS_CONFIGURE_DATE "\n"
     "%s compile dated "__DATE__" at "__TIME__"\n"
@@ -390,10 +392,14 @@ regular_expression::regular_expression()
   memset(&m_regex_buf, 0, sizeof(m_regex_buf));
 }
 
-regular_expression::regular_expression(const char * pattern, int flags)
+regular_expression::regular_expression(const char * pattern, int flags,
+                                       bool throw_on_error /*= true*/)
 {
   memset(&m_regex_buf, 0, sizeof(m_regex_buf));
-  compile(pattern, flags);
+  if (!compile(pattern, flags) && throw_on_error)
+    throw std::runtime_error(strprintf(
+      "error in regular expression \"%s\": %s",
+      m_pattern.c_str(), m_errmsg.c_str()));
 }
 
 regular_expression::~regular_expression()
@@ -620,10 +626,6 @@ int split_selective_arg(char *s, uint64_t *start,
 
 #ifdef OLD_INTERFACE
 
-// smartd exit codes
-#define EXIT_NOMEM     8   // out of memory
-#define EXIT_BADCODE   10  // internal error - should NEVER happen
-
 int64_t bytes = 0;
 
 // Helps debugging.  If the second argument is non-negative, then
@@ -642,15 +644,12 @@ void *FreeNonZero1(void *address, int size, int line, const char* file){
 
 // To help with memory checking.  Use when it is known that address is
 // NOT null.
-void *CheckFree1(void *address, int whatline, const char* file){
+void *CheckFree1(void *address, int /*whatline*/, const char* /*file*/){
   if (address){
     free(address);
     return NULL;
   }
-  
-  PrintOut(LOG_CRIT, "Internal error in CheckFree() at line %d of file %s\n%s", 
-           whatline, file, reportbug);
-  EXIT(EXIT_BADCODE);
+  throw std::runtime_error("Internal error in CheckFree()");
 }
 
 // A custom version of calloc() that tracks memory use
@@ -666,16 +665,13 @@ void *Calloc(size_t nmemb, size_t size) {
 // A custom version of strdup() that keeps track of how much memory is
 // being allocated. If mustexist is set, it also throws an error if we
 // try to duplicate a NULL string.
-char *CustomStrDup(const char *ptr, int mustexist, int whatline, const char* file){
+char *CustomStrDup(const char *ptr, int mustexist, int /*whatline*/, const char* /*file*/){
   char *tmp;
 
   // report error if ptr is NULL and mustexist is set
   if (ptr==NULL){
-    if (mustexist) {
-      PrintOut(LOG_CRIT, "Internal error in CustomStrDup() at line %d of file %s\n%s", 
-               whatline, file, reportbug);
-      EXIT(EXIT_BADCODE);
-    }
+    if (mustexist)
+      throw std::runtime_error("Internal error in CustomStrDup()");
     else
       return NULL;
   }
@@ -683,10 +679,8 @@ char *CustomStrDup(const char *ptr, int mustexist, int whatline, const char* fil
   // make a copy of the string...
   tmp=strdup(ptr);
   
-  if (!tmp) {
-    PrintOut(LOG_CRIT, "No memory to duplicate string %s at line %d of file %s\n", ptr, whatline, file);
-    EXIT(EXIT_NOMEM);
-  }
+  if (!tmp)
+    throw std::bad_alloc();
   
   // and track memory usage
   bytes+=1+strlen(ptr);
@@ -711,7 +705,6 @@ bool nonempty(const void * data, int size)
 // string of the form Xd+Yh+Zm+Ts.msec.  The resulting text string is
 // written to the array.
 void MsecToText(unsigned int msec, char *txt){
-  int start=0;
   unsigned int days, hours, min, sec;
 
   days       = msec/86400000U;
@@ -728,7 +721,6 @@ void MsecToText(unsigned int msec, char *txt){
 
   if (days) {
     txt += sprintf(txt, "%2dd+", (int)days);
-    start=1;
   }
 
   sprintf(txt, "%02d:%02d:%02d.%03d", (int)hours, (int)min, (int)sec, (int)msec);  
index 3ad6912f6da85549d88ed54cd61886cc7c8ded81..f2d081ffc022751ca6a69fbd10b9c8c8ec6b267c 100644 (file)
--- a/utility.h
+++ b/utility.h
@@ -3,8 +3,8 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2002-10 Bruce Allen <smartmontools-support@lists.sourceforge.net>
- * Copyright (C) 2008-10 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2008-11 Christian Franke <smartmontools-support@lists.sourceforge.net>
  * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
  *
  * 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 3093 2010-04-30 09:57:36Z chrfranke $"
+#define UTILITY_H_CVSID "$Id: utility.h 3285 2011-03-04 22:08:49Z chrfranke $"
 
 #include <time.h>
 #include <sys/types.h> // for regex.h (according to POSIX)
@@ -134,16 +134,6 @@ inline T * CheckFree(T * address, int whatline, const char* file)
 
 #endif // OLD_INTERFACE
 
-// This function prints either to stdout or to the syslog as needed
-
-// [From GLIBC Manual: Since the prototype doesn't specify types for
-// optional arguments, in a call to a variadic function the default
-// argument promotions are performed on the optional argument
-// values. This means the objects of type char or short int (whether
-// signed or not) are promoted to either int or unsigned int, as
-// appropriate.]
-void PrintOut(int priority, const char *fmt, ...) __attribute__ ((format(printf, 2, 3)));
-
 // Compile time check of byte ordering
 // (inline const function allows compiler to remove dead code)
 inline bool isbigendian()
@@ -273,7 +263,8 @@ public:
   // Construction & assignment
   regular_expression();
 
-  regular_expression(const char * pattern, int flags);
+  regular_expression(const char * pattern, int flags,
+                     bool throw_on_error = true);
 
   ~regular_expression();
 
@@ -323,10 +314,6 @@ private:
   bool compile();
 };
 
-// macros to control printing
-#define PRINT_ON(control)  {if (control->printing_switchable) control->dont_print=false;}
-#define PRINT_OFF(control) {if (control->printing_switchable) control->dont_print=true;}
-
 #ifdef _WIN32
 // Get exe directory
 //(implemented in os_win32.cpp)
@@ -335,21 +322,10 @@ std::string get_exe_dir();
 
 
 #ifdef OLD_INTERFACE
-// possible values for controller_type in extern.h
+// remaining controller types in old interface modules
 #define CONTROLLER_UNKNOWN              0x00
 #define CONTROLLER_ATA                  0x01
 #define CONTROLLER_SCSI                 0x02
-#define CONTROLLER_3WARE                0x03  // set by -d option, but converted to one of three types below
-#define CONTROLLER_3WARE_678K           0x04  // NOT set by guess_device_type()
-#define CONTROLLER_3WARE_9000_CHAR      0x05  // set by guess_device_type()
-#define CONTROLLER_3WARE_678K_CHAR      0x06  // set by guess_device_type()
-#define CONTROLLER_MARVELL_SATA         0x07  // SATA drives behind Marvell controllers
-#define CONTROLLER_SAT                         0x08  // SATA device behind a SCSI ATA Translation (SAT) layer
-#define CONTROLLER_HPT                  0x09  // SATA drives behind HighPoint Raid controllers
-#define CONTROLLER_CCISS               0x10  // CCISS controller 
-#define CONTROLLER_PARSEDEV             0x11  // "smartctl -r ataioctl,2 ..." output parser pseudo-device
-#define CONTROLLER_USBCYPRESS          0x12  // ATA device behind Cypress USB bridge
-#define CONTROLLER_ARECA                0x13  // Areca controller
 #endif
 
 #endif