diff --git a/sm5/CHANGELOG b/sm5/CHANGELOG
index f783685eef24409401742787086a3dc0f1afd798..45b104568b3a04a088020100ee71e9580da5b288 100644
--- a/sm5/CHANGELOG
+++ b/sm5/CHANGELOG
@@ -1,6 +1,6 @@
 CHANGELOG for smartmontools
 
-$Id: CHANGELOG,v 1.390 2004/04/05 09:41:38 guidog Exp $
+$Id: CHANGELOG,v 1.391 2004/04/07 10:11:34 chrfranke Exp $
 
 The most recent version of this file is:
 http://cvs.sourceforge.net/viewcvs.py/smartmontools/sm5/CHANGELOG?sortby=date&view=markup
@@ -26,7 +26,9 @@ Maintainers / Developers Key:
 NOTES FOR FUTURE RELEASES: see TODO file.
 
 <ADDITIONS TO THE CHANGE LOG SHOULD BE ADDED JUST BELOW HERE, PLEASE>
-  
+
+  [CF] Win32 smartd: Added DEVICESCAN for SCSI/ASPI devices.
+
   [GG] Use gethostbyname() the get the DNS domain since getdomainname() 
        returns the NIS domain when sending mails from smartd.
 
@@ -37,7 +39,7 @@ NOTES FOR FUTURE RELEASES: see TODO file.
 
   [BA] smartd.conf example configuration file now has all examples
        commented out except for 'DEVICESCAN'.
- 
+
   [CF] Win32/native smartd: Added ability to display warning "emails"
        as message box by "-m msgbox" directive. With "-m sysmsgbox",
        a system modal (always on top) message box is shown.
diff --git a/sm5/TODO b/sm5/TODO
index 82d39b26723e1728aa2e79ed344523f713f820f8..f32dd01fd9d0a55a83871020fb55a1452b600b78 100644
--- a/sm5/TODO
+++ b/sm5/TODO
@@ -1,6 +1,6 @@
 TODO list for smartmontools:
 
-$Id: TODO,v 1.49 2004/04/01 21:02:11 chrfranke Exp $
+$Id: TODO,v 1.50 2004/04/07 10:11:35 chrfranke Exp $
 
 SATA devices
 ------------
