Hello community,

here is the log from the commit of package hdparm for openSUSE:Factory checked 
in at 2012-01-09 16:22:51
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/hdparm (Old)
 and      /work/SRC/openSUSE:Factory/.hdparm.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "hdparm", Maintainer is "[email protected]"

Changes:
--------
--- /work/SRC/openSUSE:Factory/hdparm/hdparm.changes    2011-10-04 
18:11:34.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.hdparm.new/hdparm.changes       2012-01-09 
16:22:53.000000000 +0100
@@ -1,0 +2,8 @@
+Sun Jan  8 19:51:06 UTC 2012 - [email protected]
+
+- update to hdparm-9.38 
+  - updated wiper.sh to allow all SCSI_DISK major numbers
+  - updated handing for very long SECURITY-ERASE times
+  - added -J flag for wdidle3 set/get
+
+-------------------------------------------------------------------

Old:
----
  hdparm-9.37.tar.gz

New:
----
  hdparm-9.38.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ hdparm.spec ++++++
--- /var/tmp/diff_new_pack.Sn1Viu/_old  2012-01-09 16:22:56.000000000 +0100
+++ /var/tmp/diff_new_pack.Sn1Viu/_new  2012-01-09 16:22:56.000000000 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package hdparm
 #
-# Copyright (c) 2011 SUSE LINUX Products GmbH, Nuernberg, Germany.
+# Copyright (c) 2012 SUSE LINUX Products GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -15,18 +15,15 @@
 # Please submit bugfixes or comments via http://bugs.opensuse.org/
 #
 
-# norootforbuild
-
 
 Name:           hdparm
-License:        PERMISSIVE-OSI-COMPLIANT
-Group:          Hardware/Other
 PreReq:         %insserv_prereq %fillup_prereq coreutils
 Provides:       base:/sbin/hdparm
-AutoReqProv:    on
-Version:        9.37
-Release:        1
+Version:        9.38
+Release:        0
 Summary:        A Program to get and set hard disk parameters
+License:        PERMISSIVE-OSI-COMPLIANT
+Group:          Hardware/Other
 Source:         
http://sourceforge.net/projects/hdparm/files/hdparm/%{name}-%{version}.tar.gz
 Source1:        56-idedma.rules
 Source2:        sysconfig.ide

++++++ hdparm-9.37.tar.gz -> hdparm-9.38.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hdparm-9.37/Changelog new/hdparm-9.38/Changelog
--- old/hdparm-9.37/Changelog   2011-01-24 16:15:10.000000000 +0100
+++ new/hdparm-9.38/Changelog   2012-01-06 17:47:10.000000000 +0100
@@ -1,3 +1,7 @@
+9.37+
+       - updated wiper.sh to allow all SCSI_DISK major numbers
+       - updated handing for very long SECURITY-ERASE times
+       - added -J flag for wdidle3 set/get
 hdparm-9.37
        - handle raid1 start_lba values, and show -1 for indeterminte raid 
start_lba values
        - abort --fibmap when start_lba is indeterminate
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hdparm-9.37/Makefile new/hdparm-9.38/Makefile
--- old/hdparm-9.37/Makefile    2011-01-08 15:56:44.000000000 +0100
+++ new/hdparm-9.38/Makefile    2012-01-06 17:05:37.000000000 +0100
@@ -22,7 +22,7 @@
 INSTALL_DIR = $(INSTALL) -m 755 -d
 INSTALL_PROGRAM = $(INSTALL)
 
