File smartmontools-command-convert.patch of Package smartmontools
http://thread.gmane.org/gmane.linux.ide/13222/focus=13222
Subject: smartctl causing HSM violation on sata_nv, 2.6.18
sata_sil24 works because the controller hardware snoops the command
and determines protocol by itself. So, regardless of what the ioctl
says, it executes the command with non-data protocol.
The following patch against smartmontools-5.36 converts it to use
HDIO_DRIVE_TASK ioctl for AUTOSAVE and AUTO_OFFLINE which don't have
the above issue.
================================================================================
diff -uNr smartmontools-5.36/os_linux.c smartmontools-5.36-fixed/os_linux.c
--- smartmontools-5.36/os_linux.cpp 2006-04-13 02:02:19.000000000 +0900
+++ smartmontools-5.36-fixed/os_linux.cpp 2006-09-28 15:41:06.000000000 +0900
@@ -383,14 +383,10 @@
// 1 if the command succeeded and disk SMART status is "FAILING"
-// huge value of buffer size needed because HDIO_DRIVE_CMD assumes
-// that buff[3] is the data size. Since the ATA_SMART_AUTOSAVE and
-// ATA_SMART_AUTO_OFFLINE use values of 0xf1 and 0xf8 we need the space.
-// Otherwise a 4+512 byte buffer would be enough.
-#define STRANGE_BUFFER_LENGTH (4+512*0xf8)
+#define BUFFER_LEN (4+512)
int ata_command_interface(int device, smart_command_set command, int select, char *data){
- unsigned char buff[STRANGE_BUFFER_LENGTH];
+ unsigned char buff[BUFFER_LEN];
// positive: bytes to write to caller. negative: bytes to READ from
// caller. zero: non-data command
int copydata=0;
@@ -407,7 +403,7 @@
// buff[2] contains the ATA SECTOR COUNT REGISTER
// clear out buff. Large enough for HDIO_DRIVE_CMD (4+512 bytes)
- memset(buff, 0, STRANGE_BUFFER_LENGTH);
+ memset(buff, 0, BUFFER_LEN);
buff[0]=ATA_SMART_CMD;
switch (command){
@@ -457,12 +453,14 @@
buff[2]=ATA_SMART_STATUS;
break;
case AUTO_OFFLINE:
- buff[2]=ATA_SMART_AUTO_OFFLINE;
- buff[3]=select; // YET NOTE - THIS IS A NON-DATA COMMAND!!
+ // NSECT is 241 for enable but no data transfer. Use TASK ioctl.
+ buff[1]=ATA_SMART_AUTO_OFFLINE;
+ buff[2]=select;
break;
case AUTOSAVE:
- buff[2]=ATA_SMART_AUTOSAVE;
- buff[3]=select; // YET NOTE - THIS IS A NON-DATA COMMAND!!
+ // NSECT is 248 for enable but no data transfer. Use TASK ioctl.
+ buff[1]=ATA_SMART_AUTOSAVE;
+ buff[2]=select;
break;
case IMMEDIATE_OFFLINE:
buff[2]=ATA_SMART_IMMEDIATE_OFFLINE;
@@ -517,7 +515,7 @@
// There are two different types of ioctls(). The HDIO_DRIVE_TASK
// one is this:
- if (command==STATUS_CHECK){
+ if (command==AUTO_OFFLINE || command==AUTOSAVE || command==STATUS_CHECK){
int retval;
// NOT DOCUMENTED in /usr/src/linux/include/linux/hdreg.h. You