diff --git a/sm5/CHANGELOG b/sm5/CHANGELOG
index 046385e694d7e2c25718a671ec799c43c62854cc..1b958fa2b2b3e18a836fadc1c61df26bc4947f72 100644
--- a/sm5/CHANGELOG
+++ b/sm5/CHANGELOG
@@ -1,6 +1,6 @@
 CHANGELOG for smartmontools
 
-$Id: CHANGELOG,v 1.621 2007/07/18 21:18:09 chrfranke Exp $
+$Id: CHANGELOG,v 1.622 2007/07/19 21:36:38 chrfranke Exp $
 
 The most recent version of this file is:
 http://smartmontools.cvs.sourceforge.net/smartmontools/sm5/CHANGELOG?view=markup
@@ -33,6 +33,11 @@ NOTES FOR FUTURE RELEASES: see TODO file.
 
 <DEVELOPERS: ADDITIONS TO THE CHANGE LOG GO JUST BELOW HERE, PLEASE>
 
+  [CF] Windows: Added IOCTL_SCSI_MINIPORT_*SMART* for commands not handled
+       properly by SMART_IOCTL in disk class driver. This allows to use
+       READ_LOG, WRITE_LOG and ABORT_SELFTEST even if the driver does not
+       support ATA_PASS_THROUGH.
+
   [CF] Added ATA-8 revision 4, fixed WRITE LOG '-r ioctl' output.
 
   [BA] Updated smartctl and smartd so that they can be used with the latest
diff --git a/sm5/os_win32.cpp b/sm5/os_win32.cpp
index d1d3312929b937208b3ea23f02431c18ebad8a50..34dfdea9a2f6a5ebdd1f6d032f1ee66a3488b7eb 100644
--- a/sm5/os_win32.cpp
+++ b/sm5/os_win32.cpp
@@ -3,7 +3,7 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2004-6 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2004-7 Christian Franke <smartmontools-support@lists.sourceforge.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -44,10 +44,16 @@ extern int64_t bytes; // malloc() byte count
 
 
 // Needed by '-V' option (CVS versioning) of smartd/smartctl
-const char *os_XXXX_c_cvsid="$Id: os_win32.cpp,v 1.52 2007/01/05 12:23:02 chrfranke Exp $"
+const char *os_XXXX_c_cvsid="$Id: os_win32.cpp,v 1.53 2007/07/19 21:36:39 chrfranke Exp $"
 ATACMDS_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
 
 