-OBJS = hdparm.o identify.o sgio.o sysfs.o geom.o fallocate.o fibmap.o 
fwdownload.o dvdspeed.o
+OBJS = hdparm.o identify.o sgio.o sysfs.o geom.o fallocate.o fibmap.o 
fwdownload.o dvdspeed.o wdidle3.o
 
 all: hdparm
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hdparm-9.37/contrib/wdidle3_trace.txt 
new/hdparm-9.38/contrib/wdidle3_trace.txt
--- old/hdparm-9.37/contrib/wdidle3_trace.txt   1970-01-01 01:00:00.000000000 
+0100
+++ new/hdparm-9.38/contrib/wdidle3_trace.txt   2012-01-07 21:52:53.000000000 
+0100
@@ -0,0 +1,255 @@
+These are FIS (SATA Frame Information Structures) traces captured with a SATA 
analyser
+when using the WDIDLE3-1.03 program under DOS.  I do not know the sequence 
that these
+four traces were done in, which may affect the exact actions/values used.
+
+
+----------------------------------------------------------------------------------------------------------------------------------------------------
+
+wdidle3-report.sata: report state of the idle3 timer:
+
+RESET_DEVICE:
+fis: 27 00 80 44 01 00 00 00 00 00 00 d5 01 00 00 06 00 00 00 00
+fis: 27 00 80 44 01 00 00 00 00 00 00 d5 01 00 00 02 00 00 00 00
+
+IDENTIFY_DEVICE:
+fis: 27 80 ec 44 01 00 00 a0 00 00 00 d5 01 00 00 02 00 00 00 00
+data_in:
+  0: 7a 42 ff 3f 37 c8 10 00 00 00 00 00 3f 00 00 00 00 00 00 00 20 20 20 20 
57 20 2d 44 4d 57 56 41 30 35 32 33 35 36 36 38 00 00 ff ff 32 00 31 30
+ 48: 30 2e 41 30 31 30 44 57 20 43 44 57 30 35 30 30 41 41 53 44 30 2d 4d 30 
42 32 20 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 10 80
+ 96: 00 00 00 2f 01 40 00 00 00 00 07 00 ff 3f 10 00 3f 00 10 fc fb 00 00 01 
ff ff ff 0f 00 00 07 00 03 00 78 00 78 00 78 00 78 00 00 00 00 00 00 00
+144: 00 00 00 00 00 00 1f 00 06 17 00 00 44 00 40 00 fe 01 00 00 6b 74 61 7f 
23 41 69 74 41 bc 23 41 7f 40 4a 00 4a 00 00 00 fe ff 00 00 fe 80 00 00
+192: 00 00 00 00 00 00 00 00 30 60 38 3a 00 00 00 00 00 00 00 00 00 00 00 00 
01 50 e0 4e 81 ac a1 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1c 40
+240: 1c 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 21 00 00 00 00 00 00 00 
00 00 ce 16 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00
+288: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+336: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+384: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 37 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+432: 00 00 00 00 00 00 00 00 00 00 00 00 1e 10 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 10 00 00 00 00 00 00 00 00
+480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 a5 60
+
+VSC_ENABLE:
+fis: 27 80 80 45 01 44 57 a0 00 00 00 44 00 00 00 02 00 00 00 00
+
+SMART_WRITE_LOG:
+fis: 27 80 b0 d6 be 4f c2 a0 01 44 57 45 01 00 00 02 00 00 00 00
+data_out: 57 00 1a 00..
+
+SMART_READ_LOG:
+fis: 27 80 b0 d5 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00
+data_in: 40 1f 00 00..
+
+SMART_WRITE_LOG:
+fis: 27 80 b0 d6 be 4f c2 a0 bf 00 00 d5 01 00 00 02 00 00 00 00
+data_out: 2a 00 01 00 02 00 0d 00 16 00 01 00..
+
+SMART_READ_LOG:
+fis: 27 80 b0 d5 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00
+data_in: 50 00..
+
+VSC_DISABLE:
+fis: 27 80 80 44 bf 44 57 a0 00 00 00 d5 00 00 00 02 00 00 00 00
+
+----------------------------------------------------------------------------------------------------------------------------------------------------
+
+wdidle3-disable.sata: completely disable the idle3 timer:
+
+RESET,
+IDENTIFY:
+fis: 27 80 ec 44 01 00 00 a0 00 00 00 d5 01 00 00 02 00 00 00 00
+data_in:
+  0: 7a 42 ff 3f 37 c8 10 00 00 00 00 00 3f 00 00 00 00 00 00 00 20 20 20 20 
57 20 2d 44 4d 57 56 41 30 35 32 33 35 36 36 38 00 00 ff ff 32 00 31 30
+ 48: 30 2e 41 30 31 30 44 57 20 43 44 57 30 35 30 30 41 41 53 44 30 2d 4d 30 
42 32 20 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 10 80
+ 96: 00 00 00 2f 01 40 00 00 00 00 07 00 ff 3f 10 00 3f 00 10 fc fb 00 00 01 
ff ff ff 0f 00 00 07 00 03 00 78 00 78 00 78 00 78 00 00 00 00 00 00 00
+144: 00 00 00 00 00 00 1f 00 06 17 00 00 44 00 40 00 fe 01 00 00 6b 74 61 7f 
23 41 69 74 41 bc 23 41 7f 40 4a 00 4a 00 00 00 fe ff 00 00 fe 80 00 00
+192: 00 00 00 00 00 00 00 00 30 60 38 3a 00 00 00 00 00 00 00 00 00 00 00 00 
01 50 e0 4e 81 ac a1 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1c 40
+240: 1c 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 21 00 00 00 00 00 00 00 
00 00 ce 16 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00
+288: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+336: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+384: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 37 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+432: 00 00 00 00 00 00 00 00 00 00 00 00 1e 10 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 10 00 00 00 00 00 00 00 00
+480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 a5 60
+
+vSC_ENABLE:
+fis: 27 80 80 45 01 44 57 a0 00 00 00 44 00 00 00 02 00 00 00 00
+
+SMART:
+fis: 27 80 b0 d6 be 4f c2 a0 01 44 57 45 01 00 00 02 00 00 00 00
+data_out: 57 00 1b 00..
+
+SMART:
+fis: 27 80 b0 d6 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00
+data_out:
+  0: 00 00 00 00 f2 0b 00 00 d3 de 43 00 ff ff ff ff 00 00 00 00 78 57 55 00 
3c 2d 4c 00 60 70 4b 00 63 70 4b 00 00 00 00 00 00 00 00 00 f2 0b 00 00
+ 48: d4 2e 4c 00 60 70 4b 00 d0 67 4c 00 08 60 4c 00 6e 4f 44 00 63 70 4b 00 
14 00 00 00 14 00 00 00 f2 0b 00 00 b2 80 43 00 64 00 00 00 a0 00 00 00
+ 96: 50 40 55 00 73 00 83 00 73 00 63 00 e8 06 00 00 d4 33 03 00 00 00 00 00 
00 00 00 00 00 00 00 00 b7 01 87 01 83 00 83 00 e8 06 00 00 38 00 00 00
+144: d4 2d 4c 00 a4 2d 4c 00 21 00 00 00 19 00 00 00 00 00 00 00 00 03 00 00 
46 32 21 00 00 00 6e 0d 15 00 c3 00 22 04 00 00 00 00 00 00 73 00 af 01
+192: 73 00 63 00 0c 2e 4c 00 d4 33 03 00 00 00 00 00 00 00 00 00 00 00 00 00 
b7 01 00 00 af 01 d3 00 0c 2e 4c 00 00 00 00 00 0c 2e 4c 00 fc 2d 4c 00
+240: 21 00 00 00 21 00 00 00 00 00 4b 00 00 30 00 00 02 30 21 00 c2 55 6a 0d 
08 00 c3 00 8a 3e 00 00 69 61 4c 00 00 00 00 00 00 00 00 00 e4 23 00 00
+288: 01 00 00 00 19 00 00 00 c2 55 4b 00 01 68 00 00 02 30 4c 00 00 00 00 00 
00 00 00 00 4c 2e 00 24 01 31 00 00 b7 01 00 00 00 00 00 00 af 01 00 00
+336: af 01 00 00 00 32 00 00 00 00 00 00 12 2b 00 00 58 18 48 00 a7 01 00 00 
5d 18 48 00 01 00 00 00 f0 a9 47 00 19 00 00 00 69 61 4c 00 86 00 00 00
+384: c2 55 4b 00 00 06 00 00 0a 00 00 00 05 9a 47 00 d7 80 4a 00 70 5c 47 00 
44 2f 4c 00 00 0a 00 00 ac 2e 4c 00 7c 5c 47 00 73 2e 4c 00 05 9b 47 00
+432: c2 55 4b 00 f1 ff ff ff ff ff ff ff d0 67 4c 00 18 00 00 00 d0 73 20 00 
d0 67 4c 00 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+480: 00 00 00 00 00 00 00 00 00 51 43 00 ef 20 46 00 cd 01 00 00 f7 20 46 00 
14 00 00 00 14 00 00 00
+
+SMART:
+fis: 27 80 b0 d6 be 4f c2 a0 bf 00 00 d6 01 01 00 02 00 00 00 00
+data_out: 57 00 1a 00..
+
+SMART:
+fis: 27 80 b0 d5 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00
+data_in: 01 00..
+
+SMART:
+fis: 27 80 b0 d6 be 4f c2 a0 bf 00 00 d5 01 00 00 02 00 00 00 00
+data_out: 2a 00 02 00 02 00 0d 00 16 00 01 00..
+
+SMART:
+fis: 27 80 b0 d6 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00
+data_out: fc 2c 4c 00 01
+
+SMART:
+fis: 27 80 b0 d6 be 4f c2 a0 bf 00 00 d6 01 01 00 02 00 00 00 00
+data_out: 2a 00 01 00 02 00 0d 00 16 00 01 00..
+
+SMART:
+fis: 27 80 b0 d5 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00
+data_in: fc 00..
+
+VSC_DISABLE:
+fis: 27 80 80 44 bf 44 57 a0 00 00 00 d5 00 00 00 02 00 00 00 00
+
+----------------------------------------------------------------------------------------------------------------------------------------------------
+
+wdidle3-300.sata: set idle3 timeout to 300 seconds.
+
+IDENTIFY:
+data_in:
+  0: 7a 42 ff 3f 37 c8 10 00 00 00 00 00 3f 00 00 00 00 00 00 00 20 20 20 20 
57 20 2d 44 4d 57 56 41 30 35 32 33 35 36 36 38 00 00 ff ff 32 00 31 30
+ 48: 30 2e 41 30 31 30 44 57 20 43 44 57 30 35 30 30 41 41 53 44 30 2d 4d 30 
42 32 20 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 10 80
+ 96: 00 00 00 2f 01 40 00 00 00 00 07 00 ff 3f 10 00 3f 00 10 fc fb 00 00 01 
ff ff ff 0f 00 00 07 00 03 00 78 00 78 00 78 00 78 00 00 00 00 00 00 00
+144: 00 00 00 00 00 00 1f 00 06 17 00 00 44 00 40 00 fe 01 00 00 6b 74 61 7f 
23 41 69 74 41 bc 23 41 7f 40 4a 00 4a 00 00 00 fe ff 00 00 fe 80 00 00
+192: 00 00 00 00 00 00 00 00 30 60 38 3a 00 00 00 00 00 00 00 00 00 00 00 00 
01 50 e0 4e 81 ac a1 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1c 40
+240: 1c 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 21 00 00 00 00 00 00 00 
00 00 ce 16 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00
+288: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+336: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+384: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 37 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+432: 00 00 00 00 00 00 00 00 00 00 00 00 1e 10 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 10 00 00 00 00 00 00 00 00
+480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 a5 60
+
+VSC_ENABLE:
+fis: 27 80 80 45 01 44 57 a0 00 00 00 44 00 00 00 02 00 00 00 00
+
+SMART:
+fis: 27 80 b0 d6 be 4f c2 a0 01 44 57 45 01 00 00 02 00 00 00 00
+data_out: 57 00 1b 00..
+
+SMART:
+fis: 27 80 b0 d6 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00
+data_out:
+  0: e0 93 04 00 f2 0b 00 00 d3 de 43 00 ff ff ff ff 00 00 00 00 78 57 55 00 
3c 2d 4c 00 60 70 4b 00 66 70 4b 00 00 00 00 00 00 00 00 00 f2 0b 00 00
+ 48: d4 2e 4c 00 60 70 4b 00 d8 67 4c 00 08 60 4c 00 6e 4f 44 00 66 70 4b 00 
14 00 00 00 14 00 00 00 f2 0b 00 00 b2 80 43 00 64 00 00 00 a0 00 00 00
+ 96: 50 40 55 00 73 00 83 00 73 00 63 00 e8 06 00 00 d4 33 03 00 00 00 00 00 
00 00 00 00 00 00 00 00 b7 01 87 01 83 00 83 00 e8 06 00 00 38 00 00 00
+144: d4 2d 4c 00 a4 2d 4c 00 21 00 00 00 19 00 00 00 00 00 00 00 00 03 00 00 
46 32 21 00 00 00 6e 0d 15 00 c3 00 22 04 00 00 00 00 00 00 00 00 46 32
+192: d8 2d 46 32 00 02 00 00 00 03 00 00 46 32 00 00 46 32 00 00 00 03 00 00 
81 00 00 00 e8 06 00 00 71 61 4c 00 1c 2e 4c 00 f8 2d 4c 00 21 00 00 00
+240: 19 00 00 00 19 00 00 00 01 ff 00 00 b7 01 00 00 87 01 00 00 83 00 00 00 
af 01 00 00 b6 05 00 00 37 01 00 00 00 32 00 00 c3 05 00 00 60 00 00 00
+288: 19 00 00 00 01 00 00 00 58 61 4c 00 3c 2e 4c 00 01 00 00 00 58 61 4c 00 
19 00 00 00 19 00 00 00 b7 01 00 00 00 00 00 00 af 01 00 00 af 01 00 00
+336: 1f 01 48 00 a7 01 00 00 44 32 00 00 19 00 00 00 00 00 00 00 58 61 4c 00 
19 00 00 00 c2 55 4b 00 59 a9 47 00 19 00 00 00 71 61 4c 00 86 00 00 00
+384: c2 55 4b 00 00 06 00 00 0a 00 00 00 05 9a 47 00 d7 80 4a 00 70 5c 47 00 
44 2f 4c 00 00 0a 00 00 ac 2e 4c 00 7c 5c 47 00 73 2e 4c 00 05 9b 47 00
+432: c2 55 4b 00 f1 ff ff ff ff ff ff ff d8 67 4c 00 18 00 00 00 d8 73 20 00 
d8 67 4c 00 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+480: 00 00 00 00 00 00 00 00 00 51 43 00 ef 20 46 00 17 02 00 00 f7 20 46 00 
14 00 00 00 14 00 00 00
+
+SMART:
+fis:  27 80 b0 d6 be 4f c2 a0 bf 00 00 d6 01 01 00 02 00 00 00 00
+data_out: 57 00 1a 00..
+
+SMART:
+fis: 27 80 b0 d5 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00
+data_in: e0 93 04 00..
+
+SMART:
+fis: 27 80 b0 d6 be 4f c2 a0 bf 00 00 d5 01 00 00 02 00 00 00 00
+data_out: 2a 00 02 00 02 00 0d 00 16 00 01 00..
+
+SMART:
+fis: 27 80 b0 d6 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00
+data: 8a 2c 4c 00 e0 93 04 00..
+
+SMART:
+fis: 27 80 b0 d6 be 4f c2 a0 bf 00 00 d6 01 01 00 02 00 00 00 00
+data_out: 2a 00 01 00 02 00 0d 00 16 00 01 00
+
+SMART:
+fis: 27 80 b0 d5 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00
+data_in: 8a 00..
+
+VSC_DISABLE:
+fis: 27 80 80 44 bf 44 57 a0 00 00 00 d5 00 00 00 02 00 00 00 00
+
+----------------------------------------------------------------------------------------------------------------------------------------------------
+
+wdidle3-30.5.sata: change idle3 timeout to 30.5(?) seconds.
+
+IDENTIFY:
+fis: 27 80 ec 44 01 00 00 a0 00 00 00 d5 01 00 00 02 00 00 00 00
+data_in:
+  0: 7a 42 ff 3f 37 c8 10 00 00 00 00 00 3f 00 00 00 00 00 00 00 20 20 20 20 
57 20 2d 44 4d 57 56 41 30 35 32 33 35 36 36 38 00 00 ff ff 32 00 31 30
+ 48: 30 2e 41 30 31 30 44 57 20 43 44 57 30 35 30 30 41 41 53 44 30 2d 4d 30 
42 32 20 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 10 80
+ 96: 00 00 00 2f 01 40 00 00 00 00 07 00 ff 3f 10 00 3f 00 10 fc fb 00 00 01 
ff ff ff 0f 00 00 07 00 03 00 78 00 78 00 78 00 78 00 00 00 00 00 00 00
+144: 00 00 00 00 00 00 1f 00 06 17 00 00 44 00 40 00 fe 01 00 00 6b 74 61 7f 
23 41 69 74 41 bc 23 41 7f 40 4a 00 4a 00 00 00 fe ff 00 00 fe 80 00 00
+192: 00 00 00 00 00 00 00 00 30 60 38 3a 00 00 00 00 00 00 00 00 00 00 00 00 
01 50 e0 4e 81 ac a1 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1c 40
+240: 1c 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 21 00 00 00 00 00 00 00 
00 00 ce 16 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00
+288: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+336: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+384: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 37 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+432: 00 00 00 00 00 00 00 00 00 00 00 00 1e 10 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 10 00 00 00 00 00 00 00 00
+480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 a5 60
+
+VSC_ENABLE:
+fis: 27 80 80 45 01 44 57 a0 00 00 00 44 00 00 00 02 00 00 00 00
+
+SMART:
+fis: 27 80 b0 d6 be 4f c2 a0 01 44 57 45 01 00 00 02 00 00 00 00
+data_out: 57 00 1b 00..
+
+SMART:
+fis: 27 80 b0 d6 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00
+data_out:
+  0: 24 77 00 00 f2 0b 00 00 d3 de 43 00 ff ff ff ff 00 00 00 00 78 57 55 00 
3c 2d 4c 00 60 70 4b 00 67 70 4b 00 00 00 00 00 00 00 00 00 f2 0b 00 00
+ 48: d4 2e 4c 00 60 70 4b 00 d8 67 4c 00 08 60 4c 00 6e 4f 44 00 67 70 4b 00 
14 00 00 00 14 00 00 00 f2 0b 00 00 b2 80 43 00 64 00 00 00 a0 00 00 00
+ 96: 50 40 55 00 73 00 83 00 73 00 63 00 e8 06 00 00 d4 33 03 00 00 00 00 00 
00 00 00 00 00 00 00 00 b7 01 87 01 83 00 83 00 e8 06 00 00 38 00 00 00
+144: d4 2d 4c 00 a4 2d 4c 00 21 00 00 00 19 00 00 00 00 00 00 00 00 03 00 00 
46 32 21 00 00 00 6e 0d 15 00 c3 00 22 04 00 00 00 00 00 00 00 00 46 32
+192: d8 2d 46 32 00 02 00 00 00 03 00 00 46 32 00 00 46 32 00 00 00 03 00 00 
81 00 00 00 e8 06 00 00 71 61 4c 00 1c 2e 4c 00 f8 2d 4c 00 21 00 00 00
+240: 19 00 00 00 19 00 00 00 01 ff 00 00 b7 01 00 00 87 01 00 00 83 00 00 00 
af 01 00 00 b6 05 00 00 37 01 00 00 00 32 00 00 c3 05 00 00 60 00 00 00
+288: 19 00 00 00 01 00 00 00 58 61 4c 00 3c 2e 4c 00 01 00 00 00 58 61 4c 00 
19 00 00 00 19 00 00 00 b7 01 00 00 00 00 00 00 af 01 00 00 af 01 00 00
+336: 1f 01 48 00 a7 01 00 00 44 32 00 00 19 00 00 00 00 00 00 00 58 61 4c 00 
19 00 00 00 c2 55 4b 00 59 a9 47 00 19 00 00 00 71 61 4c 00 86 00 00 00
+384: c2 55 4b 00 00 06 00 00 0a 00 00 00 05 9a 47 00 d7 80 4a 00 70 5c 47 00 
44 2f 4c 00 00 0a 00 00 ac 2e 4c 00 7c 5c 47 00 73 2e 4c 00 05 9b 47 00
+432: c2 55 4b 00 f1 ff ff ff ff ff ff ff d8 67 4c 00 18 00 00 00 d8 73 20 00 
d8 67 4c 00 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+480: 00 00 00 00 00 00 00 00 00 51 43 00 ef 20 46 00 4c 02 00 00 f7 20 46 00 
14 00 00 00 14 00 00 00
+
+SMART:
+fis: 27 80 b0 d6 be 4f c2 a0 bf 00 00 d6 01 01 00 02 00 00 00 00
+data_out: 57 00 1a 00..
+
+SMART:
+fis: 27 80 b0 d5 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00
+data_in:  24 77 00..
+
+SMART:
+fis: 27 80 b0 d6 be 4f c2 a0 bf 00 00 d5 01 00 00 02 00 00 00 00
+data_out: 2A 00 02 00 02 00 0D 00 16 00 01 00..
+
+SMART:
+fis: 27 80 b0 d6 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00
+data_out: 81 2c 4c 00 24 77 00
+
+SMART:
+fis: 27 80 b0 d6 be 4f c2 a0 bf 00 00 d6 01 01 00 02 00 00 00 00
+data_out: 2a 00 01 00 02 00 0d 00 16 00 01 00..
+
+SMART:
+fis: 27 80 b0 d5 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00
+data_in: 81 00..
+
+VSC_DISABLE:
+fis: 27 80 80 44 bf 44 57 a0 00 00 00 d5 00 00 00 02
+
+----------------------------------------------------------------------------------------------------------------------------------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hdparm-9.37/hdparm.8 new/hdparm-9.38/hdparm.8
--- old/hdparm-9.37/hdparm.8    2010-11-11 15:35:57.000000000 +0100
+++ new/hdparm-9.38/hdparm.8    2012-01-07 22:58:56.000000000 +0100
@@ -1,4 +1,4 @@
-.TH HDPARM 8 "November 2010" "Version 9.36"
+.TH HDPARM 8 "January 2012" "Version 9.38"
 
 .SH NAME
 hdparm \- get/set SATA/IDE device parameters
