diff --git a/sm5/AUTHORS b/sm5/AUTHORS
index 3ccc435474960bee3023b8e9599ddb202c681387..844c20f327e13fac52076e4e500f44af4be04e32 100644
--- a/sm5/AUTHORS
+++ b/sm5/AUTHORS
@@ -1,4 +1,4 @@
-$Id: AUTHORS,v 1.6 2003/10/08 13:26:18 ballen4705 Exp $
+$Id: AUTHORS,v 1.7 2003/10/26 02:12:33 ballen4705 Exp $
 
 This code was originally developed as a Senior Thesis by Michael
 Cornwell at the Concurrent Systems Laboratory (now part of the Storage
@@ -15,6 +15,7 @@ Bruce Allen		<smartmontools-support@lists.sourceforge.net>
 Erik Inge Bols�		<knan@mo.himolde.no>
 Stanislav Brabec	<sbrabec@suse.cz>
 Peter Cassidy		<pcassidy@mac.com>
+Casper Dik              <casper@holland.sun.com>
 Guilhem Fr�zou		<guilhem.frezou@catii.fr>
 Douglas Gilbert		<dougg@torque.net>
 Guido Guenther		<agx@sigxcpu.org>
diff --git a/sm5/CHANGELOG b/sm5/CHANGELOG
index dd6037dd47bc2c50980319f6f99dc707ff771db4..f21060da9eb1f57787cfc620c44ffb0e77c95f06 100644
--- a/sm5/CHANGELOG
+++ b/sm5/CHANGELOG
@@ -1,12 +1,13 @@
 CHANGELOG for smartmontools
 
-$Id: CHANGELOG,v 1.223 2003/10/25 13:03:26 ballen4705 Exp $
+$Id: CHANGELOG,v 1.224 2003/10/26 02:12:33 ballen4705 Exp $
 
 Maintainers / Developers Key:
 [BA] Bruce Allen
 [EB] Erik Inge Bols�
 [SB] Stanislav Brabec
 [PC] Peter Cassidy
+[CD] Caper Dik
 [GF] Guilhem Fr�zou
 [DG] Douglas Gilbert
 [GG] Guido Guenther
@@ -22,6 +23,9 @@ CURRENT DEVELOPMENT VERSION (see VERSION file in this directory):
 
   <ADDITIONS TO THE CHANGE LOG SHOULD BE ADDED HERE, PLEASE>
 
+  [CD] solaris port: added SCSI functionality to solaris
+       stubs.
+
   [BA] smartd: attempt to address bug report about smartd
        hanging on USB devices when scanning:
        https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=107615
diff --git a/sm5/os_solaris.c b/sm5/os_solaris.c
index 52bb6d4e6930b48beddffe1fcdbbbaf05f149cb7..d7913bf9a1fd8566d1560e82f860e8de35d28762 100644
--- a/sm5/os_solaris.c
+++ b/sm5/os_solaris.c
@@ -3,7 +3,7 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2003 NAME HERE <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2003 Casper Dik <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
@@ -29,6 +29,14 @@
   smartmontools-support@lists.sourceforge.net
 */
 
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/param.h>
+
 // These are needed to define prototypes for the functions defined below
 #include "atacmds.h"
 #include "scsicmds.h"
@@ -37,17 +45,14 @@
 // This is to include whatever prototypes you define in os_solaris.h
 #include "os_solaris.h"
 
-const char *os_XXXX_c_cvsid="$Id: os_solaris.c,v 1.6 2003/10/15 14:06:02 ballen4705 Exp $" \
+const char *os_XXXX_c_cvsid="$Id: os_solaris.c,v 1.7 2003/10/26 02:12:33 ballen4705 Exp $" \
 ATACMDS_H_CVSID OS_XXXX_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
 
 // The printwarning() function warns about unimplemented functions
-int printedout[5];
-char *unimplemented[5]={
-  "guess_device_type()",
-  "make_device_names()",
+int printedout[2];
+char *unimplemented[2]={
   "ATA command routine ata_command_interface()",
   "3ware Escalade Controller command routine escalade_command_interface()",
-  "SCSI command interface do_scsi_cmnd_io()"
 };
 
 int printwarning(int which){
@@ -71,19 +76,151 @@ int printwarning(int which){
   return 1;
 }
 
+static const char *uscsidrvrs[] = {
+	"sd",
+	"ssd",
+	"st"
+};
+
+static const char *atadrvrs[] = {
+	"cmdk",
+	"dad",
+};
+
+static int
+isdevtype(const char *dev_name, const char *table[], int tsize)
+{
+  char devpath[MAXPATHLEN];
+  int i;
+  char *basename;
+
+  if (realpath(dev_name, devpath) == NULL)
+    return 0;
+ 
+  if ((basename = strrchr(devpath, '/')) == NULL)
+    return 0;
+
+  basename++;
+
+  for (i = 0; i < tsize; i++) {
+    int l = strlen(table[i]);
+    if (strncmp(basename, table[i], l) == 0 && basename[l] == '@')
+      return 1;
+  }
+  return 0;
+}
+
+static int
+isscsidev(const char *path)
+{
+  return isdevtype(path, uscsidrvrs, sizeof (uscsidrvrs) / sizeof (char *));
+}
+
+static int
+isatadev(const char *path)
+{
+  return isdevtype(path, atadrvrs, sizeof (atadrvrs) / sizeof (char *));
+}
+
 // tries to guess device type given the name (a path)
 int guess_device_type (const char* dev_name) {
-  if (printwarning(0))
+  if (isscsidev(dev_name))
+    return GUESS_DEVTYPE_SCSI;
+  else if (isatadev(dev_name))
+    return GUESS_DEVTYPE_ATA;
+  else
     return GUESS_DEVTYPE_DONT_KNOW;
-  return GUESS_DEVTYPE_DONT_KNOW;
+}
+
+struct pathlist {
+	char **names;
+	int  nnames;
+	int  maxnames;
+};
+
+static int
+addpath(const char *path, struct pathlist *res)
+{
+	if (++res->nnames > res->maxnames) {
+		res->maxnames += 16;
+		res->names = realloc(res->names,
+		    res->maxnames * sizeof (char *));
+		if (res->names == NULL)
+			return -1;
+	}
+	if ((res->names[res->nnames-1] = strdup(path)) == NULL)
+		return -1;
+	return 0;
+}
+
+static int 
+grokdir(const char *dir, struct pathlist *res, int testfun(const char *))
+{
+	char pathbuf[MAXPATHLEN];
+	size_t len;
+	DIR *dp;
+	struct dirent *de;
+	int isdisk = strstr(dir, "dsk") != NULL;
+	char *p;
+
+	len = snprintf(pathbuf, sizeof (pathbuf), "%s/", dir);
+	if (len >= sizeof (pathbuf))
+		return -1;
+
+	dp = opendir(dir);
+	if (dp == NULL)
+		return 0;
+
+	while ((de = readdir(dp)) != NULL) {
+		if (de->d_name[0] == '.')
+			continue;
+
+		if (strlen(de->d_name) + len >= sizeof (pathbuf))
+			continue;
+
+		if (isdisk) {
+			/* Disk represented by slice 0 */
+			p = strstr(de->d_name, "s0");
+			/* String doesn't end in "s0\0" */
+			if (p == NULL || p[2] != '\0')
+				continue;
+		} else {
+			/* Tape drive represented by the all-digit device */
+			for (p = de->d_name; *p; p++)
+				if (!isdigit(*p))
+					break;
+			if (*p != '\0')
+				continue;
+		}
+		strcpy(&pathbuf[len], de->d_name);
+		if (testfun(pathbuf)) {
+			if (addpath(pathbuf, res) == -1) {
+				closedir(dp);
+				return -1;
+			}
+		}
+	}
+	closedir(dp);
+
+	return 0;
 }
 
 // makes a list of ATA or SCSI devices for the DEVICESCAN directive of
 // smartd.  Returns number of devices, or -1 if out of memory.
 int make_device_names (char*** devlist, const char* name) {
-  if (printwarning(1))
-    return 0;
-  return 0;
+	struct pathlist res;
+
+	res.nnames = res.maxnames = 0;
+	res.names = NULL;
+	if (strcmp(name, "SCSI") == 0) {
+		if (grokdir("/dev/rdsk", &res, isscsidev) == -1)
+			return (-1);
+		if (grokdir("/dev/rmt", &res, isscsidev) == -1)
+			return (-1);
+		*devlist = res.names;
+		return res.nnames;
+	}
+	return 0;
 }
 
 // Like open().  Return integer handle, used by functions below only.
@@ -105,22 +242,91 @@ int deviceclose(int fd){
 
 // Interface to ATA devices.  See os_linux.c
 int ata_command_interface(int fd, smart_command_set command, int select, char *data){
-  if (printwarning(2))
+  if (printwarning(0))
     return -1;
   return -1;
 }
 
 // Interface to ATA devices behind 3ware escalade RAID controller cards.  See os_linux.c
 int escalade_command_interface(int fd, int disknum, smart_command_set command, int select, char *data){
-  if (printwarning(3))
+  if (printwarning(1))
     return -1;
   return -1;
 }
 
 #include <errno.h>
+#include <sys/scsi/generic/commands.h>
+#include <sys/scsi/generic/status.h>
+#include <sys/scsi/impl/types.h>
+#include <sys/scsi/impl/uscsi.h>
+
 // Interface to SCSI devices.  See os_linux.c
 int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report) {
-  if (printwarning(4))
-    return -ENOSYS;
-  return -ENOSYS;
+  struct uscsi_cmd uscsi;
+
+    if (report > 0) {
+        int k;
+        const unsigned char * ucp = iop->cmnd;
+        const char * np;
+
+        np = scsi_get_opcode_name(ucp[0]);
+        pout(" [%s: ", np ? np : "<unknown opcode>");
+        for (k = 0; k < iop->cmnd_len; ++k)
+            pout("%02x ", ucp[k]);
+        if ((report > 1) && 
+            (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
+            int trunc = (iop->dxfer_len > 256) ? 1 : 0;
+
+            pout("]\n  Outgoing data, len=%d%s:\n", (int)iop->dxfer_len,
+                 (trunc ? " [only first 256 bytes shown]" : ""));
+            dStrHex((char *)iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
+        }
+        else
+            pout("]");
+    }
+
+
+  memset(&uscsi, 0, sizeof (uscsi));
+
+  uscsi.uscsi_cdb = (void *)iop->cmnd;
+  uscsi.uscsi_cdblen = iop->cmnd_len;
+  if (iop->timeout == 0)
+    uscsi.uscsi_timeout = 60; /* XXX */
+  else
+    uscsi.uscsi_timeout = iop->timeout;
+  uscsi.uscsi_bufaddr = (void *)iop->dxferp;
+  uscsi.uscsi_buflen = iop->dxfer_len;
+  uscsi.uscsi_rqbuf = (void *)iop->sensep;
+  uscsi.uscsi_rqlen = iop->max_sense_len;
+
+  switch (iop->dxfer_dir) {
+  case DXFER_NONE:
+  case DXFER_FROM_DEVICE:
+    uscsi.uscsi_flags = USCSI_READ;
+    break;
+  case DXFER_TO_DEVICE:
+    uscsi.uscsi_flags = USCSI_WRITE;
+    break;
+  default:
+    return -EINVAL;
+  }
+  uscsi.uscsi_flags |= USCSI_ISOLATE;
+
+  if (ioctl(fd, USCSICMD, &uscsi))
+    return -errno;
+
+  iop->scsi_status = uscsi.uscsi_status;
+  iop->resid = uscsi.uscsi_resid;
+  iop->resp_sense_len = iop->max_sense_len - uscsi.uscsi_rqresid;
+
+  if (report > 0) {
+    int trunc = (iop->dxfer_len > 256) ? 1 : 0;
+    pout("  status=0\n");
+    
+    pout("  Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
+         (trunc ? " [only first 256 bytes shown]" : ""));
+    dStrHex((char *)iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
+  }
+
+  return (0);
 }
diff --git a/sm5/os_solaris.cpp b/sm5/os_solaris.cpp
index 4bddbc0562959018c0e38a42ebe808316591487d..e88e1c969cfcbd9870dcba968c34e3c9fca8adec 100644
--- a/sm5/os_solaris.cpp
+++ b/sm5/os_solaris.cpp
@@ -3,7 +3,7 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2003 NAME HERE <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2003 Casper Dik <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
@@ -29,6 +29,14 @@
   smartmontools-support@lists.sourceforge.net
 */
 
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/param.h>
+
 // These are needed to define prototypes for the functions defined below
 #include "atacmds.h"
 #include "scsicmds.h"
@@ -37,17 +45,14 @@
 // This is to include whatever prototypes you define in os_solaris.h
 #include "os_solaris.h"
 
-const char *os_XXXX_c_cvsid="$Id: os_solaris.cpp,v 1.6 2003/10/15 14:06:02 ballen4705 Exp $" \
+const char *os_XXXX_c_cvsid="$Id: os_solaris.cpp,v 1.7 2003/10/26 02:12:33 ballen4705 Exp $" \
 ATACMDS_H_CVSID OS_XXXX_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
 
 // The printwarning() function warns about unimplemented functions
-int printedout[5];
-char *unimplemented[5]={
-  "guess_device_type()",
-  "make_device_names()",
+int printedout[2];
+char *unimplemented[2]={
   "ATA command routine ata_command_interface()",
   "3ware Escalade Controller command routine escalade_command_interface()",
-  "SCSI command interface do_scsi_cmnd_io()"
 };
 
 int printwarning(int which){
@@ -71,19 +76,151 @@ int printwarning(int which){
   return 1;
 }
 
+static const char *uscsidrvrs[] = {
+	"sd",
+	"ssd",
+	"st"
+};
+
+static const char *atadrvrs[] = {
+	"cmdk",
+	"dad",
+};
+
+static int
+isdevtype(const char *dev_name, const char *table[], int tsize)
+{
+  char devpath[MAXPATHLEN];
+  int i;
+  char *basename;
+
+  if (realpath(dev_name, devpath) == NULL)
+    return 0;
+ 
+  if ((basename = strrchr(devpath, '/')) == NULL)
+    return 0;
+
+  basename++;
+
+  for (i = 0; i < tsize; i++) {
+    int l = strlen(table[i]);
+    if (strncmp(basename, table[i], l) == 0 && basename[l] == '@')
+      return 1;
+  }
+  return 0;
+}
+
+static int
+isscsidev(const char *path)
+{
+  return isdevtype(path, uscsidrvrs, sizeof (uscsidrvrs) / sizeof (char *));
+}
+
+static int
+isatadev(const char *path)
+{
+  return isdevtype(path, atadrvrs, sizeof (atadrvrs) / sizeof (char *));
+}
+
 // tries to guess device type given the name (a path)
 int guess_device_type (const char* dev_name) {
-  if (printwarning(0))
+  if (isscsidev(dev_name))
+    return GUESS_DEVTYPE_SCSI;
+  else if (isatadev(dev_name))
+    return GUESS_DEVTYPE_ATA;
+  else
     return GUESS_DEVTYPE_DONT_KNOW;
-  return GUESS_DEVTYPE_DONT_KNOW;
+}
+
+struct pathlist {
+	char **names;
+	int  nnames;
+	int  maxnames;
+};
+
+static int
+addpath(const char *path, struct pathlist *res)
+{
+	if (++res->nnames > res->maxnames) {
+		res->maxnames += 16;
+		res->names = realloc(res->names,
+		    res->maxnames * sizeof (char *));
+		if (res->names == NULL)
+			return -1;
+	}
+	if ((res->names[res->nnames-1] = strdup(path)) == NULL)
+		return -1;
+	return 0;
+}
+
+static int 
+grokdir(const char *dir, struct pathlist *res, int testfun(const char *))
+{
+	char pathbuf[MAXPATHLEN];
+	size_t len;
+	DIR *dp;
+	struct dirent *de;
+	int isdisk = strstr(dir, "dsk") != NULL;
+	char *p;
+
+	len = snprintf(pathbuf, sizeof (pathbuf), "%s/", dir);
+	if (len >= sizeof (pathbuf))
+		return -1;
+
+	dp = opendir(dir);
+	if (dp == NULL)
+		return 0;
+
+	while ((de = readdir(dp)) != NULL) {
+		if (de->d_name[0] == '.')
+			continue;
+
+		if (strlen(de->d_name) + len >= sizeof (pathbuf))
+			continue;
+
+		if (isdisk) {
+			/* Disk represented by slice 0 */
+			p = strstr(de->d_name, "s0");
+			/* String doesn't end in "s0\0" */
+			if (p == NULL || p[2] != '\0')
+				continue;
+		} else {
+			/* Tape drive represented by the all-digit device */
+			for (p = de->d_name; *p; p++)
+				if (!isdigit(*p))
+					break;
+			if (*p != '\0')
+				continue;
+		}
+		strcpy(&pathbuf[len], de->d_name);
+		if (testfun(pathbuf)) {
+			if (addpath(pathbuf, res) == -1) {
+				closedir(dp);
+				return -1;
+			}
+		}
+	}
+	closedir(dp);
+
+	return 0;
 }
 
 // makes a list of ATA or SCSI devices for the DEVICESCAN directive of
 // smartd.  Returns number of devices, or -1 if out of memory.
 int make_device_names (char*** devlist, const char* name) {
-  if (printwarning(1))
-    return 0;
-  return 0;
+	struct pathlist res;
+
+	res.nnames = res.maxnames = 0;
+	res.names = NULL;
+	if (strcmp(name, "SCSI") == 0) {
+		if (grokdir("/dev/rdsk", &res, isscsidev) == -1)
+			return (-1);
+		if (grokdir("/dev/rmt", &res, isscsidev) == -1)
+			return (-1);
+		*devlist = res.names;
+		return res.nnames;
+	}
+	return 0;
 }
 
 // Like open().  Return integer handle, used by functions below only.
@@ -105,22 +242,91 @@ int deviceclose(int fd){
 
 // Interface to ATA devices.  See os_linux.c
 int ata_command_interface(int fd, smart_command_set command, int select, char *data){
-  if (printwarning(2))
+  if (printwarning(0))
     return -1;
   return -1;
 }
 
 // Interface to ATA devices behind 3ware escalade RAID controller cards.  See os_linux.c
 int escalade_command_interface(int fd, int disknum, smart_command_set command, int select, char *data){
-  if (printwarning(3))
+  if (printwarning(1))
     return -1;
   return -1;
 }
 
 #include <errno.h>
+#include <sys/scsi/generic/commands.h>
+#include <sys/scsi/generic/status.h>
+#include <sys/scsi/impl/types.h>
+#include <sys/scsi/impl/uscsi.h>
+
 // Interface to SCSI devices.  See os_linux.c
 int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report) {
-  if (printwarning(4))
-    return -ENOSYS;
-  return -ENOSYS;
+  struct uscsi_cmd uscsi;
+
+    if (report > 0) {
+        int k;
+        const unsigned char * ucp = iop->cmnd;
+        const char * np;
+
+        np = scsi_get_opcode_name(ucp[0]);
+        pout(" [%s: ", np ? np : "<unknown opcode>");
+        for (k = 0; k < iop->cmnd_len; ++k)
+            pout("%02x ", ucp[k]);
+        if ((report > 1) && 
+            (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
+            int trunc = (iop->dxfer_len > 256) ? 1 : 0;
+
+            pout("]\n  Outgoing data, len=%d%s:\n", (int)iop->dxfer_len,
+                 (trunc ? " [only first 256 bytes shown]" : ""));
+            dStrHex((char *)iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
+        }
+        else
+            pout("]");
+    }
+
+
+  memset(&uscsi, 0, sizeof (uscsi));
+
+  uscsi.uscsi_cdb = (void *)iop->cmnd;
+  uscsi.uscsi_cdblen = iop->cmnd_len;
+  if (iop->timeout == 0)
+    uscsi.uscsi_timeout = 60; /* XXX */
+  else
+    uscsi.uscsi_timeout = iop->timeout;
+  uscsi.uscsi_bufaddr = (void *)iop->dxferp;
+  uscsi.uscsi_buflen = iop->dxfer_len;
+  uscsi.uscsi_rqbuf = (void *)iop->sensep;
+  uscsi.uscsi_rqlen = iop->max_sense_len;
+
+  switch (iop->dxfer_dir) {
+  case DXFER_NONE:
+  case DXFER_FROM_DEVICE:
+    uscsi.uscsi_flags = USCSI_READ;
+    break;
+  case DXFER_TO_DEVICE:
+    uscsi.uscsi_flags = USCSI_WRITE;
+    break;
+  default:
+    return -EINVAL;
+  }
+  uscsi.uscsi_flags |= USCSI_ISOLATE;
+
+  if (ioctl(fd, USCSICMD, &uscsi))
+    return -errno;
+
+  iop->scsi_status = uscsi.uscsi_status;
+  iop->resid = uscsi.uscsi_resid;
+  iop->resp_sense_len = iop->max_sense_len - uscsi.uscsi_rqresid;
+
+  if (report > 0) {
+    int trunc = (iop->dxfer_len > 256) ? 1 : 0;
+    pout("  status=0\n");
+    
+    pout("  Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
+         (trunc ? " [only first 256 bytes shown]" : ""));
+    dStrHex((char *)iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
+  }
+
+  return (0);
 }
diff --git a/sm5/os_solaris.h b/sm5/os_solaris.h
index e1ee73fc7507ae7cf67f910066060f8f4b52c025..f5b33a2429d68abc3a5ce3554f65cddd5d3896b2 100644
--- a/sm5/os_solaris.h
+++ b/sm5/os_solaris.h
@@ -3,7 +3,7 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2003 NAME HERE <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2003 Casper Dik <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
@@ -24,7 +24,7 @@
 #ifndef OS_SOLARIS_H_
 #define OS_SOLARIS_H_
 
-#define OS_XXXX_H_CVSID "$Id: os_solaris.h,v 1.4 2003/10/14 13:09:06 ballen4705 Exp $\n"
+#define OS_XXXX_H_CVSID "$Id: os_solaris.h,v 1.5 2003/10/26 02:12:33 ballen4705 Exp $\n"
 
 // Additional material should start here.  Note: to keep the '-V' CVS
 // reporting option working as intended, you should only #include