@@ -86,8 +86,6 @@ Windows
 Add warning Mail feature to Windows/Native smartd, probably using
 the Blat mailer as a default (http://www.blat.net/).
 
-Add DEVICESCAN for SCSI devices.
-
 Add IDE/ATA selective self test and check power mode.
 
 Add ability to run smartd as a windows service.
diff --git a/sm5/os_win32.c b/sm5/os_win32.c
index c66dcc7a5dd578f9ae65da750d334efa6630c005..5d28ad3b253796803a3ab342424603aedf2cee93 100644
--- a/sm5/os_win32.c
+++ b/sm5/os_win32.c
@@ -38,7 +38,7 @@ extern int64_t bytes; // malloc() byte count
 #define ARGUSED(x) ((void)(x))
 
 // Needed by '-V' option (CVS versioning) of smartd/smartctl
-const char *os_XXXX_c_cvsid="$Id: os_win32.c,v 1.9 2004/04/02 10:56:11 chrfranke Exp $"
+const char *os_XXXX_c_cvsid="$Id: os_win32.c,v 1.10 2004/04/07 10:11:34 chrfranke Exp $"
 ATACMDS_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
 
 
@@ -48,6 +48,7 @@ static unsigned ata_scan(void);
 
 static int aspi_open(unsigned adapter, unsigned id);
 static void aspi_close(int fd);
+static unsigned long aspi_scan(void);
 
 
 static int is_permissive()
@@ -85,44 +86,67 @@ int guess_device_type (const char * dev_name)
 // others each contain null-terminated character strings.
 int make_device_names (char*** devlist, const char* type)
 {
+	unsigned long drives;
+	int i, j, n, sz, scsi;
+	const char * path;
+
 	if (!strcmp(type, "ATA")) {
-		unsigned drives = ata_scan();
-		int i, j, n, sz;
-		if (!drives)
-			return 0;
-		n = 0;
-		for (i = 0; i <= 9; i++) {
-			if (drives & (1 << i))
-				n++;
-		}
-		assert(n > 0);
-		if (n == 0)
-			return 0;
-		sz = n * sizeof(char **);
-		*devlist = (char **)malloc(sz); bytes += sz;
-		for (i = j = 0; i < n; i++) {
-			char * s;
-			sz = sizeof("/dev/hda");
-			s = (char *)malloc(sz); bytes += sz;
-			strcpy(s, "/dev/hda");
-			while (j <= 9 && !(drives & (1 << j)))
-				j++;
-			assert(j <= 9);
-			s[sz-2] += j++;
-			(*devlist)[i] = s;
-		}
-		return n;
+		// bit i set => drive i present
+		drives = ata_scan();
+		path = "/dev/hda";
+		scsi = 0;
 	}
+	else if (!strcmp(type, "SCSI")) {
+		// bit i set => drive with ID (i & 0x7) on adapter (i >> 3) present
+		drives = aspi_scan();
+		path = "/dev/scsi00";
+		scsi = 1;
+	}
+	else
+		return -1;
 
-	if (!strcmp(type, "SCSI")) {
-		return 0; // TODO!
+	if (!drives)
+		return 0;
+
+	// Count #drives
+	n = 0;
+	for (i = 0; i < 32; i++) {
+		if (drives & (1 << i))
+			n++;
 	}
+	assert(n > 0);
+	if (n == 0)
+		return 0;
 
-	return -1;
+	// Alloc devlist
+	assert(scsi || n <= 9);
+	sz = n * sizeof(char **);
+	*devlist = (char **)malloc(sz); bytes += sz;
+
+	// Add devices
+	for (i = j = 0; i < n; i++) {
+		char * s;
+		sz = strlen(path)+1;
+		s = (char *)malloc(sz); bytes += sz;
+		strcpy(s, path);
+		while (j < 32 && !(drives & (1 << j)))
+			j++;
+		assert(j < 32);
+		if (!scsi) {
+			assert(j <= 9);
+			s[sz-2] += j; // /dev/hd[a-j]
+		}
+		else {
+			s[sz-3] += (j >> 3);  // /dev/scsi[0-3].
+			s[sz-2] += (j & 0x7); //          .....[0-7]
+		}
+		(*devlist)[i] = s;
+		j++;
+	}
+	return n;
 }
 
 
-
 // Like open().  Return positive integer handle, only used by
 // functions below.  type="ATA" or "SCSI".  If you need to store extra
 // information about your devices, create a private internal array
@@ -689,7 +713,7 @@ int ata_command_interface(int fd, smart_command_set command, int select, char *
 				return -1;
 			if (!nonempty(data, 512)) {
 				// Nothing useful returned => ioctl probably broken
-				pout("IOCTL_IDE_PASS_THROUGH does not work on your OS\n");
+				pout("IOCTL_IDE_PASS_THROUGH does not work on your version of Windows\n");
 				ide_pass_through_broken = 1; // Do not retry (smartd)
 				errno = ENOSYS;
 				return -1;
@@ -770,6 +794,16 @@ typedef struct {
 	unsigned char parameters[16];  // 42: Host adapter unique parmameters
 } ASPI_SRB_INQUIRY;
 
+// SRB for get device type
+
+typedef struct {
+	ASPI_SRB_HEAD h;               // 00: Header
+	unsigned char target_id;       // 08: Target ID
+	unsigned char lun;             // 09: LUN
+	unsigned char devtype;         // 10: LUN
+	unsigned char reserved;        // 11: Reserved
+} ASPI_SRB_DEVTYPE;
+
 // SRB for SCSI I/O
 
 typedef struct {
@@ -796,6 +830,7 @@ typedef struct {
 typedef union {
 	ASPI_SRB_HEAD h;       // Common header
 	ASPI_SRB_INQUIRY q;    // Inquiry
+	ASPI_SRB_DEVTYPE t;    // Device type
 	ASPI_SRB_IO i;         // I/O
 } ASPI_SRB;
 
@@ -843,11 +878,37 @@ static UINT (* aspi_entry)(ASPI_SRB * srb); // ASPI entrypoint
 static unsigned num_aspi_adapters;
 
 
-static int aspi_open_dll()
+static int aspi_call(ASPI_SRB * srb)
+{
+	int i;
+	aspi_entry(srb);
+	i = 0;
+	while (((volatile ASPI_SRB *)srb)->h.status == ASPI_STATUS_IN_PROGRESS) {
+		if (++i > 100/*10sek*/) {
+			pout("ASPI Adapter %u: Timeout\n", srb->h.adapter);
+			aspi_entry = 0;
+			FreeLibrary(h_aspi_dll); h_aspi_dll = INVALID_HANDLE_VALUE;
+			errno = EIO;
+			return -1;
+		}
+#ifdef _DEBUG
+		pout("ASPI Wait %d\n", i);
+#endif
+		Sleep(100);
+	}
+	return 0;
+}
+
+
+static int aspi_open_dll(int verbose)
 {
 	ASPI_SRB srb;
 
 	// Check structure layout
+	assert(sizeof(srb.h) == 8);
+	assert(sizeof(srb.q) == 58);
+	assert(sizeof(srb.t) == 12);
+	assert(sizeof(srb.i) == 64+ASPI_SENSE_SIZE);
 	assert(offsetof(ASPI_SRB,h.cmd) == 0);
 	assert(offsetof(ASPI_SRB,h.flags) == 3);
 	assert(offsetof(ASPI_SRB_IO,lun) == 9);
@@ -863,14 +924,16 @@ static int aspi_open_dll()
 
 	// Get ASPI entrypoint from winaspi.dll
 	if (!h_aspi_dll && !(h_aspi_dll = LoadLibraryA("WNASPI32.DLL"))) {
-		pout("Cannot Load WNASPI32.DLL, Error=%ld\n", GetLastError());
+		if (verbose)
+			pout("Cannot load WNASPI32.DLL, Error=%ld\n", GetLastError());
 		h_aspi_dll = INVALID_HANDLE_VALUE;
 		errno = ENOENT;
 		return -1;
 	}
 
 	if (!((FARPROC)aspi_entry = GetProcAddress(h_aspi_dll, "SendASPI32Command"))) {
-		pout("Missing SendASPI32Command() in WNASPI32.DLL\n");
+		if (verbose)
+			pout("Missing SendASPI32Command() in WNASPI32.DLL\n");
 		FreeLibrary(h_aspi_dll); h_aspi_dll = INVALID_HANDLE_VALUE;
 		errno = ENOENT;
 		return -1;
@@ -879,13 +942,11 @@ static int aspi_open_dll()
 	// Get number of adapters
 	memset(&srb, 0, sizeof(srb));
 	srb.h.cmd = ASPI_CMD_ADAPTER_INQUIRE;
-	aspi_entry(&srb);
-	while (((volatile ASPI_SRB *)&srb)->h.status == ASPI_STATUS_IN_PROGRESS) {
-		// TODO: Timeout!
-		Sleep(1);
-	}
+	if (aspi_call(&srb))
+		return -1;
 	if (srb.h.status != ASPI_STATUS_NO_ERROR) {
-		pout("ASPI Adapter Inquriy failed, Error=0x%02x\n", srb.h.status);
+		if (verbose)
+			pout("ASPI Adapter Inquriy failed, Error=0x%02x\n", srb.h.status);
 		if (!is_permissive()) {
 			aspi_entry = 0;
 			FreeLibrary(h_aspi_dll); h_aspi_dll = INVALID_HANDLE_VALUE;
@@ -896,6 +957,9 @@ static int aspi_open_dll()
 	}
 
 	num_aspi_adapters = srb.q.adapters;
+#ifdef _DEBUG
+	pout("%u ASPI adapters on manager \"%.16s\"\n", num_aspi_adapters, srb.q.manager_id);
+#endif
 	return 0;
 }
 
@@ -941,7 +1005,7 @@ static int aspi_open(unsigned adapter, unsigned id)
 	}
 
 	if (!aspi_entry) {
-		if (aspi_open_dll())
+		if (aspi_open_dll(1/*verbose*/))
 			return -1;
 	}
 
@@ -964,6 +1028,58 @@ static void aspi_close(int fd)
 }
 
 
+// Scan for SCSI drives, return bitmask [adapter:0-3][id:0-7] of drives present
+
+static unsigned long aspi_scan()
+{
+	unsigned long drives = 0;
+	unsigned ad, nad;
+
+	if (!aspi_entry) {
+		if (aspi_open_dll(0/*quiet*/))
+			return 0;
+	}
+
+	nad = num_aspi_adapters;
+	if (nad >= 4)
+		nad = 4;
+	for (ad = 0; ad < nad; ad++) {
+		ASPI_SRB srb; int id;
+		// Get adapter name
+		memset(&srb, 0, sizeof(srb));
+		srb.h.cmd = ASPI_CMD_ADAPTER_INQUIRE;
+		srb.h.adapter = ad;
+		if (aspi_call(&srb))
+			return 0;
+#ifdef _DEBUG
+		pout("ASPI Adapter %u: %02x,\"%.16s\"\n", ad, srb.h.status, srb.q.adapter_id);
+#endif
+		if (srb.h.status != ASPI_STATUS_NO_ERROR)
+			continue;
+
+		// Skip ATA/ATAPI devices
+		srb.q.adapter_id[sizeof(srb.q.adapter_id)-1] = 0;
+		if (strstr(srb.q.adapter_id, "ATAPI"))
+			continue;
+
+		for (id = 0; id <= 7; id++) {
+			// Get device type
+			memset(&srb, 0, sizeof(srb));
+			srb.h.cmd = ASPI_CMD_GET_DEVICE_TYPE;
+			srb.h.adapter = ad; srb.i.target_id = id;
+			if (aspi_call(&srb))
+				return 0;
+#ifdef _DEBUG
+			pout("Device type for scsi%u%x: %02x,%02x\n", ad, id, srb.h.status, srb.t.devtype);
+#endif
+			if (srb.h.status == ASPI_STATUS_NO_ERROR && srb.t.devtype == 0x00/*HDD*/)
+				drives |= 1 << ((ad<<3)+id);
+		}
+	}
+	return drives;
+}
+
+
 /////////////////////////////////////////////////////////////////////////////
 
 // Interface to SCSI devices.  See os_linux.c
diff --git a/sm5/os_win32.cpp b/sm5/os_win32.cpp
index f08f6d709369640309ff2a22131f84d7e54cbf63..be0e53d2a6d91e9ff0625b34994f4c0b8d61e13c 100644
--- a/sm5/os_win32.cpp
+++ b/sm5/os_win32.cpp
@@ -38,7 +38,7 @@ extern int64_t bytes; // malloc() byte count
 #define ARGUSED(x) ((void)(x))
 
 // Needed by '-V' option (CVS versioning) of smartd/smartctl
-const char *os_XXXX_c_cvsid="$Id: os_win32.cpp,v 1.9 2004/04/02 10:56:11 chrfranke Exp $"
+const char *os_XXXX_c_cvsid="$Id: os_win32.cpp,v 1.10 2004/04/07 10:11:34 chrfranke Exp $"
 ATACMDS_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
 
 
@@ -48,6 +48,7 @@ static unsigned ata_scan(void);
 
 static int aspi_open(unsigned adapter, unsigned id);
 static void aspi_close(int fd);
+static unsigned long aspi_scan(void);
 
 
 static int is_permissive()
@@ -85,44 +86,67 @@ int guess_device_type (const char * dev_name)
 // others each contain null-terminated character strings.
 int make_device_names (char*** devlist, const char* type)
 {
+	unsigned long drives;
+	int i, j, n, sz, scsi;
+	const char * path;
+
 	if (!strcmp(type, "ATA")) {
-		unsigned drives = ata_scan();
-		int i, j, n, sz;
-		if (!drives)
-			return 0;
-		n = 0;
-		for (i = 0; i <= 9; i++) {
-			if (drives & (1 << i))
-				n++;
-		}
-		assert(n > 0);
-		if (n == 0)
-			return 0;
-		sz = n * sizeof(char **);
-		*devlist = (char **)malloc(sz); bytes += sz;
-		for (i = j = 0; i < n; i++) {
-			char * s;
-			sz = sizeof("/dev/hda");
-			s = (char *)malloc(sz); bytes += sz;
-			strcpy(s, "/dev/hda");
-			while (j <= 9 && !(drives & (1 << j)))
-				j++;
-			assert(j <= 9);
-			s[sz-2] += j++;
-			(*devlist)[i] = s;
-		}
-		return n;
+		// bit i set => drive i present
+		drives = ata_scan();
+		path = "/dev/hda";
+		scsi = 0;
 	}
+	else if (!strcmp(type, "SCSI")) {
+		// bit i set => drive with ID (i & 0x7) on adapter (i >> 3) present
+		drives = aspi_scan();
+		path = "/dev/scsi00";
+		scsi = 1;
+	}
+	else
+		return -1;
 
-	if (!strcmp(type, "SCSI")) {
-		return 0; // TODO!
+	if (!drives)
+		return 0;
+
+	// Count #drives
+	n = 0;
+	for (i = 0; i < 32; i++) {
+		if (drives & (1 << i))
+			n++;
 	}
+	assert(n > 0);
+	if (n == 0)
+		return 0;
 
-	return -1;
+	// Alloc devlist
+	assert(scsi || n <= 9);
+	sz = n * sizeof(char **);
+	*devlist = (char **)malloc(sz); bytes += sz;
+
+	// Add devices
+	for (i = j = 0; i < n; i++) {
+		char * s;
+		sz = strlen(path)+1;
+		s = (char *)malloc(sz); bytes += sz;
+		strcpy(s, path);
+		while (j < 32 && !(drives & (1 << j)))
+			j++;
+		assert(j < 32);
+		if (!scsi) {
+			assert(j <= 9);
+			s[sz-2] += j; // /dev/hd[a-j]
+		}
+		else {
+			s[sz-3] += (j >> 3);  // /dev/scsi[0-3].
+			s[sz-2] += (j & 0x7); //          .....[0-7]
+		}
+		(*devlist)[i] = s;
+		j++;
+	}
+	return n;
 }
 
 
-
 // Like open().  Return positive integer handle, only used by
 // functions below.  type="ATA" or "SCSI".  If you need to store extra
 // information about your devices, create a private internal array
@@ -689,7 +713,7 @@ int ata_command_interface(int fd, smart_command_set command, int select, char *
 				return -1;
 			if (!nonempty(data, 512)) {
 				// Nothing useful returned => ioctl probably broken
-				pout("IOCTL_IDE_PASS_THROUGH does not work on your OS\n");
+				pout("IOCTL_IDE_PASS_THROUGH does not work on your version of Windows\n");
 				ide_pass_through_broken = 1; // Do not retry (smartd)
 				errno = ENOSYS;
 				return -1;
@@ -770,6 +794,16 @@ typedef struct {
 	unsigned char parameters[16];  // 42: Host adapter unique parmameters
 } ASPI_SRB_INQUIRY;
 
+// SRB for get device type
+
+typedef struct {
+	ASPI_SRB_HEAD h;               // 00: Header
+	unsigned char target_id;       // 08: Target ID
+	unsigned char lun;             // 09: LUN
+	unsigned char devtype;         // 10: LUN
+	unsigned char reserved;        // 11: Reserved
+} ASPI_SRB_DEVTYPE;
+
 // SRB for SCSI I/O
 
 typedef struct {
@@ -796,6 +830,7 @@ typedef struct {
 typedef union {
 	ASPI_SRB_HEAD h;       // Common header
 	ASPI_SRB_INQUIRY q;    // Inquiry
+	ASPI_SRB_DEVTYPE t;    // Device type
 	ASPI_SRB_IO i;         // I/O
 } ASPI_SRB;
 
@@ -843,11 +878,37 @@ static UINT (* aspi_entry)(ASPI_SRB * srb); // ASPI entrypoint
 static unsigned num_aspi_adapters;
 
 
-static int aspi_open_dll()
+static int aspi_call(ASPI_SRB * srb)
+{
+	int i;
+	aspi_entry(srb);
+	i = 0;
+	while (((volatile ASPI_SRB *)srb)->h.status == ASPI_STATUS_IN_PROGRESS) {
+		if (++i > 100/*10sek*/) {
+			pout("ASPI Adapter %u: Timeout\n", srb->h.adapter);
+			aspi_entry = 0;
+			FreeLibrary(h_aspi_dll); h_aspi_dll = INVALID_HANDLE_VALUE;
+			errno = EIO;
+			return -1;
+		}
+#ifdef _DEBUG
+		pout("ASPI Wait %d\n", i);
+#endif
+		Sleep(100);
+	}
+	return 0;
+}
+
+
+static int aspi_open_dll(int verbose)
 {
 	ASPI_SRB srb;
 
 	// Check structure layout
+	assert(sizeof(srb.h) == 8);
+	assert(sizeof(srb.q) == 58);
+	assert(sizeof(srb.t) == 12);
+	assert(sizeof(srb.i) == 64+ASPI_SENSE_SIZE);
 	assert(offsetof(ASPI_SRB,h.cmd) == 0);
 	assert(offsetof(ASPI_SRB,h.flags) == 3);
 	assert(offsetof(ASPI_SRB_IO,lun) == 9);
@@ -863,14 +924,16 @@ static int aspi_open_dll()
 
 	// Get ASPI entrypoint from winaspi.dll
 	if (!h_aspi_dll && !(h_aspi_dll = LoadLibraryA("WNASPI32.DLL"))) {
-		pout("Cannot Load WNASPI32.DLL, Error=%ld\n", GetLastError());
+		if (verbose)
+			pout("Cannot load WNASPI32.DLL, Error=%ld\n", GetLastError());
 		h_aspi_dll = INVALID_HANDLE_VALUE;
 		errno = ENOENT;
 		return -1;
 	}
 
 	if (!((FARPROC)aspi_entry = GetProcAddress(h_aspi_dll, "SendASPI32Command"))) {
-		pout("Missing SendASPI32Command() in WNASPI32.DLL\n");
+		if (verbose)
+			pout("Missing SendASPI32Command() in WNASPI32.DLL\n");
 		FreeLibrary(h_aspi_dll); h_aspi_dll = INVALID_HANDLE_VALUE;
 		errno = ENOENT;
 		return -1;
@@ -879,13 +942,11 @@ static int aspi_open_dll()
 	// Get number of adapters
 	memset(&srb, 0, sizeof(srb));
 	srb.h.cmd = ASPI_CMD_ADAPTER_INQUIRE;
-	aspi_entry(&srb);
-	while (((volatile ASPI_SRB *)&srb)->h.status == ASPI_STATUS_IN_PROGRESS) {
-		// TODO: Timeout!
-		Sleep(1);
-	}
+	if (aspi_call(&srb))
+		return -1;
 	if (srb.h.status != ASPI_STATUS_NO_ERROR) {
-		pout("ASPI Adapter Inquriy failed, Error=0x%02x\n", srb.h.status);
+		if (verbose)
+			pout("ASPI Adapter Inquriy failed, Error=0x%02x\n", srb.h.status);
 		if (!is_permissive()) {
 			aspi_entry = 0;
 			FreeLibrary(h_aspi_dll); h_aspi_dll = INVALID_HANDLE_VALUE;
@@ -896,6 +957,9 @@ static int aspi_open_dll()
 	}
 
 	num_aspi_adapters = srb.q.adapters;
+#ifdef _DEBUG
+	pout("%u ASPI adapters on manager \"%.16s\"\n", num_aspi_adapters, srb.q.manager_id);
+#endif
 	return 0;
 }
 
@@ -941,7 +1005,7 @@ static int aspi_open(unsigned adapter, unsigned id)
 	}
 
 	if (!aspi_entry) {
-		if (aspi_open_dll())
+		if (aspi_open_dll(1/*verbose*/))
 			return -1;
 	}
 
@@ -964,6 +1028,58 @@ static void aspi_close(int fd)
 }
 
 
+// Scan for SCSI drives, return bitmask [adapter:0-3][id:0-7] of drives present
+
+static unsigned long aspi_scan()
+{
+	unsigned long drives = 0;
+	unsigned ad, nad;
+
+	if (!aspi_entry) {
+		if (aspi_open_dll(0/*quiet*/))
+			return 0;
+	}
+
+	nad = num_aspi_adapters;
+	if (nad >= 4)
+		nad = 4;
+	for (ad = 0; ad < nad; ad++) {
+		ASPI_SRB srb; int id;
+		// Get adapter name
+		memset(&srb, 0, sizeof(srb));
+		srb.h.cmd = ASPI_CMD_ADAPTER_INQUIRE;
+		srb.h.adapter = ad;
+		if (aspi_call(&srb))
+			return 0;
+#ifdef _DEBUG
+		pout("ASPI Adapter %u: %02x,\"%.16s\"\n", ad, srb.h.status, srb.q.adapter_id);
+#endif
+		if (srb.h.status != ASPI_STATUS_NO_ERROR)
+			continue;
+
+		// Skip ATA/ATAPI devices
+		srb.q.adapter_id[sizeof(srb.q.adapter_id)-1] = 0;
+		if (strstr(srb.q.adapter_id, "ATAPI"))
+			continue;
+
+		for (id = 0; id <= 7; id++) {
+			// Get device type
+			memset(&srb, 0, sizeof(srb));
+			srb.h.cmd = ASPI_CMD_GET_DEVICE_TYPE;
+			srb.h.adapter = ad; srb.i.target_id = id;
+			if (aspi_call(&srb))
+				return 0;
+#ifdef _DEBUG
+			pout("Device type for scsi%u%x: %02x,%02x\n", ad, id, srb.h.status, srb.t.devtype);
+#endif
+			if (srb.h.status == ASPI_STATUS_NO_ERROR && srb.t.devtype == 0x00/*HDD*/)
+				drives |= 1 << ((ad<<3)+id);
+		}
+	}
+	return drives;
+}
+
+
 /////////////////////////////////////////////////////////////////////////////
 
 // Interface to SCSI devices.  See os_linux.c
diff --git a/sm5/smartd.8.in b/sm5/smartd.8.in
index 60bf66ddd135e53f34f4035281338181e625fedd..dd35f6578bd97986f25c89ed19eb9f8d0bcc5512 100644
--- a/sm5/smartd.8.in
+++ b/sm5/smartd.8.in
@@ -1,7 +1,7 @@
 .ig
 Copyright (C) 2002-4 Bruce Allen <smartmontools-support@lists.sourceforge.net>
  
-$Id: smartd.8.in,v 1.49 2004/04/01 21:02:11 chrfranke Exp $
+$Id: smartd.8.in,v 1.50 2004/04/07 10:11:34 chrfranke Exp $
 
 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
@@ -94,8 +94,9 @@ devices, and entries \fB"/dev/rmt/*"\fP for SCSI tape devices.
 .IP \fBWINDOWS:\fP 9
 Examine all entries \fB"/dev/hd[a-j]"\fP ("\\\\.\\PhysicalDisk[0-9]")
 for IDE/ATA devices on WinNT4/2000/XP, \fB"/dev/hd[a-d]"\fP
-(bitmask from "\\\\.\\SMARTVSD") for IDE/ATA devices on Win95/98/98SE/ME.
-Scanning of SCSI/ASPI devices is not implemented yet.
+(bitmask from "\\\\.\\SMARTVSD") for IDE/ATA devices on Win95/98/98SE/ME,
+and \fB"/dev/scsi[0-3][0-7]"\fP (ASPI adapter 0-3, ID 0-7) for SCSI
+devices on all versions of Windows.
 .PP
 \fBsmartd\fP then monitors
 for \fIall\fP possible SMART errors (corresponding to the \fB\'\-a\'\fP
@@ -1572,4 +1573,4 @@ smartmontools home page at \fBhttp://smartmontools.sourceforge.net/\fP .
 
 .SH
 CVS ID OF THIS PAGE:
-$Id: smartd.8.in,v 1.49 2004/04/01 21:02:11 chrfranke Exp $
+$Id: smartd.8.in,v 1.50 2004/04/07 10:11:34 chrfranke Exp $