@@ -308,6 +308,31 @@
 .B --Istdin
 option.
 .TP
+.I -J
+Get/set the Western Digital (WD) Green Drive's "idle3" timeout value.
+This timeout controls how often the drive parks its heads and enters
+a low power consumption state.  The factory default is eight (8) seconds,
+which is a very poor choice for use with Linux.  Leaving it at the default
+will result in hundreds of thousands of head load/unload cycles in a very
+short period of time.  The drive mechanism is only rated for 300,000 to 
1,000,000
+cycles, so leaving it at the default could result in premature failure,
+not to mention the performance impact of the drive often having to wake-up
+before doing routine I/O.
+.IP
+WD supply a WDIDLE3.EXE DOS utility for tweaking this setting,
+and you should use that program instead of hdparm
+if at all possible.  The reverse-engineered implementation in hdparm
+is not as complete as the original official program, even though it does
+seem to work on at a least a few drives.  A full power cycle is required
+for any change in setting to take effect, regardless of which program is
+used to tweak things.
+.IP
+A setting of 30 seconds is recommended for Linux use.
+Permitted values are from 8 to 12 seconds, and from 30 to 300 seconds
+in 30-second increments.
+Specify a value of zero (0) to disable the WD idle3 timer completely
+(NOT RECOMMENDED!).
+.TP
 .I -k
 Get/set the "keep_settings_over_reset" flag for the drive.
 When this flag is set, the drive will preserve the
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hdparm-9.37/hdparm.c new/hdparm-9.38/hdparm.c
--- old/hdparm-9.37/hdparm.c    2011-01-24 16:15:17.000000000 +0100
+++ new/hdparm-9.38/hdparm.c    2012-01-07 22:57:24.000000000 +0100
@@ -35,7 +35,7 @@
 
 extern const char *minor_str[];
 
-#define VERSION "v9.37"
+#define VERSION "v9.38"
 
 #ifndef O_DIRECT
 #define O_DIRECT       040000  /* direct disk access, not easily obtained from 
headers */
@@ -55,7 +55,7 @@
 static int do_identity = 0, get_geom = 0, noisy = 1, quiet = 0;
 static int do_flush_wcache = 0;
 
-//static int set_wdidle3  = 0;
+static int set_wdidle3  = 0, get_wdidle3 = 0, wdidle3 = 0;
 static int   set_timings_offset = 0;
 static __u64 timings_offset = 0;
 static int set_fsreadahead= 0, get_fsreadahead= 0, fsreadahead= 0;
@@ -706,15 +706,25 @@
        if (id) {
                timeout = id[idx];
                if (timeout && timeout <= 0xff) {
-                       if (timeout == 0xff)
+                       /*
+                        * 0xff means "more than 254 2-minute intervals (508+ 
minutes),
+                        * but we really want a better idea than that.
+                        * Norman Diamond suggests allowing 1sec per 30MB of 
capacity.
+                        */
+                       if (timeout == 0xff) {
+                               __u64 lba_limit = get_lba_capacity(id);
+                               __u64 estimate = (lba_limit / 2048ULL) / 30ULL 
/ 60;
                                timeout = 508 + 60;  /* spec says > 508 minutes 
*/
-                       else
+                               if (timeout < estimate)
+                                       timeout = estimate;
+                       } else {
                                timeout = (timeout * 2) + 5;  /* Add on a 5min 
margin */
+                       }
                }
        }
        if (!timeout)
                timeout = 2 * 60;  /* default: two hours */