+// Running on Win9x/ME ?
+static inline bool is_win9x()
+{
+	return !!(GetVersion() & 0x80000000);
+}
+
 // Running on 64-bit Windows as 32-bit app ?
 static bool is_wow64()
 {
@@ -282,15 +288,15 @@ int deviceopen(const char * pathname, char *type)
 
 	if (!strcmp(type, "ATA")) {
 		// hd[a-j](:[saicp]+)? => ATA 0-9 with options
-		char drive[1+1] = "", options[5+1] = ""; int n1 = -1, n2 = -1;
-		if (   sscanf(pathname, "hd%1[a-j]%n:%5[saicp]%n", drive, &n1, options, &n2) >= 1
+		char drive[1+1] = "", options[7+1] = ""; int n1 = -1, n2 = -1;
+		if (   sscanf(pathname, "hd%1[a-j]%n:%6[saicmp]%n", drive, &n1, options, &n2) >= 1
 		    && ((n1 == len && !options[0]) || n2 == len)                                 ) {
 			return ata_open(drive[0] - 'a', options, -1);
 		}
 		// hd[a-j],N(:[saicp]+)? => Physical drive 0-9, RAID port N, with options
 		drive[0] = 0; options[0] = 0; n1 = -1; n2 = -1;
 		unsigned port = ~0;
-		if (   sscanf(pathname, "hd%1[a-j],%u%n:%5[saicp]%n", drive, &port, &n1, options, &n2) >= 2
+		if (   sscanf(pathname, "hd%1[a-j],%u%n:%7[saicmp3]%n", drive, &port, &n1, options, &n2) >= 2
 		    && port < 32 && ((n1 == len && !options[0]) || n2 == len)                              ) {
 			return ata_open(drive[0] - 'a', options, port);
 		}
@@ -374,9 +380,10 @@ void print_smartctl_examples(){
          "            (Prints Attributes for 3ware controller 0, port 1 using tw_cli)\n"
          "\n"
          "  ATA SMART access methods and ordering may be specified by modifiers\n"
-         "  following the device name: /dev/hdX:[saic], where\n"
+         "  following the device name: /dev/hdX:[saicm], where\n"
          "  's': SMART_* IOCTLs,         'a': IOCTL_ATA_PASS_THROUGH,\n"
-         "  'i': IOCTL_IDE_PASS_THROUGH, 'c': ATA via IOCTL_SCSI_PASS_THROUGH.\n"
+         "  'i': IOCTL_IDE_PASS_THROUGH, 'c': ATA via IOCTL_SCSI_PASS_THROUGH,\n"
+         "  'm': IOCTL_SCSI_MINIPORT_*.\n"
          "  The default on this system is /dev/hdX:%s\n", ata_get_def_options()
   );
 }
@@ -388,9 +395,6 @@ void print_smartctl_examples(){
 
 // SMART_* IOCTLs, also known as DFP_* (Disk Fault Protection)
 
-// Deklarations from:
-// http://cvs.sourceforge.net/viewcvs.py/mingw/w32api/include/ddk/ntdddisk.h?rev=1.3
-
 #define FILE_READ_ACCESS       0x0001
 #define FILE_WRITE_ACCESS      0x0002
 #define METHOD_BUFFERED             0
@@ -518,7 +522,7 @@ ASSERT_SIZEOF(SENDCMDOUTPARAMS, 16+1);
 
 static void print_ide_regs(const IDEREGS * r, int out)
 {
-	pout("%s=0x%02x,%s=0x%02x, SC=0x%02x, NS=0x%02x, CL=0x%02x, CH=0x%02x, SEL=0x%02x\n",
+	pout("%s=0x%02x,%s=0x%02x, SC=0x%02x, SN=0x%02x, CL=0x%02x, CH=0x%02x, SEL=0x%02x\n",
 	(out?"STS":"CMD"), r->bCommandReg, (out?"ERR":" FR"), r->bFeaturesReg,
 	r->bSectorCountReg, r->bSectorNumberReg, r->bCylLowReg, r->bCylHighReg, r->bDriveHeadReg);
 }
@@ -544,8 +548,7 @@ static int smart_get_version(HANDLE hdevice, unsigned long * portmap = 0)
 	memset(&vers, 0, sizeof(vers));
 	if (!DeviceIoControl(hdevice, SMART_GET_VERSION,
 		NULL, 0, &vers, sizeof(vers), &num_out, NULL)) {
-		if (con->reportataioctl)
-			pout("  SMART_GET_VERSION failed, Error=%ld\n", GetLastError());
+		pout("  SMART_GET_VERSION failed, Error=%ld\n", GetLastError());
 		errno = ENOSYS;
 		return -1;
 	}
@@ -628,8 +631,9 @@ static int smart_ioctl(HANDLE hdevice, int drive, IDEREGS * regs, char * data, u
 			pout("  %s failed, Error=%ld\n", name, err);
 			print_ide_regs_io(regs, NULL);
 		}
-		errno = (   err == ERROR_INVALID_FUNCTION /*9x*/
-		         || err == ERROR_INVALID_PARAMETER/*NT/2K/XP*/ ? ENOSYS : EIO);
+		errno = (   err == ERROR_INVALID_FUNCTION/*9x*/
+		         || err == ERROR_INVALID_PARAMETER/*NT/2K/XP*/
+		         || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
 		return -1;
 	}
 	// NOTE: On Win9x, inpar.irDriveRegs now contains the returned regs
@@ -728,7 +732,7 @@ static int ide_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, u
 			print_ide_regs_io(regs, NULL);
 		}
 		VirtualFree(buf, 0, MEM_RELEASE);
-		errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
+		errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
 		return -1;
 	}
 
@@ -862,7 +866,7 @@ static int ata_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, i
 			pout("  IOCTL_ATA_PASS_THROUGH failed, Error=%ld\n", err);
 			print_ide_regs_io(regs, NULL);
 		}
-		errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
+		errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
 		return -1;
 	}
 
@@ -904,9 +908,6 @@ static int ata_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, i
 
 // ATA PASS THROUGH via SCSI PASS THROUGH (WinNT4 only)
 
-// Declarations from:
-// http://cvs.sourceforge.net/viewcvs.py/mingw/w32api/include/ddk/ntddscsi.h?rev=1.2
-
 #define IOCTL_SCSI_PASS_THROUGH \
 	CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
 
@@ -990,7 +991,7 @@ static int ata_via_scsi_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char
 		long err = GetLastError();
 		if (con->reportataioctl)
 			pout("  ATA via IOCTL_SCSI_PASS_THROUGH failed, Error=%ld\n", err);
-		errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
+		errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
 		return -1;
 	}
 
