Imported Upstream version 6.5+svn4324

This commit is contained in:
Giuseppe Iuculano 2016-07-30 18:33:10 +02:00
parent d2e702cfb9
commit a86ec89e3a
102 changed files with 9455 additions and 4849 deletions

38
AUTHORS
View File

@ -1,39 +1,41 @@
$Id: AUTHORS 3751 2013-01-18 21:19:43Z chrfranke $ $Id: AUTHORS 4285 2016-04-10 13:17:11Z chrfranke $
This code was originally developed as a Senior Thesis by Michael Developers / Maintainers / Contributors:
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/
This package is meant to be an up-to-date replacement for the Raghava Aditya <...>
ucsc-smartsuite and smartsuite packages, and is derived from that code. Bruce Allen <...>
Erik Inge Bolsø <...>
Maintainers / Developers:
Bruce Allen <smartmontools-support@lists.sourceforge.net>
Erik Inge Bolsø <knan@mo.himolde.no>
Stanislav Brabec <sbrabec@suse.cz> Stanislav Brabec <sbrabec@suse.cz>
Peter Cassidy <pcassidy@mac.com> Peter Cassidy <pcassidy@mac.com>
Praveen Chidambaram <bunchofmails@gmail.com> Praveen Chidambaram <bunchofmails@gmail.com>
Yuri Dario <mc6530@mclink.it> Yuri Dario <mc6530@mclink.it>
Casper Dik <casper@holland.sun.com> Casper Dik <...>
Christian Franke <franke@computer.org> Christian Franke <franke@computer.org>
Guilhem Frézou <guilhem.frezou@catii.fr> Guilhem Frézou <...>
Thomas Gatterweh <thomas_gatterweh@hotmail.com>
Douglas Gilbert <dgilbert@interlog.com> Douglas Gilbert <dgilbert@interlog.com>
Guido Guenther <agx@sigxcpu.org> Guido Guenther <agx@sigxcpu.org>
Jordan Hargrave <jordan_hargrave@dell.com> Jordan Hargrave <jordan_hargrave@dell.com>
Joerg Hering <hering.ruegen@gmx.de> Joerg Hering <...>
Geoff Keating <geoffk@geoffk.org> Geoff Keating <geoffk@geoffk.org>
Dr. David Kirkby <drkirkby@ntlworld.com> Dr. David Kirkby <...>
Dan Lukes <dan+smartmontools.changelog@obluda.cz>
Kai Mäkisara <kai.makisara@kolumbus.fi> Kai Mäkisara <kai.makisara@kolumbus.fi>
Nidhi Malhotra <nidhi.malhotra@pmcs.com>
Eduard Martinescu <martines@rochester.rr.com> Eduard Martinescu <martines@rochester.rr.com>
Frédéric L. W. Meunier <http://www.pervalidus.net/contact.html> Frédéric L. W. Meunier <...>
Alex Samorukov <samm@os2.kiev.ua> Alex Samorukov <samm@os2.kiev.ua>
Keiji Sawada <card_captor@users.sourceforge.net> Keiji Sawada <card_captor@users.sourceforge.net>
Manfred Schwarb <manfred99@gmx.ch> Manfred Schwarb <manfred99@gmx.ch>
Tomas Smetana <tsmetana@redhat.com> Tomas Smetana <tsmetana@redhat.com>
David Snyder <dasnyderx@yahoo.com> David Snyder <dasnyderx@yahoo.com>
Sergey Svishchev <svs@ropnet.ru> Sergey Svishchev <svs@ropnet.ru>
Phil Williams <phil@subbacultcha.demon.co.uk> Tommy Vestermark <tommy.vestermark@gmail.com>
Roger Willcocks <roger@filmlight.ltd.uk>
Phil Williams <...>
Hank Wu <hank@areca.com.tw>
Shengfeng Zhou <linux@highpoint-tech.com> Shengfeng Zhou <linux@highpoint-tech.com>
Richard Zybert <richard.zybert@zybert.co.uk> Richard Zybert <richard.zybert@zybert.co.uk>
The first smartmontools code was derived from the smartsuite package,
written by Michael Cornwell and Andre Hedrick.

1129
ChangeLog

File diff suppressed because it is too large Load Diff

230
INSTALL
View File

@ -1,10 +1,10 @@
Smartmontools installation instructions Smartmontools installation instructions
======================================= =======================================
$Id: INSTALL 3935 2014-07-05 16:28:06Z chrfranke $ $Id: INSTALL 4120 2015-08-27 16:12:21Z samm2 $
Please also see the smartmontools home page: Please also see the smartmontools home page:
http://smartmontools.sourceforge.net/ http://www.smartmontools.org/
Table of contents: Table of contents:
@ -32,49 +32,6 @@ Table of contents:
kernel version greater than or equal to 2.2.14. So any recent kernel version greater than or equal to 2.2.14. So any recent
Linux distribution should support smartmontools. Linux distribution should support smartmontools.
There are two parts of smartmontools that may require a patched or
nonstandard kernel:
(1) To get the ATA RETURN SMART STATUS command, the kernel needs
to support the HDIO_DRIVE_TASK ioctl().
(2) To run Selective Self-tests, the kernel needs to support the
HDIO_DRIVE_TASKFILE ioctl().
If your kernel does not support one or both of these ioctls, then
smartmontools will "mostly" work. The things that don't work will
give you harmless warning messages.
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.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
kernel will probably support this ioctl. [Note that this kernel
configuration option does NOT need to be enabled. Its presence
merely indicates that the required HDIO_DRIVE_TASK ioctl() is
supported.]
For item (2) above, your kernel must be configured with the kernel
configuration option CONFIG_IDE_TASKFILE_IO enabled. This
configuration option is present in all 2.4 and 2.6 series
kernels. Some 2.2.20 and later kernels also provide this support
IF they're properly patched and configured as described above.
Please see FAQ section of the URL above for additional details.
If you are using 3ware controllers, for full functionality you
must either use version 1.02.00.037 or greater of the 3w-xxxx
driver, or patch earlier 3ware 3w-xxxx drivers. See
http://smartmontools.sourceforge.net/3w-xxxx.txt
for the patch. The version 1.02.00.037 3w-xxxx.c driver was
incorporated into kernel 2.4.23-bk2 on 3 December 2003 and into
kernel 2.6.0-test5-bk11 on 23 September 2003.
B) FreeBSD B) FreeBSD
For FreeBSD support, a 5-current kernel that includes ATAng is For FreeBSD support, a 5-current kernel that includes ATAng is
@ -106,9 +63,9 @@ Table of contents:
F) Windows F) Windows
The code was tested on Windows XP SP3, 2003, Vista, Windows 7 and The code was tested on Windows XP SP3, 2003, Vista, Windows 7, 8, 8.1
Windows 8 Release Preview. Support von Windows 9x/ME and NT4 was removed and Windows 10 Release Preview. Support von Windows 9x/ME and NT4 was
after smartmontools 5.43. removed after smartmontools 5.43.
ATA or SATA devices are supported if the device driver implements ATA or SATA devices are supported if the device driver implements
the SMART IOCTLs or IOCTL_IDE_PASS_THROUGH or IOCTL_ATA_PASS_THROUGH. the SMART IOCTLs or IOCTL_IDE_PASS_THROUGH or IOCTL_ATA_PASS_THROUGH.
@ -179,7 +136,7 @@ Table of contents:
The code was tested on eComStation 1.1, but it should work on all versions The code was tested on eComStation 1.1, but it should work on all versions
of OS/2. of OS/2.
Innotek LibC 0.5 runtime is required. Innotek LibC 0.5 runtime is required.
Currently only ATA disks are supported, SCSI support will be added. Only ATA disks are supported.
[2] Installing from SVN [2] Installing from SVN
======================= =======================
@ -210,22 +167,31 @@ Table of contents:
make install (you may need to be root to do this) make install (you may need to be root to do this)
As shown (with no options to ./configure) this defaults to the As shown (with no options to ./configure) this defaults to the
following set of installation directories: following set of installation directories and other settings:
--prefix=/usr/local --prefix=/usr/local
--sbindir=/usr/local/sbin --exec-prefix='${prefix}'
--sysconfdir=/usr/local/etc --sbindir='${exec_prefix}/sbin'
--mandir=/usr/local/share/man --sysconfdir='${prefix}/etc'
--docdir=/usr/local/share/doc/smartmontools --localstatedir='${prefix}/var'
--with-exampledir=/usr/local/share/doc/smartmontools/examplescripts --datarootdir='${prefix}/share'
--with-drivedbdir=/usr/local/share/smartmontools --datadir='${datarootdir}'
--with-initscriptdir=auto --mandir='${datarootdir}/man'
--with-systemdsystemunitdir=auto --docdir='${datarootdir}/doc/smartmontools'
--enable-drivedb
--disable-attributelog
--disable-sample --disable-sample
--disable-savestates --with-systemdsystemunitdir=auto
--with-libcap-ng=auto --with-systemdenvfile=auto
--with-initscriptdir=auto
--with-exampledir='${docdir}/examplescripts'
--with-drivedbdir='${datadir}/smartmontools'
--with-smartdscriptdir='${sysconfdir}'
--with-smartdplugindir='${smartdscriptdir}/smartd_warning.d'
--without-savestates
--without-attributelog
--with-os-deps='os_linux.o dev_areca.o' (platform specific)
--without-selinux --without-selinux
--with-libcap-ng=auto
--with-working-snprintf
These will usually not overwrite existing "distribution" installations on These will usually not overwrite existing "distribution" installations on
Linux Systems since the FHS reserves this area for use by the system Linux Systems since the FHS reserves this area for use by the system
@ -415,35 +381,17 @@ To compile the Windows release with MinGW gcc on MSYS, use:
Instead of using "make install", copy the .exe files into Instead of using "make install", copy the .exe files into
some directory in the PATH. some directory in the PATH.
Cross-compile statically linked 32-bit version with MinGW-w64: Cross-compile statically linked 32-bit and 64-bit versions with MinGW-w64:
./configure --build=$(./config.guess) \ ./configure --build=$(./config.guess) \
--host=i686-w64-mingw32 \ --host=i686-w64-mingw32 \
LDFLAGS=-static LDFLAGS=-static
Tested on Cygwin and Debian Linux.
Cross-compile statically linked 64-bit version with MinGW-w64:
./configure --build=$(./config.guess) \ ./configure --build=$(./config.guess) \
--host=x86_64-w64-mingw32 \ --host=x86_64-w64-mingw32 \
LDFLAGS=-static LDFLAGS=-static
Tested on Cygwin and Debian Linux with MinGW-w64 from Tested on Cygwin, Debian and Fedora.
http://mingw-w64.sourceforge.net/.
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' \
CXXFLAGS='-g -O2 -Wall -W -Wno-format'
Cross-compile on Debian Linux with gcc-mingw32:
./configure --build=$(./config.guess) \
--host=i586-mingw32msvc
To build the Windows binary distribution, use: To build the Windows binary distribution, use:
@ -472,7 +420,8 @@ To create a Windows installer, use:
download location. download location.
It is also possible to (cross-)build the installer on Linux. It is also possible to (cross-)build the installer on Linux.
This was successfully tested on Debian with package "nsis". This was successfully tested on Debian and Fedora with package
"nsis".
To create a combined 32-/64-bit installer, use this in 32-bit build To create a combined 32-/64-bit installer, use this in 32-bit build
directory if 64-build directory is at ../build64: directory if 64-build directory is at ../build64:
@ -488,14 +437,6 @@ To both create and run the (interactive) installer, use:
The binary distribution includes all documentation files converted The binary distribution includes all documentation files converted
to DOS text file format and *.html and *.txt preformatted man pages. to DOS text file format and *.html and *.txt preformatted man pages.
The tools unix2dos.exe (package cygutils) and zip.exe (package zip
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.
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 MS Visual Studio C++ 2010 [Express], To prepare os_win32 directory for MS Visual Studio C++ 2010 [Express],
use the following on MSYS or Cygwin: use the following on MSYS or Cygwin:
@ -506,9 +447,9 @@ use the following on MSYS or Cygwin:
The MSVC project files (os_win32/vc10/*) are included in SVN (but not The MSVC project files (os_win32/vc10/*) are included in SVN (but not
in source tarball). The target config-vc10 from a Makefile configured in source tarball). The target config-vc10 from a Makefile configured
for MinGW creates os_win32/vc10/{config,svnversion}.h from for MinGW creates os_win32/vc10/{config.h,smart*.rc,svnversion.h}.
./{config,svnversion}.h. The configure skript must be run outside The configure skript must be run outside of the source directory to
of the source directory to avoid inclusion of the original config.h. avoid inclusion of the original config.h.
[11] Guidelines for OS/2, eComStation [11] Guidelines for OS/2, eComStation
@ -567,8 +508,8 @@ man smartd.conf
man smartctl man smartctl
man smartd man smartd
/usr/sbin/smartctl -s on -o on -S on /dev/hda (only root can do this) /usr/sbin/smartctl -s on -o on -S on /dev/sda (only root can do this)
/usr/sbin/smartctl -a /dev/hda (only root can do this) /usr/sbin/smartctl -a /dev/sda (only root can do this)
Note that the default location for the manual pages are Note that the default location for the manual pages are
/usr/share/man/man5 and /usr/share/man/man8. If "man" doesn't find /usr/share/man/man5 and /usr/share/man/man8. If "man" doesn't find
@ -587,22 +528,30 @@ The following files are installed if ./configure has no options:
/usr/local/sbin/smartd [Executable daemon] /usr/local/sbin/smartd [Executable daemon]
/usr/local/sbin/update-smart-drivedb [Drive database update script] /usr/local/sbin/update-smart-drivedb [Drive database update script]
/usr/local/etc/smartd.conf [Configuration file for smartd daemon] /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/etc/smartd_warning.sh [Warning skript for smartd daemon]
/usr/local/share/man/man5/smartd.conf.5 [Manual page] /usr/local/share/man/man5/smartd.conf.5 [Manual page]
/usr/local/share/man/man8/smartctl.8 [Manual page] /usr/local/share/man/man8/smartctl.8 [Manual page]
/usr/local/share/man/man8/smartd.8 [Manual page] /usr/local/share/man/man8/smartd.8 [Manual page]
/usr/local/share/man/man8/update-smart-drivedb.8 [Manual page]
/usr/local/share/doc/smartmontools/AUTHORS [Information about the authors and developers] /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/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/COPYING [GNU General Public License Version 2]
/usr/local/share/doc/smartmontools/INSTALL [Installation instructions: what you're reading!] /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/NEWS [Significant enhancements and fixes]
/usr/local/share/doc/smartmontools/README [Overview] /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/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/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/doc/smartmontools/examplescripts/ [Executable scripts for -M exec of smartd.conf (4 files)]
/usr/local/share/smartmontools/drivedb.h [Drive database] /usr/local/share/smartmontools/drivedb.h [Drive database]
Due to checks done by '--with-systemdsystemunitdir=auto' and '--with-initscriptdir=auto',
one of the following files may also be installed:
/usr/local/lib/systemd/system/smartd.service [Systemd service file for smartd]
/usr/local/etc/rc.d/init.d/smartd [Init/Startup script for smartd]
/usr/local/etc/init.d/smartd [Init/Startup script for smartd]
/usr/local/etc/rc.d/smartd [Init/Startup script for smartd]
If /usr/local/etc/smartd.conf exists and differs from the If /usr/local/etc/smartd.conf exists and differs from the
default then the default configuration file is installed as default then the default configuration file is installed as
/usr/local/etc/smartd.conf.sample instead. /usr/local/etc/smartd.conf.sample instead.
@ -640,52 +589,23 @@ a documentation file doc/latex/refman.pdf:
=========================================================== ===========================================================
When you type: When you type:
./configure [options] ./configure --help
there are six particularly important variables that affect where the a description of available configure options is printed
smartmontools software is installed. The variables are listed here, [with defaults in square brackets]. See also section [3] above.
with their default values in square brackets, and the quantities that
they affect described following that. This is a very wide table: please read
it in a wide window.
OPTIONS DEFAULT AFFECTS
------- ------- -------
--prefix /usr/local Please see below
--sbindir ${prefix}/sbin Directory for smartd/smartctl executables;
Contents of smartd/smartctl man pages
--docdir ${prefix}/share/doc/smartmontools Location of the documentation
(autoconf >= 2.60 only, see also --with-docdir below)
--mandir ${prefix}/share/man Directory for smartctl/smartd/smartd.conf man pages
--sysconfdir ${prefix}/etc Directory for smartd.conf;
Contents of smartd executable;
Contents of smartd/smartd.conf man pages;
Directory for rc.d/init.d/smartd init script
--with-initscriptdir auto Location of init scripts
--with-systemdsystemunitdir auto Location of systemd service files
--with-systemdenvfile ${sysconfdir}/sysconfig/smartmontools Path of environment file for system service
--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 --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
available, option --capabilities is added to smartd.
--disable-drivedb --enable-drivedb Disables default drive database file '${drivedbdir}/drivedb.h'
--with-drivedbdir ${prefix}/share/smartmontools Directory for 'drivedb.h' (implies --enable-drivedb)
--with-smartdscriptdir ${sysconfdir} Directory for 'smartd_warning.sh' script
--with-smartdplugindir ${sysconfdir}/smartd_warning.d Directory for 'smartd_warning.sh' plugin scripts
--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)
--enable-attributelog --disable-attributelog Enables default smartd attribute log files
--with-attributelog ${prefix}/var/lib/smartmontools/attrlog. Prefix for smartd attribute log files (implies --enable-attributelog)
--with-working-snprintf MinGW:guessed,others:yes Function snprintf() handles output truncation as specified by C99
Please note that in previous versions of smartmontools (<= 5.39) the The following old configure options are deprecated and will be removed
default for --with-docdir was in a future release of smartmontools:
${prefix}/share/doc/smartmontools-VERSION
This was changed to make it consistent with the default of the Old option Replacement
new --docdir option added in autoconf 2.60. --with-docdir=DIR --docdir=DIR (autoconf >= 2.60)
--enable-drivedb [no option needed]
--disable-drivedb --without-drivedbdir
--enable-savestates --with-savestates[=yes]
--disable-savestates [no option needed]
--enable-attrbutelog --with-attributelog[=yes]
--disable-savestates [no option needed]
The defaults for --with-initscriptdir and --with-systemdsystemunitdir are The defaults for --with-initscriptdir and --with-systemdsystemunitdir are
guessed such that the following rules apply: guessed such that the following rules apply:
@ -732,30 +652,6 @@ else
--with-initscriptdir [disabled] --with-initscriptdir [disabled]
--with-systemdsystemunitdir [disabled] --with-systemdsystemunitdir [disabled]
This is useful for test installs in a harmless subdirectory somewhere.
Here are the four possible cases for the four variables above:
Case 1:
--prefix not set
--variable not set
===> VARIABLE gets default value above
Case 2:
--prefix set
--variable not set
===> VARIABLE gets PREFIX/ prepended to default value above
Case 3:
--prefix not set
--variable set
===> VARIABLE gets value that is set
Case 4:
--prefix is set
--variable is set
===> PREFIX is IGNORED, VARIABLE gets value that is set
Here are the differences with and without --enable-sample, assuming Here are the differences with and without --enable-sample, assuming
that initscript location is set and no other options specified that initscript location is set and no other options specified

View File

@ -1,6 +1,6 @@
## Process this file with automake to produce Makefile.in ## Process this file with automake to produce Makefile.in
# #
# $Id: Makefile.am 3957 2014-07-18 18:39:06Z chrfranke $ # $Id: Makefile.am 4299 2016-04-16 19:45:57Z chrfranke $
# #
@SET_MAKE@ @SET_MAKE@
@ -42,7 +42,7 @@ sbin_PROGRAMS = \
smartctl \ smartctl \
smartd smartd
if ENABLE_DRIVEDB if ENABLE_UPDATE_SMART_DRIVEDB
if OS_WIN32_MINGW if OS_WIN32_MINGW
else else
sbin_SCRIPTS = update-smart-drivedb sbin_SCRIPTS = update-smart-drivedb
@ -70,6 +70,10 @@ smartctl_SOURCES = \
int64.h \ int64.h \
knowndrives.cpp \ knowndrives.cpp \
knowndrives.h \ knowndrives.h \
nvmecmds.cpp \
nvmecmds.h \
nvmeprint.cpp \
nvmeprint.h \
scsicmds.cpp \ scsicmds.cpp \
scsicmds.h \ scsicmds.h \
scsiata.cpp \ scsiata.cpp \
@ -78,8 +82,8 @@ smartctl_SOURCES = \
utility.cpp \ utility.cpp \
utility.h utility.h
smartctl_LDADD = @os_deps@ @os_libs@ smartctl_LDADD = $(os_deps) $(os_libs)
smartctl_DEPENDENCIES = @os_deps@ smartctl_DEPENDENCIES = $(os_deps)
EXTRA_smartctl_SOURCES = \ EXTRA_smartctl_SOURCES = \
os_darwin.cpp \ os_darwin.cpp \
@ -96,7 +100,6 @@ EXTRA_smartctl_SOURCES = \
os_qnxnto.h \ os_qnxnto.h \
os_solaris.cpp \ os_solaris.cpp \
os_solaris.h \ os_solaris.h \
os_solaris_ata.s \
os_win32.cpp \ os_win32.cpp \
os_generic.cpp \ os_generic.cpp \
os_generic.h \ os_generic.h \
@ -107,12 +110,13 @@ EXTRA_smartctl_SOURCES = \
dev_areca.cpp \ dev_areca.cpp \
dev_areca.h \ dev_areca.h \
dev_legacy.cpp \ dev_legacy.cpp \
linux_nvme_ioctl.h \
megaraid.h megaraid.h
if OS_WIN32_MINGW if OS_WIN32_MINGW
smartctl_LDADD += smartctl_res.o smartctl_LDADD += smartctl_res.o $(os_win32_manifest)
smartctl_DEPENDENCIES += smartctl_res.o smartctl_DEPENDENCIES += smartctl_res.o $(os_win32_manifest)
endif endif
@ -132,14 +136,16 @@ smartd_SOURCES = \
int64.h \ int64.h \
knowndrives.cpp \ knowndrives.cpp \
knowndrives.h \ knowndrives.h \
nvmecmds.cpp \
nvmecmds.h \
scsicmds.cpp \ scsicmds.cpp \
scsicmds.h \ scsicmds.h \
scsiata.cpp \ scsiata.cpp \
utility.cpp \ utility.cpp \
utility.h utility.h
smartd_LDADD = @os_deps@ @os_libs@ @CAPNG_LDADD@ smartd_LDADD = $(os_deps) $(os_libs) $(CAPNG_LDADD)
smartd_DEPENDENCIES = @os_deps@ smartd_DEPENDENCIES = $(os_deps)
EXTRA_smartd_SOURCES = \ EXTRA_smartd_SOURCES = \
os_darwin.cpp \ os_darwin.cpp \
@ -156,7 +162,6 @@ EXTRA_smartd_SOURCES = \
os_qnxnto.h \ os_qnxnto.h \
os_solaris.cpp \ os_solaris.cpp \
os_solaris.h \ os_solaris.h \
os_solaris_ata.s \
os_win32.cpp \ os_win32.cpp \
os_generic.cpp \ os_generic.cpp \
os_generic.h \ os_generic.h \
@ -167,6 +172,8 @@ EXTRA_smartd_SOURCES = \
dev_areca.cpp \ dev_areca.cpp \
dev_areca.h \ dev_areca.h \
dev_legacy.cpp \ dev_legacy.cpp \
linux_nvme_ioctl.h \
freebsd_nvme_ioctl.h \
megaraid.h megaraid.h
if OS_WIN32_MINGW if OS_WIN32_MINGW
@ -177,11 +184,14 @@ smartd_SOURCES += \
os_win32/syslog_win32.cpp \ os_win32/syslog_win32.cpp \
os_win32/syslog.h os_win32/syslog.h
smartd_LDADD += smartd_res.o smartd_LDADD += smartd_res.o $(os_win32_manifest)
smartd_DEPENDENCIES += smartd_res.o smartd_DEPENDENCIES += smartd_res.o $(os_win32_manifest)
endif endif
# Exclude from source tarball
nodist_EXTRA_smartctl_SOURCES = os_solaris_ata.s
nodist_EXTRA_smartd_SOURCES = os_solaris_ata.s
if NEED_GETOPT_LONG if NEED_GETOPT_LONG
@ -248,15 +258,15 @@ if OS_SOLARIS
extra_MANS = smartd.conf.4 \ extra_MANS = smartd.conf.4 \
smartctl.1m \ smartctl.1m \
smartd.1m smartd.1m
if ENABLE_DRIVEDB if ENABLE_UPDATE_SMART_DRIVEDB
extra_MANS += update-smart-drivedb.1m extra_MANS += update-smart-drivedb.1m
endif endif
all-local: $(extra_MANS) all-local: $(extra_MANS)
install-man: $(extra_MANS) install-man: $(extra_MANS)
@$(NORMAL_INSTALL) @$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(mandir)/man4 $(MKDIR_P) '$(DESTDIR)$(mandir)/man4'
$(mkinstalldirs) $(DESTDIR)$(mandir)/man1m $(MKDIR_P) '$(DESTDIR)$(mandir)/man1m'
for i in $(extra_MANS); do \ for i in $(extra_MANS); do \
if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
else file=$$i; fi; \ else file=$$i; fi; \
@ -264,8 +274,8 @@ install-man: $(extra_MANS)
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \
inst=`echo $$inst | sed '$(transform)'`.$$ext; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
echo " $(INSTALL_DATA) $$file $(DESTDIR)$(mandir)/man$$ext/$$inst"; \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(mandir)/man$$ext/$$inst'"; \
$(INSTALL_DATA) $$file $(DESTDIR)$(mandir)/man$$ext/$$inst; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(mandir)/man$$ext/$$inst"; \
done done
uninstall-man: uninstall-man:
@$(NORMAL_UNINSTALL) @$(NORMAL_UNINSTALL)
@ -276,8 +286,8 @@ uninstall-man:
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \
inst=`echo $$inst | sed '$(transform)'`.$$ext; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
echo " rm -f $(DESTDIR)$(mandir)/man$$ext/$$inst"; \ echo " rm -f '$(DESTDIR)$(mandir)/man$$ext/$$inst'"; \
rm -f $(DESTDIR)$(mandir)/man$$ext/$$inst; \ rm -f "$(DESTDIR)$(mandir)/man$$ext/$$inst"; \
done done
else else
# For systems that adopts traditional manner # For systems that adopts traditional manner
@ -286,7 +296,7 @@ man_MANS = smartd.conf.5 \
smartctl.8 \ smartctl.8 \
smartd.8 smartd.8
if ENABLE_DRIVEDB if ENABLE_UPDATE_SMART_DRIVEDB
man_MANS += update-smart-drivedb.8 man_MANS += update-smart-drivedb.8
endif endif
@ -302,7 +312,6 @@ docs_DATA = \
NEWS \ NEWS \
README \ README \
TODO \ TODO \
WARNINGS \
smartd.conf smartd.conf
examplesdir=$(exampledir) examplesdir=$(exampledir)
@ -320,7 +329,7 @@ sysconf_DATA = smartd.conf
# If modified smartd.conf exists install smartd.conf.sample instead # If modified smartd.conf exists install smartd.conf.sample instead
install-sysconfDATA: $(sysconf_DATA) install-sysconfDATA: $(sysconf_DATA)
$(mkinstalldirs) $(DESTDIR)$(sysconfdir) $(MKDIR_P) '$(DESTDIR)$(sysconfdir)'
@s="$(srcdir)/smartd.conf"; \ @s="$(srcdir)/smartd.conf"; \
f="$(DESTDIR)$(sysconfdir)/smartd.conf$(smartd_suffix)"; \ f="$(DESTDIR)$(sysconfdir)/smartd.conf$(smartd_suffix)"; \
if test -z "$(smartd_suffix)" && test -f "$$f"; then \ if test -z "$(smartd_suffix)" && test -f "$$f"; then \
@ -332,7 +341,7 @@ install-sysconfDATA: $(sysconf_DATA)
f="$$f".sample; \ f="$$f".sample; \
fi; \ fi; \
fi; \ fi; \
echo " $(INSTALL_DATA) $$s $$f"; \ echo " $(INSTALL_DATA) '$$s' '$$f'"; \
$(INSTALL_DATA) "$$s" "$$f" $(INSTALL_DATA) "$$s" "$$f"
# If smartd.conf.sample exists preserve smartd.conf # If smartd.conf.sample exists preserve smartd.conf
@ -345,7 +354,7 @@ uninstall-sysconfDATA:
echo "************************************************************"; \ echo "************************************************************"; \
f="$$f".sample; \ f="$$f".sample; \
fi; \ fi; \
echo " rm -f $$f"; \ echo " rm -f '$$f'"; \
rm -f "$$f" rm -f "$$f"
smartdscript_SCRIPTS = smartd_warning.sh smartdscript_SCRIPTS = smartd_warning.sh
@ -363,13 +372,14 @@ EXTRA_DIST = \
update-smart-drivedb.in \ update-smart-drivedb.in \
update-smart-drivedb.8.in \ update-smart-drivedb.8.in \
m4/pkg.m4 \ m4/pkg.m4 \
os_darwin/SMART.in \ os_darwin/com.smartmontools.smartd.plist.in \
os_darwin/StartupParameters.plist \ os_darwin/pkg/PackageInfo.in \
os_darwin/English_Localizable.strings \ os_darwin/pkg/Distribution.in \
os_darwin/pkg/installer/README.html \
os_darwin/pkg/root/usr/local/sbin/smart-pkg-uninstall \
os_win32/default.manifest \
os_win32/installer.nsi \ os_win32/installer.nsi \
os_win32/runcmd.c \ os_win32/runcmd.c \
os_win32/runcmda.exe.manifest \
os_win32/runcmdu.exe.manifest \
os_win32/smartctl_res.rc.in \ os_win32/smartctl_res.rc.in \
os_win32/smartd_res.rc.in \ os_win32/smartd_res.rc.in \
os_win32/smartd_warning.cmd \ os_win32/smartd_warning.cmd \
@ -387,12 +397,15 @@ CLEANFILES = \
smartd.8 \ smartd.8 \
smartd.1m \ smartd.1m \
smartd.8.html \ smartd.8.html \
smartd.8.html.tmp \
smartd.8.txt \ smartd.8.txt \
smartctl.8 \ smartctl.8 \
smartctl.1m \ smartctl.1m \
smartctl.8.html \ smartctl.8.html \
smartctl.8.html.tmp \
smartctl.8.txt \ smartctl.8.txt \
smartd.conf.5.html \ smartd.conf.5.html \
smartd.conf.5.html.tmp \
smartd.conf.5.txt \ smartd.conf.5.txt \
smartd.initd \ smartd.initd \
smartd.freebsd.initd \ smartd.freebsd.initd \
@ -417,7 +430,6 @@ MAINTAINERCLEANFILES = \
$(srcdir)/depcomp \ $(srcdir)/depcomp \
$(srcdir)/install-sh \ $(srcdir)/install-sh \
$(srcdir)/missing \ $(srcdir)/missing \
$(srcdir)/mkinstalldirs \
$(srcdir)/m4/pkg.m4 $(srcdir)/m4/pkg.m4
utility.o: svnversion.h utility.o: svnversion.h
@ -435,10 +447,10 @@ svnversion.h: ChangeLog Makefile $(svn_deps)
else else
# SVN not available, guess version info from Id strings # SVN not available, guess version info from Id strings
svnversion.h: ChangeLog Makefile svnversion.h: ChangeLog Makefile NEWS
@echo ' cat ChangeLog $$(SOURCES) | $$(VERSION_FROM_SVN_IDS) > $@' @echo ' cat ChangeLog NEWS $$(SOURCES) | $$(VERSION_FROM_SVN_IDS) > $@'
@echo '/* svnversion.h. Generated by Makefile from Id strings. */' > $@ @echo '/* svnversion.h. Generated by Makefile from Id strings. */' > $@
@(cd $(srcdir) && cat ChangeLog Makefile.am configure.ac smart*.in *.cpp *.h *.s) \ @(cd $(srcdir) && cat ChangeLog NEWS Makefile.am configure.ac smart*.in *.cpp *.h) \
| sed -n 's,^.*\$$[I][d]: [^ ]* \([0-9][0-9]* [0-9][-0-9]* [0-9][:0-9]*\)[^:0-9][^$$]*\$$.*$$,\1,p' \ | sed -n 's,^.*\$$[I][d]: [^ ]* \([0-9][0-9]* [0-9][-0-9]* [0-9][:0-9]*\)[^:0-9][^$$]*\$$.*$$,\1,p' \
| sort -n -r \ | sort -n -r \
| sed -n 'h;s,^\([^ ]*\) .*$$,REV "\1",p;g;s,^[^ ]* \([^ ]*\) .*$$,DATE "\1",p;g;s,^[^ ]* [^ ]* \([^ ]*\)$$,TIME "\1",p;q' \ | sed -n 'h;s,^\([^ ]*\) .*$$,REV "\1",p;g;s,^[^ ]* \([^ ]*\) .*$$,DATE "\1",p;g;s,^[^ ]* [^ ]* \([^ ]*\)$$,TIME "\1",p;q' \
@ -460,41 +472,27 @@ smartd_warning.sh: smartd_warning.sh.in config.status
if INSTALL_INITSCRIPT if INSTALL_INITSCRIPT
if OS_DARWIN if OS_DARWIN
initd_DATA = SMART \ initd_DATA = com.smartmontools.smartd.plist
os_darwin/StartupParameters.plist \
os_darwin/English_Localizable.strings
initd_install_name = SMART
initd_DATA_install = install-initdDATA-darwin initd_DATA_install = install-initdDATA-darwin
initd_DATA_uninstall = uninstall-initdDATA-darwin initd_DATA_uninstall = uninstall-initdDATA-darwin
SMART : os_darwin/SMART.in com.smartmontools.smartd.plist : os_darwin/com.smartmontools.smartd.plist.in
sed "s|/usr/sbin/|$(sbindir)/|" $< > $@ sed "s|/usr/sbin/|$(sbindir)/|" $< > $@
install-initdDATA-darwin: $(initd_DATA) install-initdDATA-darwin: $(initd_DATA)
$(mkinstalldirs) $(DESTDIR)$(initddir) $(MKDIR_P) '$(DESTDIR)$(initddir)'
$(mkinstalldirs) $(DESTDIR)$(initddir)/SMART $(INSTALL_DATA) $(top_builddir)/$(initd_DATA) $(DESTDIR)$(initddir)/$(initd_DATA)
$(mkinstalldirs) $(DESTDIR)$(initddir)/SMART/Resources
$(INSTALL_SCRIPT) $(top_builddir)/SMART $(DESTDIR)$(initddir)/SMART
$(INSTALL_DATA) $(srcdir)/os_darwin/StartupParameters.plist \
$(DESTDIR)$(initddir)/SMART/StartupParameters.plist
for i in English ; do \
RDIR=$(DESTDIR)$(initddir)/SMART/Resources/$${i}.lproj ; \
$(mkinstalldirs) $$RDIR ;\
$(INSTALL_DATA) $(srcdir)/os_darwin/$${i}_Localizable.strings \
$$RDIR/Localizable.strings ; \
done
uninstall-initdDATA-darwin: uninstall-initdDATA-darwin:
rm -rf $(DESTDIR)$(initddir)/$(initd_install_name) rm -f $(DESTDIR)$(initddir)/$(initd_DATA)
else else
initd_DATA = @initdfile@ initd_DATA = $(initdfile)
@initdfile@: $(srcdir)/@initdfile@.in Makefile $(initdfile): $(srcdir)/$(initdfile).in Makefile
sed "s|/usr/local/sbin/|$(sbindir)/|g" $(srcdir)/@initdfile@.in > $@ sed 's|/usr/local/sbin/|$(sbindir)/|g' $(srcdir)/$(initdfile).in > $@
initd_install_name = smartd$(smartd_suffix) initd_install_name = smartd$(smartd_suffix)
@ -502,12 +500,11 @@ initd_DATA_install = install-initdDATA-generic
initd_DATA_uninstall = uninstall-initdDATA-generic initd_DATA_uninstall = uninstall-initdDATA-generic
install-initdDATA-generic: $(initd_DATA) install-initdDATA-generic: $(initd_DATA)
$(mkinstalldirs) $(DESTDIR)$(initddir) $(MKDIR_P) '$(DESTDIR)$(initddir)'
$(INSTALL_SCRIPT) $(top_builddir)/@initdfile@ $(DESTDIR)$(initddir)/smartd$(smartd_suffix) $(INSTALL_SCRIPT) '$(top_builddir)/$(initdfile)' '$(DESTDIR)$(initddir)/smartd$(smartd_suffix)'
uninstall-initdDATA-generic: uninstall-initdDATA-generic:
rm -rf $(DESTDIR)$(initddir)/$(initd_install_name) rm -f '$(DESTDIR)$(initddir)/$(initd_install_name)'
endif endif
else else
@ -527,23 +524,23 @@ systemdsystemunit_DATA = smartd.service
endif endif
smartd.service: smartd.service.in Makefile smartd.service: smartd.service.in Makefile
cat $(srcdir)/smartd.service.in | \ @echo ' $$(SMARTD_SERVICE_FILTER) < $(srcdir)/smartd.service.in > $@'
@{ \
sed 's|/usr/local/sbin/smartd|$(sbindir)/smartd|' | \ sed 's|/usr/local/sbin/smartd|$(sbindir)/smartd|' | \
if test -n '$(systemdenvfile)'; then \ if test -n '$(systemdenvfile)'; then \
sed 's|/usr/local/etc/sysconfig/smartmontools|$(systemdenvfile)|'; \ sed 's|/usr/local/etc/sysconfig/smartmontools|$(systemdenvfile)|'; \
else \ else \
sed -e '/^EnvironmentFile=/d' -e 's| *\$$smartd[_a-z]* *||g'; \ sed -e '/^EnvironmentFile=/d' -e 's| *\$$smartd[_a-z]* *||g'; \
fi > $@ fi; } < $(srcdir)/smartd.service.in > $@
# Create empty directories if configured. # Create empty directories if configured.
# Default install rules no longer create empty directories since automake 1.11. # Default install rules no longer create empty directories since automake 1.11.
# Uses $(mkinstalldirs) instead of $(MKDIR_P) to preserve support for automake 1.7 - 1.9.
installdirs-local: installdirs-local:
@for d in '$(smartdplugindir)' '$(savestatesdir)' '$(attributelogdir)'; do \ @for d in '$(smartdplugindir)' '$(savestatesdir)' '$(attributelogdir)'; do \
test -n "$$d" || continue; \ test -n "$$d" || continue; \
echo "$(mkinstalldirs) $(DESTDIR)$$d"; \ echo " $(MKDIR_P) '$(DESTDIR)$$d'"; \
$(mkinstalldirs) "$(DESTDIR)$$d" || exit 1; \ $(MKDIR_P) "$(DESTDIR)$$d" || exit 1; \
done done
install-data-local: installdirs-local install-data-local: installdirs-local
@ -551,37 +548,12 @@ install-data-local: installdirs-local
# #
# Build man pages # Build man pages
# #
if ENABLE_CAPABILITIES MAN_FILTER = { \
MAN_CAPABILITIES = cat
else
MAN_CAPABILITIES = sed '/^\.\\" %IF ENABLE_CAPABILITIES/,/^\.\\" %ENDIF ENABLE_CAPABILITIES/ s,^,.\\"\# ,'
endif
if ENABLE_DRIVEDB
MAN_DRIVEDB = sed "s|/usr/local/share/smartmontools/drivedb\\.h|$(drivedbdir)/drivedb.h|g"
else
MAN_DRIVEDB = sed '/^\.\\" %IF ENABLE_DRIVEDB/,/^\.\\" %ENDIF ENABLE_DRIVEDB/ s,^,.\\"\# ,'
endif
if ENABLE_SAVESTATES
MAN_SAVESTATES = sed "s|/usr/local/var/lib/smartmontools/smartd\\.|$(savestates)|g"
else
MAN_SAVESTATES = sed '/^\.\\" %IF ENABLE_SAVESTATES/,/^\.\\" %ENDIF ENABLE_SAVESTATES/ s,^,.\\"\# ,'
endif
if ENABLE_ATTRIBUTELOG
MAN_ATTRIBUTELOG = sed "s|/usr/local/var/lib/smartmontools/attrlog\\.|$(attributelog)|g"
else
MAN_ATTRIBUTELOG = sed '/^\.\\" %IF ENABLE_ATTRIBUTELOG/,/^\.\\" %ENDIF ENABLE_ATTRIBUTELOG/ s,^,.\\"\# ,'
endif
MAN_FILTER = \
sed -e 's|CURRENT_SVN_VERSION|$(releaseversion)|g' \ sed -e 's|CURRENT_SVN_VERSION|$(releaseversion)|g' \
-e "s|CURRENT_SVN_DATE|`sed -n 's,^.*DATE[^"]*"\([^"]*\)".*$$,\1,p' svnversion.h`|g" \ -e "s|CURRENT_SVN_DATE|`sed -n 's,^.*DATE[^"]*"\([^"]*\)".*$$,\1,p' svnversion.h`|g" \
-e "s|CURRENT_SVN_REV|`sed -n 's,^.*REV[^"]*"\([^"]*\)".*$$,r\1,p' svnversion.h`|g" \ -e "s|CURRENT_SVN_REV|`sed -n 's,^.*REV[^"]*"\([^"]*\)".*$$,r\1,p' svnversion.h`|g" \
-e 's|/usr/local/share/man/|$(mandir)/|g' \ -e 's|/usr/local/share/man/|$(mandir)/|g' \
-e 's|/usr/local/sbin/|$(sbindir)/|g' \ -e 's|/usr/local/sbin/|$(sbindir)/|g' \
-e 's|/usr/local/etc/rc\.d/init.d/|$(initddir)/|g' \
-e 's|/usr/local/share/doc/smartmontools/examplescripts/|!exampledir!|g' \ -e 's|/usr/local/share/doc/smartmontools/examplescripts/|!exampledir!|g' \
-e 's|/usr/local/share/doc/smartmontools/|$(docsdir)/|g' \ -e 's|/usr/local/share/doc/smartmontools/|$(docsdir)/|g' \
-e 's|!exampledir!|$(exampledir)/|g' \ -e 's|!exampledir!|$(exampledir)/|g' \
@ -591,16 +563,47 @@ MAN_FILTER = \
-e 's|\\fBmail\\fP|\\fB$(os_mailer)\\fP|g' \ -e 's|\\fBmail\\fP|\\fB$(os_mailer)\\fP|g' \
-e 's|\\'\''mail\\'\''|\\'\''$(os_mailer)\\'\''|g' \ -e 's|\\'\''mail\\'\''|\\'\''$(os_mailer)\\'\''|g' \
-e 's|/usr/bin/mail|/usr/bin/$(os_mailer)|g' \ -e 's|/usr/bin/mail|/usr/bin/$(os_mailer)|g' \
-e 's|RELEASE_6_0_DRIVEDB|@DRIVEDB_BRANCH@|g' | \ -e 's|RELEASE_6_0_DRIVEDB|$(DRIVEDB_BRANCH)|g' | \
if test -n '$(drivedbdir)'; then \
sed 's|/usr/local/share/smartmontools/drivedb\.h|$(drivedbdir)/drivedb.h|g' ; \
else \
sed '/^\.\\" %IF ENABLE_DRIVEDB/,/^\.\\" %ENDIF ENABLE_DRIVEDB/ s,^,.\\"\# ,' ; \
fi | \
if test '$(with_update_smart_drivedb)' = 'yes'; then \
cat; \
else \
sed '/^\.\\" %IF ENABLE_UPDATE_SMART_DRIVEDB/,/^\.\\" %ENDIF ENABLE_UPDATE_SMART_DRIVEDB/ s,^,.\\"\# ,' ; \
fi | \
if test -n '$(initddir)'; then \
sed 's|/usr/local/etc/rc\.d/init\.d/|$(initddir)/|g' ; \
else \
sed '/^\.\\" %IF ENABLE_INITSCRIPT/,/^\.\\" %ENDIF ENABLE_INITSCRIPT/ s,^,.\\"\# ,' ; \
fi | \
if test -n '$(savestates)'; then \
sed 's|/usr/local/var/lib/smartmontools/smartd\.|$(savestates)|g' ; \
else \
sed '/^\.\\" %IF ENABLE_SAVESTATES/,/^\.\\" %ENDIF ENABLE_SAVESTATES/ s,^,.\\"\# ,' ; \
fi | \
if test -n '$(attributelog)'; then \
sed 's|/usr/local/var/lib/smartmontools/attrlog\.|$(attributelog)|g' ; \
else \
sed '/^\.\\" %IF ENABLE_ATTRIBUTELOG/,/^\.\\" %ENDIF ENABLE_ATTRIBUTELOG/ s,^,.\\"\# ,' ; \
fi | \
if test -n '$(smartdplugindir)'; then \ if test -n '$(smartdplugindir)'; then \
sed 's|/usr/local/etc/smartd_warning\.d|$(smartdplugindir)|g' ; \ sed 's|/usr/local/etc/smartd_warning\.d|$(smartdplugindir)|g' ; \
else \ else \
sed '/^\.\\" %IF ENABLE_SMARTDPLUGINDIR/,/^\.\\" %ENDIF ENABLE_SMARTDPLUGINDIR/ s,^,.\\"\# ,' ; \ sed '/^\.\\" %IF ENABLE_SMARTDPLUGINDIR/,/^\.\\" %ENDIF ENABLE_SMARTDPLUGINDIR/ s,^,.\\"\# ,' ; \
fi | \ fi | \
$(MAN_ATTRIBUTELOG) | \ if test -n '$(CAPNG_LDADD)'; then \
$(MAN_CAPABILITIES) | \ cat; \
$(MAN_DRIVEDB) | \ else \
$(MAN_SAVESTATES) | \ sed '/^\.\\" %IF ENABLE_CAPABILITIES/,/^\.\\" %ENDIF ENABLE_CAPABILITIES/ s,^,.\\"\# ,' ; \
fi | \
if test '$(with_nvme_devicescan)' = 'yes'; then \
cat; \
else \
sed '/^\.\\" %IF ENABLE_NVME_DEVICESCAN/,/^\.\\" %ENDIF ENABLE_NVME_DEVICESCAN/ s,^,.\\"\# ,' ; \
fi | \
if test -n '$(os_man_filter)'; then \ if test -n '$(os_man_filter)'; then \
sed -e 's,OS_MAN_FILTER,$(os_man_filter),g' \ sed -e 's,OS_MAN_FILTER,$(os_man_filter),g' \
-e '/^\.\\" %IF NOT OS .*$(os_man_filter)/,/^.\\" %ENDIF NOT OS .*$(os_man_filter)/ s,^,.\\"\# ,' \ -e '/^\.\\" %IF NOT OS .*$(os_man_filter)/,/^.\\" %ENDIF NOT OS .*$(os_man_filter)/ s,^,.\\"\# ,' \
@ -611,24 +614,24 @@ MAN_FILTER = \
-e 's,^!!!*,,' ; \ -e 's,^!!!*,,' ; \
else \ else \
cat; \ cat; \
fi fi; }
# Implicit rule 'smart%: smart%.in ...' does not work with BSD make # Implicit rule 'smart%: smart%.in ...' does not work with BSD make
smartctl.8: smartctl.8.in Makefile svnversion.h smartctl.8: smartctl.8.in Makefile svnversion.h
@echo ' cat $(srcdir)/smartctl.8.in | $$(MAN_FILTER) > $@' @echo ' $$(MAN_FILTER) < $(srcdir)/smartctl.8.in > $@'
@cat $(srcdir)/smartctl.8.in | $(MAN_FILTER) > $@ @$(MAN_FILTER) < $(srcdir)/smartctl.8.in > $@
smartd.8: smartd.8.in Makefile svnversion.h smartd.8: smartd.8.in Makefile svnversion.h
@echo ' cat $(srcdir)/smartd.8.in | $$(MAN_FILTER) > $@' @echo ' $$(MAN_FILTER) < $(srcdir)/smartd.8.in > $@'
@cat $(srcdir)/smartd.8.in | $(MAN_FILTER) > $@ @$(MAN_FILTER) < $(srcdir)/smartd.8.in > $@
smartd.conf.5: smartd.conf.5.in Makefile svnversion.h smartd.conf.5: smartd.conf.5.in Makefile svnversion.h
@echo ' cat $(srcdir)/smartd.conf.5.in | $$(MAN_FILTER) > $@' @echo ' $$(MAN_FILTER) < $(srcdir)/smartd.conf.5.in > $@'
@cat $(srcdir)/smartd.conf.5.in | $(MAN_FILTER) > $@ @$(MAN_FILTER) < $(srcdir)/smartd.conf.5.in > $@
update-smart-drivedb.8: update-smart-drivedb.8.in Makefile svnversion.h update-smart-drivedb.8: update-smart-drivedb.8.in Makefile svnversion.h
@echo ' cat $(srcdir)/update-smart-drivedb.8.in | $$(MAN_FILTER) > $@' @echo ' $$(MAN_FILTER) < $(srcdir)/update-smart-drivedb.8.in > $@'
@cat $(srcdir)/update-smart-drivedb.8.in | $(MAN_FILTER) > $@ @$(MAN_FILTER) < $(srcdir)/update-smart-drivedb.8.in > $@
# Build Solaris specific man pages # Build Solaris specific man pages
SOLARIS_MAN_FILTER = \ SOLARIS_MAN_FILTER = \
@ -639,20 +642,20 @@ SOLARIS_MAN_FILTER = \
-e 's,/var/log/messages,/var/adm/messages,g' -e 's,/var/log/messages,/var/adm/messages,g'
smartctl.1m: smartctl.8 smartctl.1m: smartctl.8
@echo ' cat smartctl.8 | $$(SOLARIS_MAN_FILTER) > $@' @echo ' $$(SOLARIS_MAN_FILTER) < smartctl.8 > $@'
@cat smartctl.8 | $(SOLARIS_MAN_FILTER) > $@ @$(SOLARIS_MAN_FILTER) < smartctl.8 > $@
smartd.1m: smartd.8 smartd.1m: smartd.8
@echo ' cat smartd.8 | $$(SOLARIS_MAN_FILTER) > $@' @echo ' $$(SOLARIS_MAN_FILTER) < smartd.8 > $@'
@cat smartd.8 | $(SOLARIS_MAN_FILTER) > $@ @$(SOLARIS_MAN_FILTER) < smartd.8 > $@
smartd.conf.4: smartd.conf.5 smartd.conf.4: smartd.conf.5
@echo ' cat smartd.conf.5 | $$(SOLARIS_MAN_FILTER) > $@' @echo ' $$(SOLARIS_MAN_FILTER) < smartd.conf.5 > $@'
@cat smartd.conf.5 | $(SOLARIS_MAN_FILTER) > $@ @$(SOLARIS_MAN_FILTER) < smartd.conf.5 > $@
update-smart-drivedb.1m: update-smart-drivedb.8 update-smart-drivedb.1m: update-smart-drivedb.8
@echo ' cat update-smart-drivedb.8 | $$(SOLARIS_MAN_FILTER) > $@' @echo ' $$(SOLARIS_MAN_FILTER) < update-smart-drivedb.8 > $@'
@cat update-smart-drivedb.8 | $(SOLARIS_MAN_FILTER) > $@ @$(SOLARIS_MAN_FILTER) < update-smart-drivedb.8 > $@
# Commands to convert man pages into .html and .txt # Commands to convert man pages into .html and .txt
@ -674,21 +677,15 @@ htmlman: smartctl.8.html smartd.8.html smartd.conf.5.html
txtman: smartctl.8.txt smartd.8.txt smartd.conf.5.txt txtman: smartctl.8.txt smartd.8.txt smartd.conf.5.txt
if OS_WIN32_MINGW
%.5.html: %.5 %.5.html: %.5
$(DOS2UNIX) < $< | $(MAN2HTML) | $(FIXHTML) > $@ $(MAN2HTML) $< > $@.tmp
@echo ' $$(FIXHTML) < $@.tmp > $@'
@$(FIXHTML) < $@.tmp > $@
%.8.html: %.8 %.8.html: %.8
$(DOS2UNIX) < $< | $(MAN2HTML) | $(FIXHTML) > $@ $(MAN2HTML) $< > $@.tmp
else @echo ' $$(FIXHTML) < $@.tmp > $@'
@$(FIXHTML) < $@.tmp > $@
%.5.html: %.5
$(MAN2HTML) $< | $(FIXHTML) > $@
%.8.html: %.8
$(MAN2HTML) $< | $(FIXHTML) > $@
endif
%.5.txt: %.5 %.5.txt: %.5
$(MAN2TXT) $< > $@ $(MAN2TXT) $< > $@
@ -716,22 +713,35 @@ smartd_res.o: smartd_res.rc syslogevt.rc
$(WINDRES) -I. $< $@ $(WINDRES) -I. $< $@
# Convert version for VERSIONINFO resource: 6.1 r3754 -> 6.1.0.3754, set Copyright year # Convert version for VERSIONINFO resource: 6.1 r3754 -> 6.1.0.3754, set Copyright year
WIN_RC_FILTER = \ WIN_RC_FILTER = { \
( ver=`echo '$(PACKAGE_VERSION).0' | sed -n 's,^\([0-9]*\.[0-9]*\.[0-9]*\).*$$,\1,p'`; \ ver=`echo '$(PACKAGE_VERSION).0' | sed -n 's,^\([0-9]*\.[0-9]*\.[0-9]*\).*$$,\1,p'` && \
rev=`sed -n 's,^.*REV[^"]*"\([0-9]*\).*$$,\1,p' svnversion.h`; \ rev=`sed -n 's,^.*REV[^"]*"\([0-9]*\).*$$,\1,p' svnversion.h` && \
txtver="$${ver:-0.0.0}.$${rev:-0}"; binver=`echo "$$txtver" | sed 's|\.|,|g'`; \ txtver="$${ver:-0.0.0}.$${rev:-0}" && binver=`echo "$$txtver" | sed 's|\.|,|g'` && \
yy=`sed -n 's,^.*DATE[^"]*"20\([0-9][0-9]\).*$$,\1,p' svnversion.h`; yy="$${yy:-XX}"; \ yy=`sed -n 's,^.*DATE[^"]*"20\([0-9][0-9]\).*$$,\1,p' svnversion.h` && yy="$${yy:-XX}" && \
sed -e "s|@BINARY_VERSION@|$$binver|g" -e "s|@TEXT_VERSION@|$$txtver|g" -e "s|@YY@|$$yy|g"; ) sed -e "s|@BINARY_VERSION@|$$binver|g" -e "s|@TEXT_VERSION@|$$txtver|g" -e "s|@YY@|$$yy|g"; }
smartctl_res.rc: os_win32/smartctl_res.rc.in Makefile svnversion.h smartctl_res.rc: os_win32/smartctl_res.rc.in Makefile svnversion.h
cat $< | $(WIN_RC_FILTER) > $@ @echo ' $$(WIN_RC_FILTER) < $< > $@'
@$(WIN_RC_FILTER) < $< > $@
smartd_res.rc: os_win32/smartd_res.rc.in Makefile svnversion.h smartd_res.rc: os_win32/smartd_res.rc.in Makefile svnversion.h
cat $< | $(WIN_RC_FILTER) > $@ @echo ' $$(WIN_RC_FILTER) < $< > $@'
@$(WIN_RC_FILTER) < $< > $@
syslogevt.rc: os_win32/syslogevt.mc syslogevt.rc: os_win32/syslogevt.mc
$(WINDMC) -b $< $(WINDMC) -b $<
# Application manifests
default.manifest.o: os_win32/default.manifest
echo '1 24 "$<"' | $(WINDRES) -J rc -o $@
defadmin.manifest.o: defadmin.manifest
echo '1 24 "$<"' | $(WINDRES) -J rc -o $@
defadmin.manifest: os_win32/default.manifest
sed 's,"asInvoker","requireAdministrator",' $< > $@
# Definitions for Windows distribution # Definitions for Windows distribution
if OS_WIN64 if OS_WIN64
@ -773,7 +783,6 @@ FILES_WIN32 = \
$(docdir_win32)/NEWS.txt \ $(docdir_win32)/NEWS.txt \
$(docdir_win32)/README.txt \ $(docdir_win32)/README.txt \
$(docdir_win32)/TODO.txt \ $(docdir_win32)/TODO.txt \
$(docdir_win32)/WARNINGS.txt \
$(docdir_win32)/checksums$(win_bits).txt \ $(docdir_win32)/checksums$(win_bits).txt \
$(docdir_win32)/smartd.conf \ $(docdir_win32)/smartd.conf \
$(docdir_win32)/smartctl.8.html \ $(docdir_win32)/smartctl.8.html \
@ -781,9 +790,7 @@ FILES_WIN32 = \
$(docdir_win32)/smartd.8.html \ $(docdir_win32)/smartd.8.html \
$(docdir_win32)/smartd.8.txt \ $(docdir_win32)/smartd.8.txt \
$(docdir_win32)/smartd.conf.5.html \ $(docdir_win32)/smartd.conf.5.html \
$(docdir_win32)/smartd.conf.5.txt \ $(docdir_win32)/smartd.conf.5.txt
$(exedir_win32)/runcmda.exe.manifest \
$(exedir_win32)/runcmdu.exe.manifest
if ENABLE_DRIVEDB if ENABLE_DRIVEDB
FILES_WIN32 += \ FILES_WIN32 += \
@ -792,20 +799,18 @@ endif
CLEANFILES += \ CLEANFILES += \
$(FILES_WIN32) \ $(FILES_WIN32) \
runcmdu.exe \ defadmin.manifest \
distdir.mkdir \
runcmda.exe runcmdu.exe \
smartctl-nc.exe smartctl-nc.exe.tmp \ smartctl-nc.exe smartctl-nc.exe.tmp \
smartctl_res.rc smartctl_res.o \ smartctl_res.rc smartd_res.rc \
smartd_res.rc smartd_res.o \ syslogevt.h \
syslogevt.h syslogevt.o \
syslogevt.rc syslogevt_*.bin \ syslogevt.rc syslogevt_*.bin \
wtssendmsg.exe \
update-smart-drivedb.exe \ update-smart-drivedb.exe \
distdir.mkdir wtssendmsg.exe
# Textfile converter from package cygutils or tofrodos # Note: Only use without options to be compatible with all variants
# Note: Only use without options to be compatible with both packages
UNIX2DOS = unix2dos UNIX2DOS = unix2dos
DOS2UNIX = dos2unix
# Build Windows distribution # Build Windows distribution
@ -830,11 +835,11 @@ if OS_WIN32_NSIS
# Note: Only option character '-' is also compatible with Linux version of makensis # Note: Only option character '-' is also compatible with Linux version of makensis
$(distinst_win32): os_win32/installer.nsi distdir.mkdir $(FILES_WIN32) $(distinst_win32): os_win32/installer.nsi distdir.mkdir $(FILES_WIN32)
test -z '$(builddir_win64)' || ( cd $(builddir_win64) && make distdir-win32 ) test -z '$(builddir_win64)' || ( cd $(builddir_win64) && make distdir-win32 )
@date=`sed -n 's,^.*DATE[^"]*"\([^"]*\)".*$$,\1,p' svnversion.h`; \ @date=`sed -n 's,^.*DATE[^"]*"\([^"]*\)".*$$,\1,p' svnversion.h` && \
rev=`sed -n 's,^.*REV[^"]*"\([^"]*\)".*$$,r\1,p' svnversion.h`; \ rev=`sed -n 's,^.*REV[^"]*"\([^"]*\)".*$$,r\1,p' svnversion.h` && \
verstr="$(PACKAGE_VERSION) $$date $$rev "$(BUILD_INFO); \ verstr="$(PACKAGE_VERSION) $$date $$rev "$(BUILD_INFO) && \
d64=; test -z '$(builddir_win64)' || d64='-DINPDIR64=$(builddir_win64)/$(PACKAGE)-$(VERSION).win64'; \ d64= && if [ -n '$(builddir_win64)' ]; then d64='-DINPDIR64=$(builddir_win64)/$(PACKAGE)-$(VERSION).win64'; fi && \
echo "'$(MAKENSIS)' -V2 -NOCD -DINPDIR=$(distdir_win32) $$d64 -DOUTFILE=$@ -DVERSTR='$$verstr' $<"; \ echo "'$(MAKENSIS)' -V2 -NOCD -DINPDIR=$(distdir_win32) $$d64 -DOUTFILE=$@ -DVERSTR='$$verstr' $<" && \
'$(MAKENSIS)' -V2 -NOCD -DINPDIR=$(distdir_win32) $$d64 -DOUTFILE=$@ -DVERSTR="$$verstr" $< '$(MAKENSIS)' -V2 -NOCD -DINPDIR=$(distdir_win32) $$d64 -DOUTFILE=$@ -DVERSTR="$$verstr" $<
md5sum $@ > $@.md5 md5sum $@ > $@.md5
sha1sum $@ > $@.sha1 sha1sum $@ > $@.sha1
@ -867,18 +872,10 @@ $(exedir_win32)/%.exe: %.exe
$(exedir_win32)/update-smart-drivedb.exe: update-smart-drivedb.exe $(exedir_win32)/update-smart-drivedb.exe: update-smart-drivedb.exe
cp -p $< $@ cp -p $< $@
# runcmd?.exe only differ by .exe.manifest files
$(exedir_win32)/runcmda.exe: $(exedir_win32)/runcmdu.exe
cp -p $< $@
$(exedir_win32)/%.h: $(srcdir)/%.h $(exedir_win32)/%.h: $(srcdir)/%.h
$(UNIX2DOS) < $< > $@ $(UNIX2DOS) < $< > $@
touch -r $< $@ touch -r $< $@
$(exedir_win32)/%.exe.manifest: $(srcdir)/os_win32/%.exe.manifest
$(UNIX2DOS) < $< > $@
touch -r $< $@
$(exedir_win32)/%.cmd: $(srcdir)/os_win32/%.cmd $(exedir_win32)/%.cmd: $(srcdir)/os_win32/%.cmd
$(UNIX2DOS) < $< > $@ $(UNIX2DOS) < $< > $@
touch -r $< $@ touch -r $< $@
@ -920,11 +917,17 @@ smartctl-nc.exe: smartctl.exe
mv -f $@.tmp $@ mv -f $@.tmp $@
# Build runcmd?.exe and wtssendmsg.exe # Build runcmd?.exe and wtssendmsg.exe
runcmdu.exe: os_win32/runcmd.c runcmd.o: os_win32/runcmd.c
$(CC) -Os -o $@ $< $(CC) -c -Os $<
wtssendmsg.exe: os_win32/wtssendmsg.c runcmdu.exe: runcmd.o $(os_win32_manifest)
$(CC) -Os -o $@ $< -lwtsapi32 $(CC) -o $@ $^
runcmda.exe: runcmd.o defadmin.manifest.o
$(CC) -o $@ $^
wtssendmsg.exe: os_win32/wtssendmsg.c $(os_win32_manifest)
$(CC) -Os -o $@ $< $(os_win32_manifest) -lwtsapi32
# Build os_win32/vc10/{config.h,smart*.rc,svnversion.h} for MSVC10 from MinGW files # Build os_win32/vc10/{config.h,smart*.rc,svnversion.h} for MSVC10 from MinGW files
@ -948,3 +951,44 @@ $(srcdir)/os_win32/vc10/smartd_res.rc: smartd_res.rc
cp $< $@ cp $< $@
endif endif
if OS_DARWIN
# Definitions for OSX distribution
distdir_darwin = $(PACKAGE)-$(VERSION).darwin
dmg_darwin = $(PACKAGE)-$(VERSION).dmg
pkg_darwin = $(PACKAGE)-$(VERSION).pkg
# build darwin installer
$(pkg_darwin):
${MAKE} install DESTDIR=$(distdir_darwin)/root
@cp $(srcdir)/os_darwin/pkg/root/usr/local/sbin/smart-pkg-uninstall $(distdir_darwin)/root$(sbindir)
@mkdir -p $(distdir_darwin)/pkg
@( cd $(distdir_darwin)/root && find . | cpio -o --format odc --owner 0:80 | gzip -c ) > $(distdir_darwin)/pkg/Payload
PAYLOAD_FILES=`find $(distdir_darwin)/root | wc -l` &&\
PAYLOAD_SIZEKB=`du -BK -s $(distdir_darwin)/root|${AWK} '{print $$1}'|tr -d 'K'` &&\
sed -e "s|@version@|$(VERSION)|" -e "s|@files@|$${PAYLOAD_FILES}|" \
-e "s|@size@|$${PAYLOAD_SIZEKB}|" $(srcdir)/os_darwin/pkg/PackageInfo.in \
> $(distdir_darwin)/pkg/PackageInfo &&\
sed -e "s|@version@|$(VERSION)|" -e "s|@files@|$${PAYLOAD_FILES}|" -e "s|@size@|$${PAYLOAD_SIZEKB}|" \
-e "s|@pkgname@|$(pkg_darwin)|" \
$(srcdir)/os_darwin/pkg/Distribution.in > $(distdir_darwin)/pkg/Distribution
@mkdir -p $(distdir_darwin)/pkg/Resources/English.lproj
@cp $(srcdir)/COPYING $(distdir_darwin)/pkg/Resources/English.lproj/license.txt
@mkbom -u 0 -g 80 $(distdir_darwin)/root $(distdir_darwin)/pkg/Bom
@mkdir -p $(distdir_darwin)/dmg
@( cd $(distdir_darwin)/pkg && xar --compression none -cf "../dmg/$(pkg_darwin)" * )
# build darwon dmg image
$(dmg_darwin):
@cp $(srcdir)/os_darwin/pkg/installer/README.html $(distdir_darwin)/dmg
@mkisofs -V 'smartmontools' -no-pad -r -apple -o $(distdir_darwin)/smartmontools-$(VERSION).iso \
-hfs-bless "$(distdir_darwin)/dmg/" "$(distdir_darwin)/dmg/"
@dmg dmg $(distdir_darwin)/smartmontools-$(VERSION).iso $(dmg_darwin)
md5sum $@ > $@.md5
sha1sum $@ > $@.sha1
sha256sum $@ > $@.sha256
install-darwin: install-darwin-cleanup $(pkg_darwin) $(dmg_darwin)
install-darwin-cleanup:
@rm -rf $(distdir_darwin)
endif

75
NEWS
View File

@ -1,11 +1,82 @@
smartmontools NEWS smartmontools NEWS
------------------ ------------------
$Id: NEWS 3979 2014-08-15 11:09:41Z samm2 $ $Id: NEWS 4318 2016-05-07 11:18:20Z chrfranke $
The most up-to-date version of this file is: The most up-to-date version of this file is:
http://sourceforge.net/p/smartmontools/code/HEAD/tree/trunk/smartmontools/NEWS http://sourceforge.net/p/smartmontools/code/HEAD/tree/trunk/smartmontools/NEWS
- darwin: '-S' command implemented, '-l devstat' should work now Date 2016-05-07
Summary: smartmontools release 6.5
-----------------------------------------------------------
- Experimental support for NVMe devices on FreeBSD, Linux and Windows.
- smartctl '-i', '-c', '-H' and '-l error': NVMe support.
- smartctl '-l nvmelog': New option for NVMe.
- smartd.conf '-H', '-l error' and '-W': NVMe support.
- Optional NVMe device scanning support on Linux and Windows.
- configure option '--with-nvme-devicescan' to include NVMe in
default device scanning result.
- Device scanning now allows to specify multiple '-d TYPE' options.
- ATA: Added new POWER MODE values introduced in ATA ACS-2.
- ATA: SCT commands are no longer issued if ATA Security is locked.
- SCSI: LB provisioning improvements.
- SCSI: Fixed GLTSD bit set/cleared info messages.
- SCSI: Solid State media log page is no longer checked for tapes.
- SCSI: Improved handling when no tape cartridge in drive.
- SCSI: Workaround for buggy Seagate firmware.
- SAT: Improved heuristics to detect bogus sense data from SAT layer.
- smartd: Fixed crash on missing argument to '-s' directive.
- update-smart-drivedb: Now uses HTTPS for download by default.
- update-smart-drivedb: New options to select URL and download tool.
- update-smart-drivedb: New download tool 'svn'.
- configure option '--without-update-smart-drivedb' to disable
update-smart-drivedb script.
- configure options '--disable-drivedb', '--enable-savestates',
'--enable-attributelog' and '--with-docdir' are no longer supported.
- autoconf < 2.60 and automake < 1.10 are no longer supported.
- Drive database file now also includes the DEFAULT setting
for each attribute.
- HDD, SSD and USB additions to drive database.
- Darwin: New support files for package installer.
New makefile target 'install-darwin' builds DMG image.
- Solaris: Auto detection of SATA devices behind SAT layer.
- Solaris SPARC: Legacy ATA support disabled by default.
New configure option '--with-solaris-sparc-ata' enables it.
File os_solaris_ata.s is no longer included in source tarball.
- Windows: Auto detection of USB devices specified by drive letter.
- Windows: Device scanning does no longer ignore unknown USB devices.
- Windows: Prevent drive spin up by '-n standby' check.
- Windows: New application manifests indicating Win 10 support.
- Windows smartd: '-m [sys]msgbox' is no longer supported.
- Windows installer: Defaults to 64-bit version on 64-bit Windows.
- Various code changes suggested by Clang Static Analyser and Cppcheck.
Date 2015-06-04
Summary: smartmontools release 6.4
-----------------------------------------------------------
- Device type '-d usbprolific' for Prolific PL2571/277x USB bridges.
- SAT: Support for ATA registers returned in fixed format sense data.
- smartctl '-i' and '--identify': ATA ACS-4 and SATA 3.2 enhancements.
- smartctl '-l xerror': Support for logs with more than 255 pages.
- smartctl '-l devstat': Prints ACS-3 DSN flags.
- smartctl '-l devstat': Read via SMART command if GP log is not
available.
- smartctl '-l scttempsts': Prints SCT SMART STATUS (ACS-4) and
vendor specific SCT bytes.
- configure option '--with-systemdenvfile=auto' as new default.
- configure options '--disable-drivedb', '--enable-savestates'
and '--enable-attributelog' are deprecated.
- Corresponding '--with-*' options are enhanced accordingly.
- Configure option '--with-docdir' is deprecated.
- autoconf < 2.60 and automake < 1.10 are deprecated.
(all of the above still work but a warning is printed if used)
- HDD, SSD and USB additions to drive database.
- Linux: AACRAID fixes, SMART STATUS should work now.
- Linux: '/dev/megaraid_sas_ioctl_node' fd leak fix.
- Darwin: '-S' command implemented, '-l devstat' should work now.
- Cygwin: Compile fix.
- Windows: Device type '-d aacraid' for AACRAID controllers.
- Windows: SAT autodetection based on IOCTL_STORAGE_QUERY_PROPERTY.
- Windows installer: Fix possible loss of user PATH environment variable.
Date 2014-07-26 Date 2014-07-26
Summary: smartmontools release 6.3 Summary: smartmontools release 6.3

18
README
View File

@ -3,12 +3,12 @@ smartmontools - S.M.A.R.T. utility toolset for Darwin/Mac
OSX, FreeBSD, Linux, NetBSD, OpenBSD, Solaris, and Windows. OSX, FreeBSD, Linux, NetBSD, OpenBSD, Solaris, and Windows.
========================================================== ==========================================================
$Id: README 3949 2014-07-13 17:23:40Z chrfranke $ $Id: README 4120 2015-08-27 16:12:21Z samm2 $
== HOME == == HOME ==
The home for smartmontools is located at: The home for smartmontools is located at:
http://smartmontools.sourceforge.net/ http://www.smartmontools.org/
Please see this web site for updates, documentation, and for submitting Please see this web site for updates, documentation, and for submitting
patches and bug reports. patches and bug reports.
@ -19,8 +19,8 @@ You will find a mailing list for support and other questions at:
== COPYING == == COPYING ==
Copyright (C) 2002-9 Bruce Allen <smartmontools-support@lists.sourceforge.net> Copyright (C) 2002-9 Bruce Allen
Copyright (C) 2004-14 Christian Franke <smartmontools-support@lists.sourceforge.net> Copyright (C) 2004-15 Christian Franke
This program is free software; you can redistribute it and/or modify it 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 under the terms of the GNU General Public License as published by the Free
@ -32,10 +32,7 @@ example COPYING). If not, see <http://www.gnu.org/licenses/>.
== CREDITS == == CREDITS ==
This code was originally developed as a Senior Thesis by Michael Cornwell See AUTHORS file.
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/
== OVERVIEW == == OVERVIEW ==
@ -85,11 +82,8 @@ Refer to the "INSTALL" file for detailed installation instructions.
== GETTING STARTED == == GETTING STARTED ==
To examine SMART data from a disk, try: To examine SMART data from a disk, try:
smartctl -a /dev/hda
for ATA disks, or
smartctl -a /dev/sda smartctl -a /dev/sda
for SCSI disks. See the manual page 'man smartctl' for more See the manual page 'man smartctl' for more information.
information.
To start automatic monitoring of your disks with the smartd daemon, To start automatic monitoring of your disks with the smartd daemon,
try: try:

View File

@ -1,4 +0,0 @@
$Id: WARNINGS 3904 2014-06-15 14:21:15Z chrfranke $
This file is no longer maintained, please see:
http://www.smartmontools.org/wiki/Warnings

View File

@ -1,5 +1,6 @@
/* aacraid.h /* aacraid.h
* Copyright (C) 2014 Raghava Aditya <Raghava.Aditya@pmcs.com> * Copyright (C) 2014 Raghava Aditya <Raghava.Aditya@pmcs.com>
* Copyright (C) 2015 Nidhi Malhotra <Nidhi.Malhotra@pmcs.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -12,8 +13,8 @@
*/ */
// Check windows // Check windows
#if _WIN32 || _WIN64 #if defined(_WIN32) || defined(_WIN64)
#if _WIN64 #ifdef _WIN64
#define ENVIRONMENT64 #define ENVIRONMENT64
#else #else
#define ENVIRONMENT32 #define ENVIRONMENT32
@ -32,10 +33,18 @@
#define METHOD_BUFFERED 0 #define METHOD_BUFFERED 0
#define METHOD_NEITHER 3 #define METHOD_NEITHER 3
#if defined(_WIN32) || defined(_WIN64)
#define FSAMPCTL_SCSI_BASE IOCTL_SCSI_BASE
#define ARCIOCTL_SEND_RAW_SRB CTL_CODE(FSAMPCTL_SCSI_BASE, 2201, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define AACRAID_SAS_SIGNATURE "ARCSAS"
#define SRB_FLAGS_DATA_IN 0x00000040
#define SRB_FLAGS_DATA_OUT 0x00000080
#define SRB_FLAGS_NO_DATA_TRANSFER 0x00000000
#else
#define CTL_CODE(function, method) ((4<< 16) | ((function) << 2) | (method) ) #define CTL_CODE(function, method) ((4<< 16) | ((function) << 2) | (method) )
#define FSACTL_SEND_RAW_SRB CTL_CODE(2067, METHOD_BUFFERED) #define FSACTL_SEND_RAW_SRB CTL_CODE(2067, METHOD_BUFFERED)
#endif
#define SRB_FUNCTION_EXECUTE_SCSI 0X00 #define SRB_FUNCTION_EXECUTE_SCSI 0X00
#define SRB_DataIn 0x0040 #define SRB_DataIn 0x0040
@ -67,6 +76,45 @@ typedef struct {
user_sgentry32 sg32[1]; user_sgentry32 sg32[1];
} user_sgmap32; } user_sgmap32;
#if defined(_WIN32) || defined(_WIN64)
typedef struct _SCSI_REQUEST_BLOCK {
USHORT Length; // offset 0
UCHAR Function; // offset 2
UCHAR SrbStatus; // offset 3
UCHAR ScsiStatus; // offset 4
UCHAR PathId; // offset 5
UCHAR TargetId; // offset 6
UCHAR Lun; // offset 7
UCHAR QueueTag; // offset 8
UCHAR QueueAction; // offset 9
UCHAR CdbLength; // offset a
UCHAR SenseInfoBufferLength; // offset b
ULONG SrbFlags; // offset c
ULONG DataTransferLength; // offset 10
ULONG TimeOutValue; // offset 14
PVOID DataBuffer; // offset 18
PVOID SenseInfoBuffer; // offset 1c
struct _SCSI_REQUEST_BLOCK *NextSrb; // offset 20
PVOID OriginalRequest; // offset 24
PVOID SrbExtension; // offset 28
union {
ULONG InternalStatus; // offset 2c
ULONG QueueSortKey; // offset 2c
};
#if defined(_WIN64)
//
// Force PVOID alignment of Cdb
//
ULONG Reserved;
#endif
UCHAR Cdb[16]; // offset 30
} SCSI_REQUEST_BLOCK, *PSCSI_REQUEST_BLOCK;
#define SCSI_REQUEST_BLOCK_SIZE sizeof(SCSI_REQUEST_BLOCK)
#else
typedef struct { typedef struct {
uint32_t function; //SRB_FUNCTION_EXECUTE_SCSI 0x00 uint32_t function; //SRB_FUNCTION_EXECUTE_SCSI 0x00
uint32_t channel; //bus uint32_t channel; //bus
@ -103,3 +151,4 @@ typedef struct {
uint32_t sense_data_size; uint32_t sense_data_size;
uint8_t sense_data[30]; uint8_t sense_data[30];
} user_aac_reply; } user_aac_reply;
#endif

View File

@ -1,7 +1,7 @@
/* /*
* atacmdnames.cpp * atacmdnames.cpp
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2003-8 Philip Williams * Copyright (C) 2003-8 Philip Williams
* Copyright (C) 2012 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2012 Christian Franke <smartmontools-support@lists.sourceforge.net>
@ -20,7 +20,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
const char * atacmdnames_cpp_cvsid = "$Id: atacmdnames.cpp 3670 2012-10-31 22:00:50Z chrfranke $" const char * atacmdnames_cpp_cvsid = "$Id: atacmdnames.cpp 4120 2015-08-27 16:12:21Z samm2 $"
ATACMDNAMES_H_CVSID; ATACMDNAMES_H_CVSID;
const char cmd_reserved[] = "[RESERVED]"; const char cmd_reserved[] = "[RESERVED]";

View File

@ -4,7 +4,7 @@
* This module is based on the T13/1532D Volume 1 Revision 3 (ATA/ATAPI-7) * This module is based on the T13/1532D Volume 1 Revision 3 (ATA/ATAPI-7)
* specification, which is available from http://www.t13.org/#FTP_site * specification, which is available from http://www.t13.org/#FTP_site
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* Address of support mailing list: smartmontools-support@lists.sourceforge.net * Address of support mailing list: smartmontools-support@lists.sourceforge.net
* *
* Copyright (C) 2003-8 Philip Williams * Copyright (C) 2003-8 Philip Williams
@ -23,7 +23,7 @@
#ifndef ATACMDNAMES_H_ #ifndef ATACMDNAMES_H_
#define ATACMDNAMES_H_ #define ATACMDNAMES_H_
#define ATACMDNAMES_H_CVSID "$Id: atacmdnames.h 3728 2012-12-13 17:57:50Z chrfranke $\n" #define ATACMDNAMES_H_CVSID "$Id: atacmdnames.h 4120 2015-08-27 16:12:21Z samm2 $\n"
/* Returns the name of the command (and possibly sub-command) with the given /* Returns the name of the command (and possibly sub-command) with the given
command code and feature register values. */ command code and feature register values. */

View File

@ -1,10 +1,10 @@
/* /*
* atacmds.cpp * atacmds.cpp
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2002-11 Bruce Allen
* Copyright (C) 2008-14 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2008-15 Christian Franke
* Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org> * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
* Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org>
* *
@ -32,10 +32,11 @@
#include "config.h" #include "config.h"
#include "int64.h" #include "int64.h"
#include "atacmds.h" #include "atacmds.h"
#include "knowndrives.h" // get_default_attr_defs()
#include "utility.h" #include "utility.h"
#include "dev_ata_cmd_set.h" // for parsed_ata_device #include "dev_ata_cmd_set.h" // for parsed_ata_device
const char * atacmds_cpp_cvsid = "$Id: atacmds.cpp 3971 2014-07-23 18:57:55Z chrfranke $" const char * atacmds_cpp_cvsid = "$Id: atacmds.cpp 4301 2016-04-16 20:48:29Z chrfranke $"
ATACMDS_H_CVSID; ATACMDS_H_CVSID;
// Print ATA debug messages? // Print ATA debug messages?
@ -170,7 +171,9 @@ bool parse_attribute_def(const char * opt, ata_vendor_attr_defs & defs,
// Parse option // Parse option
int len = strlen(opt); int len = strlen(opt);
int id = 0, n1 = -1, n2 = -1; int id = 0, n1 = -1, n2 = -1;
char fmtname[32+1], attrname[32+1]; char fmtname[32+1], attrname[32+1], hddssd[3+1];
attrname[0] = hddssd[0] = 0;
if (opt[0] == 'N') { if (opt[0] == 'N') {
// "N,format[,name]" // "N,format[,name]"
if (!( sscanf(opt, "N,%32[^,]%n,%32[^,]%n", fmtname, &n1, attrname, &n2) >= 1 if (!( sscanf(opt, "N,%32[^,]%n,%32[^,]%n", fmtname, &n1, attrname, &n2) >= 1
@ -178,13 +181,16 @@ bool parse_attribute_def(const char * opt, ata_vendor_attr_defs & defs,
return false; return false;
} }
else { else {
// "id,format[+][,name]" // "id,format[+][,name[,HDD|SSD]]"
if (!( sscanf(opt, "%d,%32[^,]%n,%32[^,]%n", &id, fmtname, &n1, attrname, &n2) >= 2 int n3 = -1;
&& 1 <= id && id <= 255 && (n1 == len || n2 == len))) if (!( sscanf(opt, "%d,%32[^,]%n,%32[^,]%n,%3[DHS]%n",
&id, fmtname, &n1, attrname, &n2, hddssd, &n3) >= 2
&& 1 <= id && id <= 255
&& ( n1 == len || n2 == len
// ",HDD|SSD" for DEFAULT settings only
|| (n3 == len && priority == PRIOR_DEFAULT))))
return false; return false;
} }
if (n1 == len)
attrname[0] = 0;
unsigned flags = 0; unsigned flags = 0;
// For "-v 19[78],increasing" above // For "-v 19[78],increasing" above
@ -196,6 +202,9 @@ bool parse_attribute_def(const char * opt, ata_vendor_attr_defs & defs,
// Split "format[:byteorder]" // Split "format[:byteorder]"
char byteorder[8+1] = ""; char byteorder[8+1] = "";
if (strchr(fmtname, ':')) { if (strchr(fmtname, ':')) {
if (priority == PRIOR_DEFAULT)
// TODO: Allow Byteorder in DEFAULT entry
return false;
n1 = n2 = -1; n1 = n2 = -1;
if (!( sscanf(fmtname, "%*[^:]%n:%8[012345rvwz]%n", &n1, byteorder, &n2) >= 1 if (!( sscanf(fmtname, "%*[^:]%n:%8[012345rvwz]%n", &n1, byteorder, &n2) >= 1
&& n2 == (int)strlen(fmtname))) && n2 == (int)strlen(fmtname)))
@ -220,6 +229,16 @@ bool parse_attribute_def(const char * opt, ata_vendor_attr_defs & defs,
if (!*byteorder && (format == RAWFMT_RAW64 || format == RAWFMT_HEX64)) if (!*byteorder && (format == RAWFMT_RAW64 || format == RAWFMT_HEX64))
flags |= (ATTRFLAG_NO_NORMVAL|ATTRFLAG_NO_WORSTVAL); flags |= (ATTRFLAG_NO_NORMVAL|ATTRFLAG_NO_WORSTVAL);
// ",HDD|SSD" suffix for DEFAULT settings
if (hddssd[0]) {
if (!strcmp(hddssd, "HDD"))
flags |= ATTRFLAG_HDD_ONLY;
else if (!strcmp(hddssd, "SSD"))
flags |= ATTRFLAG_SSD_ONLY;
else
return false;
}
if (!id) { if (!id) {
// "N,format" -> set format for all entries // "N,format" -> set format for all entries
for (i = 0; i < MAX_ATTRIBUTE_NUM; i++) { for (i = 0; i < MAX_ATTRIBUTE_NUM; i++) {
@ -617,7 +636,7 @@ int smartcommandhandler(ata_device * device, smart_command_set command, int sele
// If requested, invalidate serial number before any printing is done // If requested, invalidate serial number before any printing is done
if ((command == IDENTIFY || command == PIDENTIFY) && !retval && dont_print_serial_number) if ((command == IDENTIFY || command == PIDENTIFY) && !retval && dont_print_serial_number)
invalidate_serno((ata_identify_device *)data); invalidate_serno( reinterpret_cast<ata_identify_device *>(data) );
// If reporting is enabled, say what output was produced by the command // If reporting is enabled, say what output was produced by the command
if (ata_debugmode) { if (ata_debugmode) {
@ -778,9 +797,6 @@ int ataCheckPowerMode(ata_device * device) {
if ((smartcommandhandler(device, CHECK_POWER_MODE, 0, (char *)&result))) if ((smartcommandhandler(device, CHECK_POWER_MODE, 0, (char *)&result)))
return -1; return -1;
if (result!=0 && result!=0x80 && result!=0xff)
pout("ataCheckPowerMode(): ATA CHECK POWER MODE returned unknown Sector Count Register value %02x\n", result);
return (int)result; return (int)result;
} }
@ -831,9 +847,9 @@ int ata_read_identity(ata_device * device, ata_identify_device * buf, bool fix_s
packet = true; packet = true;
} }
unsigned i;
if (fix_swapped_id) { if (fix_swapped_id) {
// Swap ID strings // Swap ID strings
unsigned i;
for (i = 0; i < sizeof(buf->serial_no)-1; i += 2) for (i = 0; i < sizeof(buf->serial_no)-1; i += 2)
swap2((char *)(buf->serial_no+i)); swap2((char *)(buf->serial_no+i));
for (i = 0; i < sizeof(buf->fw_rev)-1; i += 2) for (i = 0; i < sizeof(buf->fw_rev)-1; i += 2)
@ -851,14 +867,12 @@ int ata_read_identity(ata_device * device, ata_identify_device * buf, bool fix_s
// NetBSD kernel delivers IDENTIFY data in host byte order // NetBSD kernel delivers IDENTIFY data in host byte order
// TODO: Handle NetBSD case in os_netbsd.cpp // TODO: Handle NetBSD case in os_netbsd.cpp
if (isbigendian()){ if (isbigendian()){
// swap various capability words that are needed // swap various capability words that are needed
unsigned i;
for (i=0; i<33; i++) for (i=0; i<33; i++)
swap2((char *)(buf->words047_079+i)); swap2((char *)(buf->words047_079+i));
for (i=80; i<=87; i++) for (i=80; i<=87; i++)
swap2((char *)(rawshort+i)); swap2((char *)(rawshort+i));
for (i=0; i<168; i++) for (i=0; i<168; i++)
swap2((char *)(buf->words088_255+i)); swap2((char *)(buf->words088_255+i));
} }
@ -1466,9 +1480,9 @@ static void fix_exterrlog_lba(ata_smart_exterrlog * log, unsigned nsectors)
// Read Extended Comprehensive Error Log // Read Extended Comprehensive Error Log
bool ataReadExtErrorLog(ata_device * device, ata_smart_exterrlog * log, bool ataReadExtErrorLog(ata_device * device, ata_smart_exterrlog * log,
unsigned nsectors, firmwarebug_defs firmwarebugs) unsigned page, unsigned nsectors, firmwarebug_defs firmwarebugs)
{ {
if (!ataReadLogExt(device, 0x03, 0x00, 0, log, nsectors)) if (!ataReadLogExt(device, 0x03, 0x00, page, log, nsectors))
return false; return false;
check_multi_sector_sum(log, nsectors, "SMART Extended Comprehensive Error Log Structure"); check_multi_sector_sum(log, nsectors, "SMART Extended Comprehensive Error Log Structure");
@ -1859,35 +1873,12 @@ ata_attr_state ata_get_attr_state(const ata_smart_attribute & attr,
return ATTRSTATE_OK; return ATTRSTATE_OK;
} }
// Get default raw value print format
static ata_attr_raw_format get_default_raw_format(unsigned char id)
{
switch (id) {
case 3: // Spin-up time
return RAWFMT_RAW16_OPT_AVG16;
case 5: // Reallocated sector count
case 196: // Reallocated event count
return RAWFMT_RAW16_OPT_RAW16;
case 9: // Power on hours
case 240: // Head flying hours
return RAWFMT_RAW24_OPT_RAW8;
case 190: // Temperature
case 194:
return RAWFMT_TEMPMINMAX;
default:
return RAWFMT_RAW48;
}
}
// Get attribute raw value. // Get attribute raw value.
uint64_t ata_get_attr_raw_value(const ata_smart_attribute & attr, uint64_t ata_get_attr_raw_value(const ata_smart_attribute & attr,
const ata_vendor_attr_defs & defs) const ata_vendor_attr_defs & defs)
{ {
const ata_vendor_attr_defs::entry & def = defs[attr.id]; const ata_vendor_attr_defs::entry & def = defs[attr.id];
// TODO: Allow Byteorder in DEFAULT entry
// Use default byteorder if not specified // Use default byteorder if not specified
const char * byteorder = def.byteorder; const char * byteorder = def.byteorder;
@ -1978,8 +1969,13 @@ std::string ata_format_attr_raw_value(const ata_smart_attribute & attr,
// Get print format // Get print format
ata_attr_raw_format format = defs[attr.id].raw_format; ata_attr_raw_format format = defs[attr.id].raw_format;
if (format == RAWFMT_DEFAULT) {
// Get format from DEFAULT entry
format = get_default_attr_defs()[attr.id].raw_format;
if (format == RAWFMT_DEFAULT) if (format == RAWFMT_DEFAULT)
format = get_default_raw_format(attr.id); // Unknown Attribute
format = RAWFMT_RAW48;
}
// Print // Print
std::string s; std::string s;
@ -2158,212 +2154,23 @@ std::string ata_format_attr_raw_value(const ata_smart_attribute & attr,
return s; return s;
} }
// Attribute names shouldn't be longer than 23 chars, otherwise they break the
// output of smartctl.
static const char * get_default_attr_name(unsigned char id, int rpm)
{
bool hdd = (rpm > 1), ssd = (rpm == 1);
static const char Unknown_HDD_Attribute[] = "Unknown_HDD_Attribute";
static const char Unknown_SSD_Attribute[] = "Unknown_SSD_Attribute";
switch (id) {
case 1:
return "Raw_Read_Error_Rate";
case 2:
return "Throughput_Performance";
case 3:
return "Spin_Up_Time";
case 4:
return "Start_Stop_Count";
case 5:
return "Reallocated_Sector_Ct";
case 6:
if (ssd) return Unknown_SSD_Attribute;
return "Read_Channel_Margin";
case 7:
if (ssd) return Unknown_SSD_Attribute;
return "Seek_Error_Rate";
case 8:
if (ssd) return Unknown_SSD_Attribute;
return "Seek_Time_Performance";
case 9:
return "Power_On_Hours";
case 10:
if (ssd) return Unknown_SSD_Attribute;
return "Spin_Retry_Count";
case 11:
if (ssd) return Unknown_SSD_Attribute;
return "Calibration_Retry_Count";
case 12:
return "Power_Cycle_Count";
case 13:
return "Read_Soft_Error_Rate";
case 175:
if (hdd) return Unknown_HDD_Attribute;
return "Program_Fail_Count_Chip";
case 176:
if (hdd) return Unknown_HDD_Attribute;
return "Erase_Fail_Count_Chip";
case 177:
if (hdd) return Unknown_HDD_Attribute;
return "Wear_Leveling_Count";
case 178:
if (hdd) return Unknown_HDD_Attribute;
return "Used_Rsvd_Blk_Cnt_Chip";
case 179:
if (hdd) return Unknown_HDD_Attribute;
return "Used_Rsvd_Blk_Cnt_Tot";
case 180:
if (hdd) return Unknown_HDD_Attribute;
return "Unused_Rsvd_Blk_Cnt_Tot";
case 181:
return "Program_Fail_Cnt_Total";
case 182:
if (hdd) return Unknown_HDD_Attribute;
return "Erase_Fail_Count_Total";
case 183:
return "Runtime_Bad_Block";
case 184:
return "End-to-End_Error";
case 187:
return "Reported_Uncorrect";
case 188:
return "Command_Timeout";
case 189:
if (ssd) return Unknown_SSD_Attribute;
return "High_Fly_Writes";
case 190:
// Western Digital uses this for temperature.
// It's identical to Attribute 194 except that it
// has a failure threshold set to correspond to the
// max allowed operating temperature of the drive, which
// is typically 55C. So if this attribute has failed
// in the past, it indicates that the drive temp exceeded
// 55C sometime in the past.
return "Airflow_Temperature_Cel";
case 191:
if (ssd) return Unknown_SSD_Attribute;
return "G-Sense_Error_Rate";
case 192:
return "Power-Off_Retract_Count";
case 193:
if (ssd) return Unknown_SSD_Attribute;
return "Load_Cycle_Count";
case 194:
return "Temperature_Celsius";
case 195:
// Fujitsu: "ECC_On_The_Fly_Count";
return "Hardware_ECC_Recovered";
case 196:
return "Reallocated_Event_Count";
case 197:
return "Current_Pending_Sector";
case 198:
return "Offline_Uncorrectable";
case 199:
return "UDMA_CRC_Error_Count";
case 200:
if (ssd) return Unknown_SSD_Attribute;
// Western Digital
return "Multi_Zone_Error_Rate";
case 201:
if (ssd) return Unknown_SSD_Attribute;
return "Soft_Read_Error_Rate";
case 202:
if (ssd) return Unknown_SSD_Attribute;
// Fujitsu: "TA_Increase_Count"
return "Data_Address_Mark_Errs";
case 203:
// Fujitsu
return "Run_Out_Cancel";
// Maxtor: ECC Errors
case 204:
// Fujitsu: "Shock_Count_Write_Opern"
return "Soft_ECC_Correction";
case 205:
// Fujitsu: "Shock_Rate_Write_Opern"
return "Thermal_Asperity_Rate";
case 206:
// Fujitsu
if (ssd) return Unknown_SSD_Attribute;
return "Flying_Height";
case 207:
// Maxtor
if (ssd) return Unknown_SSD_Attribute;
return "Spin_High_Current";
case 208:
// Maxtor
if (ssd) return Unknown_SSD_Attribute;
return "Spin_Buzz";
case 209:
// Maxtor
if (ssd) return Unknown_SSD_Attribute;
return "Offline_Seek_Performnce";
case 220:
if (ssd) return Unknown_SSD_Attribute;
return "Disk_Shift";
case 221:
if (ssd) return Unknown_SSD_Attribute;
return "G-Sense_Error_Rate";
case 222:
if (ssd) return Unknown_SSD_Attribute;
return "Loaded_Hours";
case 223:
if (ssd) return Unknown_SSD_Attribute;
return "Load_Retry_Count";
case 224:
if (ssd) return Unknown_SSD_Attribute;
return "Load_Friction";
case 225:
if (ssd) return Unknown_SSD_Attribute;
return "Load_Cycle_Count";
case 226:
if (ssd) return Unknown_SSD_Attribute;
return "Load-in_Time";
case 227:
if (ssd) return Unknown_SSD_Attribute;
return "Torq-amp_Count";
case 228:
return "Power-off_Retract_Count";
case 230:
// seen in IBM DTPA-353750
if (ssd) return Unknown_SSD_Attribute;
return "Head_Amplitude";
case 231:
return "Temperature_Celsius";
case 232:
// seen in Intel X25-E SSD
return "Available_Reservd_Space";
case 233:
// seen in Intel X25-E SSD
if (hdd) return Unknown_HDD_Attribute;
return "Media_Wearout_Indicator";
case 240:
if (ssd) return Unknown_SSD_Attribute;
return "Head_Flying_Hours";
case 241:
return "Total_LBAs_Written";
case 242:
return "Total_LBAs_Read";
case 250:
return "Read_Error_Retry_Rate";
case 254:
if (ssd) return Unknown_SSD_Attribute;
return "Free_Fall_Sensor";
default:
return "Unknown_Attribute";
}
}
// Get attribute name // Get attribute name
std::string ata_get_smart_attr_name(unsigned char id, const ata_vendor_attr_defs & defs, std::string ata_get_smart_attr_name(unsigned char id, const ata_vendor_attr_defs & defs,
int rpm /* = 0 */) int rpm /* = 0 */)
{ {
if (!defs[id].name.empty()) if (!defs[id].name.empty())
return defs[id].name; return defs[id].name;
else {
const ata_vendor_attr_defs::entry & def = get_default_attr_defs()[id];
if (def.name.empty())
return "Unknown_Attribute";
else if ((def.flags & ATTRFLAG_HDD_ONLY) && rpm == 1)
return "Unknown_SSD_Attribute";
else if ((def.flags & ATTRFLAG_SSD_ONLY) && rpm > 1)
return "Unknown_HDD_Attribute";
else else
return get_default_attr_name(id, rpm); return def.name;
}
} }
// Find attribute index for attribute id, -1 if not found. // Find attribute index for attribute id, -1 if not found.
@ -2428,6 +2235,7 @@ int ataReadSCTStatus(ata_device * device, ata_sct_status_response * sts)
swapx(&sts->function_code); swapx(&sts->function_code);
swapx(&sts->over_limit_count); swapx(&sts->over_limit_count);
swapx(&sts->under_limit_count); swapx(&sts->under_limit_count);
swapx(&sts->smart_status);
} }
// Check format version // Check format version

View File

@ -1,10 +1,10 @@
/* /*
* atacmds.h * atacmds.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2002-11 Bruce Allen
* Copyright (C) 2008-12 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2008-15 Christian Franke
* Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org> * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -25,7 +25,7 @@
#ifndef ATACMDS_H_ #ifndef ATACMDS_H_
#define ATACMDS_H_ #define ATACMDS_H_
#define ATACMDS_H_CVSID "$Id: atacmds.h 3825 2013-07-06 21:38:25Z samm2 $" #define ATACMDS_H_CVSID "$Id: atacmds.h 4162 2015-10-31 16:36:16Z chrfranke $"
#include "dev_interface.h" // ata_device #include "dev_interface.h" // ata_device
@ -521,7 +521,7 @@ ASSERT_SIZEOF_STRUCT(ata_selective_self_test_log, 512);
// T13/1699-D Revision 3f (Working Draft), December 11, 2006. // T13/1699-D Revision 3f (Working Draft), December 11, 2006.
// SCT Status response (read with SMART_READ_LOG page 0xe0) // SCT Status response (read with SMART_READ_LOG page 0xe0)
// Table 60 of T13/1699-D Revision 3f // Table 182 of T13/BSR INCITS 529 (ACS-4) Revision 04, August 25, 2014
#pragma pack(1) #pragma pack(1)
struct ata_sct_status_response struct ata_sct_status_response
{ {
@ -545,7 +545,8 @@ struct ata_sct_status_response
unsigned char byte205; // 205: reserved (T13/e06152r0-2: Average lifetime temperature) unsigned char byte205; // 205: reserved (T13/e06152r0-2: Average lifetime temperature)
unsigned int over_limit_count; // 206-209: # intervals since last reset with temperature > Max Op Limit unsigned int over_limit_count; // 206-209: # intervals since last reset with temperature > Max Op Limit
unsigned int under_limit_count; // 210-213: # intervals since last reset with temperature < Min Op Limit unsigned int under_limit_count; // 210-213: # intervals since last reset with temperature < Min Op Limit
unsigned char bytes214_479[266]; // 214-479: reserved unsigned short smart_status; // 214-215: LBA(32:8) of SMART RETURN STATUS (0, 0x2cf4, 0xc24f) (ACS-4)
unsigned char bytes216_479[479-216+1]; // 216-479: reserved
unsigned char vendor_specific[32];// 480-511: vendor specific unsigned char vendor_specific[32];// 480-511: vendor specific
} ATTR_PACKED; } ATTR_PACKED;
#pragma pack() #pragma pack()
@ -685,7 +686,9 @@ enum ata_attr_raw_format
enum { enum {
ATTRFLAG_INCREASING = 0x01, // Value not reset (for reallocated/pending counts) ATTRFLAG_INCREASING = 0x01, // Value not reset (for reallocated/pending counts)
ATTRFLAG_NO_NORMVAL = 0x02, // Normalized value not valid ATTRFLAG_NO_NORMVAL = 0x02, // Normalized value not valid
ATTRFLAG_NO_WORSTVAL = 0x04 // Worst value not valid ATTRFLAG_NO_WORSTVAL = 0x04, // Worst value not valid
ATTRFLAG_HDD_ONLY = 0x08, // DEFAULT setting for HDD only
ATTRFLAG_SSD_ONLY = 0x10, // DEFAULT setting for SSD only
}; };
// Vendor attribute display defs for all attribute ids // Vendor attribute display defs for all attribute ids
@ -785,7 +788,7 @@ bool ataReadSmartLog(ata_device * device, unsigned char logaddr,
void * data, unsigned nsectors); void * data, unsigned nsectors);
// Read SMART Extended Comprehensive Error Log // Read SMART Extended Comprehensive Error Log
bool ataReadExtErrorLog(ata_device * device, ata_smart_exterrlog * log, bool ataReadExtErrorLog(ata_device * device, ata_smart_exterrlog * log,
unsigned nsectors, firmwarebug_defs firwarebugs); unsigned page, unsigned nsectors, firmwarebug_defs firmwarebugs);
// Read SMART Extended Self-test Log // Read SMART Extended Self-test Log
bool ataReadExtSelfTestLog(ata_device * device, ata_smart_extselftestlog * log, bool ataReadExtSelfTestLog(ata_device * device, ata_smart_extselftestlog * log,
unsigned nsectors); unsigned nsectors);

View File

@ -1,9 +1,9 @@
/* /*
* ataidentify.cpp * ataidentify.cpp
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2012-13 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2012-15 Christian Franke
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -18,7 +18,7 @@
#include "config.h" #include "config.h"
#include "ataidentify.h" #include "ataidentify.h"
const char * ataidentify_cpp_cvsid = "$Id: ataidentify.cpp 3851 2013-08-17 20:10:11Z chrfranke $" const char * ataidentify_cpp_cvsid = "$Id: ataidentify.cpp 4120 2015-08-27 16:12:21Z samm2 $"
ATAIDENTIFY_H_CVSID; ATAIDENTIFY_H_CVSID;
#include "int64.h" #include "int64.h"
@ -33,7 +33,8 @@ const char * ataidentify_cpp_cvsid = "$Id: ataidentify.cpp 3851 2013-08-17 20:10
// Tables 16 and 18 of T13/1532D (ATA/ATAPI-7) Volume 1 Revision 4b, April 21, 2004 // Tables 16 and 18 of T13/1532D (ATA/ATAPI-7) Volume 1 Revision 4b, April 21, 2004
// Tables 29 and 39 of T13/1699-D (ATA8-ACS) Revision 6a, September 6, 2008 // Tables 29 and 39 of T13/1699-D (ATA8-ACS) Revision 6a, September 6, 2008
// Tables 50 and 61 of T13/2015-D (ACS-2) Revision 7, June 22, 2011 // Tables 50 and 61 of T13/2015-D (ACS-2) Revision 7, June 22, 2011
// Tables 51 and 56 of T13/2161-D (ACS-3) Revision 4g, February 27, 2013 // Tables 45 and 50 of T13/2161-D (ACS-3) Revision 5, October 28, 2013
// Table 44 of T13/BSR INCITS 529 (ACS-4) Revision 08, April 28, 2015 (ATAPI removed)
const char * const identify_descriptions[] = { const char * const identify_descriptions[] = {
" 0 General configuration", " 0 General configuration",
@ -42,7 +43,7 @@ const char * const identify_descriptions[] = {
". 14 ATAPI: Must be set to 0", ". 14 ATAPI: Must be set to 0",
". 13 ATAPI: Reserved", ". 13 ATAPI: Reserved",
". 12:8 ATAPI: Command set: 0x05 = CD/DVD", ". 12:8 ATAPI: Command set: 0x05 = CD/DVD",
". 7 Removable media device", ". 7 Removable media device [OBS-8]",
". 6 ATA: Not removable controller and/or device [OBS-6]", ". 6 ATA: Not removable controller and/or device [OBS-6]",
". 5:3 ATA: Vendor specific [RET-3]", ". 5:3 ATA: Vendor specific [RET-3]",
". 6:5 ATAPI: DRQ after PACKET cmd: 0x0 = 3ms, 0x2 = 50us", ". 6:5 ATAPI: DRQ after PACKET cmd: 0x0 = 3ms, 0x2 = 50us",
@ -88,7 +89,8 @@ const char * const identify_descriptions[] = {
". 10 IORDY may be disabled", ". 10 IORDY may be disabled",
". 9 LBA supported", ". 9 LBA supported",
". 8 DMA supported", ". 8 DMA supported",
". 7:0 Vendor specific [RET-4]", ". 7:2 Reserved", // ATA-3: Vendor specific, ATA-8: Retired
". 1:0 Long Phy Sector Alignment Error reporting", // ACS-2
" 50 Capabilities", " 50 Capabilities",
". 15:14 Must be set to 0x1", ". 15:14 Must be set to 0x1",
@ -116,7 +118,9 @@ const char * const identify_descriptions[] = {
". 14 OVERWRITE EXT supported", ". 14 OVERWRITE EXT supported",
". 13 CRYPTO SCRAMBLE EXT supported", ". 13 CRYPTO SCRAMBLE EXT supported",
". 12 Sanitize Device feature set supported", ". 12 Sanitize Device feature set supported",
". 11:9 Reserved", ". 11 Cmds during sanitize as specified by this standard", // ACS-3
". 10 SANITIZE ANTIFREEZE LOCK EXT supported", // ACS-3
". 9 Reserved",
". 8 Bits 7:0 are valid", ". 8 Bits 7:0 are valid",
". 7:0 Current sectors per DRQ on READ/WRITE MULTIPLE", ". 7:0 Current sectors per DRQ on READ/WRITE MULTIPLE",
@ -157,8 +161,8 @@ const char * const identify_descriptions[] = {
". 5 Trimmed LBA range(s) returning zeroed data supported", ". 5 Trimmed LBA range(s) returning zeroed data supported",
". 4 Device encrypts all user data", ". 4 Device encrypts all user data",
". 3 Extended number of user addressable sectors supported", ". 3 Extended number of user addressable sectors supported",
". 2 All write cache is non-volatile", ". 2 All write cache is non-volatile", // ACS-3
". 1:0 Reserved", ". 1:0 Zoned Capabilities", // ACS-4
" 70 Reserved", " 70 Reserved",
" 71-74 ATA: Reserved for IDENTIFY PACKET DEVICE", " 71-74 ATA: Reserved for IDENTIFY PACKET DEVICE",
@ -216,7 +220,8 @@ const char * const identify_descriptions[] = {
". 0 Must be set to 0", ". 0 Must be set to 0",
" 80 Major version number", " 80 Major version number",
". 15:11 Reserved", ". 15:12 Reserved",
". 11 ACS-4 supported",
". 10 ACS-3 supported", ". 10 ACS-3 supported",
". 9 ACS-2 supported", ". 9 ACS-2 supported",
". 8 ATA8-ACS supported", ". 8 ATA8-ACS supported",
@ -257,7 +262,7 @@ const char * const identify_descriptions[] = {
". 10 48-bit Address feature set supported", ". 10 48-bit Address feature set supported",
". 9 AAM feature set supported [OBS-ACS-2]", ". 9 AAM feature set supported [OBS-ACS-2]",
". 8 SET MAX security extension supported [OBS-ACS-3]", ". 8 SET MAX security extension supported [OBS-ACS-3]",
". 7 Reserved for Address Offset Reserved Area Boot Method", ". 7 Reserved for Addr Offset Resvd Area Boot [OBS-ACS-3]",
". 6 SET FEATURES subcommand required to spin-up", ". 6 SET FEATURES subcommand required to spin-up",
". 5 PUIS feature set supported", ". 5 PUIS feature set supported",
". 4 Removable Media Status Notification supported [OBS-8]", ". 4 Removable Media Status Notification supported [OBS-8]",
@ -278,7 +283,7 @@ const char * const identify_descriptions[] = {
". 5 GPL feature set supported", ". 5 GPL feature set supported",
". 4 Streaming feature set supported [OBS-ACS-3]", ". 4 Streaming feature set supported [OBS-ACS-3]",
". 3 Media Card Pass Through Command supported [OBS-ACS-2]", ". 3 Media Card Pass Through Command supported [OBS-ACS-2]",
". 2 Media serial number supported", // ACS-3 r3 or later: Reserved ". 2 Media serial number supported [RES-ACS-3]",
". 1 SMART self-test supported", ". 1 SMART self-test supported",
". 0 SMART error logging supported", ". 0 SMART error logging supported",
@ -309,7 +314,7 @@ const char * const identify_descriptions[] = {
". 10 48-bit Address features set supported", ". 10 48-bit Address features set supported",
". 9 AAM feature set enabled [OBS-ACS-2]", ". 9 AAM feature set enabled [OBS-ACS-2]",
". 8 SET MAX security extension enabled [OBS-ACS-3]", ". 8 SET MAX security extension enabled [OBS-ACS-3]",
". 7 Reserved for Address Offset Reserved Area Boot Method", ". 7 Reserved for Addr Offset Resvd Area Boot [OBS-ACS-3]",
". 6 SET FEATURES subcommand required to spin-up", ". 6 SET FEATURES subcommand required to spin-up",
". 5 PUIS feature set enabled", ". 5 PUIS feature set enabled",
". 4 Removable Media Status Notification enabled [OBS-8]", ". 4 Removable Media Status Notification enabled [OBS-8]",
@ -353,9 +358,18 @@ const char * const identify_descriptions[] = {
". 0 Ultra DMA mode 0 supported", ". 0 Ultra DMA mode 0 supported",
" 89 SECURITY ERASE UNIT time", " 89 SECURITY ERASE UNIT time",
". 15 Bits 14:8 of value are valid", // ACS-3
". 14:0 SECURITY ERASE UNIT time value", // value*2 minutes
" 90 ENHANCED SECURITY ERASE UNIT time", " 90 ENHANCED SECURITY ERASE UNIT time",
". 15 Bits 14:8 of value are valid", // ACS-3
". 14:0 ENHANCED SECURITY ERASE UNIT time value", // value*2 minutes
" 91 Current APM level", " 91 Current APM level",
" 92 Master password revision code", ". 15:8 Reserved", // ACS-3
". 7:0 Current APM level value",
" 92 Master Password Identifier", // ATA-7: Master Password Revision Code
" 93 Hardware reset result (PATA)", " 93 Hardware reset result (PATA)",
". 15:14 Must be set to 0x1", ". 15:14 Must be set to 0x1",
@ -393,7 +407,7 @@ const char * const identify_descriptions[] = {
"107 Inter-seek delay for ISO 7779 acoustic testing", "107 Inter-seek delay for ISO 7779 acoustic testing",
"108-111 64-bit World Wide Name", "108-111 64-bit World Wide Name",
"112-115 Reserved for a 128-bit World Wide Name", "112-115 Reserved", // ATA-7: Reserved for world wide name extension to 128 bits
"116 Reserved for TLC [OBS-ACS-3]", "116 Reserved for TLC [OBS-ACS-3]",
"117-118 Logical sector size (DWord)", "117-118 Logical sector size (DWord)",
@ -459,7 +473,7 @@ const char * const identify_descriptions[] = {
". 15:4 Reserved", ". 15:4 Reserved",
". 3:0 Nominal form factor: -, 5.25, 3.5, 2.5, 1.8, <1.8", ". 3:0 Nominal form factor: -, 5.25, 3.5, 2.5, 1.8, <1.8",
"169 Data Set Management support", "169 DATA SET MANAGEMENT command support",
". 15:1 Reserved", ". 15:1 Reserved",
". 0 Trim bit in DATA SET MANAGEMENT command supported", ". 0 Trim bit in DATA SET MANAGEMENT command supported",
@ -468,7 +482,7 @@ const char * const identify_descriptions[] = {
"176-205 Current media serial number (String)", "176-205 Current media serial number (String)",
"206 SCT Command Transport", "206 SCT Command Transport",
". 15:12 Vendor Specific", ". 15:12 Vendor specific",
". 11:8 Reserved", ". 11:8 Reserved",
". 7 Reserved for Serial ATA", ". 7 Reserved for Serial ATA",
". 6 Reserved", ". 6 Reserved",
@ -479,7 +493,7 @@ const char * const identify_descriptions[] = {
". 1 SCT Read/Write Long supported [OBS-ACS-2]", ". 1 SCT Read/Write Long supported [OBS-ACS-2]",
". 0 SCT Command Transport supported", ". 0 SCT Command Transport supported",
"207-208 Reserved for CE-ATA", "207-208 Reserved", // ATA-8: Reserved for CE-ATA
"209 Alignment of logical sectors", "209 Alignment of logical sectors",
". 15:14 Must be set to 0x1", ". 15:14 Must be set to 0x1",
@ -512,8 +526,9 @@ const char * const identify_descriptions[] = {
"221 Reserved", "221 Reserved",
"222 Transport major version number", "222 Transport major version number",
". 15:12 Transport type: 0x0 = Parallel, 0x1 = Serial", ". 15:12 Transport: 0x0 = Parallel, 0x1 = Serial, 0xe = PCIe", // PCIe: ACS-4
". 11:7 Reserved | Reserved", ". 11:8 Reserved | Reserved",
". 7 Reserved | SATA 3.2",
". 6 Reserved | SATA 3.1", ". 6 Reserved | SATA 3.1",
". 5 Reserved | SATA 3.0", ". 5 Reserved | SATA 3.0",
". 4 Reserved | SATA 2.6", ". 4 Reserved | SATA 2.6",

View File

@ -1,7 +1,7 @@
/* /*
* ataidentify.h * ataidentify.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2012 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2012 Christian Franke <smartmontools-support@lists.sourceforge.net>
* *
@ -18,7 +18,7 @@
#ifndef ATAIDENTIFY_H #ifndef ATAIDENTIFY_H
#define ATAIDENTIFY_H #define ATAIDENTIFY_H
#define ATAIDENTIFY_H_CVSID "$Id: ataidentify.h 3610 2012-09-20 21:27:19Z chrfranke $" #define ATAIDENTIFY_H_CVSID "$Id: ataidentify.h 4120 2015-08-27 16:12:21Z samm2 $"
void ata_print_identify_data(const void * id, bool all_words, int bit_level); void ata_print_identify_data(const void * id, bool all_words, int bit_level);

View File

@ -1,10 +1,10 @@
/* /*
* ataprint.cpp * ataprint.cpp
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2002-11 Bruce Allen
* Copyright (C) 2008-14 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2008-16 Christian Franke
* Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org> * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -40,7 +40,7 @@
#include "utility.h" #include "utility.h"
#include "knowndrives.h" #include "knowndrives.h"
const char * ataprint_cpp_cvsid = "$Id: ataprint.cpp 3982 2014-08-16 21:07:19Z samm2 $" const char * ataprint_cpp_cvsid = "$Id: ataprint.cpp 4256 2016-03-27 16:51:32Z chrfranke $"
ATAPRINT_H_CVSID; ATAPRINT_H_CVSID;
@ -412,6 +412,24 @@ static inline std::string format_st_er_desc(
} }
static const char * get_form_factor(unsigned short word168)
{
// Table A.32 of T13/2161-D (ACS-3) Revision 4p, September 19, 2013
// Table 236 of T13/BSR INCITS 529 (ACS-4) Revision 04, August 25, 2014
switch (word168) {
case 0x1: return "5.25 inches";
case 0x2: return "3.5 inches";
case 0x3: return "2.5 inches";
case 0x4: return "1.8 inches";
case 0x5: return "< 1.8 inches";
case 0x6: return "mSATA"; // ACS-4
case 0x7: return "M.2"; // ACS-4
case 0x8: return "MicroSSD"; // ACS-4
case 0x9: return "CFast"; // ACS-4
default : return 0;
}
}
static int find_msb(unsigned short word) static int find_msb(unsigned short word)
{ {
for (int bit = 15; bit >= 0; bit--) for (int bit = 15; bit >= 0; bit--)
@ -439,6 +457,10 @@ static const char * get_ata_major_version(const ata_identify_device * drive)
static const char * get_ata_minor_version(const ata_identify_device * drive) static const char * get_ata_minor_version(const ata_identify_device * drive)
{ {
// Table 10 of X3T13/2008D (ATA-3) Revision 7b, January 27, 1997
// Table 28 of T13/1410D (ATA/ATAPI-6) Revision 3b, February 26, 2002
// Table 31 of T13/1699-D (ATA8-ACS) Revision 6a, September 6, 2008
// Table 46 of T13/BSR INCITS 529 (ACS-4) Revision 08, April 28, 2015
switch (drive->minor_rev_num) { switch (drive->minor_rev_num) {
case 0x0001: return "ATA-1 X3T9.2/781D prior to revision 4"; case 0x0001: return "ATA-1 X3T9.2/781D prior to revision 4";
case 0x0002: return "ATA-1 published, ANSI X3.221-1994"; case 0x0002: return "ATA-1 published, ANSI X3.221-1994";
@ -489,21 +511,41 @@ static const char * get_ata_minor_version(const ata_identify_device * drive)
case 0x0052: return "ATA8-ACS T13/1699-D revision 3b"; case 0x0052: return "ATA8-ACS T13/1699-D revision 3b";
case 0x005e: return "ACS-4 T13/BSR INCITS 529 revision 5";
case 0x006d: return "ACS-3 T13/2161-D revision 5";
case 0x0082: return "ACS-2 published, ANSI INCITS 482-2012";
case 0x0107: return "ATA8-ACS T13/1699-D revision 2d"; case 0x0107: return "ATA8-ACS T13/1699-D revision 2d";
case 0x010a: return "ACS-3 published, ANSI INCITS 522-2014";
case 0x0110: return "ACS-2 T13/2015-D revision 3"; case 0x0110: return "ACS-2 T13/2015-D revision 3";
case 0x011b: return "ACS-3 T13/2161-D revision 4";
default: return 0; default: return 0;
} }
} }
static const char * get_sata_version(const ata_identify_device * drive) static const char * get_pata_version(unsigned short word222, char (& buf)[32])
{
switch (word222 & 0x0fff) {
default: snprintf(buf, sizeof(buf),
"Unknown (0x%03x)", word222 & 0x0fff); return buf;
case 0x001:
case 0x003: return "ATA8-APT";
case 0x002: return "ATA/ATAPI-7";
}
}
static const char * get_sata_version(unsigned short word222, char (& buf)[32])
{ {
unsigned short word222 = drive->words088_255[222-88];
if ((word222 & 0xf000) != 0x1000)
return 0;
switch (find_msb(word222 & 0x0fff)) { switch (find_msb(word222 & 0x0fff)) {
default: return "SATA >3.1"; default: snprintf(buf, sizeof(buf),
"SATA >3.2 (0x%03x)", word222 & 0x0fff); return buf;
case 7: return "SATA 3.2";
case 6: return "SATA 3.1"; case 6: return "SATA 3.1";
case 5: return "SATA 3.0"; case 5: return "SATA 3.0";
case 4: return "SATA 2.6"; case 4: return "SATA 2.6";
@ -511,7 +553,7 @@ static const char * get_sata_version(const ata_identify_device * drive)
case 2: return "SATA II Ext"; case 2: return "SATA II Ext";
case 1: return "SATA 1.0a"; case 1: return "SATA 1.0a";
case 0: return "ATA8-AST"; case 0: return "ATA8-AST";
case -1: return 0; case -1: return "Unknown";
} }
} }
@ -520,7 +562,10 @@ static const char * get_sata_speed(int level)
if (level <= 0) if (level <= 0)
return 0; return 0;
switch (level) { switch (level) {
default: return ">6.0 Gb/s"; default: return ">6.0 Gb/s (7)";
case 6: return ">6.0 Gb/s (6)";
case 5: return ">6.0 Gb/s (5)";
case 4: return ">6.0 Gb/s (4)";
case 3: return "6.0 Gb/s"; case 3: return "6.0 Gb/s";
case 2: return "3.0 Gb/s"; case 2: return "3.0 Gb/s";
case 1: return "1.5 Gb/s"; case 1: return "1.5 Gb/s";
@ -559,6 +604,7 @@ static void print_drive_info(const ata_identify_device * drive,
pout("Model Family: %s\n", dbentry->modelfamily); pout("Model Family: %s\n", dbentry->modelfamily);
pout("Device Model: %s\n", infofound(model)); pout("Device Model: %s\n", infofound(model));
if (!dont_print_serial_number) { if (!dont_print_serial_number) {
pout("Serial Number: %s\n", infofound(serial)); pout("Serial Number: %s\n", infofound(serial));
@ -566,6 +612,7 @@ static void print_drive_info(const ata_identify_device * drive,
int naa = ata_get_wwn(drive, oui, unique_id); int naa = ata_get_wwn(drive, oui, unique_id);
if (naa >= 0) if (naa >= 0)
pout("LU WWN Device Id: %x %06x %09" PRIx64 "\n", naa, oui, unique_id); pout("LU WWN Device Id: %x %06x %09" PRIx64 "\n", naa, oui, unique_id);
}
// Additional Product Identifier (OEM Id) string in words 170-173 // Additional Product Identifier (OEM Id) string in words 170-173
// (e08130r1, added in ACS-2 Revision 1, December 17, 2008) // (e08130r1, added in ACS-2 Revision 1, December 17, 2008)
@ -575,7 +622,7 @@ static void print_drive_info(const ata_identify_device * drive,
if (add[0]) if (add[0])
pout("Add. Product Id: %s\n", add); pout("Add. Product Id: %s\n", add);
} }
}
pout("Firmware Version: %s\n", infofound(firmware)); pout("Firmware Version: %s\n", infofound(firmware));
if (sizes.capacity) { if (sizes.capacity) {
@ -610,17 +657,9 @@ static void print_drive_info(const ata_identify_device * drive,
// Print form factor if reported // Print form factor if reported
unsigned short word168 = drive->words088_255[168-88]; unsigned short word168 = drive->words088_255[168-88];
if (word168) { if (word168) {
const char * inches; const char * form_factor = get_form_factor(word168);
switch (word168) { if (form_factor)
case 0x1: inches = "5.25"; break; pout("Form Factor: %s\n", form_factor);
case 0x2: inches = "3.5"; break;
case 0x3: inches = "2.5"; break;
case 0x4: inches = "1.8"; break;
case 0x5: inches = "< 1.8"; break;
default : inches = 0;
}
if (inches)
pout("Form Factor: %s inches\n", inches);
else else
pout("Form Factor: Unknown (0x%04x)\n", word168); pout("Form Factor: Unknown (0x%04x)\n", word168);
} }
@ -657,9 +696,17 @@ static void print_drive_info(const ata_identify_device * drive,
} }
pout("ATA Version is: %s\n", infofound(ataver.c_str())); pout("ATA Version is: %s\n", infofound(ataver.c_str()));
// If SATA drive print SATA version and speed // Print Transport specific version
const char * sataver = get_sata_version(drive); // cppcheck-suppress variableScope
if (sataver) { char buf[32] = "";
unsigned short word222 = drive->words088_255[222-88];
if (word222 != 0x0000 && word222 != 0xffff) switch (word222 >> 12) {
case 0x0: // PATA
pout("Transport Type: Parallel, %s\n", get_pata_version(word222, buf));
break;
case 0x1: // SATA
{
const char * sataver = get_sata_version(word222, buf);
const char * maxspeed = get_sata_maxspeed(drive); const char * maxspeed = get_sata_maxspeed(drive);
const char * curspeed = get_sata_curspeed(drive); const char * curspeed = get_sata_curspeed(drive);
pout("SATA Version is: %s%s%s%s%s%s\n", sataver, pout("SATA Version is: %s%s%s%s%s%s\n", sataver,
@ -667,6 +714,14 @@ static void print_drive_info(const ata_identify_device * drive,
(curspeed ? " (current: " : ""), (curspeed ? curspeed : ""), (curspeed ? " (current: " : ""), (curspeed ? curspeed : ""),
(curspeed ? ")" : "")); (curspeed ? ")" : ""));
} }
break;
case 0xe: // PCIe (ACS-4)
pout("Transport Type: PCIe (0x%03x)\n", word222 & 0x0fff);
break;
default:
pout("Transport Type: Unknown (0x%04x)\n", word222);
break;
}
// print current time and date and timezone // print current time and date and timezone
char timedatetz[DATEANDEPOCHLEN]; dateandtimezone(timedatetz); char timedatetz[DATEANDEPOCHLEN]; dateandtimezone(timedatetz);
@ -1126,9 +1181,10 @@ static unsigned GetNumLogSectors(const ata_smart_log_directory * logdir, unsigne
} }
// Get name of log. // Get name of log.
// Table A.2 of T13/2161-D (ACS-3) Revision 4, September 4, 2012
static const char * GetLogName(unsigned logaddr) static const char * GetLogName(unsigned logaddr)
{ {
// Table 205 of T13/BSR INCITS 529 (ACS-4) Revision 08, April 28, 2015
// Table 112 of Serial ATA Revision 3.2, August 7, 2013
switch (logaddr) { switch (logaddr) {
case 0x00: return "Log Directory"; case 0x00: return "Log Directory";
case 0x01: return "Summary SMART error log"; case 0x01: return "Summary SMART error log";
@ -1145,12 +1201,14 @@ static const char * GetLogName(unsigned logaddr)
case 0x0c: return "Pending Defects log"; // ACS-4 case 0x0c: return "Pending Defects log"; // ACS-4
case 0x0d: return "LPS Mis-alignment log"; // ACS-2 case 0x0d: return "LPS Mis-alignment log"; // ACS-2
case 0x10: return "NCQ Command Error log"; case 0x0f: return "Sense Data for Successful NCQ Cmds log"; // ACS-4
case 0x11: return "SATA Phy Event Counters"; case 0x10: return "SATA NCQ Queued Error log";
case 0x12: return "SATA NCQ Queue Management log"; // ACS-3 case 0x11: return "SATA Phy Event Counters log";
case 0x13: return "SATA NCQ Send and Receive log"; // ACS-3 //case 0x12: return "SATA NCQ Queue Management log"; // SATA 3.0/3.1
case 0x14: case 0x12: return "SATA NCQ NON-DATA log"; // SATA 3.2
case 0x15: case 0x13: return "SATA NCQ Send and Receive log"; // SATA 3.1
case 0x14: return "SATA Hybrid Information log"; // SATA 3.2
case 0x15: return "SATA Rebuild Assist log"; // SATA 3.2
case 0x16: case 0x16:
case 0x17: return "Reserved for Serial ATA"; case 0x17: return "Reserved for Serial ATA";
@ -1182,13 +1240,14 @@ static const char * get_log_rw(unsigned logaddr)
{ {
if ( ( logaddr <= 0x08) if ( ( logaddr <= 0x08)
|| (0x0c <= logaddr && logaddr <= 0x0d) || (0x0c <= logaddr && logaddr <= 0x0d)
|| (0x10 <= logaddr && logaddr <= 0x13) || (0x0f <= logaddr && logaddr <= 0x14)
|| (0x19 == logaddr) || (0x19 == logaddr)
|| (0x20 <= logaddr && logaddr <= 0x25) || (0x20 <= logaddr && logaddr <= 0x25)
|| (0x30 == logaddr)) || (0x30 == logaddr))
return "R/O"; return "R/O";
if ( (0x09 <= logaddr && logaddr <= 0x0a) if ( (0x09 <= logaddr && logaddr <= 0x0a)
|| (0x15 == logaddr)
|| (0x80 <= logaddr && logaddr <= 0x9f) || (0x80 <= logaddr && logaddr <= 0x9f)
|| (0xe0 <= logaddr && logaddr <= 0xe1)) || (0xe0 <= logaddr && logaddr <= 0xe1))
return "R/W"; return "R/W";
@ -1311,9 +1370,8 @@ static void PrintLogPages(const char * type, const unsigned char * data,
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
// Device statistics (Log 0x04) // Device statistics (Log 0x04)
// See Section A.5 of // Section A.5 of T13/2161-D (ACS-3) Revision 5, October 28, 2013
// ATA/ATAPI Command Set - 3 (ACS-3) // Section 9.5 of T13/BSR INCITS 529 (ACS-4) Revision 08, April 28, 2015
// T13/2161-D Revision 2, February 21, 2012.
struct devstat_entry_info struct devstat_entry_info
{ {
@ -1329,12 +1387,15 @@ const devstat_entry_info devstat_info_0x00[] = {
const devstat_entry_info devstat_info_0x01[] = { const devstat_entry_info devstat_info_0x01[] = {
{ 2, "General Statistics" }, { 2, "General Statistics" },
{ 4, "Lifetime Power-On Resets" }, { 4, "Lifetime Power-On Resets" },
{ 4, "Power-on Hours" }, // spec says no flags(?) { 4, "Power-on Hours" },
{ 6, "Logical Sectors Written" }, { 6, "Logical Sectors Written" },
{ 6, "Number of Write Commands" }, { 6, "Number of Write Commands" },
{ 6, "Logical Sectors Read" }, { 6, "Logical Sectors Read" },
{ 6, "Number of Read Commands" }, { 6, "Number of Read Commands" },
{ 6, "Date and Time TimeStamp" }, // ACS-3 { 6, "Date and Time TimeStamp" }, // ACS-3
{ 4, "Pending Error Count" }, // ACS-4
{ 2, "Workload Utilization" }, // ACS-4
{ 6, "Utilization Usage Rate" }, // ACS-4 (TODO: field provides 3 values)
{ 0, 0 } { 0, 0 }
}; };
@ -1354,6 +1415,7 @@ const devstat_entry_info devstat_info_0x03[] = {
{ 4, "Read Recovery Attempts" }, { 4, "Read Recovery Attempts" },
{ 4, "Number of Mechanical Start Failures" }, { 4, "Number of Mechanical Start Failures" },
{ 4, "Number of Realloc. Candidate Logical Sectors" }, // ACS-3 { 4, "Number of Realloc. Candidate Logical Sectors" }, // ACS-3
{ 4, "Number of High Priority Unload Events" }, // ACS-3
{ 0, 0 } { 0, 0 }
}; };
@ -1410,24 +1472,32 @@ const devstat_entry_info * devstat_infos[] = {
const int num_devstat_infos = sizeof(devstat_infos)/sizeof(devstat_infos[0]); const int num_devstat_infos = sizeof(devstat_infos)/sizeof(devstat_infos[0]);
static void print_device_statistics_page(const unsigned char * data, int page, static const char * get_device_statistics_page_name(int page)
bool & need_trailer) {
if (page < num_devstat_infos)
return devstat_infos[page][0].name;
if (page == 0xff)
return "Vendor Specific Statistics"; // ACS-4
return "Unknown Statistics";
}
static void print_device_statistics_page(const unsigned char * data, int page)
{ {
const devstat_entry_info * info = (page < num_devstat_infos ? devstat_infos[page] : 0); const devstat_entry_info * info = (page < num_devstat_infos ? devstat_infos[page] : 0);
const char * name = (info ? info[0].name : "Unknown Statistics"); const char * name = get_device_statistics_page_name(page);
// Check page number in header // Check page number in header
static const char line[] = " ===== = = == "; static const char line[] = " ===== = = === == ";
if (!data[2]) { if (!data[2]) {
pout("%3d%s%s (empty) ==\n", page, line, name); pout("0x%02x%s%s (empty) ==\n", page, line, name);
return; return;
} }
if (data[2] != page) { if (data[2] != page) {
pout("%3d%s%s (invalid page %d in header) ==\n", page, line, name, data[2]); pout("0x%02x%s%s (invalid page 0x%02x in header) ==\n", page, line, name, data[2]);
return; return;
} }
pout("%3d%s%s (rev %d) ==\n", page, line, name, data[0]); pout("0x%02x%s%s (rev %d) ==\n", page, line, name, data[0] | (data[1] << 8));
// Print entries // Print entries
for (int i = 1, offset = 8; offset < 512-7; i++, offset+=8) { for (int i = 1, offset = 8; offset < 512-7; i++, offset+=8) {
@ -1442,7 +1512,7 @@ static void print_device_statistics_page(const unsigned char * data, int page,
// Stop if unknown entries contain garbage data due to buggy firmware // Stop if unknown entries contain garbage data due to buggy firmware
if (!info && (data[offset+5] || data[offset+6])) { if (!info && (data[offset+5] || data[offset+6])) {
pout("%3d 0x%03x - - [Trailing garbage ignored]\n", page, offset); pout("0x%02x 0x%03x - - [Trailing garbage ignored]\n", page, offset);
break; break;
} }
@ -1469,15 +1539,17 @@ static void print_device_statistics_page(const unsigned char * data, int page,
valstr[0] = '-'; valstr[1] = 0; valstr[0] = '-'; valstr[1] = 0;
} }
pout("%3d 0x%03x %d%c %15s%c %s\n", pout("0x%02x 0x%03x %d %15s %c%c%c%c %s\n",
page, offset, page, offset,
abs(size), abs(size),
(flags & 0x1f ? '+' : ' '), // unknown flags
valstr, valstr,
(flags & 0x20 ? '~' : ' '), // normalized flag ((flags & 0x20) ? 'N' : '-'), // normalized statistics
(info ? info[i].name : "Unknown")); ((flags & 0x10) ? 'D' : '-'), // supports DSN (ACS-3)
if (flags & 0x20) ((flags & 0x08) ? 'C' : '-'), // monitored condition met (ACS-3)
need_trailer = true; ((flags & 0x07) ? '+' : ' '), // reserved flags
( info ? info[i].name :
(page == 0xff) ? "Vendor Specific" // ACS-4
: "Unknown" ));
} }
} }
@ -1494,13 +1566,13 @@ static bool print_device_statistics(ata_device * device, unsigned nsectors,
else else
rc = ataReadSmartLog(device, 0x04, page_0, 1); rc = ataReadSmartLog(device, 0x04, page_0, 1);
if (!rc) { if (!rc) {
pout("Read Device Statistics page 0 failed\n\n"); pout("Read Device Statistics page 0x00 failed\n\n");
return false; return false;
} }
unsigned char nentries = page_0[8]; unsigned char nentries = page_0[8];
if (!(page_0[2] == 0 && nentries > 0)) { if (!(page_0[2] == 0 && nentries > 0)) {
pout("Device Statistics page 0 is invalid (page=%d, nentries=%d)\n\n", page_0[2], nentries); pout("Device Statistics page 0x00 is invalid (page=0x%02x, nentries=%d)\n\n", page_0[2], nentries);
return false; return false;
} }
@ -1519,14 +1591,14 @@ static bool print_device_statistics(ata_device * device, unsigned nsectors,
// Add manually specified pages // Add manually specified pages
bool print_page_0 = false; bool print_page_0 = false;
for (i = 0; i < single_pages.size() || ssd_page; i++) { for (i = 0; i < single_pages.size() || ssd_page; i++) {
int page = (i < single_pages.size() ? single_pages[i] : 7); int page = (i < single_pages.size() ? single_pages[i] : 0x07);
if (!page) if (!page)
print_page_0 = true; print_page_0 = true;
else if (page >= (int)nsectors) else if (page >= (int)nsectors)
pout("Device Statistics Log has only %u pages\n", nsectors); pout("Device Statistics Log has only 0x%02x pages\n", nsectors);
else else
pages.push_back(page); pages.push_back(page);
if (page == 7) if (page == 0x07)
ssd_page = false; ssd_page = false;
} }
@ -1537,8 +1609,7 @@ static bool print_device_statistics(ata_device * device, unsigned nsectors,
pout("Page Description\n"); pout("Page Description\n");
for (i = 0; i < nentries; i++) { for (i = 0; i < nentries; i++) {
int page = page_0[8+1+i]; int page = page_0[8+1+i];
pout("%3d %s\n", page, pout("0x%02x %s\n", page, get_device_statistics_page_name(page));
(page < num_devstat_infos ? devstat_infos[page][0].name : "Unknown Statistics"));
} }
pout("\n"); pout("\n");
} }
@ -1547,8 +1618,7 @@ static bool print_device_statistics(ata_device * device, unsigned nsectors,
if (!pages.empty()) { if (!pages.empty()) {
pout("Device Statistics (%s Log 0x04)\n", pout("Device Statistics (%s Log 0x04)\n",
use_gplog ? "GP" : "SMART"); use_gplog ? "GP" : "SMART");
pout("Page Offset Size Value Description\n"); pout("Page Offset Size Value Flags Description\n");
bool need_trailer = false;
int max_page = 0; int max_page = 0;
if (!use_gplog) if (!use_gplog)
@ -1561,24 +1631,28 @@ static bool print_device_statistics(ata_device * device, unsigned nsectors,
raw_buffer pages_buf((max_page+1) * 512); raw_buffer pages_buf((max_page+1) * 512);
if (!use_gplog && !ataReadSmartLog(device, 0x04, pages_buf.data(), max_page+1)) { if (!use_gplog && !ataReadSmartLog(device, 0x04, pages_buf.data(), max_page+1)) {
pout("Read Device Statistics pages 0-%d failed\n\n", max_page); pout("Read Device Statistics pages 0x00-0x%02x failed\n\n", max_page);
return false; return false;
} }
for (i = 0; i < pages.size(); i++) { for (i = 0; i < pages.size(); i++) {
int page = pages[i]; int page = pages[i];
if (use_gplog && !ataReadLogExt(device, 0x04, 0, page, pages_buf.data(), 1)) { if (use_gplog) {
pout("Read Device Statistics page %d failed\n\n", page); if (!ataReadLogExt(device, 0x04, 0, page, pages_buf.data(), 1)) {
pout("Read Device Statistics page 0x%02x failed\n\n", page);
return false; return false;
} }
}
else if (page > max_page)
continue;
int offset = (use_gplog ? 0 : page * 512); int offset = (use_gplog ? 0 : page * 512);
print_device_statistics_page(pages_buf.data() + offset, page, need_trailer); print_device_statistics_page(pages_buf.data() + offset, page);
} }
if (need_trailer) pout("%32s|||_ C monitored condition met\n", "");
pout("%30s|_ ~ normalized value\n", ""); pout("%32s||__ D supports DSN\n", "");
pout("\n"); pout("%32s|___ N normalized value\n\n", "");
} }
return true; return true;
@ -1641,7 +1715,7 @@ static void PrintSataPhyEventCounters(const unsigned char * data, bool reset)
case 0x010: name = "R_ERR response for host-to-device data FIS, non-CRC"; break; case 0x010: name = "R_ERR response for host-to-device data FIS, non-CRC"; break;
case 0x012: name = "R_ERR response for host-to-device non-data FIS, CRC"; break; case 0x012: name = "R_ERR response for host-to-device non-data FIS, CRC"; break;
case 0x013: name = "R_ERR response for host-to-device non-data FIS, non-CRC"; break; case 0x013: name = "R_ERR response for host-to-device non-data FIS, non-CRC"; break;
default: name = (id & 0x8000 ? "Vendor specific" : "Unknown"); break; default: name = ((id & 0x8000) ? "Vendor specific" : "Unknown"); break;
} }
// Counters stop at max value, add '+' in this case // Counters stop at max value, add '+' in this case
@ -1739,7 +1813,7 @@ static int PrintSmartErrorlog(const ata_smart_errorlog *data,
for (int k = 4; k >= 0; k-- ) { for (int k = 4; k >= 0; k-- ) {
// The error log data structure entries are a circular buffer // The error log data structure entries are a circular buffer
int j, i=(data->error_log_pointer+k)%5; int i = (data->error_log_pointer + k) % 5;
const ata_smart_errorlog_struct * elog = data->errorlog_struct+i; const ata_smart_errorlog_struct * elog = data->errorlog_struct+i;
const ata_smart_errorlog_error_struct * summary = &(elog->error_struct); const ata_smart_errorlog_error_struct * summary = &(elog->error_struct);
@ -1775,7 +1849,7 @@ static int PrintSmartErrorlog(const ata_smart_errorlog *data,
pout(" Commands leading to the command that caused the error were:\n" pout(" Commands leading to the command that caused the error were:\n"
" CR FR SC SN CL CH DH DC Powered_Up_Time Command/Feature_Name\n" " CR FR SC SN CL CH DH DC Powered_Up_Time Command/Feature_Name\n"
" -- -- -- -- -- -- -- -- ---------------- --------------------\n"); " -- -- -- -- -- -- -- -- ---------------- --------------------\n");
for ( j = 4; j >= 0; j--){ for (int j = 4; j >= 0; j--) {
const ata_smart_errorlog_command_struct * thiscommand = elog->commands+j; const ata_smart_errorlog_command_struct * thiscommand = elog->commands+j;
// Spec says: unused data command structures shall be zero filled // Spec says: unused data command structures shall be zero filled
@ -1804,7 +1878,9 @@ static int PrintSmartErrorlog(const ata_smart_errorlog *data,
} }
// Print SMART Extended Comprehensive Error Log (GP Log 0x03) // Print SMART Extended Comprehensive Error Log (GP Log 0x03)
static int PrintSmartExtErrorLog(const ata_smart_exterrlog * log, static int PrintSmartExtErrorLog(ata_device * device,
const firmwarebug_defs & firmwarebugs,
const ata_smart_exterrlog * log,
unsigned nsectors, unsigned max_errors) unsigned nsectors, unsigned max_errors)
{ {
pout("SMART Extended Comprehensive Error Log Version: %u (%u sectors)\n", pout("SMART Extended Comprehensive Error Log Version: %u (%u sectors)\n",
@ -1865,11 +1941,30 @@ static int PrintSmartExtErrorLog(const ata_smart_exterrlog * log,
"DDd+hh:mm:SS.sss where DD=days, hh=hours, mm=minutes,\n" "DDd+hh:mm:SS.sss where DD=days, hh=hours, mm=minutes,\n"
"SS=sec, and sss=millisec. It \"wraps\" after 49.710 days.\n\n"); "SS=sec, and sss=millisec. It \"wraps\" after 49.710 days.\n\n");
// Recently read log page
ata_smart_exterrlog log_buf;
unsigned log_buf_page = ~0;
// Iterate through circular buffer in reverse direction // Iterate through circular buffer in reverse direction
for (unsigned i = 0, errnum = log->device_error_count; for (unsigned i = 0, errnum = log->device_error_count;
i < errcnt; i++, errnum--, erridx = (erridx > 0 ? erridx - 1 : nentries - 1)) { i < errcnt; i++, errnum--, erridx = (erridx > 0 ? erridx - 1 : nentries - 1)) {
const ata_smart_exterrlog_error_log & entry = log[erridx / 4].error_logs[erridx % 4]; // Read log page if needed
const ata_smart_exterrlog * log_p;
unsigned page = erridx / 4;
if (page == 0)
log_p = log;
else {
if (page != log_buf_page) {
memset(&log_buf, 0, sizeof(log_buf));
if (!ataReadExtErrorLog(device, &log_buf, page, 1, firmwarebugs))
break;
log_buf_page = page;
}
log_p = &log_buf;
}
const ata_smart_exterrlog_error_log & entry = log_p->error_logs[erridx % 4];
// Skip unused entries // Skip unused entries
if (!nonempty(&entry, sizeof(entry))) { if (!nonempty(&entry, sizeof(entry))) {
@ -2215,6 +2310,7 @@ static int ataPrintSCTStatus(const ata_sct_status_response * sts)
// T13/e06152r0-3 (Additional SCT Temperature Statistics), August - October 2006 // T13/e06152r0-3 (Additional SCT Temperature Statistics), August - October 2006
// Table 60 of T13/1699-D (ATA8-ACS) Revision 3f, December 2006 (format version 2) // Table 60 of T13/1699-D (ATA8-ACS) Revision 3f, December 2006 (format version 2)
// Table 80 of T13/1699-D (ATA8-ACS) Revision 6a, September 2008 (format version 3) // Table 80 of T13/1699-D (ATA8-ACS) Revision 6a, September 2008 (format version 3)
// Table 182 of T13/BSR INCITS 529 (ACS-4) Revision 02a, May 22, 2014 (smart_status field)
pout("Current Temperature: %s Celsius\n", pout("Current Temperature: %s Celsius\n",
sct_ptemp(sts->hda_temp, buf1)); sct_ptemp(sts->hda_temp, buf1));
pout("Power Cycle Min/Max Temperature: %s/%s Celsius\n", pout("Power Cycle Min/Max Temperature: %s/%s Celsius\n",
@ -2226,6 +2322,17 @@ static int ataPrintSCTStatus(const ata_sct_status_response * sts)
pout("Lifetime Average Temperature: %2d Celsius\n", avg); pout("Lifetime Average Temperature: %2d Celsius\n", avg);
pout("Under/Over Temperature Limit Count: %2u/%u\n", pout("Under/Over Temperature Limit Count: %2u/%u\n",
sts->under_limit_count, sts->over_limit_count); sts->under_limit_count, sts->over_limit_count);
if (sts->smart_status) // ACS-4
pout("SMART Status: 0x%04x (%s)\n", sts->smart_status,
(sts->smart_status == 0x2cf4 ? "FAILED" :
sts->smart_status == 0xc24f ? "PASSED" : "Reserved"));
if (nonempty(sts->vendor_specific, sizeof(sts->vendor_specific))) {
pout("Vendor specific:\n");
for (unsigned i = 0; i < sizeof(sts->vendor_specific); i++)
pout("%02x%c", sts->vendor_specific[i], ((i & 0xf) != 0xf ? ' ' : '\n'));
}
} }
return 0; return 0;
} }
@ -2425,6 +2532,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
if (options.powermode) { if (options.powermode) {
unsigned char powerlimit = 0xff; unsigned char powerlimit = 0xff;
int powermode = ataCheckPowerMode(device); int powermode = ataCheckPowerMode(device);
// TODO: Move to new function used by smartctl and smartd.
switch (powermode) { switch (powermode) {
case -1: case -1:
if (device->is_syscall_unsup()) { if (device->is_syscall_unsup()) {
@ -2432,12 +2540,28 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
} }
powername = "SLEEP"; powerlimit = 2; powername = "SLEEP"; powerlimit = 2;
break; break;
case 0: // Table 215 of T13/2015-D (ACS-2) Revision 7, June 22, 2011
// Table 293 of T13/BSR INCITS 529 (ACS-4) Revision 12, February 18, 2016
case 0x00: // PM2:Standby, EPC unavailable or Standby_z power condition
powername = "STANDBY"; powerlimit = 3; break; powername = "STANDBY"; powerlimit = 3; break;
case 0x80: case 0x01: // PM2:Standby, Standby_y power condition
powername = "STANDBY_Y"; powerlimit = 3; break;
case 0x80: // PM1:Idle, EPC unavailable
powername = "IDLE"; powerlimit = 4; break; powername = "IDLE"; powerlimit = 4; break;
case 0xff: case 0x81: // PM1:Idle, Idle_a power condition
powername = "IDLE_A"; powerlimit = 4; break;
case 0x82: // PM1:Idle, Idle_b power condition
powername = "IDLE_B"; powerlimit = 4; break;
case 0x83: // PM1:Idle, Idle_c power condition
powername = "IDLE_C"; powerlimit = 4; break;
// 0x40/41 were declared obsolete in ACS-3 Revision 1
case 0x40: // PM0:Active, NV Cache power mode enabled, spun down
powername = "ACTIVE_NV_DOWN"; break;
case 0x41: // PM0:Active, NV Cache power mode enabled, spun up
powername = "ACTIVE_NV_UP" ; break;
case 0xff: // PM0:Active or PM1:Idle
powername = "ACTIVE or IDLE"; break; powername = "ACTIVE or IDLE"; break;
default: default:
pout("CHECK POWER MODE returned unknown value 0x%02x, ignoring -n option\n", powermode); pout("CHECK POWER MODE returned unknown value 0x%02x, ignoring -n option\n", powermode);
break; break;
@ -2669,13 +2793,21 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
!(drive.cfs_enable_1 & 0x0020) ? "Disabled" : "Enabled"); // word085 !(drive.cfs_enable_1 & 0x0020) ? "Disabled" : "Enabled"); // word085
} }
// Print ATA security status // Check for ATA Security LOCK
unsigned short word128 = drive.words088_255[128-88];
bool locked = ((word128 & 0x0007) == 0x0007); // LOCKED|ENABLED|SUPPORTED
// Print ATA Security status
if (options.get_security) if (options.get_security)
print_ata_security_status("ATA Security is: ", drive.words088_255[128-88]); print_ata_security_status("ATA Security is: ", word128);
// Print write cache reordering status // Print write cache reordering status
if (options.sct_wcache_reorder_get) { if (options.sct_wcache_reorder_get) {
if (isSCTFeatureControlCapable(&drive)) { if (!isSCTFeatureControlCapable(&drive))
pout("Wt Cache Reorder: Unavailable\n");
else if (locked)
pout("Wt Cache Reorder: Unknown (SCT not supported if ATA Security is LOCKED)\n");
else {
int wcache_reorder = ataGetSetSCTWriteCacheReordering(device, int wcache_reorder = ataGetSetSCTWriteCacheReordering(device,
false /*enable*/, false /*persistent*/, false /*set*/); false /*enable*/, false /*persistent*/, false /*set*/);
@ -2687,8 +2819,6 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
else else
pout("Wt Cache Reorder: Unknown (0x%02x)\n", wcache_reorder); pout("Wt Cache Reorder: Unknown (0x%02x)\n", wcache_reorder);
} }
else
pout("Wt Cache Reorder: Unavailable\n");
} }
// Print remaining drive info // Print remaining drive info
@ -2780,6 +2910,9 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
if (!isSCTFeatureControlCapable(&drive)) if (!isSCTFeatureControlCapable(&drive))
pout("Write cache reordering %sable failed: SCT Feature Control command not supported\n", pout("Write cache reordering %sable failed: SCT Feature Control command not supported\n",
(enable ? "en" : "dis")); (enable ? "en" : "dis"));
else if (locked)
pout("Write cache reordering %sable failed: SCT not supported if ATA Security is LOCKED\n",
(enable ? "en" : "dis"));
else if (ataGetSetSCTWriteCacheReordering(device, else if (ataGetSetSCTWriteCacheReordering(device,
enable, false /*persistent*/, true /*set*/) < 0) { enable, false /*persistent*/, true /*set*/) < 0) {
pout("Write cache reordering %sable failed: %s\n", (enable ? "en" : "dis"), device->get_errmsg()); pout("Write cache reordering %sable failed: %s\n", (enable ? "en" : "dis"), device->get_errmsg());
@ -3046,7 +3179,8 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
// If GP Log is supported use smart log directory for // If GP Log is supported use smart log directory for
// error and selftest log support check. // error and selftest log support check.
if ( isGeneralPurposeLoggingCapable(&drive) bool gp_log_supported = !!isGeneralPurposeLoggingCapable(&drive);
if ( gp_log_supported
&& ( options.smart_error_log || options.smart_selftest_log && ( options.smart_error_log || options.smart_selftest_log
|| options.retry_error_log || options.retry_selftest_log)) || options.retry_error_log || options.retry_selftest_log))
need_smart_logdir = true; need_smart_logdir = true;
@ -3070,6 +3204,10 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
if (need_gp_logdir) { if (need_gp_logdir) {
if (firmwarebugs.is_set(BUG_NOLOGDIR)) if (firmwarebugs.is_set(BUG_NOLOGDIR))
gplogdir = fake_logdir(&gplogdir_buf, options); gplogdir = fake_logdir(&gplogdir_buf, options);
else if (!gp_log_supported && !is_permissive()) {
if (options.gp_logdir)
pout("General Purpose Log Directory not supported\n\n");
}
else if (ataReadLogDirectory(device, &gplogdir_buf, true)) { else if (ataReadLogDirectory(device, &gplogdir_buf, true)) {
pout("Read GP Log Directory failed\n\n"); pout("Read GP Log Directory failed\n\n");
failuretest(OPTIONAL_CMD, returnval|=FAILSMART); failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
@ -3142,17 +3280,16 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
unsigned nsectors = GetNumLogSectors(gplogdir, 0x03, true); unsigned nsectors = GetNumLogSectors(gplogdir, 0x03, true);
if (!nsectors) if (!nsectors)
pout("SMART Extended Comprehensive Error Log (GP Log 0x03) not supported\n\n"); pout("SMART Extended Comprehensive Error Log (GP Log 0x03) not supported\n\n");
else if (nsectors >= 256)
pout("SMART Extended Comprehensive Error Log size %u not supported\n\n", nsectors);
else { else {
raw_buffer log_03_buf(nsectors * 512); // Read only first sector to get error count and index
ata_smart_exterrlog * log_03 = (ata_smart_exterrlog *)log_03_buf.data(); // Print function will read more sectors as needed
if (!ataReadExtErrorLog(device, log_03, nsectors, firmwarebugs)) { ata_smart_exterrlog log_03; memset(&log_03, 0, sizeof(log_03));
if (!ataReadExtErrorLog(device, &log_03, 0, 1, firmwarebugs)) {
pout("Read SMART Extended Comprehensive Error Log failed\n\n"); pout("Read SMART Extended Comprehensive Error Log failed\n\n");
failuretest(OPTIONAL_CMD, returnval|=FAILSMART); failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
} }
else { else {
if (PrintSmartExtErrorLog(log_03, nsectors, options.smart_ext_error_log)) if (PrintSmartExtErrorLog(device, firmwarebugs, &log_03, nsectors, options.smart_ext_error_log))
returnval |= FAILERR; returnval |= FAILERR;
ok = true; ok = true;
} }
@ -3168,8 +3305,9 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
// Print SMART error log // Print SMART error log
if (do_smart_error_log) { if (do_smart_error_log) {
if (!( ( smartlogdir && GetNumLogSectors(smartlogdir, 0x01, false)) if (!( GetNumLogSectors(smartlogdir, 0x01, false)
|| (!smartlogdir && isSmartErrorLogCapable(&smartval, &drive) ) || ( !(smartlogdir && gp_log_supported)
&& isSmartErrorLogCapable(&smartval, &drive))
|| is_permissive() )) { || is_permissive() )) {
pout("SMART Error Log not supported\n\n"); pout("SMART Error Log not supported\n\n");
} }
@ -3199,7 +3337,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
pout("SMART Extended Self-test Log size %u not supported\n\n", nsectors); pout("SMART Extended Self-test Log size %u not supported\n\n", nsectors);
else { else {
raw_buffer log_07_buf(nsectors * 512); raw_buffer log_07_buf(nsectors * 512);
ata_smart_extselftestlog * log_07 = (ata_smart_extselftestlog *)log_07_buf.data(); ata_smart_extselftestlog * log_07 = reinterpret_cast<ata_smart_extselftestlog *>(log_07_buf.data());
if (!ataReadExtSelfTestLog(device, log_07, nsectors)) { if (!ataReadExtSelfTestLog(device, log_07, nsectors)) {
pout("Read SMART Extended Self-test Log failed\n\n"); pout("Read SMART Extended Self-test Log failed\n\n");
failuretest(OPTIONAL_CMD, returnval|=FAILSMART); failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
@ -3221,8 +3359,9 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
// Print SMART self-test log // Print SMART self-test log
if (do_smart_selftest_log) { if (do_smart_selftest_log) {
if (!( ( smartlogdir && GetNumLogSectors(smartlogdir, 0x06, false)) if (!( GetNumLogSectors(smartlogdir, 0x06, false)
|| (!smartlogdir && isSmartTestLogCapable(&smartval, &drive) ) || ( !(smartlogdir && gp_log_supported)
&& isSmartTestLogCapable(&smartval, &drive))
|| is_permissive() )) { || is_permissive() )) {
pout("SMART Self-test Log not supported\n\n"); pout("SMART Self-test Log not supported\n\n");
} }
@ -3266,9 +3405,15 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
// Check if SCT commands available // Check if SCT commands available
bool sct_ok = isSCTCapable(&drive); bool sct_ok = isSCTCapable(&drive);
if(!sct_ok && (options.sct_temp_sts || options.sct_temp_hist || options.sct_temp_int if ( options.sct_temp_sts || options.sct_temp_hist || options.sct_temp_int
|| options.sct_erc_get || options.sct_erc_set )) || options.sct_erc_get || options.sct_erc_set ) {
if (!sct_ok)
pout("SCT Commands not supported\n\n"); pout("SCT Commands not supported\n\n");
else if (locked) {
pout("SCT Commands not supported if ATA Security is LOCKED\n\n");
sct_ok = false;
}
}
// Print SCT status and temperature history table // Print SCT status and temperature history table
if (sct_ok && (options.sct_temp_sts || options.sct_temp_hist || options.sct_temp_int)) { if (sct_ok && (options.sct_temp_sts || options.sct_temp_hist || options.sct_temp_int)) {

View File

@ -1,7 +1,7 @@
/* /*
* ataprint.h * ataprint.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2002-9 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2002-9 Bruce Allen <smartmontools-support@lists.sourceforge.net>
* Copyright (C) 2008-12 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2008-12 Christian Franke <smartmontools-support@lists.sourceforge.net>
@ -25,7 +25,7 @@
#ifndef ATAPRINT_H_ #ifndef ATAPRINT_H_
#define ATAPRINT_H_ #define ATAPRINT_H_
#define ATAPRINT_H_CVSID "$Id: ataprint.h 3825 2013-07-06 21:38:25Z samm2 $\n" #define ATAPRINT_H_CVSID "$Id: ataprint.h 4120 2015-08-27 16:12:21Z samm2 $\n"
#include <vector> #include <vector>

View File

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
# $Id: autogen.sh 3917 2014-06-20 19:57:41Z chrfranke $ # $Id: autogen.sh 4115 2015-07-15 20:52:26Z chrfranke $
# #
# Generate ./configure from config.in and Makefile.in from Makefile.am. # Generate ./configure from configure.ac and Makefile.in from Makefile.am.
# This also adds files like missing,depcomp,install-sh to the source # This also adds files like missing,depcomp,install-sh to the source
# directory. To update these files at a later date use: # directory. To update these files at a later date use:
# autoreconf -f -i -v # autoreconf -f -i -v
@ -23,81 +23,44 @@ test -x /usr/bin/uname && /usr/bin/uname | grep -i CYGWIN >/dev/null &&
rm -f dostest.tmp rm -f dostest.tmp
} }
typep() # Find automake
{ if [ -n "$AUTOMAKE" ]; then
cmd=$1 ; TMP=$IFS ; IFS=: ; set $PATH ver=$("$AUTOMAKE" --version) || exit 1
for dir else
do maxver=
if [ -x "$dir/$cmd" ]; then for v in 1.15 1.14 1.13 1.12 1.11 1.10; do
echo "$dir/$cmd" minver=$v; test -n "$maxver" || maxver=$v
IFS=$TMP ver=$(automake-$v --version 2>/dev/null) || continue
return 0 AUTOMAKE="automake-$v"
fi break
done done
IFS=$TMP if [ -z "$AUTOMAKE" ]; then
return 1 echo "GNU Automake $minver (up to $maxver) is required to bootstrap smartmontools from SVN."
} exit 1;
fi
fi
test -x "$AUTOMAKE" || ver=$(echo "$ver" | sed -n '1s,^.*[^.0-9]\([12]\.[0-9][-.0-9pl]*\).*$,\1,p')
AUTOMAKE=`typep automake-1.14` || if [ -z "$ver" ]; then
AUTOMAKE=`typep automake-1.13` || AUTOMAKE=`typep automake-1.12` || echo "$AUTOMAKE: Unable to determine automake version."
AUTOMAKE=`typep automake-1.11` || AUTOMAKE=`typep automake-1.10` || exit 1
AUTOMAKE=`typep automake-1.9` || AUTOMAKE=`typep automake-1.8` || fi
AUTOMAKE=`typep automake-1.7` || AUTOMAKE=`typep automake17` ||
{
echo
echo "You must have at least GNU Automake 1.7 (up to 1.14) installed"
echo "in order to bootstrap smartmontools from SVN. Download the"
echo "appropriate package for your distribution, or the source tarball"
echo "from ftp://ftp.gnu.org/gnu/automake/ ."
echo
echo "Also note that support for new Automake series (anything newer"
echo "than 1.14) is only added after extensive tests. If you live in"
echo "the bleeding edge, you should know what you're doing, mainly how"
echo "to test it before the developers. Be patient."
exit 1;
}
test -x "$ACLOCAL" || ACLOCAL="aclocal`echo "$AUTOMAKE" | sed 's/.*automake//'`" && ACLOCAL=`typep "$ACLOCAL"` || # Check aclocal
{ if [ -z "$ACLOCAL" ]; then
echo ACLOCAL="aclocal$(echo "$AUTOMAKE" | sed -n 's,^.*automake\(-[.0-9]*\),\1,p')"
echo "autogen.sh found automake-1.X, but not the respective aclocal-1.X." fi
echo "Your installation of GNU Automake is broken or incomplete."
exit 2;
}
# Detect Automake version "$ACLOCAL" --version >/dev/null || exit 1
case "$AUTOMAKE" in
*automake-1.7|*automake17)
ver=1.7 ;;
*automake-1.8)
ver=1.8 ;;
*)
ver="`$AUTOMAKE --version | sed -n '1s,^.*[^.0-9]\([12]\.[0-9][-.0-9pl]*\).*$,\1,p'`"
ver="${ver:-?.?.?}"
esac
# Warn if Automake version was not tested or does not support filesystem # Warn if Automake version was not tested
amwarnings=$warnings amwarnings=$warnings
case "$ver" in case "$ver" in
1.[78]|1.[78].*) 1.10|1.10.[123]|1.11|1.11.[1-6]|1.12.[2-6]|1.13.[34])
# Check for case sensitive filesystem
# (to avoid e.g. "DIST_COMMON = ... ChangeLog ..." in Makefile.in on Cygwin)
rm -f CASETEST.TMP
echo > casetest.tmp
test -f CASETEST.TMP &&
{
echo "Warning: GNU Automake version ${ver} does not properly handle case"
echo "insensitive filesystems. Some make targets may not work."
}
rm -f casetest.tmp
;;
1.9.[1-6]|1.10|1.10.[123]|1.11|1.11.[1-6]|1.12.[2-6]|1.13.[34])
# OK # OK
;; ;;
1.14|1.14.1) 1.14|1.14.1|1.15)
# TODO: Enable 'subdir-objects' in configure.ac # TODO: Enable 'subdir-objects' in configure.ac
# For now, suppress 'subdir-objects' forward-incompatibility warning # For now, suppress 'subdir-objects' forward-incompatibility warning
test -n "$warnings" || amwarnings="--warnings=no-unsupported" test -n "$warnings" || amwarnings="--warnings=no-unsupported"
@ -108,24 +71,14 @@ case "$ver" in
echo "Please report success/failure to the smartmontools-support mailing list." echo "Please report success/failure to the smartmontools-support mailing list."
esac esac
# Install pkg-config macros # required for aclocal-1.10 --install
# (Don't use 'aclocal -I m4 --install' to keep support for automake < 1.10)
test -d m4 || mkdir m4 || exit 1 test -d m4 || mkdir m4 || exit 1
test -z "$force" || rm -f m4/pkg.m4
test -f m4/pkg.m4 || acdir=`${ACLOCAL} --print-ac-dir` &&
test -n "$acdir" && test -f "$acdir/pkg.m4" &&
{
echo "$0: installing \`m4/pkg.m4' from \`$acdir/pkg.m4'"
cp "$acdir/pkg.m4" m4/pkg.m4
}
test -f m4/pkg.m4 ||
echo "Warning: cannot install m4/pkg.m4, 'make dist' and systemd detection will not work."
set -e # stops on error status set -e # stops on error status
test -z "$warnings" || set -x test -z "$warnings" || set -x
${ACLOCAL} -I m4 $force $warnings ${ACLOCAL} -I m4 --install $force $warnings
autoheader $force $warnings autoheader $force $warnings
${AUTOMAKE} --add-missing --copy ${force:+--force-missing} $amwarnings ${AUTOMAKE} --add-missing --copy ${force:+--force-missing} $amwarnings
autoconf $force $warnings autoconf $force $warnings

View File

@ -38,7 +38,7 @@
#include "scsicmds.h" #include "scsicmds.h"
#include "utility.h" #include "utility.h"
const char * cciss_cpp_cvsid = "$Id: cciss.cpp 3945 2014-07-13 15:29:05Z chrfranke $" const char * cciss_cpp_cvsid = "$Id: cciss.cpp 4156 2015-10-18 12:20:40Z samm2 $"
CCISS_H_CVSID; CCISS_H_CVSID;
typedef struct _ReportLUNdata_struct typedef struct _ReportLUNdata_struct
@ -73,10 +73,9 @@ int cciss_io_interface(int device, int target, struct scsi_cmnd_io * iop, int re
unsigned char pBuf[512] = {0}; unsigned char pBuf[512] = {0};
unsigned char phylun[8] = {0}; unsigned char phylun[8] = {0};
int iBufLen = 512; int iBufLen = 512;
int status = -1;
int len = 0; // used later in the code. int len = 0; // used later in the code.
status = cciss_getlun(device, target, phylun, report); int status = cciss_getlun(device, target, phylun, report);
if (report > 0) if (report > 0)
printf(" cciss_getlun(%d, %d) = 0x%x; scsi3addr: %02x %02x %02x %02x %02x %02x %02x %02x\n", printf(" cciss_getlun(%d, %d) = 0x%x; scsi3addr: %02x %02x %02x %02x %02x %02x %02x %02x\n",
device, target, status, device, target, status,
@ -181,7 +180,7 @@ static int cciss_sendpassthru(unsigned int cmdtype, unsigned char *CDB,
if ((err = ioctl(fd, CCISS_PASSTHRU, &iocommand))) if ((err = ioctl(fd, CCISS_PASSTHRU, &iocommand)))
{ {
fprintf(stderr, "CCISS ioctl error %d (fd %d CDBLen %d buf_size %d)\n", fprintf(stderr, "CCISS ioctl error %d (fd %d CDBLen %u buf_size %u)\n",
fd, err, CDBlen, size); fd, err, CDBlen, size);
} }
return err; return err;

View File

@ -1,25 +1,24 @@
# #
# $Id: configure.ac 3977 2014-07-26 11:03:24Z chrfranke $ # $Id: configure.ac 4319 2016-05-07 12:14:20Z chrfranke $
# #
dnl Process this file with autoconf to produce a configure script. dnl Process this file with autoconf to produce a configure script.
AC_PREREQ(2.50) AC_PREREQ([2.60])
AC_INIT(smartmontools, 6.4, smartmontools-support@lists.sourceforge.net) AC_INIT(smartmontools, 6.6, smartmontools-support@lists.sourceforge.net)
AC_CONFIG_SRCDIR(smartctl.cpp) AM_INIT_AUTOMAKE([1.10 foreign])
smartmontools_cvs_tag=`echo '$Id: configure.ac 3977 2014-07-26 11:03:24Z chrfranke $'` smartmontools_cvs_tag=`echo '$Id: configure.ac 4319 2016-05-07 12:14:20Z chrfranke $'`
smartmontools_release_date=2014-07-26 smartmontools_release_date=2016-05-07
smartmontools_release_time="09:49:11 UTC" smartmontools_release_time="11:17:46 UTC"
AC_DEFINE_UNQUOTED(SMARTMONTOOLS_CONFIGURE_ARGS, "$ac_configure_args", [smartmontools Configure Arguments]) AC_DEFINE_UNQUOTED(SMARTMONTOOLS_CONFIGURE_ARGS, "$ac_configure_args", [smartmontools Configure Arguments])
AC_DEFINE_UNQUOTED(SMARTMONTOOLS_RELEASE_DATE, "$smartmontools_release_date", [smartmontools Release Date]) AC_DEFINE_UNQUOTED(SMARTMONTOOLS_RELEASE_DATE, "$smartmontools_release_date", [smartmontools Release Date])
AC_DEFINE_UNQUOTED(SMARTMONTOOLS_RELEASE_TIME, "$smartmontools_release_time", [smartmontools Release Time]) AC_DEFINE_UNQUOTED(SMARTMONTOOLS_RELEASE_TIME, "$smartmontools_release_time", [smartmontools Release Time])
AC_DEFINE_UNQUOTED(CONFIG_H_CVSID, "$smartmontools_cvs_tag", [smartmontools CVS Tag]) AC_DEFINE_UNQUOTED(CONFIG_H_CVSID, "$smartmontools_cvs_tag", [smartmontools CVS Tag])
AC_DEFINE_UNQUOTED(PACKAGE_HOMEPAGE, "http://smartmontools.sourceforge.net/", [smartmontools Home Page]) AC_DEFINE_UNQUOTED(PACKAGE_HOMEPAGE, "http://www.smartmontools.org/", [smartmontools Home Page])
AC_CONFIG_SRCDIR([smartctl.cpp])
AC_CONFIG_HEADER([config.h]) AC_CONFIG_HEADER([config.h])
AM_INIT_AUTOMAKE([foreign])
AM_MAINTAINER_MODE AM_MAINTAINER_MODE
AC_LANG([C++]) AC_LANG([C++])
@ -84,7 +83,6 @@ AC_MSG_RESULT([$is_svn_build])
dnl Checks for header files. dnl Checks for header files.
AC_CHECK_HEADERS([locale.h]) AC_CHECK_HEADERS([locale.h])
AC_CHECK_HEADERS([dev/ata/atavar.h]) AC_CHECK_HEADERS([dev/ata/atavar.h])
AC_CHECK_HEADERS([netdb.h])
dnl we need [u]int64_t and friends. dnl we need [u]int64_t and friends.
AC_CHECK_HEADERS([inttypes.h]) dnl C99, UNIX98, solaris 2.6+ AC_CHECK_HEADERS([inttypes.h]) dnl C99, UNIX98, solaris 2.6+
AC_CHECK_HEADERS([stdint.h]) dnl C99 AC_CHECK_HEADERS([stdint.h]) dnl C99
@ -149,16 +147,9 @@ AC_SUBST(CPPFLAGS)
AC_SUBST(LDFLAGS) AC_SUBST(LDFLAGS)
AC_SUBST(ASFLAGS) AC_SUBST(ASFLAGS)
AC_ARG_WITH(systemdenvfile,
[AS_HELP_STRING([--with-systemdenvfile=@<:@FILE|no@:>@],
[Path of systemd EnvironmentFile (implies --with-systemdsystemunitdir=yes) [SYSCONFDIR/sysconfig/smartmontools]])],
[systemdenvfile=; test "$withval" != "no" && systemdenvfile="$withval"; systemd_default=yes],
[systemdenvfile='${sysconfdir}/sysconfig/smartmontools'; systemd_default=auto])
AC_SUBST(systemdenvfile)
AC_ARG_WITH(systemdsystemunitdir, AC_ARG_WITH(systemdsystemunitdir,
[AS_HELP_STRING([--with-systemdsystemunitdir@<:@=DIR|auto|yes|no@:>@], [Location of systemd service files [auto]])], [AS_HELP_STRING([--with-systemdsystemunitdir@<:@=DIR|auto|yes|no@:>@], [Location of systemd service files [auto]])],
[], [with_systemdsystemunitdir=$systemd_default]) [], [with_systemdsystemunitdir=auto])
systemdsystemunitdir= systemdsystemunitdir=
case "$with_systemdsystemunitdir" in case "$with_systemdsystemunitdir" in
@ -179,6 +170,30 @@ esac
AC_SUBST(systemdsystemunitdir) AC_SUBST(systemdsystemunitdir)
AM_CONDITIONAL(INSTALL_SYSTEMDUNIT, [test -n "$systemdsystemunitdir"]) AM_CONDITIONAL(INSTALL_SYSTEMDUNIT, [test -n "$systemdsystemunitdir"])
AC_ARG_WITH(systemdenvfile,
[AS_HELP_STRING([--with-systemdenvfile@<:@=FILE|auto|yes|no@:>@], [Path of systemd EnvironmentFile [auto]])],
[], [with_systemdenvfile=auto])
systemdenvfile=
case "$with_systemdenvfile:$cross_compiling:$systemdsystemunitdir" in
auto:no:?*|yes:*:?*)
AC_MSG_CHECKING([for path of systemd EnvironmentFile])
for dir in sysconfig default; do
if test -d /etc/$dir; then
systemdenvfile='${sysconfdir}'/$dir/smartmontools
break
fi
done
AC_MSG_RESULT([${systemdenvfile:-no}])
case "$with_systemdenvfile:$systemdenvfile" in
yes:) AC_MSG_ERROR([Path of systemd EnvironmentFile not found]) ;;
esac ;;
auto:*|no:*) ;;
*:*:) AC_MSG_ERROR([Location of systemd service files not found]) ;;
*) systemdenvfile="$with_systemdenvfile"
esac
AC_SUBST(systemdenvfile)
AC_ARG_WITH(initscriptdir, AC_ARG_WITH(initscriptdir,
[AS_HELP_STRING([--with-initscriptdir@<:@=DIR|auto|yes|no@:>@], [Location of init scripts [auto]])], [AS_HELP_STRING([--with-initscriptdir@<:@=DIR|auto|yes|no@:>@], [Location of init scripts [auto]])],
[], [with_initscriptdir=auto]) [], [with_initscriptdir=auto])
@ -208,37 +223,33 @@ case "${host}" in
*-*-freebsd*) *-*-freebsd*)
initdfile="smartd.freebsd.initd" initdfile="smartd.freebsd.initd"
;; ;;
*-apple-darwin*)
initdfile="com.smartmontools.smartd.plist"
;;
*) *)
initdfile="smartd.initd" initdfile="smartd.initd"
;; ;;
esac esac
AC_SUBST(initdfile) AC_SUBST(initdfile)
AC_ARG_WITH(docdir,
[AS_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}'
fi
])
AC_SUBST(docdir)
AC_ARG_WITH(exampledir, AC_ARG_WITH(exampledir,
[AS_HELP_STRING([--with-exampledir=DIR], [Location of example scripts [DOCDIR/examplescripts]])], [AS_HELP_STRING([--with-exampledir=DIR], [Location of example scripts [DOCDIR/examplescripts]])],
[exampledir="$withval"], [exampledir='${docdir}/examplescripts']) [exampledir="$withval"], [exampledir='${docdir}/examplescripts'])
AC_SUBST(exampledir) AC_SUBST(exampledir)
AC_ARG_ENABLE(drivedb, drivedbdir='${datadir}/${PACKAGE}'
[AS_HELP_STRING([--disable-drivedb], [Disables drive database file])],
[], [enable_drivedb=yes])
AC_ARG_WITH(drivedbdir, AC_ARG_WITH(drivedbdir,
[AS_HELP_STRING([--with-drivedbdir=DIR], [Location of drive database file [DATADIR/smartmontools]])], [AS_HELP_STRING([--with-drivedbdir@<:@=DIR|yes|no@:>@], [Location of drive database file [DATADIR/smartmontools]])],
[drivedbdir="$withval"; enable_drivedb=yes], [case "$withval" in yes) ;; no) drivedbdir= ;; *) drivedbdir="$withval" ;; esac])
[drivedbdir=; test "$enable_drivedb" = "yes" && drivedbdir='${datadir}/${PACKAGE}'])
AC_SUBST(drivedbdir) AC_SUBST(drivedbdir)
AM_CONDITIONAL(ENABLE_DRIVEDB, [test "$enable_drivedb" = "yes"]) AM_CONDITIONAL(ENABLE_DRIVEDB, [test -n "$drivedbdir"])
AC_ARG_WITH(update-smart_drivedb,
[AS_HELP_STRING([--with-update-smart-drivedb@<:@=yes|no@:>@], [Install update-smart-drivedb script [yes]])],
[], [with_update_smart_drivedb=yes])
test -n "$drivedbdir" || with_update_smart_drivedb=no
AC_SUBST(with_update_smart_drivedb)
AM_CONDITIONAL(ENABLE_UPDATE_SMART_DRIVEDB, [test "$with_update_smart_drivedb" = "yes"])
AC_ARG_WITH(smartdscriptdir, AC_ARG_WITH(smartdscriptdir,
[AS_HELP_STRING([--with-smartdscriptdir=DIR], [Location of smartd_warning.sh script [SYSCONFDIR]])], [AS_HELP_STRING([--with-smartdscriptdir=DIR], [Location of smartd_warning.sh script [SYSCONFDIR]])],
@ -252,29 +263,27 @@ AC_ARG_WITH(smartdplugindir,
[smartdplugindir='${smartdscriptdir}/smartd_warning.d']) [smartdplugindir='${smartdscriptdir}/smartd_warning.d'])
AC_SUBST(smartdplugindir) AC_SUBST(smartdplugindir)
AC_ARG_ENABLE(savestates, [AS_HELP_STRING([--enable-savestates], [Enables default smartd state files])]) savestates=
AC_ARG_WITH(savestates, AC_ARG_WITH(savestates,
[AS_HELP_STRING([--with-savestates=PREFIX], [AS_HELP_STRING([--with-savestates@<:@=PREFIX|yes|no@:>@],
[Prefix for default smartd state files (implies --enable-savestates) [LOCALSTATEDIR/lib/smartmontools/smartd.]])], [Enable default smartd state files [no] (yes=LOCALSTATEDIR/lib/smartmontools/smartd.)])],
[savestates="$withval"; enable_savestates="yes"], [case "$withval" in yes) savestates='${localstatedir}/lib/${PACKAGE}/smartd.' ;;
[savestates=; test "$enable_savestates" = "yes" && savestates='${localstatedir}/lib/${PACKAGE}/smartd.']) no) ;; *) savestates="$withval" ;; esac])
savestatesdir="${savestates%/*}" savestatesdir="${savestates%/*}"
AC_SUBST(savestates) AC_SUBST(savestates)
AC_SUBST(savestatesdir) AC_SUBST(savestatesdir)
AM_CONDITIONAL(ENABLE_SAVESTATES, [test "$enable_savestates" = "yes"]) AM_CONDITIONAL(ENABLE_SAVESTATES, [test -n "$savestates"])
AC_ARG_ENABLE(attributelog, [AS_HELP_STRING([--enable-attributelog], [Enables default smartd attribute log files])])
attributelog=
AC_ARG_WITH(attributelog, AC_ARG_WITH(attributelog,
[AS_HELP_STRING([--with-attributelog=PREFIX], [AS_HELP_STRING([--with-attributelog@<:@=PREFIX|yes|no@:>@],
[Prefix for default smartd attribute log files (implies --enable-attributelog) [LOCALSTATEDIR/lib/smartmontools/attrlog.]])], [Enable default smartd attribute log files [no] (yes=LOCALSTATEDIR/lib/smartmontools/attrlog.)])],
[attributelog="$withval"; enable_attributelog="yes"], [case "$withval" in yes) attributelog='${localstatedir}/lib/${PACKAGE}/attrlog.' ;;
[attributelog=; test "$enable_attributelog" = "yes" && attributelog='${localstatedir}/lib/${PACKAGE}/attrlog.']) no) ;; *) attributelog="$withval" ;; esac])
attributelogdir="${attributelog%/*}" attributelogdir="${attributelog%/*}"
AC_SUBST(attributelog) AC_SUBST(attributelog)
AC_SUBST(attributelogdir) AC_SUBST(attributelogdir)
AM_CONDITIONAL(ENABLE_ATTRIBUTELOG, [test "$enable_attributelog" = "yes"]) AM_CONDITIONAL(ENABLE_ATTRIBUTELOG, [test -n "$attributelog"])
AC_ARG_ENABLE(sample, AC_ARG_ENABLE(sample,
[AS_HELP_STRING([--enable-sample], [Enables appending .sample to the installed smartd rc script and configuration file])], [AS_HELP_STRING([--enable-sample], [Enables appending .sample to the installed smartd rc script and configuration file])],
@ -311,7 +320,7 @@ AC_ARG_WITH(libcap-ng,
use_libcap_ng=no use_libcap_ng=no
if test "$with_libcap_ng" != "no"; then if test "$with_libcap_ng" != "no"; then
AC_CHECK_LIB(cap-ng, capng_clear, AC_CHECK_LIB(cap-ng, capng_clear,
[AC_DEFINE(HAVE_LIBCAP_NG, 1, [Define to 1 if you have the `cap-ng' library (-lcap-ng).]) [AC_DEFINE(HAVE_LIBCAP_NG, 1, [Define to 1 if you have the `cap-ng' library (-lcap-ng).]) dnl `vim syntax
CAPNG_LDADD="-lcap-ng"; use_libcap_ng=yes]) CAPNG_LDADD="-lcap-ng"; use_libcap_ng=yes])
if test "$use_libcap_ng" = "yes"; then if test "$use_libcap_ng" = "yes"; then
@ -323,9 +332,32 @@ fi
AC_MSG_CHECKING([whether to use libcap-ng]) AC_MSG_CHECKING([whether to use libcap-ng])
AC_SUBST(CAPNG_LDADD) AC_SUBST(CAPNG_LDADD)
AM_CONDITIONAL(ENABLE_CAPABILITIES, [test "$use_libcap_ng" = "yes"])
AC_MSG_RESULT([$use_libcap_ng]) AC_MSG_RESULT([$use_libcap_ng])
# TODO: Remove when NVMe support is no longer EXPERIMENTAL
AC_ARG_WITH(nvme-devicescan,
[AS_HELP_STRING([--with-nvme-devicescan@<:@=yes|no@:>@],
[Include NVMe devices in smartd DEVICESCAN [no]])])
AC_SUBST(with_nvme_devicescan)
if test "$with_nvme_devicescan" = "yes"; then
AC_DEFINE(WITH_NVME_DEVICESCAN, 1, [Define to 1 to include NVMe devices in smartd DEVICESCAN.])
fi
AC_ARG_WITH(solaris-sparc-ata,
[AS_HELP_STRING([--with-solaris-sparc-ata@<:@=yes|no@:>@],
[Enable legacy ATA support on Solaris SPARC (requires os_solaris_ata.s from SVN repository) [no]])])
case "$host:$with_solaris_sparc_ata" in
sparc-*-solaris*:yes)
if test ! -f "$srcdir/os_solaris_ata.s"; then
AC_MSG_ERROR([Missing source file: $srcdir/os_solaris_ata.s
This file is no longer included in the source tarball but still
available in the SVN repository.])
fi
AC_DEFINE(WITH_SOLARIS_SPARC_ATA, 1, [Define to 1 to enable legacy ATA support on Solaris SPARC.])
;;
esac
# Assume broken snprintf only on Windows with MSVCRT (MinGW without ANSI stdio support) # Assume broken snprintf only on Windows with MSVCRT (MinGW without ANSI stdio support)
libc_have_working_snprintf=yes libc_have_working_snprintf=yes
@ -357,23 +389,52 @@ AC_ARG_WITH(working-snprintf,
[libc_have_working_snprintf=$withval]) [libc_have_working_snprintf=$withval])
if test "$libc_have_working_snprintf" = "yes"; then if test "$libc_have_working_snprintf" = "yes"; then
AC_DEFINE(HAVE_WORKING_SNPRINTF, 1, [Define to 1 if the `snprintf' function is sane]) AC_DEFINE(HAVE_WORKING_SNPRINTF, 1, [Define to 1 if the `snprintf' function is sane.]) dnl `vim syntax
fi fi
if test "$prefix" = "NONE"; then os_win32_manifest=
dnl no prefix and no mandir, so use ${prefix}/share/man as default case "$host" in
if test "$mandir" = '${prefix}/man'; then *-*-mingw*)
AC_SUBST([mandir], ['${prefix}/share/man']) # Newer MinGW may add a default manifest
AC_MSG_CHECKING([whether $CC adds an application manifest])
cc_adds_manifest=no
AC_LINK_IFELSE([AC_LANG_PROGRAM()], [
if "$WINDRES" -O rc conftest.exe 2>/dev/null | grep '^1.*RT_MANIFEST' >/dev/null 2>&1; then
cc_adds_manifest=incomplete
# Manifest must provide a Win 10 compatibility ID
if "$WINDRES" -O rc conftest.exe 2>/dev/null | grep '{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}' >/dev/null 2>&1; then
cc_adds_manifest=yes
fi fi
fi],
[AC_MSG_ERROR([test compile failed])])
AC_MSG_RESULT([$cc_adds_manifest])
test "$cc_adds_manifest" = "yes" || os_win32_manifest='default.manifest.o'
;;
esac
# TODO: Remove after smartmontools 6.5
AC_ARG_WITH(docdir,
[AS_HELP_STRING([--with-docdir=DIR], [(removed, use --docdir=DIR instead)])],
[AC_MSG_ERROR([--with-docdir is no longer supported, use --docdir instead])])
AC_ARG_ENABLE(drivedb,
[AS_HELP_STRING([--disable-drivedb], [(removed, use --without-drivedbdir instead)])])
AC_ARG_ENABLE(savestates,
[AS_HELP_STRING([--enable-savestates], [(removed, use --with-savestates@<:@=yes@:>@ instead)])])
AC_ARG_ENABLE(attributelog,
[AS_HELP_STRING([--enable-attributelog], [(removed, use --with-attributelog@<:@=yes@:>@ instead)])])
if test -n "${enable_drivedb+set}${enable_savestates+set}${enable_attributelog+set}"; then
AC_MSG_ERROR([Options --disable-drivedb, --enable-savestates, --enable-attributelog are no longer supported.
Use --without-drivedbdir, --with-savestates, --with-attributelog instead.])
fi fi
AC_SUBST(releaseversion,['${PACKAGE}-${VERSION}']) AC_SUBST(releaseversion,['${PACKAGE}-${VERSION}'])
AC_SUBST(smartmontools_release_date) AC_SUBST(smartmontools_release_date)
AC_SUBST(smartmontools_release_time) AC_SUBST(smartmontools_release_time)
# Set platform-specific modules and symbols # Set platform-specific modules and symbols
os_libs= os_libs=
os_dltools='curl wget lynx' os_dltools='curl wget lynx svn'
os_mailer=mail os_mailer=mail
os_hostname="'hostname'" os_hostname="'hostname'"
os_dnsdomainname= os_dnsdomainname=
@ -394,12 +455,14 @@ case "${host}" in
*-*-freebsd*|*-*-dragonfly*|*-*-kfreebsd*-gnu*) *-*-freebsd*|*-*-dragonfly*|*-*-kfreebsd*-gnu*)
os_deps='os_freebsd.o cciss.o dev_areca.o' os_deps='os_freebsd.o cciss.o dev_areca.o'
os_libs='-lcam' os_libs='-lcam'
os_dltools='curl wget lynx fetch' os_dltools='curl wget lynx fetch svn'
AC_CHECK_LIB(usb, libusb20_dev_get_device_desc) AC_CHECK_LIB(usb, libusb20_dev_get_device_desc)
os_man_filter=FreeBSD os_man_filter=FreeBSD
;; ;;
sparc-*-solaris*) sparc-*-solaris*)
os_deps='os_solaris.o os_solaris_ata.o' os_deps='os_solaris.o'
test "$with_solaris_sparc_ata" = "yes" \
&& os_deps="$os_deps os_solaris_ata.o"
os_mailer='mailx' os_mailer='mailx'
os_solaris=yes os_solaris=yes
os_man_filter=Solaris os_man_filter=Solaris
@ -418,7 +481,7 @@ case "${host}" in
*-*-openbsd*) *-*-openbsd*)
os_deps='os_openbsd.o' os_deps='os_openbsd.o'
os_libs='-lutil' os_libs='-lutil'
os_dltools='curl wget lynx ftp' os_dltools='curl wget lynx ftp svn'
os_man_filter=OpenBSD os_man_filter=OpenBSD
;; ;;
*-*-cygwin*) *-*-cygwin*)
@ -480,6 +543,7 @@ AC_SUBST([os_hostname])
AC_SUBST([os_dnsdomainname]) AC_SUBST([os_dnsdomainname])
AC_SUBST([os_nisdomainname]) AC_SUBST([os_nisdomainname])
AC_SUBST([os_man_filter]) AC_SUBST([os_man_filter])
AC_SUBST([os_win32_manifest])
# Create drivedb.h update branch name from version: 5.41[.X] -> RELEASE_5_41_DRIVEDB # 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,' \ DRIVEDB_BRANCH=`echo $VERSION | sed 's,^\([[0-9]]*\.[[0-9]]*\)\..*$,\1,' \
@ -538,85 +602,125 @@ AC_CONFIG_FILES(Makefile)
AC_OUTPUT AC_OUTPUT
AC_PROG_MAKE_SET AC_PROG_MAKE_SET
echo "-----------------------------------------------------------------------------" >&AS_MESSAGE_FD # Note: Use `...` here as some shells do not properly parse '$(... case $x in X) ...)'
echo "${PACKAGE}-${VERSION} configuration:" >&AS_MESSAGE_FD info=`
echo "host operating system: $host" >&AS_MESSAGE_FD echo "-----------------------------------------------------------------------------"
echo "C++ compiler: $CXX" >&AS_MESSAGE_FD echo "${PACKAGE}-${VERSION} configuration:"
echo "C compiler: $CC" >&AS_MESSAGE_FD echo "host operating system: $host"
echo "preprocessor flags: $CPPFLAGS" >&AS_MESSAGE_FD echo "C++ compiler: $CXX"
echo "C++ compiler flags: $CXXFLAGS" >&AS_MESSAGE_FD echo "C compiler: $CC"
echo "C compiler flags: $CFLAGS" >&AS_MESSAGE_FD echo "preprocessor flags: $CPPFLAGS"
echo "linker flags: $LDFLAGS" >&AS_MESSAGE_FD echo "C++ compiler flags: $CXXFLAGS"
echo "OS specific modules: $os_deps $os_libs $LIBS" >&AS_MESSAGE_FD echo "C compiler flags: $CFLAGS"
echo "linker flags: $LDFLAGS"
echo "OS specific modules: $os_deps $os_libs $LIBS"
case "$host_os" in case "$host_os" in
mingw*) mingw*)
echo "resource compiler: $WINDRES" >&AS_MESSAGE_FD echo "application manifest: ${os_win32_manifest:-built-in}"
echo "message compiler: $WINDMC" >&AS_MESSAGE_FD echo "resource compiler: $WINDRES"
echo "NSIS compiler: $MAKENSIS" >&AS_MESSAGE_FD echo "message compiler: $WINDMC"
echo "NSIS compiler: $MAKENSIS"
if test -n "$drivedbdir"; then if test -n "$drivedbdir"; then
echo "drive database file: EXEDIR/drivedb.h" >&AS_MESSAGE_FD echo "drive database file: EXEDIR/drivedb.h"
if test -n "$MAKENSIS"; then if test -n "$MAKENSIS"; then
echo "database update tool: EXEDIR/update-smart-drivedb.exe" >&AS_MESSAGE_FD echo "database update tool: EXEDIR/update-smart-drivedb.exe"
fi fi
else else
echo "drive database file: [[disabled]]" >&AS_MESSAGE_FD echo "drive database file: [[disabled]]"
fi fi
if test -n "$savestates"; then if test -n "$savestates"; then
echo "smartd save files: `eval eval eval echo $savestates`MODEL-SERIAL.TYPE.state" >&AS_MESSAGE_FD echo "smartd save files: \`eval eval eval echo $savestates\`MODEL-SERIAL.TYPE.state"
fi fi
if test -n "$attributelog"; then if test -n "$attributelog"; then
echo "smartd attribute logs: `eval eval eval echo $attributelog`MODEL-SERIAL.TYPE.csv" >&AS_MESSAGE_FD echo "smartd attribute logs: \`eval eval eval echo $attributelog\`MODEL-SERIAL.TYPE.csv"
fi fi
echo "NVMe DEVICESCAN: ${with_nvme_devicescan-no}"
;; ;;
*) *)
echo "binary install path: `eval eval eval echo $sbindir`" >&AS_MESSAGE_FD echo "binary install path: \`eval eval eval echo $sbindir\`"
echo "man page install path: `eval eval eval echo $mandir`" >&AS_MESSAGE_FD echo "man page install path: \`eval eval eval echo $mandir\`"
echo "doc file install path: `eval eval eval echo $docdir`" >&AS_MESSAGE_FD echo "doc file install path: \`eval eval eval echo $docdir\`"
echo "examples install path: `eval eval eval echo $exampledir`" >&AS_MESSAGE_FD echo "examples install path: \`eval eval eval echo $exampledir\`"
if test -n "$drivedbdir"; then if test -n "$drivedbdir"; then
echo "drive database file: `eval eval eval echo $drivedbdir`/drivedb.h" >&AS_MESSAGE_FD echo "drive database file: \`eval eval eval echo $drivedbdir\`/drivedb.h"
echo "database update script: `eval eval eval echo $sbindir`/update-smart-drivedb" >&AS_MESSAGE_FD if test "$with_update_smart_drivedb" = "yes"; then
echo "download tools: `eval eval eval echo $os_dltools`" >&AS_MESSAGE_FD echo "database update script: \`eval eval eval echo $sbindir\`/update-smart-drivedb"
echo "download tools: \`eval eval eval echo $os_dltools\`"
else else
echo "drive database file: [[disabled]]" >&AS_MESSAGE_FD echo "database update script: [[disabled]]"
fi 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
echo "smartd warning script: `eval eval eval echo $smartdscriptdir`/smartd_warning.sh" >&AS_MESSAGE_FD
if test -n "$smartdplugindir"; then
echo "smartd plugin path: `eval eval eval echo $smartdplugindir`" >&AS_MESSAGE_FD
else else
echo "smartd plugin path: [[disabled]]" >&AS_MESSAGE_FD echo "drive database file: [[disabled]]"
fi
echo "local drive database: \`eval eval eval echo $sysconfdir\`/smart_drivedb.h"
echo "smartd config file: \`eval eval eval echo $sysconfdir\`/smartd.conf${smartd_suffix}"
echo "smartd warning script: \`eval eval eval echo $smartdscriptdir\`/smartd_warning.sh"
if test -n "$smartdplugindir"; then
echo "smartd plugin path: \`eval eval eval echo $smartdplugindir\`"
else
echo "smartd plugin path: [[disabled]]"
fi fi
if test -n "$initddir"; then if test -n "$initddir"; then
echo "smartd initd script: `eval eval eval echo $initddir`/smartd${smartd_suffix}" >&AS_MESSAGE_FD echo "smartd initd script: \`eval eval eval echo $initddir\`/${initdfile}"
elif test -z "$systemdsystemunitdir"; then elif test -z "$systemdsystemunitdir"; then
echo "smartd initd script: [[disabled]]" >&AS_MESSAGE_FD echo "smartd initd script: [[disabled]]"
fi fi
if test -n "$systemdsystemunitdir"; then if test -n "$systemdsystemunitdir"; then
echo "smartd systemd file: `eval eval eval echo $systemdsystemunitdir`/smartd.service" >&AS_MESSAGE_FD echo "smartd systemd file: \`eval eval eval echo $systemdsystemunitdir\`/smartd.service"
if test -n "$systemdenvfile"; then if test -n "$systemdenvfile"; then
echo "smartd environ file: `eval eval eval echo $systemdenvfile`" >&AS_MESSAGE_FD echo "smartd environ file: \`eval eval eval echo $systemdenvfile\`"
else else
echo "smartd environ file: [[disabled]]" >&AS_MESSAGE_FD echo "smartd environ file: [[disabled]]"
fi fi
fi fi
if test -n "$savestates"; then if test -n "$savestates"; then
echo "smartd save files: `eval eval eval echo $savestates`MODEL-SERIAL.TYPE.state" >&AS_MESSAGE_FD echo "smartd save files: \`eval eval eval echo $savestates\`MODEL-SERIAL.TYPE.state"
else else
echo "smartd save files: [[disabled]]" >&AS_MESSAGE_FD echo "smartd save files: [[disabled]]"
fi fi
if test -n "$attributelog"; then if test -n "$attributelog"; then
echo "smartd attribute logs: `eval eval eval echo $attributelog`MODEL-SERIAL.TYPE.csv" >&AS_MESSAGE_FD echo "smartd attribute logs: \`eval eval eval echo $attributelog\`MODEL-SERIAL.TYPE.csv"
else else
echo "smartd attribute logs: [[disabled]]" >&AS_MESSAGE_FD echo "smartd attribute logs: [[disabled]]"
fi fi
echo "libcap-ng support: $use_libcap_ng" >&AS_MESSAGE_FD echo "libcap-ng support: $use_libcap_ng"
case "$host_os" in case "$host_os" in
linux*) echo "SELinux support: ${with_selinux-no}" >&AS_MESSAGE_FD ;; linux*) echo "SELinux support: ${with_selinux-no}" ;;
esac
case "$host_os" in
linux*|cygwin*) echo "NVMe DEVICESCAN: ${with_nvme_devicescan-no}" ;;
esac esac
;; ;;
esac
echo "-----------------------------------------------------------------------------"
`
AC_MSG_NOTICE([
$info
])
# TODO: Remove when NVMe support is no longer EXPERIMENTAL
case "$host_os:${with_nvme_devicescan+set}" in
linux*:|cygwin*:|mingw*:)
AC_MSG_WARN([
This version of smartmontools provides NVMe support which is still
EXPERIMENTAL. NVMe devices are not yet included in smartd.conf
'DEVICESCAN' and 'smartctl --scan' unless '-d nvme' is specified.
Use option '--with-nvme-devicescan' to include NVMe devices.
Use option '--without-nvme-devicescan' to suppress this warning.])
;;
esac
# TODO: Remove after smartmontools 6.5
case "$host:${with_solaris_sparc_ata+set}" in
sparc-*-solaris*:)
AC_MSG_WARN([
Legacy ATA support is no longer enabled by default on Solaris SPARC.
The required source file 'os_solaris_ata.s' is no longer included in
the source tarball but still available in the SVN repository.
Use option '--with-solaris-sparc-ata' to enable legacy ATA support.
Use option '--without-solaris-sparc-ata' to suppress this warning.])
;;
esac esac
echo "-----------------------------------------------------------------------------" >&AS_MESSAGE_FD

View File

@ -1,7 +1,7 @@
/* /*
* dev_areca.cpp * dev_areca.cpp
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2012 Hank Wu <hank@areca.com.tw> * Copyright (C) 2012 Hank Wu <hank@areca.com.tw>
* *
@ -21,7 +21,7 @@
#include "dev_interface.h" #include "dev_interface.h"
#include "dev_areca.h" #include "dev_areca.h"
const char * dev_areca_cpp_cvsid = "$Id: dev_areca.cpp 3872 2014-02-03 21:07:51Z chrfranke $" const char * dev_areca_cpp_cvsid = "$Id: dev_areca.cpp 4209 2016-01-22 20:49:44Z chrfranke $"
DEV_ARECA_H_CVSID; DEV_ARECA_H_CVSID;
#include "atacmds.h" #include "atacmds.h"
@ -297,14 +297,14 @@ int generic_areca_device::arcmsr_ui_handler(unsigned char *areca_packet, int are
if (expected==-3) { if (expected==-3) {
return set_err(EIO); return set_err(EIO);
} }
expected = arcmsr_command_handler(ARCMSR_CLEAR_WQBUFFER, NULL, 0); arcmsr_command_handler(ARCMSR_CLEAR_WQBUFFER, NULL, 0);
expected = arcmsr_command_handler(ARCMSR_WRITE_WQBUFFER, areca_packet, areca_packet_len); expected = arcmsr_command_handler(ARCMSR_WRITE_WQBUFFER, areca_packet, areca_packet_len);
if ( expected > 0 ) if ( expected > 0 )
{ {
expected = arcmsr_command_handler(ARCMSR_READ_RQBUFFER, return_buff, sizeof(return_buff)); expected = arcmsr_command_handler(ARCMSR_READ_RQBUFFER, return_buff, sizeof(return_buff));
} }
if ( expected < 0 ) if ( expected < 3 + 1 ) // Prefix + Checksum
{ {
return -1; return -1;
} }

View File

@ -1,7 +1,7 @@
/* /*
* dev_areca.h * dev_areca.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2012 Hank Wu <hank@areca.com.tw> * Copyright (C) 2012 Hank Wu <hank@areca.com.tw>
* *
@ -18,7 +18,7 @@
#ifndef DEV_ARECA_H #ifndef DEV_ARECA_H
#define DEV_ARECA_H #define DEV_ARECA_H
#define DEV_ARECA_H_CVSID "$Id: dev_areca.h 3854 2013-09-12 05:36:20Z chrfranke $" #define DEV_ARECA_H_CVSID "$Id: dev_areca.h 4146 2015-10-17 12:12:49Z chrfranke $"
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/// Areca RAID support /// Areca RAID support
@ -118,9 +118,10 @@ public:
virtual bool arcmsr_ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); virtual bool arcmsr_ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
protected: protected:
generic_areca_device() : smart_device(never_called) generic_areca_device()
{ : smart_device(never_called),
} m_disknum(-1), m_encnum(-1)
{ }
void set_disknum(int disknum) void set_disknum(int disknum)
{m_disknum = disknum;} {m_disknum = disknum;}

View File

@ -1,7 +1,7 @@
/* /*
* dev_ata_cmd_set.cpp * dev_ata_cmd_set.cpp
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2008 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2008 Christian Franke <smartmontools-support@lists.sourceforge.net>
* *
@ -22,7 +22,7 @@
#include <errno.h> #include <errno.h>
const char * dev_ata_cmd_set_cpp_cvsid = "$Id: dev_ata_cmd_set.cpp,v 1.4 2008/10/24 21:49:23 manfred99 Exp $" const char * dev_ata_cmd_set_cpp_cvsid = "$Id: dev_ata_cmd_set.cpp 4122 2015-08-27 19:08:07Z chrfranke $"
DEV_ATA_CMD_SET_H_CVSID; DEV_ATA_CMD_SET_H_CVSID;

View File

@ -1,7 +1,7 @@
/* /*
* dev_ata_cmd_set.h * dev_ata_cmd_set.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2008 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2008 Christian Franke <smartmontools-support@lists.sourceforge.net>
* *
@ -18,7 +18,7 @@
#ifndef DEV_ATA_CMD_SET_H #ifndef DEV_ATA_CMD_SET_H
#define DEV_ATA_CMD_SET_H #define DEV_ATA_CMD_SET_H
#define DEV_ATA_CMD_SET_H_CVSID "$Id: dev_ata_cmd_set.h,v 1.3 2008/08/23 21:32:12 chrfranke Exp $\n" #define DEV_ATA_CMD_SET_H_CVSID "$Id: dev_ata_cmd_set.h 4122 2015-08-27 19:08:07Z chrfranke $"
#include "atacmds.h" // smart_command_set #include "atacmds.h" // smart_command_set
#include "dev_interface.h" #include "dev_interface.h"

View File

@ -1,9 +1,9 @@
/* /*
* dev_interface.cpp * dev_interface.cpp
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2008-13 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2008-16 Christian Franke <smartmontools-support@lists.sourceforge.net>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -32,27 +32,31 @@
#include <sys/timeb.h> #include <sys/timeb.h>
#endif #endif
const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp 3741 2013-01-02 17:06:54Z chrfranke $" const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp 4283 2016-04-10 12:55:59Z chrfranke $"
DEV_INTERFACE_H_CVSID; DEV_INTERFACE_H_CVSID;
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// smart_device // smart_device
int smart_device::s_num_objects = 0;
smart_device::smart_device(smart_interface * intf, const char * dev_name, smart_device::smart_device(smart_interface * intf, const char * dev_name,
const char * dev_type, const char * req_type) const char * dev_type, const char * req_type)
: m_intf(intf), m_info(dev_name, dev_type, req_type), : m_intf(intf), m_info(dev_name, dev_type, req_type),
m_ata_ptr(0), m_scsi_ptr(0) m_ata_ptr(0), m_scsi_ptr(0), m_nvme_ptr(0)
{ {
s_num_objects++;
} }
smart_device::smart_device(do_not_use_in_implementation_classes) smart_device::smart_device(do_not_use_in_implementation_classes)
: m_intf(0), m_ata_ptr(0), m_scsi_ptr(0) : m_intf(0), m_ata_ptr(0), m_scsi_ptr(0), m_nvme_ptr(0)
{ {
throw std::logic_error("smart_device: wrong constructor called in implementation class"); throw std::logic_error("smart_device: wrong constructor called in implementation class");
} }
smart_device::~smart_device() throw() smart_device::~smart_device() throw()
{ {
s_num_objects--;
} }
bool smart_device::is_syscall_unsup() const bool smart_device::is_syscall_unsup() const
@ -88,6 +92,11 @@ smart_device * smart_device::autodetect_open()
return this; return this;
} }
bool smart_device::is_powered_down()
{
return false;
}
bool smart_device::owns(const smart_device * /*dev*/) const bool smart_device::owns(const smart_device * /*dev*/) const
{ {
return false; return false;
@ -194,6 +203,20 @@ bool ata_device::ata_identify_is_cached() const
} }
/////////////////////////////////////////////////////////////////////////////
// nvme_device
bool nvme_device::set_nvme_err(nvme_cmd_out & out, unsigned status, const char * msg /* = 0 */)
{
if (!status)
throw std::logic_error("nvme_device: set_nvme_err() called with status=0");
out.status = status;
out.status_valid = true;
return set_err(EIO, "%sNVMe Status 0x%02x", (msg ? msg : ""), status);
}
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// tunnelled_device_base // tunnelled_device_base
@ -258,7 +281,8 @@ std::string smart_interface::get_valid_dev_types_str()
{ {
// default // default
std::string s = std::string s =
"ata, scsi, sat[,auto][,N][+TYPE], usbcypress[,X], usbjmicron[,p][,x][,N], usbsunplus"; "ata, scsi, nvme[,NSID], sat[,auto][,N][+TYPE], "
"usbcypress[,X], usbjmicron[,p][,x][,N], usbprolific, usbsunplus";
// append custom // append custom
std::string s2 = get_valid_custom_dev_types_str(); std::string s2 = get_valid_custom_dev_types_str();
if (!s2.empty()) { if (!s2.empty()) {
@ -364,6 +388,17 @@ smart_device * smart_interface::get_smart_device(const char * name, const char *
else if (!strcmp(type, "scsi")) else if (!strcmp(type, "scsi"))
dev = get_scsi_device(name, type); dev = get_scsi_device(name, type);
else if (str_starts_with(type, "nvme")) {
int n1 = -1, n2 = -1, len = strlen(type);
unsigned nsid = 0; // invalid namespace id -> use default
sscanf(type, "nvme%n,0x%x%n", &n1, &nsid, &n2);
if (!(n1 == len || n2 == len)) {
set_err(EINVAL, "Invalid NVMe namespace id in '%s'", type);
return 0;
}
dev = get_nvme_device(name, type, nsid);
}
else if ( ((!strncmp(type, "sat", 3) && (!type[3] || strchr(",+", type[3]))) else if ( ((!strncmp(type, "sat", 3) && (!type[3] || strchr(",+", type[3])))
|| (!strncmp(type, "usb", 3)))) { || (!strncmp(type, "usb", 3)))) {
// Split "sat...+base..." -> ("sat...", "base...") // Split "sat...+base..." -> ("sat...", "base...")
@ -384,11 +419,7 @@ smart_device * smart_interface::get_smart_device(const char * name, const char *
return 0; return 0;
} }
// Attach SAT tunnel // Attach SAT tunnel
ata_device * satdev = get_sat_device(sattype.c_str(), basedev->to_scsi()); return get_sat_device(sattype.c_str(), basedev.release()->to_scsi());
if (!satdev)
return 0;
basedev.release();
return satdev;
} }
else { else {
@ -400,6 +431,31 @@ smart_device * smart_interface::get_smart_device(const char * name, const char *
return dev; return dev;
} }
bool smart_interface::scan_smart_devices(smart_device_list & devlist,
const smart_devtype_list & types, const char * pattern /* = 0 */)
{
unsigned n = types.size();
if (n == 0)
return scan_smart_devices(devlist, (const char *)0, pattern);
if (n == 1)
return scan_smart_devices(devlist, types.front().c_str(), pattern);
for (unsigned i = 0; i < n; i++) {
smart_device_list tmplist;
if (!scan_smart_devices(tmplist, types[i].c_str(), pattern))
return false;
devlist.append(tmplist);
}
return true;
}
nvme_device * smart_interface::get_nvme_device(const char * /*name*/, const char * /*type*/, unsigned /*nsid*/)
{
set_err(ENOSYS, "NVMe devices are not supported in this version of smartmontools");
return 0;
}
smart_device * smart_interface::get_custom_smart_device(const char * /*name*/, const char * /*type*/) smart_device * smart_interface::get_custom_smart_device(const char * /*name*/, const char * /*type*/)
{ {
return 0; return 0;

View File

@ -1,9 +1,9 @@
/* /*
* dev_interface.h * dev_interface.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2008-12 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2008-16 Christian Franke
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -18,7 +18,7 @@
#ifndef DEV_INTERFACE_H #ifndef DEV_INTERFACE_H
#define DEV_INTERFACE_H #define DEV_INTERFACE_H
#define DEV_INTERFACE_H_CVSID "$Id: dev_interface.h 3663 2012-10-24 20:35:55Z chrfranke $\n" #define DEV_INTERFACE_H_CVSID "$Id: dev_interface.h 4283 2016-04-10 12:55:59Z chrfranke $\n"
#include "utility.h" #include "utility.h"
@ -33,6 +33,7 @@
class smart_interface; class smart_interface;
class ata_device; class ata_device;
class scsi_device; class scsi_device;
class nvme_device;
/// Base class for all devices /// Base class for all devices
class smart_device class smart_device
@ -78,7 +79,7 @@ protected:
enum do_not_use_in_implementation_classes { never_called }; enum do_not_use_in_implementation_classes { never_called };
/// Dummy constructor for abstract classes. /// Dummy constructor for abstract classes.
/// Must never be called in implementation classes. /// Must never be called in implementation classes.
smart_device(do_not_use_in_implementation_classes); explicit smart_device(do_not_use_in_implementation_classes);
public: public:
virtual ~smart_device() throw(); virtual ~smart_device() throw();
@ -94,6 +95,9 @@ public:
/// Return true if SCSI device /// Return true if SCSI device
bool is_scsi() const bool is_scsi() const
{ return !!m_scsi_ptr; } { return !!m_scsi_ptr; }
/// Return true if NVMe device
bool is_nvme() const
{ return !!m_nvme_ptr; }
/// Downcast to ATA device. /// Downcast to ATA device.
ata_device * to_ata() ata_device * to_ata()
@ -107,6 +111,12 @@ public:
/// Downcast to SCSI device (const). /// Downcast to SCSI device (const).
const scsi_device * to_scsi() const const scsi_device * to_scsi() const
{ return m_scsi_ptr; } { return m_scsi_ptr; }
/// Downcast to NVMe device.
nvme_device * to_nvme()
{ return m_nvme_ptr; }
/// Downcast to NVMe device (const).
const nvme_device * to_nvme() const
{ return m_nvme_ptr; }
/////////////////////////////////////////////// ///////////////////////////////////////////////
// Device information // Device information
@ -169,6 +179,10 @@ public:
/// Message is retrieved from interface's get_msg_for_errno(no). /// Message is retrieved from interface's get_msg_for_errno(no).
bool set_err(int no); bool set_err(int no);
/// Get current number of allocated 'smart_device' objects.
static int get_num_objects()
{ return s_num_objects; }
// Operations // Operations
public: public:
/////////////////////////////////////////////// ///////////////////////////////////////////////
@ -190,6 +204,17 @@ public:
/// Default implementation calls 'open()' and returns 'this'. /// Default implementation calls 'open()' and returns 'this'.
virtual smart_device * autodetect_open(); virtual smart_device * autodetect_open();
///////////////////////////////////////////////
// Support for checking power mode reported by operating system
/// Early test if device is powered up or down.
/// Can be used without calling 'open()' first!
/// Return true when device is powered down, false when
/// powered up. If this function is not implemented or
/// the mode cannot be determined, return false.
/// Default implementation returns false.
virtual bool is_powered_down();
/////////////////////////////////////////////// ///////////////////////////////////////////////
// Support for tunnelled devices // Support for tunnelled devices
@ -215,12 +240,17 @@ private:
device_info m_info; device_info m_info;
error_info m_err; error_info m_err;
// Pointers for to_ata(), to_scsi(), // Pointers for to_ata(), to_scsi(), to_nvme()
// set by ATA/SCSI interface classes. // set by ATA/SCSI/NVMe interface classes.
friend class ata_device; friend class ata_device;
ata_device * m_ata_ptr; ata_device * m_ata_ptr;
friend class scsi_device; friend class scsi_device;
scsi_device * m_scsi_ptr; scsi_device * m_scsi_ptr;
friend class nvme_device;
nvme_device * m_nvme_ptr;
// Number of objects.
static int s_num_objects;
// Prevent copy/assigment // Prevent copy/assigment
smart_device(const smart_device &); smart_device(const smart_device &);
@ -573,6 +603,94 @@ protected:
}; };
/////////////////////////////////////////////////////////////////////////////
// NVMe specific interface
/// NVMe pass through input parameters
struct nvme_cmd_in
{
unsigned char opcode; ///< Opcode (CDW0 07:00)
unsigned nsid; ///< Namespace ID
unsigned cdw10, cdw11, cdw12, cdw13, cdw14, cdw15; ///< Cmd specific
void * buffer; ///< Pointer to data buffer
unsigned size; ///< Size of buffer
enum {
no_data = 0x0, data_out = 0x1, data_in = 0x2, data_io = 0x3
};
/// Get I/O direction from opcode
unsigned char direction() const
{ return (opcode & 0x3); }
// Prepare for DATA IN command
void set_data_in(unsigned char op, void * buf, unsigned sz)
{
opcode = op;
if (direction() != data_in)
throw std::logic_error("invalid opcode for DATA IN");
buffer = buf;
size = sz;
}
nvme_cmd_in()
: opcode(0), nsid(0),
cdw10(0), cdw11(0), cdw12(0), cdw13(0), cdw14(0), cdw15(0),
buffer(0), size(0)
{ }
};
/// NVMe pass through output parameters
struct nvme_cmd_out
{
unsigned result; ///< Command specific result (DW0)
unsigned short status; ///< Status Field (DW3 31:17)
bool status_valid; ///< true if status is valid
nvme_cmd_out()
: result(0), status(0), status_valid(false)
{ }
};
/// NVMe device access
class nvme_device
: virtual public /*extends*/ smart_device
{
public:
/// NVMe pass through.
/// Return false on error.
virtual bool nvme_pass_through(const nvme_cmd_in & in, nvme_cmd_out & out) = 0;
/// Get namespace id.
unsigned get_nsid() const
{ return m_nsid; }
protected:
/// Hide/unhide NVMe interface.
void hide_nvme(bool hide = true)
{ m_nvme_ptr = (!hide ? this : 0); }
/// Constructor requires namespace ID, registers device as NVMe.
explicit nvme_device(unsigned nsid)
: smart_device(never_called),
m_nsid(nsid)
{ hide_nvme(false); }
/// Set namespace id.
/// Should be called in open() function if get_nsid() returns 0.
void set_nsid(unsigned nsid)
{ m_nsid = nsid; }
/// Set last error number and message if pass-through returns NVMe error status.
/// Returns false always to allow use as a return expression.
bool set_nvme_err(nvme_cmd_out & out, unsigned status, const char * msg = 0);
private:
unsigned m_nsid;
};
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/// Smart pointer class for device pointers /// Smart pointer class for device pointers
@ -660,6 +778,7 @@ private:
typedef any_device_auto_ptr<smart_device> smart_device_auto_ptr; typedef any_device_auto_ptr<smart_device> smart_device_auto_ptr;
typedef any_device_auto_ptr<ata_device> ata_device_auto_ptr; typedef any_device_auto_ptr<ata_device> ata_device_auto_ptr;
typedef any_device_auto_ptr<scsi_device> scsi_device_auto_ptr; typedef any_device_auto_ptr<scsi_device> scsi_device_auto_ptr;
typedef any_device_auto_ptr<nvme_device> nvme_device_auto_ptr;
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -714,6 +833,17 @@ public:
return dev; return dev;
} }
void append(smart_device_list & devlist)
{
for (unsigned i = 0; i < devlist.size(); i++) {
smart_device * dev = devlist.at(i);
if (!dev)
continue;
push_back(dev);
devlist.m_list.at(i) = 0;
}
}
// Implementation // Implementation
private: private:
std::vector<smart_device *> m_list; std::vector<smart_device *> m_list;
@ -724,6 +854,10 @@ private:
}; };
/// List of types for DEVICESCAN
typedef std::vector<std::string> smart_devtype_list;
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// smart_interface // smart_interface
@ -820,10 +954,20 @@ public:
/// Fill 'devlist' with devices of some 'type' with device names /// Fill 'devlist' with devices of some 'type' with device names
/// specified by some optional 'pattern'. /// specified by some optional 'pattern'.
/// Use platform specific default if 'type' is empty or 0.
/// Return false on error. /// Return false on error.
virtual bool scan_smart_devices(smart_device_list & devlist, const char * type, virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
const char * pattern = 0) = 0; const char * pattern = 0) = 0;
/// Fill 'devlist' with devices of all 'types' with device names
/// specified by some optional 'pattern'.
/// Use platform specific default if 'types' is empty.
/// Return false on error.
/// Default implementation calls above function for all types
/// and concatenates the results.
virtual bool scan_smart_devices(smart_device_list & devlist,
const smart_devtype_list & types, const char * pattern = 0);
protected: protected:
/// Return standard ATA device. /// Return standard ATA device.
virtual ata_device * get_ata_device(const char * name, const char * type) = 0; virtual ata_device * get_ata_device(const char * name, const char * type) = 0;
@ -831,6 +975,11 @@ protected:
/// Return standard SCSI device. /// Return standard SCSI device.
virtual scsi_device * get_scsi_device(const char * name, const char * type) = 0; virtual scsi_device * get_scsi_device(const char * name, const char * type) = 0;
/// Return standard NVMe device.
/// Default implementation returns 0.
virtual nvme_device * get_nvme_device(const char * name, const char * type,
unsigned nsid);
/// Autodetect device if no device type specified. /// Autodetect device if no device type specified.
virtual smart_device * autodetect_smart_device(const char * name) = 0; virtual smart_device * autodetect_smart_device(const char * name) = 0;
@ -843,7 +992,9 @@ protected:
/// Default implementation returns empty string. /// Default implementation returns empty string.
virtual std::string get_valid_custom_dev_types_str(); virtual std::string get_valid_custom_dev_types_str();
/// Return ATA->SCSI filter for SAT or USB. /// Return ATA->SCSI filter for a SAT or USB 'type'.
/// Device 'scsidev' is used for SCSI access.
/// Return 0 and delete 'scsidev' on error.
/// Override only if platform needs special handling. /// Override only if platform needs special handling.
virtual ata_device * get_sat_device(const char * type, scsi_device * scsidev); virtual ata_device * get_sat_device(const char * type, scsi_device * scsidev);
//{ implemented in scsiata.cpp } //{ implemented in scsiata.cpp }

View File

@ -1,9 +1,9 @@
/* /*
* dev_legacy.cpp * dev_legacy.cpp
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2008-11 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2008-16 Christian Franke <smartmontools-support@lists.sourceforge.net>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -25,7 +25,7 @@
#include <errno.h> #include <errno.h>
const char * dev_legacy_cpp_cvsid = "$Id: dev_legacy.cpp 3263 2011-02-20 18:32:56Z chrfranke $" const char * dev_legacy_cpp_cvsid = "$Id: dev_legacy.cpp 4251 2016-03-26 16:48:32Z chrfranke $"
DEV_INTERFACE_H_CVSID; DEV_INTERFACE_H_CVSID;
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -275,10 +275,13 @@ smart_device * legacy_smart_interface::autodetect_smart_device(const char * name
static void free_devnames(char * * devnames, int numdevs) static void free_devnames(char * * devnames, int numdevs)
{ {
static const char version[] = "$Id: dev_legacy.cpp 3263 2011-02-20 18:32:56Z chrfranke $"; if (!devnames)
for (int i = 0; i < numdevs; i++) return;
FreeNonZero(devnames[i], -1,__LINE__, version); for (int i = 0; i < numdevs; i++) {
FreeNonZero(devnames, (sizeof (char*) * numdevs),__LINE__, version); if (devnames[i])
free(devnames[i]);
}
free(devnames);
} }
bool legacy_smart_interface::scan_smart_devices(smart_device_list & devlist, bool legacy_smart_interface::scan_smart_devices(smart_device_list & devlist,

View File

@ -1,7 +1,7 @@
/* /*
* dev_tunnelled.h * dev_tunnelled.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2008 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2008 Christian Franke <smartmontools-support@lists.sourceforge.net>
* *
@ -18,7 +18,7 @@
#ifndef DEV_TUNNELLED_H #ifndef DEV_TUNNELLED_H
#define DEV_TUNNELLED_H #define DEV_TUNNELLED_H
#define DEV_TUNNELLED_H_CVSID "$Id: dev_tunnelled.h,v 1.1 2008/07/25 21:16:00 chrfranke Exp $\n" #define DEV_TUNNELLED_H_CVSID "$Id: dev_tunnelled.h 4122 2015-08-27 19:08:07Z chrfranke $"
#include "dev_interface.h" #include "dev_interface.h"

View File

@ -1,10 +1,9 @@
#!/bin/bash #!/bin/bash
# #
# do a smartmontools release # do a smartmontools release
# (C) 2003-11 Bruce Allen <ballen4705@users.sourceforge.net>, # (C) 2003-11 Bruce Allen, Guido Guenther
# Guido Guenther <agx@sigxcpu.org> # (C) 2006-15 Christian Franke
# (C) 2006-13 Christian Franke <smartmontools-support@lists.sourceforge.net> # $Id: do_release 4071 2015-04-26 18:25:12Z chrfranke $
# $Id: do_release 3765 2013-02-05 17:17:13Z chrfranke $
# Notes on generating releases: # Notes on generating releases:
# (1) update NEWS # (1) update NEWS
@ -15,8 +14,8 @@
set -e set -e
# Smartmontools Signing Key (through 2014) # Smartmontools Signing Key (through 2016)
KEYID=0x8F6ED8AA KEYID=0xC4A4903A
inc_release() inc_release()
{ {

1415
drivedb.h

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
# Home page: http://smartmontools.sourceforge.net # Home page: http://www.smartmontools.org
# #
# $Id: README 3958 2014-07-18 19:13:32Z chrfranke $ # $Id: README 4120 2015-08-27 16:12:21Z samm2 $
# #
# Copyright (C) 2003-8 Bruce Allen <smartmontools-support@lists.sourceforge.net> # Copyright (C) 2003-8 Bruce Allen <smartmontools-support@lists.sourceforge.net>
# Copyright (C) 2009-14 Christian Franke <smartmontools-support@lists.sourceforge.net> # Copyright (C) 2009-14 Christian Franke <smartmontools-support@lists.sourceforge.net>

151
freebsd_nvme_ioctl.h Normal file
View File

@ -0,0 +1,151 @@
/*-
* Copyright (C) 2012-2013 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/param.h>
#define NVME_PASSTHROUGH_CMD _IOWR('n', 0, struct nvme_pt_command)
struct nvme_command
{
/* dword 0 */
uint16_t opc : 8; /* opcode */
uint16_t fuse : 2; /* fused operation */
uint16_t rsvd1 : 6;
uint16_t cid; /* command identifier */
/* dword 1 */
uint32_t nsid; /* namespace identifier */
/* dword 2-3 */
uint32_t rsvd2;
uint32_t rsvd3;
/* dword 4-5 */
uint64_t mptr; /* metadata pointer */
/* dword 6-7 */
uint64_t prp1; /* prp entry 1 */
/* dword 8-9 */
uint64_t prp2; /* prp entry 2 */
/* dword 10-15 */
uint32_t cdw10; /* command-specific */
uint32_t cdw11; /* command-specific */
uint32_t cdw12; /* command-specific */
uint32_t cdw13; /* command-specific */
uint32_t cdw14; /* command-specific */
uint32_t cdw15; /* command-specific */
} __packed;
struct nvme_status {
uint16_t p : 1; /* phase tag */
uint16_t sc : 8; /* status code */
uint16_t sct : 3; /* status code type */
uint16_t rsvd2 : 2;
uint16_t m : 1; /* more */
uint16_t dnr : 1; /* do not retry */
} __packed;
struct nvme_completion {
/* dword 0 */
uint32_t cdw0; /* command-specific */
/* dword 1 */
uint32_t rsvd1;
/* dword 2 */
uint16_t sqhd; /* submission queue head pointer */
uint16_t sqid; /* submission queue identifier */
/* dword 3 */
uint16_t cid; /* command identifier */
struct nvme_status status;
} __packed;
struct nvme_pt_command {
/*
* cmd is used to specify a passthrough command to a controller or
* namespace.
*
* The following fields from cmd may be specified by the caller:
* * opc (opcode)
* * nsid (namespace id) - for admin commands only
* * cdw10-cdw15
*
* Remaining fields must be set to 0 by the caller.
*/
struct nvme_command cmd;
/*
* cpl returns completion status for the passthrough command
* specified by cmd.
*
* The following fields will be filled out by the driver, for
* consumption by the caller:
* * cdw0
* * status (except for phase)
*
* Remaining fields will be set to 0 by the driver.
*/
struct nvme_completion cpl;
/* buf is the data buffer associated with this passthrough command. */
void * buf;
/*
* len is the length of the data buffer associated with this
* passthrough command.
*/
uint32_t len;
/*
* is_read = 1 if the passthrough command will read data into the
* supplied buffer from the controller.
*
* is_read = 0 if the passthrough command will write data from the
* supplied buffer to the controller.
*/
uint32_t is_read;
/*
* driver_lock is used by the driver only. It must be set to 0
* by the caller.
*/
struct mtx * driver_lock;
};
#define nvme_completion_is_error(cpl) \
((cpl)->status.sc != 0 || (cpl)->status.sct != 0)
#define NVME_CTRLR_PREFIX "/dev/nvme"
#define NVME_NS_PREFIX "ns"

View File

@ -1,7 +1,7 @@
/* /*
* int64.h * int64.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net>
* Copyright (C) 2004-11 Christian Franke * Copyright (C) 2004-11 Christian Franke
@ -20,7 +20,7 @@
#ifndef INT64_H_ #ifndef INT64_H_
#define INT64_H_ #define INT64_H_
#define INT64_H_CVSID "$Id: int64.h 3727 2012-12-13 17:23:06Z samm2 $" #define INT64_H_CVSID "$Id: int64.h 4120 2015-08-27 16:12:21Z samm2 $"
// 64 bit integer typedefs and format strings // 64 bit integer typedefs and format strings

View File

@ -1,11 +1,10 @@
/* /*
* knowndrives.cpp * knowndrives.cpp
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* Address of support mailing list: smartmontools-support@lists.sourceforge.net
* *
* Copyright (C) 2003-11 Philip Williams, Bruce Allen * Copyright (C) 2003-11 Philip Williams, Bruce Allen
* Copyright (C) 2008-12 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2008-16 Christian Franke
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -33,7 +32,7 @@
#include <stdexcept> #include <stdexcept>
const char * knowndrives_cpp_cvsid = "$Id: knowndrives.cpp 3719 2012-12-03 21:19:33Z chrfranke $" const char * knowndrives_cpp_cvsid = "$Id: knowndrives.cpp 4208 2016-01-22 19:45:35Z chrfranke $"
KNOWNDRIVES_H_CVSID; KNOWNDRIVES_H_CVSID;
#define MODEL_STRING_LENGTH 40 #define MODEL_STRING_LENGTH 40
@ -51,6 +50,8 @@ const drive_settings builtin_knowndrives[] = {
#include "drivedb.h" #include "drivedb.h"
}; };
const unsigned builtin_knowndrives_size =
sizeof(builtin_knowndrives) / sizeof(builtin_knowndrives[0]);
/// Drive database class. Stores custom entries read from file. /// Drive database class. Stores custom entries read from file.
/// Provides transparent access to concatenation of custom and /// Provides transparent access to concatenation of custom and
@ -140,16 +141,26 @@ const char * drive_database::copy_string(const char * src)
static drive_database knowndrives; static drive_database knowndrives;
// Return true if modelfamily string describes entry for USB ID enum dbentry_type {
static bool is_usb_modelfamily(const char * modelfamily) DBENTRY_ATA_DEFAULT,
DBENTRY_ATA,
DBENTRY_USB
};
// Return type of entry
static dbentry_type get_modelfamily_type(const char * modelfamily)
{ {
return !strncmp(modelfamily, "USB:", 4); if (modelfamily[0] == 'D' && !strcmp(modelfamily, "DEFAULT"))
return DBENTRY_ATA_DEFAULT;
else if(modelfamily[0] == 'U' && str_starts_with(modelfamily, "USB:"))
return DBENTRY_USB;
else
return DBENTRY_ATA;
} }
// Return true if entry for USB ID static inline dbentry_type get_dbentry_type(const drive_settings * dbentry)
static inline bool is_usb_entry(const drive_settings * dbentry)
{ {
return is_usb_modelfamily(dbentry->modelfamily); return get_modelfamily_type(dbentry->modelfamily);
} }
// Compile regular expression, print message on failure. // Compile regular expression, print message on failure.
@ -185,8 +196,8 @@ static const drive_settings * lookup_drive(const char * model, const char * firm
firmware = ""; firmware = "";
for (unsigned i = 0; i < knowndrives.size(); i++) { for (unsigned i = 0; i < knowndrives.size(); i++) {
// Skip USB entries // Skip DEFAULT and USB entries
if (is_usb_entry(&knowndrives[i])) if (get_dbentry_type(&knowndrives[i]) != DBENTRY_ATA)
continue; continue;
// Check whether model matches the regular expression in knowndrives[i]. // Check whether model matches the regular expression in knowndrives[i].
@ -219,8 +230,8 @@ static bool parse_db_presets(const char * presets, ata_vendor_attr_defs * defs,
if (!(sscanf(presets+i, "-%c %80[^ ]%n", &opt, arg, &len) >= 2 && len > 0)) if (!(sscanf(presets+i, "-%c %80[^ ]%n", &opt, arg, &len) >= 2 && len > 0))
return false; return false;
if (opt == 'v' && defs) { if (opt == 'v' && defs) {
// Parse "-v N,format[,name]" // Parse "-v N,format[,name[,HDD|SSD]]"
if (!parse_attribute_def(arg, *defs, PRIOR_DATABASE)) if (!parse_attribute_def(arg, *defs, (firmwarebugs ? PRIOR_DATABASE : PRIOR_DEFAULT)))
return false; return false;
} }
else if (opt == 'F' && firmwarebugs) { else if (opt == 'F' && firmwarebugs) {
@ -243,6 +254,13 @@ static bool parse_db_presets(const char * presets, ata_vendor_attr_defs * defs,
return true; return true;
} }
// Parse '-v' options in default preset string, return false on error.
static inline bool parse_default_presets(const char * presets,
ata_vendor_attr_defs & defs)
{
return parse_db_presets(presets, &defs, 0, 0);
}
// Parse '-v' and '-F' options in preset string, return false on error. // Parse '-v' and '-F' options in preset string, return false on error.
static inline bool parse_presets(const char * presets, static inline bool parse_presets(const char * presets,
ata_vendor_attr_defs & defs, ata_vendor_attr_defs & defs,
@ -287,7 +305,7 @@ int lookup_usb_device(int vendor_id, int product_id, int bcd_device,
const drive_settings & dbentry = knowndrives[i]; const drive_settings & dbentry = knowndrives[i];
// Skip drive entries // Skip drive entries
if (!is_usb_entry(&dbentry)) if (get_dbentry_type(&dbentry) != DBENTRY_USB)
continue; continue;
// Check whether USB vendor:product ID matches // Check whether USB vendor:product ID matches
@ -341,7 +359,8 @@ static int showonepreset(const drive_settings * dbentry)
return 1; return 1;
} }
bool usb = is_usb_entry(dbentry); dbentry_type type = get_dbentry_type(dbentry);
bool usb = (type == DBENTRY_USB);
// print and check model and firmware regular expressions // print and check model and firmware regular expressions
int errcnt = 0; int errcnt = 0;
@ -364,12 +383,21 @@ static int showonepreset(const drive_settings * dbentry)
bool first_preset = true; bool first_preset = true;
if (*dbentry->presets) { if (*dbentry->presets) {
ata_vendor_attr_defs defs; ata_vendor_attr_defs defs;
if (type == DBENTRY_ATA_DEFAULT) {
if (!parse_default_presets(dbentry->presets, defs)) {
pout("Syntax error in DEFAULT option string \"%s\"\n", dbentry->presets);
errcnt++;
}
}
else {
if (!parse_presets(dbentry->presets, defs, firmwarebugs)) { if (!parse_presets(dbentry->presets, defs, firmwarebugs)) {
pout("Syntax error in preset option string \"%s\"\n", dbentry->presets); pout("Syntax error in preset option string \"%s\"\n", dbentry->presets);
errcnt++; errcnt++;
} }
}
for (int i = 0; i < MAX_ATTRIBUTE_NUM; i++) { for (int i = 0; i < MAX_ATTRIBUTE_NUM; i++) {
if (defs[i].priority != PRIOR_DEFAULT) { if (defs[i].priority != PRIOR_DEFAULT || !defs[i].name.empty()) {
std::string name = ata_get_smart_attr_name(i, defs); std::string name = ata_get_smart_attr_name(i, defs);
// Use leading zeros instead of spaces so that everything lines up. // Use leading zeros instead of spaces so that everything lines up.
pout("%-*s %03d %s\n", TABLEPRINTWIDTH, first_preset ? "ATTRIBUTE OPTIONS:" : "", pout("%-*s %03d %s\n", TABLEPRINTWIDTH, first_preset ? "ATTRIBUTE OPTIONS:" : "",
@ -563,7 +591,7 @@ class stdin_iterator
{ {
public: public:
explicit stdin_iterator(FILE * f) explicit stdin_iterator(FILE * f)
: m_f(f) { get(); get(); } : m_f(f), m_next(0) { get(); get(); }
stdin_iterator & operator++() stdin_iterator & operator++()
{ get(); return *this; } { get(); return *this; }
@ -767,19 +795,29 @@ static bool parse_drive_database(parse_ptr src, drive_database & db, const char
break; break;
case 4: case 4:
if (!token.value.empty()) { if (!token.value.empty()) {
if (!is_usb_modelfamily(values[0].c_str())) { // Syntax check
switch (get_modelfamily_type(values[0].c_str())) {
case DBENTRY_ATA_DEFAULT: {
ata_vendor_attr_defs defs;
if (!parse_default_presets(token.value.c_str(), defs)) {
pout("%s(%d): Syntax error in DEFAULT option string\n", path, token.line);
ok = false;
}
} break;
default: { // DBENTRY_ATA
ata_vendor_attr_defs defs; firmwarebug_defs fix; ata_vendor_attr_defs defs; firmwarebug_defs fix;
if (!parse_presets(token.value.c_str(), defs, fix)) { if (!parse_presets(token.value.c_str(), defs, fix)) {
pout("%s(%d): Syntax error in preset option string\n", path, token.line); pout("%s(%d): Syntax error in preset option string\n", path, token.line);
ok = false; ok = false;
} }
} } break;
else { case DBENTRY_USB: {
std::string type; std::string type;
if (!parse_usb_type(token.value.c_str(), type)) { if (!parse_usb_type(token.value.c_str(), type)) {
pout("%s(%d): Syntax error in USB type string\n", path, token.line); pout("%s(%d): Syntax error in USB type string\n", path, token.line);
ok = false; ok = false;
} }
} break;
} }
} }
break; break;
@ -857,7 +895,7 @@ const char * get_drivedb_path_default()
#endif #endif
// Read drive databases from standard places. // Read drive databases from standard places.
bool read_default_drive_databases() static bool read_default_drive_databases()
{ {
// Read file for local additions: /{,usr/local/}etc/smart_drivedb.h // Read file for local additions: /{,usr/local/}etc/smart_drivedb.h
const char * db1 = get_drivedb_path_add(); const char * db1 = get_drivedb_path_add();
@ -877,9 +915,60 @@ bool read_default_drive_databases()
#endif #endif
{ {
// Append builtin table. // Append builtin table.
knowndrives.append(builtin_knowndrives, knowndrives.append(builtin_knowndrives, builtin_knowndrives_size);
sizeof(builtin_knowndrives)/sizeof(builtin_knowndrives[0]));
} }
return true; return true;
} }
static ata_vendor_attr_defs default_attr_defs;
// Initialize default_attr_defs.
static bool init_default_attr_defs()
{
// Lookup default entry
const drive_settings * entry = 0;
for (unsigned i = 0; i < knowndrives.size(); i++) {
if (get_dbentry_type(&knowndrives[i]) != DBENTRY_ATA_DEFAULT)
continue;
entry = &knowndrives[i];
break;
}
if (!entry) {
// Fall back to builtin database
for (unsigned i = 0; i < builtin_knowndrives_size; i++) {
if (get_dbentry_type(&builtin_knowndrives[i]) != DBENTRY_ATA_DEFAULT)
continue;
entry = &builtin_knowndrives[i];
break;
}
if (!entry)
throw std::logic_error("DEFAULT entry missing in builtin drive database");
pout("Warning: DEFAULT entry missing in drive database file(s)\n");
}
if (!parse_default_presets(entry->presets, default_attr_defs)) {
pout("Syntax error in DEFAULT drive database entry\n");
return false;
}
return true;
}
// Init default db entry and optionally read drive databases from standard places.
bool init_drive_database(bool use_default_db)
{
if (use_default_db && !read_default_drive_databases())
return false;
return init_default_attr_defs();
}
// Get vendor attribute options from default db entry.
const ata_vendor_attr_defs & get_default_attr_defs()
{
return default_attr_defs;
}

View File

@ -1,11 +1,10 @@
/* /*
* knowndrives.h * knowndrives.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* Address of support mailing list: smartmontools-support@lists.sourceforge.net
* *
* Copyright (C) 2003-11 Philip Williams, Bruce Allen * Copyright (C) 2003-11 Philip Williams, Bruce Allen
* Copyright (C) 2008-12 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2008-15 Christian Franke
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -20,7 +19,7 @@
#ifndef KNOWNDRIVES_H_ #ifndef KNOWNDRIVES_H_
#define KNOWNDRIVES_H_ #define KNOWNDRIVES_H_
#define KNOWNDRIVES_H_CVSID "$Id: knowndrives.h 3597 2012-09-04 21:10:37Z chrfranke $\n" #define KNOWNDRIVES_H_CVSID "$Id: knowndrives.h 4162 2015-10-31 16:36:16Z chrfranke $\n"
// Structure to store drive database entries, see drivedb.h for a description. // Structure to store drive database entries, see drivedb.h for a description.
struct drive_settings { struct drive_settings {
@ -73,7 +72,10 @@ const char * get_drivedb_path_default();
// Read drive database from file. // Read drive database from file.
bool read_drive_database(const char * path); bool read_drive_database(const char * path);
// Read drive databases from standard places. // Init default db entry and optionally read drive databases from standard places.
bool read_default_drive_databases(); bool init_drive_database(bool use_default_db);
// Get vendor attribute options from default db entry.
const ata_vendor_attr_defs & get_default_attr_defs();
#endif #endif

65
linux_nvme_ioctl.h Normal file
View File

@ -0,0 +1,65 @@
/*
* Definitions for the NVM Express ioctl interface
* Copyright (c) 2011-2014, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#ifndef _UAPI_LINUX_NVME_IOCTL_H
#define _UAPI_LINUX_NVME_IOCTL_H
#include <linux/types.h>
struct nvme_user_io {
__u8 opcode;
__u8 flags;
__u16 control;
__u16 nblocks;
__u16 rsvd;
__u64 metadata;
__u64 addr;
__u64 slba;
__u32 dsmgmt;
__u32 reftag;
__u16 apptag;
__u16 appmask;
};
struct nvme_passthru_cmd {
__u8 opcode;
__u8 flags;
__u16 rsvd1;
__u32 nsid;
__u32 cdw2;
__u32 cdw3;
__u64 metadata;
__u64 addr;
__u32 metadata_len;
__u32 data_len;
__u32 cdw10;
__u32 cdw11;
__u32 cdw12;
__u32 cdw13;
__u32 cdw14;
__u32 cdw15;
__u32 timeout_ms;
__u32 result;
};
#define nvme_admin_cmd nvme_passthru_cmd
#define NVME_IOCTL_ID _IO('N', 0x40)
#define NVME_IOCTL_ADMIN_CMD _IOWR('N', 0x41, struct nvme_admin_cmd)
#define NVME_IOCTL_SUBMIT_IO _IOW('N', 0x42, struct nvme_user_io)
#define NVME_IOCTL_IO_CMD _IOWR('N', 0x43, struct nvme_passthru_cmd)
#define NVME_IOCTL_RESET _IO('N', 0x44)
#define NVME_IOCTL_SUBSYS_RESET _IO('N', 0x45)
#endif /* _UAPI_LINUX_NVME_IOCTL_H */

248
nvmecmds.cpp Normal file
View File

@ -0,0 +1,248 @@
/*
* nvmecmds.cpp
*
* Home page of code is: http://www.smartmontools.org
*
* Copyright (C) 2016 Christian Franke
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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"
#include "nvmecmds.h"
const char * nvmecmds_cvsid = "$Id: nvmecmds.cpp 4313 2016-05-01 16:17:53Z chrfranke $"
NVMECMDS_H_CVSID;
#include "dev_interface.h"
#include "atacmds.h" // swapx(), ASSERT_*(), dont_print_serial_number
#include "scsicmds.h" // dStrHex()
#include "utility.h"
using namespace smartmontools;
// Check nvme_* struct sizes
ASSERT_SIZEOF_STRUCT(nvme_id_ctrl, 4096);
ASSERT_SIZEOF_STRUCT(nvme_id_ns, 4096);
ASSERT_SIZEOF_STRUCT(nvme_error_log_page, 64);
ASSERT_SIZEOF_STRUCT(nvme_smart_log, 512);
// Print NVMe debug messages?
unsigned char nvme_debugmode = 0;
// Dump up to 4096 bytes, do not dump trailing zero bytes.
// TODO: Handle this by new unified function in utility.cpp
static void debug_hex_dump(const void * data, unsigned size)
{
const unsigned char * p = (const unsigned char *)data;
const unsigned limit = 4096; // sizeof(nvme_id_ctrl)
unsigned sz = (size <= limit ? size : limit);
while (sz > 0x10 && !p[sz-1])
sz--;
if (sz < size) {
if (sz & 0x0f)
sz = (sz & ~0x0f) + 0x10;
sz += 0x10;
if (sz > size)
sz = size;
}
dStrHex(p, sz, 0);
if (sz < size)
pout(" ...\n");
}
// Call NVMe pass-through and print debug info if requested.
static bool nvme_pass_through(nvme_device * device, const nvme_cmd_in & in,
nvme_cmd_out & out)
{
int64_t start_usec = -1;
if (nvme_debugmode) {
pout(" [NVMe call: opcode=0x%02x, size=0x%04x, nsid=0x%08x, cdw10=0x%08x",
in.opcode, in.size, in.nsid, in.cdw10);
if (in.cdw11 || in.cdw12 || in.cdw13 || in.cdw14 || in.cdw15)
pout(",\n cdw1x=0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x",
in.cdw11, in.cdw12, in.cdw13, in.cdw14, in.cdw15);
pout("]\n");
start_usec = smi()->get_timer_usec();
}
bool ok = device->nvme_pass_through(in, out);
if ( dont_print_serial_number && ok
&& in.opcode == nvme_admin_identify && in.cdw10 == 0x01) {
// Invalidate serial number
nvme_id_ctrl & id_ctrl = *reinterpret_cast<nvme_id_ctrl *>(in.buffer);
memset(id_ctrl.sn, 'X', sizeof(id_ctrl.sn));
}
if (nvme_debugmode) {
if (start_usec >= 0) {
int64_t duration_usec = smi()->get_timer_usec() - start_usec;
if (duration_usec >= 500)
pout(" [Duration: %.3fs]\n", duration_usec / 1000000.0);
}
if (!ok) {
pout(" [NVMe call failed: ");
if (out.status_valid)
pout("NVMe Status=0x%04x", out.status);
else
pout("%s", device->get_errmsg());
}
else {
pout(" [NVMe call succeeded: result=0x%08x", out.result);
if (nvme_debugmode > 1 && in.direction() == nvme_cmd_in::data_in) {
pout("\n");
debug_hex_dump(in.buffer, in.size);
pout(" ");
}
}
pout("]\n");
}
return ok;
}
// Call NVMe pass-through and print debug info if requested.
// Version without output parameters.
static bool nvme_pass_through(nvme_device * device, const nvme_cmd_in & in)
{
nvme_cmd_out out;
return nvme_pass_through(device, in, out);
}
// Read NVMe identify info with controller/namespace field CNS.
static bool nvme_read_identify(nvme_device * device, unsigned nsid,
unsigned char cns, void * data, unsigned size)
{
memset(data, 0, size);
nvme_cmd_in in;
in.set_data_in(nvme_admin_identify, data, size);
in.nsid = nsid;
in.cdw10 = cns;
return nvme_pass_through(device, in);
}
// Read NVMe Identify Controller data structure.
bool nvme_read_id_ctrl(nvme_device * device, nvme_id_ctrl & id_ctrl)
{
if (!nvme_read_identify(device, 0, 0x01, &id_ctrl, sizeof(id_ctrl)))
return false;
if (isbigendian()) {
swapx(&id_ctrl.vid);
swapx(&id_ctrl.ssvid);
swapx(&id_ctrl.cntlid);
swapx(&id_ctrl.oacs);
swapx(&id_ctrl.wctemp);
swapx(&id_ctrl.cctemp);
swapx(&id_ctrl.mtfa);
swapx(&id_ctrl.hmpre);
swapx(&id_ctrl.hmmin);
swapx(&id_ctrl.rpmbs);
swapx(&id_ctrl.nn);
swapx(&id_ctrl.oncs);
swapx(&id_ctrl.fuses);
swapx(&id_ctrl.awun);
swapx(&id_ctrl.awupf);
swapx(&id_ctrl.acwu);
swapx(&id_ctrl.sgls);
for (int i = 0; i < 32; i++) {
swapx(&id_ctrl.psd[i].max_power);
swapx(&id_ctrl.psd[i].entry_lat);
swapx(&id_ctrl.psd[i].exit_lat);
swapx(&id_ctrl.psd[i].idle_power);
swapx(&id_ctrl.psd[i].active_power);
}
}
return true;
}
// Read NVMe Identify Namespace data structure for namespace NSID.
bool nvme_read_id_ns(nvme_device * device, unsigned nsid, nvme_id_ns & id_ns)
{
if (!nvme_read_identify(device, nsid, 0x00, &id_ns, sizeof(id_ns)))
return false;
if (isbigendian()) {
swapx(&id_ns.nsze);
swapx(&id_ns.ncap);
swapx(&id_ns.nuse);
swapx(&id_ns.nawun);
swapx(&id_ns.nawupf);
swapx(&id_ns.nacwu);
swapx(&id_ns.nabsn);
swapx(&id_ns.nabo);
swapx(&id_ns.nabspf);
for (int i = 0; i < 16; i++)
swapx(&id_ns.lbaf[i].ms);
}
return true;
}
// Read NVMe log page with identifier LID.
bool nvme_read_log_page(nvme_device * device, unsigned char lid, void * data, unsigned size)
{
if (!(4 <= size && size <= 0x4000 && (size % 4) == 0))
throw std::logic_error("nvme_read_log_page(): invalid size");
memset(data, 0, size);
nvme_cmd_in in;
in.set_data_in(nvme_admin_get_log_page, data, size);
in.nsid = device->get_nsid();
in.cdw10 = lid | (((size / 4) - 1) << 16);
return nvme_pass_through(device, in);
}
// Read NVMe Error Information Log.
bool nvme_read_error_log(nvme_device * device, nvme_error_log_page * error_log, unsigned num_entries)
{
if (!nvme_read_log_page(device, 0x01, error_log, num_entries * sizeof(*error_log)))
return false;
if (isbigendian()) {
for (unsigned i = 0; i < num_entries; i++) {
swapx(&error_log[i].error_count);
swapx(&error_log[i].sqid);
swapx(&error_log[i].cmdid);
swapx(&error_log[i].status_field);
swapx(&error_log[i].parm_error_location);
swapx(&error_log[i].lba);
swapx(&error_log[i].nsid);
}
}
return true;
}
// Read NVMe SMART/Health Information log.
bool nvme_read_smart_log(nvme_device * device, nvme_smart_log & smart_log)
{
if (!nvme_read_log_page(device, 0x02, &smart_log, sizeof(smart_log)))
return false;
if (isbigendian()) {
swapx(&smart_log.warning_temp_time);
swapx(&smart_log.critical_comp_time);
for (int i = 0; i < 8; i++)
swapx(&smart_log.temp_sensor[i]);
}
return true;
}

239
nvmecmds.h Normal file
View File

@ -0,0 +1,239 @@
/*
* nvmecmds.h
*
* Home page of code is: http://www.smartmontools.org
*
* Copyright (C) 2016 Christian Franke
*
* Original code from <linux/nvme.h>:
* Copyright (C) 2011-2014 Intel Corporation
*
* 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 NVMECMDS_H
#define NVMECMDS_H
#define NVMECMDS_H_CVSID "$Id: nvmecmds.h 4297 2016-04-16 16:48:01Z chrfranke $"
#include "int64.h"
// The code below was orginally imported from <linux/nvme.h> include file from
// Linux kernel sources. Types from <linux/types.h> were replaced.
// Symbol names are unchanged but placed in a namespace to allow inclusion
// of the original <linux/nvme.h>.
namespace smartmontools {
////////////////////////////////////////////////////////////////////////////
// BEGIN: From <linux/nvme.h>
/*
* Definitions for the NVM Express interface
* Copyright (c) 2011-2014, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
struct nvme_error_log_page {
uint64_t error_count;
unsigned short sqid;
unsigned short cmdid;
unsigned short status_field;
unsigned short parm_error_location;
uint64_t lba;
unsigned int nsid;
unsigned char vs;
unsigned char resv[35];
};
struct nvme_id_power_state {
unsigned short max_power; // centiwatts
unsigned char rsvd2;
unsigned char flags;
unsigned int entry_lat; // microseconds
unsigned int exit_lat; // microseconds
unsigned char read_tput;
unsigned char read_lat;
unsigned char write_tput;
unsigned char write_lat;
unsigned short idle_power;
unsigned char idle_scale;
unsigned char rsvd19;
unsigned short active_power;
unsigned char active_work_scale;
unsigned char rsvd23[9];
};
struct nvme_id_ctrl {
unsigned short vid;
unsigned short ssvid;
char sn[20];
char mn[40];
char fr[8];
unsigned char rab;
unsigned char ieee[3];
unsigned char cmic;
unsigned char mdts;
unsigned short cntlid;
unsigned int ver;
unsigned int rtd3r;
unsigned int rtd3e;
unsigned int oaes;
unsigned char rsvd96[160];
unsigned short oacs;
unsigned char acl;
unsigned char aerl;
unsigned char frmw;
unsigned char lpa;
unsigned char elpe;
unsigned char npss;
unsigned char avscc;
unsigned char apsta;
unsigned short wctemp;
unsigned short cctemp;
unsigned short mtfa;
unsigned int hmpre;
unsigned int hmmin;
unsigned char tnvmcap[16];
unsigned char unvmcap[16];
unsigned int rpmbs;
unsigned char rsvd316[196];
unsigned char sqes;
unsigned char cqes;
unsigned char rsvd514[2];
unsigned int nn;
unsigned short oncs;
unsigned short fuses;
unsigned char fna;
unsigned char vwc;
unsigned short awun;
unsigned short awupf;
unsigned char nvscc;
unsigned char rsvd531;
unsigned short acwu;
unsigned char rsvd534[2];
unsigned int sgls;
unsigned char rsvd540[1508];
struct nvme_id_power_state psd[32];
unsigned char vs[1024];
};
struct nvme_lbaf {
unsigned short ms;
unsigned char ds;
unsigned char rp;
};
struct nvme_id_ns {
uint64_t nsze;
uint64_t ncap;
uint64_t nuse;
unsigned char nsfeat;
unsigned char nlbaf;
unsigned char flbas;
unsigned char mc;
unsigned char dpc;
unsigned char dps;
unsigned char nmic;
unsigned char rescap;
unsigned char fpi;
unsigned char rsvd33;
unsigned short nawun;
unsigned short nawupf;
unsigned short nacwu;
unsigned short nabsn;
unsigned short nabo;
unsigned short nabspf;
unsigned char rsvd46[2];
unsigned char nvmcap[16];
unsigned char rsvd64[40];
unsigned char nguid[16];
unsigned char eui64[8];
struct nvme_lbaf lbaf[16];
unsigned char rsvd192[192];
unsigned char vs[3712];
};
struct nvme_smart_log {
unsigned char critical_warning;
unsigned char temperature[2];
unsigned char avail_spare;
unsigned char spare_thresh;
unsigned char percent_used;
unsigned char rsvd6[26];
unsigned char data_units_read[16];
unsigned char data_units_written[16];
unsigned char host_reads[16];
unsigned char host_writes[16];
unsigned char ctrl_busy_time[16];
unsigned char power_cycles[16];
unsigned char power_on_hours[16];
unsigned char unsafe_shutdowns[16];
unsigned char media_errors[16];
unsigned char num_err_log_entries[16];
unsigned int warning_temp_time;
unsigned int critical_comp_time;
unsigned short temp_sensor[8];
unsigned char rsvd216[296];
};
enum nvme_admin_opcode {
//nvme_admin_delete_sq = 0x00,
//nvme_admin_create_sq = 0x01,
nvme_admin_get_log_page = 0x02,
//nvme_admin_delete_cq = 0x04,
//nvme_admin_create_cq = 0x05,
nvme_admin_identify = 0x06,
//nvme_admin_abort_cmd = 0x08,
//nvme_admin_set_features = 0x09,
//nvme_admin_get_features = 0x0a,
//nvme_admin_async_event = 0x0c,
//nvme_admin_ns_mgmt = 0x0d,
//nvme_admin_activate_fw = 0x10,
//nvme_admin_download_fw = 0x11,
//nvme_admin_ns_attach = 0x15,
//nvme_admin_format_nvm = 0x80,
//nvme_admin_security_send = 0x81,
//nvme_admin_security_recv = 0x82,
};
// END: From <linux/nvme.h>
////////////////////////////////////////////////////////////////////////////
} // namespace smartmontools
class nvme_device;
// Print NVMe debug messages?
extern unsigned char nvme_debugmode;
// Read NVMe Identify Controller data structure.
bool nvme_read_id_ctrl(nvme_device * device, smartmontools::nvme_id_ctrl & id_ctrl);
// Read NVMe Identify Namespace data structure for namespace NSID.
bool nvme_read_id_ns(nvme_device * device, unsigned nsid, smartmontools::nvme_id_ns & id_ns);
// Read NVMe log page with identifier LID.
bool nvme_read_log_page(nvme_device * device, unsigned char lid, void * data, unsigned size);
// Read NVMe Error Information Log.
bool nvme_read_error_log(nvme_device * device, smartmontools::nvme_error_log_page * error_log,
unsigned num_entries);
// Read NVMe SMART/Health Information log.
bool nvme_read_smart_log(nvme_device * device, smartmontools::nvme_smart_log & smart_log);
#endif // NVMECMDS_H

469
nvmeprint.cpp Normal file
View File

@ -0,0 +1,469 @@
/*
* nvmeprint.cpp
*
* Home page of code is: http://www.smartmontools.org
*
* Copyright (C) 2016 Christian Franke
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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"
#include "nvmeprint.h"
const char * nvmeprint_cvsid = "$Id: nvmeprint.cpp 4311 2016-04-27 21:03:01Z chrfranke $"
NVMEPRINT_H_CVSID;
#include "int64.h"
#include "utility.h"
#include "dev_interface.h"
#include "nvmecmds.h"
#include "atacmds.h" // dont_print_serial_number
#include "scsicmds.h" // dStrHex()
#include "smartctl.h"
using namespace smartmontools;
// Return true if 128 bit LE integer is != 0.
static bool le128_is_non_zero(const unsigned char (& val)[16])
{
for (int i = 0; i < 16; i++) {
if (val[i])
return true;
}
return false;
}
// Format 128 bit integer for printing.
// Add value with SI prefixes if BYTES_PER_UNIT is specified.
static const char * le128_to_str(char (& str)[64], uint64_t hi, uint64_t lo, unsigned bytes_per_unit)
{
if (!hi) {
// Up to 64-bit, print exact value
format_with_thousands_sep(str, sizeof(str)-16, lo);
if (lo && bytes_per_unit && lo < 0xffffffffffffffffULL / bytes_per_unit) {
int i = strlen(str);
str[i++] = ' '; str[i++] = '[';
format_capacity(str+i, (int)sizeof(str)-i-1, lo * bytes_per_unit);
i = strlen(str);
str[i++] = ']'; str[i] = 0;
}
}
else {
// More than 64-bit, print approximate value, prepend ~ flag
snprintf(str, sizeof(str), "~%.0f",
hi * (0xffffffffffffffffULL + 1.0) + lo);
}
return str;
}
// Format 128 bit LE integer for printing.
// Add value with SI prefixes if BYTES_PER_UNIT is specified.
static const char * le128_to_str(char (& str)[64], const unsigned char (& val)[16],
unsigned bytes_per_unit = 0)
{
uint64_t hi = val[15];
for (int i = 15-1; i >= 8; i--) {
hi <<= 8; hi += val[i];
}
uint64_t lo = val[7];
for (int i = 7-1; i >= 0; i--) {
lo <<= 8; lo += val[i];
}
return le128_to_str(str, hi, lo, bytes_per_unit);
}
// Format capacity specified as 64bit LBA count for printing.
static const char * lbacap_to_str(char (& str)[64], uint64_t lba_cnt, int lba_bits)
{
return le128_to_str(str, (lba_cnt >> (64 - lba_bits)), (lba_cnt << lba_bits), 1);
}
// Format a Kelvin temperature value in Celsius.
static const char * kelvin_to_str(char (& str)[64], int k)
{
if (!k) // unsupported?
str[0] = '-', str[1] = 0;
else
snprintf(str, sizeof(str), "%d Celsius", k - 273);
return str;
}
static inline unsigned le16_to_uint(const unsigned char (& val)[2])
{
return ((val[1] << 8) | val[0]);
}
static void print_drive_info(const nvme_id_ctrl & id_ctrl, const nvme_id_ns & id_ns,
unsigned nsid, bool show_all)
{
char buf[64];
pout("Model Number: %s\n", format_char_array(buf, id_ctrl.mn));
if (!dont_print_serial_number)
pout("Serial Number: %s\n", format_char_array(buf, id_ctrl.sn));
pout("Firmware Version: %s\n", format_char_array(buf, id_ctrl.fr));
// Vendor and Subsystem IDs are usually equal
if (show_all || id_ctrl.vid != id_ctrl.ssvid) {
pout("PCI Vendor ID: 0x%04x\n", id_ctrl.vid);
pout("PCI Vendor Subsystem ID: 0x%04x\n", id_ctrl.ssvid);
}
else {
pout("PCI Vendor/Subsystem ID: 0x%04x\n", id_ctrl.vid);
}
pout("IEEE OUI Identifier: 0x%02x%02x%02x\n",
id_ctrl.ieee[2], id_ctrl.ieee[1], id_ctrl.ieee[0]);
// Capacity info is optional for devices without namespace management
if (show_all || le128_is_non_zero(id_ctrl.tnvmcap) || le128_is_non_zero(id_ctrl.unvmcap)) {
pout("Total NVM Capacity: %s\n", le128_to_str(buf, id_ctrl.tnvmcap, 1));
pout("Unallocated NVM Capacity: %s\n", le128_to_str(buf, id_ctrl.unvmcap, 1));
}
pout("Controller ID: %d\n", id_ctrl.cntlid);
// Print namespace info if available
pout("Number of Namespaces: %u\n", id_ctrl.nn);
if (nsid && id_ns.nsze) {
const char * align = &(" "[nsid < 10 ? 0 : (nsid < 100 ? 1 : 2)]);
int fmt_lba_bits = id_ns.lbaf[id_ns.flbas & 0xf].ds;
// Size and Capacity are equal if thin provisioning is not supported
if (show_all || id_ns.ncap != id_ns.nsze || (id_ns.nsfeat & 0x01)) {
pout("Namespace %u Size: %s%s\n", nsid, align,
lbacap_to_str(buf, id_ns.nsze, fmt_lba_bits));
pout("Namespace %u Capacity: %s%s\n", nsid, align,
lbacap_to_str(buf, id_ns.ncap, fmt_lba_bits));
}
else {
pout("Namespace %u Size/Capacity: %s%s\n", nsid, align,
lbacap_to_str(buf, id_ns.nsze, fmt_lba_bits));
}
// Utilization may be always equal to Capacity if thin provisioning is not supported
if (show_all || id_ns.nuse != id_ns.ncap || (id_ns.nsfeat & 0x01))
pout("Namespace %u Utilization: %s%s\n", nsid, align,
lbacap_to_str(buf, id_ns.nuse, fmt_lba_bits));
pout("Namespace %u Formatted LBA Size: %s%u\n", nsid, align, (1U << fmt_lba_bits));
}
char td[DATEANDEPOCHLEN]; dateandtimezone(td);
pout("Local Time is: %s\n", td);
}
// Format scaled power value.
static const char * format_power(char (& str)[16], unsigned power, unsigned scale)
{
switch (scale & 0x3) {
case 0: // not reported
str[0] = '-'; str[1] = ' '; str[2] = 0; break;
case 1: // 0.0001W
snprintf(str, sizeof(str), "%u.%04uW", power / 10000, power % 10000); break;
case 2: // 0.01W
snprintf(str, sizeof(str), "%u.%02uW", power / 100, power % 100); break;
default: // reserved
str[0] = '?'; str[1] = 0; break;
}
return str;
}
static void print_drive_capabilities(const nvme_id_ctrl & id_ctrl, const nvme_id_ns & id_ns,
unsigned nsid, bool show_all)
{
pout("Firmware Updates (0x%02x): %d Slot%s%s%s\n", id_ctrl.frmw,
((id_ctrl.frmw >> 1) & 0x7), (((id_ctrl.frmw >> 1) & 0x7) != 1 ? "s" : ""),
((id_ctrl.frmw & 0x01) ? ", Slot 1 R/O" : ""),
((id_ctrl.frmw & 0x10) ? ", no Reset required" : ""));
if (show_all || id_ctrl.oacs)
pout("Optional Admin Commands (0x%04x): %s%s%s%s%s%s\n", id_ctrl.oacs,
(!id_ctrl.oacs ? " -" : ""),
((id_ctrl.oacs & 0x0001) ? " Security" : ""),
((id_ctrl.oacs & 0x0002) ? " Format" : ""),
((id_ctrl.oacs & 0x0004) ? " Frmw_DL" : ""),
((id_ctrl.oacs & 0x0008) ? " NS_Mngmt" : ""),
((id_ctrl.oacs & ~0x000f) ? " *Other*" : ""));
if (show_all || id_ctrl.oncs)
pout("Optional NVM Commands (0x%04x): %s%s%s%s%s%s%s%s\n", id_ctrl.oncs,
(!id_ctrl.oncs ? " -" : ""),
((id_ctrl.oncs & 0x0001) ? " Comp" : ""),
((id_ctrl.oncs & 0x0002) ? " Wr_Unc" : ""),
((id_ctrl.oncs & 0x0004) ? " DS_Mngmt" : ""),
((id_ctrl.oncs & 0x0008) ? " Wr_Zero" : ""),
((id_ctrl.oncs & 0x0010) ? " Sav/Sel_Feat" : ""),
((id_ctrl.oncs & 0x0020) ? " Resv" : ""),
((id_ctrl.oncs & ~0x003f) ? " *Other*" : ""));
if (id_ctrl.mdts)
pout("Maximum Data Transfer Size: %u Pages\n", (1U << id_ctrl.mdts));
else if (show_all)
pout("Maximum Data Transfer Size: -\n");
// Temperature thresholds are optional
char buf[64];
if (show_all || id_ctrl.wctemp)
pout("Warning Comp. Temp. Threshold: %s\n", kelvin_to_str(buf, id_ctrl.wctemp));
if (show_all || id_ctrl.cctemp)
pout("Critical Comp. Temp. Threshold: %s\n", kelvin_to_str(buf, id_ctrl.cctemp));
if (nsid && (show_all || id_ns.nsfeat)) {
const char * align = &(" "[nsid < 10 ? 0 : (nsid < 100 ? 1 : 2)]);
pout("Namespace %u Features (0x%02x): %s%s%s%s%s%s\n", nsid, id_ns.nsfeat, align,
(!id_ns.nsfeat ? " -" : ""),
((id_ns.nsfeat & 0x01) ? " Thin_Prov" : ""),
((id_ns.nsfeat & 0x02) ? " NA_Fields" : ""),
((id_ns.nsfeat & 0x04) ? " Dea/Unw_Error" : ""),
((id_ns.nsfeat & ~0x07) ? " *Other*" : ""));
}
// Print Power States
pout("\nSupported Power States\n");
pout("St Op Max Active Idle RL RT WL WT Ent_Lat Ex_Lat\n");
for (int i = 0; i <= id_ctrl.npss /* 1-based */ && i < 32; i++) {
char p1[16], p2[16], p3[16];
const nvme_id_power_state & ps = id_ctrl.psd[i];
pout("%2d %c %9s %8s %8s %3d %2d %2d %2d %8u %7u\n", i,
((ps.flags & 0x02) ? '-' : '+'),
format_power(p1, ps.max_power, ((ps.flags & 0x01) ? 1 : 2)),
format_power(p2, ps.active_power, ps.active_work_scale),
format_power(p3, ps.idle_power, ps.idle_scale),
ps.read_lat & 0x1f, ps.read_tput & 0x1f,
ps.write_lat & 0x1f, ps.write_tput & 0x1f,
ps.entry_lat, ps.exit_lat);
}
// Print LBA sizes
if (nsid && id_ns.lbaf[0].ds) {
pout("\nSupported LBA Sizes (NSID 0x%x)\n", nsid);
pout("Id Fmt Data Metadt Rel_Perf\n");
for (int i = 0; i <= id_ns.nlbaf /* 1-based */ && i < 16; i++) {
const nvme_lbaf & lba = id_ns.lbaf[i];
pout("%2d %c %7u %7d %9d\n", i, (i == id_ns.flbas ? '+' : '-'),
(1U << lba.ds), lba.ms, lba.rp);
}
}
}
static void print_critical_warning(unsigned char w)
{
pout("SMART overall-health self-assessment test result: %s\n",
(!w ? "PASSED" : "FAILED!"));
if (w) {
if (w & 0x01)
pout("- available spare has fallen below threshold\n");
if (w & 0x02)
pout("- temperature is above or below threshold\n");
if (w & 0x04)
pout("- NVM subsystem reliability has been degraded\n");
if (w & 0x08)
pout("- media has been placed in read only mode\n");
if (w & 0x10)
pout("- volatile memory backup device has failed\n");
if (w & ~0x1f)
pout("- unknown critical warning(s) (0x%02x)\n", w & ~0x1f);
}
pout("\n");
}
static void print_smart_log(const nvme_smart_log & smart_log, unsigned nsid,
const nvme_id_ctrl & id_ctrl, bool show_all)
{
char buf[64];
pout("SMART/Health Information (NVMe Log 0x02, NSID 0x%x)\n", nsid);
pout("Critical Warning: 0x%02x\n", smart_log.critical_warning);
pout("Temperature: %s\n",
kelvin_to_str(buf, le16_to_uint(smart_log.temperature)));
pout("Available Spare: %u%%\n", smart_log.avail_spare);
pout("Available Spare Threshold: %u%%\n", smart_log.spare_thresh);
pout("Percentage Used: %u%%\n", smart_log.percent_used);
pout("Data Units Read: %s\n", le128_to_str(buf, smart_log.data_units_read, 1000*512));
pout("Data Units Written: %s\n", le128_to_str(buf, smart_log.data_units_written, 1000*512));
pout("Host Read Commands: %s\n", le128_to_str(buf, smart_log.host_reads));
pout("Host Write Commands: %s\n", le128_to_str(buf, smart_log.host_writes));
pout("Controller Busy Time: %s\n", le128_to_str(buf, smart_log.ctrl_busy_time));
pout("Power Cycles: %s\n", le128_to_str(buf, smart_log.power_cycles));
pout("Power On Hours: %s\n", le128_to_str(buf, smart_log.power_on_hours));
pout("Unsafe Shutdowns: %s\n", le128_to_str(buf, smart_log.unsafe_shutdowns));
pout("Media and Data Integrity Errors: %s\n", le128_to_str(buf, smart_log.media_errors));
pout("Error Information Log Entries: %s\n", le128_to_str(buf, smart_log.num_err_log_entries));
// Temperature thresholds are optional
if (show_all || id_ctrl.wctemp || smart_log.warning_temp_time)
pout("Warning Comp. Temperature Time: %d\n", smart_log.warning_temp_time);
if (show_all || id_ctrl.cctemp || smart_log.critical_comp_time)
pout("Critical Comp. Temperature Time: %d\n", smart_log.critical_comp_time);
// Temperature sensors are optional
for (int i = 0; i < 8; i++) {
if (show_all || smart_log.temp_sensor[i])
pout("Temperature Sensor %d: %s\n", i + 1,
kelvin_to_str(buf, smart_log.temp_sensor[i]));
}
pout("\n");
}
static void print_error_log(const nvme_error_log_page * error_log,
unsigned num_entries, unsigned print_entries)
{
pout("Error Information (NVMe Log 0x01, max %u entries)\n", num_entries);
unsigned cnt = 0;
for (unsigned i = 0; i < num_entries; i++) {
const nvme_error_log_page & e = error_log[i];
if (!e.error_count)
continue; // unused or invalid entry
if (++cnt > print_entries)
continue;
if (cnt == 1)
pout("Num ErrCount SQId CmdId Status PELoc LBA NSID VS\n");
char sq[16] = "-", cm[16] = "-", st[16] = "-", pe[16] = "-";
char lb[32] = "-", ns[16] = "-", vs[8] = "-";
if (e.sqid != 0xffff)
snprintf(sq, sizeof(sq), "%d", e.sqid);
if (e.cmdid != 0xffff)
snprintf(cm, sizeof(cm), "0x%04x", e.cmdid);
if (e.status_field != 0xffff)
snprintf(st, sizeof(st), "0x%04x", e.status_field);
if (e.parm_error_location != 0xffff)
snprintf(pe, sizeof(pe), "0x%03x", e.parm_error_location);
if (e.lba != 0xffffffffffffffffULL)
snprintf(lb, sizeof(lb), "%" PRIu64, e.lba);
if (e.nsid != 0xffffffffU)
snprintf(ns, sizeof(ns), "%u", e.nsid);
if (e.vs != 0x00)
snprintf(vs, sizeof(vs), "0x%02x", e.vs);
pout("%3u %10" PRIu64 " %5s %7s %7s %6s %12s %5s %5s\n",
i, e.error_count, sq, cm, st, pe, lb, ns, vs);
}
if (!cnt)
pout("No Errors Logged\n");
else if (cnt > print_entries)
pout("... (%u entries not shown)\n", cnt - print_entries);
pout("\n");
}
int nvmePrintMain(nvme_device * device, const nvme_print_options & options)
{
if (!( options.drive_info || options.drive_capabilities
|| options.smart_check_status || options.smart_vendor_attrib
|| options.error_log_entries || options.log_page_size )) {
pout("NVMe device successfully opened\n\n"
"Use 'smartctl -a' (or '-x') to print SMART (and more) information\n\n");
return 0;
}
// Show unset optional values only if debugging is enabled
bool show_all = (nvme_debugmode > 0);
// Read Identify Controller always
nvme_id_ctrl id_ctrl;
if (!nvme_read_id_ctrl(device, id_ctrl)) {
pout("Read NVMe Identify Controller failed: %s\n", device->get_errmsg());
return FAILID;
}
// Print Identify Controller/Namespace info
if (options.drive_info || options.drive_capabilities) {
pout("=== START OF INFORMATION SECTION ===\n");
nvme_id_ns id_ns; memset(&id_ns, 0, sizeof(id_ns));
unsigned nsid = device->get_nsid();
if (nsid == 0xffffffffU) {
// Broadcast namespace
if (id_ctrl.nn == 1) {
// No namespace management, get size from single namespace
nsid = 1;
if (!nvme_read_id_ns(device, nsid, id_ns))
nsid = 0;
}
}
else {
// Identify current namespace
if (!nvme_read_id_ns(device, nsid, id_ns)) {
pout("Read NVMe Identify Namespace 0x%x failed: %s\n", nsid, device->get_errmsg());
return FAILID;
}
}
if (options.drive_info)
print_drive_info(id_ctrl, id_ns, nsid, show_all);
if (options.drive_capabilities)
print_drive_capabilities(id_ctrl, id_ns, nsid, show_all);
pout("\n");
}
if ( options.smart_check_status || options.smart_vendor_attrib
|| options.error_log_entries)
pout("=== START OF SMART DATA SECTION ===\n");
// Print SMART Status and SMART/Health Information
int retval = 0;
if (options.smart_check_status || options.smart_vendor_attrib) {
nvme_smart_log smart_log;
if (!nvme_read_smart_log(device, smart_log)) {
pout("Read NVMe SMART/Health Information failed: %s\n\n", device->get_errmsg());
return FAILSMART;
}
if (options.smart_check_status) {
print_critical_warning(smart_log.critical_warning);
if (smart_log.critical_warning)
retval |= FAILSTATUS;
}
if (options.smart_vendor_attrib) {
print_smart_log(smart_log, device->get_nsid(), id_ctrl, show_all);
}
}
// Print Error Information Log
if (options.error_log_entries) {
unsigned num_entries = id_ctrl.elpe + 1; // 0-based value
raw_buffer error_log_buf(num_entries * sizeof(nvme_error_log_page));
nvme_error_log_page * error_log =
reinterpret_cast<nvme_error_log_page *>(error_log_buf.data());
if (!nvme_read_error_log(device, error_log, num_entries)) {
pout("Read Error Information Log failed: %s\n\n", device->get_errmsg());
return retval | FAILSMART;
}
print_error_log(error_log, num_entries, options.error_log_entries);
}
// Dump log page
if (options.log_page_size) {
// Align size to dword boundary
unsigned size = ((options.log_page_size + 4-1) / 4) * 4;
raw_buffer log_buf(size);
if (!nvme_read_log_page(device, options.log_page, log_buf.data(), size)) {
pout("Read NVMe Log 0x%02x failed: %s\n\n", options.log_page, device->get_errmsg());
return retval | FAILSMART;
}
pout("NVMe Log 0x%02x (0x%04x bytes)\n", options.log_page, size);
dStrHex(log_buf.data(), size, 0);
pout("\n");
}
return retval;
}

49
nvmeprint.h Normal file
View File

@ -0,0 +1,49 @@
/*
* nvmeprint.h
*
* Home page of code is: http://www.smartmontools.org
*
* Copyright (C) 2016 Christian Franke
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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 NVMEPRINT_H
#define NVMEPRINT_H
#define NVMEPRINT_H_CVSID "$Id: nvmeprint.h 4311 2016-04-27 21:03:01Z chrfranke $"
#include "nvmecmds.h"
// options for nvmePrintMain
struct nvme_print_options
{
bool drive_info;
bool drive_capabilities;
bool smart_check_status;
bool smart_vendor_attrib;
unsigned error_log_entries;
unsigned char log_page;
unsigned log_page_size;
nvme_print_options()
: drive_info(false),
drive_capabilities(false),
smart_check_status(false),
smart_vendor_attrib(false),
error_log_entries(0),
log_page(0),
log_page_size(0)
{ }
};
int nvmePrintMain(nvme_device * device, const nvme_print_options & options);
#endif // NVMEPRINT_H

View File

@ -1,7 +1,7 @@
/* /*
* os_darwin.cpp * os_darwin.cpp
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2004-8 Geoffrey Keating <geoffk@geoffk.org> * Copyright (C) 2004-8 Geoffrey Keating <geoffk@geoffk.org>
* Copyright (C) 2014 Alex Samorukov <samm@os2.kiev.ua> * Copyright (C) 2014 Alex Samorukov <samm@os2.kiev.ua>
@ -22,6 +22,7 @@
#include <mach/mach.h> #include <mach/mach.h>
#include <mach/mach_error.h> #include <mach/mach_error.h>
#include <mach/mach_init.h> #include <mach/mach_init.h>
#include <sys/utsname.h>
#include <IOKit/IOCFPlugIn.h> #include <IOKit/IOCFPlugIn.h>
#include <IOKit/IOKitLib.h> #include <IOKit/IOKitLib.h>
#include <IOKit/IOReturn.h> #include <IOKit/IOReturn.h>
@ -45,7 +46,7 @@
#include "dev_interface.h" #include "dev_interface.h"
// Needed by '-V' option (CVS versioning) of smartd/smartctl // Needed by '-V' option (CVS versioning) of smartd/smartctl
const char *os_darwin_cpp_cvsid="$Id: os_darwin.cpp 3982 2014-08-16 21:07:19Z samm2 $" \ const char *os_darwin_cpp_cvsid="$Id: os_darwin.cpp 4214 2016-01-24 22:53:37Z samm2 $" \
ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_DARWIN_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_DARWIN_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
// examples for smartctl // examples for smartctl
@ -77,7 +78,7 @@ static struct {
IOATASMARTInterface **smartIf; IOATASMARTInterface **smartIf;
} devices[20]; } devices[20];
const char * dev_darwin_cpp_cvsid = "$Id: os_darwin.cpp 3982 2014-08-16 21:07:19Z samm2 $" const char * dev_darwin_cpp_cvsid = "$Id: os_darwin.cpp 4214 2016-01-24 22:53:37Z samm2 $"
DEV_INTERFACE_H_CVSID; DEV_INTERFACE_H_CVSID;
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -181,8 +182,8 @@ bool darwin_smart_device::open()
if (strcmp (type, "ATA") != 0) if (strcmp (type, "ATA") != 0)
{ {
errno = EINVAL; set_err (EINVAL);
return -1; return false;
} }
// Find a free device number. // Find a free device number.
@ -191,8 +192,8 @@ bool darwin_smart_device::open()
break; break;
if (devnum == sizeof (devices) / sizeof (devices[0])) if (devnum == sizeof (devices) / sizeof (devices[0]))
{ {
errno = EMFILE; set_err (EMFILE);
return -1; return false;
} }
devname = NULL; devname = NULL;
@ -218,8 +219,8 @@ bool darwin_smart_device::open()
if (! disk) if (! disk)
{ {
errno = ENOENT; set_err(ENOENT);
return -1; return false;
} }
// Find a SMART-capable driver which is a parent of this device. // Find a SMART-capable driver which is a parent of this device.
@ -232,9 +233,9 @@ bool darwin_smart_device::open()
err = IORegistryEntryGetParentEntry (disk, kIOServicePlane, &disk); err = IORegistryEntryGetParentEntry (disk, kIOServicePlane, &disk);
if (err != kIOReturnSuccess || ! disk) if (err != kIOReturnSuccess || ! disk)
{ {
errno = ENODEV; set_err(ENODEV);
IOObjectRelease (prevdisk); IOObjectRelease (prevdisk);
return -1; return false;
} }
} }
@ -311,9 +312,9 @@ static int make_device_names (char*** devlist, const char* name) {
// Create an array of service names. // Create an array of service names.
IOIteratorReset (i); IOIteratorReset (i);
*devlist = (char**)calloc (result, sizeof (char *)); if (! result)
if (! *devlist)
goto error; goto error;
*devlist = (char**)calloc (result, sizeof (char *));
index = 0; index = 0;
while ((device = IOIteratorNext (i)) != MACH_PORT_NULL) { while ((device = IOIteratorNext (i)) != MACH_PORT_NULL) {
if (is_smart_capable (device)) if (is_smart_capable (device))
@ -342,6 +343,9 @@ static int make_device_names (char*** devlist, const char* name) {
free ((*devlist)[index]); free ((*devlist)[index]);
free (*devlist); free (*devlist);
} }
if(!result) // no devs found
return 0;
return -1; return -1;
} }
@ -454,7 +458,7 @@ bool darwin_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & ou
if (select != SHORT_SELF_TEST && select != EXTEND_SELF_TEST) if (select != SHORT_SELF_TEST && select != EXTEND_SELF_TEST)
{ {
errno = EINVAL; errno = EINVAL;
err = -1; return set_err(ENOSYS, "Unsupported SMART self-test mode");
} }
err = smartIf->SMARTExecuteOffLineImmediate (ifp, err = smartIf->SMARTExecuteOffLineImmediate (ifp,
select == EXTEND_SELF_TEST); select == EXTEND_SELF_TEST);
@ -488,6 +492,8 @@ class darwin_smart_interface
: public /*implements*/ smart_interface : public /*implements*/ smart_interface
{ {
public: public:
virtual std::string get_os_version_str();
virtual std::string get_app_examples(const char * appname); virtual std::string get_app_examples(const char * appname);
virtual bool scan_smart_devices(smart_device_list & devlist, const char * type, virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
@ -505,6 +511,15 @@ protected:
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
std::string darwin_smart_interface::get_os_version_str()
{
// now we are just getting darwin runtime version, to get OSX version more things needs to be done, see
// http://stackoverflow.com/questions/11072804/how-do-i-determine-the-os-version-at-runtime-in-os-x-or-ios-without-using-gesta
struct utsname osname;
uname(&osname);
return strprintf("%s %s %s", osname.sysname, osname.release, osname.machine);
}
std::string darwin_smart_interface::get_app_examples(const char * appname) std::string darwin_smart_interface::get_app_examples(const char * appname)
{ {
if (!strcmp(appname, "smartctl")) if (!strcmp(appname, "smartctl"))

View File

@ -1,7 +1,7 @@
/* /*
* os_generic.h * os_generic.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2004-8 Geoff Keating <geoffk@geoffk.org> * Copyright (C) 2004-8 Geoff Keating <geoffk@geoffk.org>
* *
@ -24,7 +24,7 @@
#ifndef OS_DARWIN_H_ #ifndef OS_DARWIN_H_
#define OS_DARWIN_H_ #define OS_DARWIN_H_
#define OS_DARWIN_H_CVSID "$Id: os_darwin.h 3728 2012-12-13 17:57:50Z chrfranke $\n" #define OS_DARWIN_H_CVSID "$Id: os_darwin.h 4120 2015-08-27 16:12:21Z samm2 $\n"
// Isn't in 10.3.9? // Isn't in 10.3.9?

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<dict>
<key>SMART disk monitoring</key>
<string>SMART disk monitoring</string>
<key>Starting SMART disk monitoring</key>
<string>Starting SMART disk monitoring</string>
<key>Stopping SMART disk monitoring</key>
<string>Stopping SMART disk monitoring</string>
</dict>
</plist>

View File

@ -1,56 +0,0 @@
#!/bin/sh
# Darwin init file for smartd
#
# Home page of code is: http://smartmontools.sourceforge.net
#
# Copyright (C) 2004-8 Geoffrey Keating <geoffk@geoffk.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.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# $Id: SMART.in 3728 2012-12-13 17:57:50Z chrfranke $
##
# SMART monitoring
##
. /etc/rc.common
StartService ()
{
if [ "${SMARTd:=-YES-}" = "-YES-" ] &&
! GetPID smartd > /dev/null; then
ConsoleMessage "Starting SMART disk monitoring"
/usr/sbin/smartd -p /var/run/smartd.pid
fi
}
StopService ()
{
if pid=$(GetPID smartd); then
ConsoleMessage "Stopping SMART disk monitoring"
kill -TERM "${pid}"
else
echo "smartd is not running."
fi
}
RestartService ()
{
if pid=$(GetPID smartd); then
kill -HUP "${pid}"
else
StartService
fi
}
RunService "$1"

View File

@ -1,5 +0,0 @@
{
Description = "SMART disk monitoring";
Provides = ("SMART");
Requires = ("System Log");
}

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<dict>
<key>SuccessfulExit</key>
<false/>
</dict>
<key>Label</key>
<string>com.smartmontools.smartd</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/sbin/smartd</string>
<string>-n</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<installer-gui-script minSpecVersion="2">
<allowed-os-versions>
<os-version min="10.5"/>
</allowed-os-versions>
<license file="license.txt" mime-type="text/plain"/>
<!-- <welcome file="welcome.rtf" mime-type="text/rtf"/> -->
<title>S.M.A.R.T. disk monitoring tools</title>
<pkg-ref id="com.smartmontools.pkg"/>
<choices-outline>
<line choice="default">
<line choice="com.smartmontools.pkg"/>
</line>
</choices-outline>
<choice id="default"/>
<choice id="com.smartmontools.pkg" visible="false">
<pkg-ref version="@version@" installKBytes="@size@" id="com.smartmontools.pkg">@pkgname@</pkg-ref>
</choice>
<domains enable_localSystem="true"/>
<options customize="never" rootVolumeOnly="true"/>
</installer-gui-script>

View File

@ -0,0 +1,6 @@
<pkg-info format-version="2" identifier="com.smartmontools.pkg" version="@version@" install-location="/" auth="root">
<payload installKBytes="@size@" numberOfFiles="@files@"/>
<!-- <scripts>
<postinstall file="./postinstall"/>
</scripts> -->
</pkg-info>

View File

@ -0,0 +1,26 @@
<html>
<body>
<h2>About this package</h2>
The smartmontools package contains two utility programs (smartctl and smartd) to control
and monitor storage systems using the Self-Monitoring, Analysis and Reporting
Technology System (SMART) built into most modern ATA and SCSI harddisks.
In many cases, these utilities will provide advanced warning of disk degradation and failure.
<h2>Installing</h2>
To install package click on the smartmontools.pkg icon and follow installation process. Files will be installed to the <b>/usr/local/</b> directory.
<h2>Usage</h2>
If you are having trouble understanding the output of smartctl or smartd, please first read the manual pages installed on your system:
<pre>
man 8 smartctl
man 8 smartd
man 8 update-smart-drivedb
man 5 smartd.conf
</pre>
To use smartmontools with USB drives please download and install
<a href="https://github.com/kasbert/OS-X-SAT-SMART-Driver">Max OS X kernel driver for providing access to external drive SMART data</a>. SAT SMART Driver is a free open source project (published under Apple Public Source License) by Jarkko Sonninen.
If you are using OS X El Capitan 10.11+ it is recommended to use signed version available from <a href="http://binaryfruit.com/drivedx/usb-drive-support/">DriveDx web site</a>.
<p>
More information could be found on the <a href="https://www.smartmontools.org">www.smartmontools.org</a> website.
<h2>Uninstalling</h2>
If you want to uninstall already installed package run <tt>'sudo smart-pkg-uninstall'</tt> in the terminal.
</body>
</html>

View File

@ -0,0 +1,40 @@
#!/bin/sh
echo "Smartmontools package uninstaller:"
# check if we are running with root uid
if [[ $EUID -ne 0 ]]; then
echo " Error: this script must be run as root"
exit 1
fi
# check if package is installed
pkgutil --info com.smartmontools.pkg > /dev/null 2>/dev/null
if [ $? -ne 0 ]; then
echo " Error: smartmontools package is not installed"
exit 1
fi
# smartmontools pkg could be installed only on system volume, so this should be safe
cd /
echo " - removing files"
for str in `pkgutil --files com.smartmontools.pkg`
do
if [ -f "$str" ]
then
rm -f "$str"
fi
done
echo " - removing empty directories"
for str in `pkgutil --files com.smartmontools.pkg`
do
if [ -d "$str" ]
then
rmdir -p "$str" 2>/dev/null
fi
done
echo " - removing package system entry"
pkgutil --forget com.smartmontools.pkg
echo "Done, smartmontolls package removed"

View File

@ -1,9 +1,9 @@
/* /*
* os_freebsd.c * os_freebsd.c
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2003-10 Eduard Martinescu <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2003-10 Eduard Martinescu
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -38,6 +38,8 @@
#include "config.h" #include "config.h"
#include "int64.h" #include "int64.h"
// set by /usr/include/sys/ata.h, suppress warning
#undef ATA_READ_LOG_EXT
#include "atacmds.h" #include "atacmds.h"
#include "scsicmds.h" #include "scsicmds.h"
#include "cciss.h" #include "cciss.h"
@ -68,6 +70,9 @@
#include <dev/usb/usbhid.h> #include <dev/usb/usbhid.h>
#endif #endif
// based on "/sys/dev/nvme/nvme.h" from FreeBSD kernel sources
#include "freebsd_nvme_ioctl.h" // NVME_PASSTHROUGH_CMD, nvme_completion_is_error
#define CONTROLLER_3WARE_9000_CHAR 0x01 #define CONTROLLER_3WARE_9000_CHAR 0x01
#define CONTROLLER_3WARE_678K_CHAR 0x02 #define CONTROLLER_3WARE_678K_CHAR 0x02
@ -75,7 +80,7 @@
#define PATHINQ_SETTINGS_SIZE 128 #define PATHINQ_SETTINGS_SIZE 128
#endif #endif
const char *os_XXXX_c_cvsid="$Id: os_freebsd.cpp 3902 2014-05-23 19:14:15Z samm2 $" \ const char *os_XXXX_c_cvsid="$Id: os_freebsd.cpp 4257 2016-03-27 23:32:54Z samm2 $" \
ATACMDS_H_CVSID CCISS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_FREEBSD_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; ATACMDS_H_CVSID CCISS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_FREEBSD_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
#define NO_RETURN 0 #define NO_RETURN 0
@ -86,7 +91,11 @@ ATACMDS_H_CVSID CCISS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_FREEBSD_H_CVSID SC
// Utility function for printing warnings // Utility function for printing warnings
void printwarning(int msgNo, const char* extra) { void printwarning(int msgNo, const char* extra) {
if (msgNo >= 0 && msgNo <= MAX_MSG) {
static int printed[] = {0,0,0,0}; static int printed[] = {0,0,0,0};
if (!printed[msgNo]) {
static const char* message[]={ static const char* message[]={
"The SMART RETURN STATUS return value (smartmontools -H option/Directive)\n can not be retrieved with this version of ATAng, please do not rely on this value\nYou should update to at least 5.2\n", "The SMART RETURN STATUS return value (smartmontools -H option/Directive)\n can not be retrieved with this version of ATAng, please do not rely on this value\nYou should update to at least 5.2\n",
@ -97,8 +106,6 @@ void printwarning(int msgNo, const char* extra) {
"ATA support is not provided for this kernel version. Please ugrade to a recent 5-CURRENT kernel (post 09/01/2003 or so)\n" "ATA support is not provided for this kernel version. Please ugrade to a recent 5-CURRENT kernel (post 09/01/2003 or so)\n"
}; };
if (msgNo >= 0 && msgNo <= MAX_MSG) {
if (!printed[msgNo]) {
printed[msgNo] = 1; printed[msgNo] = 1;
pout("%s", message[msgNo]); pout("%s", message[msgNo]);
if (extra) if (extra)
@ -120,8 +127,6 @@ void printwarning(int msgNo, const char* extra) {
#define ARGUSED(x) ((void)(x)) #define ARGUSED(x) ((void)(x))
// global variable holding byte count of allocated memory
long long bytes;
extern unsigned char failuretest_permissive; extern unsigned char failuretest_permissive;
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -466,6 +471,112 @@ int freebsd_atacam_device::do_cmd( struct ata_ioc_request* request, bool is_48bi
#endif #endif
/////////////////////////////////////////////////////////////////////////////
/// NVMe support
class freebsd_nvme_device
: public /*implements*/ nvme_device,
public /*extends*/ freebsd_smart_device
{
public:
freebsd_nvme_device(smart_interface * intf, const char * dev_name,
const char * req_type, unsigned nsid);
virtual bool open();
virtual bool nvme_pass_through(const nvme_cmd_in & in, nvme_cmd_out & out);
};
freebsd_nvme_device::freebsd_nvme_device(smart_interface * intf, const char * dev_name,
const char * req_type, unsigned nsid)
: smart_device(intf, dev_name, "nvme", req_type),
nvme_device(nsid),
freebsd_smart_device()
{
}
bool freebsd_nvme_device::open()
{
const char *dev = get_dev_name();
if (!strnstr(dev, NVME_CTRLR_PREFIX, strlen(NVME_CTRLR_PREFIX))) {
set_err(EINVAL, "NVMe controller controller/namespace ids must begin with '%s'",
NVME_CTRLR_PREFIX);
return false;
}
int nsid = -1, ctrlid = -1;
char tmp;
if(sscanf(dev, NVME_CTRLR_PREFIX"%d%c", &ctrlid, &tmp) == 1)
{
if(ctrlid < 0) {
set_err(EINVAL, "Invalid NVMe controller number");
return false;
}
nsid = 0xFFFFFFFF; // broadcast id
}
else if (sscanf(dev, NVME_CTRLR_PREFIX"%d"NVME_NS_PREFIX"%d%c",
&ctrlid, &nsid, &tmp) == 2)
{
if(ctrlid < 0 || nsid < 0) {
set_err(EINVAL, "Invalid NVMe controller/namespace number");
return false;
}
}
else {
set_err(EINVAL, "Invalid NVMe controller/namespace syntax");
return false;
}
// we should always open controller, not namespace device
char full_path[64];
snprintf(full_path, sizeof(full_path), NVME_CTRLR_PREFIX"%d", ctrlid);
int fd;
if ((fd = ::open(full_path, O_RDWR))<0) {
set_err(errno);
return false;
}
set_fd(fd);
if (!get_nsid()) {
set_nsid(nsid);
}
return true;
}
bool freebsd_nvme_device::nvme_pass_through(const nvme_cmd_in & in, nvme_cmd_out & out)
{
// nvme_passthru_cmd pt;
struct nvme_pt_command pt;
memset(&pt, 0, sizeof(pt));
pt.cmd.opc = in.opcode;
pt.cmd.nsid = in.nsid;
pt.buf = in.buffer;
pt.len = in.size;
pt.cmd.cdw10 = in.cdw10;
pt.cmd.cdw11 = in.cdw11;
pt.cmd.cdw12 = in.cdw12;
pt.cmd.cdw13 = in.cdw13;
pt.cmd.cdw14 = in.cdw14;
pt.cmd.cdw15 = in.cdw15;
pt.is_read = 1; // should we use in.direction()?
int status = ioctl(get_fd(), NVME_PASSTHROUGH_CMD, &pt);
if (status < 0)
return set_err(errno, "NVME_PASSTHROUGH_CMD: %s", strerror(errno));
out.result=pt.cpl.cdw0; // Command specific result (DW0)
if (nvme_completion_is_error(&pt.cpl))
return set_nvme_err(out, nvme_completion_is_error(&pt.cpl));
return true;
}
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/// Implement AMCC/3ware RAID support /// Implement AMCC/3ware RAID support
@ -917,7 +1028,8 @@ bool freebsd_scsi_device::close(){
freebsd_scsi_device::freebsd_scsi_device(smart_interface * intf, freebsd_scsi_device::freebsd_scsi_device(smart_interface * intf,
const char * dev_name, const char * req_type) const char * dev_name, const char * req_type)
: smart_device(intf, dev_name, "scsi", req_type), : smart_device(intf, dev_name, "scsi", req_type),
freebsd_smart_device() freebsd_smart_device(),
m_camdev(0)
{ {
} }
@ -1122,10 +1234,8 @@ freebsd_areca_ata_device::freebsd_areca_ata_device(smart_interface * intf, const
smart_device * freebsd_areca_ata_device::autodetect_open() smart_device * freebsd_areca_ata_device::autodetect_open()
{ {
int is_ata = 1;
// autodetect device type // autodetect device type
is_ata = arcmsr_get_dev_type(); int is_ata = arcmsr_get_dev_type();
if(is_ata < 0) if(is_ata < 0)
{ {
set_err(EIO); set_err(EIO);
@ -1360,6 +1470,9 @@ protected:
virtual scsi_device * get_scsi_device(const char * name, const char * type); virtual scsi_device * get_scsi_device(const char * name, const char * type);
virtual nvme_device * get_nvme_device(const char * name, const char * type,
unsigned nsid);
virtual smart_device * autodetect_smart_device(const char * name); virtual smart_device * autodetect_smart_device(const char * name);
virtual smart_device * get_custom_smart_device(const char * name, const char * type); virtual smart_device * get_custom_smart_device(const char * name, const char * type);
@ -1401,6 +1514,12 @@ scsi_device * freebsd_smart_interface::get_scsi_device(const char * name, const
return new freebsd_scsi_device(this, name, type); return new freebsd_scsi_device(this, name, type);
} }
nvme_device * freebsd_smart_interface::get_nvme_device(const char * name, const char * type,
unsigned nsid)
{
return new freebsd_nvme_device(this, name, type, nsid);
}
// we are using CAM subsystem XPT enumerator to found all CAM (scsi/usb/ada/...) // we are using CAM subsystem XPT enumerator to found all CAM (scsi/usb/ada/...)
// devices on system despite of it's names // devices on system despite of it's names
// //
@ -1476,11 +1595,12 @@ bool get_dev_names_cam(std::vector<std::string> & names, bool show_all)
} }
for (unsigned i = 0; i < ccb.cdm.num_matches; i++) { for (unsigned i = 0; i < ccb.cdm.num_matches; i++) {
struct bus_match_result *bus_result;
struct device_match_result *dev_result; struct device_match_result *dev_result;
struct periph_match_result *periph_result; struct periph_match_result *periph_result;
if (ccb.cdm.matches[i].type == DEV_MATCH_BUS) { if (ccb.cdm.matches[i].type == DEV_MATCH_BUS) {
struct bus_match_result *bus_result;
bus_result = &ccb.cdm.matches[i].result.bus_result; bus_result = &ccb.cdm.matches[i].result.bus_result;
if (strcmp(bus_result->dev_name,"xpt") == 0) /* skip XPT bus at all */ if (strcmp(bus_result->dev_name,"xpt") == 0) /* skip XPT bus at all */
@ -1588,19 +1708,19 @@ int get_dev_names_ata(char*** names) {
n = -1; n = -1;
goto end; goto end;
}; };
bytes+=1+strlen(mp[n]);
n++; n++;
}; };
}; };
}; };
if (n <= 0)
goto end;
mp = (char **)reallocf(mp,n*(sizeof (char*))); // shrink to correct size mp = (char **)reallocf(mp,n*(sizeof (char*))); // shrink to correct size
if (mp == NULL && n > 0 ) { // reallocf never fail for size=0, but may return NULL if (mp == NULL) {
serrno=errno; serrno=errno;
pout("Out of memory constructing scan device list (on line %d)\n", __LINE__); pout("Out of memory constructing scan device list (on line %d)\n", __LINE__);
n = -1; n = -1;
goto end; goto end;
}; };
bytes += (n)*(sizeof(char*)); // and set allocated byte count
end: end:
if (fd>=0) if (fd>=0)
@ -1779,13 +1899,13 @@ static int usbdevlist(int busno,unsigned short & vendor_id,
return false; return false;
#else // freebsd < 8.0 USB stack, ioctl interface #else // freebsd < 8.0 USB stack, ioctl interface
int i, f, a, rc; int i, a, rc;
char buf[50]; char buf[50];
int ncont; int ncont;
for (ncont = 0, i = 0; i < 10; i++) { for (ncont = 0, i = 0; i < 10; i++) {
snprintf(buf, sizeof(buf), "%s%d", USBDEV, i); snprintf(buf, sizeof(buf), "%s%d", USBDEV, i);
f = open(buf, O_RDONLY); int f = open(buf, O_RDONLY);
if (f >= 0) { if (f >= 0) {
memset(done, 0, sizeof done); memset(done, 0, sizeof done);
for (a = 1; a < USB_MAX_DEVICES; a++) { for (a = 1; a < USB_MAX_DEVICES; a++) {
@ -1813,12 +1933,11 @@ smart_device * freebsd_smart_interface::autodetect_smart_device(const char * nam
struct cam_device *cam_dev; struct cam_device *cam_dev;
union ccb ccb; union ccb ccb;
int bus=-1; int bus=-1;
int i,c; int i;
int len;
const char * test_name = name; const char * test_name = name;
// if dev_name null, or string length zero // if dev_name null, or string length zero
if (!name || !(len = strlen(name))) if (!name || !*name)
return 0; return 0;
// Dereference symlinks // Dereference symlinks
@ -1840,7 +1959,7 @@ smart_device * freebsd_smart_interface::autodetect_smart_device(const char * nam
// check ATA/ATAPI devices // check ATA/ATAPI devices
for (i = 0; i < numata; i++) { for (i = 0; i < numata; i++) {
if(!strcmp(atanames[i],test_name)) { if(!strcmp(atanames[i],test_name)) {
for (c = i; c < numata; c++) free(atanames[c]); for (int c = i; c < numata; c++) free(atanames[c]);
free(atanames); free(atanames);
return new freebsd_ata_device(this, test_name, ""); return new freebsd_ata_device(this, test_name, "");
} }
@ -1910,6 +2029,11 @@ smart_device * freebsd_smart_interface::autodetect_smart_device(const char * nam
// device is LSI raid supported by mfi driver // device is LSI raid supported by mfi driver
if(!strncmp("/dev/mfid", test_name, strlen("/dev/mfid"))) if(!strncmp("/dev/mfid", test_name, strlen("/dev/mfid")))
set_err(EINVAL, "To monitor disks on LSI RAID load mfip.ko module and run 'smartctl -a /dev/passX' to show SMART information"); set_err(EINVAL, "To monitor disks on LSI RAID load mfip.ko module and run 'smartctl -a /dev/passX' to show SMART information");
// form /dev/nvme* or nvme*
if(!strncmp("/dev/nvme", test_name, strlen("/dev/nvme")))
return new freebsd_nvme_device(this, name, "", 0 /* use default nsid */);
// device type unknown // device type unknown
return 0; return 0;
} }
@ -1917,13 +2041,15 @@ smart_device * freebsd_smart_interface::autodetect_smart_device(const char * nam
smart_device * freebsd_smart_interface::get_custom_smart_device(const char * name, const char * type) smart_device * freebsd_smart_interface::get_custom_smart_device(const char * name, const char * type)
{ {
int disknum = -1, n1 = -1, n2 = -1;
if (sscanf(type, "3ware,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) {
// 3Ware ? // 3Ware ?
static const char * fbsd_dev_twe_ctrl = "/dev/twe"; static const char * fbsd_dev_twe_ctrl = "/dev/twe";
static const char * fbsd_dev_twa_ctrl = "/dev/twa"; static const char * fbsd_dev_twa_ctrl = "/dev/twa";
static const char * fbsd_dev_tws_ctrl = "/dev/tws"; static const char * fbsd_dev_tws_ctrl = "/dev/tws";
int disknum = -1, n1 = -1, n2 = -1, contr = -1; int contr = -1;
if (sscanf(type, "3ware,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) {
if (n2 != (int)strlen(type)) { if (n2 != (int)strlen(type)) {
set_err(EINVAL, "Option -d 3ware,N requires N to be a non-negative integer"); set_err(EINVAL, "Option -d 3ware,N requires N to be a non-negative integer");
return 0; return 0;

View File

@ -1,7 +1,7 @@
/* /*
* os_freebsd.h * os_freebsd.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2003-8 Eduard Martinescu <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2003-8 Eduard Martinescu <smartmontools-support@lists.sourceforge.net>
* *
@ -82,7 +82,7 @@
#ifndef OS_FREEBSD_H_ #ifndef OS_FREEBSD_H_
#define OS_FREEBSD_H_ #define OS_FREEBSD_H_
#define OS_FREEBSD_H_CVSID "$Id: os_freebsd.h 3727 2012-12-13 17:23:06Z samm2 $" #define OS_FREEBSD_H_CVSID "$Id: os_freebsd.h 4120 2015-08-27 16:12:21Z samm2 $"
#define MAX_NUM_DEV 26 #define MAX_NUM_DEV 26

View File

@ -1,7 +1,7 @@
/* /*
* os_generic.cpp * os_generic.cpp
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) YEAR YOUR_NAME <smartmontools-support@lists.sourceforge.net> * Copyright (C) YEAR YOUR_NAME <smartmontools-support@lists.sourceforge.net>
* Copyright (C) 2003-8 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2003-8 Bruce Allen <smartmontools-support@lists.sourceforge.net>
@ -83,7 +83,7 @@
// should have one *_H_CVSID macro appearing below for each file // should have one *_H_CVSID macro appearing below for each file
// appearing with #include "*.h" above. Please list these (below) in // appearing with #include "*.h" above. Please list these (below) in
// alphabetic/dictionary order. // alphabetic/dictionary order.
const char * os_XXXX_cpp_cvsid="$Id: os_generic.cpp 3579 2012-07-20 17:50:12Z chrfranke $" const char * os_XXXX_cpp_cvsid="$Id: os_generic.cpp 4120 2015-08-27 16:12:21Z samm2 $"
ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_GENERIC_H_CVSID UTILITY_H_CVSID; ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_GENERIC_H_CVSID UTILITY_H_CVSID;
// This is here to prevent compiler warnings for unused arguments of // This is here to prevent compiler warnings for unused arguments of

View File

@ -1,7 +1,7 @@
/* /*
* os_generic.h * os_generic.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) YEAR YOUR_NAME <smartmontools-support@lists.sourceforge.net> * Copyright (C) YEAR YOUR_NAME <smartmontools-support@lists.sourceforge.net>
* Copyright (C) 2003-8 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2003-8 Bruce Allen <smartmontools-support@lists.sourceforge.net>
@ -25,7 +25,7 @@
// In the three following lines, change 'GENERIC' to your OS name // In the three following lines, change 'GENERIC' to your OS name
#ifndef OS_GENERIC_H_ #ifndef OS_GENERIC_H_
#define OS_GENERIC_H_ #define OS_GENERIC_H_
#define OS_GENERIC_H_CVSID "$Id: os_generic.h 3728 2012-12-13 17:57:50Z chrfranke $\n" #define OS_GENERIC_H_CVSID "$Id: os_generic.h 4120 2015-08-27 16:12:21Z samm2 $\n"
// Additional material should start here. Note: to keep the '-V' CVS // Additional material should start here. Note: to keep the '-V' CVS
// reporting option working as intended, you should only #include // reporting option working as intended, you should only #include

View File

@ -1,11 +1,11 @@
/* /*
* os_linux.cpp * os_linux.cpp
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2003-11 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2003-11 Bruce Allen
* Copyright (C) 2003-11 Doug Gilbert <dgilbert@interlog.com> * Copyright (C) 2003-11 Doug Gilbert <dgilbert@interlog.com>
* Copyright (C) 2008-14 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2008-16 Christian Franke
* *
* Original AACRaid code: * Original AACRaid code:
* Copyright (C) 2014 Raghava Aditya <raghava.aditya@pmcs.com> * Copyright (C) 2014 Raghava Aditya <raghava.aditya@pmcs.com>
@ -93,13 +93,16 @@
#include "dev_ata_cmd_set.h" #include "dev_ata_cmd_set.h"
#include "dev_areca.h" #include "dev_areca.h"
// "include/uapi/linux/nvme_ioctl.h" from Linux kernel sources
#include "linux_nvme_ioctl.h" // nvme_passthru_cmd, NVME_IOCTL_ADMIN_CMD
#ifndef ENOTSUP #ifndef ENOTSUP
#define ENOTSUP ENOSYS #define ENOTSUP ENOSYS
#endif #endif
#define ARGUSED(x) ((void)(x)) #define ARGUSED(x) ((void)(x))
const char * os_linux_cpp_cvsid = "$Id: os_linux.cpp 3900 2014-05-01 17:08:59Z chrfranke $" const char * os_linux_cpp_cvsid = "$Id: os_linux.cpp 4295 2016-04-15 20:01:32Z chrfranke $"
OS_LINUX_H_CVSID; OS_LINUX_H_CVSID;
extern unsigned char failuretest_permissive; extern unsigned char failuretest_permissive;
@ -194,11 +197,11 @@ bool linux_smart_device::close()
// examples for smartctl // examples for smartctl
static const char smartctl_examples[] = static const char smartctl_examples[] =
"=================================================== SMARTCTL EXAMPLES =====\n\n" "=================================================== SMARTCTL EXAMPLES =====\n\n"
" smartctl --all /dev/hda (Prints all SMART information)\n\n" " smartctl --all /dev/sda (Prints all SMART information)\n\n"
" smartctl --smart=on --offlineauto=on --saveauto=on /dev/hda\n" " smartctl --smart=on --offlineauto=on --saveauto=on /dev/sda\n"
" (Enables SMART on first disk)\n\n" " (Enables SMART on first disk)\n\n"
" smartctl --test=long /dev/hda (Executes extended disk self-test)\n\n" " smartctl --test=long /dev/sda (Executes extended disk self-test)\n\n"
" smartctl --attributes --log=selftest --quietmode=errorsonly /dev/hda\n" " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/sda\n"
" (Prints Self-Test & Attribute errors)\n" " (Prints Self-Test & Attribute errors)\n"
" smartctl --all --device=3ware,2 /dev/sda\n" " smartctl --all --device=3ware,2 /dev/sda\n"
" smartctl --all --device=3ware,2 /dev/twe0\n" " smartctl --all --device=3ware,2 /dev/twe0\n"
@ -356,7 +359,6 @@ int linux_ata_device::ata_command_interface(smart_command_set command, int selec
unsigned char task[sizeof(ide_task_request_t)+512]; unsigned char task[sizeof(ide_task_request_t)+512];
ide_task_request_t *reqtask=(ide_task_request_t *) task; ide_task_request_t *reqtask=(ide_task_request_t *) task;
task_struct_t *taskfile=(task_struct_t *) reqtask->io_ports; task_struct_t *taskfile=(task_struct_t *) reqtask->io_ports;
int retval;
memset(task, 0, sizeof(task)); memset(task, 0, sizeof(task));
@ -377,9 +379,9 @@ int linux_ata_device::ata_command_interface(smart_command_set command, int selec
// copy user data into the task request structure // copy user data into the task request structure
memcpy(task+sizeof(ide_task_request_t), data, 512); memcpy(task+sizeof(ide_task_request_t), data, 512);
if ((retval=ioctl(get_fd(), HDIO_DRIVE_TASKFILE, task))) { if (ioctl(get_fd(), HDIO_DRIVE_TASKFILE, task)) {
if (retval==-EINVAL) if (errno==EINVAL)
pout("Kernel lacks HDIO_DRIVE_TASKFILE support; compile kernel with CONFIG_IDE_TASKFILE_IO set\n"); pout("Kernel lacks HDIO_DRIVE_TASKFILE support; compile kernel with CONFIG_IDE_TASK_IOCTL set\n");
return -1; return -1;
} }
return 0; return 0;
@ -388,8 +390,6 @@ int linux_ata_device::ata_command_interface(smart_command_set command, int selec
// There are two different types of ioctls(). The HDIO_DRIVE_TASK // There are two different types of ioctls(). The HDIO_DRIVE_TASK
// one is this: // one is this:
if (command==STATUS_CHECK || command==AUTOSAVE || command==AUTO_OFFLINE){ if (command==STATUS_CHECK || command==AUTOSAVE || command==AUTO_OFFLINE){
int retval;
// NOT DOCUMENTED in /usr/src/linux/include/linux/hdreg.h. You // NOT DOCUMENTED in /usr/src/linux/include/linux/hdreg.h. You
// have to read the IDE driver source code. Sigh. // have to read the IDE driver source code. Sigh.
// buff[0]: ATA COMMAND CODE REGISTER // buff[0]: ATA COMMAND CODE REGISTER
@ -405,8 +405,8 @@ int linux_ata_device::ata_command_interface(smart_command_set command, int selec
buff[4]=normal_lo; buff[4]=normal_lo;
buff[5]=normal_hi; buff[5]=normal_hi;
if ((retval=ioctl(get_fd(), HDIO_DRIVE_TASK, buff))) { if (ioctl(get_fd(), HDIO_DRIVE_TASK, buff)) {
if (retval==-EINVAL) { if (errno==EINVAL) {
pout("Error SMART Status command via HDIO_DRIVE_TASK failed"); pout("Error SMART Status command via HDIO_DRIVE_TASK failed");
pout("Rebuild older linux 2.2 kernels with HDIO_DRIVE_TASK support added\n"); pout("Rebuild older linux 2.2 kernels with HDIO_DRIVE_TASK support added\n");
} }
@ -548,14 +548,14 @@ static int sg_io_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report,
(DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) { (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
int trunc = (iop->dxfer_len > 256) ? 1 : 0; int trunc = (iop->dxfer_len > 256) ? 1 : 0;
j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing " snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing "
"data, len=%d%s:\n", (int)iop->dxfer_len, "data, len=%d%s:\n", (int)iop->dxfer_len,
(trunc ? " [only first 256 bytes shown]" : "")); (trunc ? " [only first 256 bytes shown]" : ""));
dStrHex((const char *)iop->dxferp, dStrHex((const char *)iop->dxferp,
(trunc ? 256 : iop->dxfer_len) , 1); (trunc ? 256 : iop->dxfer_len) , 1);
} }
else else
j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n"); snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
pout("%s", buff); pout("%s", buff);
} }
memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
@ -648,7 +648,7 @@ static int sg_io_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report,
} }
} }
if (report) { if (report) {
if (SCSI_STATUS_CHECK_CONDITION == iop->scsi_status) { if (SCSI_STATUS_CHECK_CONDITION == iop->scsi_status && iop->sensep) {
if ((iop->sensep[0] & 0x7f) > 0x71) if ((iop->sensep[0] & 0x7f) > 0x71)
pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n", pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
iop->scsi_status, iop->sensep[1] & 0xf, iop->scsi_status, iop->sensep[1] & 0xf,
@ -696,18 +696,17 @@ static int sisc_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report)
j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>"); j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
for (k = 0; k < (int)iop->cmnd_len; ++k) for (k = 0; k < (int)iop->cmnd_len; ++k)
j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]); j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);
if ((report > 1) && if ((report > 1) && (DXFER_TO_DEVICE == iop->dxfer_dir)) {
(DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
int trunc = (iop->dxfer_len > 256) ? 1 : 0; int trunc = (iop->dxfer_len > 256) ? 1 : 0;
j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing " snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing "
"data, len=%d%s:\n", (int)iop->dxfer_len, "data, len=%d%s:\n", (int)iop->dxfer_len,
(trunc ? " [only first 256 bytes shown]" : "")); (trunc ? " [only first 256 bytes shown]" : ""));
dStrHex((const char *)iop->dxferp, dStrHex((const char *)iop->dxferp,
(trunc ? 256 : iop->dxfer_len) , 1); (trunc ? 256 : iop->dxfer_len) , 1);
} }
else else
j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n"); snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
pout("%s", buff); pout("%s", buff);
} }
switch (iop->dxfer_dir) { switch (iop->dxfer_dir) {
@ -977,14 +976,14 @@ bool linux_aacraid_device::scsi_pass_through(scsi_cmnd_io *iop)
(DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) { (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
int trunc = (iop->dxfer_len > 256) ? 1 : 0; int trunc = (iop->dxfer_len > 256) ? 1 : 0;
j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing " snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing "
"data, len=%d%s:\n", (int)iop->dxfer_len, "data, len=%d%s:\n", (int)iop->dxfer_len,
(trunc ? " [only first 256 bytes shown]" : "")); (trunc ? " [only first 256 bytes shown]" : ""));
dStrHex((const char *)iop->dxferp, dStrHex((const char *)iop->dxferp,
(trunc ? 256 : iop->dxfer_len) , 1); (trunc ? 256 : iop->dxfer_len) , 1);
} }
else else
j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n"); snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
pout("%s", buff); pout("%s", buff);
} }
@ -1002,7 +1001,7 @@ bool linux_aacraid_device::scsi_pass_through(scsi_cmnd_io *iop)
uint8_t aBuff[sizeof(user_aac_srb64) + sizeof(user_aac_reply)] = {0,}; uint8_t aBuff[sizeof(user_aac_srb64) + sizeof(user_aac_reply)] = {0,};
pSrb = (user_aac_srb64*)aBuff; pSrb = (user_aac_srb64*)aBuff;
pReply = (user_aac_reply*)(aBuff+sizeof(user_aac_srb64)); pSrb->count = sizeof(user_aac_srb64) - sizeof(user_sgentry64);
#elif defined(ENVIRONMENT32) #elif defined(ENVIRONMENT32)
//Create user 32 bit request //Create user 32 bit request
@ -1010,8 +1009,7 @@ bool linux_aacraid_device::scsi_pass_through(scsi_cmnd_io *iop)
uint8_t aBuff[sizeof(user_aac_srb32) + sizeof(user_aac_reply)] = {0,}; uint8_t aBuff[sizeof(user_aac_srb32) + sizeof(user_aac_reply)] = {0,};
pSrb = (user_aac_srb32*)aBuff; pSrb = (user_aac_srb32*)aBuff;
pReply = (user_aac_reply*)(aBuff+sizeof(user_aac_srb32)); pSrb->count = sizeof(user_aac_srb32) - sizeof(user_sgentry32);
#endif #endif
pSrb->function = SRB_FUNCTION_EXECUTE_SCSI; pSrb->function = SRB_FUNCTION_EXECUTE_SCSI;
@ -1048,33 +1046,60 @@ bool linux_aacraid_device::scsi_pass_through(scsi_cmnd_io *iop)
pSrb->sg64.sg64[0].addr64.hi32 = ((intptr_t)iop->dxferp) >> 32; pSrb->sg64.sg64[0].addr64.hi32 = ((intptr_t)iop->dxferp) >> 32;
pSrb->sg64.sg64[0].length = (uint32_t)iop->dxfer_len; pSrb->sg64.sg64[0].length = (uint32_t)iop->dxfer_len;
pSrb->count = sizeof(user_aac_srb64) + pSrb->count += pSrb->sg64.count * sizeof(user_sgentry64);
(sizeof(user_sgentry64)*(pSrb->sg64.count-1));
#elif defined(ENVIRONMENT32) #elif defined(ENVIRONMENT32)
pSrb->sg32.count = 1; pSrb->sg32.count = 1;
pSrb->sg32.sg32[0].addr32 = (intptr_t)iop->dxferp; pSrb->sg32.sg32[0].addr32 = (intptr_t)iop->dxferp;
pSrb->sg32.sg32[0].length = (uint32_t)iop->dxfer_len; pSrb->sg32.sg32[0].length = (uint32_t)iop->dxfer_len;
pSrb->count = sizeof(user_aac_srb32) + pSrb->count += pSrb->sg32.count * sizeof(user_sgentry32);
(sizeof(user_sgentry32)*(pSrb->sg32.count-1));
#endif #endif
} }
pReply = (user_aac_reply*)(aBuff+pSrb->count);
memcpy(pSrb->cdb,iop->cmnd,iop->cmnd_len); memcpy(pSrb->cdb,iop->cmnd,iop->cmnd_len);
int rc = 0; int rc = 0;
errno = 0; errno = 0;
rc = ioctl(get_fd(),FSACTL_SEND_RAW_SRB,pSrb); rc = ioctl(get_fd(),FSACTL_SEND_RAW_SRB,pSrb);
if(rc!= 0 || pReply->srb_status != 0x01) {
if(pReply->srb_status == 0x08) { if (rc != 0)
return set_err(EIO, "aacraid: Device %d %d does not exist\n" ,aLun,aId ); return set_err(errno, "aacraid send_raw_srb: %d.%d = %s",
aLun, aId, strerror(errno));
/* see kernel aacraid.h and MSDN SCSI_REQUEST_BLOCK documentation */
#define SRB_STATUS_SUCCESS 0x1
#define SRB_STATUS_ERROR 0x4
#define SRB_STATUS_NO_DEVICE 0x08
#define SRB_STATUS_SELECTION_TIMEOUT 0x0a
#define SRB_STATUS_AUTOSENSE_VALID 0x80
iop->scsi_status = pReply->scsi_status;
if (pReply->srb_status == (SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_ERROR)
&& iop->scsi_status == SCSI_STATUS_CHECK_CONDITION) {
memcpy(iop->sensep, pReply->sense_data, pReply->sense_data_size);
iop->resp_sense_len = pReply->sense_data_size;
return true; /* request completed with sense data */
} }
return set_err((errno ? errno : EIO), "aacraid result: %d.%d = %d/%d",
aLun, aId, errno, switch (pReply->srb_status & 0x3f) {
pReply->srb_status);
case SRB_STATUS_SUCCESS:
return true; /* request completed successfully */
case SRB_STATUS_NO_DEVICE:
return set_err(EIO, "aacraid: Device %d %d does not exist", aLun, aId);
case SRB_STATUS_SELECTION_TIMEOUT:
return set_err(EIO, "aacraid: Device %d %d not responding", aLun, aId);
default:
return set_err(EIO, "aacraid result: %d.%d = 0x%x",
aLun, aId, pReply->srb_status);
} }
return true;
} }
@ -1087,7 +1112,7 @@ class linux_megaraid_device
{ {
public: public:
linux_megaraid_device(smart_interface *intf, const char *name, linux_megaraid_device(smart_interface *intf, const char *name,
unsigned int bus, unsigned int tgt); unsigned int tgt);
virtual ~linux_megaraid_device() throw(); virtual ~linux_megaraid_device() throw();
@ -1100,7 +1125,6 @@ public:
private: private:
unsigned int m_disknum; unsigned int m_disknum;
unsigned int m_busnum;
unsigned int m_hba; unsigned int m_hba;
int m_fd; int m_fd;
@ -1113,10 +1137,10 @@ private:
}; };
linux_megaraid_device::linux_megaraid_device(smart_interface *intf, linux_megaraid_device::linux_megaraid_device(smart_interface *intf,
const char *dev_name, unsigned int bus, unsigned int tgt) const char *dev_name, unsigned int tgt)
: smart_device(intf, dev_name, "megaraid", "megaraid"), : smart_device(intf, dev_name, "megaraid", "megaraid"),
linux_smart_device(O_RDWR | O_NONBLOCK), linux_smart_device(O_RDWR | O_NONBLOCK),
m_disknum(tgt), m_busnum(bus), m_hba(0), m_disknum(tgt), m_hba(0),
m_fd(-1), pt_cmd(0) m_fd(-1), pt_cmd(0)
{ {
set_info().info_name = strprintf("%s [megaraid_disk_%02d]", dev_name, m_disknum); set_info().info_name = strprintf("%s [megaraid_disk_%02d]", dev_name, m_disknum);
@ -1176,7 +1200,7 @@ bool linux_megaraid_device::open()
int mjr; int mjr;
int report = scsi_debugmode; int report = scsi_debugmode;
if(sscanf(get_dev_name(),"/dev/bus/%d", &m_hba) == 0) { if (sscanf(get_dev_name(), "/dev/bus/%u", &m_hba) == 0) {
if (!linux_smart_device::open()) if (!linux_smart_device::open())
return false; return false;
/* Get device HBA */ /* Get device HBA */
@ -1256,14 +1280,14 @@ bool linux_megaraid_device::scsi_pass_through(scsi_cmnd_io *iop)
(DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) { (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
int trunc = (iop->dxfer_len > 256) ? 1 : 0; int trunc = (iop->dxfer_len > 256) ? 1 : 0;
j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing " snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing "
"data, len=%d%s:\n", (int)iop->dxfer_len, "data, len=%d%s:\n", (int)iop->dxfer_len,
(trunc ? " [only first 256 bytes shown]" : "")); (trunc ? " [only first 256 bytes shown]" : ""));
dStrHex((const char *)iop->dxferp, dStrHex((const char *)iop->dxferp,
(trunc ? 256 : iop->dxfer_len) , 1); (trunc ? 256 : iop->dxfer_len) , 1);
} }
else else
j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n"); snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
pout("%s", buff); pout("%s", buff);
} }
@ -1299,7 +1323,6 @@ bool linux_megaraid_device::megasas_cmd(int cdbLen, void *cdb,
{ {
struct megasas_pthru_frame *pthru; struct megasas_pthru_frame *pthru;
struct megasas_iocpacket uio; struct megasas_iocpacket uio;
int rc;
memset(&uio, 0, sizeof(uio)); memset(&uio, 0, sizeof(uio));
pthru = &uio.frame.pthru; pthru = &uio.frame.pthru;
@ -1341,9 +1364,8 @@ bool linux_megaraid_device::megasas_cmd(int cdbLen, void *cdb,
uio.sgl[0].iov_len = dataLen; uio.sgl[0].iov_len = dataLen;
} }
rc = 0;
errno = 0; errno = 0;
rc = ioctl(m_fd, MEGASAS_IOC_FIRMWARE, &uio); int rc = ioctl(m_fd, MEGASAS_IOC_FIRMWARE, &uio);
if (pthru->cmd_status || rc != 0) { if (pthru->cmd_status || rc != 0) {
if (pthru->cmd_status == 12) { if (pthru->cmd_status == 12) {
return set_err(EIO, "megasas_cmd: Device %d does not exist\n", m_disknum); return set_err(EIO, "megasas_cmd: Device %d does not exist\n", m_disknum);
@ -1965,10 +1987,8 @@ linux_areca_ata_device::linux_areca_ata_device(smart_interface * intf, const cha
smart_device * linux_areca_ata_device::autodetect_open() smart_device * linux_areca_ata_device::autodetect_open()
{ {
int is_ata = 1;
// autodetect device type // autodetect device type
is_ata = arcmsr_get_dev_type(); int is_ata = arcmsr_get_dev_type();
if(is_ata < 0) if(is_ata < 0)
{ {
set_err(EIO); set_err(EIO);
@ -2345,7 +2365,6 @@ int linux_highpoint_device::ata_command_interface(smart_command_set command, int
unsigned int *hpt_tf = (unsigned int *)task; unsigned int *hpt_tf = (unsigned int *)task;
ide_task_request_t *reqtask = (ide_task_request_t *)(&task[4*sizeof(int)]); ide_task_request_t *reqtask = (ide_task_request_t *)(&task[4*sizeof(int)]);
task_struct_t *taskfile = (task_struct_t *)reqtask->io_ports; task_struct_t *taskfile = (task_struct_t *)reqtask->io_ports;
int retval;
memset(task, 0, sizeof(task)); memset(task, 0, sizeof(task));
@ -2370,16 +2389,13 @@ int linux_highpoint_device::ata_command_interface(smart_command_set command, int
memcpy(task+sizeof(ide_task_request_t)+4*sizeof(int), data, 512); memcpy(task+sizeof(ide_task_request_t)+4*sizeof(int), data, 512);
if ((retval=ioctl(get_fd(), HPTIO_CTL, task))) { if (ioctl(get_fd(), HPTIO_CTL, task))
if (retval==-EINVAL)
pout("Kernel lacks HDIO_DRIVE_TASKFILE support; compile kernel with CONFIG_IDE_TASKFILE_IO set\n");
return -1; return -1;
}
return 0; return 0;
} }
if (command==STATUS_CHECK){ if (command==STATUS_CHECK){
int retval;
unsigned const char normal_lo=0x4f, normal_hi=0xc2; unsigned const char normal_lo=0x4f, normal_hi=0xc2;
unsigned const char failed_lo=0xf4, failed_hi=0x2c; unsigned const char failed_lo=0xf4, failed_hi=0x2c;
buff[4]=normal_lo; buff[4]=normal_lo;
@ -2387,15 +2403,8 @@ int linux_highpoint_device::ata_command_interface(smart_command_set command, int
hpt[2] = HDIO_DRIVE_TASK; hpt[2] = HDIO_DRIVE_TASK;
if ((retval=ioctl(get_fd(), HPTIO_CTL, hpt_buff))) { if (ioctl(get_fd(), HPTIO_CTL, hpt_buff))
if (retval==-EINVAL) {
pout("Error SMART Status command via HDIO_DRIVE_TASK failed");
pout("Rebuild older linux 2.2 kernels with HDIO_DRIVE_TASK support added\n");
}
else
syserror("Error SMART Status command failed");
return -1; return -1;
}
if (buff[4]==normal_lo && buff[5]==normal_hi) if (buff[4]==normal_lo && buff[5]==normal_hi)
return 0; return 0;
@ -2570,6 +2579,76 @@ smart_device * linux_scsi_device::autodetect_open()
return this; return this;
} }
/////////////////////////////////////////////////////////////////////////////
/// NVMe support
class linux_nvme_device
: public /*implements*/ nvme_device,
public /*extends*/ linux_smart_device
{
public:
linux_nvme_device(smart_interface * intf, const char * dev_name,
const char * req_type, unsigned nsid);
virtual bool open();
virtual bool nvme_pass_through(const nvme_cmd_in & in, nvme_cmd_out & out);
};
linux_nvme_device::linux_nvme_device(smart_interface * intf, const char * dev_name,
const char * req_type, unsigned nsid)
: smart_device(intf, dev_name, "nvme", req_type),
nvme_device(nsid),
linux_smart_device(O_RDONLY | O_NONBLOCK)
{
}
bool linux_nvme_device::open()
{
if (!linux_smart_device::open())
return false;
if (!get_nsid()) {
// Use actual NSID (/dev/nvmeXnN) if available,
// else use broadcast namespace (/dev/nvmeX)
int nsid = ioctl(get_fd(), NVME_IOCTL_ID, (void*)0);
set_nsid(nsid);
}
return true;
}
bool linux_nvme_device::nvme_pass_through(const nvme_cmd_in & in, nvme_cmd_out & out)
{
nvme_passthru_cmd pt;
memset(&pt, 0, sizeof(pt));
pt.opcode = in.opcode;
pt.nsid = in.nsid;
pt.addr = (uint64_t)in.buffer;
pt.data_len = in.size;
pt.cdw10 = in.cdw10;
pt.cdw11 = in.cdw11;
pt.cdw12 = in.cdw12;
pt.cdw13 = in.cdw13;
pt.cdw14 = in.cdw14;
pt.cdw15 = in.cdw15;
// Kernel default for NVMe admin commands is 60 seconds
// pt.timeout_ms = 60 * 1000;
int status = ioctl(get_fd(), NVME_IOCTL_ADMIN_CMD, &pt);
if (status < 0)
return set_err(errno, "NVME_IOCTL_ADMIN_CMD: %s", strerror(errno));
if (status > 0)
return set_nvme_err(out, status);
out.result = pt.result;
return true;
}
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// USB bridge ID detection // USB bridge ID detection
@ -2642,6 +2721,9 @@ protected:
virtual scsi_device * get_scsi_device(const char * name, const char * type); virtual scsi_device * get_scsi_device(const char * name, const char * type);
virtual nvme_device * get_nvme_device(const char * name, const char * type,
unsigned nsid);
virtual smart_device * autodetect_smart_device(const char * name); virtual smart_device * autodetect_smart_device(const char * name);
virtual smart_device * get_custom_smart_device(const char * name, const char * type); virtual smart_device * get_custom_smart_device(const char * name, const char * type);
@ -2650,7 +2732,9 @@ protected:
private: private:
bool get_dev_list(smart_device_list & devlist, const char * pattern, bool get_dev_list(smart_device_list & devlist, const char * pattern,
bool scan_ata, bool scan_scsi, const char * req_type, bool autodetect); bool scan_ata, bool scan_scsi, bool scan_nvme,
const char * req_type, bool autodetect);
bool get_dev_megasas(smart_device_list & devlist); bool get_dev_megasas(smart_device_list & devlist);
smart_device * missing_option(const char * opt); smart_device * missing_option(const char * opt);
int megasas_dcmd_cmd(int bus_no, uint32_t opcode, void *buf, int megasas_dcmd_cmd(int bus_no, uint32_t opcode, void *buf,
@ -2675,10 +2759,9 @@ std::string linux_smart_interface::get_app_examples(const char * appname)
} }
// we are going to take advantage of the fact that Linux's devfs will only // we are going to take advantage of the fact that Linux's devfs will only
// have device entries for devices that exist. So if we get the equivalent of // have device entries for devices that exist.
// ls /dev/hd[a-t], we have all the ATA devices on the system
bool linux_smart_interface::get_dev_list(smart_device_list & devlist, bool linux_smart_interface::get_dev_list(smart_device_list & devlist,
const char * pattern, bool scan_ata, bool scan_scsi, const char * pattern, bool scan_ata, bool scan_scsi, bool scan_nvme,
const char * req_type, bool autodetect) const char * req_type, bool autodetect)
{ {
// Use glob to look for any directory entries matching the pattern // Use glob to look for any directory entries matching the pattern
@ -2761,6 +2844,8 @@ bool linux_smart_interface::get_dev_list(smart_device_list & devlist,
dev = autodetect_smart_device(name); dev = autodetect_smart_device(name);
else if (is_scsi) else if (is_scsi)
dev = new linux_scsi_device(this, name, req_type, true /*scanning*/); dev = new linux_scsi_device(this, name, req_type, true /*scanning*/);
else if (scan_nvme)
dev = new linux_nvme_device(this, name, req_type, 0 /* use default nsid */);
else else
dev = new linux_ata_device(this, name, req_type); dev = new linux_ata_device(this, name, req_type);
if (dev) // autodetect_smart_device() may return nullptr. if (dev) // autodetect_smart_device() may return nullptr.
@ -2799,20 +2884,19 @@ bool linux_smart_interface::get_dev_megasas(smart_device_list & devlist)
return false; return false;
// getting bus numbers with megasas devices // getting bus numbers with megasas devices
struct dirent *ep; // we are using sysfs to get list of all scsi hosts
unsigned int host_no = 0;
char sysfsdir[256];
/* we are using sysfs to get list of all scsi hosts */
DIR * dp = opendir ("/sys/class/scsi_host/"); DIR * dp = opendir ("/sys/class/scsi_host/");
if (dp != NULL) if (dp != NULL)
{ {
struct dirent *ep;
while ((ep = readdir (dp)) != NULL) { while ((ep = readdir (dp)) != NULL) {
if (!sscanf(ep->d_name, "host%d", &host_no)) unsigned int host_no = 0;
if (!sscanf(ep->d_name, "host%u", &host_no))
continue; continue;
/* proc_name should be megaraid_sas */ /* proc_name should be megaraid_sas */
char sysfsdir[256];
snprintf(sysfsdir, sizeof(sysfsdir) - 1, snprintf(sysfsdir, sizeof(sysfsdir) - 1,
"/sys/class/scsi_host/host%d/proc_name", host_no); "/sys/class/scsi_host/host%u/proc_name", host_no);
if((fp = fopen(sysfsdir, "r")) == NULL) if((fp = fopen(sysfsdir, "r")) == NULL)
continue; continue;
if(fgets(line, sizeof(line), fp) != NULL && !strncmp(line,"megaraid_sas",12)) { if(fgets(line, sizeof(line), fp) != NULL && !strncmp(line,"megaraid_sas",12)) {
@ -2842,19 +2926,32 @@ bool linux_smart_interface::scan_smart_devices(smart_device_list & devlist,
bool scan_ata = (!*type || !strcmp(type, "ata" )); bool scan_ata = (!*type || !strcmp(type, "ata" ));
// "sat" detection will be later handled in linux_scsi_device::autodetect_open() // "sat" detection will be later handled in linux_scsi_device::autodetect_open()
bool scan_scsi = (!*type || !strcmp(type, "scsi") || !strcmp(type, "sat")); bool scan_scsi = (!*type || !strcmp(type, "scsi") || !strcmp(type, "sat"));
if (!(scan_ata || scan_scsi))
return true; #ifdef WITH_NVME_DEVICESCAN // TODO: Remove when NVMe support is no longer EXPERIMENTAL
bool scan_nvme = (!*type || !strcmp(type, "nvme"));
#else
bool scan_nvme = ( !strcmp(type, "nvme"));
#endif
if (!(scan_ata || scan_scsi || scan_nvme)) {
set_err(EINVAL, "Invalid type '%s', valid arguments are: ata, scsi, sat, nvme", type);
return false;
}
if (scan_ata) if (scan_ata)
get_dev_list(devlist, "/dev/hd[a-t]", true, false, type, false); get_dev_list(devlist, "/dev/hd[a-t]", true, false, false, type, false);
if (scan_scsi) { if (scan_scsi) {
bool autodetect = !*type; // Try USB autodetection if no type specifed bool autodetect = !*type; // Try USB autodetection if no type specifed
get_dev_list(devlist, "/dev/sd[a-z]", false, true, type, autodetect); get_dev_list(devlist, "/dev/sd[a-z]", false, true, false, type, autodetect);
// Support up to 104 devices // Support up to 104 devices
get_dev_list(devlist, "/dev/sd[a-c][a-z]", false, true, type, autodetect); get_dev_list(devlist, "/dev/sd[a-c][a-z]", false, true, false, type, autodetect);
// get device list from the megaraid device // get device list from the megaraid device
get_dev_megasas(devlist); get_dev_megasas(devlist);
} }
if (scan_nvme) {
get_dev_list(devlist, "/dev/nvme[0-9]", false, false, true, type, false);
get_dev_list(devlist, "/dev/nvme[1-9][0-9]", false, false, true, type, false);
}
// if we found traditional links, we are done // if we found traditional links, we are done
if (devlist.size() > 0) if (devlist.size() > 0)
@ -2862,7 +2959,7 @@ bool linux_smart_interface::scan_smart_devices(smart_device_list & devlist,
// else look for devfs entries without traditional links // else look for devfs entries without traditional links
// TODO: Add udev support // TODO: Add udev support
return get_dev_list(devlist, "/dev/discs/disc*", scan_ata, scan_scsi, type, false); return get_dev_list(devlist, "/dev/discs/disc*", scan_ata, scan_scsi, false, type, false);
} }
ata_device * linux_smart_interface::get_ata_device(const char * name, const char * type) ata_device * linux_smart_interface::get_ata_device(const char * name, const char * type)
@ -2875,6 +2972,12 @@ scsi_device * linux_smart_interface::get_scsi_device(const char * name, const ch
return new linux_scsi_device(this, name, type); return new linux_scsi_device(this, name, type);
} }
nvme_device * linux_smart_interface::get_nvme_device(const char * name, const char * type,
unsigned nsid)
{
return new linux_nvme_device(this, name, type, nsid);
}
smart_device * linux_smart_interface::missing_option(const char * opt) smart_device * linux_smart_interface::missing_option(const char * opt)
{ {
set_err(EINVAL, "requires option '%s'", opt); set_err(EINVAL, "requires option '%s'", opt);
@ -2922,6 +3025,7 @@ linux_smart_interface::megasas_dcmd_cmd(int bus_no, uint32_t opcode, void *buf,
} }
int r = ioctl(fd, MEGASAS_IOC_FIRMWARE, &ioc); int r = ioctl(fd, MEGASAS_IOC_FIRMWARE, &ioc);
::close(fd);
if (r < 0) { if (r < 0) {
return (r); return (r);
} }
@ -2946,7 +3050,7 @@ linux_smart_interface::megasas_pd_add_list(int bus_no, smart_device_list & devli
*/ */
megasas_pd_list * list = 0; megasas_pd_list * list = 0;
for (unsigned list_size = 1024; ; ) { for (unsigned list_size = 1024; ; ) {
list = (megasas_pd_list *)realloc(list, list_size); list = reinterpret_cast<megasas_pd_list *>(realloc(list, list_size));
if (!list) if (!list)
throw std::bad_alloc(); throw std::bad_alloc();
bzero(list, list_size); bzero(list, list_size);
@ -2967,7 +3071,7 @@ linux_smart_interface::megasas_pd_add_list(int bus_no, smart_device_list & devli
continue; /* non disk device found */ continue; /* non disk device found */
char line[128]; char line[128];
snprintf(line, sizeof(line) - 1, "/dev/bus/%d", bus_no); snprintf(line, sizeof(line) - 1, "/dev/bus/%d", bus_no);
smart_device * dev = new linux_megaraid_device(this, line, 0, list->addr[i].device_id); smart_device * dev = new linux_megaraid_device(this, line, list->addr[i].device_id);
devlist.push_back(dev); devlist.push_back(dev);
} }
free(list); free(list);
@ -3059,6 +3163,10 @@ smart_device * linux_smart_interface::autodetect_smart_device(const char * name)
if (str_starts_with(test_name, "nos")) if (str_starts_with(test_name, "nos"))
return new linux_scsi_device(this, name, ""); return new linux_scsi_device(this, name, "");
// form /dev/nvme* or nvme*
if (str_starts_with(test_name, "nvme"))
return new linux_nvme_device(this, name, "", 0 /* use default nsid */);
// form /dev/tw[ael]* or tw[ael]* // form /dev/tw[ael]* or tw[ael]*
if (str_starts_with(test_name, "tw") && strchr("ael", test_name[2])) if (str_starts_with(test_name, "tw") && strchr("ael", test_name[2]))
return missing_option("-d 3ware,N"); return missing_option("-d 3ware,N");
@ -3156,16 +3264,15 @@ smart_device * linux_smart_interface::get_custom_smart_device(const char * name,
// MegaRAID ? // MegaRAID ?
if (sscanf(type, "megaraid,%d", &disknum) == 1) { if (sscanf(type, "megaraid,%d", &disknum) == 1) {
return new linux_megaraid_device(this, name, 0, disknum); return new linux_megaraid_device(this, name, disknum);
} }
//aacraid? //aacraid?
unsigned int device; unsigned host, chan, device;
unsigned int host; if (sscanf(type, "aacraid,%u,%u,%u", &host, &chan, &device) == 3) {
if(sscanf(type, "aacraid,%d,%d,%d", &host, &channel, &device)==3) {
//return new linux_aacraid_device(this,name,channel,device); //return new linux_aacraid_device(this,name,channel,device);
return get_sat_device("sat,auto", return get_sat_device("sat,auto",
new linux_aacraid_device(this, name, host, channel, device)); new linux_aacraid_device(this, name, host, chan, device));
} }

View File

@ -1,7 +1,7 @@
/* /*
* os_linux.h * os_linux.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2003-8 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2003-8 Bruce Allen <smartmontools-support@lists.sourceforge.net>
* *
@ -38,7 +38,7 @@
#ifndef OS_LINUX_H_ #ifndef OS_LINUX_H_
#define OS_LINUX_H_ #define OS_LINUX_H_
#define OS_LINUX_H_CVSID "$Id: os_linux.h 3728 2012-12-13 17:57:50Z chrfranke $\n" #define OS_LINUX_H_CVSID "$Id: os_linux.h 4120 2015-08-27 16:12:21Z samm2 $\n"
/* /*
The following definitions/macros/prototypes are used for three The following definitions/macros/prototypes are used for three

View File

@ -1,7 +1,7 @@
/* /*
* os_netbsd.cpp * os_netbsd.cpp
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2003-8 Sergey Svishchev <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2003-8 Sergey Svishchev <smartmontools-support@lists.sourceforge.net>
* *
@ -26,14 +26,11 @@
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
const char * os_netbsd_cpp_cvsid = "$Id: os_netbsd.cpp 3806 2013-03-29 20:17:03Z chrfranke $" const char * os_netbsd_cpp_cvsid = "$Id: os_netbsd.cpp 4320 2016-05-10 13:39:19Z chrfranke $"
OS_NETBSD_H_CVSID; OS_NETBSD_H_CVSID;
/* global variable holding byte count of allocated memory */
extern long long bytes;
enum warnings { enum warnings {
BAD_SMART, NO_3WARE, NO_ARECA, MAX_MSG BAD_SMART, MAX_MSG
}; };
/* Utility function for printing warnings */ /* Utility function for printing warnings */
@ -57,7 +54,7 @@ printwarning(int msgNo, const char *extra)
return; return;
} }
static const char *net_dev_prefix = "/dev/"; static const char *net_dev_prefix = "/dev/r";
static const char *net_dev_ata_disk = "wd"; static const char *net_dev_ata_disk = "wd";
static const char *net_dev_scsi_disk = "sd"; static const char *net_dev_scsi_disk = "sd";
static const char *net_dev_scsi_tape = "enrst"; static const char *net_dev_scsi_tape = "enrst";
@ -128,12 +125,17 @@ get_dev_names(char ***names, const char *prefix)
return -1; return -1;
} }
sprintf(mp[n], "%s%s%c", net_dev_prefix, p, 'a' + getrawpartition()); sprintf(mp[n], "%s%s%c", net_dev_prefix, p, 'a' + getrawpartition());
bytes += strlen(mp[n]) + 1;
n++; n++;
} }
mp = (char **)realloc(mp, n * (sizeof(char *))); char ** tmp = (char **)realloc(mp, n * (sizeof(char *)));
bytes += (n) * (sizeof(char *)); if (NULL == tmp) {
pout("Out of memory constructing scan device list\n");
free(mp);
return -1;
}
else
mp = tmp;
*names = mp; *names = mp;
return n; return n;
} }
@ -320,7 +322,8 @@ ata_command_interface(int fd, smart_command_set command, int select, char *data)
return 0; return 0;
} }
if ((retval = ioctl(fd, ATAIOCCOMMAND, &req))) { retval = ioctl(fd, ATAIOCCOMMAND, &req);
if (retval < 0) {
perror("Failed command"); perror("Failed command");
return -1; return -1;
} }

View File

@ -1,7 +1,7 @@
/* /*
* os_netbsd.h * os_netbsd.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2003-8 Sergey Svishchev <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2003-8 Sergey Svishchev <smartmontools-support@lists.sourceforge.net>
* *
@ -24,7 +24,7 @@
#ifndef OS_NETBSD_H_ #ifndef OS_NETBSD_H_
#define OS_NETBSD_H_ #define OS_NETBSD_H_
#define OS_NETBSD_H_CVSID "$Id: os_netbsd.h 3728 2012-12-13 17:57:50Z chrfranke $\n" #define OS_NETBSD_H_CVSID "$Id: os_netbsd.h 4120 2015-08-27 16:12:21Z samm2 $\n"
#include <sys/device.h> #include <sys/device.h>
#include <sys/param.h> #include <sys/param.h>

View File

@ -1,7 +1,7 @@
/* /*
* os_openbsd.c * os_openbsd.c
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2004-10 David Snyder <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2004-10 David Snyder <smartmontools-support@lists.sourceforge.net>
* *
@ -27,14 +27,11 @@
#include <errno.h> #include <errno.h>
const char * os_openbsd_cpp_cvsid = "$Id: os_openbsd.cpp 3727 2012-12-13 17:23:06Z samm2 $" const char * os_openbsd_cpp_cvsid = "$Id: os_openbsd.cpp 4321 2016-05-10 13:43:10Z chrfranke $"
OS_OPENBSD_H_CVSID; OS_OPENBSD_H_CVSID;
/* global variable holding byte count of allocated memory */
extern long long bytes;
enum warnings { enum warnings {
BAD_SMART, NO_3WARE, NO_ARECA, MAX_MSG BAD_SMART, MAX_MSG
}; };
/* Utility function for printing warnings */ /* Utility function for printing warnings */
@ -132,12 +129,17 @@ get_dev_names(char ***names, const char *prefix)
return -1; return -1;
} }
sprintf(mp[n], "%s%s%c", net_dev_prefix, p, 'a' + getrawpartition()); sprintf(mp[n], "%s%s%c", net_dev_prefix, p, 'a' + getrawpartition());
bytes += strlen(mp[n]) + 1;
n++; n++;
} }
mp = (char **)realloc(mp, n * (sizeof(char *))); char ** tmp = (char **)realloc(mp, n * (sizeof(char *)));
bytes += (n) * (sizeof(char *)); if (NULL == tmp) {
pout("Out of memory constructing scan device list\n");
free(mp);
return -1;
}
else
mp = tmp;
*names = mp; *names = mp;
return n; return n;
} }
@ -316,7 +318,8 @@ ata_command_interface(int fd, smart_command_set command, int select, char *data)
unsigned const short normal = WDSMART_CYL, failed = 0x2cf4; unsigned const short normal = WDSMART_CYL, failed = 0x2cf4;
if ((retval = ioctl(fd, ATAIOCCOMMAND, &req))) { retval = ioctl(fd, ATAIOCCOMMAND, &req);
if (retval < 0) {
perror("Failed command"); perror("Failed command");
return -1; return -1;
} }

View File

@ -1,7 +1,7 @@
/* /*
* os_openbsd.h * os_openbsd.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2004-8 David Snyder <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2004-8 David Snyder <smartmontools-support@lists.sourceforge.net>
* *
@ -26,7 +26,7 @@
#ifndef OS_OPENBSD_H_ #ifndef OS_OPENBSD_H_
#define OS_OPENBSD_H_ #define OS_OPENBSD_H_
#define OS_OPENBSD_H_CVSID "$Id: os_openbsd.h 3728 2012-12-13 17:57:50Z chrfranke $\n" #define OS_OPENBSD_H_CVSID "$Id: os_openbsd.h 4120 2015-08-27 16:12:21Z samm2 $\n"
/* from NetBSD: atareg.h,v 1.17, by Manuel Bouyer */ /* from NetBSD: atareg.h,v 1.17, by Manuel Bouyer */
/* Actually fits _perfectly_ into OBSDs wdcreg.h, but... */ /* Actually fits _perfectly_ into OBSDs wdcreg.h, but... */

View File

@ -1,7 +1,7 @@
/* /*
* os_os2.c * os_os2.c
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2004-8 Yuri Dario <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2004-8 Yuri Dario <smartmontools-support@lists.sourceforge.net>
* *
@ -31,7 +31,7 @@
#include "os_os2.h" #include "os_os2.h"
// Needed by '-V' option (CVS versioning) of smartd/smartctl // Needed by '-V' option (CVS versioning) of smartd/smartctl
const char *os_XXXX_c_cvsid="$Id: os_os2.cpp 3806 2013-03-29 20:17:03Z chrfranke $" \ const char *os_XXXX_c_cvsid="$Id: os_os2.cpp 4120 2015-08-27 16:12:21Z samm2 $" \
ATACMDS_H_CVSID OS_XXXX_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; ATACMDS_H_CVSID OS_XXXX_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
// global handle to device driver // global handle to device driver

View File

@ -1,7 +1,7 @@
/* /*
* os_os2.c * os_os2.c
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2004-8 Yuri Dario <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2004-8 Yuri Dario <smartmontools-support@lists.sourceforge.net>
* *
@ -18,7 +18,7 @@
#ifndef OS_OS2_H_ #ifndef OS_OS2_H_
#define OS_OS2_H_ #define OS_OS2_H_
#define OS_XXXX_H_CVSID "$Id: os_os2.h 3728 2012-12-13 17:57:50Z chrfranke $\n" #define OS_XXXX_H_CVSID "$Id: os_os2.h 4120 2015-08-27 16:12:21Z samm2 $\n"
// Additional material should start here. Note: to keep the '-V' CVS // Additional material should start here. Note: to keep the '-V' CVS
// reporting option working as intended, you should only #include // reporting option working as intended, you should only #include

View File

@ -1,7 +1,7 @@
/* /*
* os_generic.h * os_generic.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) Joerg Hering <smartmontools-support@lists.sourceforge.net> * Copyright (C) Joerg Hering <smartmontools-support@lists.sourceforge.net>
* Copyright (C) 2003-8 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2003-8 Bruce Allen <smartmontools-support@lists.sourceforge.net>
@ -23,7 +23,7 @@
*/ */
#ifndef OS_QNXNTO_H_ #ifndef OS_QNXNTO_H_
#define OS_QNXNTO_H_ #define OS_QNXNTO_H_
#define OS_QNXNTO_H_CVSID "$Id: os_qnxnto.h 3728 2012-12-13 17:57:50Z chrfranke $\n" #define OS_QNXNTO_H_CVSID "$Id: os_qnxnto.h 4120 2015-08-27 16:12:21Z samm2 $\n"
// Additional material should start here. Note: to keep the '-V' CVS // Additional material should start here. Note: to keep the '-V' CVS
// reporting option working as intended, you should only #include // reporting option working as intended, you should only #include

View File

@ -1,10 +1,10 @@
/* /*
* os_solaris.c * os_solaris.c
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2003-8 SAWADA Keiji <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2003-08 SAWADA Keiji
* Copyright (C) 2003-8 Casper Dik <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2003-15 Casper Dik
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -37,11 +37,7 @@
#define ARGUSED(x) ((void)(x)) #define ARGUSED(x) ((void)(x))
extern long long bytes; const char *os_XXXX_c_cvsid="$Id: os_solaris.cpp 4253 2016-03-26 19:47:47Z chrfranke $" \
static const char *filenameandversion="$Id: os_solaris.cpp 3806 2013-03-29 20:17:03Z chrfranke $";
const char *os_XXXX_c_cvsid="$Id: os_solaris.cpp 3806 2013-03-29 20:17:03Z chrfranke $" \
ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_SOLARIS_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_SOLARIS_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
// The printwarning() function warns about unimplemented functions // The printwarning() function warns about unimplemented functions
@ -99,6 +95,7 @@ void print_smartctl_examples(){
static const char *uscsidrvrs[] = { static const char *uscsidrvrs[] = {
"sd", "sd",
"ssd", "ssd",
"disk", // SATA devices
"st" "st"
}; };
@ -166,9 +163,8 @@ addpath(const char *path, struct pathlist *res)
res->names = static_cast<char**>(realloc(res->names, res->maxnames * sizeof (char *))); res->names = static_cast<char**>(realloc(res->names, res->maxnames * sizeof (char *)));
if (res->names == NULL) if (res->names == NULL)
return -1; return -1;
bytes += 16*sizeof(char *);
} }
if (!(res->names[res->nnames-1] = CustomStrDup((char *)path, 1, __LINE__, filenameandversion))) if (!(res->names[res->nnames-1] = strdup(path)))
return -1; return -1;
return 0; return 0;
} }
@ -248,7 +244,6 @@ int make_device_names (char*** devlist, const char* name) {
// shrink array to min possible size // shrink array to min possible size
res.names = static_cast<char**>(realloc(res.names, res.nnames * sizeof (char *))); res.names = static_cast<char**>(realloc(res.names, res.nnames * sizeof (char *)));
bytes -= sizeof(char *)*(res.maxnames-res.nnames);
// pass list back // pass list back
*devlist = res.names; *devlist = res.names;
@ -271,7 +266,7 @@ int deviceclose(int fd){
return close(fd); return close(fd);
} }
#if defined(__sparc) #if defined(WITH_SOLARIS_SPARC_ATA)
// swap each 2-byte pairs in a sector // swap each 2-byte pairs in a sector
static void swap_sector(void *p) static void swap_sector(void *p)
{ {
@ -286,7 +281,7 @@ static void swap_sector(void *p)
// Interface to ATA devices. See os_linux.c // Interface to ATA devices. See os_linux.c
int ata_command_interface(int fd, smart_command_set command, int select, char *data){ int ata_command_interface(int fd, smart_command_set command, int select, char *data){
#if defined(__sparc) #if defined(WITH_SOLARIS_SPARC_ATA)
int err; int err;
switch (command){ switch (command){
@ -328,7 +323,7 @@ int ata_command_interface(int fd, smart_command_set command, int select, char *d
EXIT(1); EXIT(1);
break; break;
} }
#else /* __sparc */ #else /* WITH_SOLARIS_SPARC_ATA */
ARGUSED(fd); ARGUSED(command); ARGUSED(select); ARGUSED(data); ARGUSED(fd); ARGUSED(command); ARGUSED(select); ARGUSED(data);
/* Above smart_* routines uses undocumented ioctls of "dada" /* Above smart_* routines uses undocumented ioctls of "dada"
@ -395,7 +390,7 @@ int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report)
default: default:
return -EINVAL; return -EINVAL;
} }
uscsi.uscsi_flags |= (USCSI_ISOLATE | USCSI_RQENABLE); uscsi.uscsi_flags |= (USCSI_ISOLATE | USCSI_RQENABLE | USCSI_SILENT);
if (ioctl(fd, USCSICMD, &uscsi)) { if (ioctl(fd, USCSICMD, &uscsi)) {
int err = errno; int err = errno;

View File

@ -1,7 +1,7 @@
/* /*
* os_solaris.h * os_solaris.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2003-8 SAWADA Keiji <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2003-8 SAWADA Keiji <smartmontools-support@lists.sourceforge.net>
* Copyright (C) 2003-8 Casper Dik <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2003-8 Casper Dik <smartmontools-support@lists.sourceforge.net>
@ -25,7 +25,7 @@
#ifndef OS_SOLARIS_H_ #ifndef OS_SOLARIS_H_
#define OS_SOLARIS_H_ #define OS_SOLARIS_H_
#define OS_SOLARIS_H_CVSID "$Id: os_solaris.h 3728 2012-12-13 17:57:50Z chrfranke $\n" #define OS_SOLARIS_H_CVSID "$Id: os_solaris.h 4120 2015-08-27 16:12:21Z samm2 $\n"
// Additional material should start here. Note: to keep the '-V' CVS // Additional material should start here. Note: to keep the '-V' CVS
// reporting option working as intended, you should only #include // reporting option working as intended, you should only #include

View File

@ -1,697 +0,0 @@
!
! os_solaris_ata.s
!
! Home page of code is: http://smartmontools.sourceforge.net
!
! Copyright (C) 2003-8 SAWADA Keiji <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 of the License, or
! (at your option) any later version.
!
! This program is distributed in the hope that it will be useful, but
! WITHOUT ANY WARRANTY; without even the implied warranty of
! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
! General Public License for more details.
!
! You should have received a copy of the GNU General Public License
! along with this program; if not, write to the Free Software Foundation,
! Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
!
!
! --------------------------------------------------------
! direct access routines to ATA device under Solaris/SPARC
! --------------------------------------------------------
!
! Information
! -----------
!
! In Solaris, programmer can pass SCSI command to target device directly
! by using USCSI ioctl or using "scg" generic SCSI driver. But, such
! method does not exist for ATA devices.
!
! However, I can access Solaris kernel source because I am subscriber of
! Source Foundation Program of Solaris. So, I can find method of
! accessing ATA device directly. The method is to pack command in
! undocumented structure and issue ioctl that appears only in kernel
! source. Yes, that is the same way in using USCSI interface.
!
! But, I met difficulty in disclosing this technique. I have signed NDA
! with Sun that inhibits me not to violate their intellectual property.
!
! Fortunately, Sun allows licensees to publish "Interfaces" if:
!
! (1) he/she treats Solaris code as confidential
!
! (2) and he/she doesn't incorporate Sun's code into his/her code
!
! (3) and disclose enough information to use "Interface" to everyone.
!
! So, I publish that technique in assembly code or object code because:
!
! (1) I believe Sun's intellectural property is not invaded because I
! didn't reveal any struct member and ioctl to non-licensee.
!
! (2) no piece of kernel source is included in this code.
!
! (3) And finally, I publish enough information below in order to use
! this code.
!
! For last reason, please don't remove "Calling Interface" section from
! distribution.
!
!
! Calling Interface
! -----------------
!
! Name of function/macro presents corresponding S.M.A.R.T. command.
!
! Parameters are described below.
!
! int fd
!
! File descriptor of ATA device. Device would be
! /dev/rdsk/cXtXdXsX.
!
! Device should be raw device serviced by "dada" driver. ATAPI
! CD-ROM/R/RW, DVD-ROM, and so on are not allowed because they are
! serviced by "sd" driver. On x86 Solaris, "cmdk" driver services
! them, this routines doesn't work.
!
! int s
! Select sector for service. For example, this indicates log sector
! number for smart_read_log() function. Probably you need to read
! ATA specification for this parameter.
!
! void *data
! Data going to be read/written. It don't have to be word aligned,
! But data shall points valid user memory space.
!
! This is very tiny routines, but if you feel this insufficient, please
! let me know.
!
! ksw / SAWADA Keiji
! <card_captor@users.sourceforge.net>
.file "solaris-ata-in.c"
.section ".rodata"
.align 8
.LLC0:
.asciz "$Id: os_solaris_ata.s 3728 2012-12-13 17:57:50Z chrfranke $"
.global os_solaris_ata_s_cvsid
.section ".data"
.align 4
.type os_solaris_ata_s_cvsid, #object
.size os_solaris_ata_s_cvsid, 4
os_solaris_ata_s_cvsid:
.long .LLC0
.section ".text"
.align 4
.type ata_cmd, #function
.proc 04
ata_cmd:
!#PROLOGUE# 0
save %sp, -184, %sp
!#PROLOGUE# 1
st %i0, [%fp+68]
st %i1, [%fp+72]
st %i2, [%fp+76]
st %i3, [%fp+80]
st %i4, [%fp+84]
st %i5, [%fp+88]
ld [%fp+92], %g1
st %g1, [%fp-76]
ld [%fp-76], %g1
and %g1, 3, %g1
cmp %g1, 0
be .LL2
nop
mov -2, %g1
st %g1, [%fp-80]
b .LL1
nop
.LL2:
add %fp, -56, %g1
mov %g1, %o0
mov 0, %o1
mov 36, %o2
call memset, 0
nop
add %fp, -72, %g1
mov %g1, %o0
mov 0, %o1
mov 16, %o2
call memset, 0
nop
ld [%fp+72], %g1
stb %g1, [%fp-72]
mov 1, %g1
stb %g1, [%fp-71]
mov 1, %g1
stb %g1, [%fp-70]
ld [%fp+76], %g1
stb %g1, [%fp-69]
ld [%fp+84], %g1
sll %g1, 9, %g1
st %g1, [%fp-68]
ld [%fp+80], %g1
st %g1, [%fp-60]
mov 10, %g1
sth %g1, [%fp-52]
ld [%fp+88], %g1
cmp %g1, 0
be .LL3
nop
mov 14, %g1
st %g1, [%fp-84]
b .LL4
nop
.LL3:
mov 6, %g1
st %g1, [%fp-84]
.LL4:
ld [%fp-84], %g1
st %g1, [%fp-48]
ld [%fp+88], %g1
sll %g1, 9, %g1
st %g1, [%fp-44]
ld [%fp+88], %g1
sll %g1, 9, %g1
st %g1, [%fp-40]
ld [%fp+88], %g1
cmp %g1, 0
be .LL5
nop
ld [%fp+92], %g1
st %g1, [%fp-88]
b .LL6
nop
.LL5:
st %g0, [%fp-88]
.LL6:
ld [%fp-88], %g1
st %g1, [%fp-36]
add %fp, -72, %g1
st %g1, [%fp-32]
add %fp, -56, %g1
ld [%fp+68], %o0
mov 1481, %o1
mov %g1, %o2
call ioctl, 0
nop
mov %o0, %g1
st %g1, [%fp-80]
.LL1:
ld [%fp-80], %i0
ret
restore
.size ata_cmd, .-ata_cmd
.align 4
.global ata_identify
.type ata_identify, #function
.proc 04
ata_identify:
!#PROLOGUE# 0
save %sp, -648, %sp
!#PROLOGUE# 1
st %i0, [%fp+68]
st %i1, [%fp+72]
add %fp, -536, %g1
st %g1, [%sp+92]
ld [%fp+68], %o0
mov 236, %o1
mov 0, %o2
mov 0, %o3
mov 1, %o4
mov 1, %o5
call ata_cmd, 0
nop
mov %o0, %g1
st %g1, [%fp-20]
add %fp, -536, %g1
ld [%fp+72], %o0
mov %g1, %o1
mov 512, %o2
call memcpy, 0
nop
ld [%fp-20], %g1
cmp %g1, 0
be .LL8
nop
mov -1, %g1
st %g1, [%fp-540]
b .LL9
nop
.LL8:
st %g0, [%fp-540]
.LL9:
ld [%fp-540], %g1
mov %g1, %i0
ret
restore
.size ata_identify, .-ata_identify
.align 4
.global ata_pidentify
.type ata_pidentify, #function
.proc 04
ata_pidentify:
!#PROLOGUE# 0
save %sp, -648, %sp
!#PROLOGUE# 1
st %i0, [%fp+68]
st %i1, [%fp+72]
add %fp, -536, %g1
st %g1, [%sp+92]
ld [%fp+68], %o0
mov 161, %o1
mov 0, %o2
mov 0, %o3
mov 1, %o4
mov 1, %o5
call ata_cmd, 0
nop
mov %o0, %g1
st %g1, [%fp-20]
add %fp, -536, %g1
ld [%fp+72], %o0
mov %g1, %o1
mov 512, %o2
call memcpy, 0
nop
ld [%fp-20], %g1
cmp %g1, 0
be .LL11
nop
mov -1, %g1
st %g1, [%fp-540]
b .LL12
nop
.LL11:
st %g0, [%fp-540]
.LL12:
ld [%fp-540], %g1
mov %g1, %i0
ret
restore
.size ata_pidentify, .-ata_pidentify
.align 4
.global smart_read_data
.type smart_read_data, #function
.proc 04
smart_read_data:
!#PROLOGUE# 0
save %sp, -648, %sp
!#PROLOGUE# 1
st %i0, [%fp+68]
st %i1, [%fp+72]
add %fp, -536, %g1
st %g1, [%sp+92]
ld [%fp+68], %o0
mov 176, %o1
mov 208, %o2
sethi %hi(12733440), %g1
or %g1, 768, %o3
mov 0, %o4
mov 1, %o5
call ata_cmd, 0
nop
mov %o0, %g1
st %g1, [%fp-20]
add %fp, -536, %g1
ld [%fp+72], %o0
mov %g1, %o1
mov 512, %o2
call memcpy, 0
nop
ld [%fp-20], %g1
cmp %g1, 0
be .LL14
nop
mov -1, %g1
st %g1, [%fp-540]
b .LL15
nop
.LL14:
st %g0, [%fp-540]
.LL15:
ld [%fp-540], %g1
mov %g1, %i0
ret
restore
.size smart_read_data, .-smart_read_data
.align 4
.global smart_read_thresholds
.type smart_read_thresholds, #function
.proc 04
smart_read_thresholds:
!#PROLOGUE# 0
save %sp, -648, %sp
!#PROLOGUE# 1
st %i0, [%fp+68]
st %i1, [%fp+72]
add %fp, -536, %g1
st %g1, [%sp+92]
ld [%fp+68], %o0
mov 176, %o1
mov 209, %o2
sethi %hi(12733440), %g1
or %g1, 769, %o3
mov 1, %o4
mov 1, %o5
call ata_cmd, 0
nop
mov %o0, %g1
st %g1, [%fp-20]
add %fp, -536, %g1
ld [%fp+72], %o0
mov %g1, %o1
mov 512, %o2
call memcpy, 0
nop
ld [%fp-20], %g1
cmp %g1, 0
be .LL17
nop
mov -1, %g1
st %g1, [%fp-540]
b .LL18
nop
.LL17:
st %g0, [%fp-540]
.LL18:
ld [%fp-540], %g1
mov %g1, %i0
ret
restore
.size smart_read_thresholds, .-smart_read_thresholds
.align 4
.global smart_auto_save
.type smart_auto_save, #function
.proc 04
smart_auto_save:
!#PROLOGUE# 0
save %sp, -128, %sp
!#PROLOGUE# 1
st %i0, [%fp+68]
st %i1, [%fp+72]
st %g0, [%sp+92]
ld [%fp+68], %o0
mov 176, %o1
mov 210, %o2
sethi %hi(12733440), %g1
or %g1, 768, %o3
ld [%fp+72], %o4
mov 0, %o5
call ata_cmd, 0
nop
mov %o0, %g1
st %g1, [%fp-20]
ld [%fp-20], %g1
cmp %g1, 0
be .LL20
nop
mov -1, %g1
st %g1, [%fp-24]
b .LL21
nop
.LL20:
st %g0, [%fp-24]
.LL21:
ld [%fp-24], %g1
mov %g1, %i0
ret
restore
.size smart_auto_save, .-smart_auto_save
.align 4
.global smart_immediate_offline
.type smart_immediate_offline, #function
.proc 04
smart_immediate_offline:
!#PROLOGUE# 0
save %sp, -128, %sp
!#PROLOGUE# 1
st %i0, [%fp+68]
st %i1, [%fp+72]
ld [%fp+72], %g1
and %g1, 255, %o5
sethi %hi(12733440), %g1
or %g1, 768, %g1
or %o5, %g1, %g1
st %g0, [%sp+92]
ld [%fp+68], %o0
mov 176, %o1
mov 212, %o2
mov %g1, %o3
mov 0, %o4
mov 0, %o5
call ata_cmd, 0
nop
mov %o0, %g1
st %g1, [%fp-20]
ld [%fp-20], %g1
cmp %g1, 0
be .LL23
nop
mov -1, %g1
st %g1, [%fp-24]
b .LL24
nop
.LL23:
st %g0, [%fp-24]
.LL24:
ld [%fp-24], %g1
mov %g1, %i0
ret
restore
.size smart_immediate_offline, .-smart_immediate_offline
.align 4
.global smart_read_log
.type smart_read_log, #function
.proc 04
smart_read_log:
!#PROLOGUE# 0
save %sp, -128, %sp
!#PROLOGUE# 1
st %i0, [%fp+68]
st %i1, [%fp+72]
st %i2, [%fp+76]
st %i3, [%fp+80]
ld [%fp+72], %g1
and %g1, 255, %o5
sethi %hi(12733440), %g1
or %g1, 768, %g1
or %o5, %g1, %o5
ld [%fp+80], %g1
st %g1, [%sp+92]
ld [%fp+68], %o0
mov 176, %o1
mov 213, %o2
mov %o5, %o3
ld [%fp+76], %o4
ld [%fp+76], %o5
call ata_cmd, 0
nop
mov %o0, %g1
st %g1, [%fp-20]
ld [%fp-20], %g1
cmp %g1, 0
be .LL26
nop
mov -1, %g1
st %g1, [%fp-24]
b .LL27
nop
.LL26:
st %g0, [%fp-24]
.LL27:
ld [%fp-24], %g1
mov %g1, %i0
ret
restore
.size smart_read_log, .-smart_read_log
.align 4
.global smart_enable
.type smart_enable, #function
.proc 04
smart_enable:
!#PROLOGUE# 0
save %sp, -128, %sp
!#PROLOGUE# 1
st %i0, [%fp+68]
st %g0, [%sp+92]
ld [%fp+68], %o0
mov 176, %o1
mov 216, %o2
sethi %hi(12733440), %g1
or %g1, 768, %o3
mov 0, %o4
mov 0, %o5
call ata_cmd, 0
nop
mov %o0, %g1
st %g1, [%fp-20]
ld [%fp-20], %g1
cmp %g1, 0
be .LL29
nop
mov -1, %g1
st %g1, [%fp-24]
b .LL30
nop
.LL29:
st %g0, [%fp-24]
.LL30:
ld [%fp-24], %g1
mov %g1, %i0
ret
restore
.size smart_enable, .-smart_enable
.align 4
.global smart_disable
.type smart_disable, #function
.proc 04
smart_disable:
!#PROLOGUE# 0
save %sp, -128, %sp
!#PROLOGUE# 1
st %i0, [%fp+68]
st %g0, [%sp+92]
ld [%fp+68], %o0
mov 176, %o1
mov 217, %o2
sethi %hi(12733440), %g1
or %g1, 768, %o3
mov 0, %o4
mov 0, %o5
call ata_cmd, 0
nop
mov %o0, %g1
st %g1, [%fp-20]
ld [%fp-20], %g1
cmp %g1, 0
be .LL32
nop
mov -1, %g1
st %g1, [%fp-24]
b .LL33
nop
.LL32:
st %g0, [%fp-24]
.LL33:
ld [%fp-24], %g1
mov %g1, %i0
ret
restore
.size smart_disable, .-smart_disable
.align 4
.global smart_status
.type smart_status, #function
.proc 04
smart_status:
!#PROLOGUE# 0
save %sp, -128, %sp
!#PROLOGUE# 1
st %i0, [%fp+68]
st %g0, [%sp+92]
ld [%fp+68], %o0
mov 176, %o1
mov 218, %o2
sethi %hi(12733440), %g1
or %g1, 768, %o3
mov 0, %o4
mov 0, %o5
call ata_cmd, 0
nop
mov %o0, %g1
st %g1, [%fp-20]
ld [%fp-20], %g1
cmp %g1, 0
be .LL35
nop
mov -1, %g1
st %g1, [%fp-24]
b .LL36
nop
.LL35:
st %g0, [%fp-24]
.LL36:
ld [%fp-24], %g1
mov %g1, %i0
ret
restore
.size smart_status, .-smart_status
.align 4
.global smart_status_check
.type smart_status_check, #function
.proc 04
smart_status_check:
!#PROLOGUE# 0
save %sp, -128, %sp
!#PROLOGUE# 1
st %i0, [%fp+68]
st %g0, [%sp+92]
ld [%fp+68], %o0
mov 176, %o1
mov 218, %o2
sethi %hi(12733440), %g1
or %g1, 768, %o3
mov 0, %o4
mov 0, %o5
call ata_cmd, 0
nop
mov %o0, %g1
st %g1, [%fp-20]
ld [%fp-20], %g1
cmp %g1, 0
be .LL38
nop
mov -1, %g1
st %g1, [%fp-24]
b .LL37
nop
.LL38:
st %g0, [%fp-24]
.LL37:
ld [%fp-24], %i0
ret
restore
.size smart_status_check, .-smart_status_check
.align 4
.global smart_auto_offline
.type smart_auto_offline, #function
.proc 04
smart_auto_offline:
!#PROLOGUE# 0
save %sp, -128, %sp
!#PROLOGUE# 1
st %i0, [%fp+68]
st %i1, [%fp+72]
st %g0, [%sp+92]
ld [%fp+68], %o0
mov 176, %o1
mov 219, %o2
sethi %hi(12733440), %g1
or %g1, 768, %o3
ld [%fp+72], %o4
mov 0, %o5
call ata_cmd, 0
nop
mov %o0, %g1
st %g1, [%fp-20]
ld [%fp-20], %g1
cmp %g1, 0
be .LL40
nop
mov -1, %g1
st %g1, [%fp-24]
b .LL41
nop
.LL40:
st %g0, [%fp-24]
.LL41:
ld [%fp-24], %g1
mov %g1, %i0
ret
restore
.size smart_auto_offline, .-smart_auto_offline
.ident "GCC: (GNU) 3.4.2"

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/* /*
* os_win32/daemon_win32.cpp * os_win32/daemon_win32.cpp
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2004-14 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2004-14 Christian Franke <smartmontools-support@lists.sourceforge.net>
* *
@ -20,7 +20,7 @@
#include "daemon_win32.h" #include "daemon_win32.h"
const char * daemon_win32_cpp_cvsid = "$Id: daemon_win32.cpp 3959 2014-07-18 19:22:18Z chrfranke $" const char * daemon_win32_cpp_cvsid = "$Id: daemon_win32.cpp 4120 2015-08-27 16:12:21Z samm2 $"
DAEMON_WIN32_H_CVSID; DAEMON_WIN32_H_CVSID;
#include <stdio.h> #include <stdio.h>

View File

@ -1,7 +1,7 @@
/* /*
* os_win32/daemon_win32.h * os_win32/daemon_win32.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2004-12 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2004-12 Christian Franke <smartmontools-support@lists.sourceforge.net>
* *
@ -18,7 +18,7 @@
#ifndef DAEMON_WIN32_H #ifndef DAEMON_WIN32_H
#define DAEMON_WIN32_H #define DAEMON_WIN32_H
#define DAEMON_WIN32_H_CVSID "$Id: daemon_win32.h 3584 2012-08-05 17:05:32Z chrfranke $" #define DAEMON_WIN32_H_CVSID "$Id: daemon_win32.h 4120 2015-08-27 16:12:21Z samm2 $"
#include <signal.h> #include <signal.h>

27
os_win32/default.manifest Normal file
View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="asInvoker"
uiAccess="false"
/>
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
</assembly>

View File

@ -1,9 +1,9 @@
; ;
; smartmontools install NSIS script ; os_win32/installer.nsi - smartmontools install NSIS script
; ;
; Home page of code is: http://smartmontools.sourceforge.net ; Home page of code is: http://www.smartmontools.org
; ;
; Copyright (C) 2006-14 Christian Franke <smartmontools-support@lists.sourceforge.net> ; Copyright (C) 2006-15 Christian Franke
; ;
; This program is free software; you can redistribute it and/or modify ; 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 ; it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
; You should have received a copy of the GNU General Public License ; You should have received a copy of the GNU General Public License
; (for example COPYING); If not, see <http://www.gnu.org/licenses/>. ; (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
; ;
; $Id: installer.nsi 3912 2014-06-18 19:03:30Z chrfranke $ ; $Id: installer.nsi 4174 2015-11-22 16:19:29Z chrfranke $
; ;
@ -36,6 +36,8 @@
Name "smartmontools" Name "smartmontools"
OutFile "${OUTFILE}" OutFile "${OUTFILE}"
RequestExecutionLevel admin
SetCompressor /solid lzma SetCompressor /solid lzma
XPStyle on XPStyle on
@ -43,7 +45,7 @@ InstallColors /windows
; Set in .onInit ; Set in .onInit
;InstallDir "$PROGRAMFILES\smartmontools" ;InstallDir "$PROGRAMFILES\smartmontools"
;InstallDirRegKey HKLM "Software\smartmontools" "Install_Dir" ;InstallDirRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "InstallLocation"
Var EDITOR Var EDITOR
@ -56,12 +58,9 @@ Var EDITOR
LicenseData "${INPDIR}\doc\COPYING.txt" LicenseData "${INPDIR}\doc\COPYING.txt"
!include "FileFunc.nsh" !include "FileFunc.nsh"
!include "LogicLib.nsh"
!include "Sections.nsh" !include "Sections.nsh"
!insertmacro GetParameters
!insertmacro GetOptions
RequestExecutionLevel admin
;-------------------------------------------------------------------- ;--------------------------------------------------------------------
; Pages ; Pages
@ -81,6 +80,11 @@ UninstPage instfiles
InstType "Full" InstType "Full"
InstType "Extract files only" InstType "Extract files only"
InstType "Drive menu" InstType "Drive menu"
!ifdef INPDIR64
InstType "Full (x64)"
InstType "Extract files only (x64)"
InstType "Drive menu (x64)"
!endif
;-------------------------------------------------------------------- ;--------------------------------------------------------------------
@ -88,8 +92,17 @@ InstType "Drive menu"
!ifdef INPDIR64 !ifdef INPDIR64
Section "64-bit version" X64_SECTION Section "64-bit version" X64_SECTION
SectionIn 4 5 6
; Handled in Function CheckX64 ; Handled in Function CheckX64
SectionEnd SectionEnd
!define FULL_TYPES "1 4"
!define EXTRACT_TYPES "2 5"
!define DRIVEMENU_TYPE "3 6"
!else
!define FULL_TYPES "1"
!define EXTRACT_TYPES "2"
!define DRIVEMENU_TYPE "3"
!endif !endif
SectionGroup "!Program files" SectionGroup "!Program files"
@ -97,14 +110,15 @@ SectionGroup "!Program files"
!macro FileExe path option !macro FileExe path option
!ifdef INPDIR64 !ifdef INPDIR64
; Use dummy SetOutPath to control archive location of executables ; Use dummy SetOutPath to control archive location of executables
StrCmp $X64 "" +5 ${If} $X64 != ""
Goto +2 Goto +2
SetOutPath "$INSTDIR\bin64" SetOutPath "$INSTDIR\bin64"
File ${option} '${INPDIR64}\${path}' File ${option} '${INPDIR64}\${path}'
GoTo +4 ${Else}
Goto +2 Goto +2
SetOutPath "$INSTDIR\bin" SetOutPath "$INSTDIR\bin"
File ${option} '${INPDIR}\${path}' File ${option} '${INPDIR}\${path}'
${EndIf}
!else !else
File ${option} '${INPDIR}\${path}' File ${option} '${INPDIR}\${path}'
!endif !endif
@ -112,7 +126,7 @@ SectionGroup "!Program files"
Section "smartctl" SMARTCTL_SECTION Section "smartctl" SMARTCTL_SECTION
SectionIn 1 2 SectionIn ${FULL_TYPES} ${EXTRACT_TYPES}
SetOutPath "$INSTDIR\bin" SetOutPath "$INSTDIR\bin"
!insertmacro FileExe "bin\smartctl.exe" "" !insertmacro FileExe "bin\smartctl.exe" ""
@ -121,17 +135,18 @@ SectionGroup "!Program files"
Section "smartd" SMARTD_SECTION Section "smartd" SMARTD_SECTION
SectionIn 1 2 SectionIn ${FULL_TYPES} ${EXTRACT_TYPES}
SetOutPath "$INSTDIR\bin" SetOutPath "$INSTDIR\bin"
; Stop service ? ; Stop service ?
StrCpy $1 "" StrCpy $1 ""
IfFileExists "$INSTDIR\bin\smartd.exe" 0 nosrv ${If} ${FileExists} "$INSTDIR\bin\smartd.exe"
ReadRegStr $0 HKLM "System\CurrentControlSet\Services\smartd" "ImagePath" ReadRegStr $0 HKLM "System\CurrentControlSet\Services\smartd" "ImagePath"
StrCmp $0 "" nosrv ${If} $0 != ""
ExecWait "net stop smartd" $1 ExecWait "net stop smartd" $1
nosrv: ${EndIf}
${EndIf}
!insertmacro FileExe "bin\smartd.exe" "" !insertmacro FileExe "bin\smartd.exe" ""
IfFileExists "$INSTDIR\bin\smartd.conf" 0 +2 IfFileExists "$INSTDIR\bin\smartd.conf" 0 +2
@ -142,15 +157,16 @@ SectionGroup "!Program files"
!insertmacro FileExe "bin\wtssendmsg.exe" "" !insertmacro FileExe "bin\wtssendmsg.exe" ""
; Restart service ? ; Restart service ?
StrCmp $1 "0" 0 +3 ${If} $1 == "0"
MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2 "Restart smartd service ?" /SD IDNO IDYES 0 IDNO +2 MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2 "Restart smartd service ?" /SD IDNO IDYES 0 IDNO +2
ExecWait "net start smartd" ExecWait "net start smartd"
${EndIf}
SectionEnd SectionEnd
Section "smartctl-nc (GSmartControl)" SMARTCTL_NC_SECTION Section "smartctl-nc (GSmartControl)" SMARTCTL_NC_SECTION
SectionIn 1 2 SectionIn ${FULL_TYPES} ${EXTRACT_TYPES}
SetOutPath "$INSTDIR\bin" SetOutPath "$INSTDIR\bin"
!insertmacro FileExe "bin\smartctl-nc.exe" "" !insertmacro FileExe "bin\smartctl-nc.exe" ""
@ -159,7 +175,7 @@ SectionGroup "!Program files"
Section "drivedb.h (Drive Database)" DRIVEDB_SECTION Section "drivedb.h (Drive Database)" DRIVEDB_SECTION
SectionIn 1 2 SectionIn ${FULL_TYPES} ${EXTRACT_TYPES}
SetOutPath "$INSTDIR\bin" SetOutPath "$INSTDIR\bin"
File "${INPDIR}\bin\drivedb.h" File "${INPDIR}\bin\drivedb.h"
@ -171,7 +187,7 @@ SectionGroupEnd
Section "!Documentation" DOC_SECTION Section "!Documentation" DOC_SECTION
SectionIn 1 2 SectionIn ${FULL_TYPES} ${EXTRACT_TYPES}
SetOutPath "$INSTDIR\doc" SetOutPath "$INSTDIR\doc"
File "${INPDIR}\doc\AUTHORS.txt" File "${INPDIR}\doc\AUTHORS.txt"
@ -182,12 +198,12 @@ Section "!Documentation" DOC_SECTION
File "${INPDIR}\doc\NEWS.txt" File "${INPDIR}\doc\NEWS.txt"
File "${INPDIR}\doc\README.txt" File "${INPDIR}\doc\README.txt"
File "${INPDIR}\doc\TODO.txt" File "${INPDIR}\doc\TODO.txt"
File "${INPDIR}\doc\WARNINGS.txt"
!ifdef INPDIR64 !ifdef INPDIR64
StrCmp $X64 "" +3 ${If} $X64 != ""
File "${INPDIR64}\doc\checksums64.txt" File "${INPDIR64}\doc\checksums64.txt"
GoTo +2 ${Else}
File "${INPDIR}\doc\checksums32.txt" File "${INPDIR}\doc\checksums32.txt"
${EndIf}
!else !else
File "${INPDIR}\doc\checksums??.txt" File "${INPDIR}\doc\checksums??.txt"
!endif !endif
@ -203,7 +219,7 @@ SectionEnd
Section "Uninstaller" UNINST_SECTION Section "Uninstaller" UNINST_SECTION
SectionIn 1 SectionIn ${FULL_TYPES}
AddSize 40 AddSize 40
CreateDirectory "$INSTDIR" CreateDirectory "$INSTDIR"
@ -211,8 +227,9 @@ Section "Uninstaller" UNINST_SECTION
; Keep old Install_Dir registry entry for GSmartControl ; Keep old Install_Dir registry entry for GSmartControl
ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\GSmartControl" "InstallLocation" ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\GSmartControl" "InstallLocation"
ReadRegStr $1 HKLM "Software\smartmontools" "Install_Dir" ReadRegStr $1 HKLM "Software\smartmontools" "Install_Dir"
StrCmp "$0$1" "" +2 0 ${If} "$0$1" != ""
WriteRegStr HKLM "Software\smartmontools" "Install_Dir" "$INSTDIR" WriteRegStr HKLM "Software\smartmontools" "Install_Dir" "$INSTDIR"
${EndIf}
; Write uninstall keys and program ; Write uninstall keys and program
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "DisplayName" "smartmontools" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "DisplayName" "smartmontools"
@ -222,9 +239,9 @@ Section "Uninstaller" UNINST_SECTION
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "InstallLocation" "$INSTDIR" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "InstallLocation" "$INSTDIR"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "UninstallString" '"$INSTDIR\uninst-smartmontools.exe"' WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "UninstallString" '"$INSTDIR\uninst-smartmontools.exe"'
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "Publisher" "smartmontools.org" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "Publisher" "smartmontools.org"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "URLInfoAbout" "http://www.smartmontools.org/" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "URLInfoAbout" "https://www.smartmontools.org/"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "HelpLink" "http://sourceforge.net/projects/smartmontools/support" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "HelpLink" "http://sourceforge.net/projects/smartmontools/support"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "URLUpdateInfo" "http://smartmontools.no-ip.org/" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "URLUpdateInfo" "http://builds.smartmontools.org/"
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "NoModify" 1 WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "NoModify" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "NoRepair" 1 WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "NoRepair" 1
WriteUninstaller "uninst-smartmontools.exe" WriteUninstaller "uninst-smartmontools.exe"
@ -233,7 +250,7 @@ SectionEnd
Section "Start Menu Shortcuts" MENU_SECTION Section "Start Menu Shortcuts" MENU_SECTION
SectionIn 1 SectionIn ${FULL_TYPES}
SetShellVarContext all SetShellVarContext all
@ -246,15 +263,15 @@ Section "Start Menu Shortcuts" MENU_SECTION
!macroend !macroend
; runcmdu ; runcmdu
IfFileExists "$INSTDIR\bin\smartctl.exe" 0 +2 ${If} ${FileExists} "$INSTDIR\bin\smartctl.exe"
IfFileExists "$INSTDIR\bin\smartd.exe" 0 noruncmd ${OrIf} ${FileExists} "$INSTDIR\bin\smartd.exe"
SetOutPath "$INSTDIR\bin" SetOutPath "$INSTDIR\bin"
!insertmacro FileExe "bin\runcmdu.exe" "" !insertmacro FileExe "bin\runcmdu.exe" ""
File "${INPDIR}\bin\runcmdu.exe.manifest" Delete "$INSTDIR\bin\runcmdu.exe.manifest" ; TODO: Remove after smartmontools 6.5
noruncmd: ${EndIf}
; smartctl ; smartctl
IfFileExists "$INSTDIR\bin\smartctl.exe" 0 noctl ${If} ${FileExists} "$INSTDIR\bin\smartctl.exe"
SetOutPath "$INSTDIR\bin" SetOutPath "$INSTDIR\bin"
!insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartctl (Admin CMD).lnk" "$WINDIR\system32\cmd.exe" '/k PATH=$INSTDIR\bin;%PATH%&cd /d "$INSTDIR\bin"' !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartctl (Admin CMD).lnk" "$WINDIR\system32\cmd.exe" '/k PATH=$INSTDIR\bin;%PATH%&cd /d "$INSTDIR\bin"'
CreateDirectory "$SMPROGRAMS\smartmontools\smartctl Examples" CreateDirectory "$SMPROGRAMS\smartmontools\smartctl Examples"
@ -274,10 +291,10 @@ Section "Start Menu Shortcuts" MENU_SECTION
!insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartctl Examples\Stop(Abort) selftest (-X).lnk" "$INSTDIR\bin\runcmdu.exe" "smartctl -X sda" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartctl Examples\Stop(Abort) selftest (-X).lnk" "$INSTDIR\bin\runcmdu.exe" "smartctl -X sda"
!insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartctl Examples\Turn SMART off (-s off).lnk" "$INSTDIR\bin\runcmdu.exe" "smartctl -s off sda" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartctl Examples\Turn SMART off (-s off).lnk" "$INSTDIR\bin\runcmdu.exe" "smartctl -s off sda"
!insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartctl Examples\Turn SMART on (-s on).lnk" "$INSTDIR\bin\runcmdu.exe" "smartctl -s on sda" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartctl Examples\Turn SMART on (-s on).lnk" "$INSTDIR\bin\runcmdu.exe" "smartctl -s on sda"
noctl: ${EndIf}
; smartd ; smartd
IfFileExists "$INSTDIR\bin\smartd.exe" 0 nod ${If} ${FileExists} "$INSTDIR\bin\smartd.exe"
SetOutPath "$INSTDIR\bin" SetOutPath "$INSTDIR\bin"
CreateDirectory "$SMPROGRAMS\smartmontools\smartd Examples" CreateDirectory "$SMPROGRAMS\smartmontools\smartd Examples"
!insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartd Examples\Daemon start, smartd.log.lnk" "$INSTDIR\bin\runcmdu.exe" "smartd -l local0" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartd Examples\Daemon start, smartd.log.lnk" "$INSTDIR\bin\runcmdu.exe" "smartd -l local0"
@ -296,10 +313,10 @@ Section "Start Menu Shortcuts" MENU_SECTION
!insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartd Examples\Service remove.lnk" "$INSTDIR\bin\runcmdu.exe" "smartd remove" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartd Examples\Service remove.lnk" "$INSTDIR\bin\runcmdu.exe" "smartd remove"
!insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartd Examples\Service start.lnk" "$INSTDIR\bin\runcmdu.exe" "net start smartd" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartd Examples\Service start.lnk" "$INSTDIR\bin\runcmdu.exe" "net start smartd"
!insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartd Examples\Service stop.lnk" "$INSTDIR\bin\runcmdu.exe" "net stop smartd" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartd Examples\Service stop.lnk" "$INSTDIR\bin\runcmdu.exe" "net stop smartd"
nod: ${EndIf}
; Documentation ; Documentation
IfFileExists "$INSTDIR\doc\README.TXT" 0 nodoc ${If} ${FileExists} "$INSTDIR\doc\README.TXT"
SetOutPath "$INSTDIR\doc" SetOutPath "$INSTDIR\doc"
CreateDirectory "$SMPROGRAMS\smartmontools\Documentation" CreateDirectory "$SMPROGRAMS\smartmontools\Documentation"
CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\smartctl manual page (html).lnk" "$INSTDIR\doc\smartctl.8.html" CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\smartctl manual page (html).lnk" "$INSTDIR\doc\smartctl.8.html"
@ -309,36 +326,36 @@ Section "Start Menu Shortcuts" MENU_SECTION
CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\smartd manual page (txt).lnk" "$INSTDIR\doc\smartd.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" CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\smartd.conf manual page (txt).lnk" "$INSTDIR\doc\smartd.conf.5.txt"
CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\smartd.conf sample.lnk" "$EDITOR" "$INSTDIR\doc\smartd.conf" CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\smartd.conf sample.lnk" "$EDITOR" "$INSTDIR\doc\smartd.conf"
IfFileExists "$INSTDIR\bin\drivedb.h" 0 nodb ${If} ${FileExists} "$INSTDIR\bin\drivedb.h"
CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\drivedb.h (view).lnk" "$EDITOR" "$INSTDIR\bin\drivedb.h" CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\drivedb.h (view).lnk" "$EDITOR" "$INSTDIR\bin\drivedb.h"
!insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\Documentation\drivedb-add.h (create, edit).lnk" "$EDITOR" "$INSTDIR\bin\drivedb-add.h" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\Documentation\drivedb-add.h (create, edit).lnk" "$EDITOR" "$INSTDIR\bin\drivedb-add.h"
nodb: ${EndIf}
CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\ChangeLog.lnk" "$INSTDIR\doc\ChangeLog.txt" CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\ChangeLog.lnk" "$INSTDIR\doc\ChangeLog.txt"
CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\COPYING.lnk" "$INSTDIR\doc\COPYING.txt" CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\COPYING.lnk" "$INSTDIR\doc\COPYING.txt"
CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\NEWS.lnk" "$INSTDIR\doc\NEWS.txt" CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\NEWS.lnk" "$INSTDIR\doc\NEWS.txt"
CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\Windows version download page.lnk" "http://smartmontools.no-ip.org/" ${EndIf}
nodoc:
; Homepage ; Homepage
CreateShortCut "$SMPROGRAMS\smartmontools\smartmontools Home Page.lnk" "http://www.smartmontools.org/" CreateShortCut "$SMPROGRAMS\smartmontools\smartmontools Home Page.lnk" "https://www.smartmontools.org/"
CreateShortCut "$SMPROGRAMS\smartmontools\smartmontools Daily Builds.lnk" "http://builds.smartmontools.org/"
; drivedb.h update ; drivedb.h update
IfFileExists "$INSTDIR\bin\update-smart-drivedb.exe" 0 noupdb ${If} ${FileExists} "$INSTDIR\bin\update-smart-drivedb.exe"
SetOutPath "$INSTDIR\bin" SetOutPath "$INSTDIR\bin"
!insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\drivedb.h update.lnk" "$INSTDIR\bin\update-smart-drivedb.exe" "" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\drivedb.h update.lnk" "$INSTDIR\bin\update-smart-drivedb.exe" ""
noupdb: ${EndIf}
; Uninstall ; Uninstall
IfFileExists "$INSTDIR\uninst-smartmontools.exe" 0 noinst ${If} ${FileExists} "$INSTDIR\uninst-smartmontools.exe"
SetOutPath "$INSTDIR" SetOutPath "$INSTDIR"
!insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\Uninstall smartmontools.lnk" "$INSTDIR\uninst-smartmontools.exe" "" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\Uninstall smartmontools.lnk" "$INSTDIR\uninst-smartmontools.exe" ""
noinst: ${EndIf}
SectionEnd SectionEnd
Section "Add install dir to PATH" PATH_SECTION Section "Add install dir to PATH" PATH_SECTION
SectionIn 1 SectionIn ${FULL_TYPES}
Push "$INSTDIR\bin" Push "$INSTDIR\bin"
Call AddToPath Call AddToPath
@ -358,13 +375,13 @@ SectionGroup "Add smartctl to drive menu"
!macroend !macroend
Section "Remove existing entries first" DRIVE_REMOVE_SECTION Section "Remove existing entries first" DRIVE_REMOVE_SECTION
SectionIn 3 SectionIn ${DRIVEMENU_TYPE}
!insertmacro DriveMenuRemove !insertmacro DriveMenuRemove
SectionEnd SectionEnd
!macro DriveSection id name args !macro DriveSection id name args
Section 'smartctl ${args} ...' DRIVE_${id}_SECTION Section 'smartctl ${args} ...' DRIVE_${id}_SECTION
SectionIn 3 SectionIn ${DRIVEMENU_TYPE}
Call CheckRunCmdA Call CheckRunCmdA
DetailPrint 'Add drive menu entry "${name}": smartctl ${args} ...' DetailPrint 'Add drive menu entry "${name}": smartctl ${args} ...'
WriteRegStr HKCR "Drive\shell\smartctl${id}" "" "${name}" WriteRegStr HKCR "Drive\shell\smartctl${id}" "" "${name}"
@ -386,37 +403,40 @@ SectionGroupEnd
Section "Uninstall" Section "Uninstall"
; Stop & remove service ; Stop & remove service
IfFileExists "$INSTDIR\bin\smartd.exe" 0 nosrv ${If} ${FileExists} "$INSTDIR\bin\smartd.exe"
ReadRegStr $0 HKLM "System\CurrentControlSet\Services\smartd" "ImagePath" ReadRegStr $0 HKLM "System\CurrentControlSet\Services\smartd" "ImagePath"
StrCmp $0 "" nosrv ${If} $0 != ""
ExecWait "net stop smartd" ExecWait "net stop smartd"
MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2 "Remove smartd service ?" /SD IDNO IDYES 0 IDNO nosrv MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2 "Remove smartd service ?" /SD IDNO IDYES 0 IDNO +2
ExecWait "$INSTDIR\bin\smartd.exe remove" ExecWait "$INSTDIR\bin\smartd.exe remove"
nosrv: ${EndIf}
${EndIf}
; Remove installer registry keys ; Remove installer registry keys
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools"
DeleteRegKey HKLM "Software\smartmontools" DeleteRegKey HKLM "Software\smartmontools"
; Remove conf file ? ; Remove conf file ?
IfFileExists "$INSTDIR\bin\smartd.conf" 0 noconf ${If} ${FileExists} "$INSTDIR\bin\smartd.conf"
; Assume unchanged if timestamp is equal to sample file ; Assume unchanged if timestamp is equal to sample file
GetFileTime "$INSTDIR\bin\smartd.conf" $0 $1 GetFileTime "$INSTDIR\bin\smartd.conf" $0 $1
GetFileTime "$INSTDIR\doc\smartd.conf" $2 $3 GetFileTime "$INSTDIR\doc\smartd.conf" $2 $3
StrCmp "$0:$1" "$2:$3" +2 0 StrCmp "$0:$1" "$2:$3" +2 0
MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2 "Delete configuration file$\n$INSTDIR\bin\smartd.conf ?" /SD IDNO IDYES 0 IDNO noconf MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2 "Delete configuration file$\n$INSTDIR\bin\smartd.conf ?" /SD IDNO IDYES 0 IDNO +2
Delete "$INSTDIR\bin\smartd.conf" Delete "$INSTDIR\bin\smartd.conf"
noconf: ${EndIf}
; Remove log file ? ; Remove log file ?
IfFileExists "$INSTDIR\bin\smartd.log" 0 +3 ${If} ${FileExists} "$INSTDIR\bin\smartd.log"
MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2 "Delete log file$\n$INSTDIR\bin\smartd.log ?" /SD IDNO IDYES 0 IDNO +2 MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2 "Delete log file$\n$INSTDIR\bin\smartd.log ?" /SD IDNO IDYES 0 IDNO +2
Delete "$INSTDIR\bin\smartd.log" Delete "$INSTDIR\bin\smartd.log"
${EndIf}
; Remove drivedb-add file ? ; Remove drivedb-add file ?
IfFileExists "$INSTDIR\bin\drivedb-add.h" 0 +3 ${If} ${FileExists} "$INSTDIR\bin\drivedb-add.h"
MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2 "Delete local drive database file$\n$INSTDIR\bin\drivedb-add.h ?" /SD IDNO IDYES 0 IDNO +2 MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2 "Delete local drive database file$\n$INSTDIR\bin\drivedb-add.h ?" /SD IDNO IDYES 0 IDNO +2
Delete "$INSTDIR\bin\drivedb-add.h" Delete "$INSTDIR\bin\drivedb-add.h"
${EndIf}
; Remove files ; Remove files
Delete "$INSTDIR\bin\smartctl.exe" Delete "$INSTDIR\bin\smartctl.exe"
@ -432,9 +452,9 @@ Section "Uninstall"
Delete "$INSTDIR\bin\smartd-run.bat" Delete "$INSTDIR\bin\smartd-run.bat"
Delete "$INSTDIR\bin\net-run.bat" Delete "$INSTDIR\bin\net-run.bat"
Delete "$INSTDIR\bin\runcmda.exe" Delete "$INSTDIR\bin\runcmda.exe"
Delete "$INSTDIR\bin\runcmda.exe.manifest" Delete "$INSTDIR\bin\runcmda.exe.manifest" ; TODO: Remove after smartmontools 6.5
Delete "$INSTDIR\bin\runcmdu.exe" Delete "$INSTDIR\bin\runcmdu.exe"
Delete "$INSTDIR\bin\runcmdu.exe.manifest" Delete "$INSTDIR\bin\runcmdu.exe.manifest" ; TODO: Remove after smartmontools 6.5
Delete "$INSTDIR\bin\wtssendmsg.exe" Delete "$INSTDIR\bin\wtssendmsg.exe"
Delete "$INSTDIR\doc\AUTHORS.txt" Delete "$INSTDIR\doc\AUTHORS.txt"
Delete "$INSTDIR\doc\ChangeLog.txt" Delete "$INSTDIR\doc\ChangeLog.txt"
@ -444,7 +464,6 @@ Section "Uninstall"
Delete "$INSTDIR\doc\NEWS.txt" Delete "$INSTDIR\doc\NEWS.txt"
Delete "$INSTDIR\doc\README.txt" Delete "$INSTDIR\doc\README.txt"
Delete "$INSTDIR\doc\TODO.txt" Delete "$INSTDIR\doc\TODO.txt"
Delete "$INSTDIR\doc\WARNINGS.txt"
Delete "$INSTDIR\doc\checksums*.txt" Delete "$INSTDIR\doc\checksums*.txt"
Delete "$INSTDIR\doc\smartctl.8.html" Delete "$INSTDIR\doc\smartctl.8.html"
Delete "$INSTDIR\doc\smartctl.8.txt" Delete "$INSTDIR\doc\smartctl.8.txt"
@ -479,14 +498,15 @@ Section "Uninstall"
!insertmacro DriveMenuRemove !insertmacro DriveMenuRemove
; Check for still existing entries ; Check for still existing entries
IfFileExists "$INSTDIR\bin\smartd.exe" 0 +3 ${If} ${FileExists} "$INSTDIR\bin\smartd.exe"
MessageBox MB_OK|MB_ICONEXCLAMATION "$INSTDIR\bin\smartd.exe could not be removed.$\nsmartd is possibly still running." /SD IDOK MessageBox MB_OK|MB_ICONEXCLAMATION "$INSTDIR\bin\smartd.exe could not be removed.$\nsmartd is possibly still running." /SD IDOK
Goto +3 ${ElseIf} ${FileExists} "$INSTDIR"
IfFileExists "$INSTDIR" 0 +2
MessageBox MB_OK "Note: $INSTDIR could not be removed." /SD IDOK MessageBox MB_OK "Note: $INSTDIR could not be removed." /SD IDOK
${EndIf}
IfFileExists "$SMPROGRAMS\smartmontools" 0 +2 ${If} ${FileExists} "$SMPROGRAMS\smartmontools"
MessageBox MB_OK "Note: $SMPROGRAMS\smartmontools could not be removed." /SD IDOK MessageBox MB_OK "Note: $SMPROGRAMS\smartmontools could not be removed." /SD IDOK
${EndIf}
SectionEnd SectionEnd
@ -502,19 +522,32 @@ SectionEnd
Function .onInit Function .onInit
; Set default install directories ; Set default install directories
StrCmp $INSTDIR "" 0 endinst ; /D=PATH option specified ? ${If} $INSTDIR == "" ; /D=PATH option not specified ?
ReadRegStr $INSTDIR HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "InstallLocation" ReadRegStr $INSTDIR HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "InstallLocation"
StrCmp $INSTDIR "" 0 endinst ; Already installed ? ${If} $INSTDIR == "" ; Not already installed ?
ReadRegStr $INSTDIR HKLM "Software\smartmontools" "Install_Dir" ReadRegStr $INSTDIR HKLM "Software\smartmontools" "Install_Dir"
StrCmp $INSTDIR "" 0 endinst ; Already installed ? ${If} $INSTDIR == "" ; Not already installed (smartmontools < r3911/6.3) ?
StrCpy $INSTDIR "$PROGRAMFILES\smartmontools" StrCpy $INSTDIR "$PROGRAMFILES\smartmontools"
!ifdef INPDIR64 !ifdef INPDIR64
StrCpy $INSTDIR32 $INSTDIR StrCpy $INSTDIR32 $INSTDIR
StrCpy $INSTDIR64 "$PROGRAMFILES64\smartmontools" StrCpy $INSTDIR64 "$PROGRAMFILES64\smartmontools"
!endif !endif
endinst: ${EndIf}
${EndIf}
${EndIf}
!ifdef INPDIR64 !ifdef INPDIR64
; Check for 64-bit unless already installed in 32-bit location
${If} $INSTDIR64 != ""
${OrIf} $INSTDIR != "$PROGRAMFILES\smartmontools"
; $1 = IsWow64Process(GetCurrentProcess(), ($0=FALSE, &$0))
System::Call "kernel32::GetCurrentProcess() i.s"
System::Call "kernel32::IsWow64Process(i s, *i 0 r0) i.r1"
${If} "$0 $1" == "1 1" ; 64-bit Windows ?
!insertmacro SelectSection ${X64_SECTION}
${EndIf}
${EndIf}
; Sizes of binary sections include 32-bit and 64-bit executables ; Sizes of binary sections include 32-bit and 64-bit executables
!insertmacro AdjustSectionSize ${SMARTCTL_SECTION} !insertmacro AdjustSectionSize ${SMARTCTL_SECTION}
!insertmacro AdjustSectionSize ${SMARTD_SECTION} !insertmacro AdjustSectionSize ${SMARTD_SECTION}
@ -523,47 +556,57 @@ Function .onInit
; Use Notepad++ if installed ; Use Notepad++ if installed
StrCpy $EDITOR "$PROGRAMFILES\Notepad++\notepad++.exe" StrCpy $EDITOR "$PROGRAMFILES\Notepad++\notepad++.exe"
IfFileExists "$EDITOR" +2 0 ${IfNot} ${FileExists} "$EDITOR"
StrCpy $EDITOR "notepad.exe" StrCpy $EDITOR "notepad.exe"
${EndIf}
Call ParseCmdLine Call ParseCmdLine
!ifdef INPDIR64
Call CheckX64
!endif
FunctionEnd FunctionEnd
; Check x64 section and update INSTDIR accordingly ; Check x64 section and update INSTDIR accordingly
!ifdef INPDIR64 !ifdef INPDIR64
Function CheckX64 Function CheckX64
SectionGetFlags ${X64_SECTION} $0 ${IfNot} ${SectionIsSelected} ${X64_SECTION}
IntOp $0 $0 & ${SF_SELECTED}
IntCmp $0 ${SF_SELECTED} x64
StrCpy $X64 "" StrCpy $X64 ""
StrCmp $INSTDIR32 "" +3 ${If} $INSTDIR32 != ""
${AndIf} $INSTDIR == $INSTDIR64
StrCpy $INSTDIR $INSTDIR32 StrCpy $INSTDIR $INSTDIR32
StrCpy $INSTDIR32 "" ${EndIf}
Goto done ${Else}
x64:
StrCpy $X64 "t" StrCpy $X64 "t"
StrCmp $INSTDIR64 "" +3 ${If} $INSTDIR64 != ""
${AndIf} $INSTDIR == $INSTDIR32
StrCpy $INSTDIR $INSTDIR64 StrCpy $INSTDIR $INSTDIR64
StrCpy $INSTDIR64 "" ${EndIf}
done: ${EndIf}
FunctionEnd FunctionEnd
!endif !endif
; Command line parsing ; Command line parsing
!macro CheckCmdLineOption name section
StrCpy $allopts "$allopts,${name}" !macro GetCmdLineOption var name
Push ",$opts," Push ",$opts,"
Push ",${name}," Push ",${name},"
Call StrStr Call StrStr
Pop $0 Pop ${var}
StrCmp $0 "" 0 sel_${name} ${If} ${var} != ""
!insertmacro UnselectSection ${section}
Goto done_${name}
sel_${name}:
!insertmacro SelectSection ${section}
StrCpy $nomatch "" StrCpy $nomatch ""
done_${name}: ${EndIf}
!macroend
!macro CheckCmdLineOption name section
StrCpy $allopts "$allopts,${name}"
!insertmacro GetCmdLineOption $0 ${name}
${If} $0 == ""
!insertmacro UnselectSection ${section}
${Else}
!insertmacro SelectSection ${section}
${EndIf}
!macroend !macroend
Function ParseCmdLine Function ParseCmdLine
@ -571,19 +614,30 @@ Function ParseCmdLine
Var /global opts Var /global opts
${GetParameters} $R0 ${GetParameters} $R0
${GetOptions} $R0 "/SO" $opts ${GetOptions} $R0 "/SO" $opts
IfErrors 0 +2 ${If} ${Errors}
Return Return
${EndIf}
Var /global allopts Var /global allopts
StrCpy $allopts ""
Var /global nomatch Var /global nomatch
StrCpy $nomatch "t" StrCpy $nomatch "t"
; turn sections on or off
!ifdef INPDIR64 !ifdef INPDIR64
!insertmacro CheckCmdLineOption "x64" ${X64_SECTION} ; Change previous 64-bit setting
Call CheckX64 StrCpy $allopts ",x32|x64"
StrCmp $opts "x64" 0 +2 !insertmacro GetCmdLineOption $0 "x32"
Return ; leave sections unchanged if only "x64" is specified ${If} $0 != ""
!insertmacro UnselectSection ${X64_SECTION}
${EndIf}
!insertmacro GetCmdLineOption $0 "x64"
${If} $0 != ""
!insertmacro SelectSection ${X64_SECTION}
${EndIf}
; Leave other sections unchanged if only "x32" or "x64" is specified
${If} $opts == "x32"
${OrIf} $opts == "x64"
Return
${EndIf}
!endif !endif
; Turn sections on or off
!insertmacro CheckCmdLineOption "smartctl" ${SMARTCTL_SECTION} !insertmacro CheckCmdLineOption "smartctl" ${SMARTCTL_SECTION}
!insertmacro CheckCmdLineOption "smartd" ${SMARTD_SECTION} !insertmacro CheckCmdLineOption "smartd" ${SMARTD_SECTION}
!insertmacro CheckCmdLineOption "smartctlnc" ${SMARTCTL_NC_SECTION} !insertmacro CheckCmdLineOption "smartctlnc" ${SMARTCTL_NC_SECTION}
@ -599,22 +653,25 @@ Function ParseCmdLine
!insertmacro CheckCmdLineOption "drive3" ${DRIVE_3_SECTION} !insertmacro CheckCmdLineOption "drive3" ${DRIVE_3_SECTION}
!insertmacro CheckCmdLineOption "drive4" ${DRIVE_4_SECTION} !insertmacro CheckCmdLineOption "drive4" ${DRIVE_4_SECTION}
!insertmacro CheckCmdLineOption "drive5" ${DRIVE_5_SECTION} !insertmacro CheckCmdLineOption "drive5" ${DRIVE_5_SECTION}
StrCmp $opts "-" done ${If} $opts != "-"
StrCmp $nomatch "" done ${If} $nomatch != ""
StrCpy $0 "$allopts,-" "" 1 StrCpy $0 "$allopts,-" "" 1
MessageBox MB_OK "Usage: smartmontools-VERSION.win32-setup [/S] [/SO component,...] [/D=INSTDIR]$\n$\ncomponents:$\n $0" MessageBox MB_OK "Usage: smartmontools-VERSION.win32-setup [/S] [/SO component,...] [/D=INSTDIR]$\n$\ncomponents:$\n $0"
Abort Abort
done: ${EndIf}
${EndIf}
FunctionEnd FunctionEnd
; Install runcmda.exe if missing ; Install runcmda.exe only once
Function CheckRunCmdA Function CheckRunCmdA
IfFileExists "$INSTDIR\bin\runcmda.exe" done 0 Var /global runcmda
${If} $runcmda == ""
StrCpy $runcmda "t"
SetOutPath "$INSTDIR\bin" SetOutPath "$INSTDIR\bin"
!insertmacro FileExe "bin\runcmda.exe" "" !insertmacro FileExe "bin\runcmda.exe" ""
File "${INPDIR}\bin\runcmda.exe.manifest" Delete "$INSTDIR\bin\runcmda.exe.manifest" ; TODO: Remove after smartmontools 6.5
done: ${EndIf}
FunctionEnd FunctionEnd
@ -647,8 +704,34 @@ Function AddToPath
Push $1 Push $1
Push $2 Push $2
Push $3 Push $3
Push $4
ReadRegStr $1 ${Environ} "PATH" ; NSIS ReadRegStr returns empty string on string overflow
; Native calls are used here to check actual length of PATH
; $4 = RegOpenKey(HKEY_CURRENT_USER, "Environment", &$3)
System::Call "advapi32::RegOpenKey(i 0x80000001, t'Environment', *i.r3) i.r4"
IntCmp $4 0 0 done done
; $4 = RegQueryValueEx($3, "PATH", (DWORD*)0, (DWORD*)0, &$1, ($2=NSIS_MAX_STRLEN, &$2))
; RegCloseKey($3)
System::Call "advapi32::RegQueryValueEx(i $3, t'PATH', i 0, i 0, t.r1, *i ${NSIS_MAX_STRLEN} r2) i.r4"
System::Call "advapi32::RegCloseKey(i $3)"
${If} $4 = 234 ; ERROR_MORE_DATA
DetailPrint "AddToPath: original length $2 > ${NSIS_MAX_STRLEN}"
MessageBox MB_OK "PATH not updated, original length $2 > ${NSIS_MAX_STRLEN}" /SD IDOK
Goto done
${EndIf}
${If} $4 <> 0 ; NO_ERROR
${If} $4 <> 2 ; ERROR_FILE_NOT_FOUND
DetailPrint "AddToPath: unexpected error code $4"
Goto done
${EndIf}
StrCpy $1 ""
${EndIf}
; Check if already in PATH
Push "$1;" Push "$1;"
Push "$0;" Push "$0;"
Call StrStr Call StrStr
@ -660,16 +743,31 @@ Function AddToPath
Pop $2 Pop $2
StrCmp $2 "" 0 done StrCmp $2 "" 0 done
; Prevent NSIS string overflow
StrLen $2 $0
StrLen $3 $1
IntOp $2 $2 + $3
IntOp $2 $2 + 2 ; $2 = strlen(dir) + strlen(PATH) + sizeof(";")
${If} $2 > ${NSIS_MAX_STRLEN}
DetailPrint "AddToPath: new length $2 > ${NSIS_MAX_STRLEN}"
MessageBox MB_OK "PATH not updated, new length $2 > ${NSIS_MAX_STRLEN}." /SD IDOK
Goto done
${EndIf}
; Append dir to PATH
DetailPrint "Add to PATH: $0" DetailPrint "Add to PATH: $0"
StrCpy $2 $1 1 -1 StrCpy $2 $1 1 -1
StrCmp $2 ";" 0 +2 ${If} $2 == ";"
StrCpy $1 $1 -1 ; remove trailing ';' StrCpy $1 $1 -1 ; remove trailing ';'
StrCmp $1 "" +2 ; no leading ';' ${EndIf}
${If} $1 != "" ; no leading ';'
StrCpy $0 "$1;$0" StrCpy $0 "$1;$0"
${EndIf}
WriteRegExpandStr ${Environ} "PATH" $0 WriteRegExpandStr ${Environ} "PATH" $0
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
done: done:
Pop $4
Pop $3 Pop $3
Pop $2 Pop $2
Pop $1 Pop $1
@ -694,8 +792,9 @@ Function un.RemoveFromPath
ReadRegStr $1 ${Environ} "PATH" ReadRegStr $1 ${Environ} "PATH"
StrCpy $5 $1 1 -1 StrCpy $5 $1 1 -1
StrCmp $5 ";" +2 ${If} $5 != ";"
StrCpy $1 "$1;" ; ensure trailing ';' StrCpy $1 "$1;" ; ensure trailing ';'
${EndIf}
Push $1 Push $1
Push "$0;" Push "$0;"
Call un.StrStr Call un.StrStr
@ -709,8 +808,9 @@ Function un.RemoveFromPath
StrCpy $6 $2 "" $3 ; $6 is now the part after the path to remove StrCpy $6 $2 "" $3 ; $6 is now the part after the path to remove
StrCpy $3 "$5$6" StrCpy $3 "$5$6"
StrCpy $5 $3 1 -1 StrCpy $5 $3 1 -1
StrCmp $5 ";" 0 +2 ${If} $5 == ";"
StrCpy $3 $3 -1 ; remove trailing ';' StrCpy $3 $3 -1 ; remove trailing ';'
${EndIf}
WriteRegExpandStr ${Environ} "PATH" $3 WriteRegExpandStr ${Environ} "PATH" $3
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
@ -745,13 +845,12 @@ Function ${un}StrStr
StrCpy $R4 0 StrCpy $R4 0
; $R1=substring, $R2=string, $R3=strlen(substring) ; $R1=substring, $R2=string, $R3=strlen(substring)
; $R4=count, $R5=tmp ; $R4=count, $R5=tmp
loop: ${Do}
StrCpy $R5 $R2 $R3 $R4 StrCpy $R5 $R2 $R3 $R4
StrCmp $R5 $R1 done ${IfThen} $R5 == $R1 ${|} ${ExitDo} ${|}
StrCmp $R5 "" done ${IfThen} $R5 == "" ${|} ${ExitDo} ${|}
IntOp $R4 $R4 + 1 IntOp $R4 $R4 + 1
Goto loop ${Loop}
done:
StrCpy $R1 $R2 "" $R4 StrCpy $R1 $R2 "" $R4
Pop $R5 Pop $R5
Pop $R4 Pop $R4
@ -771,8 +870,6 @@ FunctionEnd
; http://nsis.sourceforge.net/IShellLink_Set_RunAs_flag ; http://nsis.sourceforge.net/IShellLink_Set_RunAs_flag
; ;
!include "LogicLib.nsh"
!define IPersistFile {0000010b-0000-0000-c000-000000000046} !define IPersistFile {0000010b-0000-0000-c000-000000000046}
!define CLSID_ShellLink {00021401-0000-0000-C000-000000000046} !define CLSID_ShellLink {00021401-0000-0000-C000-000000000046}
!define IID_IShellLinkA {000214EE-0000-0000-C000-000000000046} !define IID_IShellLinkA {000214EE-0000-0000-C000-000000000046}
@ -819,5 +916,5 @@ Function ShellLinkSetRunAs
${Else} ${Else}
DetailPrint "Set RunAsAdmin: $9" DetailPrint "Set RunAsAdmin: $9"
${EndIf} ${EndIf}
System::Store L ; push $0-$9, $R0-$R9 System::Store L ; pop $R9-$R0, $9-$0
FunctionEnd FunctionEnd

View File

@ -1,7 +1,7 @@
/* /*
* Run console command and wait for user input * Run console command and wait for user input
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2011 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2011 Christian Franke <smartmontools-support@lists.sourceforge.net>
* *
@ -15,7 +15,7 @@
* *
*/ */
char svnid[] = "$Id: runcmd.c 3453 2011-10-16 12:45:27Z chrfranke $"; char svnid[] = "$Id: runcmd.c 4120 2015-08-27 16:12:21Z samm2 $";
#include <stdio.h> #include <stdio.h>
#include <windows.h> #include <windows.h>

View File

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="1.0.0.0"
name="runcmda.exe"
type="win32"
/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="requireAdministrator"
uiAccess="false"
/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

View File

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="1.0.0.0"
name="runcmdu.exe"
type="win32"
/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="asInvoker"
uiAccess="false"
/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

View File

@ -1,7 +1,7 @@
/* /*
* os_win32/syslog.h * os_win32/syslog.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2004-8 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2004-8 Christian Franke <smartmontools-support@lists.sourceforge.net>
* *
@ -19,7 +19,7 @@
#ifndef SYSLOG_H #ifndef SYSLOG_H
#define SYSLOG_H #define SYSLOG_H
#define SYSLOG_H_CVSID "$Id: syslog.h 3728 2012-12-13 17:57:50Z chrfranke $\n" #define SYSLOG_H_CVSID "$Id: syslog.h 4120 2015-08-27 16:12:21Z samm2 $\n"
#include <stdarg.h> #include <stdarg.h>

View File

@ -1,9 +1,9 @@
/* /*
* os_win32/syslog_win32.cpp * os_win32/syslog_win32.cpp
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2004-12 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2004-15 Christian Franke
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -33,7 +33,7 @@
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> // RegisterEventSourceA(), ReportEventA(), ... #include <windows.h> // RegisterEventSourceA(), ReportEventA(), ...
const char *syslog_win32_cpp_cvsid = "$Id: syslog_win32.cpp 3575 2012-07-19 21:32:56Z chrfranke $" const char *syslog_win32_cpp_cvsid = "$Id: syslog_win32.cpp 4149 2015-10-17 15:38:01Z chrfranke $"
SYSLOG_H_CVSID; SYSLOG_H_CVSID;
#ifdef _MSC_VER #ifdef _MSC_VER
@ -420,7 +420,7 @@ int main(int argc, char* argv[])
if (i % 13 == 0) if (i % 13 == 0)
Sleep(1000L); Sleep(1000L);
sprintf(buf, "Log Line %d\n", i); sprintf(buf, "Log Line %d\n", i);
syslog(i % 17 ? LOG_INFO : LOG_ERR, buf); syslog((i % 17) ? LOG_INFO : LOG_ERR, buf);
} }
closelog(); closelog();
return 0; return 0;

View File

@ -1,7 +1,7 @@
;/* ;/*
; * os_win32/syslogevt.mc ; * os_win32/syslogevt.mc
; * ; *
; * Home page of code is: http://smartmontools.sourceforge.net ; * Home page of code is: http://www.smartmontools.org
; * ; *
; * Copyright (C) 2004-10 Christian Franke <smartmontools-support@lists.sourceforge.net> ; * Copyright (C) 2004-10 Christian Franke <smartmontools-support@lists.sourceforge.net>
; * ; *
@ -16,7 +16,7 @@
; * ; *
; */ ; */
; ;
;// $Id: syslogevt.mc 3727 2012-12-13 17:23:06Z samm2 $ ;// $Id: syslogevt.mc 4120 2015-08-27 16:12:21Z samm2 $
; ;
;// Use message compiler "mc" or "windmc" to generate ;// Use message compiler "mc" or "windmc" to generate
;// syslogevt.rc, syslogevt.h, msg00001.bin ;// syslogevt.rc, syslogevt.h, msg00001.bin

View File

@ -1,7 +1,7 @@
; ;
; smartmontools drive database update NSIS script ; smartmontools drive database update NSIS script
; ;
; Home page of code is: http://smartmontools.sourceforge.net ; Home page of code is: http://www.smartmontools.org
; ;
; Copyright (C) 2011-13 Christian Franke <smartmontools-support@lists.sourceforge.net> ; Copyright (C) 2011-13 Christian Franke <smartmontools-support@lists.sourceforge.net>
; ;
@ -13,7 +13,7 @@
; You should have received a copy of the GNU General Public License ; You should have received a copy of the GNU General Public License
; (for example COPYING); If not, see <http://www.gnu.org/licenses/>. ; (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
; ;
; $Id: update-smart-drivedb.nsi 3815 2013-06-06 17:31:59Z chrfranke $ ; $Id: update-smart-drivedb.nsi 4120 2015-08-27 16:12:21Z samm2 $
; ;

View File

@ -47,7 +47,7 @@
<ClCompile> <ClCompile>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>.;..\..\getopt;..\..\regex;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>.;..\..\getopt;..\..\regex;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_DEBUG;HAVE_CONFIG_H;_USE_32BIT_TIME_T;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_DEBUG;__func__=__FUNCTION__;HAVE_CONFIG_H;_USE_32BIT_TIME_T;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild> <MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
@ -66,7 +66,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile> <ClCompile>
<AdditionalIncludeDirectories>.;..\..\getopt;..\..\regex;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>.;..\..\getopt;..\..\regex;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>NDEBUG;HAVE_CONFIG_H;_USE_32BIT_TIME_T;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>NDEBUG;__func__=__FUNCTION__;HAVE_CONFIG_H;_USE_32BIT_TIME_T;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader> <PrecompiledHeader>
</PrecompiledHeader> </PrecompiledHeader>
@ -85,6 +85,8 @@
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\ataidentify.cpp" /> <ClCompile Include="..\..\ataidentify.cpp" />
<ClCompile Include="..\..\dev_areca.cpp" /> <ClCompile Include="..\..\dev_areca.cpp" />
<ClCompile Include="..\..\nvmecmds.cpp" />
<ClCompile Include="..\..\nvmeprint.cpp" />
<ClCompile Include="..\daemon_win32.cpp"> <ClCompile Include="..\daemon_win32.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@ -171,8 +173,11 @@
<ClCompile Include="..\..\utility.cpp" /> <ClCompile Include="..\..\utility.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\aacraid.h" />
<ClInclude Include="..\..\ataidentify.h" /> <ClInclude Include="..\..\ataidentify.h" />
<ClInclude Include="..\..\dev_areca.h" /> <ClInclude Include="..\..\dev_areca.h" />
<ClInclude Include="..\..\nvmecmds.h" />
<ClInclude Include="..\..\nvmeprint.h" />
<ClInclude Include="config.h" /> <ClInclude Include="config.h" />
<ClInclude Include="svnversion.h" /> <ClInclude Include="svnversion.h" />
<CustomBuildStep Include="..\daemon_win32.h"> <CustomBuildStep Include="..\daemon_win32.h">

View File

@ -65,6 +65,8 @@
<ClCompile Include="..\..\utility.cpp" /> <ClCompile Include="..\..\utility.cpp" />
<ClCompile Include="..\..\ataidentify.cpp" /> <ClCompile Include="..\..\ataidentify.cpp" />
<ClCompile Include="..\..\dev_areca.cpp" /> <ClCompile Include="..\..\dev_areca.cpp" />
<ClCompile Include="..\..\nvmecmds.cpp" />
<ClCompile Include="..\..\nvmeprint.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\wbemcli_small.h"> <ClInclude Include="..\wbemcli_small.h">
@ -82,6 +84,7 @@
<ClInclude Include="..\..\getopt\getopt.h"> <ClInclude Include="..\..\getopt\getopt.h">
<Filter>getopt</Filter> <Filter>getopt</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\aacraid.h" />
<ClInclude Include="..\..\atacmdnames.h" /> <ClInclude Include="..\..\atacmdnames.h" />
<ClInclude Include="..\..\atacmds.h" /> <ClInclude Include="..\..\atacmds.h" />
<ClInclude Include="..\..\ataprint.h" /> <ClInclude Include="..\..\ataprint.h" />
@ -101,6 +104,8 @@
<ClInclude Include="..\..\dev_areca.h" /> <ClInclude Include="..\..\dev_areca.h" />
<ClInclude Include="config.h" /> <ClInclude Include="config.h" />
<ClInclude Include="svnversion.h" /> <ClInclude Include="svnversion.h" />
<ClInclude Include="..\..\nvmecmds.h" />
<ClInclude Include="..\..\nvmeprint.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="..\installer.nsi"> <None Include="..\installer.nsi">

View File

@ -88,6 +88,11 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\dev_areca.cpp" /> <ClCompile Include="..\..\dev_areca.cpp" />
<ClCompile Include="..\..\nvmecmds.cpp" />
<ClCompile Include="..\..\nvmeprint.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\daemon_win32.cpp" /> <ClCompile Include="..\daemon_win32.cpp" />
<ClCompile Include="..\syslog_win32.cpp" /> <ClCompile Include="..\syslog_win32.cpp" />
<ClCompile Include="..\wmiquery.cpp" /> <ClCompile Include="..\wmiquery.cpp" />
@ -174,11 +179,17 @@
<ClCompile Include="..\..\utility.cpp" /> <ClCompile Include="..\..\utility.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\aacraid.h" />
<ClInclude Include="..\..\ataidentify.h"> <ClInclude Include="..\..\ataidentify.h">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\dev_areca.h" /> <ClInclude Include="..\..\dev_areca.h" />
<ClInclude Include="..\..\nvmecmds.h" />
<ClInclude Include="..\..\nvmeprint.h">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="..\daemon_win32.h" /> <ClInclude Include="..\daemon_win32.h" />
<ClInclude Include="..\syslog.h" /> <ClInclude Include="..\syslog.h" />
<ClInclude Include="..\wbemcli_small.h" /> <ClInclude Include="..\wbemcli_small.h" />

View File

@ -65,6 +65,8 @@
<ClCompile Include="..\..\utility.cpp" /> <ClCompile Include="..\..\utility.cpp" />
<ClCompile Include="..\..\ataidentify.cpp" /> <ClCompile Include="..\..\ataidentify.cpp" />
<ClCompile Include="..\..\dev_areca.cpp" /> <ClCompile Include="..\..\dev_areca.cpp" />
<ClCompile Include="..\..\nvmecmds.cpp" />
<ClCompile Include="..\..\nvmeprint.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\daemon_win32.h"> <ClInclude Include="..\daemon_win32.h">
@ -88,6 +90,7 @@
<ClInclude Include="..\..\getopt\getopt.h"> <ClInclude Include="..\..\getopt\getopt.h">
<Filter>getopt</Filter> <Filter>getopt</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\aacraid.h" />
<ClInclude Include="..\..\atacmdnames.h" /> <ClInclude Include="..\..\atacmdnames.h" />
<ClInclude Include="..\..\atacmds.h" /> <ClInclude Include="..\..\atacmds.h" />
<ClInclude Include="..\..\cissio_freebsd.h" /> <ClInclude Include="..\..\cissio_freebsd.h" />
@ -104,6 +107,8 @@
<ClInclude Include="..\..\dev_areca.h" /> <ClInclude Include="..\..\dev_areca.h" />
<ClInclude Include="config.h" /> <ClInclude Include="config.h" />
<ClInclude Include="svnversion.h" /> <ClInclude Include="svnversion.h" />
<ClInclude Include="..\..\nvmecmds.h" />
<ClInclude Include="..\..\nvmeprint.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="..\installer.nsi"> <None Include="..\installer.nsi">

View File

@ -1,7 +1,7 @@
/* /*
* os_win32/wbemcli_small.h * os_win32/wbemcli_small.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* This file was extracted from wbemcli.h of the w64 mingw-runtime package * This file was extracted from wbemcli.h of the w64 mingw-runtime package
* (http://mingw-w64.sourceforge.net/). See original copyright below. * (http://mingw-w64.sourceforge.net/). See original copyright below.

View File

@ -1,7 +1,7 @@
/* /*
* os_win32/wmiquery.cpp * os_win32/wmiquery.cpp
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2011-13 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2011-13 Christian Franke <smartmontools-support@lists.sourceforge.net>
* *
@ -23,7 +23,7 @@
#include <stdio.h> #include <stdio.h>
const char * wmiquery_cpp_cvsid = "$Id: wmiquery.cpp 3802 2013-03-24 18:36:21Z chrfranke $" const char * wmiquery_cpp_cvsid = "$Id: wmiquery.cpp 4120 2015-08-27 16:12:21Z samm2 $"
WMIQUERY_H_CVSID; WMIQUERY_H_CVSID;

View File

@ -1,9 +1,9 @@
/* /*
* os_win32/wmiquery.h * os_win32/wmiquery.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2011 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2011-15 Christian Franke
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -18,7 +18,7 @@
#ifndef WMIQUERY_H #ifndef WMIQUERY_H
#define WMIQUERY_H #define WMIQUERY_H
#define WMIQUERY_H_CVSID "$Id: wmiquery.h 3475 2011-11-10 21:43:40Z chrfranke $" #define WMIQUERY_H_CVSID "$Id: wmiquery.h 4152 2015-10-17 16:08:21Z chrfranke $"
#ifdef HAVE_WBEMCLI_H #ifdef HAVE_WBEMCLI_H
#include <wbemcli.h> #include <wbemcli.h>
@ -45,7 +45,7 @@ class com_bstr
{ {
public: public:
/// Construct from string. /// Construct from string.
com_bstr(const char * str); explicit com_bstr(const char * str);
/// Destructor frees BSTR. /// Destructor frees BSTR.
~com_bstr() ~com_bstr()

View File

@ -1,7 +1,7 @@
/* /*
* WTSSendMessage() command line tool * WTSSendMessage() command line tool
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2012 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2012 Christian Franke <smartmontools-support@lists.sourceforge.net>
* *
@ -18,7 +18,7 @@
#define WINVER 0x0500 #define WINVER 0x0500
#define _WIN32_WINNT WINVER #define _WIN32_WINNT WINVER
char svnid[] = "$Id: wtssendmsg.c 3714 2012-11-24 16:34:47Z chrfranke $"; char svnid[] = "$Id: wtssendmsg.c 4120 2015-08-27 16:12:21Z samm2 $";
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -30,7 +30,7 @@ char svnid[] = "$Id: wtssendmsg.c 3714 2012-11-24 16:34:47Z chrfranke $";
static int usage() static int usage()
{ {
printf("wtssendmsg $Revision: 3714 $ - Display a message box on client desktops\n" printf("wtssendmsg $Revision: 4120 $ - Display a message box on client desktops\n"
"Copyright (C) 2012 Christian Franke, smartmontools.org\n\n" "Copyright (C) 2012 Christian Franke, smartmontools.org\n\n"
"Usage: wtssendmsg [-cas] [-v] [\"Caption\"] \"Message\"|-\n" "Usage: wtssendmsg [-cas] [-v] [\"Caption\"] \"Message\"|-\n"
" wtssendmsg -v\n\n" " wtssendmsg -v\n\n"

View File

@ -1,10 +1,10 @@
/* /*
* scsiata.cpp * scsiata.cpp
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2006-12 Douglas Gilbert <dgilbert@interlog.com> * Copyright (C) 2006-15 Douglas Gilbert <dgilbert@interlog.com>
* Copyright (C) 2009-13 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2009-16 Christian Franke
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -62,7 +62,7 @@
#include "dev_ata_cmd_set.h" // ata_device_with_command_set #include "dev_ata_cmd_set.h" // ata_device_with_command_set
#include "dev_tunnelled.h" // tunnelled_device<> #include "dev_tunnelled.h" // tunnelled_device<>
const char * scsiata_cpp_cvsid = "$Id: scsiata.cpp 3922 2014-06-23 19:17:18Z chrfranke $"; const char * scsiata_cpp_cvsid = "$Id: scsiata.cpp 4276 2016-04-02 19:13:39Z chrfranke $";
/* This is a slightly stretched SCSI sense "descriptor" format header. /* This is a slightly stretched SCSI sense "descriptor" format header.
The addition is to allow the 0x70 and 0x71 response codes. The idea The addition is to allow the 0x70 and 0x71 response codes. The idea
@ -203,6 +203,25 @@ sat_device::~sat_device() throw()
// des[11]: lba_high (7:0) // des[11]: lba_high (7:0)
// des[12]: device // des[12]: device
// des[13]: status // des[13]: status
//
//
// ATA registers returned via fixed format sense (allowed >= SAT-2)
// fxs[0]: info_valid (bit 7); response_code (6:0)
// fxs[1]: (obsolete)
// fxs[2]: sense_key (3:0) --> recovered error (formerly 'no sense')
// fxs[3]: information (31:24) --> ATA Error register
// fxs[4]: information (23:16) --> ATA Status register
// fxs[5]: information (15:8) --> ATA Device register
// fxs[6]: information (7:0) --> ATA Count (7:0)
// fxs[7]: additional sense length [should be >= 10]
// fxs[8]: command specific info (31:24) --> Extend (7), count_upper_nonzero
// (6), lba_upper_nonzero(5), log_index (3:0)
// fxs[9]: command specific info (23:16) --> ATA LBA (7:0)
// fxs[10]: command specific info (15:8) --> ATA LBA (15:8)
// fxs[11]: command specific info (7:0) --> ATA LBA (23:16)
// fxs[12]: additional sense code (asc) --> 0x0
// fxs[13]: additional sense code qualifier (ascq) --> 0x1d
// asc,ascq = 0x0,0x1d --> 'ATA pass through information available'
@ -243,7 +262,7 @@ bool sat_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
unsigned char cdb[SAT_ATA_PASSTHROUGH_16LEN]; unsigned char cdb[SAT_ATA_PASSTHROUGH_16LEN];
unsigned char sense[32]; unsigned char sense[32];
const unsigned char * ardp; const unsigned char * ardp;
int status, ard_len, have_sense; int ard_len, have_sense;
int extend = 0; int extend = 0;
int ck_cond = 0; /* set to 1 to read register(s) back */ int ck_cond = 0; /* set to 1 to read register(s) back */
int protocol = 3; /* non-data */ int protocol = 3; /* non-data */
@ -251,6 +270,7 @@ bool sat_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks */ int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks */
int t_length = 0; /* 0 -> no data transferred */ int t_length = 0; /* 0 -> no data transferred */
int passthru_size = DEF_SAT_ATA_PASSTHRU_SIZE; int passthru_size = DEF_SAT_ATA_PASSTHRU_SIZE;
bool sense_descriptor = true;
memset(cdb, 0, sizeof(cdb)); memset(cdb, 0, sizeof(cdb));
memset(sense, 0, sizeof(sense)); memset(sense, 0, sizeof(sense));
@ -358,6 +378,8 @@ bool sat_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
have_sense = sg_scsi_normalize_sense(io_hdr.sensep, io_hdr.resp_sense_len, have_sense = sg_scsi_normalize_sense(io_hdr.sensep, io_hdr.resp_sense_len,
&ssh); &ssh);
if (have_sense) { if (have_sense) {
sense_descriptor = ssh.response_code >= 0x72;
if (sense_descriptor) {
/* look for SAT ATA Return Descriptor */ /* look for SAT ATA Return Descriptor */
ardp = sg_scsi_sense_desc_find(io_hdr.sensep, ardp = sg_scsi_sense_desc_find(io_hdr.sensep,
io_hdr.resp_sense_len, io_hdr.resp_sense_len,
@ -369,9 +391,20 @@ bool sat_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
else if (ard_len > 14) else if (ard_len > 14)
ard_len = 14; ard_len = 14;
} }
}
scsi_do_sense_disect(&io_hdr, &sinfo); scsi_do_sense_disect(&io_hdr, &sinfo);
status = scsiSimpleSenseFilter(&sinfo); int status = scsiSimpleSenseFilter(&sinfo);
if (0 != status) {
// Workaround for bogus sense_key in sense data with SAT ATA Return Descriptor
if ( status && ck_cond && ardp && ard_len > 13
&& (ardp[13] & 0xc1) == 0x40 /* !BSY && DRDY && !ERR */) {
if (scsi_debugmode > 0)
pout("ATA status (0x%02x) indicates success, ignoring SCSI sense_key\n",
ardp[13]);
status = 0;
}
if (0 != status) { /* other than no_sense and recovered_error */
if (scsi_debugmode > 0) { if (scsi_debugmode > 0) {
pout("sat_device::ata_pass_through: scsi error: %s\n", pout("sat_device::ata_pass_through: scsi error: %s\n",
scsiErrString(status)); scsiErrString(status));
@ -408,28 +441,59 @@ bool sat_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
hi.lba_mid = ardp[ 8]; hi.lba_mid = ardp[ 8];
hi.lba_high = ardp[10]; hi.lba_high = ardp[10];
} }
} else if ((! sense_descriptor) &&
(0 == ssh.asc) &&
(SCSI_ASCQ_ATA_PASS_THROUGH == ssh.ascq) &&
(0 != io_hdr.sensep[4] /* Some ATA STATUS bit must be set */)) {
/* in SAT-2 and later, ATA registers may be passed back via
* fixed format sense data [ref: sat3r07 section 12.2.2.7] */
ata_out_regs & lo = out.out_regs;
lo.error = io_hdr.sensep[ 3];
lo.status = io_hdr.sensep[ 4];
lo.device = io_hdr.sensep[ 5];
lo.sector_count = io_hdr.sensep[ 6];
lo.lba_low = io_hdr.sensep[ 9];
lo.lba_mid = io_hdr.sensep[10];
lo.lba_high = io_hdr.sensep[11];
if (in.in_regs.is_48bit_cmd()) {
if (0 == (0x60 & io_hdr.sensep[8])) {
ata_out_regs & hi = out.out_regs.prev;
hi.sector_count = 0;
hi.lba_low = 0;
hi.lba_mid = 0;
hi.lba_high = 0;
} else {
/* getting the "hi." values when either
* count_upper_nonzero or lba_upper_nonzero are set
* involves fetching the SCSI ATA PASS-THROUGH
* Results log page and decoding the descriptor with
* the matching log_index field. Painful. */
} }
} }
if (ardp == NULL)
ck_cond = 0; /* not the type of sense data expected */
} }
if (0 == ck_cond) { }
} else { /* ck_cond == 0 */
if (have_sense) { if (have_sense) {
if ((ssh.response_code >= 0x72) && if (((SCSI_SK_NO_SENSE == ssh.sense_key) ||
((SCSI_SK_NO_SENSE == ssh.sense_key) ||
(SCSI_SK_RECOVERED_ERR == ssh.sense_key)) && (SCSI_SK_RECOVERED_ERR == ssh.sense_key)) &&
(0 == ssh.asc) && (0 == ssh.asc) &&
(SCSI_ASCQ_ATA_PASS_THROUGH == ssh.ascq)) { (SCSI_ASCQ_ATA_PASS_THROUGH == ssh.ascq)) {
if (ardp) {
if (scsi_debugmode > 0) { if (scsi_debugmode > 0) {
if (sense_descriptor && ardp) {
pout("Values from ATA Return Descriptor are:\n"); pout("Values from ATA Return Descriptor are:\n");
dStrHex((const char *)ardp, ard_len, 1); dStrHex((const char *)ardp, ard_len, 1);
} else if (! sense_descriptor) {
pout("Values from ATA fixed format sense are:\n");
pout(" Error: 0x%x\n", io_hdr.sensep[3]);
pout(" Status: 0x%x\n", io_hdr.sensep[4]);
pout(" Device: 0x%x\n", io_hdr.sensep[5]);
pout(" Count: 0x%x\n", io_hdr.sensep[6]);
}
}
} }
return set_err(EIO, "SAT command failed"); return set_err(EIO, "SAT command failed");
} }
} }
}
}
return true; return true;
} }
@ -1118,6 +1182,148 @@ bool usbjmicron_device::get_registers(unsigned short addr,
} }
/////////////////////////////////////////////////////////////////////////////
/// Prolific USB Bridge support. (PL2773) (Probably works on PL2771 also...)
class usbprolific_device
: public tunnelled_device<
/*implements*/ ata_device,
/*by tunnelling through a*/ scsi_device
>
{
public:
usbprolific_device(smart_interface * intf, scsi_device * scsidev,
const char * req_type);
virtual ~usbprolific_device() throw();
virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
};
usbprolific_device::usbprolific_device(smart_interface * intf, scsi_device * scsidev,
const char * req_type)
: smart_device(intf, scsidev->get_dev_name(), "usbprolific", req_type),
tunnelled_device<ata_device, scsi_device>(scsidev)
{
set_info().info_name = strprintf("%s [USB Prolific]", scsidev->get_info_name());
}
usbprolific_device::~usbprolific_device() throw()
{
}
bool usbprolific_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
{
if (!ata_cmd_is_supported(in,
ata_device::supports_data_out |
ata_device::supports_48bit_hi_null |
ata_device::supports_output_regs |
ata_device::supports_smart_status,
"Prolific" )
)
return false;
scsi_cmnd_io io_hdr;
memset(&io_hdr, 0, sizeof(io_hdr));
unsigned char cmd_rw = 0x10; // Read
switch (in.direction) {
case ata_cmd_in::no_data:
io_hdr.dxfer_dir = DXFER_NONE;
break;
case ata_cmd_in::data_in:
io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
io_hdr.dxfer_len = in.size;
io_hdr.dxferp = (unsigned char *)in.buffer;
memset(in.buffer, 0, in.size);
break;
case ata_cmd_in::data_out:
io_hdr.dxfer_dir = DXFER_TO_DEVICE;
io_hdr.dxfer_len = in.size;
io_hdr.dxferp = (unsigned char *)in.buffer;
cmd_rw = 0x0; // Write
break;
default:
return set_err(EINVAL);
}
// Based on reverse engineering of iSmart.exe with API Monitor.
// Seen commands:
// D0 0 0 0 06 7B 0 0 0 0 0 0 // Read Firmware info?, reads 16 bytes
// F4 0 0 0 06 7B // ??
// D8 15 0 D8 06 7B 0 0 0 0 1 1 4F C2 A0 B0 // SMART Enable
// D8 15 0 D0 06 7B 0 0 2 0 1 1 4F C2 A0 B0 // SMART Read values
// D8 15 0 D1 06 7B 0 0 2 0 1 1 4F C2 A0 B0 // SMART Read thresholds
// D8 15 0 D4 06 7B 0 0 0 0 0 1 4F C2 A0 B0 // SMART Execute self test
// D7 0 0 0 06 7B 0 0 0 0 0 0 0 0 0 0 // Read status registers, Reads 16 bytes of data
// Additional DATA OUT support based on document from Prolific
// Build pass through command
unsigned char cdb[16];
cdb[ 0] = 0xD8; // Operation Code (D8 = Prolific ATA pass through)
cdb[ 1] = cmd_rw|0x5; // Read(0x10)/Write(0x0) | NORMAL(0x5)/PREFIX(0x0)(?)
cdb[ 2] = 0x0; // Reserved
cdb[ 3] = in.in_regs.features; // Feature register (SMART command)
cdb[ 4] = 0x06; // Check Word (VendorID magic, Prolific: 0x067B)
cdb[ 5] = 0x7B; // Check Word (VendorID magic, Prolific: 0x067B)
cdb[ 6] = (unsigned char)(io_hdr.dxfer_len >> 24); // Length MSB
cdb[ 7] = (unsigned char)(io_hdr.dxfer_len >> 16); // Length ...
cdb[ 8] = (unsigned char)(io_hdr.dxfer_len >> 8); // Length ...
cdb[ 9] = (unsigned char)(io_hdr.dxfer_len ); // Length LSB
cdb[10] = in.in_regs.sector_count; // Sector Count
cdb[11] = in.in_regs.lba_low; // LBA Low (7:0)
cdb[12] = in.in_regs.lba_mid; // LBA Mid (15:8)
cdb[13] = in.in_regs.lba_high; // LBA High (23:16)
cdb[14] = in.in_regs.device | 0xA0; // Device/Head
cdb[15] = in.in_regs.command; // ATA Command Register (only PIO supported)
// Use '-r scsiioctl,1' to print CDB for debug purposes
io_hdr.cmnd = cdb;
io_hdr.cmnd_len = 16;
scsi_device * scsidev = get_tunnel_dev();
if (!scsi_pass_through_and_check(scsidev, &io_hdr,
"usbprolific_device::ata_pass_through: "))
return set_err(scsidev->get_err());
if (in.out_needed.is_set()) {
// Read ATA output registers
unsigned char regbuf[16] = {0, };
memset(&io_hdr, 0, sizeof(io_hdr));
io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
io_hdr.dxfer_len = sizeof(regbuf);
io_hdr.dxferp = regbuf;
memset(cdb, 0, sizeof(cdb));
cdb[ 0] = 0xD7; // Prolific read registers
cdb[ 4] = 0x06; // Check Word (VendorID magic, Prolific: 0x067B)
cdb[ 5] = 0x7B; // Check Word (VendorID magic, Prolific: 0x067B)
io_hdr.cmnd = cdb;
io_hdr.cmnd_len = sizeof(cdb);
if (!scsi_pass_through_and_check(scsidev, &io_hdr,
"usbprolific_device::scsi_pass_through (get registers): "))
return set_err(scsidev->get_err());
// Use '-r scsiioctl,2' to print input registers for debug purposes
// Example: 50 00 00 00 00 01 4f 00 c2 00 a0 da 00 b0 00 50
out.out_regs.status = regbuf[0]; // Status
out.out_regs.error = regbuf[1]; // Error
out.out_regs.sector_count = regbuf[2]; // Sector Count (7:0)
out.out_regs.lba_low = regbuf[4]; // LBA Low (7:0)
out.out_regs.lba_mid = regbuf[6]; // LBA Mid (7:0)
out.out_regs.lba_high = regbuf[8]; // LBA High (7:0)
out.out_regs.device = regbuf[10]; // Device/Head
// = regbuf[11]; // ATA Feature (7:0)
// = regbuf[13]; // ATA Command
}
return true;
}
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/// SunplusIT USB Bridge support. /// SunplusIT USB Bridge support.
@ -1280,6 +1486,13 @@ using namespace sat;
ata_device * smart_interface::get_sat_device(const char * type, scsi_device * scsidev) ata_device * smart_interface::get_sat_device(const char * type, scsi_device * scsidev)
{ {
if (!scsidev)
throw std::logic_error("smart_interface: get_sat_device() called with scsidev=0");
// Take temporary ownership of 'scsidev' to delete it on error
scsi_device_auto_ptr scsidev_holder(scsidev);
ata_device * satdev = 0;
if (!strncmp(type, "sat", 3)) { if (!strncmp(type, "sat", 3)) {
const char * t = type + 3; const char * t = type + 3;
bool enable_auto = false; bool enable_auto = false;
@ -1293,7 +1506,7 @@ ata_device * smart_interface::get_sat_device(const char * type, scsi_device * sc
set_err(EINVAL, "Option '-d sat[,auto][,N]' requires N to be 0, 12 or 16"); set_err(EINVAL, "Option '-d sat[,auto][,N]' requires N to be 0, 12 or 16");
return 0; return 0;
} }
return new sat_device(this, scsidev, type, ptlen, enable_auto); satdev = new sat_device(this, scsidev, type, ptlen, enable_auto);
} }
else if (!strncmp(type, "usbcypress", 10)) { else if (!strncmp(type, "usbcypress", 10)) {
@ -1304,7 +1517,7 @@ ata_device * smart_interface::get_sat_device(const char * type, scsi_device * sc
"an hexadecimal number between 0x0 and 0xff"); "an hexadecimal number between 0x0 and 0xff");
return 0; return 0;
} }
return new usbcypress_device(this, scsidev, type, signature); satdev = new usbcypress_device(this, scsidev, type, signature);
} }
else if (!strncmp(type, "usbjmicron", 10)) { else if (!strncmp(type, "usbjmicron", 10)) {
@ -1325,17 +1538,25 @@ ata_device * smart_interface::get_sat_device(const char * type, scsi_device * sc
set_err(EINVAL, "Option '-d usbjmicron[,p][,x],<n>' requires <n> to be 0 or 1"); set_err(EINVAL, "Option '-d usbjmicron[,p][,x],<n>' requires <n> to be 0 or 1");
return 0; return 0;
} }
return new usbjmicron_device(this, scsidev, type, prolific, ata_48bit_support, port); satdev = new usbjmicron_device(this, scsidev, type, prolific, ata_48bit_support, port);
}
else if (!strcmp(type, "usbprolific")) {
satdev = new usbprolific_device(this, scsidev, type);
} }
else if (!strcmp(type, "usbsunplus")) { else if (!strcmp(type, "usbsunplus")) {
return new usbsunplus_device(this, scsidev, type); satdev = new usbsunplus_device(this, scsidev, type);
} }
else { else {
set_err(EINVAL, "Unknown USB device type '%s'", type); set_err(EINVAL, "Unknown USB device type '%s'", type);
return 0; return 0;
} }
// 'scsidev' is now owned by 'satdev'
scsidev_holder.release();
return satdev;
} }
// Try to detect a SAT device behind a SCSI interface. // Try to detect a SAT device behind a SCSI interface.

View File

@ -1,13 +1,11 @@
/* /*
* scsicmds.cpp * scsicmds.cpp
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2002-8 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2002-8 Bruce Allen
* Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org> * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
* * Copyright (C) 2003-16 Douglas Gilbert <dgilbert@interlog.com>
* Additional SCSI work:
* Copyright (C) 2003-13 Douglas Gilbert <dgilbert@interlog.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -49,7 +47,7 @@
#include "dev_interface.h" #include "dev_interface.h"
#include "utility.h" #include "utility.h"
const char *scsicmds_c_cvsid="$Id: scsicmds.cpp 3915 2014-06-19 18:24:57Z dpgilbert $" const char *scsicmds_c_cvsid="$Id: scsicmds.cpp 4243 2016-03-20 18:29:36Z chrfranke $"
SCSICMDS_H_CVSID; SCSICMDS_H_CVSID;
// Print SCSI debug messages? // Print SCSI debug messages?
@ -61,13 +59,11 @@ supported_vpd_pages * supported_vpd_pages_p = NULL;
supported_vpd_pages::supported_vpd_pages(scsi_device * device) : num_valid(0) supported_vpd_pages::supported_vpd_pages(scsi_device * device) : num_valid(0)
{ {
unsigned char b[0xfc]; /* pre SPC-3 INQUIRY max response size */ unsigned char b[0xfc]; /* pre SPC-3 INQUIRY max response size */
int n;
memset(b, 0, sizeof(b)); memset(b, 0, sizeof(b));
if (device && (0 == scsiInquiryVpd(device, SCSI_VPD_SUPPORTED_VPD_PAGES, if (device && (0 == scsiInquiryVpd(device, SCSI_VPD_SUPPORTED_VPD_PAGES,
b, sizeof(b)))) { b, sizeof(b)))) {
num_valid = (b[2] << 8) + b[3]; num_valid = (b[2] << 8) + b[3];
n = sizeof(pages); int n = sizeof(pages);
if (num_valid > n) if (num_valid > n)
num_valid = n; num_valid = n;
memcpy(pages, b + 4, num_valid); memcpy(pages, b + 4, num_valid);
@ -91,7 +87,6 @@ void
dStrHex(const char* str, int len, int no_ascii) dStrHex(const char* str, int len, int no_ascii)
{ {
const char* p = str; const char* p = str;
unsigned char c;
char buff[82]; char buff[82];
int a = 0; int a = 0;
const int bpstart = 5; const int bpstart = 5;
@ -110,7 +105,7 @@ dStrHex(const char* str, int len, int no_ascii)
for(i = 0; i < len; i++) for(i = 0; i < len; i++)
{ {
c = *p++; unsigned char c = *p++;
bpos += 3; bpos += 3;
if (bpos == (bpstart + (9 * 3))) if (bpos == (bpstart + (9 * 3)))
bpos++; bpos++;
@ -125,6 +120,9 @@ dStrHex(const char* str, int len, int no_ascii)
} }
if (cpos > (cpstart+15)) if (cpos > (cpstart+15))
{ {
while (cpos > 0 && buff[cpos-1] == ' ')
cpos--;
buff[cpos] = 0;
pout("%s\n", buff); pout("%s\n", buff);
bpos = bpstart; bpos = bpstart;
cpos = cpstart; cpos = cpstart;
@ -136,6 +134,9 @@ dStrHex(const char* str, int len, int no_ascii)
} }
if (cpos > cpstart) if (cpos > cpstart)
{ {
while (cpos > 0 && buff[cpos-1] == ' ')
cpos--;
buff[cpos] = 0;
pout("%s\n", buff); pout("%s\n", buff);
} }
} }
@ -175,14 +176,12 @@ static const char * vendor_specific = "<vendor specific>";
const char * const char *
scsi_get_opcode_name(UINT8 opcode) scsi_get_opcode_name(UINT8 opcode)
{ {
int k;
int len = sizeof(opcode_name_arr) / sizeof(opcode_name_arr[0]); int len = sizeof(opcode_name_arr) / sizeof(opcode_name_arr[0]);
struct scsi_opcode_name * onp;
if (opcode >= 0xc0) if (opcode >= 0xc0)
return vendor_specific; return vendor_specific;
for (k = 0; k < len; ++k) { for (int k = 0; k < len; ++k) {
onp = &opcode_name_arr[k]; struct scsi_opcode_name * onp = &opcode_name_arr[k];
if (opcode == onp->opcode) if (opcode == onp->opcode)
return onp->name; return onp->name;
else if (opcode < onp->opcode) else if (opcode < onp->opcode)
@ -195,11 +194,9 @@ void
scsi_do_sense_disect(const struct scsi_cmnd_io * io_buf, scsi_do_sense_disect(const struct scsi_cmnd_io * io_buf,
struct scsi_sense_disect * out) struct scsi_sense_disect * out)
{ {
int resp_code;
memset(out, 0, sizeof(struct scsi_sense_disect)); memset(out, 0, sizeof(struct scsi_sense_disect));
if (SCSI_STATUS_CHECK_CONDITION == io_buf->scsi_status) { if (SCSI_STATUS_CHECK_CONDITION == io_buf->scsi_status) {
resp_code = (io_buf->sensep[0] & 0x7f); int resp_code = (io_buf->sensep[0] & 0x7f);
out->resp_code = resp_code; out->resp_code = resp_code;
if (resp_code >= 0x72) { if (resp_code >= 0x72) {
out->sense_key = (io_buf->sensep[1] & 0xf); out->sense_key = (io_buf->sensep[1] & 0xf);
@ -302,19 +299,19 @@ scsi_vpd_dev_id_iter(const unsigned char * initial_desig_desc, int page_len,
int * off, int m_assoc, int m_desig_type, int m_code_set) int * off, int m_assoc, int m_desig_type, int m_code_set)
{ {
const unsigned char * ucp; const unsigned char * ucp;
int k, c_set, assoc, desig_type; int k;
for (k = *off, ucp = initial_desig_desc ; (k + 3) < page_len; ) { for (k = *off, ucp = initial_desig_desc ; (k + 3) < page_len; ) {
k = (k < 0) ? 0 : (k + ucp[k + 3] + 4); k = (k < 0) ? 0 : (k + ucp[k + 3] + 4);
if ((k + 4) > page_len) if ((k + 4) > page_len)
break; break;
c_set = (ucp[k] & 0xf); int c_set = (ucp[k] & 0xf);
if ((m_code_set >= 0) && (m_code_set != c_set)) if ((m_code_set >= 0) && (m_code_set != c_set))
continue; continue;
assoc = ((ucp[k + 1] >> 4) & 0x3); int assoc = ((ucp[k + 1] >> 4) & 0x3);
if ((m_assoc >= 0) && (m_assoc != assoc)) if ((m_assoc >= 0) && (m_assoc != assoc))
continue; continue;
desig_type = (ucp[k + 1] & 0xf); int desig_type = (ucp[k + 1] & 0xf);
if ((m_desig_type >= 0) && (m_desig_type != desig_type)) if ((m_desig_type >= 0) && (m_desig_type != desig_type))
continue; continue;
*off = k; *off = k;
@ -330,11 +327,6 @@ int
scsi_decode_lu_dev_id(const unsigned char * b, int blen, char * s, int slen, scsi_decode_lu_dev_id(const unsigned char * b, int blen, char * s, int slen,
int * transport) int * transport)
{ {
int m, c_set, assoc, desig_type, i_len, naa, off, u, have_scsi_ns;
const unsigned char * ucp;
const unsigned char * ip;
int si = 0;
if (transport) if (transport)
*transport = -1; *transport = -1;
if (slen < 32) { if (slen < 32) {
@ -342,25 +334,29 @@ scsi_decode_lu_dev_id(const unsigned char * b, int blen, char * s, int slen,
s[0] = '\0'; s[0] = '\0';
return -1; return -1;
} }
have_scsi_ns = 0;
s[0] = '\0'; s[0] = '\0';
off = -1; int si = 0;
int have_scsi_ns = 0;
int off = -1;
int u;
while ((u = scsi_vpd_dev_id_iter(b, blen, &off, -1, -1, -1)) == 0) { while ((u = scsi_vpd_dev_id_iter(b, blen, &off, -1, -1, -1)) == 0) {
ucp = b + off; const unsigned char * ucp = b + off;
i_len = ucp[3]; int i_len = ucp[3];
if ((off + i_len + 4) > blen) { if ((off + i_len + 4) > blen) {
snprintf(s+si, slen-si, "error: designator length"); snprintf(s+si, slen-si, "error: designator length");
return -1; return -1;
} }
assoc = ((ucp[1] >> 4) & 0x3); int assoc = ((ucp[1] >> 4) & 0x3);
if (transport && assoc && (ucp[1] & 0x80) && (*transport < 0)) if (transport && assoc && (ucp[1] & 0x80) && (*transport < 0))
*transport = (ucp[0] >> 4) & 0xf; *transport = (ucp[0] >> 4) & 0xf;
if (0 != assoc) if (0 != assoc)
continue; continue;
ip = ucp + 4; const unsigned char * ip = ucp + 4;
c_set = (ucp[0] & 0xf); int c_set = (ucp[0] & 0xf);
desig_type = (ucp[1] & 0xf); int desig_type = (ucp[1] & 0xf);
int naa;
switch (desig_type) { switch (desig_type) {
case 0: /* vendor specific */ case 0: /* vendor specific */
case 1: /* T10 vendor identification */ case 1: /* T10 vendor identification */
@ -373,7 +369,7 @@ scsi_decode_lu_dev_id(const unsigned char * b, int blen, char * s, int slen,
if (have_scsi_ns) if (have_scsi_ns)
si = 0; si = 0;
si += snprintf(s+si, slen-si, "0x"); si += snprintf(s+si, slen-si, "0x");
for (m = 0; m < i_len; ++m) for (int m = 0; m < i_len; ++m)
si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]); si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
break; break;
case 3: /* NAA */ case 3: /* NAA */
@ -394,7 +390,7 @@ scsi_decode_lu_dev_id(const unsigned char * b, int blen, char * s, int slen,
return -1; return -1;
} }
si += snprintf(s+si, slen-si, "0x"); si += snprintf(s+si, slen-si, "0x");
for (m = 0; m < 8; ++m) for (int m = 0; m < 8; ++m)
si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]); si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
} else if ((3 == naa ) || (5 == naa)) { } else if ((3 == naa ) || (5 == naa)) {
/* NAA=3 Locally assigned; NAA=5 IEEE Registered */ /* NAA=3 Locally assigned; NAA=5 IEEE Registered */
@ -403,7 +399,7 @@ scsi_decode_lu_dev_id(const unsigned char * b, int blen, char * s, int slen,
return -1; return -1;
} }
si += snprintf(s+si, slen-si, "0x"); si += snprintf(s+si, slen-si, "0x");
for (m = 0; m < 8; ++m) for (int m = 0; m < 8; ++m)
si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]); si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
} else if (6 == naa) { /* NAA IEEE Registered extended */ } else if (6 == naa) { /* NAA IEEE Registered extended */
if (16 != i_len) { if (16 != i_len) {
@ -411,7 +407,7 @@ scsi_decode_lu_dev_id(const unsigned char * b, int blen, char * s, int slen,
return -1; return -1;
} }
si += snprintf(s+si, slen-si, "0x"); si += snprintf(s+si, slen-si, "0x");
for (m = 0; m < 16; ++m) for (int m = 0; m < 16; ++m)
si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]); si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
} }
break; break;
@ -461,7 +457,6 @@ scsiLogSense(scsi_device * device, int pagenum, int subpagenum, UINT8 *pBuf,
UINT8 cdb[10]; UINT8 cdb[10];
UINT8 sense[32]; UINT8 sense[32];
int pageLen; int pageLen;
int status, res;
if (known_resp_len > bufLen) if (known_resp_len > bufLen)
return -EIO; return -EIO;
@ -494,6 +489,7 @@ scsiLogSense(scsi_device * device, int pagenum, int subpagenum, UINT8 *pBuf,
if (!device->scsi_pass_through(&io_hdr)) if (!device->scsi_pass_through(&io_hdr))
return -device->get_errno(); return -device->get_errno();
scsi_do_sense_disect(&io_hdr, &sinfo); scsi_do_sense_disect(&io_hdr, &sinfo);
int res;
if ((res = scsiSimpleSenseFilter(&sinfo))) if ((res = scsiSimpleSenseFilter(&sinfo)))
return res; return res;
/* sanity check on response */ /* sanity check on response */
@ -529,7 +525,7 @@ scsiLogSense(scsi_device * device, int pagenum, int subpagenum, UINT8 *pBuf,
if (!device->scsi_pass_through(&io_hdr)) if (!device->scsi_pass_through(&io_hdr))
return -device->get_errno(); return -device->get_errno();
scsi_do_sense_disect(&io_hdr, &sinfo); scsi_do_sense_disect(&io_hdr, &sinfo);
status = scsiSimpleSenseFilter(&sinfo); int status = scsiSimpleSenseFilter(&sinfo);
if (0 != status) if (0 != status)
return status; return status;
/* sanity check on response */ /* sanity check on response */
@ -589,7 +585,6 @@ scsiModeSense(scsi_device * device, int pagenum, int subpagenum, int pc,
struct scsi_sense_disect sinfo; struct scsi_sense_disect sinfo;
UINT8 cdb[6]; UINT8 cdb[6];
UINT8 sense[32]; UINT8 sense[32];
int status;
if ((bufLen < 0) || (bufLen > 255)) if ((bufLen < 0) || (bufLen > 255))
return -EINVAL; return -EINVAL;
@ -611,7 +606,7 @@ scsiModeSense(scsi_device * device, int pagenum, int subpagenum, int pc,
if (!device->scsi_pass_through(&io_hdr)) if (!device->scsi_pass_through(&io_hdr))
return -device->get_errno(); return -device->get_errno();
scsi_do_sense_disect(&io_hdr, &sinfo); scsi_do_sense_disect(&io_hdr, &sinfo);
status = scsiSimpleSenseFilter(&sinfo); int status = scsiSimpleSenseFilter(&sinfo);
if (SIMPLE_ERR_TRY_AGAIN == status) { if (SIMPLE_ERR_TRY_AGAIN == status) {
if (!device->scsi_pass_through(&io_hdr)) if (!device->scsi_pass_through(&io_hdr))
return -device->get_errno(); return -device->get_errno();
@ -687,7 +682,6 @@ scsiModeSense10(scsi_device * device, int pagenum, int subpagenum, int pc,
struct scsi_sense_disect sinfo; struct scsi_sense_disect sinfo;
UINT8 cdb[10]; UINT8 cdb[10];
UINT8 sense[32]; UINT8 sense[32];
int status;
memset(&io_hdr, 0, sizeof(io_hdr)); memset(&io_hdr, 0, sizeof(io_hdr));
memset(cdb, 0, sizeof(cdb)); memset(cdb, 0, sizeof(cdb));
@ -708,7 +702,7 @@ scsiModeSense10(scsi_device * device, int pagenum, int subpagenum, int pc,
if (!device->scsi_pass_through(&io_hdr)) if (!device->scsi_pass_through(&io_hdr))
return -device->get_errno(); return -device->get_errno();
scsi_do_sense_disect(&io_hdr, &sinfo); scsi_do_sense_disect(&io_hdr, &sinfo);
status = scsiSimpleSenseFilter(&sinfo); int status = scsiSimpleSenseFilter(&sinfo);
if (SIMPLE_ERR_TRY_AGAIN == status) { if (SIMPLE_ERR_TRY_AGAIN == status) {
if (!device->scsi_pass_through(&io_hdr)) if (!device->scsi_pass_through(&io_hdr))
return -device->get_errno(); return -device->get_errno();
@ -879,8 +873,6 @@ scsiRequestSense(scsi_device * device, struct scsi_sense_disect * sense_info)
UINT8 cdb[6]; UINT8 cdb[6];
UINT8 sense[32]; UINT8 sense[32];
UINT8 buff[18]; UINT8 buff[18];
int len;
UINT8 resp_code;
memset(&io_hdr, 0, sizeof(io_hdr)); memset(&io_hdr, 0, sizeof(io_hdr));
memset(cdb, 0, sizeof(cdb)); memset(cdb, 0, sizeof(cdb));
@ -898,13 +890,13 @@ scsiRequestSense(scsi_device * device, struct scsi_sense_disect * sense_info)
if (!device->scsi_pass_through(&io_hdr)) if (!device->scsi_pass_through(&io_hdr))
return -device->get_errno(); return -device->get_errno();
if (sense_info) { if (sense_info) {
resp_code = buff[0] & 0x7f; UINT8 resp_code = buff[0] & 0x7f;
sense_info->resp_code = resp_code; sense_info->resp_code = resp_code;
sense_info->sense_key = buff[2] & 0xf; sense_info->sense_key = buff[2] & 0xf;
sense_info->asc = 0; sense_info->asc = 0;
sense_info->ascq = 0; sense_info->ascq = 0;
if ((0x70 == resp_code) || (0x71 == resp_code)) { if ((0x70 == resp_code) || (0x71 == resp_code)) {
len = buff[7] + 8; int len = buff[7] + 8;
if (len > 13) { if (len > 13) {
sense_info->asc = buff[12]; sense_info->asc = buff[12];
sense_info->ascq = buff[13]; sense_info->ascq = buff[13];
@ -989,40 +981,6 @@ scsiSendDiagnostic(scsi_device * device, int functioncode, UINT8 *pBuf,
return scsiSimpleSenseFilter(&sinfo); return scsiSimpleSenseFilter(&sinfo);
} }
/* RECEIVE DIAGNOSTIC command. Returns 0 if ok, 1 if NOT READY, 2 if
* command not supported, 3 if field in command not supported or returns
* negated errno. SPC-3 section 6.18 (rev 22a) */
int
scsiReceiveDiagnostic(scsi_device * device, int pcv, int pagenum, UINT8 *pBuf,
int bufLen)
{
struct scsi_cmnd_io io_hdr;
struct scsi_sense_disect sinfo;
UINT8 cdb[6];
UINT8 sense[32];
memset(&io_hdr, 0, sizeof(io_hdr));
memset(cdb, 0, sizeof(cdb));
io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
io_hdr.dxfer_len = bufLen;
io_hdr.dxferp = pBuf;
cdb[0] = RECEIVE_DIAGNOSTIC;
cdb[1] = pcv;
cdb[2] = pagenum;
cdb[3] = (bufLen >> 8) & 0xff;
cdb[4] = bufLen & 0xff;
io_hdr.cmnd = cdb;
io_hdr.cmnd_len = sizeof(cdb);
io_hdr.sensep = sense;
io_hdr.max_sense_len = sizeof(sense);
io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
if (!device->scsi_pass_through(&io_hdr))
return -device->get_errno();
scsi_do_sense_disect(&io_hdr, &sinfo);
return scsiSimpleSenseFilter(&sinfo);
}
/* TEST UNIT READY command. SPC-3 section 6.33 (rev 22a) */ /* TEST UNIT READY command. SPC-3 section 6.33 (rev 22a) */
static int static int
_testunitready(scsi_device * device, struct scsi_sense_disect * sinfo) _testunitready(scsi_device * device, struct scsi_sense_disect * sinfo)
@ -1072,7 +1030,8 @@ scsiTestUnitReady(scsi_device * device)
} }
/* READ DEFECT (10) command. Returns 0 if ok, 1 if NOT READY, 2 if /* READ DEFECT (10) command. Returns 0 if ok, 1 if NOT READY, 2 if
* command not supported, 3 if field in command not supported or returns * command not supported, 3 if field in command not supported, 101 if
* defect list not found (e.g. SSD may not have defect list) or returns
* negated errno. SBC-2 section 5.12 (rev 16) */ * negated errno. SBC-2 section 5.12 (rev 16) */
int int
scsiReadDefect10(scsi_device * device, int req_plist, int req_glist, scsiReadDefect10(scsi_device * device, int req_plist, int req_glist,
@ -1102,11 +1061,15 @@ scsiReadDefect10(scsi_device * device, int req_plist, int req_glist,
if (!device->scsi_pass_through(&io_hdr)) if (!device->scsi_pass_through(&io_hdr))
return -device->get_errno(); return -device->get_errno();
scsi_do_sense_disect(&io_hdr, &sinfo); scsi_do_sense_disect(&io_hdr, &sinfo);
/* Look for "(Primary|Grown) defect list not found" */
if ((sinfo.resp_code >= 0x70) && (0x1c == sinfo.asc))
return 101;
return scsiSimpleSenseFilter(&sinfo); return scsiSimpleSenseFilter(&sinfo);
} }
/* READ DEFECT (12) command. Returns 0 if ok, 1 if NOT READY, 2 if /* READ DEFECT (12) command. Returns 0 if ok, 1 if NOT READY, 2 if
* command not supported, 3 if field in command not supported or returns * command not supported, 3 if field in command not supported, 101 if
* defect list not found (e.g. SSD may not have defect list) or returns
* negated errno. SBC-3 section 5.18 (rev 35; vale Mark Evans) */ * negated errno. SBC-3 section 5.18 (rev 35; vale Mark Evans) */
int int
scsiReadDefect12(scsi_device * device, int req_plist, int req_glist, scsiReadDefect12(scsi_device * device, int req_plist, int req_glist,
@ -1142,6 +1105,9 @@ scsiReadDefect12(scsi_device * device, int req_plist, int req_glist,
if (!device->scsi_pass_through(&io_hdr)) if (!device->scsi_pass_through(&io_hdr))
return -device->get_errno(); return -device->get_errno();
scsi_do_sense_disect(&io_hdr, &sinfo); scsi_do_sense_disect(&io_hdr, &sinfo);
/* Look for "(Primary|Grown) defect list not found" */
if ((sinfo.resp_code >= 0x70) && (0x1c == sinfo.asc))
return 101;
return scsiSimpleSenseFilter(&sinfo); return scsiSimpleSenseFilter(&sinfo);
} }
@ -1229,7 +1195,7 @@ scsiGetSize(scsi_device * device, unsigned int * lb_sizep,
int * lb_per_pb_expp) int * lb_per_pb_expp)
{ {
unsigned int last_lba = 0, lb_size = 0; unsigned int last_lba = 0, lb_size = 0;
int k, res; int res;
uint64_t ret_val = 0; uint64_t ret_val = 0;
UINT8 rc16resp[32]; UINT8 rc16resp[32];
@ -1246,7 +1212,7 @@ scsiGetSize(scsi_device * device, unsigned int * lb_sizep,
pout("scsiGetSize: READ CAPACITY(16) failed, res=%d\n", res); pout("scsiGetSize: READ CAPACITY(16) failed, res=%d\n", res);
return 0; return 0;
} }
for (k = 0; k < 8; ++k) { for (int k = 0; k < 8; ++k) {
if (k > 0) if (k > 0)
ret_val <<= 8; ret_val <<= 8;
ret_val |= rc16resp[k + 0]; ret_val |= rc16resp[k + 0];
@ -1291,10 +1257,10 @@ scsiGetProtPBInfo(scsi_device * device, unsigned char * rc16_12_31p)
int int
scsiModePageOffset(const UINT8 * resp, int len, int modese_len) scsiModePageOffset(const UINT8 * resp, int len, int modese_len)
{ {
int resp_len, bd_len;
int offset = -1; int offset = -1;
if (resp) { if (resp) {
int resp_len, bd_len;
if (10 == modese_len) { if (10 == modese_len) {
resp_len = (resp[0] << 8) + resp[1] + 2; resp_len = (resp[0] << 8) + resp[1] + 2;
bd_len = (resp[6] << 8) + resp[7]; bd_len = (resp[6] << 8) + resp[7];
@ -1381,10 +1347,8 @@ scsiFetchIECmpage(scsi_device * device, struct scsi_iec_mode_page *iecp,
int int
scsi_IsExceptionControlEnabled(const struct scsi_iec_mode_page *iecp) scsi_IsExceptionControlEnabled(const struct scsi_iec_mode_page *iecp)
{ {
int offset;
if (iecp && iecp->gotCurrent) { if (iecp && iecp->gotCurrent) {
offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr), int offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr),
iecp->modese_len); iecp->modese_len);
if (offset >= 0) if (offset >= 0)
return (iecp->raw_curr[offset + 2] & DEXCPT_ENABLE) ? 0 : 1; return (iecp->raw_curr[offset + 2] & DEXCPT_ENABLE) ? 0 : 1;
@ -1397,10 +1361,8 @@ scsi_IsExceptionControlEnabled(const struct scsi_iec_mode_page *iecp)
int int
scsi_IsWarningEnabled(const struct scsi_iec_mode_page *iecp) scsi_IsWarningEnabled(const struct scsi_iec_mode_page *iecp)
{ {
int offset;
if (iecp && iecp->gotCurrent) { if (iecp && iecp->gotCurrent) {
offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr), int offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr),
iecp->modese_len); iecp->modese_len);
if (offset >= 0) if (offset >= 0)
return (iecp->raw_curr[offset + 2] & EWASC_ENABLE) ? 1 : 0; return (iecp->raw_curr[offset + 2] & EWASC_ENABLE) ? 1 : 0;
@ -1429,10 +1391,9 @@ int
scsiSetExceptionControlAndWarning(scsi_device * device, int enabled, scsiSetExceptionControlAndWarning(scsi_device * device, int enabled,
const struct scsi_iec_mode_page *iecp) const struct scsi_iec_mode_page *iecp)
{ {
int k, offset, resp_len; int offset, resp_len;
int err = 0; int err = 0;
UINT8 rout[SCSI_IECMP_RAW_LEN]; UINT8 rout[SCSI_IECMP_RAW_LEN];
int sp, eCEnabled, wEnabled;
if ((! iecp) || (! iecp->gotCurrent)) if ((! iecp) || (! iecp->gotCurrent))
return -EINVAL; return -EINVAL;
@ -1449,7 +1410,7 @@ scsiSetExceptionControlAndWarning(scsi_device * device, int enabled,
resp_len = rout[0] + 1; resp_len = rout[0] + 1;
rout[2] &= 0xef; rout[2] &= 0xef;
} }
sp = (rout[offset] & 0x80) ? 1 : 0; /* PS bit becomes 'SELECT's SP bit */ int sp = (rout[offset] & 0x80) ? 1 : 0; /* PS bit becomes 'SELECT's SP bit */
if (enabled) { if (enabled) {
rout[offset + 2] = SCSI_IEC_MP_BYTE2_ENABLED; rout[offset + 2] = SCSI_IEC_MP_BYTE2_ENABLED;
if (scsi_debugmode > 2) if (scsi_debugmode > 2)
@ -1468,7 +1429,7 @@ scsiSetExceptionControlAndWarning(scsi_device * device, int enabled,
rout[offset + 2] = chg2 ? (rout[offset + 2] & chg2) : rout[offset + 2] = chg2 ? (rout[offset + 2] & chg2) :
iecp->raw_curr[offset + 2]; iecp->raw_curr[offset + 2];
for (k = 3; k < 12; ++k) { for (int k = 3; k < 12; ++k) {
if (0 == iecp->raw_chg[offset + k]) if (0 == iecp->raw_chg[offset + k])
rout[offset + k] = iecp->raw_curr[offset + k]; rout[offset + k] = iecp->raw_curr[offset + k];
} }
@ -1479,8 +1440,8 @@ scsiSetExceptionControlAndWarning(scsi_device * device, int enabled,
return 0; return 0;
} }
} else { /* disabling Exception Control and (temperature) Warnings */ } else { /* disabling Exception Control and (temperature) Warnings */
eCEnabled = (rout[offset + 2] & DEXCPT_ENABLE) ? 0 : 1; int eCEnabled = (rout[offset + 2] & DEXCPT_ENABLE) ? 0 : 1;
wEnabled = (rout[offset + 2] & EWASC_ENABLE) ? 1 : 0; int wEnabled = (rout[offset + 2] & EWASC_ENABLE) ? 1 : 0;
if ((! eCEnabled) && (! wEnabled)) { if ((! eCEnabled) && (! wEnabled)) {
if (scsi_debugmode > 0) if (scsi_debugmode > 0)
pout("scsiSetExceptionControlAndWarning: already disabled\n"); pout("scsiSetExceptionControlAndWarning: already disabled\n");
@ -1533,7 +1494,6 @@ scsiCheckIE(scsi_device * device, int hasIELogPage, int hasTempLogPage,
struct scsi_sense_disect sense_info; struct scsi_sense_disect sense_info;
int err; int err;
int temperatureSet = 0; int temperatureSet = 0;
unsigned short pagesize;
UINT8 currTemp, trTemp; UINT8 currTemp, trTemp;
*asc = 0; *asc = 0;
@ -1549,7 +1509,7 @@ scsiCheckIE(scsi_device * device, int hasIELogPage, int hasTempLogPage,
return err; return err;
} }
// pull out page size from response, don't forget to add 4 // pull out page size from response, don't forget to add 4
pagesize = (unsigned short) ((tBuf[2] << 8) | tBuf[3]) + 4; unsigned short pagesize = (unsigned short) ((tBuf[2] << 8) | tBuf[3]) + 4;
if ((pagesize < 4) || tBuf[4] || tBuf[5]) { if ((pagesize < 4) || tBuf[4] || tBuf[5]) {
pout("Log Sense failed, IE page, bad parameter code or length\n"); pout("Log Sense failed, IE page, bad parameter code or length\n");
return SIMPLE_ERR_BAD_PARAM; return SIMPLE_ERR_BAD_PARAM;
@ -2109,30 +2069,6 @@ scsiGetIEString(UINT8 asc, UINT8 ascq)
} }
/* This is not documented in t10.org, page 0x80 is vendor specific */
/* Some IBM disks do an offline read-scan when they get this command. */
int
scsiSmartIBMOfflineTest(scsi_device * device)
{
UINT8 tBuf[256];
int res;
memset(tBuf, 0, sizeof(tBuf));
/* Build SMART Off-line Immediate Diag Header */
tBuf[0] = 0x80; /* Page Code */
tBuf[1] = 0x00; /* Reserved */
tBuf[2] = 0x00; /* Page Length MSB */
tBuf[3] = 0x04; /* Page Length LSB */
tBuf[4] = 0x03; /* SMART Revision */
tBuf[5] = 0x00; /* Reserved */
tBuf[6] = 0x00; /* Off-line Immediate Time MSB */
tBuf[7] = 0x00; /* Off-line Immediate Time LSB */
res = scsiSendDiagnostic(device, SCSI_DIAG_NO_SELF_TEST, tBuf, 8);
if (res)
pout("IBM offline test failed [%s]\n", scsiErrString(res));
return res;
}
int int
scsiSmartDefaultSelfTest(scsi_device * device) scsiSmartDefaultSelfTest(scsi_device * device)
{ {
@ -2207,7 +2143,7 @@ int
scsiFetchExtendedSelfTestTime(scsi_device * device, int * durationSec, scsiFetchExtendedSelfTestTime(scsi_device * device, int * durationSec,
int modese_len) int modese_len)
{ {
int err, offset, res; int err, offset;
UINT8 buff[64]; UINT8 buff[64];
memset(buff, 0, sizeof(buff)); memset(buff, 0, sizeof(buff));
@ -2233,7 +2169,7 @@ scsiFetchExtendedSelfTestTime(scsi_device * device, int * durationSec,
if (offset < 0) if (offset < 0)
return -EINVAL; return -EINVAL;
if (buff[offset + 1] >= 0xa) { if (buff[offset + 1] >= 0xa) {
res = (buff[offset + 10] << 8) | buff[offset + 11]; int res = (buff[offset + 10] << 8) | buff[offset + 11];
*durationSec = res; *durationSec = res;
return 0; return 0;
} }
@ -2244,17 +2180,13 @@ scsiFetchExtendedSelfTestTime(scsi_device * device, int * durationSec,
void void
scsiDecodeErrCounterPage(unsigned char * resp, struct scsiErrorCounter *ecp) scsiDecodeErrCounterPage(unsigned char * resp, struct scsiErrorCounter *ecp)
{ {
int k, j, num, pl, pc;
unsigned char * ucp;
unsigned char * xp;
uint64_t * ullp;
memset(ecp, 0, sizeof(*ecp)); memset(ecp, 0, sizeof(*ecp));
num = (resp[2] << 8) | resp[3]; int num = (resp[2] << 8) | resp[3];
ucp = &resp[0] + 4; unsigned char * ucp = &resp[0] + 4;
while (num > 3) { while (num > 3) {
pc = (ucp[0] << 8) | ucp[1]; int pc = (ucp[0] << 8) | ucp[1];
pl = ucp[3] + 4; int pl = ucp[3] + 4;
uint64_t * ullp;
switch (pc) { switch (pc) {
case 0: case 0:
case 1: case 1:
@ -2271,14 +2203,14 @@ scsiDecodeErrCounterPage(unsigned char * resp, struct scsiErrorCounter *ecp)
ullp = &ecp->counter[7]; ullp = &ecp->counter[7];
break; break;
} }
k = pl - 4; int k = pl - 4;
xp = ucp + 4; unsigned char * xp = ucp + 4;
if (k > (int)sizeof(*ullp)) { if (k > (int)sizeof(*ullp)) {
xp += (k - sizeof(*ullp)); xp += (k - sizeof(*ullp));
k = sizeof(*ullp); k = sizeof(*ullp);
} }
*ullp = 0; *ullp = 0;
for (j = 0; j < k; ++j) { for (int j = 0; j < k; ++j) {
if (j > 0) if (j > 0)
*ullp <<= 8; *ullp <<= 8;
*ullp |= xp[j]; *ullp |= xp[j];
@ -2292,17 +2224,15 @@ void
scsiDecodeNonMediumErrPage(unsigned char *resp, scsiDecodeNonMediumErrPage(unsigned char *resp,
struct scsiNonMediumError *nmep) struct scsiNonMediumError *nmep)
{ {
int k, j, num, pl, pc, szof;
unsigned char * ucp;
unsigned char * xp;
memset(nmep, 0, sizeof(*nmep)); memset(nmep, 0, sizeof(*nmep));
num = (resp[2] << 8) | resp[3]; int num = (resp[2] << 8) | resp[3];
ucp = &resp[0] + 4; unsigned char * ucp = &resp[0] + 4;
szof = sizeof(nmep->counterPC0); int szof = sizeof(nmep->counterPC0);
while (num > 3) { while (num > 3) {
pc = (ucp[0] << 8) | ucp[1]; int pc = (ucp[0] << 8) | ucp[1];
pl = ucp[3] + 4; int pl = ucp[3] + 4;
int k;
unsigned char * xp;
switch (pc) { switch (pc) {
case 0: case 0:
nmep->gotPC0 = 1; nmep->gotPC0 = 1;
@ -2313,7 +2243,7 @@ scsiDecodeNonMediumErrPage(unsigned char *resp,
k = szof; k = szof;
} }
nmep->counterPC0 = 0; nmep->counterPC0 = 0;
for (j = 0; j < k; ++j) { for (int j = 0; j < k; ++j) {
if (j > 0) if (j > 0)
nmep->counterPC0 <<= 8; nmep->counterPC0 <<= 8;
nmep->counterPC0 |= xp[j]; nmep->counterPC0 |= xp[j];
@ -2328,7 +2258,7 @@ scsiDecodeNonMediumErrPage(unsigned char *resp,
k = szof; k = szof;
} }
nmep->counterTFE_H = 0; nmep->counterTFE_H = 0;
for (j = 0; j < k; ++j) { for (int j = 0; j < k; ++j) {
if (j > 0) if (j > 0)
nmep->counterTFE_H <<= 8; nmep->counterTFE_H <<= 8;
nmep->counterTFE_H |= xp[j]; nmep->counterTFE_H |= xp[j];
@ -2343,7 +2273,7 @@ scsiDecodeNonMediumErrPage(unsigned char *resp,
k = szof; k = szof;
} }
nmep->counterPE_H = 0; nmep->counterPE_H = 0;
for (j = 0; j < k; ++j) { for (int j = 0; j < k; ++j) {
if (j > 0) if (j > 0)
nmep->counterPE_H <<= 8; nmep->counterPE_H <<= 8;
nmep->counterPE_H |= xp[j]; nmep->counterPE_H |= xp[j];
@ -2369,7 +2299,7 @@ scsiDecodeNonMediumErrPage(unsigned char *resp,
int int
scsiCountFailedSelfTests(scsi_device * fd, int noisy) scsiCountFailedSelfTests(scsi_device * fd, int noisy)
{ {
int num, k, n, err, res, fails, fail_hour; int num, k, err, fails, fail_hour;
UINT8 * ucp; UINT8 * ucp;
unsigned char resp[LOG_RESP_SELF_TEST_LEN]; unsigned char resp[LOG_RESP_SELF_TEST_LEN];
@ -2398,13 +2328,13 @@ scsiCountFailedSelfTests(scsi_device * fd, int noisy)
for (k = 0, ucp = resp + 4; k < 20; ++k, ucp += 20 ) { for (k = 0, ucp = resp + 4; k < 20; ++k, ucp += 20 ) {
// timestamp in power-on hours (or zero if test in progress) // timestamp in power-on hours (or zero if test in progress)
n = (ucp[6] << 8) | ucp[7]; int n = (ucp[6] << 8) | ucp[7];
// The spec says "all 20 bytes will be zero if no test" but // The spec says "all 20 bytes will be zero if no test" but
// DG has found otherwise. So this is a heuristic. // DG has found otherwise. So this is a heuristic.
if ((0 == n) && (0 == ucp[4])) if ((0 == n) && (0 == ucp[4]))
break; break;
res = ucp[4] & 0xf; int res = ucp[4] & 0xf;
if ((res > 2) && (res < 8)) { if ((res > 2) && (res < 8)) {
fails++; fails++;
if (1 == fails) if (1 == fails)
@ -2483,7 +2413,7 @@ int
scsiGetRPM(scsi_device * device, int modese_len, int * form_factorp, scsiGetRPM(scsi_device * device, int modese_len, int * form_factorp,
int * haw_zbcp) int * haw_zbcp)
{ {
int err, offset, speed; int err, offset;
UINT8 buff[64]; UINT8 buff[64];
int pc = MPAGE_CONTROL_DEFAULT; int pc = MPAGE_CONTROL_DEFAULT;
@ -2491,7 +2421,7 @@ scsiGetRPM(scsi_device * device, int modese_len, int * form_factorp,
if ((0 == scsiInquiryVpd(device, SCSI_VPD_BLOCK_DEVICE_CHARACTERISTICS, if ((0 == scsiInquiryVpd(device, SCSI_VPD_BLOCK_DEVICE_CHARACTERISTICS,
buff, sizeof(buff))) && buff, sizeof(buff))) &&
(((buff[2] << 8) + buff[3]) > 2)) { (((buff[2] << 8) + buff[3]) > 2)) {
speed = (buff[4] << 8) + buff[5]; int speed = (buff[4] << 8) + buff[5];
if (form_factorp) if (form_factorp)
*form_factorp = buff[7] & 0xf; *form_factorp = buff[7] & 0xf;
if (haw_zbcp) if (haw_zbcp)
@ -2737,7 +2667,7 @@ const unsigned char *
sg_scsi_sense_desc_find(const unsigned char * sensep, int sense_len, sg_scsi_sense_desc_find(const unsigned char * sensep, int sense_len,
int desc_type) int desc_type)
{ {
int add_sen_len, add_len, desc_len, k; int add_sen_len;
const unsigned char * descp; const unsigned char * descp;
if ((sense_len < 8) || (0 == (add_sen_len = sensep[7]))) if ((sense_len < 8) || (0 == (add_sen_len = sensep[7])))
@ -2747,9 +2677,9 @@ sg_scsi_sense_desc_find(const unsigned char * sensep, int sense_len,
add_sen_len = (add_sen_len < (sense_len - 8)) ? add_sen_len = (add_sen_len < (sense_len - 8)) ?
add_sen_len : (sense_len - 8); add_sen_len : (sense_len - 8);
descp = &sensep[8]; descp = &sensep[8];
for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) { for (int desc_len = 0, k = 0; k < add_sen_len; k += desc_len) {
descp += desc_len; descp += desc_len;
add_len = (k < (add_sen_len - 1)) ? descp[1]: -1; int add_len = (k < (add_sen_len - 1)) ? descp[1]: -1;
desc_len = add_len + 2; desc_len = add_len + 2;
if (descp[0] == desc_type) if (descp[0] == desc_type)
return descp; return descp;

View File

@ -1,13 +1,11 @@
/* /*
* scsicmds.h * scsicmds.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2002-8 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2002-8 Bruce Allen
* Copyright (C) 2000 Michael Cornwell <cornwell@acm.org> * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
* * Copyright (C) 2003-15 Douglas Gilbert <dgilbert@interlog.com>
* Additional SCSI work:
* Copyright (C) 2003-13 Douglas Gilbert <dgilbert@interlog.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -32,7 +30,7 @@
#ifndef SCSICMDS_H_ #ifndef SCSICMDS_H_
#define SCSICMDS_H_ #define SCSICMDS_H_
#define SCSICMDS_H_CVSID "$Id: scsicmds.h 3896 2014-04-28 04:31:25Z dpgilbert $\n" #define SCSICMDS_H_CVSID "$Id: scsicmds.h 4152 2015-10-17 16:08:21Z chrfranke $\n"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -322,7 +320,7 @@ class scsi_device;
class supported_vpd_pages class supported_vpd_pages
{ {
public: public:
supported_vpd_pages(scsi_device * device); explicit supported_vpd_pages(scsi_device * device);
~supported_vpd_pages() { num_valid = 0; } ~supported_vpd_pages() { num_valid = 0; }
bool is_supported(int vpd_page_num) const; bool is_supported(int vpd_page_num) const;
@ -385,9 +383,6 @@ int scsiRequestSense(scsi_device * device, struct scsi_sense_disect * sense_info
int scsiSendDiagnostic(scsi_device * device, int functioncode, UINT8 *pBuf, int bufLen); int scsiSendDiagnostic(scsi_device * device, int functioncode, UINT8 *pBuf, int bufLen);
int scsiReceiveDiagnostic(scsi_device * device, int pcv, int pagenum, UINT8 *pBuf,
int bufLen);
int scsiReadDefect10(scsi_device * device, int req_plist, int req_glist, int dl_format, int scsiReadDefect10(scsi_device * device, int req_plist, int req_glist, int dl_format,
UINT8 *pBuf, int bufLen); UINT8 *pBuf, int bufLen);
@ -433,8 +428,6 @@ const char* scsiGetIEString(UINT8 asc, UINT8 ascq);
int scsiGetTemp(scsi_device * device, UINT8 *currenttemp, UINT8 *triptemp); int scsiGetTemp(scsi_device * device, UINT8 *currenttemp, UINT8 *triptemp);
int scsiSmartIBMOfflineTest(scsi_device * device);
int scsiSmartDefaultSelfTest(scsi_device * device); int scsiSmartDefaultSelfTest(scsi_device * device);
int scsiSmartShortSelfTest(scsi_device * device); int scsiSmartShortSelfTest(scsi_device * device);
int scsiSmartExtendSelfTest(scsi_device * device); int scsiSmartExtendSelfTest(scsi_device * device);

View File

@ -1,13 +1,11 @@
/* /*
* scsiprint.cpp * scsiprint.cpp
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2002-11 Bruce Allen
* Copyright (C) 2000 Michael Cornwell <cornwell@acm.org> * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
* * Copyright (C) 2003-15 Douglas Gilbert <dgilbert@interlog.com>
* Additional SCSI work:
* Copyright (C) 2003-13 Douglas Gilbert <dgilbert@interlog.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -42,7 +40,7 @@
#define GBUF_SIZE 65535 #define GBUF_SIZE 65535
const char * scsiprint_c_cvsid = "$Id: scsiprint.cpp 3898 2014-04-30 17:44:13Z dpgilbert $" const char * scsiprint_c_cvsid = "$Id: scsiprint.cpp 4292 2016-04-12 23:06:59Z dpgilbert $"
SCSIPRINT_H_CVSID; SCSIPRINT_H_CVSID;
@ -87,6 +85,14 @@ scsiGetSupportedLogPages(scsi_device * device)
if (scsi_debugmode > 0) if (scsi_debugmode > 0)
pout("Log Sense for supported pages failed [%s]\n", pout("Log Sense for supported pages failed [%s]\n",
scsiErrString(err)); scsiErrString(err));
/* try one more time with defined length, workaround for the bug #678
found with ST8000NM0075/E001 */
err = scsiLogSense(device, SUPPORTED_LPAGES, 0, gBuf,
LOG_RESP_LEN, 68); /* 64 max pages + 4b header */
if (scsi_debugmode > 0)
pout("Log Sense for supported pages failed (second attempt) [%s]\n",
scsiErrString(err));
if (err)
return; return;
} }
@ -151,8 +157,8 @@ scsiGetSmartData(scsi_device * device, bool attribs)
{ {
UINT8 asc; UINT8 asc;
UINT8 ascq; UINT8 ascq;
UINT8 currenttemp = 0; UINT8 currenttemp = 255;
UINT8 triptemp = 0; UINT8 triptemp = 255;
const char * cp; const char * cp;
int err = 0; int err = 0;
print_on(); print_on();
@ -173,13 +179,13 @@ scsiGetSmartData(scsi_device * device, bool attribs)
pout("SMART Health Status: OK\n"); pout("SMART Health Status: OK\n");
if (attribs && !gTempLPage) { if (attribs && !gTempLPage) {
if (currenttemp) { if (255 == currenttemp)
if (255 != currenttemp)
pout("Current Drive Temperature: %d C\n", currenttemp);
else
pout("Current Drive Temperature: <not available>\n"); pout("Current Drive Temperature: <not available>\n");
} else
if (triptemp) pout("Current Drive Temperature: %d C\n", currenttemp);
if (255 == triptemp)
pout("Drive Trip Temperature: <not available>\n");
else
pout("Drive Trip Temperature: %d C\n", triptemp); pout("Drive Trip Temperature: %d C\n", triptemp);
} }
pout("\n"); pout("\n");
@ -204,7 +210,7 @@ scsiGetTapeAlertsData(scsi_device * device, int peripheral_type)
print_on(); print_on();
if ((err = scsiLogSense(device, TAPE_ALERTS_LPAGE, 0, gBuf, if ((err = scsiLogSense(device, TAPE_ALERTS_LPAGE, 0, gBuf,
LOG_RESP_TAPE_ALERT_LEN, LOG_RESP_TAPE_ALERT_LEN))) { LOG_RESP_TAPE_ALERT_LEN, LOG_RESP_TAPE_ALERT_LEN))) {
pout("scsiGetTapesAlertData Failed [%s]\n", scsiErrString(err)); pout("%s Failed [%s]\n", __func__, scsiErrString(err));
print_off(); print_off();
return -1; return -1;
} }
@ -244,14 +250,13 @@ scsiGetTapeAlertsData(scsi_device * device, int peripheral_type)
static void static void
scsiGetStartStopData(scsi_device * device) scsiGetStartStopData(scsi_device * device)
{ {
UINT32 u; int err, len, k, extra;
int err, len, k, extra, pc;
unsigned char * ucp; unsigned char * ucp;
if ((err = scsiLogSense(device, STARTSTOP_CYCLE_COUNTER_LPAGE, 0, gBuf, if ((err = scsiLogSense(device, STARTSTOP_CYCLE_COUNTER_LPAGE, 0, gBuf,
LOG_RESP_LEN, 0))) { LOG_RESP_LEN, 0))) {
print_on(); print_on();
pout("scsiGetStartStopData Failed [%s]\n", scsiErrString(err)); pout("%s Failed [%s]\n", __func__, scsiErrString(err));
print_off(); print_off();
return; return;
} }
@ -271,7 +276,8 @@ scsiGetStartStopData(scsi_device * device)
return; return;
} }
extra = ucp[3] + 4; extra = ucp[3] + 4;
pc = (ucp[0] << 8) + ucp[1]; int pc = (ucp[0] << 8) + ucp[1];
UINT32 u;
switch (pc) { switch (pc) {
case 1: case 1:
if (10 == extra) if (10 == extra)
@ -321,7 +327,7 @@ scsiGetStartStopData(scsi_device * device)
static void static void
scsiPrintGrownDefectListLen(scsi_device * device) scsiPrintGrownDefectListLen(scsi_device * device)
{ {
int err, dl_format, got_rd12, generation; int err, dl_format, got_rd12;
unsigned int dl_len, div; unsigned int dl_len, div;
memset(gBuf, 0, 8); memset(gBuf, 0, 8);
@ -339,7 +345,9 @@ scsiPrintGrownDefectListLen(scsi_device * device)
return; return;
} else } else
got_rd12 = 0; got_rd12 = 0;
} else { } else if (101 == err) /* Defect list not found, leave quietly */
return;
else {
if (scsi_debugmode > 0) { if (scsi_debugmode > 0) {
print_on(); print_on();
pout("Read defect list (12) Failed: %s\n", scsiErrString(err)); pout("Read defect list (12) Failed: %s\n", scsiErrString(err));
@ -351,7 +359,7 @@ scsiPrintGrownDefectListLen(scsi_device * device)
got_rd12 = 1; got_rd12 = 1;
if (got_rd12) { if (got_rd12) {
generation = (gBuf[2] << 8) + gBuf[3]; int generation = (gBuf[2] << 8) + gBuf[3];
if ((generation > 1) && (scsi_debugmode > 0)) { if ((generation > 1) && (scsi_debugmode > 0)) {
print_on(); print_on();
pout("Read defect list (12): generation=%d\n", generation); pout("Read defect list (12): generation=%d\n", generation);
@ -403,9 +411,8 @@ scsiPrintGrownDefectListLen(scsi_device * device)
static void static void
scsiPrintSeagateCacheLPage(scsi_device * device) scsiPrintSeagateCacheLPage(scsi_device * device)
{ {
int k, j, num, pl, pc, err, len; int num, pl, pc, err, len;
unsigned char * ucp; unsigned char * ucp;
unsigned char * xp;
uint64_t ull; uint64_t ull;
if ((err = scsiLogSense(device, SEAGATE_CACHE_LPAGE, 0, gBuf, if ((err = scsiLogSense(device, SEAGATE_CACHE_LPAGE, 0, gBuf,
@ -458,14 +465,14 @@ scsiPrintSeagateCacheLPage(scsi_device * device)
"> segment size"); break; "> segment size"); break;
default: pout(" Unknown Seagate parameter code [0x%x]", pc); break; default: pout(" Unknown Seagate parameter code [0x%x]", pc); break;
} }
k = pl - 4; int k = pl - 4;
xp = ucp + 4; unsigned char * xp = ucp + 4;
if (k > (int)sizeof(ull)) { if (k > (int)sizeof(ull)) {
xp += (k - (int)sizeof(ull)); xp += (k - (int)sizeof(ull));
k = (int)sizeof(ull); k = (int)sizeof(ull);
} }
ull = 0; ull = 0;
for (j = 0; j < k; ++j) { for (int j = 0; j < k; ++j) {
if (j > 0) if (j > 0)
ull <<= 8; ull <<= 8;
ull |= xp[j]; ull |= xp[j];
@ -480,15 +487,14 @@ scsiPrintSeagateCacheLPage(scsi_device * device)
static void static void
scsiPrintSeagateFactoryLPage(scsi_device * device) scsiPrintSeagateFactoryLPage(scsi_device * device)
{ {
int k, j, num, pl, pc, len, err, good, bad; int num, pl, pc, len, err, good, bad;
unsigned char * ucp; unsigned char * ucp;
unsigned char * xp;
uint64_t ull; uint64_t ull;
if ((err = scsiLogSense(device, SEAGATE_FACTORY_LPAGE, 0, gBuf, if ((err = scsiLogSense(device, SEAGATE_FACTORY_LPAGE, 0, gBuf,
LOG_RESP_LEN, 0))) { LOG_RESP_LEN, 0))) {
print_on(); print_on();
pout("scsiPrintSeagateFactoryLPage Failed [%s]\n", scsiErrString(err)); pout("%s Failed [%s]\n", __func__, scsiErrString(err));
print_off(); print_off();
return; return;
} }
@ -550,14 +556,14 @@ scsiPrintSeagateFactoryLPage(scsi_device * device)
break; break;
} }
if (good) { if (good) {
k = pl - 4; int k = pl - 4;
xp = ucp + 4; unsigned char * xp = ucp + 4;
if (k > (int)sizeof(ull)) { if (k > (int)sizeof(ull)) {
xp += (k - (int)sizeof(ull)); xp += (k - (int)sizeof(ull));
k = (int)sizeof(ull); k = (int)sizeof(ull);
} }
ull = 0; ull = 0;
for (j = 0; j < k; ++j) { for (int j = 0; j < k; ++j) {
if (j > 0) if (j > 0)
ull <<= 8; ull <<= 8;
ull |= xp[j]; ull |= xp[j];
@ -578,10 +584,7 @@ scsiPrintErrorCounterLog(scsi_device * device)
{ {
struct scsiErrorCounter errCounterArr[3]; struct scsiErrorCounter errCounterArr[3];
struct scsiErrorCounter * ecp; struct scsiErrorCounter * ecp;
struct scsiNonMediumError nme;
int found[3] = {0, 0, 0}; int found[3] = {0, 0, 0};
const char * pageNames[3] = {"read: ", "write: ", "verify: "};
double processed_gb;
if (gReadECounterLPage && (0 == scsiLogSense(device, if (gReadECounterLPage && (0 == scsiLogSense(device,
READ_ERROR_COUNTER_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) { READ_ERROR_COUNTER_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) {
@ -616,10 +619,11 @@ scsiPrintErrorCounterLog(scsi_device * device)
if (! found[k]) if (! found[k])
continue; continue;
ecp = &errCounterArr[k]; ecp = &errCounterArr[k];
static const char * const pageNames[3] = {"read: ", "write: ", "verify: "};
pout("%s%8" PRIu64 " %8" PRIu64 " %8" PRIu64 " %8" PRIu64 " %8" PRIu64, pout("%s%8" PRIu64 " %8" PRIu64 " %8" PRIu64 " %8" PRIu64 " %8" PRIu64,
pageNames[k], ecp->counter[0], ecp->counter[1], pageNames[k], ecp->counter[0], ecp->counter[1],
ecp->counter[2], ecp->counter[3], ecp->counter[4]); ecp->counter[2], ecp->counter[3], ecp->counter[4]);
processed_gb = ecp->counter[5] / 1000000000.0; double processed_gb = ecp->counter[5] / 1000000000.0;
pout(" %12.3f %8" PRIu64 "\n", processed_gb, ecp->counter[6]); pout(" %12.3f %8" PRIu64 "\n", processed_gb, ecp->counter[6]);
} }
} }
@ -627,6 +631,7 @@ scsiPrintErrorCounterLog(scsi_device * device)
pout("Error Counter logging not supported\n"); pout("Error Counter logging not supported\n");
if (gNonMediumELPage && (0 == scsiLogSense(device, if (gNonMediumELPage && (0 == scsiLogSense(device,
NON_MEDIUM_ERROR_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) { NON_MEDIUM_ERROR_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) {
struct scsiNonMediumError nme;
scsiDecodeNonMediumErrPage(gBuf, &nme); scsiDecodeNonMediumErrPage(gBuf, &nme);
if (nme.gotPC0) if (nme.gotPC0)
pout("\nNon-medium error count: %8" PRIu64 "\n", nme.counterPC0); pout("\nNon-medium error count: %8" PRIu64 "\n", nme.counterPC0);
@ -718,7 +723,7 @@ static const char * self_test_result[] = {
static int static int
scsiPrintSelfTest(scsi_device * device) scsiPrintSelfTest(scsi_device * device)
{ {
int num, k, n, res, err, durationSec; int num, k, err, durationSec;
int noheader = 1; int noheader = 1;
int retval = 0; int retval = 0;
UINT8 * ucp; UINT8 * ucp;
@ -736,7 +741,7 @@ scsiPrintSelfTest(scsi_device * device)
if ((err = scsiLogSense(device, SELFTEST_RESULTS_LPAGE, 0, gBuf, if ((err = scsiLogSense(device, SELFTEST_RESULTS_LPAGE, 0, gBuf,
LOG_RESP_SELF_TEST_LEN, 0))) { LOG_RESP_SELF_TEST_LEN, 0))) {
print_on(); print_on();
pout("scsiPrintSelfTest Failed [%s]\n", scsiErrString(err)); pout("%s: Failed [%s]\n", __func__, scsiErrString(err));
print_off(); print_off();
return FAILSMART; return FAILSMART;
} }
@ -760,7 +765,7 @@ scsiPrintSelfTest(scsi_device * device)
int i; int i;
// timestamp in power-on hours (or zero if test in progress) // timestamp in power-on hours (or zero if test in progress)
n = (ucp[6] << 8) | ucp[7]; int n = (ucp[6] << 8) | ucp[7];
// The spec says "all 20 bytes will be zero if no test" but // The spec says "all 20 bytes will be zero if no test" but
// DG has found otherwise. So this is a heuristic. // DG has found otherwise. So this is a heuristic.
@ -783,6 +788,7 @@ scsiPrintSelfTest(scsi_device * device)
// check the self-test result nibble, using the self-test results // check the self-test result nibble, using the self-test results
// field table from T10/1416-D (SPC-3) Rev. 23, section 7.2.10: // field table from T10/1416-D (SPC-3) Rev. 23, section 7.2.10:
int res;
switch ((res = ucp[4] & 0xf)) { switch ((res = ucp[4] & 0xf)) {
case 0x3: case 0x3:
// an unknown error occurred while the device server // an unknown error occurred while the device server
@ -901,7 +907,7 @@ static const char * reassign_status[] = {
static int static int
scsiPrintBackgroundResults(scsi_device * device) scsiPrintBackgroundResults(scsi_device * device)
{ {
int num, j, m, err, pc, pl, truncated; int num, j, m, err, truncated;
int noheader = 1; int noheader = 1;
int firstresult = 1; int firstresult = 1;
int retval = 0; int retval = 0;
@ -910,7 +916,7 @@ scsiPrintBackgroundResults(scsi_device * device)
if ((err = scsiLogSense(device, BACKGROUND_RESULTS_LPAGE, 0, gBuf, if ((err = scsiLogSense(device, BACKGROUND_RESULTS_LPAGE, 0, gBuf,
LOG_RESP_LONG_LEN, 0))) { LOG_RESP_LONG_LEN, 0))) {
print_on(); print_on();
pout("scsiPrintBackgroundResults Failed [%s]\n", scsiErrString(err)); pout("%s Failed [%s]\n", __func__, scsiErrString(err));
print_off(); print_off();
return FAILSMART; return FAILSMART;
} }
@ -935,9 +941,9 @@ scsiPrintBackgroundResults(scsi_device * device)
ucp = gBuf + 4; ucp = gBuf + 4;
num -= 4; num -= 4;
while (num > 3) { while (num > 3) {
pc = (ucp[0] << 8) | ucp[1]; int pc = (ucp[0] << 8) | ucp[1];
// pcb = ucp[2]; // pcb = ucp[2];
pl = ucp[3] + 4; int pl = ucp[3] + 4;
switch (pc) { switch (pc) {
case 0: case 0:
if (noheader) { if (noheader) {
@ -1010,14 +1016,14 @@ scsiPrintBackgroundResults(scsi_device * device)
static int static int
scsiPrintSSMedia(scsi_device * device) scsiPrintSSMedia(scsi_device * device)
{ {
int num, err, pc, pl, truncated; int num, err, truncated;
int retval = 0; int retval = 0;
UINT8 * ucp; UINT8 * ucp;
if ((err = scsiLogSense(device, SS_MEDIA_LPAGE, 0, gBuf, if ((err = scsiLogSense(device, SS_MEDIA_LPAGE, 0, gBuf,
LOG_RESP_LONG_LEN, 0))) { LOG_RESP_LONG_LEN, 0))) {
print_on(); print_on();
pout("scsiPrintSSMedia Failed [%s]\n", scsiErrString(err)); pout("%s: Failed [%s]\n", __func__, scsiErrString(err));
print_off(); print_off();
return FAILSMART; return FAILSMART;
} }
@ -1041,9 +1047,9 @@ scsiPrintSSMedia(scsi_device * device)
ucp = gBuf + 4; ucp = gBuf + 4;
num -= 4; num -= 4;
while (num > 3) { while (num > 3) {
pc = (ucp[0] << 8) | ucp[1]; int pc = (ucp[0] << 8) | ucp[1];
// pcb = ucp[2]; // pcb = ucp[2];
pl = ucp[3] + 4; int pl = ucp[3] + 4;
switch (pc) { switch (pc) {
case 1: case 1:
if (pl < 8) { if (pl < 8) {
@ -1200,7 +1206,6 @@ show_sas_port_param(unsigned char * ucp, int param_len)
int j, m, n, nphys, t, sz, spld_len; int j, m, n, nphys, t, sz, spld_len;
unsigned char * vcp; unsigned char * vcp;
uint64_t ull; uint64_t ull;
unsigned int ui;
char s[64]; char s[64];
sz = sizeof(s); sz = sizeof(s);
@ -1297,6 +1302,7 @@ show_sas_port_param(unsigned char * ucp, int param_len)
} }
pout(" attached SAS address = 0x%" PRIx64 "\n", ull); pout(" attached SAS address = 0x%" PRIx64 "\n", ull);
pout(" attached phy identifier = %d\n", vcp[24]); pout(" attached phy identifier = %d\n", vcp[24]);
unsigned int ui;
ui = (vcp[32] << 24) | (vcp[33] << 16) | (vcp[34] << 8) | vcp[35]; ui = (vcp[32] << 24) | (vcp[33] << 16) | (vcp[34] << 8) | vcp[35];
pout(" Invalid DWORD count = %u\n", ui); pout(" Invalid DWORD count = %u\n", ui);
ui = (vcp[36] << 24) | (vcp[37] << 16) | (vcp[38] << 8) | vcp[39]; ui = (vcp[36] << 24) | (vcp[37] << 16) | (vcp[38] << 8) | vcp[39];
@ -1306,15 +1312,16 @@ show_sas_port_param(unsigned char * ucp, int param_len)
ui = (vcp[44] << 24) | (vcp[45] << 16) | (vcp[46] << 8) | vcp[47]; ui = (vcp[44] << 24) | (vcp[45] << 16) | (vcp[46] << 8) | vcp[47];
pout(" Phy reset problem = %u\n", ui); pout(" Phy reset problem = %u\n", ui);
if (spld_len > 51) { if (spld_len > 51) {
int num_ped, peis; int num_ped;
unsigned char * xcp; unsigned char * xcp;
unsigned int pvdt;
num_ped = vcp[51]; num_ped = vcp[51];
if (num_ped > 0) if (num_ped > 0)
pout(" Phy event descriptors:\n"); pout(" Phy event descriptors:\n");
xcp = vcp + 52; xcp = vcp + 52;
for (m = 0; m < (num_ped * 12); m += 12, xcp += 12) { for (m = 0; m < (num_ped * 12); m += 12, xcp += 12) {
int peis;
unsigned int pvdt;
peis = xcp[3]; peis = xcp[3];
ui = (xcp[4] << 24) | (xcp[5] << 16) | (xcp[6] << 8) | ui = (xcp[4] << 24) | (xcp[5] << 16) | (xcp[6] << 8) |
xcp[7]; xcp[7];
@ -1330,12 +1337,12 @@ show_sas_port_param(unsigned char * ucp, int param_len)
static int static int
show_protocol_specific_page(unsigned char * resp, int len) show_protocol_specific_page(unsigned char * resp, int len)
{ {
int k, num, param_len; int k, num;
unsigned char * ucp; unsigned char * ucp;
num = len - 4; num = len - 4;
for (k = 0, ucp = resp + 4; k < num; ) { for (k = 0, ucp = resp + 4; k < num; ) {
param_len = ucp[3] + 4; int param_len = ucp[3] + 4;
if (6 != (0xf & ucp[4])) if (6 != (0xf & ucp[4]))
return 0; /* only decode SAS log page */ return 0; /* only decode SAS log page */
if (0 == k) if (0 == k)
@ -1359,7 +1366,7 @@ scsiPrintSasPhy(scsi_device * device, int reset)
if ((err = scsiLogSense(device, PROTOCOL_SPECIFIC_LPAGE, 0, gBuf, if ((err = scsiLogSense(device, PROTOCOL_SPECIFIC_LPAGE, 0, gBuf,
LOG_RESP_LONG_LEN, 0))) { LOG_RESP_LONG_LEN, 0))) {
print_on(); print_on();
pout("scsiPrintSasPhy Log Sense Failed [%s]\n\n", scsiErrString(err)); pout("%s Log Sense Failed [%s]\n\n", __func__, scsiErrString(err));
print_off(); print_off();
return FAILSMART; return FAILSMART;
} }
@ -1381,7 +1388,7 @@ scsiPrintSasPhy(scsi_device * device, int reset)
if ((err = scsiLogSelect(device, 1 /* pcr */, 0 /* sp */, 0 /* pc */, if ((err = scsiLogSelect(device, 1 /* pcr */, 0 /* sp */, 0 /* pc */,
PROTOCOL_SPECIFIC_LPAGE, 0, NULL, 0))) { PROTOCOL_SPECIFIC_LPAGE, 0, NULL, 0))) {
print_on(); print_on();
pout("scsiPrintSasPhy Log Select (reset) Failed [%s]\n\n", pout("%s Log Select (reset) Failed [%s]\n\n", __func__,
scsiErrString(err)); scsiErrString(err));
print_off(); print_off();
return FAILSMART; return FAILSMART;
@ -1391,7 +1398,7 @@ scsiPrintSasPhy(scsi_device * device, int reset)
} }
static const char * peripheral_dt_arr[] = { static const char * peripheral_dt_arr[32] = {
"disk", "disk",
"tape", "tape",
"printer", "printer",
@ -1407,23 +1414,23 @@ static const char * peripheral_dt_arr[] = {
"storage array", "storage array",
"enclosure", "enclosure",
"simplified disk", "simplified disk",
"optical card reader" "optical card reader",
"reserved [0x10]" "reserved [0x10]",
"object based storage" "object based storage",
"automation/driver interface" "automation/driver interface",
"security manager device" "security manager device",
"host managed zoned block device" "host managed zoned block device",
"reserved [0x15]" "reserved [0x15]",
"reserved [0x16]" "reserved [0x16]",
"reserved [0x17]" "reserved [0x17]",
"reserved [0x18]" "reserved [0x18]",
"reserved [0x19]" "reserved [0x19]",
"reserved [0x1a]" "reserved [0x1a]",
"reserved [0x1b]" "reserved [0x1b]",
"reserved [0x1c]" "reserved [0x1c]",
"reserved [0x1d]" "reserved [0x1d]",
"well known logical unit" "well known logical unit",
"unknown or no device type" "unknown or no device type",
}; };
static const char * transport_proto_arr[] = { static const char * transport_proto_arr[] = {
@ -1451,10 +1458,9 @@ scsiGetDriveInfo(scsi_device * device, UINT8 * peripheral_type, bool all)
{ {
char timedatetz[DATEANDEPOCHLEN]; char timedatetz[DATEANDEPOCHLEN];
struct scsi_iec_mode_page iec; struct scsi_iec_mode_page iec;
int err, iec_err, len, req_len, avail_len, n, scsi_version; int err, iec_err, len, req_len, avail_len, scsi_version;
int is_tape = 0; bool is_tape = false;
int peri_dt = 0; int peri_dt = 0;
int returnval = 0;
int transport = -1; int transport = -1;
int form_factor = 0; int form_factor = 0;
int haw_zbc = 0; int haw_zbc = 0;
@ -1480,8 +1486,10 @@ scsiGetDriveInfo(scsi_device * device, UINT8 * peripheral_type, bool all)
avail_len = gBuf[4] + 5; avail_len = gBuf[4] + 5;
len = (avail_len < req_len) ? avail_len : req_len; len = (avail_len < req_len) ? avail_len : req_len;
peri_dt = gBuf[0] & 0x1f; peri_dt = gBuf[0] & 0x1f;
if (peripheral_type)
*peripheral_type = peri_dt; *peripheral_type = peri_dt;
if ((SCSI_PT_SEQUENTIAL_ACCESS == peri_dt) ||
(SCSI_PT_MEDIUM_CHANGER == peri_dt))
is_tape = true;
if (len < 36) { if (len < 36) {
print_on(); print_on();
@ -1521,16 +1529,15 @@ scsiGetDriveInfo(scsi_device * device, UINT8 * peripheral_type, bool all)
protect = gBuf[5] & 0x1; /* from and including SPC-3 */ protect = gBuf[5] & 0x1; /* from and including SPC-3 */
if (! is_tape) { /* only do this for disks */ if (! is_tape) { /* assume disk if not tape drive (or tape changer) */
unsigned int lb_size = 0; unsigned int lb_size = 0;
unsigned char lb_prov_resp[8]; unsigned char lb_prov_resp[8];
char cap_str[64];
char si_str[64];
char lb_str[16]; char lb_str[16];
int lb_per_pb_exp = 0; int lb_per_pb_exp = 0;
uint64_t capacity = scsiGetSize(device, &lb_size, &lb_per_pb_exp); uint64_t capacity = scsiGetSize(device, &lb_size, &lb_per_pb_exp);
if (capacity) { if (capacity) {
char cap_str[64], si_str[64];
format_with_thousands_sep(cap_str, sizeof(cap_str), capacity); format_with_thousands_sep(cap_str, sizeof(cap_str), capacity);
format_capacity(si_str, sizeof(si_str), capacity); format_capacity(si_str, sizeof(si_str), capacity);
pout("User Capacity: %s bytes [%s]\n", cap_str, si_str); pout("User Capacity: %s bytes [%s]\n", cap_str, si_str);
@ -1548,7 +1555,7 @@ scsiGetDriveInfo(scsi_device * device, UINT8 * peripheral_type, bool all)
snprintf(lb_str, sizeof(lb_str) - 1, "%u", snprintf(lb_str, sizeof(lb_str) - 1, "%u",
(lb_size * (1 << lb_per_pb_exp))); (lb_size * (1 << lb_per_pb_exp)));
pout("Physical block size: %s bytes\n", lb_str); pout("Physical block size: %s bytes\n", lb_str);
n = ((rc16_12[2] & 0x3f) << 8) + rc16_12[3]; int n = ((rc16_12[2] & 0x3f) << 8) + rc16_12[3];
if (n > 0) // not common so cut the clutter if (n > 0) // not common so cut the clutter
pout("Lowest aligned LBA: %d\n", n); pout("Lowest aligned LBA: %d\n", n);
} }
@ -1581,16 +1588,31 @@ scsiGetDriveInfo(scsi_device * device, UINT8 * peripheral_type, bool all)
lbprz = !! (rc16_12[2] & 0x40); lbprz = !! (rc16_12[2] & 0x40);
} }
} }
/* Thin Provisioning VPD page renamed Logical Block Provisioning VPD
* page in sbc3r25; some fields changed their meaning so that the
* new page covered both thin and resource provisioned LUs. */
if (0 == scsiInquiryVpd(device, SCSI_VPD_LOGICAL_BLOCK_PROVISIONING, if (0 == scsiInquiryVpd(device, SCSI_VPD_LOGICAL_BLOCK_PROVISIONING,
lb_prov_resp, sizeof(lb_prov_resp))) { lb_prov_resp, sizeof(lb_prov_resp))) {
int prov_type = lb_prov_resp[6] & 0x7; int prov_type = lb_prov_resp[6] & 0x7; /* added sbc3r27 */
int vpd_lbprz = ((lb_prov_resp[5] >> 2) & 0x7); /* sbc4r07 */
if (-1 == lbprz) if (-1 == lbprz)
lbprz = !! (lb_prov_resp[5] & 0x4); lbprz = vpd_lbprz;
else if ((0 == vpd_lbprz) && (1 == lbprz))
; /* vpd_lbprz introduced in sbc3r27, expanded in sbc4r07 */
else
lbprz = vpd_lbprz;
switch (prov_type) { switch (prov_type) {
case 0: case 0:
pout("LB provisioning type: unreported, LBPME=%d, LBPRZ=%d\n", if (lbpme <= 0) {
lbpme, lbprz); pout("LU is fully provisioned");
if (lbprz)
pout(" [LBPRZ=%d]\n", lbprz);
else
pout("\n");
} else
pout("LB provisioning type: not reported [LBPME=1, "
"LBPRZ=%d]\n", lbprz);
break; break;
case 1: case 1:
pout("LU is resource provisioned, LBPRZ=%d\n", lbprz); pout("LU is resource provisioned, LBPRZ=%d\n", lbprz);
@ -1603,8 +1625,11 @@ scsiGetDriveInfo(scsi_device * device, UINT8 * peripheral_type, bool all)
prov_type, lbprz); prov_type, lbprz);
break; break;
} }
} else if (1 == lbpme) } else if (1 == lbpme) {
if (scsi_debugmode > 0)
pout("rcap_16 sets LBPME but no LB provisioning VPD page\n");
pout("Logical block provisioning enabled, LBPRZ=%d\n", lbprz); pout("Logical block provisioning enabled, LBPRZ=%d\n", lbprz);
}
int rpm = scsiGetRPM(device, modese_len, &form_factor, &haw_zbc); int rpm = scsiGetRPM(device, modese_len, &form_factor, &haw_zbc);
if (rpm >= 0) { if (rpm >= 0) {
@ -1709,9 +1734,6 @@ scsiGetDriveInfo(scsi_device * device, UINT8 * peripheral_type, bool all)
dateandtimezone(timedatetz); dateandtimezone(timedatetz);
pout("Local Time is: %s\n", timedatetz); pout("Local Time is: %s\n", timedatetz);
if ((SCSI_PT_SEQUENTIAL_ACCESS == *peripheral_type) ||
(SCSI_PT_MEDIUM_CHANGER == *peripheral_type))
is_tape = 1;
// See if unit accepts SCSI commmands from us // See if unit accepts SCSI commmands from us
if ((err = scsiTestUnitReady(device))) { if ((err = scsiTestUnitReady(device))) {
if (SIMPLE_ERR_NOT_READY == err) { if (SIMPLE_ERR_NOT_READY == err) {
@ -1723,7 +1745,10 @@ scsiGetDriveInfo(scsi_device * device, UINT8 * peripheral_type, bool all)
print_off(); print_off();
} else if (SIMPLE_ERR_NO_MEDIUM == err) { } else if (SIMPLE_ERR_NO_MEDIUM == err) {
print_on(); print_on();
pout("NO MEDIUM present on device\n"); if (is_tape)
pout("NO tape present in drive\n");
else
pout("NO MEDIUM present in device\n");
print_off(); print_off();
} else if (SIMPLE_ERR_BECOMING_READY == err) { } else if (SIMPLE_ERR_BECOMING_READY == err) {
print_on(); print_on();
@ -1734,8 +1759,12 @@ scsiGetDriveInfo(scsi_device * device, UINT8 * peripheral_type, bool all)
pout("device Test Unit Ready [%s]\n", scsiErrString(err)); pout("device Test Unit Ready [%s]\n", scsiErrString(err));
print_off(); print_off();
} }
if (! is_tape) {
int returnval = 0; // TODO: exit with FAILID if failuretest returns
failuretest(MANDATORY_CMD, returnval|=FAILID); failuretest(MANDATORY_CMD, returnval|=FAILID);
} }
}
if (iec_err) { if (iec_err) {
if (!is_tape) { if (!is_tape) {
@ -1836,21 +1865,20 @@ scsiSmartDisable(scsi_device * device)
static void static void
scsiPrintTemp(scsi_device * device) scsiPrintTemp(scsi_device * device)
{ {
UINT8 temp = 0; UINT8 temp = 255;
UINT8 trip = 0; UINT8 trip = 255;
if (scsiGetTemp(device, &temp, &trip)) if (scsiGetTemp(device, &temp, &trip))
return; return;
if (temp) { if (255 == temp)
if (255 != temp)
pout("Current Drive Temperature: %d C\n", temp);
else
pout("Current Drive Temperature: <not available>\n"); pout("Current Drive Temperature: <not available>\n");
} else
if (trip) pout("Current Drive Temperature: %d C\n", temp);
if (255 == trip)
pout("Drive Trip Temperature: <not available>\n");
else
pout("Drive Trip Temperature: %d C\n", trip); pout("Drive Trip Temperature: %d C\n", trip);
if (temp || trip)
pout("\n"); pout("\n");
} }
@ -1863,6 +1891,8 @@ scsiPrintMain(scsi_device * device, const scsi_print_options & options)
int returnval = 0; int returnval = 0;
int res, durationSec; int res, durationSec;
struct scsi_sense_disect sense_info; struct scsi_sense_disect sense_info;
bool is_disk;
bool is_tape;
bool any_output = options.drive_info; bool any_output = options.drive_info;
@ -1880,34 +1910,33 @@ scsiPrintMain(scsi_device * device, const scsi_print_options & options)
failuretest(MANDATORY_CMD, returnval |= FAILID); failuretest(MANDATORY_CMD, returnval |= FAILID);
any_output = true; any_output = true;
} }
is_disk = (SCSI_PT_DIRECT_ACCESS == peripheral_type);
is_tape = ((SCSI_PT_SEQUENTIAL_ACCESS == peripheral_type) ||
(SCSI_PT_MEDIUM_CHANGER == peripheral_type));
// Print read look-ahead status for disks
short int wce = -1, rcd = -1; short int wce = -1, rcd = -1;
// Print read look-ahead status for disks
if (options.get_rcd || options.get_wce) { if (options.get_rcd || options.get_wce) {
if (SCSI_PT_DIRECT_ACCESS == peripheral_type) if (is_disk) {
res = scsiGetSetCache(device, modese_len, &wce, &rcd); res = scsiGetSetCache(device, modese_len, &wce, &rcd);
else if (options.get_rcd)
res = -1; // fetch for disks only
any_output = true;
}
if (options.get_rcd) {
pout("Read Cache is: %s\n", pout("Read Cache is: %s\n",
res ? "Unavailable" : // error res ? "Unavailable" : // error
rcd ? "Disabled" : "Enabled"); rcd ? "Disabled" : "Enabled");
} if (options.get_wce)
if (options.get_wce) {
pout("Writeback Cache is: %s\n", pout("Writeback Cache is: %s\n",
res ? "Unavailable" : // error res ? "Unavailable" : // error
!wce ? "Disabled" : "Enabled"); !wce ? "Disabled" : "Enabled");
} }
} else
any_output = true;
if (options.drive_info) if (options.drive_info)
pout("\n"); pout("\n");
// START OF THE ENABLE/DISABLE SECTION OF THE CODE // START OF THE ENABLE/DISABLE SECTION OF THE CODE
if ( options.smart_disable || options.smart_enable if (options.smart_disable || options.smart_enable ||
|| options.smart_auto_save_disable || options.smart_auto_save_enable) options.smart_auto_save_disable || options.smart_auto_save_enable)
pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n"); pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n");
if (options.smart_enable) { if (options.smart_enable) {
@ -1926,38 +1955,36 @@ scsiPrintMain(scsi_device * device, const scsi_print_options & options)
if (scsiSetControlGLTSD(device, 0, modese_len)) { if (scsiSetControlGLTSD(device, 0, modese_len)) {
pout("Enable autosave (clear GLTSD bit) failed\n"); pout("Enable autosave (clear GLTSD bit) failed\n");
failuretest(OPTIONAL_CMD,returnval |= FAILSMART); failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
} } else
else { pout("Autosave enabled (GLTSD bit cleared).\n");
pout("Autosave enabled (GLTSD bit set).\n");
}
any_output = true; any_output = true;
} }
// Enable/Disable write cache // Enable/Disable write cache
if (options.set_wce && SCSI_PT_DIRECT_ACCESS == peripheral_type) { if (options.set_wce && is_disk) {
short int enable = wce = (options.set_wce > 0); short int enable = wce = (options.set_wce > 0);
rcd = -1; rcd = -1;
if (scsiGetSetCache(device, modese_len, &wce, &rcd)) { if (scsiGetSetCache(device, modese_len, &wce, &rcd)) {
pout("Write cache %sable failed: %s\n", (enable ? "en" : "dis"), pout("Write cache %sable failed: %s\n", (enable ? "en" : "dis"),
device->get_errmsg()); device->get_errmsg());
failuretest(OPTIONAL_CMD,returnval |= FAILSMART); failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
} } else
else
pout("Write cache %sabled\n", (enable ? "en" : "dis")); pout("Write cache %sabled\n", (enable ? "en" : "dis"));
any_output = true; any_output = true;
} }
// Enable/Disable read cache // Enable/Disable read cache
if (options.set_rcd && SCSI_PT_DIRECT_ACCESS == peripheral_type) { if (options.set_rcd && is_disk) {
short int enable = (options.set_rcd > 0); short int enable = (options.set_rcd > 0);
rcd = !enable; rcd = !enable;
wce = -1; wce = -1;
if (scsiGetSetCache(device, modese_len, &wce, &rcd)) { if (scsiGetSetCache(device, modese_len, &wce, &rcd)) {
pout("Read cache %sable failed: %s\n", (enable ? "en" : "dis"), pout("Read cache %sable failed: %s\n", (enable ? "en" : "dis"),
device->get_errmsg()); device->get_errmsg());
failuretest(OPTIONAL_CMD,returnval |= FAILSMART); failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
} } else
else
pout("Read cache %sabled\n", (enable ? "en" : "dis")); pout("Read cache %sabled\n", (enable ? "en" : "dis"));
any_output = true; any_output = true;
} }
@ -1966,29 +1993,25 @@ scsiPrintMain(scsi_device * device, const scsi_print_options & options)
if (scsiSetControlGLTSD(device, 1, modese_len)) { if (scsiSetControlGLTSD(device, 1, modese_len)) {
pout("Disable autosave (set GLTSD bit) failed\n"); pout("Disable autosave (set GLTSD bit) failed\n");
failuretest(OPTIONAL_CMD,returnval |= FAILSMART); failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
} } else
else { pout("Autosave disabled (GLTSD bit set).\n");
pout("Autosave disabled (GLTSD bit cleared).\n");
}
any_output = true; any_output = true;
} }
if ( options.smart_disable || options.smart_enable if (options.smart_disable || options.smart_enable ||
|| options.smart_auto_save_disable || options.smart_auto_save_enable) options.smart_auto_save_disable || options.smart_auto_save_enable)
pout("\n"); // END OF THE ENABLE/DISABLE SECTION OF THE CODE pout("\n"); // END OF THE ENABLE/DISABLE SECTION OF THE CODE
// START OF READ-ONLY OPTIONS APART FROM -V and -i // START OF READ-ONLY OPTIONS APART FROM -V and -i
if ( options.smart_check_status || options.smart_ss_media_log if (options.smart_check_status || options.smart_ss_media_log ||
|| options.smart_vendor_attrib || options.smart_error_log options.smart_vendor_attrib || options.smart_error_log ||
|| options.smart_selftest_log || options.smart_vendor_attrib options.smart_selftest_log || options.smart_background_log ||
|| options.smart_background_log || options.sasphy options.sasphy)
)
pout("=== START OF READ SMART DATA SECTION ===\n"); pout("=== START OF READ SMART DATA SECTION ===\n");
if (options.smart_check_status) { if (options.smart_check_status) {
scsiGetSupportedLogPages(device); scsiGetSupportedLogPages(device);
checkedSupportedLogPages = 1; checkedSupportedLogPages = 1;
if ((SCSI_PT_SEQUENTIAL_ACCESS == peripheral_type) || if (is_tape) {
(SCSI_PT_MEDIUM_CHANGER == peripheral_type)) { /* tape device */
if (gTapeAlertsLPage) { if (gTapeAlertsLPage) {
if (options.drive_info) if (options.drive_info)
pout("TapeAlert Supported\n"); pout("TapeAlert Supported\n");
@ -2008,7 +2031,7 @@ scsiPrintMain(scsi_device * device, const scsi_print_options & options)
any_output = true; any_output = true;
} }
if (options.smart_ss_media_log) { if (is_disk && options.smart_ss_media_log) {
if (! checkedSupportedLogPages) if (! checkedSupportedLogPages)
scsiGetSupportedLogPages(device); scsiGetSupportedLogPages(device);
res = 0; res = 0;
@ -2021,12 +2044,11 @@ scsiPrintMain(scsi_device * device, const scsi_print_options & options)
if (options.smart_vendor_attrib) { if (options.smart_vendor_attrib) {
if (! checkedSupportedLogPages) if (! checkedSupportedLogPages)
scsiGetSupportedLogPages(device); scsiGetSupportedLogPages(device);
if (gTempLPage) { if (gTempLPage)
scsiPrintTemp(device); scsiPrintTemp(device);
}
if (gStartStopLPage) if (gStartStopLPage)
scsiGetStartStopData(device); scsiGetStartStopData(device);
if (SCSI_PT_DIRECT_ACCESS == peripheral_type) { if (is_disk) {
scsiPrintGrownDefectListLen(device); scsiPrintGrownDefectListLen(device);
if (gSeagateCacheLPage) if (gSeagateCacheLPage)
scsiPrintSeagateCacheLPage(device); scsiPrintSeagateCacheLPage(device);
@ -2058,7 +2080,7 @@ scsiPrintMain(scsi_device * device, const scsi_print_options & options)
failuretest(OPTIONAL_CMD, returnval|=res); failuretest(OPTIONAL_CMD, returnval|=res);
any_output = true; any_output = true;
} }
if (options.smart_background_log) { if (options.smart_background_log && is_disk) {
if (! checkedSupportedLogPages) if (! checkedSupportedLogPages)
scsiGetSupportedLogPages(device); scsiGetSupportedLogPages(device);
res = 0; res = 0;
@ -2090,15 +2112,13 @@ scsiPrintMain(scsi_device * device, const scsi_print_options & options)
(sense_info.asc == 0x04 && sense_info.ascq == 0x09)) { (sense_info.asc == 0x04 && sense_info.ascq == 0x09)) {
if (!options.smart_selftest_force) { if (!options.smart_selftest_force) {
pout("Can't start self-test without aborting current test"); pout("Can't start self-test without aborting current test");
if (sense_info.progress != -1) { if (sense_info.progress != -1)
pout(" (%d%% remaining)", pout(" (%d%% remaining)",
100 - sense_info.progress * 100 / 65535); 100 - sense_info.progress * 100 / 65535);
} pout(",\nadd '-t force' option to override, or run "
pout(",\nadd '-t force' option to override, or run 'smartctl -X' " "'smartctl -X' to abort test.\n");
"to abort test.\n");
return -1; return -1;
} } else
else
scsiSmartSelfTestAbort(device); scsiSmartSelfTestAbort(device);
} }
} }
@ -2143,8 +2163,8 @@ scsiPrintMain(scsi_device * device, const scsi_print_options & options)
} }
if (!any_output) if (!any_output)
pout("SCSI device successfully opened\n\n" pout("SCSI device successfully opened\n\nUse 'smartctl -a' (or '-x') "
"Use 'smartctl -a' (or '-x') to print SMART (and more) information\n\n"); "to print SMART (and more) information\n\n");
return returnval; return returnval;
} }

View File

@ -1,7 +1,7 @@
/* /*
* scsiprint.h * scsiprint.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2002-9 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2002-9 Bruce Allen <smartmontools-support@lists.sourceforge.net>
* Copyright (C) 2000 Michael Cornwell <cornwell@acm.org> * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
@ -29,7 +29,7 @@
#ifndef SCSI_PRINT_H_ #ifndef SCSI_PRINT_H_
#define SCSI_PRINT_H_ #define SCSI_PRINT_H_
#define SCSIPRINT_H_CVSID "$Id: scsiprint.h 3776 2013-02-17 04:25:42Z dpgilbert $\n" #define SCSIPRINT_H_CVSID "$Id: scsiprint.h 4120 2015-08-27 16:12:21Z samm2 $\n"
// Options for scsiPrintMain // Options for scsiPrintMain
struct scsi_print_options struct scsi_print_options

View File

@ -1,8 +1,8 @@
.ig .ig
Copyright (C) 2002-10 Bruce Allen <smartmontools-support@lists.sourceforge.net> Copyright (C) 2002-10 Bruce Allen
Copyright (C) 2004-14 Christian Franke <smartmontools-support@lists.sourceforge.net> Copyright (C) 2004-16 Christian Franke
$Id: smartctl.8.in 3965 2014-07-20 14:46:41Z chrfranke $ $Id: smartctl.8.in 4311 2016-04-27 21:03:01Z chrfranke $
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -18,16 +18,13 @@ Research Center), Jack Baskin School of Engineering, University of
California, Santa Cruz. http://ssrc.soe.ucsc.edu/ California, Santa Cruz. http://ssrc.soe.ucsc.edu/
.. ..
.TH SMARTCTL 8 CURRENT_SVN_DATE CURRENT_SVN_VERSION CURRENT_SVN_DATE .TH SMARTCTL 8 "CURRENT_SVN_DATE" "CURRENT_SVN_VERSION" "SMART Monitoring Tools"
.SH NAME .SH NAME
\fBsmartctl\fP \- Control and Monitor Utility for SMART Disks \fBsmartctl\fP \- Control and Monitor Utility for SMART Disks
.SH SYNOPSIS .SH SYNOPSIS
.B smartctl [options] device .B smartctl [options] device
.SH PACKAGE VERSION
CURRENT_SVN_VERSION CURRENT_SVN_DATE CURRENT_SVN_REV
.SH DESCRIPTION .SH DESCRIPTION
.\" %IF NOT OS ALL .\" %IF NOT OS ALL
.\"! [This man page is generated for the OS_MAN_FILTER version of smartmontools. .\"! [This man page is generated for the OS_MAN_FILTER version of smartmontools.
@ -55,11 +52,9 @@ option (for more information see the section on "ATA, SCSI command sets
and SAT" below). Device paths are as follows: and SAT" below). Device paths are as follows:
.\" %IF OS Linux .\" %IF OS Linux
.IP \fBLINUX\fP: 9 .IP \fBLINUX\fP: 9
Use the forms \fB"/dev/hd[a\-t]"\fP for IDE/ATA devices, and Use the forms \fB"/dev/sd[a\-z]"\fP for ATA/SATA and SCSI/SAS devices.
\fB"/dev/sd[a\-z]"\fP for SCSI devices. For SCSI Tape Drives and For SCSI Tape Drives and Changers with TapeAlert support use the
Changers with TapeAlert support use the devices \fB"/dev/nst*"\fP and devices \fB"/dev/nst*"\fP and \fB"/dev/sg*"\fP. For disks behind
\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 3ware controllers you may need \fB"/dev/sd[a\-z]"\fP or
\fB"/dev/twe[0\-9]"\fP, \fB"/dev/twa[0\-9]"\fP or \fB"/dev/twl[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 below. For disks behind HighPoint RocketRAID controllers you may need
@ -74,6 +69,8 @@ the hpahcisr and hpsa drivers, the device nodes you need are \fB"/dev/sg[0\-9]*"
("lsscsi \-g" is helpful in determining which scsi generic device node corresponds ("lsscsi \-g" is helpful in determining which scsi generic device node corresponds
to which device.) Use the nodes corresponding to the RAID controllers, to which device.) Use the nodes corresponding to the RAID controllers,
not the nodes corresponding to logical drives. See the \fB\-d\fP option below, as well. not the nodes corresponding to logical drives. See the \fB\-d\fP option below, as well.
Use the forms \fB"/dev/nvme[0\-9]"\fP (broadcast namespace) or
\fB"/dev/nvme[0\-9]n[1\-9]"\fP (specific namespace 1\-9) for NVMe devices.
.\" %ENDIF OS Linux .\" %ENDIF OS Linux
.\" %IF OS Darwin .\" %IF OS Darwin
.IP \fBDARWIN\fP: 9 .IP \fBDARWIN\fP: 9
@ -135,8 +132,15 @@ For disks behind an Intel ICHxR controller with RST driver use
\fB"/dev/csmi[0\-9],N"\fP where N specifies the port behind the logical \fB"/dev/csmi[0\-9],N"\fP where N specifies the port behind the logical
scsi controller "\\\\.\\Scsi[0\-9]:". scsi controller "\\\\.\\Scsi[0\-9]:".
[NEW EXPERIMENTAL SMARTCTL FEATURE] For SATA or SAS disks behind an Areca For SATA or SAS disks behind an Areca controller use
controller use \fB"/dev/arcmsr[0\-9]"\fP, see \'\-d areca,N[/E]\' below. \fB"/dev/arcmsr[0\-9]"\fP, see \'\-d areca,N[/E]\' below.
[NEW EXPERIMENTAL SMARTCTL FEATURE]
Use the forms \fB"/dev/nvme[0\-9]"\fP (broadcast namespace) or
\fB"/dev/nvme[0\-9]n[1\-9]"\fP (specific namespace 1\-9) for first,
second, ..., NVMe device.
Alternatively use the forms \fB"/dev/nvmes[0\-9][n[1\-9]]"\fP for NVMe devices
behind the logical scsi controller "\\\\.\\Scsi[0\-9]:".
The prefix \fB"/dev/"\fP is optional. The prefix \fB"/dev/"\fP is optional.
.\" %ENDIF OS Windows Cygwin .\" %ENDIF OS Windows Cygwin
@ -186,6 +190,13 @@ than the potential maximum drive capacity.) Indicates if the drive is
in the smartmontools database (see \'\-v\' options below). If so, the in the smartmontools database (see \'\-v\' options below). If so, the
drive model family may also be printed. If \'\-n\' (see below) is drive model family may also be printed. If \'\-n\' (see below) is
specified, the power mode of the drive is printed. specified, the power mode of the drive is printed.
.\" %IF OS FreeBSD Linux Windows Cygwin
[NVMe] [FreeBSD, Linux, Windows and Cygwin only]
[NEW EXPERIMENTAL SMARTCTL FEATURE]
For NVMe devices the information is obtained from the Identify Controller
and the Identify Namespace data structure.
.\" %ENDIF OS FreeBSD Linux Windows Cygwin
.TP .TP
.B \-\-identify[=[w][nvb]] .B \-\-identify[=[w][nvb]]
[ATA only] Prints an annotated table of the IDENTIFY DEVICE data. [ATA only] Prints an annotated table of the IDENTIFY DEVICE data.
@ -211,6 +222,12 @@ and for SCSI, this is equivalent to
.nf .nf
\'\-H \-i \-A \-l error \-l selftest\'. \'\-H \-i \-A \-l error \-l selftest\'.
.fi .fi
.\" %IF OS FreeBSD Linux Windows Cygwin
For NVMe, this is equivalent to
.nf
\'\-H \-i \-c \-A \-l error'.
.fi
.\" %ENDIF OS FreeBSD Linux Windows Cygwin
Note that for ATA disks this does \fBnot\fP enable the non-SMART options Note that for ATA disks this does \fBnot\fP enable the non-SMART options
and the SMART options which require support for 48-bit ATA commands. and the SMART options which require support for 48-bit ATA commands.
.TP .TP
@ -225,6 +242,12 @@ and for SCSI, this is equivalent to
.nf .nf
\'\-H \-i \-A \-l error \-l selftest \-l background \-l sasphy\'. \'\-H \-i \-A \-l error \-l selftest \-l background \-l sasphy\'.
.fi .fi
.\" %IF OS FreeBSD Linux Windows Cygwin
For NVMe, this is equivalent to
.nf
\'\-H \-i \-c \-A \-l error'.
.fi
.\" %ENDIF OS FreeBSD Linux Windows Cygwin
.TP .TP
.B \-\-scan .B \-\-scan
Scans for devices and prints each device name, device type and protocol Scans for devices and prints each device name, device type and protocol
@ -244,6 +267,10 @@ For example:
.nf .nf
smartctl \-\-scan\-open \-\- \-a \-W 4,45,50 \-m admin@work > smartd.conf smartctl \-\-scan\-open \-\- \-a \-W 4,45,50 \-m admin@work > smartd.conf
.fi .fi
[NEW EXPERIMENTAL SMARTCTL FEATURE]
Multiple \'\-d TYPE\' options may be specified with \'\-\-scan[\-open]\'
to combine the scan results of more than one TYPE.
.TP .TP
.B \-g NAME, \-\-get=NAME .B \-g NAME, \-\-get=NAME
Get non-SMART device settings. See \'\-s, \-\-set\' below for further info. Get non-SMART device settings. See \'\-s, \-\-set\' below for further info.
@ -266,7 +293,7 @@ which failed either now or in the past.
.I silent .I silent
\- print no output. The only way to learn about what was found is to \- print no output. The only way to learn about what was found is to
use the exit status of \fBsmartctl\fP (see RETURN VALUES below). use the exit status of \fBsmartctl\fP (see EXIT STATUS below).
.I noserial .I noserial
\- Do not print the serial number of the device. \- Do not print the serial number of the device.
@ -297,6 +324,19 @@ from issuing SCSI commands to an ATA device.
\fBsmartctl\fP \fBsmartctl\fP
from issuing ATA commands to a SCSI device. from issuing ATA commands to a SCSI device.
.\" %ENDIF NOT OS Darwin
.\" %IF OS FreeBSD Linux Windows Cygwin
.I nvme[,NSID]
\- [FreeBSD, Linux, Windows and Cygwin only]
[NEW EXPERIMENTAL SMARTCTL FEATURE]
the device type is NVM Express (NVMe).
The optional parameter NSID specifies the namespace id (in hex) passed
to the driver.
Use 0xffffffff for the broadcast namespace id.
The default for NSID is the namespace id addressed by the device name.
.\" %ENDIF OS FreeBSD Linux Windows Cygwin
.\" %IF NOT OS Darwin
.I sat[,auto][,N] .I sat[,auto][,N]
\- the device type is SCSI to ATA Translation (SAT). \- the device type is SCSI to ATA Translation (SAT).
This is for ATA disks that have a SCSI to ATA Translation (SAT) Layer This is for ATA disks that have a SCSI to ATA Translation (SAT) Layer
@ -331,13 +371,17 @@ 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 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. PORT does not exist or is not connected to a disk.
[NEW EXPERIMENTAL SMARTCTL FEATURE]
The Prolific PL2507/3507 USB bridges with older firmware support a pass-through The Prolific PL2507/3507 USB bridges with older firmware support a pass-through
command similar to JMicron and work with \'\-d usbjmicron,0\'. command similar to JMicron and work with \'\-d usbjmicron,0\'.
Newer Prolific firmware requires a modified command which can be selected by Newer Prolific firmware requires a modified command which can be selected by
\'\-d usbjmicron,p\'. \'\-d usbjmicron,p\'.
Note that this does not yet support the SMART status command. Note that this does not yet support the SMART status command.
.I usbprolific
\- [NEW EXPERIMENTAL SMARTCTL FEATURE]
this device type is for SATA disks that are behind a Prolific PL2571/2771/2773/2775
USB to SATA bridge.
.I usbsunplus .I usbsunplus
\- this device type is for SATA disks that are behind a SunplusIT USB to SATA \- this device type is for SATA disks that are behind a SunplusIT USB to SATA
bridge. bridge.
@ -372,24 +416,32 @@ For PERC2/3/4 controllers: \fBmegadevN\fP
.br .br
For PERC5/6 controllers: \fBmegaraid_sas_ioctlN\fP For PERC5/6 controllers: \fBmegaraid_sas_ioctlN\fP
.\" %ENDIF OS Linux
.\" %IF OS Linux Windows Cygwin
.I aacraid,H,L,ID .I aacraid,H,L,ID
\- [Linux only] [NEW EXPERIMENTAL SMARTCTL FEATURE] \- [Linux, Windows and Cygwin only] [NEW EXPERIMENTAL SMARTCTL FEATURE]
the device consists of one or more SCSI/SAS disks connected to an AacRaid controller. the device consists of one or more SCSI/SAS disks connected to an AacRaid controller.
The non-negative integers H,L,ID (Host number, Lun, ID) denote which disk The non-negative integers H,L,ID (Host number, Lun, ID) denote which disk
on the controller is monitored. on the controller is monitored.
Use syntax such as: Use syntax such as:
.nf .nf
\fBsmartctl \-a \-d aacraid,0,0,66 /dev/sda\fP \fBsmartctl \-a \-d aacraid,0,0,2 /dev/sda\fP
.fi .fi
.nf .nf
\fBsmartctl \-a \-d aacraid,0,0,66 /dev/sdb\fP \fBsmartctl \-a \-d aacraid,1,0,4 /dev/sdb\fP
.fi .fi
The L and ID numbers of a disk can be found in /proc/scsi/scsi
The following entry in /proc/devices must exist: \fBaac\fP. .\" %ENDIF OS Linux Windows Cygwin
.\" %IF OS Linux
On Linux, the following entry in /proc/devices must exist: \fBaac\fP.
Character device nodes /dev/aacH (H=Host number) are created if required. Character device nodes /dev/aacH (H=Host number) are created if required.
.\" %ENDIF OS Linux .\" %ENDIF OS Linux
.\" %IF OS Windows Cygwin
On Windows, the device name parameter /dev/sdX is ignored if \'-d aacraid\'
is specified.
.\" %ENDIF OS Windows Cygwin
.\" %IF OS FreeBSD Linux .\" %IF OS FreeBSD Linux
.I 3ware,N .I 3ware,N
\- [FreeBSD and Linux only] the device consists of one or more ATA disks \- [FreeBSD and Linux only] the device consists of one or more ATA disks
@ -495,7 +547,7 @@ On FreeBSD use syntax such as:
.fi .fi
.\" %ENDIF OS FreeBSD .\" %ENDIF OS FreeBSD
.\" %IF OS Windows Cygwin .\" %IF OS Windows Cygwin
[NEW EXPERIMENTAL SMARTCTL FEATURE] On Windows and Cygwin use syntax such as: On Windows and Cygwin use syntax such as:
.nf .nf
\fBsmartctl \-a \-d areca,2 /dev/arcmsr0\fP \fBsmartctl \-a \-d areca,2 /dev/arcmsr0\fP
.fi .fi
@ -526,8 +578,8 @@ later. Lower-numbered firmware versions will give (harmless) SCSI
error messages and no SMART information. error messages and no SMART information.
.I areca,N/E .I areca,N/E
\- [FreeBSD, Linux, Windows and Cygwin only] [NEW EXPERIMENTAL SMARTCTL FEATURE] the \- [FreeBSD, Linux, Windows and Cygwin only] the device consists of one
device consists of one or more SATA or SAS disks connected to an Areca SAS RAID controller. or more SATA or SAS disks connected to an Areca SAS RAID controller.
The integer N (range 1 to 128) denotes the channel (slot) and E (range The integer N (range 1 to 128) denotes the channel (slot) and E (range
1 to 8) denotes the enclosure. 1 to 8) denotes the enclosure.
Important: This requires Areca SAS controller firmware version 1.51 or later. Important: This requires Areca SAS controller firmware version 1.51 or later.
@ -670,6 +722,13 @@ shows the SCSI commands in hex and the corresponding status. Invoking
it a second time adds a hex listing of the first 64 bytes of data send to, it a second time adds a hex listing of the first 64 bytes of data send to,
or received from the device. or received from the device.
.\" %IF OS FreeBSD Linux Windows Cygwin
.I nvmeioctl
\- [FreeBSD, Linux, Windows and Cygwin only]
[NEW EXPERIMENTAL SMARTCTL FEATURE]
report only ioctl() transactions with NVMe devices.
.\" %ENDIF OS FreeBSD Linux Windows Cygwin
Any argument may include a positive integer to specify the level of detail Any argument may include a positive integer to specify the level of detail
that should be reported. The argument should be followed by a comma then that should be reported. The argument should be followed by a comma then
the integer with no spaces. For example, the integer with no spaces. For example,
@ -689,7 +748,7 @@ behaviour. This is does not work for SCSI devices yet.
checks when the device is in a low-power mode. It may be used to prevent 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 a disk from being spun-up by \fBsmartctl\fP. The power mode is ignored by
default. A nonzero exit status is returned if the device is in one of the default. A nonzero exit status is returned if the device is in one of the
specified low-power modes (see RETURN VALUES below). specified low-power modes (see EXIT STATUS below).
Note: If this option is used it may also be necessary to specify the device 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 type with the \'\-d\' option. Otherwise the device may spin up due to
@ -885,13 +944,11 @@ the drive. The setting of the standby timer is not affected.
The write cache is usually enabled by default. The write cache is usually enabled by default.
.I wcache[,on|off] .I wcache[,on|off]
\- [SCSI] [NEW EXPERIMENTAL SMARTCTL FEATURE] \- [SCSI] Gets/sets the \'Write Cache Enable\' (WCE) bit (if supported).
Gets/sets the \'Write Cache Enable\' (WCE) bit (if supported).
The write cache is usually enabled by default. The write cache is usually enabled by default.
.I wcreorder[,on|off] .I wcreorder[,on|off]
\- [ATA only] [NEW EXPERIMENTAL SMARTCTL FEATURE] \- [ATA only] Gets/sets Write Cache Reordering.
Gets/sets Write Cache Reordering.
If it is disabled (off), disk write scheduling is executed on a If it is disabled (off), disk write scheduling is executed on a
first-in-first-out (FIFO) basis. If Write Cache Reordering is enabled (on), first-in-first-out (FIFO) basis. If Write Cache Reordering is enabled (on),
then disk write scheduling may be reordered by the drive. If write cache is then disk write scheduling may be reordered by the drive. If write cache is
@ -901,21 +958,15 @@ The state of Write Cache Reordering has no effect on either NCQ or LCQ queued
commands. commands.
.I rcache[,on|off] .I rcache[,on|off]
\- [SCSI only] [NEW EXPERIMENTAL SMARTCTL FEATURE] \- [SCSI only] Gets/sets the \'Read Cache Disable\' (RCE) bit.
Gets/sets the \'Read Cache Disable\' (RCE) bit. \'Off\' value disables read cache \'Off\' value disables read cache (if supported).
(if supported).
The read cache is usually enabled by default. The read cache is usually enabled by default.
.TP .TP
.B SMART READ AND DISPLAY DATA OPTIONS: .B SMART READ AND DISPLAY DATA OPTIONS:
.TP .TP
.B \-H, \-\-health .B \-H, \-\-health
Check: Ask the device to report its SMART health status or pending Prints the health status of the device or pending TapeAlert messages.
TapeAlert messages. SMART status is based on
information that it has gathered from online and offline
tests, which were used to determine/update its
SMART vendor-specific Attribute values. TapeAlert status is obtained
by reading the TapeAlert log page.
If the device reports failing health status, this means If the device reports failing health status, this means
.B either .B either
@ -924,9 +975,36 @@ that the device has already failed,
that it is predicting its own failure within the next 24 hours. If that it is predicting its own failure within the next 24 hours. If
this happens, use the \'\-a\' option to get more information, and this happens, use the \'\-a\' option to get more information, and
.B get your data off the disk and to someplace safe as soon as you can. .B get your data off the disk and to someplace safe as soon as you can.
[ATA] Health status is obtained by checking the (boolean) result returned
by the SMART RETURN STATUS command.
The return value of this ATA command may be unknown due to limitations or
bugs in some layer (e.g. RAID controller or USB bridge firmware) between
disk and operating system.
In this case, \fBsmartctl\fP prints a warning and checks whether any
Prefailure SMART Attribute value is less than or equal to its threshold
(see \'\-A\' below).
[SCSI] Health status is obtained by checking the Additional Sense Code
(ASC) and Additional Sense Code Qualifier (ASCQ) from Informal Exceptions
(IE) log page (if supported) and/or from SCSI sense data.
[SCSI tape drive or changer] TapeAlert status is obtained by reading the
TapeAlert log page.
Please note that the TapeAlert log page flags are cleared for the initiator
when the page is read.
This means that each alert condition is reported only once by \fBsmartctl\fP
for each initiator for each activation of the condition.
.\" %IF OS FreeBSD Linux Windows Cygwin
[NVMe] [FreeBSD, Linux, Windows and Cygwin only]
[NEW EXPERIMENTAL SMARTCTL FEATURE]
NVMe status is obtained by reading the "Critical Warning" byte from
the SMART/Health Information log.
.\" %ENDIF OS FreeBSD Linux Windows Cygwin
.TP .TP
.B \-c, \-\-capabilities .B \-c, \-\-capabilities
[ATA only] Prints only the generic SMART capabilities. These [ATA] Prints only the generic SMART capabilities. These
show what SMART features are implemented and how the device will show what SMART features are implemented and how the device will
respond to some of the different SMART commands. For example it respond to some of the different SMART commands. For example it
shows if the device logs errors, if it supports offline surface shows if the device logs errors, if it supports offline surface
@ -941,6 +1019,13 @@ then the time may jump to a larger value and then count down as the
Immediate Offline Test is carried out. Please see REFERENCES below Immediate Offline Test is carried out. Please see REFERENCES below
for further information about the the flags and capabilities described for further information about the the flags and capabilities described
by this option. by this option.
.\" %IF OS FreeBSD Linux Windows Cygwin
[NVMe] [FreeBSD, Linux, Windows and Cygwin only]
[NEW EXPERIMENTAL SMARTCTL FEATURE]
Prints various NVMe device capabilities obtained from the Identify Controller
and the Identify Namespace data structure.
.\" %ENDIF OS FreeBSD Linux Windows Cygwin
.TP .TP
.B \-A, \-\-attributes .B \-A, \-\-attributes
[ATA] Prints only the vendor specific SMART Attributes. The Attributes [ATA] Prints only the vendor specific SMART Attributes. The Attributes
@ -1033,6 +1118,13 @@ the drive is already in the smartmontools drive database.
and start-stop cycle counter log pages. Certain vendor specific and start-stop cycle counter log pages. Certain vendor specific
attributes are listed if recognised. The attributes are output in a attributes are listed if recognised. The attributes are output in a
relatively free format (compared with ATA disk attributes). relatively free format (compared with ATA disk attributes).
.\" %IF OS FreeBSD Linux Windows Cygwin
[NVMe] [FreeBSD, Linux, Windows and Cygwin only]
[NEW EXPERIMENTAL SMARTCTL FEATURE]
For NVMe devices the attributes are obtained from the SMART/Health
Information log.
.\" %ENDIF OS FreeBSD Linux Windows Cygwin
.TP .TP
.B \-f FORMAT, \-\-format=FORMAT .B \-f FORMAT, \-\-format=FORMAT
[ATA only] Selects the output format of the attributes: [ATA only] Selects the output format of the attributes:
@ -1139,6 +1231,17 @@ receives a command which is not implemented or is not valid.
\- [SCSI] prints the error counter log pages for reads, write and verifies. \- [SCSI] prints the error counter log pages for reads, write and verifies.
The verify row is only output if it has an element other than zero. The verify row is only output if it has an element other than zero.
.\" %IF OS FreeBSD Linux Windows Cygwin
.I error[,NUM]
\- [NVMe] [FreeBSD, Linux, Windows and Cygwin only]
[NEW EXPERIMENTAL SMARTCTL FEATURE]
prints the NVMe Error Information log.
Only the 16 most recent log entries are printed by default.
This number can be changed by the optional parameter NUM.
The maximum number of log entries is vendor specific
(in the range from 1 to 256 inclusive).
.\" %ENDIF OS FreeBSD Linux Windows Cygwin
.I xerror[,NUM][,error] .I xerror[,NUM][,error]
\- [ATA only] prints the Extended Comprehensive SMART error log \- [ATA only] prints the Extended Comprehensive SMART error log
(General Purpose Log address 0x03). Unlike the Summary SMART error (General Purpose Log address 0x03). Unlike the Summary SMART error
@ -1326,6 +1429,18 @@ This command:
writes a binary representation of the one sector log 0x11 writes a binary representation of the one sector log 0x11
(SATA Phy Event Counters) to file log.bin. (SATA Phy Event Counters) to file log.bin.
.\" %IF OS FreeBSD Linux Windows Cygwin
.I nvmelog,PAGE,SIZE
\- [NVMe only] [FreeBSD, Linux, Windows and Cygwin only]
[NEW EXPERIMENTAL SMARTCTL FEATURE]
prints a hex dump of the first SIZE bytes from the NVMe log with
identifier PAGE.
PAGE is a hexadecimal number in the range from 0x1 to 0xff.
SIZE is a hexadecimal number in the range from 0x4 to 0x4000 (16 KiB).
\fBWARNING: Do not specify the identifier of an unknown log page.
Reading a log page may have undesirable side effects.\fP
.\" %ENDIF OS FreeBSD Linux Windows Cygwin
.I ssd .I ssd
\- [ATA] prints the Solid State Device Statistics log page. \- [ATA] prints the Solid State Device Statistics log page.
This has the same effect as \'\-l devstat,7\', see above. This has the same effect as \'\-l devstat,7\', see above.
@ -1658,6 +1773,7 @@ If
.\"! \fBEXEDIR/drivedb.h\fP .\"! \fBEXEDIR/drivedb.h\fP
.\" %ENDIF OS Windows .\" %ENDIF OS Windows
is present, the contents of this file is used instead of the built in table. is present, the contents of this file is used instead of the built in table.
.\" %IF ENABLE_UPDATE_SMART_DRIVEDB
Run Run
.\" %IF NOT OS Windows .\" %IF NOT OS Windows
@ -1670,6 +1786,7 @@ Run
.\"! \fBEXEDIR/update-smart-drivedb.exe\fP .\"! \fBEXEDIR/update-smart-drivedb.exe\fP
.\" %ENDIF OS Windows .\" %ENDIF OS Windows
to update this file from the smartmontools SVN repository. to update this file from the smartmontools SVN repository.
.\" %ENDIF ENABLE_UPDATE_SMART_DRIVEDB
.\" %ENDIF ENABLE_DRIVEDB .\" %ENDIF ENABLE_DRIVEDB
The database files use the same C/C++ syntax that is used to initialize The database files use the same C/C++ syntax that is used to initialize
@ -1791,25 +1908,25 @@ a disk can be specified by N\-\fBmax\fP.
For example the commands: For example the commands:
.nf .nf
smartctl \-t select,10\-20 /dev/hda smartctl \-t select,10\-20 /dev/sda
smartctl \-t select,10+11 /dev/hda smartctl \-t select,10+11 /dev/sda
.fi .fi
both runs a self test on one span consisting of LBAs ten to twenty both runs a self test on one span consisting of LBAs ten to twenty
(inclusive). The command: (inclusive). The command:
.nf .nf
smartctl \-t select,100000000\-max /dev/hda smartctl \-t select,100000000\-max /dev/sda
.fi .fi
run a self test from LBA 100000000 up to the end of the disk. run a self test from LBA 100000000 up to the end of the disk.
The \'\-t\' option can be given up to five times, to test The \'\-t\' option can be given up to five times, to test
up to five spans. For example the command: up to five spans. For example the command:
.nf .nf
smartctl \-t select,0\-100 \-t select,1000\-2000 /dev/hda smartctl \-t select,0\-100 \-t select,1000\-2000 /dev/sda
.fi .fi
runs a self test on two spans. The first span consists of 101 LBAs runs a self test on two spans. The first span consists of 101 LBAs
and the second span consists of 1001 LBAs. Note that the spans can and the second span consists of 1001 LBAs. Note that the spans can
overlap partially or completely, for example: overlap partially or completely, for example:
.nf .nf
smartctl \-t select,0\-10 \-t select,5\-15 \-t select,10\-20 /dev/hda smartctl \-t select,0\-10 \-t select,5\-15 \-t select,10\-20 /dev/sda
.fi .fi
The results of the selective self-test can be obtained (both during The results of the selective self-test can be obtained (both during
and after the test) by printing the SMART self-test log, using the and after the test) by printing the SMART self-test log, using the
@ -1836,15 +1953,15 @@ argument.
For example the commands: For example the commands:
.nf .nf
smartctl \-t select,10\-20 /dev/hda smartctl \-t select,10\-20 /dev/sda
smartctl \-t select,redo /dev/hda smartctl \-t select,redo /dev/sda
smartctl \-t select,redo+20 /dev/hda smartctl \-t select,redo+20 /dev/sda
.fi .fi
have the same effect as: have the same effect as:
.nf .nf
smartctl \-t select,10\-20 /dev/hda smartctl \-t select,10\-20 /dev/sda
smartctl \-t select,10\-20 /dev/hda smartctl \-t select,10\-20 /dev/sda
smartctl \-t select,10\-29 /dev/hda smartctl \-t select,10\-29 /dev/sda
.fi .fi
.I select,next[+SIZE] .I select,next[+SIZE]
@ -1855,15 +1972,15 @@ optional +SIZE argument.
For example the commands: For example the commands:
.nf .nf
smartctl \-t select,0\-999 /dev/hda smartctl \-t select,0\-999 /dev/sda
smartctl \-t select,next /dev/hda smartctl \-t select,next /dev/sda
smartctl \-t select,next+2000 /dev/hda smartctl \-t select,next+2000 /dev/sda
.fi .fi
have the same effect as: have the same effect as:
.nf .nf
smartctl \-t select,0\-999 /dev/hda smartctl \-t select,0\-999 /dev/sda
smartctl \-t select,1000\-1999 /dev/hda smartctl \-t select,1000\-1999 /dev/sda
smartctl \-t select,2000\-3999 /dev/hda smartctl \-t select,2000\-3999 /dev/sda
.fi .fi
If the last test ended at the last LBA of the disk, the new range starts If the last test ended at the last LBA of the disk, the new range starts
@ -1986,62 +2103,55 @@ browser.
.SH EXAMPLES .SH EXAMPLES
.nf .nf
.B smartctl \-a /dev/hda .B smartctl \-a /dev/sda
.fi .fi
Print a large amount of SMART information for drive /dev/hda which is Print a large amount of SMART information for drive /dev/sda .
typically an ATA (IDE) or SATA disk in Linux.
.PP .PP
.nf .nf
.B smartctl \-a /dev/sdb .B smartctl \-s off /dev/sdd
.fi .fi
Print a large amount of SMART information for drive /dev/sdb . This may Disable SMART monitoring and data log collection on drive /dev/sdd .
be a SCSI disk or an ATA (SATA) disk.
.PP .PP
.nf .nf
.B smartctl \-s off /dev/hdd .B smartctl \-\-smart=on \-\-offlineauto=on \-\-saveauto=on /dev/sda
.fi .fi
Disable SMART monitoring and data log collection on drive /dev/hdd . Enable SMART on drive /dev/sda, enable automatic offline
.PP
.nf
.B smartctl \-\-smart=on \-\-offlineauto=on \-\-saveauto=on /dev/hda
.fi
Enable SMART on drive /dev/hda, enable automatic offline
testing every four hours, and enable autosaving of testing every four hours, and enable autosaving of
SMART Attributes. This is a good start-up line for your system\'s SMART Attributes. This is a good start-up line for your system\'s
init files. You can issue this command on a running system. init files. You can issue this command on a running system.
.PP .PP
.nf .nf
.B smartctl \-t long /dev/hdc .B smartctl \-t long /dev/sdc
.fi .fi
Begin an extended self-test of drive /dev/hdc. You can issue this Begin an extended self-test of drive /dev/sdc. You can issue this
command on a running system. The results can be seen in the self-test command on a running system. The results can be seen in the self-test
log visible with the \'\-l selftest\' option after it has completed. log visible with the \'\-l selftest\' option after it has completed.
.PP .PP
.nf .nf
.B smartctl \-s on \-t offline /dev/hda .B smartctl \-s on \-t offline /dev/sda
.fi .fi
Enable SMART on the disk, and begin an immediate offline test of Enable SMART on the disk, and begin an immediate offline test of
drive /dev/hda. You can issue this command on a running system. The drive /dev/sda. You can issue this command on a running system. The
results are only used to update the SMART Attributes, visible results are only used to update the SMART Attributes, visible
with the \'\-A\' option. If any device errors occur, they are logged to with the \'\-A\' option. If any device errors occur, they are logged to
the SMART error log, which can be seen with the \'\-l error\' option. the SMART error log, which can be seen with the \'\-l error\' option.
.PP .PP
.nf .nf
.B smartctl \-A \-v 9,minutes /dev/hda .B smartctl \-A \-v 9,minutes /dev/sda
.fi .fi
Shows the vendor Attributes, when the disk stores its power-on time Shows the vendor Attributes, when the disk stores its power-on time
internally in minutes rather than hours. internally in minutes rather than hours.
.PP .PP
.nf .nf
.B smartctl \-q errorsonly \-H \-l selftest /dev/hda .B smartctl \-q errorsonly \-H \-l selftest /dev/sda
.fi .fi
Produces output only if the device returns failing SMART status, Produces output only if the device returns failing SMART status,
or if some of the logged self-tests ended with errors. or if some of the logged self-tests ended with errors.
.PP .PP
.nf .nf
.B smartctl \-q silent \-a /dev/hda .B smartctl \-q silent \-a /dev/sda
.fi .fi
Examine all SMART data for device /dev/hda, but produce no Examine all SMART data for device /dev/sda, but produce no
printed output. You must use the exit status (the printed output. You must use the exit status (the
.B $? .B $?
shell variable) to learn if any Attributes are out of bound, if the shell variable) to learn if any Attributes are out of bound, if the
@ -2100,7 +2210,7 @@ Start a short self-test on the (S)ATA disk connected to second pmport on the
first channel of the first HighPoint RocketRAID controller card. first channel of the first HighPoint RocketRAID controller card.
.PP .PP
.nf .nf
.B smartctl \-t select,10\-100 \-t select,30\-300 \-t afterselect,on \-t pending,45 /dev/hda .B smartctl \-t select,10\-100 \-t select,30\-300 \-t afterselect,on \-t pending,45 /dev/sda
.fi .fi
Run a selective self-test on LBAs 10 to 100 and 30 to 300. After the Run a selective self-test on LBAs 10 to 100 and 30 to 300. After the
these LBAs have been tested, read-scan the remainder of the disk. If the disk is these LBAs have been tested, read-scan the remainder of the disk. If the disk is
@ -2113,13 +2223,13 @@ device is restored.
Examine all SMART data for the first SCSI disk connected to a cciss Examine all SMART data for the first SCSI disk connected to a cciss
RAID controller card. RAID controller card.
.SH RETURN VALUES .SH EXIT STATUS
The return values of \fBsmartctl\fP are defined by a bitmask. If all The exit statuses of \fBsmartctl\fP are defined by a bitmask.
is well with the disk, the return value (exit status) of If all is well with the disk, the exit status (return value) of
\fBsmartctl\fP is 0 (all bits turned off). If a problem occurs, or an \fBsmartctl\fP is 0 (all bits turned off). If a problem occurs, or an
error, potential error, or fault is detected, then a non-zero status error, potential error, or fault is detected, then a non-zero status
is returned. In this case, the eight different bits in the return is returned. In this case, the eight different bits in the exit status
value have the following meanings for ATA disks; some of these values have the following meanings for ATA disks; some of these values
may also be returned for SCSI disks. may also be returned for SCSI disks.
.TP .TP
.B Bit 0: .B Bit 0:
@ -2188,68 +2298,44 @@ drive database (see \'\-B\' option).
optional local drive database (see \'\-B\' option). optional local drive database (see \'\-B\' option).
.\" %ENDIF NOT OS Windows .\" %ENDIF NOT OS Windows
.SH NOTES
The TapeAlert log page flags are cleared for the initiator when the
page is read. This means that each alert condition is reported only
once by \fBsmartctl\fP for each initiator for each activation of the
condition.
.SH AUTHORS .SH AUTHORS
\fBBruce Allen\fP \fBBruce Allen\fP (project initiator),
.br .br
University of Wisconsin \- Milwaukee Physics Department \fBChristian Franke\fP (project manager, Windows port and all sort of things),
.br .br
\fBChristian Franke\fP (Windows interface, C++ redesign, most enhancements \fBDouglas Gilbert\fP (SCSI subsystem),
since 2009)
.br .br
\fBsmartmontools\-support@lists.sourceforge.net\fP \fBVolker Kuhlmann\fP (moderator of support and database mailing list),
.br
\fBGabriele Pohl\fP (wiki & development team support),
.br
\fBAlex Samorukov\fP (FreeBSD port and more, new Trac wiki).
The following have made large contributions to smartmontools: Many other individuals have made contributions and corrections,
.br see AUTHORS, ChangeLog and repository files.
\fBCasper Dik\fP (Solaris SCSI interface)
.br
\fBDouglas Gilbert\fP (SCSI subsystem)
.br
\fBGuido Guenther\fP (Autoconf/Automake packaging)
.br
\fBGeoffrey Keating\fP (Darwin ATA interface)
.br
\fBEduard Martinescu\fP (FreeBSD interface)
.br
\fBFr\['e]d\['e]ric L. W. Meunier\fP (Web site and Mailing list)
.br
\fBGabriele Pohl\fP (Web site and Wiki, conversion from CVS to SVN)
.br
\fBKeiji Sawada\fP (Solaris ATA interface)
.br
\fBManfred Schwarb\fP (Drive database)
.br
\fBSergey Svishchev\fP (NetBSD interface)
.br
\fBDavid Snyder and Sergey Svishchev\fP (OpenBSD interface)
.br
\fBPhil Williams\fP (User interface and drive database)
.br
\fBYuri Dario\fP (OS/2, eComStation interface)
.br
\fBShengfeng Zhou\fP (Linux/FreeBSD HighPoint RocketRAID interface)
.br
Many other individuals have made smaller contributions and corrections.
The first smartmontools code was derived from the smartsuite package, The first smartmontools code was derived from the smartsuite package,
written by Michael Cornwell, and from the previous UCSC smartsuite package. written by Michael Cornwell and Andre Hedrick.
This code was originally developed as a
Senior Thesis by Michael Cornwell at the Concurrent Systems Laboratory .SH REPORTING BUGS
(now part of the Storage Systems Research Center), Jack Baskin School To submit a bug report, create a ticket in smartmontools wiki:
of Engineering, University of California, Santa .br
Cruz. \fBhttp://ssrc.soe.ucsc.edu/\fP . <\fBhttp://www.smartmontools.org/\fP>.
.br
Alternatively send the info to the smartmontools support mailing list:
.br
<\fBhttps://lists.sourceforge.net/lists/listinfo/smartmontools-support\fB>.
.SH SEE ALSO .SH SEE ALSO
\fBsmartd\fP(8), \fBupdate-smart-drivedb\fP(8). \fBsmartd\fP(8).
.\" %IF ENABLE_UPDATE_SMART_DRIVEDB
.br
\fBupdate-smart-drivedb\fP(8).
.\" %ENDIF ENABLE_UPDATE_SMART_DRIVEDB
.SH REFERENCES .SH REFERENCES
Please see the following web site for more info: Please see the following web site for more info:
\fBhttp://smartmontools.sourceforge.net/\fP \fBhttp://www.smartmontools.org/\fP
An introductory article about smartmontools is \fIMonitoring Hard An introductory article about smartmontools is \fIMonitoring Hard
Disks with SMART\fP, by Bruce Allen, Linux Journal, January 2004, Disks with SMART\fP, by Bruce Allen, Linux Journal, January 2004,
@ -2269,5 +2355,7 @@ publications of the Small Form Factors (SFF) Committee.
Links to these and other documents may be found on the Links page of the Links to these and other documents may be found on the Links page of the
\fBsmartmontools\fP Wiki at \fBhttp://www.smartmontools.org/wiki/Links\fP . \fBsmartmontools\fP Wiki at \fBhttp://www.smartmontools.org/wiki/Links\fP .
.SH SVN ID OF THIS PAGE .SH PACKAGE VERSION
$Id: smartctl.8.in 3965 2014-07-20 14:46:41Z chrfranke $ CURRENT_SVN_VERSION CURRENT_SVN_DATE CURRENT_SVN_REV
.br
$Id: smartctl.8.in 4311 2016-04-27 21:03:01Z chrfranke $

View File

@ -1,10 +1,10 @@
/* /*
* smartctl.cpp * smartctl.cpp
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2002-11 Bruce Allen
* Copyright (C) 2008-14 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2008-16 Christian Franke
* Copyright (C) 2000 Michael Cornwell <cornwell@acm.org> * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -48,10 +48,11 @@
#include "knowndrives.h" #include "knowndrives.h"
#include "scsicmds.h" #include "scsicmds.h"
#include "scsiprint.h" #include "scsiprint.h"
#include "nvmeprint.h"
#include "smartctl.h" #include "smartctl.h"
#include "utility.h" #include "utility.h"
const char * smartctl_cpp_cvsid = "$Id: smartctl.cpp 3936 2014-07-05 17:16:23Z chrfranke $" const char * smartctl_cpp_cvsid = "$Id: smartctl.cpp 4311 2016-04-27 21:03:01Z chrfranke $"
CONFIG_H_CVSID SMARTCTL_H_CVSID; CONFIG_H_CVSID SMARTCTL_H_CVSID;
// Globals to control printing // Globals to control printing
@ -128,7 +129,7 @@ static void Usage()
"======================================= READ AND DISPLAY DATA OPTIONS =====\n\n" "======================================= READ AND DISPLAY DATA OPTIONS =====\n\n"
" -H, --health\n" " -H, --health\n"
" Show device SMART health status\n\n" " Show device SMART health status\n\n"
" -c, --capabilities (ATA)\n" " -c, --capabilities (ATA, NVMe)\n"
" Show device SMART capabilities\n\n" " Show device SMART capabilities\n\n"
" -A, --attributes\n" " -A, --attributes\n"
" Show device SMART vendor-specific Attributes and values\n\n" " Show device SMART vendor-specific Attributes and values\n\n"
@ -140,7 +141,8 @@ static void Usage()
" background, sasphy[,reset], sataphy[,reset],\n" " background, sasphy[,reset], sataphy[,reset],\n"
" scttemp[sts,hist], scttempint,N[,p],\n" " scttemp[sts,hist], scttempint,N[,p],\n"
" scterc[,N,M], devstat[,N], ssd,\n" " scterc[,N,M], devstat[,N], ssd,\n"
" gplog,N[,RANGE], smartlog,N[,RANGE]\n\n" " gplog,N[,RANGE], smartlog,N[,RANGE],\n"
" nvmelog,N,SIZE\n\n"
" -v N,OPTION , --vendorattribute=N,OPTION (ATA)\n" " -v N,OPTION , --vendorattribute=N,OPTION (ATA)\n"
" Set display OPTION for vendor Attribute N (see man page)\n\n" " Set display OPTION for vendor Attribute N (see man page)\n\n"
" -F TYPE, --firmwarebug=TYPE (ATA)\n" " -F TYPE, --firmwarebug=TYPE (ATA)\n"
@ -194,7 +196,7 @@ static std::string getvalidarglist(int opt)
case 'b': case 'b':
return "warn, exit, ignore"; return "warn, exit, ignore";
case 'r': case 'r':
return "ioctl[,N], ataioctl[,N], scsiioctl[,N]"; return "ioctl[,N], ataioctl[,N], scsiioctl[,N], nvmeioctl[,N]";
case opt_smart: case opt_smart:
case 'o': case 'o':
case 'S': case 'S':
@ -205,8 +207,8 @@ static std::string getvalidarglist(int opt)
"background, sasphy[,reset], sataphy[,reset], " "background, sasphy[,reset], sataphy[,reset], "
"scttemp[sts,hist], scttempint,N[,p], " "scttemp[sts,hist], scttempint,N[,p], "
"scterc[,N,M], devstat[,N], ssd, " "scterc[,N,M], devstat[,N], ssd, "
"gplog,N[,RANGE], smartlog,N[,RANGE]"; "gplog,N[,RANGE], smartlog,N[,RANGE], "
"nvmelog,N,SIZE";
case 'P': case 'P':
return "use, ignore, show, showall"; return "use, ignore, show, showall";
case 't': case 't':
@ -259,13 +261,13 @@ enum checksum_err_mode_t {
static checksum_err_mode_t checksum_err_mode = CHECKSUM_ERR_WARN; static checksum_err_mode_t checksum_err_mode = CHECKSUM_ERR_WARN;
static void scan_devices(const char * type, bool with_open, char ** argv); static void scan_devices(const smart_devtype_list & types, bool with_open, char ** argv);
/* Takes command options and sets features to be run */ /* Takes command options and sets features to be run */
static 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, ata_print_options & ataopts, scsi_print_options & scsiopts,
bool & print_type_only) nvme_print_options & nvmeopts, bool & print_type_only)
{ {
// Please update getvalidarglist() if you edit shortopts // Please update getvalidarglist() if you edit shortopts
const char *shortopts = "h?Vq:d:T:b:r:s:o:S:HcAl:iaxv:P:t:CXF:n:B:f:g:"; const char *shortopts = "h?Vq:d:T:b:r:s:o:S:HcAl:iaxv:P:t:CXF:n:B:f:g:";
@ -313,7 +315,8 @@ static const char * parse_options(int argc, char** argv,
opterr=optopt=0; opterr=optopt=0;
const char * type = 0; // set to -d optarg const char * type = 0; // set to -d optarg
bool no_defaultdb = false; // set true on '-B FILE' smart_devtype_list scan_types; // multiple -d TYPE options for --scan
bool use_default_db = true; // set false on '-B FILE'
bool output_format_set = false; // set true on '-f FORMAT' bool output_format_set = false; // set true on '-f FORMAT'
int scan = 0; // set by --scan, --scan-open int scan = 0; // set by --scan, --scan-open
bool badarg = false, captive = false; bool badarg = false, captive = false;
@ -345,8 +348,14 @@ static const char * parse_options(int argc, char** argv,
case 'd': case 'd':
if (!strcmp(optarg, "test")) if (!strcmp(optarg, "test"))
print_type_only = true; print_type_only = true;
else else if (!strcmp(optarg, "auto")) {
type = (strcmp(optarg, "auto") ? optarg : (char *)0); type = 0;
scan_types.clear();
}
else {
type = optarg;
scan_types.push_back(optarg);
}
break; break;
case 'T': case 'T':
if (!strcmp(optarg,"normal")) { if (!strcmp(optarg,"normal")) {
@ -376,26 +385,22 @@ static const char * parse_options(int argc, char** argv,
break; break;
case 'r': case 'r':
{ {
int i; int n1 = -1, n2 = -1, len = strlen(optarg);
char *s; char s[9+1]; unsigned i = 1;
sscanf(optarg, "%9[a-z]%n,%u%n", s, &n1, &i, &n2);
// split_report_arg() may modify its first argument string, so use a if (!((n1 == len || n2 == len) && 1 <= i && i <= 4)) {
// copy of optarg in case we want optarg for an error message.
if (!(s = strdup(optarg))) {
throw std::bad_alloc();
}
if (split_report_arg(s, &i)) {
badarg = true; badarg = true;
} else if (!strcmp(s,"ioctl")) { } else if (!strcmp(s,"ioctl")) {
ata_debugmode = scsi_debugmode = i; ata_debugmode = scsi_debugmode = nvme_debugmode = i;
} else if (!strcmp(s,"ataioctl")) { } else if (!strcmp(s,"ataioctl")) {
ata_debugmode = i; ata_debugmode = i;
} else if (!strcmp(s,"scsiioctl")) { } else if (!strcmp(s,"scsiioctl")) {
scsi_debugmode = i; scsi_debugmode = i;
} else if (!strcmp(s,"nvmeioctl")) {
nvme_debugmode = i;
} else { } else {
badarg = true; badarg = true;
} }
free(s);
} }
break; break;
@ -437,7 +442,7 @@ static const char * parse_options(int argc, char** argv,
} }
break; break;
case 'H': case 'H':
ataopts.smart_check_status = scsiopts.smart_check_status = true; ataopts.smart_check_status = scsiopts.smart_check_status = nvmeopts.smart_check_status = true;
scsiopts.smart_ss_media_log = true; scsiopts.smart_ss_media_log = true;
break; break;
case 'F': case 'F':
@ -447,14 +452,23 @@ static const char * parse_options(int argc, char** argv,
badarg = true; badarg = true;
break; break;
case 'c': case 'c':
ataopts.smart_general_values = true; ataopts.smart_general_values = nvmeopts.drive_capabilities = true;
break; break;
case 'A': case 'A':
ataopts.smart_vendor_attrib = scsiopts.smart_vendor_attrib = true; ataopts.smart_vendor_attrib = scsiopts.smart_vendor_attrib = nvmeopts.smart_vendor_attrib = true;
break; break;
case 'l': case 'l':
if (!strcmp(optarg,"error")) { if (str_starts_with(optarg, "error")) {
int n1 = -1, n2 = -1, len = strlen(optarg);
unsigned val = ~0;
sscanf(optarg, "error%n,%u%n", &n1, &val, &n2);
ataopts.smart_error_log = scsiopts.smart_error_log = true; ataopts.smart_error_log = scsiopts.smart_error_log = true;
if (n1 == len)
nvmeopts.error_log_entries = 16;
else if (n2 == len && val > 0)
nvmeopts.error_log_entries = val;
else
badarg = true;
} else if (!strcmp(optarg,"selftest")) { } else if (!strcmp(optarg,"selftest")) {
ataopts.smart_selftest_log = scsiopts.smart_selftest_log = true; ataopts.smart_selftest_log = scsiopts.smart_selftest_log = true;
} else if (!strcmp(optarg, "selective")) { } else if (!strcmp(optarg, "selective")) {
@ -503,10 +517,14 @@ static const char * parse_options(int argc, char** argv,
sscanf(optarg, "devstat%n,%u%n", &n1, &val, &n2); sscanf(optarg, "devstat%n,%u%n", &n1, &val, &n2);
if (n1 == len) if (n1 == len)
ataopts.devstat_all_pages = true; ataopts.devstat_all_pages = true;
else if (n2 == len && val <= 255) else {
if (n2 != len) // retry with hex
sscanf(optarg, "devstat,0x%x%n", &val, &n2);
if (n2 == len && val <= 0xff)
ataopts.devstat_pages.push_back(val); ataopts.devstat_pages.push_back(val);
else else
badarg = true; badarg = true;
}
} else if (!strncmp(optarg, "xerror", sizeof("xerror")-1)) { } else if (!strncmp(optarg, "xerror", sizeof("xerror")-1)) {
int n1 = -1, n2 = -1, len = strlen(optarg); int n1 = -1, n2 = -1, len = strlen(optarg);
@ -579,12 +597,25 @@ static const char * parse_options(int argc, char** argv,
req.nsectors = (sign == '-' ? nsectors-page+1 : nsectors); req.nsectors = (sign == '-' ? nsectors-page+1 : nsectors);
ataopts.log_requests.push_back(req); ataopts.log_requests.push_back(req);
} }
} else { }
else if (str_starts_with(optarg, "nvmelog,")) {
int n = -1, len = strlen(optarg);
unsigned page = 0, size = 0;
sscanf(optarg, "nvmelog,0x%x,0x%x%n", &page, &size, &n);
if (n == len && page <= 0xff && 0 < size && size <= 0x4000) {
nvmeopts.log_page = page; nvmeopts.log_page_size = size;
}
else
badarg = true;
}
else {
badarg = true; badarg = true;
} }
break; break;
case 'i': case 'i':
ataopts.drive_info = scsiopts.drive_info = true; ataopts.drive_info = scsiopts.drive_info = nvmeopts.drive_info = true;
break; break;
case opt_identify: case opt_identify:
@ -603,23 +634,25 @@ static const char * parse_options(int argc, char** argv,
break; break;
case 'a': case 'a':
ataopts.drive_info = scsiopts.drive_info = true; ataopts.drive_info = scsiopts.drive_info = nvmeopts.drive_info = true;
ataopts.smart_check_status = scsiopts.smart_check_status = true; ataopts.smart_check_status = scsiopts.smart_check_status = nvmeopts.smart_check_status = true;
ataopts.smart_general_values = true; ataopts.smart_general_values = nvmeopts.drive_capabilities = true;
ataopts.smart_vendor_attrib = scsiopts.smart_vendor_attrib = true; ataopts.smart_vendor_attrib = scsiopts.smart_vendor_attrib = nvmeopts.smart_vendor_attrib = true;
ataopts.smart_error_log = scsiopts.smart_error_log = true; ataopts.smart_error_log = scsiopts.smart_error_log = true;
nvmeopts.error_log_entries = 16;
ataopts.smart_selftest_log = scsiopts.smart_selftest_log = true; ataopts.smart_selftest_log = scsiopts.smart_selftest_log = true;
ataopts.smart_selective_selftest_log = true; ataopts.smart_selective_selftest_log = true;
/* scsiopts.smart_background_log = true; */ /* scsiopts.smart_background_log = true; */
scsiopts.smart_ss_media_log = true; scsiopts.smart_ss_media_log = true;
break; break;
case 'x': case 'x':
ataopts.drive_info = scsiopts.drive_info = true; ataopts.drive_info = scsiopts.drive_info = nvmeopts.drive_info = true;
ataopts.smart_check_status = scsiopts.smart_check_status = true; ataopts.smart_check_status = scsiopts.smart_check_status = nvmeopts.smart_check_status = true;
ataopts.smart_general_values = true; ataopts.smart_general_values = nvmeopts.drive_capabilities = true;
ataopts.smart_vendor_attrib = scsiopts.smart_vendor_attrib = true; ataopts.smart_vendor_attrib = scsiopts.smart_vendor_attrib = nvmeopts.smart_vendor_attrib = true;
ataopts.smart_ext_error_log = 8; ataopts.smart_ext_error_log = 8;
ataopts.retry_error_log = true; ataopts.retry_error_log = true;
nvmeopts.error_log_entries = 16;
ataopts.smart_ext_selftest_log = 25; ataopts.smart_ext_selftest_log = 25;
ataopts.retry_selftest_log = true; ataopts.retry_selftest_log = true;
scsiopts.smart_error_log = scsiopts.smart_selftest_log = true; scsiopts.smart_error_log = scsiopts.smart_selftest_log = true;
@ -661,7 +694,7 @@ static const char * parse_options(int argc, char** argv,
} else if (!strcmp(optarg, "show")) { } else if (!strcmp(optarg, "show")) {
ataopts.show_presets = true; ataopts.show_presets = true;
} else if (!strcmp(optarg, "showall")) { } else if (!strcmp(optarg, "showall")) {
if (!no_defaultdb && !read_default_drive_databases()) if (!init_drive_database(use_default_db))
EXIT(FAILCMD); EXIT(FAILCMD);
if (optind < argc) { // -P showall MODEL [FIRMWARE] if (optind < argc) { // -P showall MODEL [FIRMWARE]
int cnt = showmatchingpresets(argv[optind], (optind+1<argc ? argv[optind+1] : NULL)); int cnt = showmatchingpresets(argv[optind], (optind+1<argc ? argv[optind+1] : NULL));
@ -801,7 +834,7 @@ static const char * parse_options(int argc, char** argv,
if (*path == '+' && path[1]) if (*path == '+' && path[1])
path++; path++;
else else
no_defaultdb = true; use_default_db = false;
if (!read_drive_database(path)) if (!read_drive_database(path))
EXIT(FAILCMD); EXIT(FAILCMD);
} }
@ -997,9 +1030,9 @@ static const char * parse_options(int argc, char** argv,
// Special handling of --scan, --scanopen // Special handling of --scan, --scanopen
if (scan) { if (scan) {
// Read or init drive database to allow USB ID check. // Read or init drive database to allow USB ID check.
if (!no_defaultdb && !read_default_drive_databases()) if (!init_drive_database(use_default_db))
EXIT(FAILCMD); EXIT(FAILCMD);
scan_devices(type, (scan == opt_scan_open), argv + optind); scan_devices(scan_types, (scan == opt_scan_open), argv + optind);
EXIT(0); EXIT(0);
} }
@ -1009,6 +1042,15 @@ static const char * parse_options(int argc, char** argv,
if (printing_is_switchable) if (printing_is_switchable)
printing_is_off = true; printing_is_off = true;
// Check for multiple -d TYPE options
if (scan_types.size() > 1) {
printing_is_off = false;
printslogan();
pout("ERROR: multiple -d TYPE options are only allowed with --scan\n");
UsageSummary();
EXIT(FAILCMD);
}
// error message if user has asked for more than one test // error message if user has asked for more than one test
if (testcnt > 1) { if (testcnt > 1) {
printing_is_off = false; printing_is_off = false;
@ -1075,7 +1117,7 @@ static const char * parse_options(int argc, char** argv,
} }
// Read or init drive database // Read or init drive database
if (!no_defaultdb && !read_default_drive_databases()) if (!init_drive_database(use_default_db))
EXIT(FAILCMD); EXIT(FAILCMD);
return type; return type;
@ -1151,19 +1193,22 @@ void checksumwarning(const char * string)
// Return info string about device protocol // Return info string about device protocol
static const char * get_protocol_info(const smart_device * dev) static const char * get_protocol_info(const smart_device * dev)
{ {
switch ((int)dev->is_ata() | ((int)dev->is_scsi() << 1)) { switch ( (int)dev->is_ata()
| ((int)dev->is_scsi() << 1)
| ((int)dev->is_nvme() << 2)) {
case 0x1: return "ATA"; case 0x1: return "ATA";
case 0x2: return "SCSI"; case 0x2: return "SCSI";
case 0x3: return "ATA+SCSI"; case 0x3: return "ATA+SCSI";
case 0x4: return "NVMe";
default: return "Unknown"; default: return "Unknown";
} }
} }
// Device scan // Device scan
// smartctl [-d type] --scan[-open] -- [PATTERN] [smartd directive ...] // smartctl [-d type] --scan[-open] -- [PATTERN] [smartd directive ...]
void scan_devices(const char * type, bool with_open, char ** argv) void scan_devices(const smart_devtype_list & types, bool with_open, char ** argv)
{ {
bool dont_print = !(ata_debugmode || scsi_debugmode); bool dont_print = !(ata_debugmode || scsi_debugmode || nvme_debugmode);
const char * pattern = 0; const char * pattern = 0;
int ai = 0; int ai = 0;
@ -1172,7 +1217,7 @@ void scan_devices(const char * type, bool with_open, char ** argv)
smart_device_list devlist; smart_device_list devlist;
printing_is_off = dont_print; printing_is_off = dont_print;
bool ok = smi()->scan_smart_devices(devlist, type , pattern); bool ok = smi()->scan_smart_devices(devlist, types, pattern);
printing_is_off = false; printing_is_off = false;
if (!ok) { if (!ok) {
@ -1224,8 +1269,9 @@ static int main_worker(int argc, char **argv)
// Parse input arguments // Parse input arguments
ata_print_options ataopts; ata_print_options ataopts;
scsi_print_options scsiopts; scsi_print_options scsiopts;
nvme_print_options nvmeopts;
bool print_type_only = false; bool print_type_only = false;
const char * type = parse_options(argc, argv, ataopts, scsiopts, print_type_only); const char * type = parse_options(argc, argv, ataopts, scsiopts, nvmeopts, print_type_only);
const char * name = argv[argc-1]; const char * name = argv[argc-1];
@ -1258,6 +1304,11 @@ static int main_worker(int argc, char **argv)
pout("%s: Device of type '%s' [%s] detected\n", pout("%s: Device of type '%s' [%s] detected\n",
dev->get_info_name(), dev->get_dev_type(), get_protocol_info(dev.get())); dev->get_info_name(), dev->get_dev_type(), get_protocol_info(dev.get()));
if (dev->is_ata() && ataopts.powermode>=2 && dev->is_powered_down()) {
pout( "%s: Device is in %s mode, exit(%d)\n", dev->get_info_name(), "STANDBY (OS)", FAILPOWER );
return FAILPOWER;
}
// Open device // Open device
{ {
// Save old info // Save old info
@ -1267,7 +1318,8 @@ static int main_worker(int argc, char **argv)
dev.replace( dev->autodetect_open() ); dev.replace( dev->autodetect_open() );
// Report if type has changed // Report if type has changed
if ((type || print_type_only) && oldinfo.dev_type != dev->get_dev_type()) if ( (ata_debugmode || scsi_debugmode || nvme_debugmode || print_type_only)
&& oldinfo.dev_type != dev->get_dev_type() )
pout("%s: Device open changed type from '%s' to '%s'\n", pout("%s: Device open changed type from '%s' to '%s'\n",
dev->get_info_name(), oldinfo.dev_type.c_str(), dev->get_dev_type()); dev->get_info_name(), oldinfo.dev_type.c_str(), dev->get_dev_type());
} }
@ -1285,9 +1337,11 @@ static int main_worker(int argc, char **argv)
retval = ataPrintMain(dev->to_ata(), ataopts); retval = ataPrintMain(dev->to_ata(), ataopts);
else if (dev->is_scsi()) else if (dev->is_scsi())
retval = scsiPrintMain(dev->to_scsi(), scsiopts); retval = scsiPrintMain(dev->to_scsi(), scsiopts);
else if (dev->is_nvme())
retval = nvmePrintMain(dev->to_nvme(), nvmeopts);
else else
// we should never fall into this branch! // we should never fall into this branch!
pout("%s: Neither ATA nor SCSI device\n", dev->get_info_name()); pout("%s: Neither ATA, SCSI nor NVMe device\n", dev->get_info_name());
dev->close(); dev->close();
return retval; return retval;
@ -1298,6 +1352,8 @@ static int main_worker(int argc, char **argv)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int status; int status;
bool badcode = false;
try { try {
// Do the real work ... // Do the real work ...
status = main_worker(argc, argv); status = main_worker(argc, argv);
@ -1314,8 +1370,21 @@ int main(int argc, char **argv)
catch (const std::exception & ex) { catch (const std::exception & ex) {
// Other fatal errors // Other fatal errors
printf("Smartctl: Exception: %s\n", ex.what()); printf("Smartctl: Exception: %s\n", ex.what());
badcode = true;
status = FAILCMD; status = FAILCMD;
} }
// Check for remaining device objects
if (smart_device::get_num_objects() != 0) {
printf("Smartctl: Internal Error: %d device object(s) left at exit.\n",
smart_device::get_num_objects());
badcode = true;
status = FAILCMD;
}
if (badcode)
printf("Please inform " PACKAGE_BUGREPORT ", including output of smartctl -V.\n");
return status; return status;
} }

View File

@ -1,7 +1,7 @@
/* /*
* smartctl.h * smartctl.h
* *
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2002-10 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) 2008-10 Christian Franke <smartmontools-support@lists.sourceforge.net>
@ -26,7 +26,7 @@
#ifndef SMARTCTL_H_ #ifndef SMARTCTL_H_
#define SMARTCTL_H_ #define SMARTCTL_H_
#define SMARTCTL_H_CVSID "$Id: smartctl.h 3727 2012-12-13 17:23:06Z samm2 $\n" #define SMARTCTL_H_CVSID "$Id: smartctl.h 4120 2015-08-27 16:12:21Z samm2 $\n"
// Return codes (bitmask) // Return codes (bitmask)

View File

@ -1,8 +1,8 @@
.ig .ig
Copyright (C) 2002-10 Bruce Allen <smartmontools-support@lists.sourceforge.net> Copyright (C) 2002-10 Bruce Allen
Copyright (C) 2004-14 Christian Franke <smartmontools-support@lists.sourceforge.net> Copyright (C) 2004-16 Christian Franke
$Id: smartd.8.in 3965 2014-07-20 14:46:41Z chrfranke $ $Id: smartd.8.in 4299 2016-04-16 19:45:57Z chrfranke $
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -18,16 +18,13 @@ Research Center), Jack Baskin School of Engineering, University of
California, Santa Cruz. http://ssrc.soe.ucsc.edu/ California, Santa Cruz. http://ssrc.soe.ucsc.edu/
.. ..
.TH SMARTD 8 CURRENT_SVN_DATE CURRENT_SVN_VERSION CURRENT_SVN_DATE .TH SMARTD 8 "CURRENT_SVN_DATE" "CURRENT_SVN_VERSION" "SMART Monitoring Tools"
.SH NAME .SH NAME
\fBsmartd\fP \- SMART Disk Monitoring Daemon \fBsmartd\fP \- SMART Disk Monitoring Daemon
.SH SYNOPSIS .SH SYNOPSIS
.B smartd [options] .B smartd [options]
.SH PACKAGE VERSION
CURRENT_SVN_VERSION CURRENT_SVN_DATE CURRENT_SVN_REV
.SH DESCRIPTION .SH DESCRIPTION
.\" %IF NOT OS ALL .\" %IF NOT OS ALL
.\"! [This man page is generated for the OS_MAN_FILTER version of smartmontools. .\"! [This man page is generated for the OS_MAN_FILTER version of smartmontools.
@ -101,8 +98,15 @@ devices that support SMART. The scanning is done as follows:
.IP \fBLINUX:\fP 9 .IP \fBLINUX:\fP 9
Examine all entries \fB"/dev/hd[a-t]"\fP for IDE/ATA Examine all entries \fB"/dev/hd[a-t]"\fP for IDE/ATA
devices, and \fB"/dev/sd[a-z]"\fP, \fB"/dev/sd[a-c][a-z]"\fP devices, and \fB"/dev/sd[a-z]"\fP, \fB"/dev/sd[a-c][a-z]"\fP
for SCSI or SATA devices. for ATA/SATA or SCSI/SAS devices.
Disks behind RAID controllers are not included. Disks behind RAID controllers are not included.
[NEW EXPERIMENTAL SMARTD FEATURE]
If directive \'\-d nvme\'
.\" %IF ENABLE_NVME_DEVICESCAN
or no \'\-d\' directive
.\" %ENDIF ENABLE_NVME_DEVICESCAN
is specified, examine all entries \fB"/dev/nvme[0-99]"\fP for NVMe devices.
.\" %ENDIF OS Linux .\" %ENDIF OS Linux
.\" %IF OS FreeBSD .\" %IF OS FreeBSD
.IP \fBFREEBSD:\fP 9 .IP \fBFREEBSD:\fP 9
@ -139,6 +143,13 @@ examine all entries \fB"/dev/csmi[0\-9],N"\fP for drives behind an Intel
ICHxR controller with RST driver. ICHxR controller with RST driver.
Disks behind Areca RAID controllers are not included. Disks behind Areca RAID controllers are not included.
[NEW EXPERIMENTAL SMARTD FEATURE]
If directive \'\-d nvme\'
.\" %IF ENABLE_NVME_DEVICESCAN
or no \'\-d\' directive
.\" %ENDIF ENABLE_NVME_DEVICESCAN
is specified, examine all entries \fB"/dev/nvme[0-9]"\fP for NVMe devices.
.\" %ENDIF OS Windows Cygwin .\" %ENDIF OS Windows Cygwin
.PP .PP
\fBsmartd\fP then monitors \fBsmartd\fP then monitors
@ -186,13 +197,14 @@ can be used to verify the existence of the default configuration file.
By using \'\-\' for FILE, the configuration is read from standard By using \'\-\' for FILE, the configuration is read from standard
input. This is useful for commands like: input. This is useful for commands like:
.nf .nf
.B echo /dev/hdb \-m user@home \-M test | smartd \-c \- \-q onecheck .B echo /dev/sdb \-m user@home \-M test | smartd \-c \- \-q onecheck
.fi .fi
to perform quick and simple checks without a configuration file. to perform quick and simple checks without a configuration file.
.\" %IF ENABLE_CAPABILITIES .\" %IF ENABLE_CAPABILITIES
.TP .TP
.B \-C, \-\-capabilities .B \-C, \-\-capabilities
Use \fBcapabilities\fP(7). [Linux only] Use libcap-ng to drop unneeded Linux process \fBcapabilities\fP(7).
The following capabilities are kept: CAP_SYS_ADMIN, CAP_SYS_RAWIO, CAP_MKNOD.
Warning: Mail notification does not work when used. Warning: Mail notification does not work when used.
.\" %ENDIF ENABLE_CAPABILITIES .\" %ENDIF ENABLE_CAPABILITIES
@ -283,7 +295,7 @@ log output is redirected as follows:
.TP .TP
.B \-n, \-\-no\-fork .B \-n, \-\-no\-fork
Do not fork into background; this is useful when executed from modern Do not fork into background; this is useful when executed from modern
init methods like initng, minit or supervise. init methods like initng, minit, supervise or systemd.
.\" %IF OS Cygwin .\" %IF OS Cygwin
On Cygwin, this allows running \fBsmartd\fP as service via cygrunsrv, On Cygwin, this allows running \fBsmartd\fP as service via cygrunsrv,
@ -379,6 +391,13 @@ this option are:
.I scsiioctl .I scsiioctl
\- report only ioctl() transactions with SCSI devices. \- report only ioctl() transactions with SCSI devices.
.\" %IF OS FreeBSD Linux Windows Cygwin
.I nvmeioctl
\- [FreeBSD, Linux, Windows and Cygwin only]
[NEW EXPERIMENTAL SMARTD FEATURE]
report only ioctl() transactions with NVMe devices.
.\" %ENDIF OS FreeBSD Linux Windows Cygwin
Any argument may include a positive integer to specify the level of Any argument may include a positive integer to specify the level of
detail that should be reported. The argument should be followed by a detail that should be reported. The argument should be followed by a
comma then the integer with no spaces. For example, \fIataioctl,2\fP comma then the integer with no spaces. For example, \fIataioctl,2\fP
@ -416,7 +435,6 @@ forced by SIGUSR1. After a normal check cycle, a file is only rewritten if
an important change (which usually results in a SYSLOG output) occurred. an important change (which usually results in a SYSLOG output) occurred.
.TP .TP
.B \-w PATH, \-\-warnexec=PATH .B \-w PATH, \-\-warnexec=PATH
[NEW EXPERIMENTAL SMARTD FEATURE]
Run the executable PATH instead of the default script when smartd Run the executable PATH instead of the default script when smartd
needs to send warning messages. PATH must point to an executable binary needs to send warning messages. PATH must point to an executable binary
file or script. file or script.
@ -464,6 +482,7 @@ once. The exit status (the shell
variable) will be zero if all went well, and nonzero if no devices variable) will be zero if all went well, and nonzero if no devices
were detected or some other problem was encountered. were detected or some other problem was encountered.
.\" %IF ENABLE_INITSCRIPT
Note that \fBsmartmontools\fP provides a start-up script in Note that \fBsmartmontools\fP provides a start-up script in
\fB/usr/local/etc/rc.d/init.d/smartd\fP which is responsible for starting and \fB/usr/local/etc/rc.d/init.d/smartd\fP which is responsible for starting and
stopping the daemon via the normal init interface. Using this script, stopping the daemon via the normal init interface. Using this script,
@ -476,6 +495,7 @@ and stop it by using the command:
.B /usr/local/etc/rc.d/init.d/smartd stop .B /usr/local/etc/rc.d/init.d/smartd stop
.fi .fi
.\" %ENDIF ENABLE_INITSCRIPT
.SH CONFIGURATION .SH CONFIGURATION
The syntax of the \fBsmartd.conf\fP(5) file is discussed separately. The syntax of the \fBsmartd.conf\fP(5) file is discussed separately.
@ -489,7 +509,7 @@ or
.B \'\-u\' .B \'\-u\'
Directives. For example: Directives. For example:
.nf .nf
.B \'Device: /dev/hda, SMART Attribute: 194 Temperature_Celsius changed from 94 to 93\' .B \'Device: /dev/sda, SMART Attribute: 194 Temperature_Celsius changed from 94 to 93\'
.fi .fi
Note that in this message, the value given is the \'Normalized\' not the \'Raw\' Note that in this message, the value given is the \'Normalized\' not the \'Raw\'
Attribute value (the disk temperature in this case is about 22 Attribute value (the disk temperature in this case is about 22
@ -500,7 +520,7 @@ and
Directives modify this behavior, so that the information is printed Directives modify this behavior, so that the information is printed
with the Raw values as well, for example: with the Raw values as well, for example:
.nf .nf
.B \'Device: /dev/hda, SMART Attribute: 194 Temperature_Celsius changed from 94 [Raw 22] to 93 [Raw 23]\' .B \'Device: /dev/sda, SMART Attribute: 194 Temperature_Celsius changed from 94 [Raw 22] to 93 [Raw 23]\'
.fi .fi
Here the Raw values are the actual disk temperatures in Celsius. The Here the Raw values are the actual disk temperatures in Celsius. The
way in which the Raw values are printed, and the names under which the way in which the Raw values are printed, and the names under which the
@ -518,7 +538,7 @@ will make log entries at loglevel
.B LOG_CRIT .B LOG_CRIT
if a SMART Attribute has failed, for example: if a SMART Attribute has failed, for example:
.nf .nf
.B \'Device: /dev/hdc, Failed SMART Attribute: 5 Reallocated_Sector_Ct\' .B \'Device: /dev/sdc, Failed SMART Attribute: 5 Reallocated_Sector_Ct\'
.fi .fi
This loglevel is used for reporting enabled by the This loglevel is used for reporting enabled by the
.B \'\-H\', \-f\', \'\-l\ selftest\', .B \'\-H\', \-f\', \'\-l\ selftest\',
@ -549,14 +569,17 @@ see the \fBsmartd\fP '\-l' command-line option described above.
.\" %ENDIF OS Solaris .\" %ENDIF OS Solaris
.\" %IF OS Cygwin .\" %IF OS Cygwin
The Cygwin Version of \fBsmartd\fP can be run as a service via the The Cygwin Version of \fBsmartd\fP can be run as a service via the
cygrunsrv tool. The start-up script provides Cygwin-specific commands cygrunsrv tool.
to install and remove the service: .\" %IF ENABLE_INITSCRIPT
The start-up script provides Cygwin-specific commands to install and
remove the service:
.nf .nf
.B /usr/local/etc/rc.d/init.d/smartd install [options] .B /usr/local/etc/rc.d/init.d/smartd install [options]
.B /usr/local/etc/rc.d/init.d/smartd remove .B /usr/local/etc/rc.d/init.d/smartd remove
.fi .fi
The service can be started and stopped by the start-up script as usual The service can be started and stopped by the start-up script as usual
(see \fBEXAMPLES\fP above). (see \fBEXAMPLES\fP above).
.\" %ENDIF ENABLE_INITSCRIPT
.\" %ENDIF OS Cygwin .\" %ENDIF OS Cygwin
.\" %IF OS Windows .\" %IF OS Windows
@ -624,10 +647,8 @@ set using \fB/etc/localtime\fP. The work-around \fIfails\fP if the
time-zone is set using the \'\fBTZ\fP\' variable (or a file that it time-zone is set using the \'\fBTZ\fP\' variable (or a file that it
points to). points to).
.SH RETURN VALUES .SH EXIT STATUS
The return value (exit status) of The exit status (return value) of \fBsmartd\fP can have the following values:
\fBsmartd\fP
can have the following values:
.TP .TP
.B 0: .B 0:
Daemon startup successful, or \fBsmartd\fP was killed by a SIGTERM (or in debug mode, a SIGQUIT). Daemon startup successful, or \fBsmartd\fP was killed by a SIGTERM (or in debug mode, a SIGQUIT).
@ -654,16 +675,11 @@ Config file exists, but cannot be read.
\fBsmartd\fP \fBsmartd\fP
ran out of memory during startup. ran out of memory during startup.
.TP .TP
.B 9:
A compile time constant of\fB smartd\fP was too small. This can be caused by an
excessive number of disks, or by lines in \fB /usr/local/etc/smartd.conf\fP that are too long.
Please report this problem to \fB smartmontools-support@lists.sourceforge.net\fP.
.TP
.B 10: .B 10:
An inconsistency was found in \fBsmartd\fP\'s internal data An inconsistency was found in \fBsmartd\fP\'s internal data
structures. This should never happen. It must be due to either a structures. This should never happen. It must be due to either a
coding or compiler bug. \fIPlease\fP report such failures to coding or compiler bug. \fIPlease\fP report such failures to
smartmontools-support@lists.sourceforge.net. smartmontools developers, see REPORTING BUGS below.
.TP .TP
.B 16: .B 16:
A device explicitly listed in A device explicitly listed in
@ -718,59 +734,43 @@ optional local drive database (see \'\-B\' option).
.\" %ENDIF NOT OS Windows .\" %ENDIF NOT OS Windows
.SH AUTHORS .SH AUTHORS
\fBBruce Allen\fP \fBBruce Allen\fP (project initiator),
.br .br
University of Wisconsin \- Milwaukee Physics Department \fBChristian Franke\fP (project manager, Windows port and all sort of things),
.br .br
\fBChristian Franke\fP (Windows interface, C++ redesign, most enhancements \fBDouglas Gilbert\fP (SCSI subsystem),
since 2009)
.br .br
\fBsmartmontools\-support@lists.sourceforge.net\fP \fBVolker Kuhlmann\fP (moderator of support and database mailing list),
.br
\fBGabriele Pohl\fP (wiki & development team support),
.br
\fBAlex Samorukov\fP (FreeBSD port and more, new Trac wiki).
The following have made large contributions to smartmontools: Many other individuals have made contributions and corrections,
.br see AUTHORS, ChangeLog and repository files.
\fBCasper Dik\fP (Solaris SCSI interface)
.br
\fBDouglas Gilbert\fP (SCSI subsystem)
.br
\fBGuido Guenther\fP (Autoconf/Automake packaging)
.br
\fBGeoffrey Keating\fP (Darwin ATA interface)
.br
\fBEduard Martinescu\fP (FreeBSD interface)
.br
\fBFr\['e]d\['e]ric L. W. Meunier\fP (Web site and Mailing list)
.br
\fBGabriele Pohl\fP (Web site and Wiki, conversion from CVS to SVN)
.br
\fBKeiji Sawada\fP (Solaris ATA interface)
.br
\fBManfred Schwarb\fP (Drive database)
.br
\fBSergey Svishchev\fP (NetBSD interface)
.br
\fBDavid Snyder and Sergey Svishchev\fP (OpenBSD interface)
.br
\fBPhil Williams\fP (User interface and drive database)
.br
\fBShengfeng Zhou\fP (Linux/FreeBSD HighPoint RocketRAID interface)
.br
Many other individuals have made smaller contributions and corrections.
The first smartmontools code was derived from the smartsuite package, The first smartmontools code was derived from the smartsuite package,
written by Michael Cornwell, and from the previous UCSC smartsuite package. written by Michael Cornwell and Andre Hedrick.
This code was originally developed as a
Senior Thesis by Michael Cornwell at the Concurrent Systems Laboratory .SH REPORTING BUGS
(now part of the Storage Systems Research Center), Jack Baskin School To submit a bug report, create a ticket in smartmontools wiki:
of Engineering, University of California, Santa .br
Cruz. \fBhttp://ssrc.soe.ucsc.edu/\fP . <\fBhttp://www.smartmontools.org/\fP>.
.br
Alternatively send the info to the smartmontools support mailing list:
.br
<\fBhttps://lists.sourceforge.net/lists/listinfo/smartmontools-support\fB>.
.SH SEE ALSO .SH SEE ALSO
\fBsmartd.conf\fP(5), \fBsmartctl\fP(8), \fBupdate-smart-drivedb\fP(8). \fBsmartd.conf\fP(5), \fBsmartctl\fP(8).
.\" %IF ENABLE_UPDATE_SMART_DRIVEDB
.br
\fBupdate-smart-drivedb\fP(8).
.\" %ENDIF ENABLE_UPDATE_SMART_DRIVEDB
.SH REFERENCES .SH REFERENCES
Please see the following web site for more info: Please see the following web site for more info:
\fBhttp://smartmontools.sourceforge.net/\fP \fBhttp://www.smartmontools.org/\fP
An introductory article about smartmontools is \fIMonitoring Hard An introductory article about smartmontools is \fIMonitoring Hard
Disks with SMART\fP, by Bruce Allen, Linux Journal, January 2004, Disks with SMART\fP, by Bruce Allen, Linux Journal, January 2004,
@ -790,5 +790,7 @@ publications of the Small Form Factors (SFF) Committee.
Links to these and other documents may be found on the Links page of the Links to these and other documents may be found on the Links page of the
\fBsmartmontools\fP Wiki at \fBhttp://www.smartmontools.org/wiki/Links\fP . \fBsmartmontools\fP Wiki at \fBhttp://www.smartmontools.org/wiki/Links\fP .
.SH SVN ID OF THIS PAGE .SH PACKAGE VERSION
$Id: smartd.8.in 3965 2014-07-20 14:46:41Z chrfranke $ CURRENT_SVN_VERSION CURRENT_SVN_DATE CURRENT_SVN_REV
.br
$Id: smartd.8.in 4299 2016-04-16 19:45:57Z chrfranke $

View File

@ -1,8 +1,8 @@
# Sample configuration file for smartd. See man smartd.conf. # Sample configuration file for smartd. See man smartd.conf.
# Home page is: http://smartmontools.sourceforge.net # Home page is: http://www.smartmontools.org
# $Id: smartd.conf 3651 2012-10-18 15:11:36Z samm2 $ # $Id: smartd.conf 4120 2015-08-27 16:12:21Z samm2 $
# smartd will re-read the configuration file if it receives a HUP # smartd will re-read the configuration file if it receives a HUP
# signal # signal
@ -33,21 +33,21 @@ DEVICESCAN
# and min/max temperatures. # and min/max temperatures.
#DEVICESCAN -I 194 -I 231 -I 9 -W 5 #DEVICESCAN -I 194 -I 231 -I 9 -W 5
# First (primary) ATA/IDE hard disk. Monitor all attributes, enable # First ATA/SATA or SCSI/SAS disk. Monitor all attributes, enable
# automatic online data collection, automatic Attribute autosave, and # automatic online data collection, automatic Attribute autosave, and
# start a short self-test every day between 2-3am, and a long self test # start a short self-test every day between 2-3am, and a long self test
# Saturdays between 3-4am. # Saturdays between 3-4am.
#/dev/hda -a -o on -S on -s (S/../.././02|L/../../6/03) #/dev/sda -a -o on -S on -s (S/../.././02|L/../../6/03)
# Monitor SMART status, ATA Error Log, Self-test log, and track # Monitor SMART status, ATA Error Log, Self-test log, and track
# changes in all attributes except for attribute 194 # changes in all attributes except for attribute 194
#/dev/hdb -H -l error -l selftest -t -I 194 #/dev/sdb -H -l error -l selftest -t -I 194
# Monitor all attributes except normalized Temperature (usually 194), # Monitor all attributes except normalized Temperature (usually 194),
# but track Temperature changes >= 4 Celsius, report Temperatures # but track Temperature changes >= 4 Celsius, report Temperatures
# >= 45 Celsius and changes in Raw value of Reallocated_Sector_Ct (5). # >= 45 Celsius and changes in Raw value of Reallocated_Sector_Ct (5).
# Send mail on SMART failures or when Temperature is >= 55 Celsius. # Send mail on SMART failures or when Temperature is >= 55 Celsius.
#/dev/hdc -a -I 194 -W 4,45,55 -R 5 -m admin@example.com #/dev/sdc -a -I 194 -W 4,45,55 -R 5 -m admin@example.com
# An ATA disk may appear as a SCSI device to the OS. If a SCSI to # An ATA disk may appear as a SCSI device to the OS. If a SCSI to
# ATA Translation (SAT) layer is between the OS and the device then # ATA Translation (SAT) layer is between the OS and the device then
@ -57,7 +57,7 @@ DEVICESCAN
# A very silent check. Only report SMART health status if it fails # A very silent check. Only report SMART health status if it fails
# But send an email in this case # But send an email in this case
#/dev/hdc -H -C 0 -U 0 -m admin@example.com #/dev/sdc -H -C 0 -U 0 -m admin@example.com
# First two SCSI disks. This will monitor everything that smartd can # First two SCSI disks. This will monitor everything that smartd can
# monitor. Start extended self-tests Wednesdays between 6-7pm and # monitor. Start extended self-tests Wednesdays between 6-7pm and
@ -141,5 +141,5 @@ DEVICESCAN
# All but -d, -m and -M Directives are only implemented for ATA devices # All but -d, -m and -M Directives are only implemented for ATA devices
# #
# If the test string DEVICESCAN is the first uncommented text # If the test string DEVICESCAN is the first uncommented text
# then smartd will scan for devices /dev/hd[a-l] and /dev/sd[a-z] # then smartd will scan for devices.
# DEVICESCAN may be followed by any desired Directives. # DEVICESCAN may be followed by any desired Directives.

View File

@ -1,8 +1,8 @@
.ig .ig
Copyright (C) 2002-10 Bruce Allen <smartmontools-support@lists.sourceforge.net> Copyright (C) 2002-10 Bruce Allen
Copyright (C) 2004-14 Christian Franke <smartmontools-support@lists.sourceforge.net> Copyright (C) 2004-16 Christian Franke
$Id: smartd.conf.5.in 3965 2014-07-20 14:46:41Z chrfranke $ $Id: smartd.conf.5.in 4307 2016-04-24 12:37:31Z chrfranke $
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -18,13 +18,10 @@ Research Center), Jack Baskin School of Engineering, University of
California, Santa Cruz. http://ssrc.soe.ucsc.edu/ California, Santa Cruz. http://ssrc.soe.ucsc.edu/
.. ..
.TH SMARTD.CONF 5 CURRENT_SVN_DATE CURRENT_SVN_VERSION CURRENT_SVN_DATE .TH SMARTD.CONF 5 "CURRENT_SVN_DATE" "CURRENT_SVN_VERSION" "SMART Monitoring Tools"
.SH NAME .SH NAME
\fBsmartd.conf\fP \- SMART Disk Monitoring Daemon Configuration File\fP \fBsmartd.conf\fP \- SMART Disk Monitoring Daemon Configuration File\fP
.SH PACKAGE VERSION
CURRENT_SVN_VERSION CURRENT_SVN_DATE CURRENT_SVN_REV
.SH DESCRIPTION .SH DESCRIPTION
.\" %IF NOT OS ALL .\" %IF NOT OS ALL
.\"! [This man page is generated for the OS_MAN_FILTER version of smartmontools. .\"! [This man page is generated for the OS_MAN_FILTER version of smartmontools.
@ -90,27 +87,17 @@ Section below!
.nf .nf
.B ################################################ .B ################################################
.B # This is an example smartd startup config file .B # This is an example smartd startup config file
.B # /usr/local/etc/smartd.conf for monitoring three .B # /usr/local/etc/smartd.conf
.B # ATA disks, three SCSI disks, six ATA disks
.B # behind two 3ware controllers, three SATA disks
.B # directly connected to the HighPoint Rocket-
.B # RAID controller, two SATA disks connected to
.B # the HighPoint RocketRAID controller via a pmport
.B # device, four SATA disks connected to an Areca
.B # RAID controller, and one SATA disk.
.B # .B #
.B # First ATA disk on two different interfaces. On .B # On the second disk, start a long self-test every
.B # the second disk, start a long self-test every
.B # Sunday between 3 and 4 am. .B # Sunday between 3 and 4 am.
.B # .B #
.B \ \ /dev/hda -a -m admin@example.com,root@localhost .B \ \ /dev/sda -a -m admin@example.com,root@localhost
.B \ \ /dev/hdc -a -I 194 -I 5 -i 12 -s L/../../7/03 .B \ \ /dev/sdb -a -I 194 -I 5 -i 12 -s L/../../7/03
.B # .B #
.B # SCSI disks. Send a TEST warning email to admin on .B # Send a TEST warning email to admin on startup.
.B # startup.
.B # .B #
.B \ \ /dev/sda .B \ \ /dev/sdc -m admin@example.com -M test
.B \ \ /dev/sdb -m admin@example.com -M test
.B # .B #
.B # Strange device. It\'s SCSI. Start a scheduled .B # Strange device. It\'s SCSI. Start a scheduled
.B # long self test between 5 and 6 am Monday/Thursday .B # long self test between 5 and 6 am Monday/Thursday
@ -220,7 +207,7 @@ Section below!
.B # and Usage Attributes, apart from Attributes .B # and Usage Attributes, apart from Attributes
.B # 9, 194, and 231, and shows continued lines: .B # 9, 194, and 231, and shows continued lines:
.B # .B #
.B \ \ /dev/hdd\ -l\ error\ \e .B \ \ /dev/sdd\ -l\ error\ \e
.B \ \ \ \ \ \ \ \ \ \ \ -l\ selftest\ \e .B \ \ \ \ \ \ \ \ \ \ \ -l\ selftest\ \e
.B \ \ \ \ \ \ \ \ \ \ \ -t\ \e\ \ \ \ \ \ # Attributes not tracked: .B \ \ \ \ \ \ \ \ \ \ \ -t\ \e\ \ \ \ \ \ # Attributes not tracked:
.B \ \ \ \ \ \ \ \ \ \ \ -I\ 194\ \e\ \ # temperature .B \ \ \ \ \ \ \ \ \ \ \ -I\ 194\ \e\ \ # temperature
@ -335,6 +322,18 @@ from issuing SCSI commands to an ATA device.
\fBsmartd\fP \fBsmartd\fP
from issuing ATA commands to a SCSI device. from issuing ATA commands to a SCSI device.
.\" %ENDIF NOT OS Darwin
.\" %IF OS FreeBSD Linux Windows Cygwin
.I nvme[,NSID]
\- [FreeBSD, Linux, Windows and Cygwin only] [NEW EXPERIMENTAL SMARTD FEATURE]
the device type is NVM Express (NVMe).
The optional parameter NSID specifies the namespace id (in hex) passed
to the driver.
Use 0xffffffff for the broadcast namespace id.
The default for NSID is the namespace id addressed by the device name.
.\" %ENDIF OS FreeBSD Linux Windows Cygwin
.\" %IF NOT OS Darwin
.I sat[,auto][,N] .I sat[,auto][,N]
\- the device type is SCSI to ATA Translation (SAT). \- the device type is SCSI to ATA Translation (SAT).
This is for ATA disks that have a SCSI to ATA Translation (SAT) Layer This is for ATA disks that have a SCSI to ATA Translation (SAT) Layer
@ -369,13 +368,17 @@ 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 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. PORT does not exist or is not connected to a disk.
[NEW EXPERIMENTAL SMARTD FEATURE]
The Prolific PL2507/3507 USB bridges with older firmware support a pass-through The Prolific PL2507/3507 USB bridges with older firmware support a pass-through
command similar to JMicron and work with \'\-d usbjmicron,0\'. command similar to JMicron and work with \'\-d usbjmicron,0\'.
Newer Prolific firmware requires a modified command which can be selected by Newer Prolific firmware requires a modified command which can be selected by
\'\-d usbjmicron,p\'. \'\-d usbjmicron,p\'.
Note that this does not yet support the SMART status command. Note that this does not yet support the SMART status command.
.I usbprolific
\- [NEW EXPERIMENTAL SMARTD FEATURE]
this device type is for SATA disks that are behind a Prolific PL2571/2771/2773/2775
USB to SATA bridge.
.I usbsunplus .I usbsunplus
\- this device type is for SATA disks that are behind a SunplusIT USB to SATA \- this device type is for SATA disks that are behind a SunplusIT USB to SATA
bridge. bridge.
@ -397,15 +400,17 @@ It is possible to set RAID device name as /dev/bus/N, where N is a SCSI bus
number. number.
Please see the \fBsmartctl\fP(8) man page for further details. Please see the \fBsmartctl\fP(8) man page for further details.
.\" %ENDIF OS Linux
.\" %IF OS Linux Windows Cygwin
.I aacraid,H,L,ID .I aacraid,H,L,ID
\- [Linux only] [NEW EXPERIMENTAL SMARTD FEATURE] \- [Linux, Windows and Cygwin only] [NEW EXPERIMENTAL SMARTD FEATURE]
the device consists of one or more SCSI/SAS disks connected to an AacRaid controller. the device consists of one or more SCSI/SAS disks connected to an AacRaid controller.
The non-negative integers H,L,ID (Host number, Lun, ID) denote which disk The non-negative integers H,L,ID (Host number, Lun, ID) denote which disk
on the controller is monitored. on the controller is monitored.
In log files and email messages this disk will be identified as aacraid_disk_HH_LL_ID. In log files and email messages this disk will be identified as aacraid_disk_HH_LL_ID.
Please see the \fBsmartctl\fP(8) man page for further details. Please see the \fBsmartctl\fP(8) man page for further details.
.\" %ENDIF OS Linux .\" %ENDIF OS Linux Windows Cygwin
.\" %IF OS FreeBSD Linux .\" %IF OS FreeBSD Linux
.I 3ware,N .I 3ware,N
\- [FreeBSD and Linux only] the device consists of one or more ATA disks \- [FreeBSD and Linux only] the device consists of one or more ATA disks
@ -432,8 +437,8 @@ areca_disk_XX with XX in the range from 01 to 24 inclusive.
Please see the \fBsmartctl\fP(8) man page for further details. Please see the \fBsmartctl\fP(8) man page for further details.
.I areca,N/E .I areca,N/E
\- [FreeBSD, Linux, Windows and Cygwin only] [NEW EXPERIMENTAL SMARTD FEATURE] the \- [FreeBSD, Linux, Windows and Cygwin only] the device consists of one
device consists of one or more SATA or SAS disks connected to an Areca SAS RAID controller. or more SATA or SAS disks connected to an Areca SAS RAID controller.
The integer N (range 1 to 128) denotes the channel (slot) and E (range The integer N (range 1 to 128) denotes the channel (slot) and E (range
1 to 8) denotes the enclosure. 1 to 8) denotes the enclosure.
Important: This requires Areca SAS controller firmware version 1.51 or later. Important: This requires Areca SAS controller firmware version 1.51 or later.
@ -463,8 +468,7 @@ Please see the \fBsmartctl\fP(8) man page for further details.
.\" %ENDIF OS FreeBSD Linux .\" %ENDIF OS FreeBSD Linux
.I ignore .I ignore
\- [NEW EXPERIMENTAL SMARTD FEATURE] \- the device specified by this configuration entry should be ignored.
the device specified by this configuration entry should be ignored.
This allows to ignore specific devices which are detected by a following This allows to ignore specific devices which are detected by a following
DEVICESCAN configuration line. DEVICESCAN configuration line.
It may also be used to temporary disable longer multi-line configuration entries. It may also be used to temporary disable longer multi-line configuration entries.
@ -574,24 +578,41 @@ Directive are \fIon\fP and \fIoff\fP. Also affects SCSI devices.
[Please see the \fBsmartctl \-S\fP command-line option.] [Please see the \fBsmartctl \-S\fP command-line option.]
.TP .TP
.B \-H .B \-H
[ATA only] Check the SMART health status of the disk. If any Prefailure [ATA] Check the health status of the disk with the SMART RETURN
Attributes are less than or equal to their threshold values, then disk STATUS command.
If this command reports a failing health status, then disk
failure is predicted in less than 24 hours, and a message at loglevel failure is predicted in less than 24 hours, and a message at loglevel
.B \'LOG_CRIT\' .B \'LOG_CRIT\'
will be logged to syslog. [Please see the will be logged to syslog. [Please see the
.B smartctl \-H .B smartctl \-H
command-line option.] command-line option.]
.\" %IF OS FreeBSD Linux Windows Cygwin
[NVMe] [FreeBSD, Linux, Windows and Cygwin only]
[NEW EXPERIMENTAL SMARTD FEATURE]
Checks the "Critical Warning" byte from the SMART/Health Information log.
If any warning bit is set, a message at loglevel \fB\'LOG_CRIT\'\fP
will be logged to syslog.
.\" %ENDIF OS FreeBSD Linux Windows Cygwin
.TP .TP
.B \-l TYPE .B \-l TYPE
Reports increases in the number of errors in one of three SMART logs. The Reports increases in the number of errors in one of three SMART logs. The
valid arguments to this Directive are: valid arguments to this Directive are:
.I error .I error
\- [ATA only] report if the number of ATA errors reported in the Summary SMART \- [ATA] report if the number of ATA errors reported in the Summary SMART
error log has increased since the last check. error log has increased since the last check.
.\" %IF OS FreeBSD Linux Windows Cygwin
.I error
\- [NVMe] [FreeBSD, Linux, Windows and Cygwin only]
[NEW EXPERIMENTAL SMARTD FEATURE]
report if the "Number of Error Information Log Entries" from the
SMART/Health Information log has increased since the last check.
.\" %ENDIF OS FreeBSD Linux Windows Cygwin
.I xerror .I xerror
\- [ATA only] report if the number of ATA errors reported in the Extended \- [ATA] report if the number of ATA errors reported in the Extended
Comprehensive SMART error log has increased since the last check. Comprehensive SMART error log has increased since the last check.
If both \'\-l error\' and \'\-l xerror\' are specified, smartd checks If both \'\-l error\' and \'\-l xerror\' are specified, smartd checks
@ -599,6 +620,13 @@ the maximum of both values.
[Please see the \fBsmartctl \-l xerror\fP command-line option.] [Please see the \fBsmartctl \-l xerror\fP command-line option.]
.\" %IF OS FreeBSD Linux Windows Cygwin
.I xerror
\- [NVMe] [FreeBSD, Linux, Windows and Cygwin only]
[NEW EXPERIMENTAL SMARTD FEATURE]
same as \'-l error\'.
.\" %ENDIF OS FreeBSD Linux Windows Cygwin
.I selftest .I selftest
\- report if the number of failed tests reported in the SMART \- report if the number of failed tests reported in the SMART
Self-Test Log has increased since the last check, or if the timestamp Self-Test Log has increased since the last check, or if the timestamp
@ -868,7 +896,6 @@ below.
.\" %IF ENABLE_SMARTDPLUGINDIR .\" %IF ENABLE_SMARTDPLUGINDIR
.\" %IF NOT OS Windows .\" %IF NOT OS Windows
[NEW EXPERIMENTAL SMARTD FEATURE]
If a word of the comma separated list has the form \'@plugin\', a custom If a word of the comma separated list has the form \'@plugin\', a custom
script /usr/local/etc/smartd_warning.d/plugin is run and the word is script /usr/local/etc/smartd_warning.d/plugin is run and the word is
removed from the list before sending mail. The string \'plugin\' may be any removed from the list before sending mail. The string \'plugin\' may be any
@ -881,9 +908,8 @@ This is handled by the script /usr/local/etc/smartd_warning.sh
.\" %ENDIF ENABLE_SMARTDPLUGINDIR .\" %ENDIF ENABLE_SMARTDPLUGINDIR
.\" %IF OS Windows .\" %IF OS Windows
[Windows only] [NEW EXPERIMENTAL SMARTD FEATURE] [Windows only] If one of the following words are used as the first address
If one of the following words are used as the first address in the in the comma separated list, warning messages are sent via WTSSendMessage().
comma separated list, warning messages are sent via WTSSendMessage().
This displays message boxes on the desktops of the selected sessions. This displays message boxes on the desktops of the selected sessions.
Address \'\fBconsole\fP\' specifies the console session only, Address \'\fBconsole\fP\' specifies the console session only,
\'\fBactive\fP\' specifies the console session and all active remote \'\fBactive\fP\' specifies the console session and all active remote
@ -891,8 +917,6 @@ sessions, and \'\fBconnected\fP\' specifies the console session and
all connected (active or waiting for login) remote sessions. all connected (active or waiting for login) remote sessions.
This is handled by the script EXEDIR/smartd_warning.cmd which runs This is handled by the script EXEDIR/smartd_warning.cmd which runs
the tool EXEDIR/wtssendmsg.exe (see also \'\-M exec\' below). the tool EXEDIR/wtssendmsg.exe (see also \'\-M exec\' below).
The addresses \'\fBmsgbox\fP\' and \'\fBsysmsgbox\fP\' are now
deprecated and have the same effect as \'\fBconsole\fP\'.
.\" %ENDIF OS Windows .\" %ENDIF OS Windows
.TP .TP
.B \-M TYPE .B \-M TYPE
@ -978,7 +1002,7 @@ exported by \fBsmartd\fP are:
is set to the argument of \-M exec, if present or else to \'mail\' is set to the argument of \-M exec, if present or else to \'mail\'
(examples: /usr/local/bin/mail, mail). (examples: /usr/local/bin/mail, mail).
.IP \fBSMARTD_DEVICE\fP 4 .IP \fBSMARTD_DEVICE\fP 4
is set to the device path (examples: /dev/hda, /dev/sdb). is set to the device path (example: /dev/sda).
.IP \fBSMARTD_DEVICETYPE\fP 4 .IP \fBSMARTD_DEVICETYPE\fP 4
is set to the device type specified by \'-d\' directive or is set to the device type specified by \'-d\' directive or
\'auto\' if none. \'auto\' if none.
@ -1082,10 +1106,6 @@ It it set to empty on \'\-M once\' and set to \'1\' on \'\-M daily\'.
.\" They define a non-existent option; useful because man2html can't correctly reset the margins. .\" They define a non-existent option; useful because man2html can't correctly reset the margins.
.TP .TP
.B \& .B \&
The shell which is used to run PATH is system-dependent. For vanilla
Linux/glibc it\'s bash. For other systems, the man page for
\fBpopen\fP(3) should say what shell is used.
If the \'\-m ADD\' Directive is given with a normal address argument, If the \'\-m ADD\' Directive is given with a normal address argument,
then the executable pointed to by PATH will be run in a shell with then the executable pointed to by PATH will be run in a shell with
STDIN receiving the body of the email message, and with the same STDIN receiving the body of the email message, and with the same
@ -1130,7 +1150,7 @@ Some sample scripts are also included in
/usr/local/share/doc/smartmontools/examplescripts/. /usr/local/share/doc/smartmontools/examplescripts/.
.\" %ENDIF NOT OS Windows .\" %ENDIF NOT OS Windows
[NEW EXPERIMENTAL SMARTD FEATURE] The executable is run by the script The executable is run by the script
.\" %IF NOT OS Windows .\" %IF NOT OS Windows
/usr/local/etc/smartd_warning.sh. /usr/local/etc/smartd_warning.sh.
.\" %ENDIF NOT OS Windows .\" %ENDIF NOT OS Windows
@ -1339,6 +1359,12 @@ To combine all of the above reports, use:
For ATA devices, smartd interprets Attribute 194 or 190 as Temperature Celsius For ATA devices, smartd interprets Attribute 194 or 190 as Temperature Celsius
by default. This can be changed to Attribute 9 or 220 by the drive by default. This can be changed to Attribute 9 or 220 by the drive
database or by the \'\-v 9,temp\' or \'\-v 220,temp\' directive. database or by the \'\-v 9,temp\' or \'\-v 220,temp\' directive.
.\" %IF OS FreeBSD Linux Windows Cygwin
[NEW EXPERIMENTAL SMARTD FEATURE]
For NVMe devices, smartd checks the maximum of the Composite Temperature value
and all Temperature Sensor values reported by SMART/Health Information log.
.\" %ENDIF OS FreeBSD Linux Windows Cygwin
.TP .TP
.B \-F TYPE .B \-F TYPE
[ATA only] Modifies the behavior of \fBsmartd\fP to compensate for some [ATA only] Modifies the behavior of \fBsmartd\fP to compensate for some
@ -1492,8 +1518,11 @@ will do the same, but restricts the scan to ATA devices only.
will do the same, but only monitors the SMART health status of the will do the same, but only monitors the SMART health status of the
devices, (rather than the default \-a, which monitors all SMART devices, (rather than the default \-a, which monitors all SMART
properties). properties).
.br
[NEW EXPERIMENTAL SMARTD FEATURE] [NEW EXPERIMENTAL SMARTD FEATURE]
Multiple \'\-d TYPE\' options may be specified with DEVICESCAN
to combine the scan results of more than one TYPE.
Configuration entries for specific devices may precede the \fBDEVICESCAN\fP entry. Configuration entries for specific devices may precede the \fBDEVICESCAN\fP entry.
For example For example
.nf .nf
@ -1581,5 +1610,7 @@ full path of this file.
\fBsmartd\fP(8), \fBsmartctl\fP(8), \fBsmartd\fP(8), \fBsmartctl\fP(8),
\fBmail\fP(1), \fBregex\fP(7). \fBmail\fP(1), \fBregex\fP(7).
.SH SVN ID OF THIS PAGE .SH PACKAGE VERSION
$Id: smartd.conf.5.in 3965 2014-07-20 14:46:41Z chrfranke $ CURRENT_SVN_VERSION CURRENT_SVN_DATE CURRENT_SVN_REV
.br
$Id: smartd.conf.5.in 4307 2016-04-24 12:37:31Z chrfranke $

View File

@ -1,10 +1,10 @@
/* /*
* Home page of code is: http://smartmontools.sourceforge.net * Home page of code is: http://www.smartmontools.org
* *
* Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2002-11 Bruce Allen
* Copyright (C) 2008-16 Christian Franke
* Copyright (C) 2000 Michael Cornwell <cornwell@acm.org> * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
* Copyright (C) 2008 Oliver Bock <brevilo@users.sourceforge.net> * Copyright (C) 2008 Oliver Bock <brevilo@users.sourceforge.net>
* Copyright (C) 2008-14 Christian Franke <smartmontools-support@lists.sourceforge.net>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -51,9 +51,6 @@
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
#include <unistd.h> #include <unistd.h>
#endif #endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#ifdef _WIN32 #ifdef _WIN32
#ifdef _MSC_VER #ifdef _MSC_VER
@ -78,6 +75,7 @@ typedef int pid_t;
#include "dev_interface.h" #include "dev_interface.h"
#include "knowndrives.h" #include "knowndrives.h"
#include "scsicmds.h" #include "scsicmds.h"
#include "nvmecmds.h"
#include "utility.h" #include "utility.h"
// This is for solaris, where signal() resets the handler to SIG_DFL // This is for solaris, where signal() resets the handler to SIG_DFL
@ -102,13 +100,11 @@ typedef int pid_t;
#define SIGQUIT_KEYNAME "CONTROL-\\" #define SIGQUIT_KEYNAME "CONTROL-\\"
#endif // _WIN32 #endif // _WIN32
#if defined (__SVR4) && defined (__sun) const char * smartd_cpp_cvsid = "$Id: smartd.cpp 4308 2016-04-24 13:36:10Z chrfranke $"
extern "C" int getdomainname(char *, int); // no declaration in header files!
#endif
const char * smartd_cpp_cvsid = "$Id: smartd.cpp 3948 2014-07-13 16:53:30Z chrfranke $"
CONFIG_H_CVSID; CONFIG_H_CVSID;
using namespace smartmontools;
// smartd exit codes // smartd exit codes
#define EXIT_BADCMD 1 // command line did not parse #define EXIT_BADCMD 1 // command line did not parse
#define EXIT_BADCONF 2 // syntax error in config file #define EXIT_BADCONF 2 // syntax error in config file
@ -385,19 +381,24 @@ struct persistent_dev_state
// SCSI ONLY // SCSI ONLY
struct scsi_error_counter { struct scsi_error_counter_t {
struct scsiErrorCounter errCounter; struct scsiErrorCounter errCounter;
unsigned char found; unsigned char found;
scsi_error_counter() : found(0) { } scsi_error_counter_t() : found(0)
{ memset(&errCounter, 0, sizeof(errCounter)); }
}; };
scsi_error_counter scsi_error_counters[3]; scsi_error_counter_t scsi_error_counters[3];
struct scsi_nonmedium_error { struct scsi_nonmedium_error_t {
struct scsiNonMediumError nme; struct scsiNonMediumError nme;
unsigned char found; unsigned char found;
scsi_nonmedium_error() : found(0) { } scsi_nonmedium_error_t() : found(0)
{ memset(&nme, 0, sizeof(nme)); }
}; };
scsi_nonmedium_error scsi_nonmedium_error; scsi_nonmedium_error_t scsi_nonmedium_error;
// NVMe only
uint64_t nvme_err_log_entries;
persistent_dev_state(); persistent_dev_state();
}; };
@ -409,7 +410,8 @@ persistent_dev_state::persistent_dev_state()
scheduled_test_next_check(0), scheduled_test_next_check(0),
selective_test_last_start(0), selective_test_last_start(0),
selective_test_last_end(0), selective_test_last_end(0),
ataerrorcount(0) ataerrorcount(0),
nvme_err_log_entries(0)
{ {
} }
@ -429,6 +431,7 @@ struct temp_dev_state
bool powermodefail; // true if power mode check failed bool powermodefail; // true if power mode check failed
int powerskipcnt; // Number of checks skipped due to idle or standby mode int powerskipcnt; // Number of checks skipped due to idle or standby mode
int lastpowermodeskipped; // the last power mode that was skipped
// SCSI ONLY // SCSI ONLY
unsigned char SmartPageSupported; // has log sense IE page (0x2f) unsigned char SmartPageSupported; // has log sense IE page (0x2f)
@ -461,6 +464,7 @@ temp_dev_state::temp_dev_state()
tempmin_delay(0), tempmin_delay(0),
powermodefail(false), powermodefail(false),
powerskipcnt(0), powerskipcnt(0),
lastpowermodeskipped(0),
SmartPageSupported(false), SmartPageSupported(false),
TempPageSupported(false), TempPageSupported(false),
ReadECounterPageSupported(false), ReadECounterPageSupported(false),
@ -566,12 +570,13 @@ static bool parse_dev_state_line(const char * line, persistent_dev_state & state
"|(resvd)" // (23) "|(resvd)" // (23)
")" // 18) ")" // 18)
")" // 16) ")" // 16)
"|(nvme-err-log-entries)" // (24)
")" // 1) ")" // 1)
" *= *([0-9]+)[ \n]*$", // (24) " *= *([0-9]+)[ \n]*$", // (25)
REG_EXTENDED REG_EXTENDED
); );
const int nmatch = 1+24; const int nmatch = 1+25;
regmatch_t match[nmatch]; regmatch_t match[nmatch];
if (!regex.execute(line, nmatch, match)) if (!regex.execute(line, nmatch, match))
return false; return false;
@ -629,6 +634,8 @@ static bool parse_dev_state_line(const char * line, persistent_dev_state & state
else else
return false; return false;
} }
else if (match[m+7].rm_so >= 0)
state.nvme_err_log_entries = val;
else else
return false; return false;
return true; return true;
@ -734,6 +741,9 @@ static bool write_dev_state(const char * path, const persistent_dev_state & stat
write_dev_state_line(f, "ata-smart-attribute", i, "resvd", pa.resvd); write_dev_state_line(f, "ata-smart-attribute", i, "resvd", pa.resvd);
} }
// NVMe only
write_dev_state_line(f, "nvme-err-log-entries", state.nvme_err_log_entries);
return true; return true;
} }
@ -884,10 +894,6 @@ static int Goodbye(int status)
// delete PID file, if one was created // delete PID file, if one was created
RemovePidFile(); RemovePidFile();
// if we are exiting because of a code bug, tell user
if (status==EXIT_BADCODE)
PrintOut(LOG_CRIT, "Please inform " PACKAGE_BUGREPORT ", including output of smartd -V.\n");
// and this should be the final output from smartd before it exits // and this should be the final output from smartd before it exits
PrintOut(status?LOG_CRIT:LOG_INFO, "smartd is exiting (exit status %d)\n", status); PrintOut(status?LOG_CRIT:LOG_INFO, "smartd is exiting (exit status %d)\n", status);
@ -1056,13 +1062,13 @@ static void MailWarning(const dev_config & cfg, dev_state & state, int which, co
env[11].set("SMARTD_NEXTDAYS", dates); env[11].set("SMARTD_NEXTDAYS", dates);
// now construct a command to send this as EMAIL // now construct a command to send this as EMAIL
char command[2048];
if (!*executable) if (!*executable)
executable = "<mail>"; executable = "<mail>";
const char * newadd = (!address.empty()? address.c_str() : "<nomailer>"); const char * newadd = (!address.empty()? address.c_str() : "<nomailer>");
const char * newwarn = (which? "Warning via" : "Test of"); const char * newwarn = (which? "Warning via" : "Test of");
#ifndef _WIN32 #ifndef _WIN32
char command[2048];
snprintf(command, sizeof(command), "%s 2>&1", warning_script.c_str()); snprintf(command, sizeof(command), "%s 2>&1", warning_script.c_str());
// tell SYSLOG what we are about to do... // tell SYSLOG what we are about to do...
@ -1109,12 +1115,9 @@ static void MailWarning(const dev_config & cfg, dev_state & state, int which, co
errno?strerror(errno):""); errno?strerror(errno):"");
else { else {
// mail process apparently succeeded. Check and report exit status // mail process apparently succeeded. Check and report exit status
int status8;
if (WIFEXITED(status)) { if (WIFEXITED(status)) {
// exited 'normally' (but perhaps with nonzero status) // exited 'normally' (but perhaps with nonzero status)
status8=WEXITSTATUS(status); int status8 = WEXITSTATUS(status);
if (status8>128) if (status8>128)
PrintOut(LOG_CRIT,"%s %s to %s: failed (32-bit/8-bit exit status: %d/%d) perhaps caught signal %d [%s]\n", PrintOut(LOG_CRIT,"%s %s to %s: failed (32-bit/8-bit exit status: %d/%d) perhaps caught signal %d [%s]\n",
newwarn, executable, newadd, status, status8, status8-128, strsignal(status8-128)); newwarn, executable, newadd, status, status8, status8-128, strsignal(status8-128));
@ -1140,6 +1143,7 @@ static void MailWarning(const dev_config & cfg, dev_state & state, int which, co
#else // _WIN32 #else // _WIN32
{ {
char command[2048];
snprintf(command, sizeof(command), "cmd /c \"%s\"", warning_script.c_str()); snprintf(command, sizeof(command), "cmd /c \"%s\"", warning_script.c_str());
char stdoutbuf[800]; // < buffer in syslog_win32::vsyslog() char stdoutbuf[800]; // < buffer in syslog_win32::vsyslog()
@ -1472,7 +1476,7 @@ static const char *GetValidArgList(char opt)
case 'q': case 'q':
return "nodev, errors, nodevstartup, never, onecheck, showtests"; return "nodev, errors, nodevstartup, never, onecheck, showtests";
case 'r': case 'r':
return "ioctl[,N], ataioctl[,N], scsiioctl[,N]"; return "ioctl[,N], ataioctl[,N], scsiioctl[,N], nvmeioctl[,N]";
case 'B': case 'B':
case 'p': case 'p':
case 'w': case 'w':
@ -1507,7 +1511,7 @@ static void Usage()
PrintOut(LOG_INFO," [default is %s]\n\n", configfile); PrintOut(LOG_INFO," [default is %s]\n\n", configfile);
#ifdef HAVE_LIBCAP_NG #ifdef HAVE_LIBCAP_NG
PrintOut(LOG_INFO," -C, --capabilities\n"); PrintOut(LOG_INFO," -C, --capabilities\n");
PrintOut(LOG_INFO," Use capabilities.\n" PrintOut(LOG_INFO," Drop unneeded Linux process capabilities.\n"
" Warning: Mail notification does not work when used.\n\n"); " Warning: Mail notification does not work when used.\n\n");
#endif #endif
PrintOut(LOG_INFO," -d, --debug\n"); PrintOut(LOG_INFO," -d, --debug\n");
@ -1591,7 +1595,7 @@ static int read_ata_error_count(ata_device * device, const char * name,
} }
else { else {
ata_smart_exterrlog logx; ata_smart_exterrlog logx;
if (!ataReadExtErrorLog(device, &logx, 1 /*first sector only*/, firmwarebugs)) { if (!ataReadExtErrorLog(device, &logx, 0, 1 /*first sector only*/, firmwarebugs)) {
PrintOut(LOG_INFO,"Device: %s, Read Extended Comprehensive SMART Error Log failed\n",name); PrintOut(LOG_INFO,"Device: %s, Read Extended Comprehensive SMART Error Log failed\n",name);
return -1; return -1;
} }
@ -1706,7 +1710,7 @@ static bool check_pending_id(const dev_config & cfg, const dev_state & state,
return true; return true;
} }
// Called by ATA/SCSIDeviceScan() after successful device check // Called by ATA/SCSI/NVMeDeviceScan() after successful device check
static void finish_device_scan(dev_config & cfg, dev_state & state) static void finish_device_scan(dev_config & cfg, dev_state & state)
{ {
// Set cfg.emailfreq if user hasn't set it // Set cfg.emailfreq if user hasn't set it
@ -1808,6 +1812,12 @@ static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atade
} }
} }
// Check for ATA Security LOCK
unsigned short word128 = drive.words088_255[128-88];
bool locked = ((word128 & 0x0007) == 0x0007); // LOCKED|ENABLED|SUPPORTED
if (locked)
PrintOut(LOG_INFO, "Device: %s, ATA Security is **LOCKED**\n", name);
// Set default '-C 197[+]' if no '-C ID' is specified. // Set default '-C 197[+]' if no '-C ID' is specified.
if (!cfg.curr_pending_set) if (!cfg.curr_pending_set)
cfg.curr_pending_id = get_unc_attr_id(false, cfg.attribute_defs, cfg.curr_pending_incr); cfg.curr_pending_id = get_unc_attr_id(false, cfg.attribute_defs, cfg.curr_pending_incr);
@ -1849,9 +1859,13 @@ static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atade
if (ataEnableSmart(atadev)) { if (ataEnableSmart(atadev)) {
// Enable SMART command has failed // Enable SMART command has failed
PrintOut(LOG_INFO,"Device: %s, could not enable SMART capability\n",name); PrintOut(LOG_INFO,"Device: %s, could not enable SMART capability\n",name);
if (ataIsSmartEnabled(&drive) <= 0) {
CloseDevice(atadev, name); CloseDevice(atadev, name);
return 2; return 2;
} }
PrintOut(LOG_INFO, "Device: %s, proceeding since SMART is already enabled\n", name);
}
// disable device attribute autosave... // disable device attribute autosave...
if (cfg.autosave==1) { if (cfg.autosave==1) {
@ -2060,7 +2074,10 @@ static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atade
PrintOut(LOG_CRIT, "Device: %s, no ATA CHECK POWER STATUS support, ignoring -n Directive\n", name); PrintOut(LOG_CRIT, "Device: %s, no ATA CHECK POWER STATUS support, ignoring -n Directive\n", name);
cfg.powermode=0; cfg.powermode=0;
} }
else if (powermode!=0 && powermode!=0x80 && powermode!=0xff) { else if (powermode!=0x00 && powermode!=0x01
&& powermode!=0x40 && powermode!=0x41
&& powermode!=0x80 && powermode!=0x81 && powermode!=0x82 && powermode!=0x83
&& powermode!=0xff) {
PrintOut(LOG_CRIT, "Device: %s, CHECK POWER STATUS returned %d, not ATA compliant, ignoring -n Directive\n", PrintOut(LOG_CRIT, "Device: %s, CHECK POWER STATUS returned %d, not ATA compliant, ignoring -n Directive\n",
name, powermode); name, powermode);
cfg.powermode=0; cfg.powermode=0;
@ -2106,6 +2123,9 @@ static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atade
if (!isSCTErrorRecoveryControlCapable(&drive)) if (!isSCTErrorRecoveryControlCapable(&drive))
PrintOut(LOG_INFO, "Device: %s, no SCT Error Recovery Control support, ignoring -l scterc\n", PrintOut(LOG_INFO, "Device: %s, no SCT Error Recovery Control support, ignoring -l scterc\n",
name); name);
else if (locked)
PrintOut(LOG_INFO, "Device: %s, no SCT support if ATA Security is LOCKED, ignoring -l scterc\n",
name);
else if ( ataSetSCTErrorRecoveryControltime(atadev, 1, cfg.sct_erc_readtime ) else if ( ataSetSCTErrorRecoveryControltime(atadev, 1, cfg.sct_erc_readtime )
|| ataSetSCTErrorRecoveryControltime(atadev, 2, cfg.sct_erc_writetime)) || ataSetSCTErrorRecoveryControltime(atadev, 2, cfg.sct_erc_writetime))
PrintOut(LOG_INFO, "Device: %s, set of SCT Error Recovery Control failed\n", name); PrintOut(LOG_INFO, "Device: %s, set of SCT Error Recovery Control failed\n", name);
@ -2156,7 +2176,7 @@ static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atade
// please. // please.
static int SCSIDeviceScan(dev_config & cfg, dev_state & state, scsi_device * scsidev) static int SCSIDeviceScan(dev_config & cfg, dev_state & state, scsi_device * scsidev)
{ {
int k, err, req_len, avail_len, version, len; int err, req_len, avail_len, version, len;
const char *device = cfg.name.c_str(); const char *device = cfg.name.c_str();
struct scsi_iec_mode_page iec; struct scsi_iec_mode_page iec;
UINT8 tBuf[64]; UINT8 tBuf[64];
@ -2223,7 +2243,7 @@ static int SCSIDeviceScan(dev_config & cfg, dev_state & state, scsi_device * scs
uint64_t capacity = scsiGetSize(scsidev, &lb_size, NULL); uint64_t capacity = scsiGetSize(scsidev, &lb_size, NULL);
if (capacity) if (capacity)
format_capacity(si_str, sizeof(si_str), capacity); format_capacity(si_str, sizeof(si_str), capacity, ".");
else else
si_str[0] = '\0'; si_str[0] = '\0';
@ -2284,8 +2304,11 @@ static int SCSIDeviceScan(dev_config & cfg, dev_state & state, scsi_device * scs
// Flag that certain log pages are supported (information may be // Flag that certain log pages are supported (information may be
// available from other sources). // available from other sources).
if (0 == scsiLogSense(scsidev, SUPPORTED_LPAGES, 0, tBuf, sizeof(tBuf), 0)) { if (0 == scsiLogSense(scsidev, SUPPORTED_LPAGES, 0, tBuf, sizeof(tBuf), 0) ||
for (k = 4; k < tBuf[3] + LOGPAGEHDRSIZE; ++k) { 0 == scsiLogSense(scsidev, SUPPORTED_LPAGES, 0, tBuf, sizeof(tBuf), 68))
/* workaround for the bug #678 on ST8000NM0075/E001. Up to 64 pages + 4b header */
{
for (int k = 4; k < tBuf[3] + LOGPAGEHDRSIZE; ++k) {
switch (tBuf[k]) { switch (tBuf[k]) {
case TEMPERATURE_LPAGE: case TEMPERATURE_LPAGE:
state.TempPageSupported = 1; state.TempPageSupported = 1;
@ -2394,6 +2417,119 @@ static int SCSIDeviceScan(dev_config & cfg, dev_state & state, scsi_device * scs
return 0; return 0;
} }
// Convert 128 bit LE integer to uint64_t or its max value on overflow.
static uint64_t le128_to_uint64(const unsigned char (& val)[16])
{
for (int i = 8; i < 16; i++) {
if (val[i])
return ~(uint64_t)0;
}
uint64_t lo = val[7];
for (int i = 7-1; i >= 0; i--) {
lo <<= 8; lo += val[i];
}
return lo;
}
// Get max temperature in Kelvin reported in NVMe SMART/Health log.
static int nvme_get_max_temp_kelvin(const nvme_smart_log & smart_log)
{
int k = (smart_log.temperature[1] << 8) | smart_log.temperature[0];
for (int i = 0; i < 8; i++) {
if (smart_log.temp_sensor[i] > k)
k = smart_log.temp_sensor[i];
}
return k;
}
static int NVMeDeviceScan(dev_config & cfg, dev_state & state, nvme_device * nvmedev)
{
const char *name = cfg.name.c_str();
// Device must be open
// Get ID Controller
nvme_id_ctrl id_ctrl;
if (!nvme_read_id_ctrl(nvmedev, id_ctrl)) {
PrintOut(LOG_INFO, "Device: %s, NVMe Identify Controller failed\n", name);
CloseDevice(nvmedev, name);
return 2;
}
// Get drive identity
char model[40+1], serial[20+1], firmware[8+1];
format_char_array(model, id_ctrl.mn);
format_char_array(serial, id_ctrl.sn);
format_char_array(firmware, id_ctrl.fr);
// Format device id string for warning emails
char nsstr[32] = "", capstr[32] = "";
unsigned nsid = nvmedev->get_nsid();
if (nsid != 0xffffffff)
snprintf(nsstr, sizeof(nsstr), ", NSID:%u", nsid);
uint64_t capacity = le128_to_uint64(id_ctrl.tnvmcap);
if (capacity)
format_capacity(capstr, sizeof(capstr), capacity, ".");
cfg.dev_idinfo = strprintf("%s, S/N:%s, FW:%s%s%s%s", model, serial, firmware,
nsstr, (capstr[0] ? ", " : ""), capstr);
PrintOut(LOG_INFO, "Device: %s, %s\n", name, cfg.dev_idinfo.c_str());
// Read SMART/Health log
nvme_smart_log smart_log;
if (!nvme_read_smart_log(nvmedev, smart_log)) {
PrintOut(LOG_INFO, "Device: %s, failed to read NVMe SMART/Health Information\n", name);
CloseDevice(nvmedev, name);
return 2;
}
// Check temperature sensor support
if (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit) {
if (!nvme_get_max_temp_kelvin(smart_log)) {
PrintOut(LOG_INFO, "Device: %s, no Temperature sensors, ignoring -W %d,%d,%d\n",
name, cfg.tempdiff, cfg.tempinfo, cfg.tempcrit);
cfg.tempdiff = cfg.tempinfo = cfg.tempcrit = 0;
}
}
// Init total error count
if (cfg.errorlog || cfg.xerrorlog) {
state.nvme_err_log_entries = le128_to_uint64(smart_log.num_err_log_entries);
}
// If no supported tests selected, return
if (!( cfg.smartcheck || cfg.errorlog || cfg.xerrorlog
|| cfg.tempdiff || cfg.tempinfo || cfg.tempcrit )) {
CloseDevice(nvmedev, name);
return 3;
}
// Tell user we are registering device
PrintOut(LOG_INFO,"Device: %s, is SMART capable. Adding to \"monitor\" list.\n", name);
// Make sure that init_standby_check() ignores NVMe devices
cfg.offlinests_ns = cfg.selfteststs_ns = false;
CloseDevice(nvmedev, name);
if (!state_path_prefix.empty()) {
// Build file name for state file
std::replace_if(model, model+strlen(model), not_allowed_in_filename, '_');
std::replace_if(serial, serial+strlen(serial), not_allowed_in_filename, '_');
nsstr[0] = 0;
if (nsid != 0xffffffff)
snprintf(nsstr, sizeof(nsstr), "-n%u", nsid);
cfg.state_file = strprintf("%s%s-%s%s.nvme.state", state_path_prefix.c_str(), model, serial, nsstr);
// Read previous state
if (read_dev_state(cfg.state_file.c_str(), state))
PrintOut(LOG_INFO, "Device: %s, state read from %s\n", name, cfg.state_file.c_str());
}
finish_device_scan(cfg, state);
return 0;
}
// If the self-test log has got more self-test errors (or more recent // If the self-test log has got more self-test errors (or more recent
// self-test errors) recorded, then notify user. // self-test errors) recorded, then notify user.
static void CheckSelfTestLogs(const dev_config & cfg, dev_state & state, int newi) static void CheckSelfTestLogs(const dev_config & cfg, dev_state & state, int newi)
@ -2999,6 +3135,28 @@ static int ATACheckDevice(const dev_config & cfg, dev_state & state, ata_device
if (cfg.emailtest) if (cfg.emailtest)
MailWarning(cfg, state, 0, "TEST EMAIL from smartd for device: %s", name); MailWarning(cfg, state, 0, "TEST EMAIL from smartd for device: %s", name);
// User may have requested (with the -n Directive) to leave the disk
// alone if it is in idle or standby mode. In this case check the
// power mode first before opening the device for full access,
// and exit without check if disk is reported in standby.
if (cfg.powermode && !state.powermodefail) {
// Note that 'is_powered_down()' handles opening the device itself, and
// can be used before calling 'open()' (that's the whole point of 'is_powered_down()'!).
if (atadev->is_powered_down())
{
// skip at most powerskipmax checks
if (!cfg.powerskipmax || state.powerskipcnt<cfg.powerskipmax) {
// report first only except if state has changed, avoid waking up system disk
if ((!state.powerskipcnt || state.lastpowermodeskipped != -1) && !cfg.powerquiet) {
PrintOut(LOG_INFO, "Device: %s, is in %s mode, suspending checks\n", name, "STANDBY (OS)");
state.lastpowermodeskipped = -1;
}
state.powerskipcnt++;
return 0;
}
}
}
// if we can't open device, fail gracefully rather than hard -- // if we can't open device, fail gracefully rather than hard --
// perhaps the next time around we'll be able to open it. ATAPI // perhaps the next time around we'll be able to open it. ATAPI
// cd/dvd devices will hang awaiting media if O_NONBLOCK is not // cd/dvd devices will hang awaiting media if O_NONBLOCK is not
@ -3035,20 +3193,48 @@ static int ATACheckDevice(const dev_config & cfg, dev_state & state, ata_device
if (cfg.powermode>=1) if (cfg.powermode>=1)
dontcheck=1; dontcheck=1;
break; break;
case 0: case 0x00:
// STANDBY // STANDBY
mode="STANDBY"; mode="STANDBY";
if (cfg.powermode>=2) if (cfg.powermode>=2)
dontcheck=1; dontcheck=1;
break; break;
case 0x01:
// STANDBY_Y
mode="STANDBY_Y";
if (cfg.powermode>=2)
dontcheck=1;
break;
case 0x80: case 0x80:
// IDLE // IDLE
mode="IDLE"; mode="IDLE";
if (cfg.powermode>=3) if (cfg.powermode>=3)
dontcheck=1; dontcheck=1;
break; break;
case 0x81:
// IDLE_A
mode="IDLE_A";
if (cfg.powermode>=3)
dontcheck=1;
break;
case 0x82:
// IDLE_B
mode="IDLE_B";
if (cfg.powermode>=3)
dontcheck=1;
break;
case 0x83:
// IDLE_C
mode="IDLE_C";
if (cfg.powermode>=3)
dontcheck=1;
break;
case 0xff: case 0xff:
// ACTIVE/IDLE // ACTIVE/IDLE
case 0x40:
// ACTIVE
case 0x41:
// ACTIVE
mode="ACTIVE or IDLE"; mode="ACTIVE or IDLE";
break; break;
default: default:
@ -3064,8 +3250,11 @@ static int ATACheckDevice(const dev_config & cfg, dev_state & state, ata_device
// skip at most powerskipmax checks // skip at most powerskipmax checks
if (!cfg.powerskipmax || state.powerskipcnt<cfg.powerskipmax) { if (!cfg.powerskipmax || state.powerskipcnt<cfg.powerskipmax) {
CloseDevice(atadev, name); CloseDevice(atadev, name);
if (!state.powerskipcnt && !cfg.powerquiet) // report first only and avoid waking up system disk // report first only except if state has changed, avoid waking up system disk
if ((!state.powerskipcnt || state.lastpowermodeskipped != powermode) && !cfg.powerquiet) {
PrintOut(LOG_INFO, "Device: %s, is in %s mode, suspending checks\n", name, mode); PrintOut(LOG_INFO, "Device: %s, is in %s mode, suspending checks\n", name, mode);
state.lastpowermodeskipped = powermode;
}
state.powerskipcnt++; state.powerskipcnt++;
return 0; return 0;
} }
@ -3218,12 +3407,7 @@ static int ATACheckDevice(const dev_config & cfg, dev_state & state, ata_device
static int SCSICheckDevice(const dev_config & cfg, dev_state & state, scsi_device * scsidev, bool allow_selftests) static int SCSICheckDevice(const dev_config & cfg, dev_state & state, scsi_device * scsidev, bool allow_selftests)
{ {
UINT8 asc, ascq;
UINT8 currenttemp;
UINT8 triptemp;
UINT8 tBuf[252];
const char * name = cfg.name.c_str(); const char * name = cfg.name.c_str();
const char *cp;
// If the user has asked for it, test the email warning system // If the user has asked for it, test the email warning system
if (cfg.emailtest) if (cfg.emailtest)
@ -3238,9 +3422,9 @@ static int SCSICheckDevice(const dev_config & cfg, dev_state & state, scsi_devic
} else if (debugmode) } else if (debugmode)
PrintOut(LOG_INFO,"Device: %s, opened SCSI device\n", name); PrintOut(LOG_INFO,"Device: %s, opened SCSI device\n", name);
reset_warning_mail(cfg, state, 9, "open device worked again"); reset_warning_mail(cfg, state, 9, "open device worked again");
currenttemp = 0;
asc = 0; UINT8 asc = 0, ascq = 0;
ascq = 0; UINT8 currenttemp = 0, triptemp = 0;
if (!state.SuppressReport) { if (!state.SuppressReport) {
if (scsiCheckIE(scsidev, state.SmartPageSupported, state.TempPageSupported, if (scsiCheckIE(scsidev, state.SmartPageSupported, state.TempPageSupported,
&asc, &ascq, &currenttemp, &triptemp)) { &asc, &ascq, &currenttemp, &triptemp)) {
@ -3251,7 +3435,7 @@ static int SCSICheckDevice(const dev_config & cfg, dev_state & state, scsi_devic
} }
} }
if (asc > 0) { if (asc > 0) {
cp = scsiGetIEString(asc, ascq); const char * cp = scsiGetIEString(asc, ascq);
if (cp) { if (cp) {
PrintOut(LOG_CRIT, "Device: %s, SMART Failure: %s\n", name, cp); PrintOut(LOG_CRIT, "Device: %s, SMART Failure: %s\n", name, cp);
MailWarning(cfg, state, 1,"Device: %s, SMART Failure: %s", name, cp); MailWarning(cfg, state, 1,"Device: %s, SMART Failure: %s", name, cp);
@ -3278,6 +3462,7 @@ static int SCSICheckDevice(const dev_config & cfg, dev_state & state, scsi_devic
} }
if (!cfg.attrlog_file.empty()){ if (!cfg.attrlog_file.empty()){
// saving error counters to state // saving error counters to state
UINT8 tBuf[252];
if (state.ReadECounterPageSupported && (0 == scsiLogSense(scsidev, if (state.ReadECounterPageSupported && (0 == scsiLogSense(scsidev,
READ_ERROR_COUNTER_LPAGE, 0, tBuf, sizeof(tBuf), 0))) { READ_ERROR_COUNTER_LPAGE, 0, tBuf, sizeof(tBuf), 0))) {
scsiDecodeErrCounterPage(tBuf, &state.scsi_error_counters[0].errCounter); scsiDecodeErrCounterPage(tBuf, &state.scsi_error_counters[0].errCounter);
@ -3303,6 +3488,89 @@ static int SCSICheckDevice(const dev_config & cfg, dev_state & state, scsi_devic
return 0; return 0;
} }
static int NVMeCheckDevice(const dev_config & cfg, dev_state & state, nvme_device * nvmedev)
{
const char * name = cfg.name.c_str();
// TODO: Use common open function for ATA/SCSI/NVMe
// If user has asked, test the email warning system
if (cfg.emailtest)
MailWarning(cfg, state, 0, "TEST EMAIL from smartd for device: %s", name);
if (!nvmedev->open()) {
PrintOut(LOG_INFO, "Device: %s, open() failed: %s\n", name, nvmedev->get_errmsg());
MailWarning(cfg, state, 9, "Device: %s, unable to open device", name);
return 1;
}
if (debugmode)
PrintOut(LOG_INFO,"Device: %s, opened NVMe device\n", name);
reset_warning_mail(cfg, state, 9, "open device worked again");
// Read SMART/Health log
nvme_smart_log smart_log;
if (!nvme_read_smart_log(nvmedev, smart_log)) {
PrintOut(LOG_INFO, "Device: %s, failed to read NVMe SMART/Health Information\n", name);
MailWarning(cfg, state, 6, "Device: %s, failed to read NVMe SMART/Health Information", name);
state.must_write = true;
return 0;
}
// Check Critical Warning bits
if (cfg.smartcheck && smart_log.critical_warning) {
unsigned char w = smart_log.critical_warning;
std::string msg;
static const char * const wnames[] =
{"LowSpare", "Temperature", "Reliability", "R/O", "VolMemBackup"};
for (unsigned b = 0, cnt = 0; b < 8 ; b++) {
if (!(w & (1 << b)))
continue;
if (cnt)
msg += ", ";
if (++cnt > 3) {
msg += "..."; break;
}
if (b >= sizeof(wnames)/sizeof(wnames[0])) {
msg += "*Unknown*"; break;
}
msg += wnames[b];
}
PrintOut(LOG_CRIT, "Device: %s, Critical Warning (0x%02x): %s\n", name, w, msg.c_str());
MailWarning(cfg, state, 1, "Device: %s, Critical Warning (0x%02x): %s", name, w, msg.c_str());
state.must_write = true;
}
// Check temperature limits
if (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit) {
int k = nvme_get_max_temp_kelvin(smart_log);
// Convert Kelvin to positive Celsius (TODO: Allow negative temperatures)
int c = k - 273;
if (c < 1)
c = 1;
else if (c > 0xff)
c = 0xff;
CheckTemperature(cfg, state, c, 0);
}
// Check if number of errors has increased
if (cfg.errorlog || cfg.xerrorlog) {
uint64_t oldcnt = state.nvme_err_log_entries;
uint64_t newcnt = le128_to_uint64(smart_log.num_err_log_entries);
if (newcnt > oldcnt) {
PrintOut(LOG_CRIT, "Device: %s, number of Error Log entries increased from %" PRIu64 " to %" PRIu64 "\n",
name, oldcnt, newcnt);
MailWarning(cfg, state, 4, "Device: %s, number of Error Log entries increased from %" PRIu64 " to %" PRIu64,
name, oldcnt, newcnt);
state.must_write = true;
}
state.nvme_err_log_entries = newcnt;
}
CloseDevice(nvmedev, name);
return 0;
}
// 0=not used, 1=not disabled, 2=disable rejected by OS, 3=disabled // 0=not used, 1=not disabled, 2=disable rejected by OS, 3=disabled
static int standby_disable_state = 0; static int standby_disable_state = 0;
@ -3393,6 +3661,8 @@ static void CheckDevicesOnce(const dev_config_vector & configs, dev_state_vector
ATACheckDevice(cfg, state, dev->to_ata(), firstpass, allow_selftests); ATACheckDevice(cfg, state, dev->to_ata(), firstpass, allow_selftests);
else if (dev->is_scsi()) else if (dev->is_scsi())
SCSICheckDevice(cfg, state, dev->to_scsi(), allow_selftests); SCSICheckDevice(cfg, state, dev->to_scsi(), allow_selftests);
else if (dev->is_nvme())
NVMeCheckDevice(cfg, state, dev->to_nvme());
} }
do_disable_standby_check(configs, states); do_disable_standby_check(configs, states);
@ -3657,7 +3927,7 @@ static const char * strtok_dequote(const char * delimiters)
// This function returns 1 if it has correctly parsed one token (and // This function returns 1 if it has correctly parsed one token (and
// any arguments), else zero if no tokens remain. It returns -1 if an // any arguments), else zero if no tokens remain. It returns -1 if an
// error was encountered. // error was encountered.
static int ParseToken(char * token, dev_config & cfg) static int ParseToken(char * token, dev_config & cfg, smart_devtype_list & scan_types)
{ {
char sym; char sym;
const char * name = cfg.name.c_str(); const char * name = cfg.name.c_str();
@ -3729,8 +3999,10 @@ static int ParseToken(char * token, dev_config & cfg)
cfg.removable = true; cfg.removable = true;
} else if (!strcmp(arg, "auto")) { } else if (!strcmp(arg, "auto")) {
cfg.dev_type = ""; cfg.dev_type = "";
scan_types.clear();
} else { } else {
cfg.dev_type = arg; cfg.dev_type = arg;
scan_types.push_back(arg);
} }
break; break;
case 'F': case 'F':
@ -3898,13 +4170,13 @@ static int ParseToken(char * token, dev_config & cfg)
configfile, lineno, name, arg, cfg.test_regex.get_errmsg()); configfile, lineno, name, arg, cfg.test_regex.get_errmsg());
return -1; return -1;
} }
}
// Do a bit of sanity checking and warn user if we think that // Do a bit of sanity checking and warn user if we think that
// their regexp is "strange". User probably confused about shell // their regexp is "strange". User probably confused about shell
// glob(3) syntax versus regular expression syntax regexp(7). // glob(3) syntax versus regular expression syntax regexp(7).
if (arg[(val = strspn(arg, "0123456789/.-+*|()?^$[]SLCOcnr"))]) if (arg[(val = strspn(arg, "0123456789/.-+*|()?^$[]SLCOcnr"))])
PrintOut(LOG_INFO, "File %s line %d (drive %s): warning, character %d (%c) looks odd in extended regular expression %s\n", PrintOut(LOG_INFO, "File %s line %d (drive %s): warning, character %d (%c) looks odd in extended regular expression %s\n",
configfile, lineno, name, val+1, arg[val], arg); configfile, lineno, name, val+1, arg[val], arg);
}
break; break;
case 'm': case 'm':
// send email to address that follows // send email to address that follows
@ -3914,17 +4186,13 @@ static int ParseToken(char * token, dev_config & cfg)
if (!cfg.emailaddress.empty()) if (!cfg.emailaddress.empty())
PrintOut(LOG_INFO, "File %s line %d (drive %s): ignoring previous Address Directive -m %s\n", PrintOut(LOG_INFO, "File %s line %d (drive %s): ignoring previous Address Directive -m %s\n",
configfile, lineno, name, cfg.emailaddress.c_str()); configfile, lineno, name, cfg.emailaddress.c_str());
#ifdef _WIN32 #ifdef _WIN32 // TODO: Remove after smartmontools 6.5
if ( !strcmp(arg, "msgbox") || !strcmp(arg, "sysmsgbox") if ( !strcmp(arg, "msgbox") || !strcmp(arg, "sysmsgbox")
|| str_starts_with(arg, "msgbox,") || str_starts_with(arg, "sysmsgbox,")) { || str_starts_with(arg, "msgbox,") || str_starts_with(arg, "sysmsgbox,")) {
cfg.emailaddress = "console"; PrintOut(LOG_CRIT, "File %s line %d (drive %s): -m %s is no longer supported, use -m console[,...] instead\n",
const char * arg2 = strchr(arg, ','); configfile, lineno, name, arg);
if (arg2) return -1;
cfg.emailaddress += arg2;
PrintOut(LOG_INFO, "File %s line %d (drive %s): Deprecated -m %s changed to -m %s\n",
configfile, lineno, name, arg, cfg.emailaddress.c_str());
} }
else
#endif #endif
cfg.emailaddress = arg; cfg.emailaddress = arg;
} }
@ -3998,8 +4266,8 @@ static int ParseToken(char * token, dev_config & cfg)
break; break;
case 'W': case 'W':
// track Temperature // track Temperature
if ((val=Get3Integers(arg=strtok(NULL,delim), name, token, lineno, configfile, if (Get3Integers(arg=strtok(NULL, delim), name, token, lineno, configfile,
&cfg.tempdiff, &cfg.tempinfo, &cfg.tempcrit))<0) &cfg.tempdiff, &cfg.tempinfo, &cfg.tempcrit) < 0)
return -1; return -1;
break; break;
case 'v': case 'v':
@ -4130,7 +4398,8 @@ static int ParseToken(char * token, dev_config & cfg)
// -2: found an error // -2: found an error
// //
// Note: this routine modifies *line from the caller! // Note: this routine modifies *line from the caller!
static int ParseConfigLine(dev_config_vector & conf_entries, dev_config & default_conf, int lineno, /*const*/ char * line) static int ParseConfigLine(dev_config_vector & conf_entries, dev_config & default_conf,
smart_devtype_list & scan_types, int lineno, /*const*/ char * line)
{ {
const char *delim = " \n\t"; const char *delim = " \n\t";
@ -4159,7 +4428,7 @@ static int ParseConfigLine(dev_config_vector & conf_entries, dev_config & defaul
// parse tokens one at a time from the file. // parse tokens one at a time from the file.
while (char * token = strtok(0, delim)) { while (char * token = strtok(0, delim)) {
int rc = ParseToken(token, cfg); int rc = ParseToken(token, cfg, scan_types);
if (rc < 0) if (rc < 0)
// error found on the line // error found on the line
return -2; return -2;
@ -4171,6 +4440,13 @@ static int ParseConfigLine(dev_config_vector & conf_entries, dev_config & defaul
// PrintOut(LOG_INFO,"Parsed token %s\n",token); // PrintOut(LOG_INFO,"Parsed token %s\n",token);
} }
// Check for multiple -d TYPE directives
if (retval != -1 && scan_types.size() > 1) {
PrintOut(LOG_CRIT, "Drive: %s, invalid multiple -d TYPE Directives on line %d of file %s\n",
cfg.name.c_str(), cfg.lineno, configfile);
return -2;
}
// Don't perform checks below for DEFAULT entries // Don't perform checks below for DEFAULT entries
if (retval == 0) if (retval == 0)
return retval; return retval;
@ -4227,7 +4503,7 @@ static int ParseConfigLine(dev_config_vector & conf_entries, dev_config & defaul
// Empty configuration file ==> conf_entries.empty() // Empty configuration file ==> conf_entries.empty()
// No configuration file ==> conf_entries[0].lineno == 0 // No configuration file ==> conf_entries[0].lineno == 0
// SCANDIRECTIVE found ==> conf_entries.back().lineno != 0 (size >= 1) // SCANDIRECTIVE found ==> conf_entries.back().lineno != 0 (size >= 1)
static int ParseConfigFile(dev_config_vector & conf_entries) static int ParseConfigFile(dev_config_vector & conf_entries, smart_devtype_list & scan_types)
{ {
// maximum line length in configuration file // maximum line length in configuration file
const int MAXLINELEN = 256; const int MAXLINELEN = 256;
@ -4256,7 +4532,7 @@ static int ParseConfigFile(dev_config_vector & conf_entries)
if (!f) { if (!f) {
char fakeconfig[] = SCANDIRECTIVE " -a"; // TODO: Remove this hack, build cfg_entry. char fakeconfig[] = SCANDIRECTIVE " -a"; // TODO: Remove this hack, build cfg_entry.
if (ParseConfigLine(conf_entries, default_conf, 0, fakeconfig) != -1) if (ParseConfigLine(conf_entries, default_conf, scan_types, 0, fakeconfig) != -1)
throw std::logic_error("Internal error parsing " SCANDIRECTIVE); throw std::logic_error("Internal error parsing " SCANDIRECTIVE);
return 0; return 0;
} }
@ -4288,7 +4564,7 @@ static int ParseConfigFile(dev_config_vector & conf_entries)
// are we at the end of the file? // are we at the end of the file?
if (!code){ if (!code){
if (cont) { if (cont) {
scandevice = ParseConfigLine(conf_entries, default_conf, contlineno, fullline); scandevice = ParseConfigLine(conf_entries, default_conf, scan_types, contlineno, fullline);
// See if we found a SCANDIRECTIVE directive // See if we found a SCANDIRECTIVE directive
if (scandevice==-1) if (scandevice==-1)
return 0; return 0;
@ -4296,7 +4572,6 @@ static int ParseConfigFile(dev_config_vector & conf_entries)
if (scandevice==-2) if (scandevice==-2)
return -1; return -1;
// the final line is part of a continuation line // the final line is part of a continuation line
cont=0;
entry+=scandevice; entry+=scandevice;
} }
break; break;
@ -4342,7 +4617,8 @@ static int ParseConfigFile(dev_config_vector & conf_entries)
} }
// Not a continuation line. Parse it // Not a continuation line. Parse it
scandevice = ParseConfigLine(conf_entries, default_conf, contlineno, fullline); scan_types.clear();
scandevice = ParseConfigLine(conf_entries, default_conf, scan_types, contlineno, fullline);
// did we find a scandevice directive? // did we find a scandevice directive?
if (scandevice==-1) if (scandevice==-1)
@ -4442,7 +4718,7 @@ static void ParseOpts(int argc, char **argv)
opterr=optopt=0; opterr=optopt=0;
bool badarg = false; bool badarg = false;
bool no_defaultdb = false; // set true on '-B FILE' bool use_default_db = true; // set false on '-B FILE'
// Parse input options. // Parse input options.
int optchar; int optchar;
@ -4529,33 +4805,22 @@ static void ParseOpts(int argc, char **argv)
case 'r': case 'r':
// report IOCTL transactions // report IOCTL transactions
{ {
int i; int n1 = -1, n2 = -1, len = strlen(optarg);
char *s; char s[9+1]; unsigned i = 1;
sscanf(optarg, "%9[a-z]%n,%u%n", s, &n1, &i, &n2);
// split_report_arg() may modify its first argument string, so use a if (!((n1 == len || n2 == len) && 1 <= i && i <= 4)) {
// copy of optarg in case we want optarg for an error message.
if (!(s = strdup(optarg))) {
PrintOut(LOG_CRIT, "No memory to process -r option - exiting\n");
EXIT(EXIT_NOMEM);
}
if (split_report_arg(s, &i)) {
badarg = true; badarg = true;
} else if (i<1 || i>3) {
debugmode=1;
PrintHead();
PrintOut(LOG_CRIT, "======> INVALID REPORT LEVEL: %s <=======\n", optarg);
PrintOut(LOG_CRIT, "======> LEVEL MUST BE INTEGER BETWEEN 1 AND 3<=======\n");
EXIT(EXIT_BADCMD);
} else if (!strcmp(s,"ioctl")) { } else if (!strcmp(s,"ioctl")) {
ata_debugmode = scsi_debugmode = i; ata_debugmode = scsi_debugmode = nvme_debugmode = i;
} else if (!strcmp(s,"ataioctl")) { } else if (!strcmp(s,"ataioctl")) {
ata_debugmode = i; ata_debugmode = i;
} else if (!strcmp(s,"scsiioctl")) { } else if (!strcmp(s,"scsiioctl")) {
scsi_debugmode = i; scsi_debugmode = i;
} else if (!strcmp(s,"nvmeioctl")) {
nvme_debugmode = i;
} else { } else {
badarg = true; badarg = true;
} }
free(s); // TODO: use std::string
} }
break; break;
case 'c': case 'c':
@ -4583,7 +4848,7 @@ static void ParseOpts(int argc, char **argv)
if (*path == '+' && path[1]) if (*path == '+' && path[1])
path++; path++;
else else
no_defaultdb = true; use_default_db = false;
unsigned char savedebug = debugmode; debugmode = 1; unsigned char savedebug = debugmode; debugmode = 1;
if (!read_drive_database(path)) if (!read_drive_database(path))
EXIT(EXIT_BADCMD); EXIT(EXIT_BADCMD);
@ -4688,9 +4953,9 @@ static void ParseOpts(int argc, char **argv)
#endif #endif
// Read or init drive database // Read or init drive database
if (!no_defaultdb) { {
unsigned char savedebug = debugmode; debugmode = 1; unsigned char savedebug = debugmode; debugmode = 1;
if (!read_default_drive_databases()) if (!init_drive_database(use_default_db))
EXIT(EXIT_BADCMD); EXIT(EXIT_BADCMD);
debugmode = savedebug; debugmode = savedebug;
} }
@ -4703,14 +4968,17 @@ static void ParseOpts(int argc, char **argv)
// SCANDIRECTIVE Directive was found. It makes entries for device // SCANDIRECTIVE Directive was found. It makes entries for device
// names returned by scan_smart_devices() in os_OSNAME.cpp // names returned by scan_smart_devices() in os_OSNAME.cpp
static int MakeConfigEntries(const dev_config & base_cfg, static int MakeConfigEntries(const dev_config & base_cfg,
dev_config_vector & conf_entries, smart_device_list & scanned_devs, const char * type) dev_config_vector & conf_entries, smart_device_list & scanned_devs,
const smart_devtype_list & types)
{ {
// make list of devices // make list of devices
smart_device_list devlist; smart_device_list devlist;
if (!smi()->scan_smart_devices(devlist, (*type ? type : 0))) if (!smi()->scan_smart_devices(devlist, types)) {
PrintOut(LOG_CRIT,"Problem creating device name scan list\n"); PrintOut(LOG_CRIT, "DEVICESCAN failed: %s\n", smi()->get_errmsg());
return 0;
}
// if no devices, or error constructing list, return // if no devices, return
if (devlist.size() <= 0) if (devlist.size() <= 0)
return 0; return 0;
@ -4729,7 +4997,7 @@ static int MakeConfigEntries(const dev_config & base_cfg,
dev_config & cfg = conf_entries.back(); dev_config & cfg = conf_entries.back();
cfg.name = dev->get_info().info_name; cfg.name = dev->get_info().info_name;
cfg.dev_name = dev->get_info().dev_name; cfg.dev_name = dev->get_info().dev_name;
cfg.dev_type = type; cfg.dev_type = dev->get_info().dev_type;
} }
return devlist.size(); return devlist.size();
@ -4754,7 +5022,8 @@ static void CanNotRegister(const char *name, const char *type, int line, bool sc
static int ReadOrMakeConfigEntries(dev_config_vector & conf_entries, smart_device_list & scanned_devs) static int ReadOrMakeConfigEntries(dev_config_vector & conf_entries, smart_device_list & scanned_devs)
{ {
// parse configuration file configfile (normally /etc/smartd.conf) // parse configuration file configfile (normally /etc/smartd.conf)
int entries = ParseConfigFile(conf_entries); smart_devtype_list scan_types;
int entries = ParseConfigFile(conf_entries, scan_types);
if (entries < 0) { if (entries < 0) {
// There was an error reading the configuration file. // There was an error reading the configuration file.
@ -4782,14 +5051,14 @@ static int ReadOrMakeConfigEntries(dev_config_vector & conf_entries, smart_devic
PrintOut(LOG_INFO,"No configuration file %s found, scanning devices\n", configfile); PrintOut(LOG_INFO,"No configuration file %s found, scanning devices\n", configfile);
// make config list of devices to search for // make config list of devices to search for
MakeConfigEntries(first, conf_entries, scanned_devs, first.dev_type.c_str()); MakeConfigEntries(first, conf_entries, scanned_devs, scan_types);
// warn user if scan table found no devices // warn user if scan table found no devices
if (conf_entries.empty()) if (conf_entries.empty())
PrintOut(LOG_CRIT,"In the system's table of devices NO devices found to scan\n"); PrintOut(LOG_CRIT,"In the system's table of devices NO devices found to scan\n");
} }
else else
PrintOut(LOG_CRIT,"Configuration file %s parsed but has no entries (like /dev/hda)\n",configfile); PrintOut(LOG_CRIT, "Configuration file %s parsed but has no entries\n", configfile);
return conf_entries.size(); return conf_entries.size();
} }
@ -4930,8 +5199,15 @@ static void RegisterDevices(const dev_config_vector & conf_entries, smart_device
dev.reset(); dev.reset();
} }
} }
// or register NVMe devices
else if (dev->is_nvme()) {
if (NVMeDeviceScan(cfg, state, dev->to_nvme())) {
CanNotRegister(cfg.name.c_str(), "NVMe", cfg.lineno, scanning);
dev.reset();
}
}
else { else {
PrintOut(LOG_INFO, "Device: %s, neither ATA nor SCSI device\n", cfg.name.c_str()); PrintOut(LOG_INFO, "Device: %s, neither ATA, SCSI nor NVMe device\n", cfg.name.c_str());
dev.reset(); dev.reset();
} }
@ -5057,13 +5333,16 @@ static int main_worker(int argc, char **argv)
// Log number of devices we are monitoring... // Log number of devices we are monitoring...
if (devices.size() > 0 || quit==2 || (quit==1 && !firstpass)) { if (devices.size() > 0 || quit==2 || (quit==1 && !firstpass)) {
int numata = 0; int numata = 0, numscsi = 0;
for (unsigned i = 0; i < devices.size(); i++) { for (unsigned i = 0; i < devices.size(); i++) {
if (devices.at(i)->is_ata()) const smart_device * dev = devices.at(i);
if (dev->is_ata())
numata++; numata++;
else if (dev->is_scsi())
numscsi++;
} }
PrintOut(LOG_INFO,"Monitoring %d ATA and %d SCSI devices\n", PrintOut(LOG_INFO,"Monitoring %d ATA/SATA, %d SCSI/SAS and %d NVMe devices\n",
numata, devices.size() - numata); numata, numscsi, (int)devices.size() - numata - numscsi);
} }
else { else {
PrintOut(LOG_INFO,"Unable to monitor any SMART enabled devices. Try debug (-d) option. Exiting...\n"); PrintOut(LOG_INFO,"Unable to monitor any SMART enabled devices. Try debug (-d) option. Exiting...\n");
@ -5159,6 +5438,16 @@ static int smartd_main(int argc, char **argv)
status = EXIT_BADCODE; status = EXIT_BADCODE;
} }
// Check for remaining device objects
if (smart_device::get_num_objects() != 0) {
PrintOut(LOG_CRIT, "Smartd: Internal Error: %d device object(s) left at exit.\n",
smart_device::get_num_objects());
status = EXIT_BADCODE;
}
if (status == EXIT_BADCODE)
PrintOut(LOG_CRIT, "Please inform " PACKAGE_BUGREPORT ", including output of smartd -V.\n");
if (is_initialized) if (is_initialized)
status = Goodbye(status); status = Goodbye(status);

View File

@ -2,7 +2,7 @@
# smartmontools init file for smartd # smartmontools init file for smartd
# Copyright (C) 2002-8 Bruce Allen <smartmontools-support@lists.sourceforge.net> # Copyright (C) 2002-8 Bruce Allen <smartmontools-support@lists.sourceforge.net>
# $Id: smartd.initd.in 3727 2012-12-13 17:23:06Z samm2 $ # $Id: smartd.initd.in 4120 2015-08-27 16:12:21Z samm2 $
# For RedHat and cousins: # For RedHat and cousins:
# chkconfig: 2345 40 40 # chkconfig: 2345 40 40
@ -540,7 +540,7 @@ elif uname | grep -i CYGWIN > /dev/null 2>&1 ; then
Controls and monitors storage devices using the Self-Monitoring \ Controls and monitors storage devices using the Self-Monitoring \
Analysis and Reporting Technology System (S.M.A.R.T.) \ Analysis and Reporting Technology System (S.M.A.R.T.) \
built into ATA and SCSI Hard Drives. \ built into ATA and SCSI Hard Drives. \
http://smartmontools.sourceforge.net/" http://www.smartmontools.org/"
# Source configuration file. This should define the shell variable smartd_opts. # Source configuration file. This should define the shell variable smartd_opts.
# Email smartmontools-support@lists.sourceforge.net if there is a better choice # Email smartmontools-support@lists.sourceforge.net if there is a better choice

View File

@ -1,8 +1,8 @@
.ig .ig
Copyright (C) 2013 Hannes von Haugwitz <hannes@vonhaugwitz.com> Copyright (C) 2013 Hannes von Haugwitz <hannes@vonhaugwitz.com>
Copyright (C) 2014 Christian Franke <smartmontools-support@lists.sourceforge.net> Copyright (C) 2014-16 Christian Franke
$Id: update-smart-drivedb.8.in 3961 2014-07-19 16:44:10Z chrfranke $ $Id: update-smart-drivedb.8.in 4223 2016-02-26 20:18:40Z chrfranke $
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -13,19 +13,21 @@ You should have received a copy of the GNU General Public License
(for example COPYING); If not, see <http://www.gnu.org/licenses/>. (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
.. ..
.TH UPDATE-SMART-DRIVEDB 8 CURRENT_SVN_DATE CURRENT_SVN_VERSION CURRENT_SVN_DATE .TH UPDATE-SMART-DRIVEDB 8 "CURRENT_SVN_DATE" "CURRENT_SVN_VERSION" "SMART Monitoring Tools"
.SH NAME .SH NAME
update-smart-drivedb \- update smartmontools drive database update-smart-drivedb \- update smartmontools drive database
.SH "SYNOPSIS" .SH "SYNOPSIS"
.B update-smart-drivedb .B update-smart-drivedb
.RB [ -v ] .RI [ OPTIONS ]
.RI [ DESTFILE ] .RI [ DESTFILE ]
.SH PACKAGE VERSION
CURRENT_SVN_VERSION CURRENT_SVN_DATE CURRENT_SVN_REV
.SH "DESCRIPTION" .SH "DESCRIPTION"
.\" %IF NOT OS ALL
.\"! [This man page is generated for the OS_MAN_FILTER version of smartmontools.
.\"! It does not contain info specific to other platforms.]
.\"! .PP
.\" %ENDIF NOT OS ALL
.B update-smart-drivedb .B update-smart-drivedb
updates updates
.B /usr/local/share/smartmontools/drivedb.h .B /usr/local/share/smartmontools/drivedb.h
@ -36,18 +38,18 @@ from smartmontools SVN repository.
It tries to download first from the current branch and then from It tries to download first from the current branch and then from
trunk. The tools used for downloading are either trunk. The tools used for downloading are either
.BR curl (1), .BR curl (1),
.BR wget "(1) or" .BR wget (1),
.BR lynx (1). .BR lynx (1),
.\" %IF OS FreeBSD .\" %IF OS FreeBSD
On FreeBSD,
.BR fetch (1) .BR fetch (1)
is used as a fallback. [FreeBSD only],
.\" %ENDIF OS FreeBSD .\" %ENDIF OS FreeBSD
.\" %IF OS OpenBSD .\" %IF OS OpenBSD
On OpenBSD,
.BR ftp (1) .BR ftp (1)
is used as a fallback. [OpenBSD only],
.\" %ENDIF OS OpenBSD .\" %ENDIF OS OpenBSD
or
.BR svn (1).
The old file is kept if the downloaded file is identical (ignoring The old file is kept if the downloaded file is identical (ignoring
the differences in Id string) otherwise it is moved to the differences in Id string) otherwise it is moved to
@ -55,8 +57,60 @@ the differences in Id string) otherwise it is moved to
.SH "OPTIONS" .SH "OPTIONS"
.TP .TP
\-v .B \-s SMARTCTL
verbose output Use the
.BR smartctl (8)
executable at path SMARTCTL for drive database syntax check.
The form \'\-s \-\' disables the syntax check.
The default is
.BR /usr/local/sbin/smartctl .
.TP
.B \-t TOOL
Use TOOL for download.
TOOL is one of:
.I curl wget lynx
.\" %IF OS FreeBSD
.I fetch
.\" %ENDIF OS FreeBSD
.\" %IF OS OpenBSD
.I ftp
.\" %ENDIF OS OpenBSD
.IR svn .
The default is the first one found in PATH.
.TP
.B \-u LOCATION
Use URL of LOCATION for download. LOCATION is one of:
.br
.I sf
(Sourceforge code browser via HTTPS),
.br
.I svn
(SVN repository via HTTPS),
.br
.I svni
(SVN repository via HTTP),
.br
.I trac
(Trac code browser via HTTPS).
.br
The default is
.IR svn .
.TP
.B \-\-cacert FILE
Use CA certificates from FILE to verify the peer.
.TP
.B \-\-capath DIR
Use CA certificate files from DIR to verify the peer.
.TP
.B \-\-insecure
Don't abort download if certificate verification fails.
This option is also required if a HTTP URL is selected with \'-u\' option.
.TP
.B \-\-dryrun
Print download commands only.
.TP
.B \-v
Verbose output.
.SH "EXAMPLES" .SH "EXAMPLES"
.nf .nf
@ -83,22 +137,30 @@ current drive database.
previous drive database. previous drive database.
.TP .TP
.B /usr/local/share/smartmontools/drivedb.h.error .B /usr/local/share/smartmontools/drivedb.h.error
new drive database rejected due to syntax errors. new drive database if rejected due to syntax errors.
.TP .TP
.B /usr/local/share/smartmontools/drivedb.h.lastcheck .B /usr/local/share/smartmontools/drivedb.h.lastcheck
empty file created if downloaded file was identical. empty file created if downloaded file was identical.
.SH "SEE ALSO"
.BR smartctl (8),
.BR smartd (8).
.SH AUTHORS .SH AUTHORS
\fBChristian Franke\fP \fBChristian Franke\fP.
.br
\fBsmartmontools\-support@lists.sourceforge.net\fP
.br .br
This manual page was originally written by This manual page was originally written by
.BR "Hannes von Haugwitz <hannes@vonhaugwitz.com>" . .BR "Hannes von Haugwitz <hannes@vonhaugwitz.com>" .
.SH SVN ID OF THIS PAGE .SH REPORTING BUGS
$Id: update-smart-drivedb.8.in 3961 2014-07-19 16:44:10Z chrfranke $ To submit a bug report, create a ticket in smartmontools wiki:
.br
<\fBhttp://www.smartmontools.org/\fP>.
.br
Alternatively send the info to the smartmontools support mailing list:
.br
<\fBhttps://lists.sourceforge.net/lists/listinfo/smartmontools-support\fB>.
.SH SEE ALSO
\fBsmartctl\fP(8), \fBsmartd\fP(8).
.SH PACKAGE VERSION
CURRENT_SVN_VERSION CURRENT_SVN_DATE CURRENT_SVN_REV
.br
$Id: update-smart-drivedb.8.in 4223 2016-02-26 20:18:40Z chrfranke $

View File

@ -2,7 +2,7 @@
# #
# smartmontools drive database update script # smartmontools drive database update script
# #
# Copyright (C) 2010-13 Christian Franke <smartmontools-support@lists.sourceforge.net> # Copyright (C) 2010-16 Christian Franke
# #
# This program is free software; you can redistribute it and/or modify # 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 # 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 # You should have received a copy of the GNU General Public License
# (for example COPYING); If not, see <http://www.gnu.org/licenses/>. # (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
# #
# $Id: update-smart-drivedb.in 3814 2013-06-04 19:38:25Z chrfranke $ # $Id: update-smart-drivedb.in 4224 2016-02-26 20:29:24Z chrfranke $
# #
set -e set -e
@ -34,104 +34,343 @@ os_dltools="@os_dltools@"
BRANCH="@DRIVEDB_BRANCH@" BRANCH="@DRIVEDB_BRANCH@"
# Default drivedb location # Default drivedb location
DEST="$drivedbdir/drivedb.h" DRIVEDB="$drivedbdir/drivedb.h"
# Smartctl used for syntax check # Smartctl used for syntax check
SMARTCTL="$sbindir/smartctl" SMARTCTL="$sbindir/smartctl"
# Download URL for sourceforge code browser myname=$0
SRCEXPR='http://sourceforge.net/p/smartmontools/code/HEAD/tree/$location/smartmontools/drivedb.h?format=raw'
# Parse options usage()
q="-q " {
case "$1" in
-v) q=; shift ;;
esac
case "$*" in
-*|*\ *)
cat <<EOF cat <<EOF
smartmontools $VERSION drive database update script smartmontools $VERSION drive database update script
Usage: $0 [-v] [DESTFILE] Usage: $myname [OPTIONS] [DESTFILE]
-v verbose output -s SMARTCTL Use SMARTCTL for syntax check ('-s -' to disable)
[default: $SMARTCTL]
-t TOOL Use TOOL for download: $os_dltools
[default: first one found in PATH]
-u LOCATION Use URL of LOCATION for download:
sf (Sourceforge code browser via HTTPS)
svn (SVN repository via HTTPS) [default]
svni (SVN repository via HTTP)
trac (Trac code browser via HTTPS)
--cacert FILE Use CA certificates from FILE to verify the peer
--capath DIR Use CA certificate files from DIR to verify the peer
--insecure Don't abort download if certificate verification fails
--dryrun Print download commands only
-v Verbose output
Updates $DEST Updates $DRIVEDB
or DESTFILE from smartmontools SVN repository. or DESTFILE from smartmontools SVN repository.
Tries to download first from branch $BRANCH Tries to download first from branch $BRANCH
and then from trunk. and then from trunk.
EOF EOF
exit 1 exit 1
}
error()
{
echo "$myname: $*" >&2
exit 1
}
warning()
{
echo "$myname: (Warning) $*" >&2
}
selecturl()
{
case $1 in
sf) url='https://sourceforge.net/p/smartmontools/code/HEAD/tree/trunk/smartmontools/drivedb.h?format=raw' ;;
svn) url='https://svn.code.sf.net/p/smartmontools/code/trunk/smartmontools/drivedb.h' ;;
svni) url='http://svn.code.sf.net/p/smartmontools/code/trunk/smartmontools/drivedb.h' ;;
trac) url='https://www.smartmontools.org/export/HEAD/trunk/smartmontools/drivedb.h' ;;
*) usage ;;
esac
}
inpath()
{
local d rc save
rc=1
save=$IFS
IFS=':'
for d in $PATH; do
test -f "$d/$1" || continue
test -x "$d/$1" || continue
rc=0
break
done
IFS=$save
return $rc
}
vecho()
{
test -n "$q" || echo "$*"
}
# vrun COMMAND ARGS...
vrun()
{
if [ -n "$dryrun" ]; then
echo "$*"
elif [ -n "$q" ]; then
"$@" 2>/dev/null
else
echo "$*"
"$@"
fi
}
# vrun2 OUTFILE COMMAND ARGS...
vrun2()
{
local f err rc
f=$1; shift
rc=0
if [ -n "$dryrun" ]; then
echo "$* > $f"
else
vecho "$* > $f"
err=`"$@" 2>&1 > $f` || rc=$?
if [ -n "$err" ]; then
vecho "$err" >&2
test $rc != 0 || rc=42
fi
fi
return $rc
}
# download URL FILE
download()
{
local f u se rc
u=$1; f=$2
rc=0
case $tool in
curl)
vrun curl ${q:+-s} -f --max-redirs 0 \
${cacert:+--cacert "$cacert"} \
${capath:+--capath "$capath"} \
${insecure:+--insecure} \
-o "$f" "$u" || rc=$?
;; ;;
"") ;; wget)
*) DEST="$1" ;; vrun wget $q --max-redirect=0 \
${cacert:+--ca-certificate="$cacert"} \
${capath:+--ca-directory="$capath"} \
${insecure:+--no-check-certificate} \
-O "$f" "$u" || rc=$?
;;
lynx)
test -z "$cacert" || vrun export SSL_CERT_FILE="$cacert"
test -z "$capath" || vrun export SSL_CERT_DIR="$capath"
# Check also stderr as lynx does not return != 0 on HTTP error
vrun2 "$f" lynx -stderr -noredir -source "$u" || rc=$?
;;
svn)
vrun svn $q export \
--non-interactive --no-auth-cache \
${cacert:+--config-option "servers:global:ssl-trust-default-ca=no"} \
${cacert:+--config-option "servers:global:ssl-authority-files=$cacert"} \
${insecure:+--trust-server-cert} \
"$u" "$f" || rc=$?
;;
fetch) # FreeBSD
vrun fetch $q --no-redirect \
${cacert:+--ca-cert "$cacert"} \
${capath:+--ca-path "$capath"} \
${insecure:+--no-verify-hostname} \
-o "$f" "$u" || rc=$?
;;
ftp) # OpenBSD
vrun ftp \
${cacert:+-S cafile="$cacert"} \
${capath:+-S capath="$capath"} \
${insecure:+-S dont} \
-o "$f" "$u" || rc=$?
;;
*) error "$tool: unknown (internal error)" ;;
esac
return $rc
}
# Parse options
smtctl=$SMARTCTL
tool=
url=
q="-q"
dryrun=
cacert=
capath=
insecure=
while true; do case $1 in
-s)
shift; test -n "$1" || usage
smtctl=$1 ;;
-t)
shift
case $1 in *\ *) usage ;; esac
case " $os_dltools " in *\ $1\ *) ;; *) usage ;; esac
tool=$1 ;;
-u)
shift; selecturl "$1" ;;
-v)
q= ;;
--dryrun)
dryrun=t ;;
--cacert)
shift; test -n "$1" || usage
cacert=$1 ;;
--capath)
shift; test -n "$1" || usage
capath=$1 ;;
--insecure)
insecure=t ;;
-*)
usage ;;
*)
break ;;
esac; shift; done
case $# in
0) DEST=$DRIVEDB ;;
1) DEST=$1 ;;
*) usage ;;
esac esac
# Abort if 'which' is not available if [ -z "$tool" ]; then
which which >/dev/null || exit 1 # Find download tool in PATH
for t in $os_dltools; do
# Find download tool if inpath "$t"; then
DOWNLOAD= tool=$t
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 break
fi fi
done done
if [ -z "$DOWNLOAD" ]; then test -n "$tool" || error "found none of: $os_dltools"
echo "$0: found none of: $os_dltools" >&2; exit 1
fi fi
test -n "$url" || selecturl "svn"
# Check option compatibility
case "$tool:$url" in
svn:http*://svn.code.sf.net*) ;;
svn:*) error "'-t svn' requires '-u svn' or '-u svni'" ;;
esac
case "$tool:${capath:+set}" in
svn:set) warning "'--capath' is ignored if '-t svn' is used" ;;
esac
case "${insecure:-f}:$url" in
t:http:*) insecure= ;;
?:https:*) ;;
*) error "'-u svni' requires '--insecure'" ;;
esac
case "$tool:$insecure" in
lynx:t) warning "'--insecure' is ignored if '-t lynx' is used" ;;
esac
# Try possible branch first, then trunk # Try possible branch first, then trunk
errmsg=
errmsg2=
for location in "branches/$BRANCH" "trunk"; do for location in "branches/$BRANCH" "trunk"; do
test -n "$q" || echo "Download from $location" test -z "$errmsg" || errmsg2=$errmsg
vecho "Download from $location with $tool"
# Adjust URL
case $location in
trunk) src=$url ;;
*) src=`echo "$url" | sed "s,/trunk/,/$location/,"` ;;
esac
# Download
test -n "$dryrun" || rm -f "$DEST.new" || exit 1
rc=0
download "$src" "$DEST.new" || rc=$?
test -z "$dryrun" || continue
errmsg= errmsg=
rm -f "$DEST.new" if [ $rc != 0 ]; then
SRC="`eval echo "$SRCEXPR"`" errmsg="download from $location failed ($tool: exit $rc)"
if (eval $DOWNLOAD); then :; else
errmsg="download from $location failed (HTTP error)"
continue continue
fi fi
if grep -i '<title>.*Error has Occurred' "$DEST.new" >/dev/null; then
errmsg="download from $location failed (SF code browser error)" # Check file contents
case `sed 1q "$DEST.new"` in
/*) ;;
\<*)
errmsg="download from $location failed (HTML error message)"
continue ;;
*)
errmsg="download from $location failed (Unknown file contents)"
continue ;;
esac
# Check file size
size=`wc -c < "$DEST.new"`
if [ "$size" -lt 10000 ]; then
errmsg="download from $location failed (too small file size $size bytes)"
continue continue
fi fi
if [ "$size" -gt 1000000 ]; then
errmsg="download from $location failed (too large file size $size bytes)"
break
fi
break break
done done
test -z "$dryrun" || exit 0
if [ -n "$errmsg" ]; then if [ -n "$errmsg" ]; then
rm -f "$DEST.new" rm -f "$DEST.new"
echo "$0: $errmsg" >&2 test -z "$errmsg2" || echo "$myname: $errmsg2" >&2
exit 1 error "$errmsg"
fi fi
# Adjust timestamp and permissions # Adjust timestamp and permissions
touch "$DEST.new" touch "$DEST.new"
chmod 0644 "$DEST.new" chmod 0644 "$DEST.new"
# Check syntax if [ "$smtctl" != "-" ]; then
rm -f "$DEST.error" # Check syntax
if $SMARTCTL -B "$DEST.new" -P showall >/dev/null; then :; else rm -f "$DEST.error"
if "$smtctl" -B "$DEST.new" -P showall >/dev/null; then
test -n "$q" || echo "$smtctl: syntax OK"
else
mv "$DEST.new" "$DEST.error" mv "$DEST.new" "$DEST.error"
echo "$DEST.error: rejected by $SMARTCTL, probably no longer compatible" >&2 echo "$DEST.error: rejected by $smtctl, probably no longer compatible" >&2
exit 1 exit 1
fi
fi fi
# Keep old file if identical # Keep old file if identical, ignore missing Id keyword expansion in new file
rm -f "$DEST.lastcheck" rm -f "$DEST.lastcheck"
if [ -f "$DEST" ]; then if [ -f "$DEST" ]; then
if cmp "$DEST" "$DEST.new" >/dev/null 2>/dev/null; then if cmp "$DEST" "$DEST.new" >/dev/null 2>/dev/null \
|| cat "$DEST" | sed 's|\$''Id''[^$]*\$|$''Id''$|' \
| cmp - "$DEST.new" >/dev/null 2>/dev/null; then
rm -f "$DEST.new" rm -f "$DEST.new"
touch "$DEST.lastcheck" touch "$DEST.lastcheck"
echo "$DEST is already up to date" echo "$DEST is already up to date"

Some files were not shown because too many files have changed in this diff Show More