-       timeout *= 60; /* secs */
+       timeout *= 60; /* convert minutes to seconds */
        return timeout;
 }
 
@@ -778,7 +788,7 @@
                        exit(EINVAL);
        }
        printf(" Issuing %s command, password=\"%s\", user=%s",
-               description, security_password, data[0] ? "master" : "user");
+               description, security_password, (data[0] & 1) ? "master" : 
"user");
        if (security_command == ATA_OP_SECURITY_SET_PASS)
                printf(", mode=%s", data[1] ? "max" : "high");
        printf("\n");
@@ -949,44 +959,6 @@
        exit(EINVAL);
 }
 
-#if 0
-static int do_wdidle3 (int fd, const char *devname)
-{
-       struct ata_tf tf;
-       int err = 0;
-       const unsigned char vu_op = 0x8a;
-
-       abort_if_not_full_device(fd, 0, devname, NULL);
-       confirm_please_destroy_my_drive("--wdidle3", "This is not fully 
implemented yet, and could destroy the drive and/or all data on it.");
-       printf("attempting to tweak Western Digital \"idle-3\" parameters\n");
-       fflush(stdout);
-
-  {
-    unsigned char bits;
-    for (bits = 0; bits <= 0x1f; ++bits) {
-       tf_init(&tf, vu_op, 0, 0);
-       tf.lob.feat  = 'W';
-       tf.lob.nsect = 'D';
-       tf.lob.lbal  = 'C';
-       tf.lob.lbam  = 0x00;
-       tf.lob.lbah  = 0x00;
-       tf.dev       = 0xa0 | (tf.dev & 0xb0) | (bits & 0xf);
-       if (bits >= 0x10)
-               tf.dev |= 0x40;
-
-       /* This probably wants to transfer data, but.. ???? */
-       if (sg16(fd, SG_WRITE, SG_PIO, &tf, NULL, 0, 5 /* seconds */)) {
-               err = errno;
-               perror("FAILED");
-       } else {
-               printf("succeeded\n");
-       }
-    }
-  }
-       return err;
-}
-#endif
-
 static __u16 *get_dco_identify_data (int fd, int quietly)
 {
        static __u8 args[4+512];
@@ -1016,6 +988,9 @@
        __u64 max = 0;
        struct hdio_taskfile r;
 
+       get_identify_data(fd);
+       if (!id)
+               exit(EIO);
        memset(&r, 0, sizeof(r));
        r.cmd_req = TASKFILE_CMD_REQ_NODATA;
        r.dphase  = TASKFILE_DPHASE_NONE;
@@ -1027,9 +1002,6 @@
        r.iflags.lob.lbah     = 1;
        r.lob.dev = 0x40;
 
-       get_identify_data(fd);
-       if (!id)
-               exit(EIO);
        if (((id[83] & 0xc400) == 0x4400) && (id[86] & 0x0400)) {
                r.iflags.hob.lbal  = 1;
                r.iflags.hob.lbam  = 1;
@@ -1466,6 +1438,7 @@
        " -H   Read temperature from drive (Hitachi only)\n"
        " -i   Display drive identification\n"
        " -I   Detailed/current information directly from drive\n"
+       " -J   Get/set Western DIgital \"Idle3\" timeout for a WDC \"Green\" 
drive (DANGEROUS)\n"
        " -k   Get/set keep_settings_over_reset flag (0/1)\n"
        " -K   Set drive keep_features_over_reset flag (0/1)\n"
        " -L   Set drive doorlock (0/1) (removable harddisks only)\n"
@@ -1518,7 +1491,6 @@
        " --trim-sector-ranges        Tell SSD firmware to discard unneeded 
data sectors: lba:count ..\n"
        " --trim-sector-ranges-stdin  Same as above, but reads lba:count pairs 
from stdin\n"
        " --verbose         Display extra diagnostics from some commands\n"
-       //" --wdidle3         Issue the Western Digitial \"Idle3\" command 
(EXTREMELY DANGEROUS)\n"
        " --write-sector    Repair/overwrite a (possibly bad) sector directly 
on the media (VERY DANGEROUS)\n"
        "\n");
        exit(rc);
@@ -1578,8 +1550,16 @@
                exit(do_trim_from_stdin(fd, devname));
        }
 
-       //if (set_wdidle3)
-       //      do_wdidle3(fd, devname);
+       if (set_wdidle3) {
+               unsigned char timeout = wdidle3_msecs_to_timeout(wdidle3);
+               confirm_please_destroy_my_drive("-J", "This implementation is 
not as thorough as the official WDIDLE3.EXE. Use at your own risk!");
+               if (get_wdidle3) {
+                       printf(" setting wdidle3 to ");
+                       wdidle3_print_timeout(timeout);
+                       putchar('\n');
+               }
+               err = wdidle3_set_timeout(fd, timeout);
+       }
        if (set_fsreadahead) {
                if (get_fsreadahead)
                        printf(" setting fs readahead to %d\n", fsreadahead);
@@ -2149,6 +2129,15 @@
                                printf("%lld\n", start_lba);
                }
        }
+       if (get_wdidle3) {
+               unsigned char timeout = 0;
+               err = wdidle3_get_timeout(fd, &timeout);
+               if (!err) {
+                       printf(" wdidle3      = ");
+                       wdidle3_print_timeout(timeout);
+                       putchar('\n');
+               }
+       }
        if (get_powermode) {
                __u8 args[4] = {ATA_OP_CHECKPOWERMODE1,0,0,0};
                const char *state = "unknown";
@@ -2670,8 +2659,6 @@
        } else if (0 == strcasecmp(name, "read-sector")) {
                read_sector = 1;
                get_u64_parm(0, 0, NULL, &read_sector_addr, 0, lba_limit, name, 
lba_emsg);
-       //} else if (0 == strcasecmp(name, "wdidle3")) {
-       //      set_wdidle3 = 1;
        } else if (0 == strcasecmp(name, "Istdout")) {
                do_IDentity = 2;
        } else if (0 == strcasecmp(name, "security-mode")) {
@@ -2759,6 +2746,7 @@
                                case     SET_FLAG('H',hitachi_temp);
                                case      DO_FLAG('i',do_identity);
                                case      DO_FLAG('I',do_IDentity);
+                               case 
GET_SET_PARM('J',"WDC-idle3-timeout",wdidle3,0,300);
                                case 
GET_SET_PARM('k',"kernel-keep-settings",keep,0,1);
                                case     
SET_PARM('K',"drive-keep-settings",dkeep,0,1);
                                case     SET_PARM('L',"door-lock",doorlock,0,1);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hdparm-9.37/hdparm.h new/hdparm-9.38/hdparm.h
--- old/hdparm-9.37/hdparm.h    2010-11-24 22:54:19.000000000 +0100
+++ new/hdparm-9.38/hdparm.h    2012-01-06 17:38:59.000000000 +0100
@@ -25,6 +25,11 @@
 int set_dvdspeed(int fd, int speed);
 int fd_is_raid (int fd);
 
+int  wdidle3_set_timeout (int fd, unsigned char timeout);
+int  wdidle3_get_timeout (int fd, unsigned char *timeout);
+void wdidle3_print_timeout (unsigned char timeout);
+unsigned char wdidle3_msecs_to_timeout (unsigned int msecs);
+
 extern const char *BuffType[4];
 
 struct local_hd_big_geometry {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hdparm-9.37/hdparm.lsm new/hdparm-9.38/hdparm.lsm
--- old/hdparm-9.37/hdparm.lsm  2011-01-24 16:17:21.000000000 +0100
+++ new/hdparm-9.38/hdparm.lsm  2012-01-07 23:00:13.000000000 +0100
@@ -1,9 +1,10 @@
 Begin4
 Title:         hdparm
-Version:       9.37
-Entered-date:  2011-01-24
+Version:       9.38
+Entered-date:  2012-01-07
 Description:   hdparm - get/set hard disk parameters for Linux SATA/IDE drives.
-               v9.37 Enable --fibmap to work on RAID1; other tweaks.
+               v9.38 Added -J, fixed erase timeouts, updated wiper.sh
+               v9.37 Enable --fibmap to work on RAID1; other tweaks
                v9.36 manpage updates, wiper.sh version 3.1
                v9.35 Fixed CDB breakage from v9.34; -B works again now
                v9.34 Fixed CDB transfer length bug that affected some commands
@@ -111,7 +112,7 @@
 Maintained-by: [email protected] (Mark Lord)
 Primary-site:  http://sourceforge.net/projects/hdparm/
 Alternate-site:        http://www.ibiblio.org/pub/Linux/system/hardware
-               122K hdparm-9.37.tar.gz
+               131K hdparm-9.38.tar.gz
                4K hdparm.lsm
 Platforms:     Linux
 Copying-policy:        BSD License
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hdparm-9.37/identify.c new/hdparm-9.38/identify.c
--- old/hdparm-9.37/identify.c  2010-09-24 01:24:50.000000000 +0200
+++ new/hdparm-9.38/identify.c  2011-12-04 23:49:22.000000000 +0100
@@ -1330,8 +1330,20 @@
                kk =  val[ENH_ERASE_TIME];
                if((jj && jj <= 0x00ff) || (kk && kk <= 0x00ff)) {
                        printf("\t");
-                       if(jj) printf("%umin for SECURITY ERASE UNIT. ",        
 (jj == 0xff) ? 508 : (jj * 2));
-                       if(kk) printf("%umin for ENHANCED SECURITY ERASE 
UNIT.", (kk == 0xff) ? 508 : (kk * 2));
+                       if (jj) {
+                               if (jj == 0xff)
+                                       printf("more than 508");
+                               else
+                                       printf("%u", jj * 2);
+                               printf("min for SECURITY ERASE UNIT. ");
+                       }
+                       if (kk) {
+                               if (kk == 0xff)
+                                       printf("more than 508");
+                               else
+                                       printf("%u", kk * 2);
+                               printf("min for ENHANCED SECURITY ERASE UNIT. 
");
+                       }
                        printf("\n");
                }
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hdparm-9.37/sgio.c new/hdparm-9.38/sgio.c
--- old/hdparm-9.37/sgio.c      2010-10-19 15:10:00.000000000 +0200
+++ new/hdparm-9.38/sgio.c      2012-01-06 17:06:03.000000000 +0100
@@ -95,6 +95,8 @@
                        return 1;
                case ATA_OP_SECURITY_ERASE_PREPARE:
                case ATA_OP_SECURITY_ERASE_UNIT:
+               case ATA_OP_VENDOR_SPECIFIC_0x80:
+               case ATA_OP_SMART:
                        return 0;
        }
        if (lba >= lba28_limit)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hdparm-9.37/sgio.c.orig new/hdparm-9.38/sgio.c.orig
--- old/hdparm-9.37/sgio.c.orig 1970-01-01 01:00:00.000000000 +0100
+++ new/hdparm-9.38/sgio.c.orig 2010-10-19 15:10:00.000000000 +0200
@@ -0,0 +1,580 @@
+/* sgio.c - by Mark Lord (C) 2007 -- freely distributable */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <scsi/scsi.h>
+#include <scsi/sg.h>
+
+#include "sgio.h"
+#include "hdparm.h"
+
+#include <linux/hdreg.h>
+
+extern int verbose;
+extern int prefer_ata12;
+
+static const int default_timeout_secs = 15;
+
+/*
+ * Taskfile layout for SG_ATA_16 cdb:
+ *
+ * LBA48:
+ * cdb[ 3] = hob_feat
+ * cdb[ 5] = hob_nsect
+ * cdb[ 7] = hob_lbal
+ * cdb[ 9] = hob_lbam
+ * cdb[11] = hob_lbah
+ *
+ * LBA28/LBA48:
+ * cdb[ 4] = feat
+ * cdb[ 6] = nsect
+ * cdb[ 8] = lbal
+ * cdb[10] = lbam
+ * cdb[12] = lbah
+ * cdb[13] = device
+ * cdb[14] = command
+ *
+ * Taskfile layout for SG_ATA_12 cdb:
+ *
+ * cdb[ 3] = feat
+ * cdb[ 4] = nsect
+ * cdb[ 5] = lbal
+ * cdb[ 6] = lbam
+ * cdb[ 7] = lbah
+ * cdb[ 8] = device
+ * cdb[ 9] = command
+ *
+ * dxfer_direction choices:
+ *     SG_DXFER_TO_DEV, SG_DXFER_FROM_DEV, SG_DXFER_NONE
+ */
+
+#if 0  /* maybe use this in sg16 later.. ? */
+static inline int get_rw (__u8 ata_op)
+{
+       switch (ata_op) {
+               case ATA_OP_DSM:
+               case ATA_OP_WRITE_PIO:
+               case ATA_OP_WRITE_LONG:
+               case ATA_OP_WRITE_LONG_ONCE:
+               case ATA_OP_WRITE_PIO_EXT:
+               case ATA_OP_WRITE_DMA_EXT:
+               case ATA_OP_WRITE_FPDMA:
+               case ATA_OP_WRITE_UNC_EXT:
+               case ATA_OP_WRITE_DMA:
+               case ATA_OP_SECURITY_UNLOCK:
+               case ATA_OP_SECURITY_DISABLE:
+               case ATA_OP_SECURITY_ERASE_UNIT:
+               case ATA_OP_SECURITY_SET_PASS:
+                       return SG_WRITE;
+               default:
+                       return SG_READ;
+       }
+}
+#endif
+
+static inline int needs_lba48 (__u8 ata_op, __u64 lba, unsigned int nsect)
+{
+       switch (ata_op) {
+               case ATA_OP_DSM:
+               case ATA_OP_READ_PIO_EXT:
+               case ATA_OP_READ_DMA_EXT:
+               case ATA_OP_WRITE_PIO_EXT:
+               case ATA_OP_WRITE_DMA_EXT:
+               case ATA_OP_READ_VERIFY_EXT:
+               case ATA_OP_WRITE_UNC_EXT:
+               case ATA_OP_READ_NATIVE_MAX_EXT:
+               case ATA_OP_SET_MAX_EXT:
+               case ATA_OP_FLUSHCACHE_EXT:
+                       return 1;
+               case ATA_OP_SECURITY_ERASE_PREPARE:
+               case ATA_OP_SECURITY_ERASE_UNIT:
+                       return 0;
+       }
+       if (lba >= lba28_limit)
+               return 1;
+       if (nsect) {
+               if (nsect > 0xff)
+                       return 1;
+               if ((lba + nsect - 1) >= lba28_limit)
+                       return 1;
+       }
+       return 0;
+}
+
+static inline int is_dma (__u8 ata_op)
+{
+       switch (ata_op) {
+               case ATA_OP_DSM:
+               case ATA_OP_READ_DMA_EXT:
+               case ATA_OP_READ_FPDMA:
+               case ATA_OP_WRITE_DMA_EXT:
+               case ATA_OP_WRITE_FPDMA:
+               case ATA_OP_READ_DMA:
+               case ATA_OP_WRITE_DMA:
+                       return SG_DMA;
+               default:
+                       return SG_PIO;
+       }
+}
+
+void tf_init (struct ata_tf *tf, __u8 ata_op, __u64 lba, unsigned int nsect)
+{
+       memset(tf, 0, sizeof(*tf));
+       tf->command  = ata_op;
+       tf->dev      = ATA_USING_LBA;
+       tf->lob.lbal = lba;
+       tf->lob.lbam = lba >>  8;
+       tf->lob.lbah = lba >> 16;
+       tf->lob.nsect = nsect;
+       if (needs_lba48(ata_op, lba, nsect)) {
+               tf->is_lba48 = 1;
+               tf->hob.nsect = nsect >> 8;
+               tf->hob.lbal = lba >> 24;
+               tf->hob.lbam = lba >> 32;
+               tf->hob.lbah = lba >> 40;
+       } else {
+               tf->dev |= (lba >> 24) & 0x0f;
+       }
+}
+
+#ifdef SG_IO
+
+__u64 tf_to_lba (struct ata_tf *tf)
+{
+       __u32 lba24, lbah;
+       __u64 lba64;
+
+       lba24 = (tf->lob.lbah << 16) | (tf->lob.lbam << 8) | (tf->lob.lbal);
+       if (tf->is_lba48)
+               lbah = (tf->hob.lbah << 16) | (tf->hob.lbam << 8) | 
(tf->hob.lbal);
+       else
+               lbah = (tf->dev & 0x0f);
+       lba64 = (((__u64)lbah) << 24) | (__u64)lba24;
+       return lba64;
+}
+
+enum {
+       SG_CDB2_TLEN_NODATA     = 0 << 0,
+       SG_CDB2_TLEN_FEAT       = 1 << 0,
+       SG_CDB2_TLEN_NSECT      = 2 << 0,
+
+       SG_CDB2_TLEN_BYTES      = 0 << 2,
+       SG_CDB2_TLEN_SECTORS    = 1 << 2,
+
+       SG_CDB2_TDIR_TO_DEV     = 0 << 3,
+       SG_CDB2_TDIR_FROM_DEV   = 1 << 3,
+
+       SG_CDB2_CHECK_COND      = 1 << 5,
+};
+
+static void dump_bytes (const char *prefix, unsigned char *p, int len)
+{
+       int i;
+
+       if (prefix)
+               fprintf(stderr, "%s: ", prefix);
+       for (i = 0; i < len; ++i)
+               fprintf(stderr, " %02x", p[i]);
+       fprintf(stderr, "\n");
+}
+
+int sg16 (int fd, int rw, int dma, struct ata_tf *tf,
+       void *data, unsigned int data_bytes, unsigned int timeout_secs)
+{
+       unsigned char cdb[SG_ATA_16_LEN];
+       unsigned char sb[32], *desc;
+       struct scsi_sg_io_hdr io_hdr;
+       int prefer12 = prefer_ata12, demanded_sense = 0;
+
+       if (tf->command == ATA_OP_PIDENTIFY)
+               prefer12 = 0;
+
+       memset(&cdb, 0, sizeof(cdb));
+       memset(&sb,     0, sizeof(sb));
+       memset(&io_hdr, 0, sizeof(struct scsi_sg_io_hdr));
+       if (data && data_bytes && !rw)
+               memset(data, 0, data_bytes);
+
+       if (dma) {
+               //cdb[1] = data ? (rw ? SG_ATA_PROTO_UDMA_OUT : 
SG_ATA_PROTO_UDMA_IN) : SG_ATA_PROTO_NON_DATA;
+               cdb[1] = data ? SG_ATA_PROTO_DMA : SG_ATA_PROTO_NON_DATA;
+       } else {
+               cdb[1] = data ? (rw ? SG_ATA_PROTO_PIO_OUT : 
SG_ATA_PROTO_PIO_IN) : SG_ATA_PROTO_NON_DATA;
+       }
+
+       /* libata/AHCI workaround: don't demand sense data for IDENTIFY 
commands */
+       if (data) {
+               cdb[2] |= SG_CDB2_TLEN_NSECT | SG_CDB2_TLEN_SECTORS;
+               cdb[2] |= rw ? SG_CDB2_TDIR_TO_DEV : SG_CDB2_TDIR_FROM_DEV;
+       } else {
+               cdb[2] = SG_CDB2_CHECK_COND;
+       }
+
+       if (!prefer12 || tf->is_lba48) {
+               cdb[ 0] = SG_ATA_16;
+               cdb[ 4] = tf->lob.feat;
+               cdb[ 6] = tf->lob.nsect;
+               cdb[ 8] = tf->lob.lbal;
+               cdb[10] = tf->lob.lbam;
+               cdb[12] = tf->lob.lbah;
+               cdb[13] = tf->dev;
+               cdb[14] = tf->command;
+               if (tf->is_lba48) {
+                       cdb[ 1] |= SG_ATA_LBA48;
+                       cdb[ 3]  = tf->hob.feat;
+                       cdb[ 5]  = tf->hob.nsect;
+                       cdb[ 7]  = tf->hob.lbal;
+                       cdb[ 9]  = tf->hob.lbam;
+                       cdb[11]  = tf->hob.lbah;
+               }
+               io_hdr.cmd_len = SG_ATA_16_LEN;
+       } else {
+               cdb[ 0] = SG_ATA_12;
+               cdb[ 3] = tf->lob.feat;
+               cdb[ 4] = tf->lob.nsect;
+               cdb[ 5] = tf->lob.lbal;
+               cdb[ 6] = tf->lob.lbam;
+               cdb[ 7] = tf->lob.lbah;
+               cdb[ 8] = tf->dev;
+               cdb[ 9] = tf->command;
+               io_hdr.cmd_len = SG_ATA_12_LEN;
+       }
+
+       io_hdr.interface_id     = 'S';
+       io_hdr.mx_sb_len        = sizeof(sb);
+       io_hdr.dxfer_direction  = data ? (rw ? SG_DXFER_TO_DEV : 
SG_DXFER_FROM_DEV) : SG_DXFER_NONE;
+       io_hdr.dxfer_len        = data ? data_bytes : 0;
+       io_hdr.dxferp           = data;
+       io_hdr.cmdp             = cdb;
+       io_hdr.sbp              = sb;
+       io_hdr.pack_id          = tf_to_lba(tf);
+       io_hdr.timeout          = (timeout_secs ? timeout_secs : 
default_timeout_secs) * 1000; /* msecs */
+
+       if (verbose) {
+               dump_bytes("outgoing cdb", cdb, sizeof(cdb));
+               if (rw && data)
+                       dump_bytes("outgoing_data", data, data_bytes);
+       }
+
+       if (ioctl(fd, SG_IO, &io_hdr) == -1) {
+               if (verbose)
+                       perror("ioctl(fd,SG_IO)");
+               return -1;      /* SG_IO not supported */
+       }
+
+       if (verbose)
+               fprintf(stderr, "SG_IO: ATA_%u status=0x%x, host_status=0x%x, 
driver_status=0x%x\n",
+                       io_hdr.cmd_len, io_hdr.status, io_hdr.host_status, 
io_hdr.driver_status);
+
+       if (io_hdr.status && io_hdr.status != SG_CHECK_CONDITION) {
+               if (verbose)
+                       fprintf(stderr, "SG_IO: bad status: 0x%x\n", 
io_hdr.status);
+               errno = EBADE;
+               return -1;
+       }
+       if (io_hdr.host_status) {
+               if (verbose)
+                       fprintf(stderr, "SG_IO: bad host status: 0x%x\n", 
io_hdr.host_status);
+               errno = EBADE;
+               return -1;
+       }
+       if (verbose) {
+               dump_bytes("SG_IO: sb[]", sb, sizeof(sb));
+               if (!rw && data)
+                       dump_bytes("incoming_data", data, data_bytes);
+       }
+
+       if (io_hdr.driver_status && (io_hdr.driver_status != SG_DRIVER_SENSE)) {
+               if (verbose)
+                       fprintf(stderr, "SG_IO: bad driver status: 0x%x\n", 
io_hdr.driver_status);
+               errno = EBADE;
+               return -1;
+       }
+
+       desc = sb + 8;
+       if (io_hdr.driver_status != SG_DRIVER_SENSE) {
+               if (sb[0] | sb[1] | sb[2] | sb[3] | sb[4] | sb[5] | sb[6] | 
sb[7] | sb[8] | sb[9]) {
+                       static int second_try = 0;
+                       if (!second_try++)
+                               fprintf(stderr, "SG_IO: questionable sense 
data, results may be incorrect\n");
+               } else if (demanded_sense) {
+                       static int second_try = 0;
+                       if (!second_try++)
+                               fprintf(stderr, "SG_IO: missing sense data, 
results may be incorrect\n");
+               }
+       } else if (sb[0] != 0x72 || sb[7] < 14 || desc[0] != 0x09 || desc[1] < 
0x0c) {
+               dump_bytes("SG_IO: bad/missing sense data, sb[]", sb, 
sizeof(sb));
+       }
+
+       if (verbose) {
+               unsigned int len = desc[1] + 2, maxlen = sizeof(sb) - 8 - 2;
+               if (len > maxlen)
+                       len = maxlen;
+               dump_bytes("SG_IO: desc[]", desc, len);
+       }
+
+       tf->is_lba48  = desc[ 2] & 1;
+       tf->error     = desc[ 3];
+       tf->lob.nsect = desc[ 5];
+       tf->lob.lbal  = desc[ 7];
+       tf->lob.lbam  = desc[ 9];
+       tf->lob.lbah  = desc[11];
+       tf->dev       = desc[12];
+       tf->status    = desc[13];
+       tf->hob.feat  = 0;
+       if (tf->is_lba48) {
+               tf->hob.nsect = desc[ 4];
+               tf->hob.lbal  = desc[ 6];
+               tf->hob.lbam  = desc[ 8];
+               tf->hob.lbah  = desc[10];
+       } else {
+               tf->hob.nsect = 0;
+               tf->hob.lbal  = 0;
+               tf->hob.lbam  = 0;
+               tf->hob.lbah  = 0;
+       }
+
+       if (verbose)
+               fprintf(stderr, "      ATA_%u stat=%02x err=%02x nsect=%02x 
lbal=%02x lbam=%02x lbah=%02x dev=%02x\n",
+                               io_hdr.cmd_len, tf->status, tf->error, 
tf->lob.nsect, tf->lob.lbal, tf->lob.lbam, tf->lob.lbah, tf->dev);
+
+       if (tf->status & (ATA_STAT_ERR | ATA_STAT_DRQ)) {
+               if (verbose) {
+                       fprintf(stderr, "I/O error, ata_op=0x%02x 
ata_status=0x%02x ata_error=0x%02x\n",
+                               tf->command, tf->status, tf->error);
+               }
+               errno = EIO;
+               return -1;
+       }
+       return 0;
+}
+
+#endif /* SG_IO */
+
+int do_drive_cmd (int fd, unsigned char *args, unsigned int timeout_secs)
+{
+#ifdef SG_IO
+
+       struct ata_tf tf;
+       void *data = NULL;
+       unsigned int data_bytes = 0;
+       int rc;
+
+       if (args == NULL)
+               goto use_legacy_ioctl;
+       /*
+        * Reformat and try to issue via SG_IO:
+        * args[0]: command in; status out.
+        * args[1]: lbal for SMART, nsect for all others; error out
+        * args[2]: feat in; nsect out.
+        * args[3]: data-count (512 multiple) for all cmds.
+        */
+       tf_init(&tf, args[0], 0, 0);
+       tf.lob.nsect = args[1];
+       tf.lob.feat  = args[2];
+       if (args[3]) {
+               data_bytes   = args[3] * 512;
+               data         = args + 4;
+               if (!tf.lob.nsect)
+                       tf.lob.nsect = args[3];
+       }
+       if (tf.command == ATA_OP_SMART) {
+               tf.lob.nsect = args[3];
+               tf.lob.lbal  = args[1];
+               tf.lob.lbam  = 0x4f;
+               tf.lob.lbah  = 0xc2;
+       }
+
+       rc = sg16(fd, SG_READ, is_dma(tf.command), &tf, data, data_bytes, 
timeout_secs);
+       if (rc == -1) {
+               if (errno == EINVAL || errno == ENODEV || errno == EBADE)
+                       goto use_legacy_ioctl;
+       }
+
+       if (rc == 0 || errno == EIO) {
+               args[0] = tf.status;
+               args[1] = tf.error;
+               args[2] = tf.lob.nsect;
+       }
+       return rc;
+
+use_legacy_ioctl:
+#endif /* SG_IO */
+       if (verbose) {
+               if (args)
+                       fprintf(stderr, "Trying legacy HDIO_DRIVE_CMD\n");
+       }
+       return ioctl(fd, HDIO_DRIVE_CMD, args);
+}
+
+int do_taskfile_cmd (int fd, struct hdio_taskfile *r, unsigned int 
timeout_secs)
+{
+       int rc;
+#ifdef SG_IO
+       struct ata_tf tf;
+       void *data = NULL;
+       unsigned int data_bytes = 0;
+       int rw = SG_READ;
+       /*
+        * Reformat and try to issue via SG_IO:
+        */
+       tf_init(&tf, 0, 0, 0);
+#if 1 /* debugging */
+       if (verbose) {
+               printf("oflags.lob_all=0x%02x, flags={", r->oflags.lob_all);
+               if (r->oflags.lob.feat) printf(" feat");
+               if (r->oflags.lob.nsect)printf(" nsect");
+               if (r->oflags.lob.lbal) printf(" lbal");
+               if (r->oflags.lob.lbam) printf(" lbam");
+               if (r->oflags.lob.lbah) printf(" lbah");
+               if (r->oflags.lob.dev)  printf(" dev");
+               if (r->oflags.lob.command) printf(" command");
+               printf(" }\n");
+               printf("oflags.hob_all=0x%02x, flags={", r->oflags.hob_all);
+               if (r->oflags.hob.feat) printf(" feat");
+               if (r->oflags.hob.nsect)printf(" nsect");
+               if (r->oflags.hob.lbal) printf(" lbal");
+               if (r->oflags.hob.lbam) printf(" lbam");
+               if (r->oflags.hob.lbah) printf(" lbah");
+               printf(" }\n");
+       }
+#endif
+       if (r->oflags.lob.feat)         tf.lob.feat  = r->lob.feat;
+       if (r->oflags.lob.lbal)         tf.lob.lbal  = r->lob.lbal;
+       if (r->oflags.lob.nsect)        tf.lob.nsect = r->lob.nsect;
+       if (r->oflags.lob.lbam)         tf.lob.lbam  = r->lob.lbam;
+       if (r->oflags.lob.lbah)         tf.lob.lbah  = r->lob.lbah;
+       if (r->oflags.lob.dev)          tf.dev       = r->lob.dev;
+       if (r->oflags.lob.command)      tf.command   = r->lob.command;
+       if (needs_lba48(tf.command,0,0) || r->oflags.hob_all || 
r->iflags.hob_all) {
+               tf.is_lba48 = 1;
+               if (r->oflags.hob.feat) tf.hob.feat  = r->hob.feat;
+               if (r->oflags.hob.lbal) tf.hob.lbal  = r->hob.lbal;
+               if (r->oflags.hob.nsect)tf.hob.nsect = r->hob.nsect;
+               if (r->oflags.hob.lbam) tf.hob.lbam  = r->hob.lbam;
+               if (r->oflags.hob.lbah) tf.hob.lbah  = r->hob.lbah;
+               if (verbose)
+                       fprintf(stderr, "using LBA48 taskfile\n");
+       }
+       switch (r->cmd_req) {
+               case TASKFILE_CMD_REQ_OUT:
+               case TASKFILE_CMD_REQ_RAW_OUT:
+                       data_bytes = r->obytes;
+                       data       = r->data;
+                       rw         = SG_WRITE;
+                       break;
+               case TASKFILE_CMD_REQ_IN:
+                       data_bytes = r->ibytes;
+                       data       = r->data;
+                       break;
+       }
+
+       rc = sg16(fd, rw, is_dma(tf.command), &tf, data, data_bytes, 
timeout_secs);
+       if (rc == -1) {
+               if (errno == EINVAL || errno == ENODEV || errno == EBADE)
+                       goto use_legacy_ioctl;
+       }
+
+       if (rc == 0 || errno == EIO) {
+               if (r->iflags.lob.feat)         r->lob.feat  = tf.error;
+               if (r->iflags.lob.lbal)         r->lob.lbal  = tf.lob.lbal;
+               if (r->iflags.lob.nsect)        r->lob.nsect = tf.lob.nsect;
+               if (r->iflags.lob.lbam)         r->lob.lbam  = tf.lob.lbam;
+               if (r->iflags.lob.lbah)         r->lob.lbah  = tf.lob.lbah;
+               if (r->iflags.lob.dev)          r->lob.dev   = tf.dev;
+               if (r->iflags.lob.command)      r->lob.command = tf.status;
+               if (r->iflags.hob.feat)         r->hob.feat  = tf.hob.feat;
+               if (r->iflags.hob.lbal)         r->hob.lbal  = tf.hob.lbal;
+               if (r->iflags.hob.nsect)        r->hob.nsect = tf.hob.nsect;
+               if (r->iflags.hob.lbam)         r->hob.lbam  = tf.hob.lbam;
+               if (r->iflags.hob.lbah)         r->hob.lbah  = tf.hob.lbah;
+       }
+       return rc;
+
+use_legacy_ioctl:
+#else
+       timeout_secs = 0;       /* keep compiler happy */
+#endif /* SG_IO */
+       if (verbose)
+               fprintf(stderr, "trying legacy HDIO_DRIVE_TASKFILE\n");
+       errno = 0;
+
+       rc = ioctl(fd, HDIO_DRIVE_TASKFILE, r);
+       if (verbose) {
+               int err = errno;
+               fprintf(stderr, "rc=%d, errno=%d, returned ATA registers: ", 
rc, err);
+               if (r->iflags.lob.feat)         fprintf(stderr, " er=%02x", 
r->lob.feat);
+               if (r->iflags.lob.nsect)        fprintf(stderr, " ns=%02x", 
r->lob.nsect);
+               if (r->iflags.lob.lbal)         fprintf(stderr, " ll=%02x", 
r->lob.lbal);
+               if (r->iflags.lob.lbam)         fprintf(stderr, " lm=%02x", 
r->lob.lbam);
+               if (r->iflags.lob.lbah)         fprintf(stderr, " lh=%02x", 
r->lob.lbah);
+               if (r->iflags.lob.dev)          fprintf(stderr, " dh=%02x", 
r->lob.dev);
+               if (r->iflags.lob.command)      fprintf(stderr, " st=%02x", 
r->lob.command);
+               if (r->iflags.hob.feat)         fprintf(stderr, " err=%02x", 
r->hob.feat);
+               if (r->iflags.hob.nsect)        fprintf(stderr, " err=%02x", 
r->hob.nsect);
+               if (r->iflags.hob.lbal)         fprintf(stderr, " err=%02x", 
r->hob.lbal);
+               if (r->iflags.hob.lbam)         fprintf(stderr, " err=%02x", 
r->hob.lbam);
+               if (r->iflags.hob.lbah)         fprintf(stderr, " err=%02x", 
r->hob.lbah);
+               fprintf(stderr, "\n");
+               errno = err;
+       }
+       if (rc == -1 && errno == EINVAL) {
+               fprintf(stderr, "The running kernel lacks CONFIG_IDE_TASK_IOCTL 
support for this device.\n");
+               errno = EINVAL;
+       }
+       return rc;
+}
+
+void init_hdio_taskfile (struct hdio_taskfile *r, __u8 ata_op, int rw, int 
force_lba48,
+                               __u64 lba, unsigned int nsect, int data_bytes)
+{
+       memset(r, 0, sizeof(struct hdio_taskfile) + data_bytes);
+       if (!data_bytes) {
+               r->dphase  = TASKFILE_DPHASE_NONE;
+               r->cmd_req = TASKFILE_CMD_REQ_NODATA;
+       } else if (rw == RW_WRITE) {
+               r->dphase  = TASKFILE_DPHASE_PIO_OUT;
+               r->cmd_req = TASKFILE_CMD_REQ_RAW_OUT;
+               r->obytes  = data_bytes;
+       } else { /* rw == RW_READ */
+               r->dphase  = TASKFILE_DPHASE_PIO_IN;
+               r->cmd_req = TASKFILE_CMD_REQ_IN;
+               r->ibytes  = data_bytes;
+       }
+       r->lob.command      = ata_op;
+       r->oflags.lob.command = 1;
+       r->oflags.lob.dev     = 1;
+       r->oflags.lob.lbal    = 1;
+       r->oflags.lob.lbam    = 1;
+       r->oflags.lob.lbah    = 1;
+       r->oflags.lob.nsect   = 1;
+
+       r->iflags.lob.command = 1;
+       r->iflags.lob.feat    = 1;
+
+       r->lob.nsect = nsect;
+       r->lob.lbal  = lba;
+       r->lob.lbam  = lba >>  8;
+       r->lob.lbah  = lba >> 16;
+       r->lob.dev   = 0xa0 | ATA_USING_LBA;
+
+       if (needs_lba48(ata_op, lba, nsect) || force_lba48) {
+               r->hob.nsect = nsect >>  8;
+               r->hob.lbal  = lba   >> 24;
+               r->hob.lbam  = lba   >> 32;
+               r->hob.lbah  = lba   >> 40;
+               r->oflags.hob.nsect = 1;
+               r->oflags.hob.lbal  = 1;
+               r->oflags.hob.lbam  = 1;
+               r->oflags.hob.lbah  = 1;
+       } else {
+               r->lob.dev |= (lba >> 24) & 0x0f;
+       }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hdparm-9.37/sgio.h new/hdparm-9.38/sgio.h
--- old/hdparm-9.37/sgio.h      2010-10-19 14:45:47.000000000 +0200
+++ new/hdparm-9.38/sgio.h      2012-01-06 15:45:00.000000000 +0100
@@ -54,6 +54,7 @@
        ATA_OP_SECURITY_ERASE_UNIT      = 0xf4,
        ATA_OP_SECURITY_FREEZE_LOCK     = 0xf5,
        ATA_OP_SECURITY_DISABLE         = 0xf6,
+       ATA_OP_VENDOR_SPECIFIC_0x80     = 0x80,
 };
 
 /*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hdparm-9.37/wdidle3.c new/hdparm-9.38/wdidle3.c
--- old/hdparm-9.37/wdidle3.c   1970-01-01 01:00:00.000000000 +0100
+++ new/hdparm-9.38/wdidle3.c   2012-01-07 22:40:49.000000000 +0100
@@ -0,0 +1,212 @@
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/syscall.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+
+#include "sgio.h"
+#include "hdparm.h"
+
+extern int verbose;  /* hdparm.c */
+
+/*
+ * The Western Digital (WD) "Green" drive IDLE3 timeout value is 8-bits.
+ * Earlier models used a strict value from 8.0 to 25.5 seconds (0x50 to 0xff).
+ * Later models use 8.0 to 12.7 secs (0x50 to 0x7f), and 30 to 300 secs (0x81 
to 0x8a).
+ * Other values are undefined, but have been observed on some drives.
+ *
+ * Older drives (from WDIDLE3.EXE documentation):
+ * 0x00        timer disabled.
+ * 0x50-0xff   timeout in tenths of a second, from 8.0 to 25.5 seconds.
+ *
+ *
+ * Some drives  (found by observation):
+ * 0x01-0x50   timeout in seconds, from 1 to 30 seconds (?).
+ *
+ * Newer drives (from WDIDLE3.EXE documentation):
+ * 0x00        timer disabled.
+ * 0x01-0x49   not permitted by WDIDLE3.EXE; reports as 0.1 to 7.9 seconds.
+ * 0x50-0x7f   timeout in tenths of a second, from 8.0 to 12.7 seconds.
+ * 0x80                not permitted by WDIDLE3.EXE; reports as 12.8 seconds.
+ * 0x81-0x8a   timeout in 30s of seconds, from 30 to 300 seconds.
+ * 0x90-0xff   not permitted; reports as 330 to 3810 seconds.
+ *
+ * A WD whitepaper identified some models/versions of drives with the "older" 
firmware,
+ * but no comprehensive list exists.   Models with firmware 02.01B01 are 
"older",
+ * and models with "02.01B02" are "newer".
+ *
+ * The real WDIDLE3 utility determines the correct value ranges
+ * by interogating the drive somehow, or perhaps based on the reported 
firmware version.
+ *
+ * WDIDLE3.EXE also writes some scary looking full 512-byte sequences to the 
drives
+ * in addition to what we do here.
+ *
+ * So this (hdparm) method may be somewhat risky, since it doesn't do 
everything WD does.
+ */
+
+enum {
+       WDC_VSC_DISABLED        = 'D',
+       WDC_VSC_ENABLED         = 'E',
+       WDC_IDLE3_READ          = 1,
+       WDC_IDLE3_WRITE         = 2,
+       WDC_OP_TIMEOUT_SECS     = 12,
+       WDC_TIMEOUT_THRESHOLD   = 128,
+};
+
+static int wdidle3_issue (int fd, int rw, struct ata_tf *tf, void *data, const 
char *msg)
+{
+       int ret = sg16(fd, rw, SG_PIO, tf, data, data ? 512 : 0, 
WDC_OP_TIMEOUT_SECS);
+       if (ret != 0) {
+               ret = errno;
+               perror(msg);
+       }
+       return ret;
+}
+
+/*
+ * Note: when WD vendor-specific-commands (vsc) are enabled,
+ * the ATA_OP_SMART command is "enhanced" to support additional
+ * functions to read/write specific data "registers" from the firmware.
+ * This may (or not) also cause regular SMART commands to fail (?).
+ */
+static int wdidle3_vsc_enable_disable (int fd, int setting)
+{
+       struct ata_tf   tf;
+       unsigned long long vendor_WD0 = ('W' << 16) | ('D' << 8) | 0;
+
+       tf_init(&tf, ATA_OP_VENDOR_SPECIFIC_0x80, vendor_WD0, 0);
+       tf.lob.feat     = setting;
+       tf.dev          = 0xa0;
+       return wdidle3_issue(fd, SG_WRITE, &tf, NULL, __func__);
+}
+
+/*
+ * This sends a key (password? I2C address?) to the drive
+ * in preparation for a data_in or data_out command.
+ */
+static int wdidle3_vsc_send_key (int fd, int rw)
+{
+       char            data[512];
+       struct ata_tf   tf;
+
+       memset(data, 0, sizeof(data));
+       tf_init(&tf, ATA_OP_SMART, 0xc24fbe, 1);
+       tf.lob.feat     = 0xd6;
+       tf.dev          = 0xa0;
+       data[ 0]        = 0x2a;
+       data[ 2]        = rw;
+       data[ 4]        = 0x02;
+       data[ 6]        = 0x0d;
+       data[ 8]        = 0x16;
+       data[10]        = 0x01;
+       return wdidle3_issue(fd, SG_WRITE, &tf, data, __func__);
+}
+
+/*
+ * This reads a data value from the drive.
+ */
+static int wdidle3_data_in (int fd, unsigned char *timeout)
+{
+       char            data[512];
+       int             ret;
+       struct ata_tf   tf;
+
+       memset(data, 0, sizeof(data));
+       tf_init(&tf, ATA_OP_SMART, 0xc24fbf, 1);
+       tf.lob.feat     = 0xd5;
+       tf.dev          = 0xa0;
+       ret = wdidle3_issue(fd, SG_READ, &tf, data, __func__);
+       if (!ret)
+               *timeout = data[0];
+       return ret;
+}
+
+/*
+ * This writes a data value to the drive.
+ */
+static int wdidle3_vsc_data_out (int fd, unsigned char timeout)
+{
+       char            data[512];
+       struct ata_tf   tf;
+
+       memset(data, 0, sizeof(data));
+       tf_init(&tf, ATA_OP_SMART, 0xc24fbf, 1);
+       tf.lob.feat     = 0xd6;
+       tf.dev          = 0xa0;
+       data[0]         = timeout;
+       return wdidle3_issue(fd, SG_WRITE, &tf, data, __func__);
+}
+
+int wdidle3_set_timeout (int fd, unsigned char timeout)
+{
+       int ret, ret2;
+
+       ret = wdidle3_vsc_enable_disable(fd, WDC_VSC_ENABLED);
+       if (!ret) {
+               ret = wdidle3_vsc_send_key(fd, WDC_IDLE3_WRITE);
+               if (!ret)
+                       ret = wdidle3_vsc_data_out(fd, timeout);
+               ret2 = wdidle3_vsc_enable_disable(fd, WDC_VSC_DISABLED);
+               if (!ret)
+                       ret = ret2;
+       }
+       return ret;
+}
+
+int wdidle3_get_timeout (int fd, unsigned char *timeout)
+{
+       int ret, ret2;
+
+       ret = wdidle3_vsc_enable_disable(fd, WDC_VSC_ENABLED);
+       if (!ret) {
+               ret = wdidle3_vsc_send_key(fd, WDC_IDLE3_READ);
+               if (!ret)
+                       ret = wdidle3_data_in(fd, timeout);
+               ret2 = wdidle3_vsc_enable_disable(fd, WDC_VSC_DISABLED);
+               if (!ret)
+                       ret = ret2;
+       }
+       return ret;
+}
+
+unsigned char wdidle3_msecs_to_timeout (unsigned int secs)
+{
+       unsigned char timeout;
+
+       if (secs == 0)
+               timeout = 0;            /* disabled */
+       else if (secs < 8)
+               timeout = 80;           /* 8.0 seconds minimum */
+       else if (secs <= (WDC_TIMEOUT_THRESHOLD / 10))
+               timeout = secs * 10;    /* 8.0 to 12.7 seconds */
+       else {
+               secs += 29;             /* round up to next multiple of 30 */
+               if (secs > 300)
+                       secs = 300;     /* max timeout is 300 secs */
+               timeout = (secs / 30) + WDC_TIMEOUT_THRESHOLD;
+       }
+       return timeout;
+}
+
+void wdidle3_print_timeout (unsigned char timeout)
+{
+       if (verbose)
+               printf("[raw=0x%02x] ", timeout);       //FIXME
+       if (timeout == 0)
+               printf("disabled");
+       else if (timeout < 0x50 || timeout == WDC_TIMEOUT_THRESHOLD)
+               printf("%u ??", timeout);
+       else if (timeout < WDC_TIMEOUT_THRESHOLD)
+               printf("%u.%u secs", timeout / 10, timeout % 10);
+       else {
+               if (timeout > (WDC_TIMEOUT_THRESHOLD + 10))
+                       printf("%u ??", timeout);
+               else
+                       printf("%u secs", (timeout - WDC_TIMEOUT_THRESHOLD) * 
30);
+               printf(" (or %u.%u secs for older drives)", timeout / 10, 
timeout % 10);
+       }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hdparm-9.37/wiper/Changelog 
new/hdparm-9.38/wiper/Changelog
--- old/hdparm-9.37/wiper/Changelog     2011-01-24 16:14:26.000000000 +0100
+++ new/hdparm-9.38/wiper/Changelog     2011-02-21 15:59:43.000000000 +0100
@@ -1,3 +1,5 @@
+wiper.sh-3.4
+       - updated to allow all SCSI_DISK_MAJOR numbers, not just "8"
 wiper.sh-3.3
        - remove need for external "rdev" utility, to keep Suse/Redhat/Fedora 
users happy
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hdparm-9.37/wiper/wiper.sh 
new/hdparm-9.38/wiper/wiper.sh
--- old/hdparm-9.37/wiper/wiper.sh      2011-01-16 23:01:28.000000000 +0100
+++ new/hdparm-9.38/wiper/wiper.sh      2011-02-21 15:58:26.000000000 +0100
@@ -2,7 +2,7 @@
 #
 # SATA SSD free-space TRIM utility, by Mark Lord <[email protected]>
 
-VERSION=3.3 
+VERSION=3.4 
 
 # Copyright (C) 2009-2010 Mark Lord.  All rights reserved.
 #
@@ -370,15 +370,24 @@
        rawdev=""
 elif [ "`get_major $fsdev`" -ne "`get_major $rawdev`" ]; then  ## sanity check
        rawdev=""
-elif [ "`get_major $fsdev`" -ne "8" ]; then ## "SCSI" drives only; no LVM 
confusion for now
-       echo "$rawdev: does not appear to be a SCSI/SATA SSD, aborting." >&2
-       exit 1
-elif ! $HDPARM -I $rawdev | $GREP -i '[        ][*][   ]*Data Set Management 
TRIM supported' &>/dev/null ; then
-       if [ "$commit" = "yes" ]; then
-               echo "$rawdev: DSM/TRIM command not supported, aborting." >&2
+else
+       ## "SCSI" drives only; no LVM confusion for now:
+       maj="$(get_major $fsdev)"
+       maj_ok=0
+       for scsi_major in 8 65 66 67 68 69 70 71 ; do
+               [ "$maj" = "$scsi_major" ] && maj_ok=1
+       done
+       if [ $maj_ok -eq 0 ]; then
+               echo "$rawdev: does not appear to be a SCSI/SATA SSD, 
aborting." >&2
                exit 1
        fi
-       echo "$rawdev: DSM/TRIM command not supported (continuing with 
dry-run)." >&2
+       if ! $HDPARM -I $rawdev | $GREP -i '[   ][*][   ]*Data Set Management 
TRIM supported' &>/dev/null ; then
+               if [ "$commit" = "yes" ]; then
+                       echo "$rawdev: DSM/TRIM command not supported, 
aborting." >&2
+                       exit 1
+               fi
+               echo "$rawdev: DSM/TRIM command not supported (continuing with 
dry-run)." >&2
+       fi
 fi
 if [ "$rawdev" = "" ]; then
        echo "$fsdev: unable to reliably determine the underlying physical 
device name, aborting" >&2

-- 
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to