@@ -1020,7 +1021,12 @@ static int ata_via_scsi_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char
 
 /////////////////////////////////////////////////////////////////////////////
 
-// ATA PASS THROUGH via 3ware specific SCSI MINIPORT ioctl
+// SMART IOCTL via SCSI MINIPORT ioctl
+
+// This function is handled by ATAPI port driver (atapi.sys) or by SCSI
+// miniport driver (via SCSI port driver scsiport.sys).
+// It can be used to skip the missing or broken handling of some SMART
+// command codes (e.g. READ_LOG) in the disk class driver (disk.sys)
 
 #define IOCTL_SCSI_MINIPORT \
 	CTL_CODE(IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
@@ -1038,8 +1044,155 @@ typedef struct _SRB_IO_CONTROL {
 
 ASSERT_SIZEOF(SRB_IO_CONTROL, 28);
 
+#define FILE_DEVICE_SCSI 0x001b
+
+#define IOCTL_SCSI_MINIPORT_SMART_VERSION               ((FILE_DEVICE_SCSI << 16) + 0x0500)
+#define IOCTL_SCSI_MINIPORT_IDENTIFY                    ((FILE_DEVICE_SCSI << 16) + 0x0501)
+#define IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS          ((FILE_DEVICE_SCSI << 16) + 0x0502)
+#define IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS       ((FILE_DEVICE_SCSI << 16) + 0x0503)
+#define IOCTL_SCSI_MINIPORT_ENABLE_SMART                ((FILE_DEVICE_SCSI << 16) + 0x0504)
+#define IOCTL_SCSI_MINIPORT_DISABLE_SMART               ((FILE_DEVICE_SCSI << 16) + 0x0505)
+#define IOCTL_SCSI_MINIPORT_RETURN_STATUS               ((FILE_DEVICE_SCSI << 16) + 0x0506)
+#define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE     ((FILE_DEVICE_SCSI << 16) + 0x0507)
+#define IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES       ((FILE_DEVICE_SCSI << 16) + 0x0508)
+#define IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS       ((FILE_DEVICE_SCSI << 16) + 0x0509)
+#define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE ((FILE_DEVICE_SCSI << 16) + 0x050a)
+#define IOCTL_SCSI_MINIPORT_READ_SMART_LOG              ((FILE_DEVICE_SCSI << 16) + 0x050b)
+#define IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG             ((FILE_DEVICE_SCSI << 16) + 0x050c)
+
+/////////////////////////////////////////////////////////////////////////////
+
+static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, int datasize)
+{
+	// Select code
+	DWORD code = 0; const char * name = 0;
+	if (regs->bCommandReg == ATA_IDENTIFY_DEVICE) {
+		code = IOCTL_SCSI_MINIPORT_IDENTIFY; name = "IDENTIFY";
+	}
+	else if (regs->bCommandReg == ATA_SMART_CMD) switch (regs->bFeaturesReg) {
+	  case ATA_SMART_READ_VALUES:
+		code = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS; name = "READ_SMART_ATTRIBS"; break;
+	  case ATA_SMART_READ_THRESHOLDS:
+		code = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS; name = "READ_SMART_THRESHOLDS"; break;
+	  case ATA_SMART_ENABLE:
+		code = IOCTL_SCSI_MINIPORT_ENABLE_SMART; name = "ENABLE_SMART"; break;
+	  case ATA_SMART_DISABLE:
+		code = IOCTL_SCSI_MINIPORT_DISABLE_SMART; name = "DISABLE_SMART"; break;
+	  case ATA_SMART_STATUS:
+		code = IOCTL_SCSI_MINIPORT_RETURN_STATUS; name = "RETURN_STATUS"; break;
+	  case ATA_SMART_AUTOSAVE:
+		code = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE; name = "ENABLE_DISABLE_AUTOSAVE"; break;
+	//case ATA_SMART_SAVE: // obsolete since ATA-6, not used by smartmontools
+	//	code = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES; name = "SAVE_ATTRIBUTE_VALUES"; break;
+	  case ATA_SMART_IMMEDIATE_OFFLINE:
+		code = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS; name = "EXECUTE_OFFLINE_DIAGS"; break;
+	  case ATA_SMART_AUTO_OFFLINE:
+		code = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE; name = "ENABLE_DISABLE_AUTO_OFFLINE"; break;
+	  case ATA_SMART_READ_LOG_SECTOR:
+		code = IOCTL_SCSI_MINIPORT_READ_SMART_LOG; name = "READ_SMART_LOG"; break;
+	  case ATA_SMART_WRITE_LOG_SECTOR:
+		code = IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG; name = "WRITE_SMART_LOG"; break;
+	}
+	if (!code) {
+		errno = ENOSYS;
+		return -1;
+	}
+
+	// Set SRB
+	struct {
+		SRB_IO_CONTROL srbc;
+		union {
+			SENDCMDINPARAMS in;
+			SENDCMDOUTPARAMS out;
+		} params;
+		char space[512-1];
+	} sb;
+	ASSERT_SIZEOF(sb, sizeof(SRB_IO_CONTROL)+sizeof(SENDCMDINPARAMS)-1+512);
+	memset(&sb, 0, sizeof(sb));
+
+	unsigned size;
+	if (datasize > 0) {
+		if (datasize > (int)sizeof(sb.space)+1) {
+			errno = EINVAL;
+			return -1;
+		}
+		size = datasize;
+	}
+	else if (datasize < 0) {
+		if (-datasize > (int)sizeof(sb.space)+1) {
+			errno = EINVAL;
+			return -1;
+		}
+		size = -datasize;
+		memcpy(sb.params.in.bBuffer, data, size);
+	}
+	else if (code == IOCTL_SCSI_MINIPORT_RETURN_STATUS)
+		size = sizeof(IDEREGS);
+	else
+		size = 0;
+	sb.srbc.HeaderLength = sizeof(SRB_IO_CONTROL);
+	memcpy(sb.srbc.Signature, "SCSIDISK", 8); // atapi.sys
+	sb.srbc.Timeout = 60; // seconds
+	sb.srbc.ControlCode = code;
+	//sb.srbc.ReturnCode = 0;
+	sb.srbc.Length = sizeof(SENDCMDINPARAMS)-1 + size;
+	sb.params.in.irDriveRegs = *regs;
+	sb.params.in.cBufferSize = size;
+
+	// Call miniport ioctl
+	size += sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)-1;
+	DWORD num_out;
+	if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
+		&sb, size, &sb, size, &num_out, NULL)) {
+		long err = GetLastError();
+		if (con->reportataioctl) {
+			pout("  IOCTL_SCSI_MINIPORT_%s failed, Error=%ld\n", name, err);
+			print_ide_regs_io(regs, NULL);
+		}
+		errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
+		return -1;
+	}
+
+	// Check result
+	if (sb.srbc.ReturnCode) {
+		if (con->reportataioctl) {
+			pout("  IOCTL_SCSI_MINIPORT_%s failed, ReturnCode=0x%08lx\n", name, sb.srbc.ReturnCode);
+			print_ide_regs_io(regs, NULL);
+		}
+		errno = EIO;
+		return -1;
+	}
+
+	if (sb.params.out.DriverStatus.bDriverError) {
+		if (con->reportataioctl) {
+			pout("  IOCTL_SCSI_MINIPORT_%s failed, DriverError=0x%02x, IDEError=0x%02x\n", name,
+				sb.params.out.DriverStatus.bDriverError, sb.params.out.DriverStatus.bIDEError);
+			print_ide_regs_io(regs, NULL);
+		}
+		errno = (!sb.params.out.DriverStatus.bIDEError ? ENOSYS : EIO);
+		return -1;
+	}
+
+	if (con->reportataioctl > 1) {
+		pout("  IOCTL_SCSI_MINIPORT_%s suceeded, bytes returned: %lu (buffer %lu)\n", name,
+			num_out, sb.params.out.cBufferSize);
+		print_ide_regs_io(regs, (code == IOCTL_SCSI_MINIPORT_RETURN_STATUS ?
+		                         (const IDEREGS *)(sb.params.out.bBuffer) : 0));
+	}
+
+	if (datasize > 0)
+		memcpy(data, sb.params.out.bBuffer, datasize);
+	else if (datasize == 0 && code == IOCTL_SCSI_MINIPORT_RETURN_STATUS)
+		*regs = *(const IDEREGS *)(sb.params.out.bBuffer);
+
+	return 0;
+}
+
+
 /////////////////////////////////////////////////////////////////////////////
 
+// ATA PASS THROUGH via 3ware specific SCSI MINIPORT ioctl
+
 static int ata_via_3ware_miniport_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, int datasize, int port)
 {
 	struct {
@@ -1464,7 +1617,7 @@ static int get_device_power_state(HANDLE hdevice)
 // TODO: Put in a struct indexed by fd (or better a C++ object of course ;-)
 static HANDLE h_ata_ioctl = 0;
 static const char * ata_def_options;
-static char * ata_cur_options;
+static char * ata_usr_options;
 static int ata_driveno; // Drive number
 static char ata_smartver_state[10]; // SMART_GET_VERSION: 0=unknown, 1=OK, 2=failed
 
@@ -1526,7 +1679,7 @@ static const char * ata_get_def_options()
 	else if ((ver & 0xff) == 4) // WinNT4
 		return "sc"; // SMART_*, SCSI_PASS_THROUGH
 	else // WinXP, 2003, Vista
-		return "psai"; // GetDevicePowerState(), SMART_*, ATA_, IDE_PASS_THROUGH
+		return "psaim"; // GetDevicePowerState(), SMART_*, ATA_, IDE_PASS_THROUGH, SCSI_MINIPORT_*
 }
 
 
@@ -1534,24 +1687,20 @@ static const char * ata_get_def_options()
 
 static int ata_open(int drive, const char * options, int port)
 {
-	int win9x;
-	char devpath[30];
-	int devmap;
-
 	// TODO: This version does not allow to open more than 1 ATA devices
 	if (h_ata_ioctl) {
 		errno = ENFILE;
 		return -1;
 	}
 
-	win9x = ((GetVersion() & 0x80000000) != 0);
-
+	bool win9x = is_win9x();
 	if (!(0 <= drive && drive <= (win9x ? 7 : 9))) {
 		errno = ENOENT;
 		return -1;
 	}
 
 	// path depends on Windows Version
+	char devpath[30];
 	if (win9x)
 		// Use patched "smartvse.vxd" for drives 4-7, see INSTALL file for details
 		strcpy(devpath, (drive <= 3 ? "\\\\.\\SMARTVSD" : "\\\\.\\SMARTVSE"));
@@ -1580,14 +1729,15 @@ static int ata_open(int drive, const char * options, int port)
 	if (con->reportataioctl > 1)
 		pout("%s: successfully opened\n", devpath);
 
-	// Save options
-	if (!*options) {
-		// Set default options according to Windows version
-		if (!ata_def_options)
-			ata_def_options = ata_get_def_options();
-		options = (port < 0 ? ata_def_options : "s3"); // RAID: SMART_* and SCSI_MINIPORT
-	}
-	ata_cur_options = strdup(options);
+	// Set default options according to Windows version
+	if (!ata_def_options)
+		ata_def_options = ata_get_def_options();
+	// Save user options
+	if (port >= 0 && !*options)
+		options = "s3"; // RAID: SMART_* and SCSI_MINIPORT
+	assert(!ata_usr_options);
+	if (*options)
+		ata_usr_options = strdup(options);
 
 	// NT4/2000/XP: SMART_GET_VERSION may spin up disk, so delay until first real SMART_* call
 	ata_driveno = drive;
@@ -1597,7 +1747,7 @@ static int ata_open(int drive, const char * options, int port)
 	// Win9X/ME: Get drive map
 	// RAID: Get port map
 	unsigned long portmap = 0;
-	devmap = smart_get_version(h_ata_ioctl, (port >= 0 ? &portmap : 0));
+	int devmap = smart_get_version(h_ata_ioctl, (port >= 0 ? &portmap : 0));
 	if (devmap < 0) {
 		if (!is_permissive()) {
 			ata_close(0);
@@ -1651,9 +1801,9 @@ static void ata_close(int /*fd*/)
 {
 	CloseHandle(h_ata_ioctl);
 	h_ata_ioctl = 0;
-	if (ata_cur_options) {
-		free(ata_cur_options);
-		ata_cur_options = 0;
+	if (ata_usr_options) {
+		free(ata_usr_options);
+		ata_usr_options = 0;
 	}
 }
 
@@ -1662,10 +1812,9 @@ static void ata_close(int /*fd*/)
 
 static int ata_scan(unsigned long * drives, int * rdriveno, unsigned long * rdrives)
 {
-	int win9x = ((GetVersion() & 0x80000000) != 0);
-	int cnt = 0, i;
-
-	for (i = 0; i <= 9; i++) {
+	bool win9x = is_win9x();
+	int cnt = 0;
+	for (int i = 0; i <= 9; i++) {
 		char devpath[30];
 		GETVERSIONOUTPARAMS vers;
 		const GETVERSIONINPARAMS_EX & vers_ex = (const GETVERSIONINPARAMS_EX &)vers;
@@ -1770,8 +1919,9 @@ int ata_command_interface(int fd, smart_command_set command, int select, char *
 	regs.bCylHighReg = SMART_CYL_HI; regs.bCylLowReg = SMART_CYL_LOW;
 	int datasize = 0;
 
-	// Try all IOCTLS by default: SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH
-	const char * valid_options = "saic";
+	// Try by default: SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH,
+	// and SCSI_MINIPORT_* if requested by user
+	const char * valid_options = (ata_usr_options ? "saicm" : "saic");
 
 	switch (command) {
 	  case CHECK_POWER_MODE:
@@ -1795,15 +1945,18 @@ int ata_command_interface(int fd, smart_command_set command, int select, char *
 		regs.bFeaturesReg = ATA_SMART_READ_LOG_SECTOR;
 		regs.bSectorNumberReg = select;
 		regs.bSectorCountReg = 1;
-		valid_options = "saic3";
-		// Note: SMART_RCV_DRIVE_DATA supports this only on Win9x/ME
+		// SMART_RCV_DRIVE_DATA supports this only on Win9x/ME
+		// Try SCSI_MINIPORT also to skip buggy class driver
+		valid_options = (ata_usr_options || is_win9x() ? "saicm3" : "aicm3");
 		datasize = 512;
 		break;
 	  case WRITE_LOG:
 		regs.bFeaturesReg = ATA_SMART_WRITE_LOG_SECTOR;
 		regs.bSectorNumberReg = select;
 		regs.bSectorCountReg = 1;
-		valid_options = "a"; // ATA_PASS_THROUGH only, others don't support DATA_OUT
+		// ATA_PASS_THROUGH, SCSI_MINIPORT, others don't support DATA_OUT
+		// but SCSI_MINIPORT_* only if requested by user
+		valid_options = (ata_usr_options ? "am" : "a");
 		datasize = -512; // DATA_OUT!
 		break;
 	  case IDENTIFY:
@@ -1829,7 +1982,8 @@ int ata_command_interface(int fd, smart_command_set command, int select, char *
 		regs.bSectorNumberReg = 1;
 		break;
 	  case STATUS_CHECK:
-		valid_options = "sai"; // Needs IDE register return
+		// Requires CL,CH register return
+		valid_options = (ata_usr_options ? "saim" : "sai");
 	  case STATUS:
 		regs.bFeaturesReg = ATA_SMART_STATUS;
 		break;
@@ -1844,8 +1998,9 @@ int ata_command_interface(int fd, smart_command_set command, int select, char *
 	  case IMMEDIATE_OFFLINE:
 		regs.bFeaturesReg = ATA_SMART_IMMEDIATE_OFFLINE;
 		regs.bSectorNumberReg = select;
-		valid_options = "saic3";
-		// Note: SMART_SEND_DRIVE_COMMAND supports ABORT_SELF_TEST only on Win9x/ME
+		// SMART_SEND_DRIVE_COMMAND supports ABORT_SELF_TEST only on Win9x/ME
+		valid_options = (ata_usr_options || select != 127/*ABORT*/ || is_win9x() ?
+			"saicm3" : "aicm3");
 		break;
 	  default:
 		pout("Unrecognized command %d in win32_ata_command_interface()\n"
@@ -1856,8 +2011,10 @@ int ata_command_interface(int fd, smart_command_set command, int select, char *
 
 	// Try all valid ioctls in the order specified in dev_ioctls;
 	bool powered_up = false;
+	assert(ata_def_options);
+	const char * options = (ata_usr_options ? ata_usr_options : ata_def_options);
 	for (int i = 0; ; i++) {
-		char opt = ata_cur_options[i];
+		char opt = options[i];
 
 		if (!opt) {
 			if (command == CHECK_POWER_MODE && powered_up) {
@@ -1875,7 +2032,7 @@ int ata_command_interface(int fd, smart_command_set command, int select, char *
 			continue;
 
 		errno = 0;
-		assert(datasize == 0 || datasize == 512 || (opt == 'a' && datasize == -512));
+		assert(datasize == 0 || datasize == 512 || (strchr("am", opt) && datasize == -512));
 		int rc;
 		switch (opt) {
 		  default: assert(0);
@@ -1890,8 +2047,8 @@ int ata_command_interface(int fd, smart_command_set command, int select, char *
 				assert(port == -1);
 				if (smart_get_version(h_ata_ioctl) < 0) {
 					if (!con->permissive) {
-						pout("ATA/SATA driver is possibly a SCSI class driver not supporting SMART.\n");
-						pout("If this is a SCSI disk, try \"scsi<adapter><id>\".\n");
+						pout("ATA/SATA driver is possibly a SCSI driver not supporting SMART.\n");
+						pout("If this is a SCSI disk, try '/dev/sd%c\'.\n", 'a'+ata_driveno);
 						ata_smartver_state[ata_driveno] = 2;
 						rc = -1; errno = ENOSYS;
 						break;
@@ -1902,6 +2059,9 @@ int ata_command_interface(int fd, smart_command_set command, int select, char *
 			}
 			rc = smart_ioctl(h_ata_ioctl, fd, &regs, data, datasize, port);
 			break;
+		  case 'm':
+			rc = ata_via_scsi_miniport_smart_ioctl(h_ata_ioctl, &regs, data, datasize);
+			break;
 		  case 'a':
 			rc = ata_pass_through_ioctl(h_ata_ioctl, &regs, data, datasize);
 			break;
@@ -1980,7 +2140,7 @@ int ata_command_interface(int fd, smart_command_set command, int select, char *
 int ata_identify_is_cached(int fd)
 {
 	// Not RAID and WinNT4/2000/XP => true, RAID or Win9x/ME => false
-	return (!(fd & 0xff00) && (GetVersion() & 0x80000000) == 0);
+	return (!(fd & 0xff00) && !is_win9x());
 }
 
 
@@ -2736,7 +2896,7 @@ static int do_spt_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report)
 
 	memset(&sb, 0, sizeof(sb));
 	sb.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
-        sb.spt.CdbLength = iop->cmnd_len;
+	sb.spt.CdbLength = iop->cmnd_len;
 	memcpy(sb.spt.Cdb, iop->cmnd, iop->cmnd_len);
 	sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf);
 	sb.spt.SenseInfoOffset =