diff --git a/libburn/trunk/Makefile.am b/libburn/trunk/Makefile.am
index b0d4f19f..8d9c87d2 100644
--- a/libburn/trunk/Makefile.am
+++ b/libburn/trunk/Makefile.am
@@ -203,10 +203,12 @@ EXTRA_DIST = \
 	libburn/os-freebsd.h \
 	libburn/os-linux.h \
 	libburn/os-libcdio.h \
+	libburn/os-solaris.h \
 	libburn/sg-dummy.c \
 	libburn/sg-freebsd.c \
 	libburn/sg-linux.c \
 	libburn/sg-libcdio.c \
+	libburn/sg-solaris.c \
 	COPYING \
 	NEWS \
 	ChangeLog \
diff --git a/libburn/trunk/README b/libburn/trunk/README
index 7fd4206a..75fe3765 100644
--- a/libburn/trunk/README
+++ b/libburn/trunk/README
@@ -105,8 +105,9 @@ The project comprises of several more or less interdependent parts which
 together strive to be a usable foundation for application development.
 These are libraries, language bindings, and middleware binaries which emulate
 classical (and valuable) Linux tools.
-Currently it is supported on Linux with kernels >= 2.4 and on FreeBSD versions 
-with ATAPI/CAM support enabled in the kernel, see atapicam(4).
+Currently it is supported on GNU/Linux with kernels >= 2.4,
+on FreeBSD with ATAPI/CAM enabled in the kernel (see man atapicam),
+and on OpenSolaris (tested with kernel 5.11).
 On other X/Open compliant systems there will only be pseudo drives, but no
 direct MMC operation on real CD/DVD/BD drives.
 
diff --git a/libburn/trunk/cdrskin/README b/libburn/trunk/cdrskin/README
index 55088b83..7c9fd1ed 100644
--- a/libburn/trunk/cdrskin/README
+++ b/libburn/trunk/cdrskin/README
@@ -13,7 +13,8 @@ Copyright (C) 2006-2010 Thomas Schmitt, provided under GPL version 2 or later.
 cdrskin is a limited cdrecord compatibility wrapper which allows to use
 most of the libburn features from the command line.
 
-Currently it is supported on Linux with kernels >= 2.4 and on FreeBSD.
+Currently it is supported on GNU/Linux with kernels >= 2.4,
+on FreeBSD and on OpenSolaris.
 IDE drives under Linux 2.4. need kernel module ide-scsi.
 ATA and SATA drives under FreeBSD need kernel module atapicam.
 On other X/Open compliant systems there will only be emulated drives, but no
diff --git a/libburn/trunk/cdrskin/cdrskin_eng.html b/libburn/trunk/cdrskin/cdrskin_eng.html
index dcc4b51a..ed906f70 100644
--- a/libburn/trunk/cdrskin/cdrskin_eng.html
+++ b/libburn/trunk/cdrskin/cdrskin_eng.html
@@ -269,8 +269,9 @@ Bug fixes towards cdrskin-0.7.8.pl00:
 <DT><H3>Development snapshot, version 0.8.1 :</H3></DT>
 <DD>Enhancements towards current stable version 0.8.0.pl00:
 <UL>
-<LI>none yet</LI>
+<LI>A new system adapter allows to burn CD, DVD and BD on OpenSolaris</LI>
 <!--
+<LI>none yet</LI>
 -->
 
 </UL>
@@ -278,8 +279,14 @@ Bug fixes towards cdrskin-0.7.8.pl00:
 
 <DD>Bug fixes towards cdrskin-0.8.0.pl00:
 <UL>
-<LI>none yet</LI>
+<LI>
+CD TOC was not read if the first track did not start at LBA 0
+</LI>
+<LI>
+CD-ROM media got attributed random lead-in and lead-out adresses
+</LI>
 <!--
+<LI>none yet</LI>
 -->
 </UL>
 </DD>
diff --git a/libburn/trunk/cdrskin/cdrskin_timestamp.h b/libburn/trunk/cdrskin/cdrskin_timestamp.h
index 9f7f569a..9929168e 100644
--- a/libburn/trunk/cdrskin/cdrskin_timestamp.h
+++ b/libburn/trunk/cdrskin/cdrskin_timestamp.h
@@ -1 +1 @@
-#define Cdrskin_timestamP "2010.06.07.171706"
+#define Cdrskin_timestamP "2010.06.07.172925"
diff --git a/libburn/trunk/libburn/libdax_msgs.h b/libburn/trunk/libburn/libdax_msgs.h
index 061bd7cd..1b34b857 100644
--- a/libburn/trunk/libburn/libdax_msgs.h
+++ b/libburn/trunk/libburn/libdax_msgs.h
@@ -434,6 +434,8 @@ Range "scdbackup"          :  0x00020000 to 0x0002ffff
  0x00020009 (SORRY,HIGH)   = Neither stdio-path nor its directory exist
  0x0002000a (FAILURE,HIGH) = Cannot accept '...' as SG_IO CDROM drive
  0x0002000b (FAILURE,HIGH) = File object '...' not found
+ 0x0002000c (FAILURE,HIGH) = Cannot start device file enumeration
+ 0x0002000d (FAILURE,HIGH) = Cannot enumerate next device
            
  General library operations:
 
diff --git a/libburn/trunk/libburn/os-solaris.h b/libburn/trunk/libburn/os-solaris.h
new file mode 100644
index 00000000..f0b18476
--- /dev/null
+++ b/libburn/trunk/libburn/os-solaris.h
@@ -0,0 +1,68 @@
+
+/* os-libcdio.h
+   Operating system specific libburn definitions and declarations. Included
+   by os.h in case of compilation for
+           Solaris based systems, e.g. SunOS 5.11
+           with Solaris uscsi MMC transport adapter sg-solaris.c
+
+   Copyright (C) 2010 Thomas Schmitt <scdbackup@gmx.net>, provided under GPLv2+
+*/
+
+
+/** List of all signals which shall be caught by signal handlers and trigger
+    a graceful abort of libburn. (See man signal.h)
+*/
+/* Once as system defined macros */
+#define BURN_OS_SIGNAL_MACRO_LIST \
+ SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, \
+ SIGFPE, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM, \
+ SIGUSR1, SIGUSR2, SIGXCPU, SIGTSTP, SIGTTIN, \
+ SIGTTOU
+
+/* Once as text 1:1 list of strings for messages and interpreters */
+#define BURN_OS_SIGNAL_NAME_LIST \
+ "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGABRT", \
+ "SIGFPE", "SIGSEGV", "SIGPIPE", "SIGALRM", "SIGTERM", \
+ "SIGUSR1", "SIGUSR2", "SIGXCPU", "SIGTSTP", "SIGTTIN", \
+ "SIGTTOU"
+
+/* The number of above list items */
+#define BURN_OS_SIGNAL_COUNT 16
+
+/** To list all signals which shall surely not be caught */
+#define BURN_OS_NON_SIGNAL_MACRO_LIST \
+SIGKILL, SIGCHLD, SIGSTOP, SIGURG, SIGWINCH
+
+/* The number of above list items */
+#define BURN_OS_NON_SIGNAL_COUNT 5
+
+
+/* The maximum size for a (SCSI) i/o transaction */
+/* Important : MUST be at least 32768 ! */
+/* My Blu-ray burner LG GGW-H20 writes junk if stream recording is combined
+   with buffer size 32 kB. So stream recording is allowed only with size 64k.
+
+   >>> ??? is 64 kB ok for Solaris uscsi ?
+*/
+#define BURN_OS_TRANSPORT_BUFFER_SIZE 65536
+
+
+/* >>> */
+
+/* To hold the position of the most recently delivered address from
+   device enumeration.
+*/
+struct burn_drive_enumerator_struct {
+	void *dir;
+};
+
+#define BURN_OS_DEFINE_DRIVE_ENUMERATOR_T \
+typedef struct burn_drive_enumerator_struct burn_drive_enumerator_t;
+
+
+/* The list of operating system dependent elements in struct burn_drive.
+   Usually they are initialized in  sg-*.c:enumerate_common().
+*/
+#define BURN_OS_TRANSPORT_DRIVE_ELEMENTS \
+	int fd;
+
diff --git a/libburn/trunk/libburn/os.h b/libburn/trunk/libburn/os.h
index 376650a0..9fc6149f 100644
--- a/libburn/trunk/libburn/os.h
+++ b/libburn/trunk/libburn/os.h
@@ -14,6 +14,14 @@
 */
 
 
+#ifdef Libburn_use_sg_dummY
+
+
+/* --------- Any other system. With dummy MMC transport sg-dummy.c --------- */
+#include "os-dummy.h"
+
+
+#else
 #ifdef Libburn_use_libcdiO
 
 
@@ -45,6 +53,14 @@
 #include "os-linux.h"
 
 
+#else
+#ifdef __sun
+
+
+/* ------- Solaris (e.g. SunOS 5.11) with uscsi ------ */
+#include "os-solaris.h"
+
+
 #else
 
 
@@ -52,10 +68,12 @@
 #include "os-dummy.h"
 
 
+#endif /* ! __sun*/
 #endif /* ! __linux */
 #endif /* ! __FreeBSD__kernel__ */
 #endif /* ! __FreeBSD__ */
 #endif /* ! Libburn_use_libcdiO */
+#endif /* ! Libburn_use_sg_dummY */
 
 
 #endif /* ! BURN_OS_H_INCLUDED */
diff --git a/libburn/trunk/libburn/sg-solaris.c b/libburn/trunk/libburn/sg-solaris.c
new file mode 100644
index 00000000..784f5656
--- /dev/null
+++ b/libburn/trunk/libburn/sg-solaris.c
@@ -0,0 +1,892 @@
+/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
+
+/*
+   Copyright (c) 2010 Thomas Schmitt <scdbackup@gmx.net>
+   Provided under GPL version 2 or later.
+*/
+
+
+/*
+
+This is the main operating system dependent SCSI part of libburn. It implements
+the transport level aspects of SCSI control and command i/o.
+
+Present implementation: Solaris uscsi, e.g. for SunOS 5.11
+
+
+PORTING:
+
+Porting libburn typically will consist of adding a new operating system case
+to the following switcher files:
+  os.h    Operating system specific libburn definitions and declarations.
+  sg.c    Operating system dependent transport level modules.
+and of deriving the following system specific files from existing examples:
+  os-*.h  Included by os.h. You will need some general system knowledge
+          about signals and knowledge about the storage object needs of your
+          transport level module sg-*.c.
+
+  sg-*.c  This source module. You will need special system knowledge about
+          how to detect all potentially available drives, how to open them,
+          eventually how to exclusively reserve them, how to perform
+          SCSI transactions, how to inquire the (pseudo-)SCSI driver.
+          You will not need to care about CD burning, MMC or other high-level
+          SCSI aspects.
+
+Said sg-*.c operations are defined by a public function interface, which has
+to be implemented in a way that provides libburn with the desired services:
+
+sg_id_string()          returns an id string of the SCSI transport adapter.
+                        It may be called before initialization but then may
+                        return only a preliminary id.
+
+sg_initialize()         performs global initialization of the SCSI transport
+                        adapter and eventually needed operating system
+                        facilities. Checks for compatibility of supporting
+                        software components.
+
+sg_shutdown()           performs global finalizations and releases golbally
+                        aquired resources.
+
+sg_give_next_adr()      iterates over the set of potentially useful drive 
+                        address strings.
+
+scsi_enumerate_drives() brings all available, not-whitelist-banned, and
+                        accessible drives into libburn's list of drives.
+
+sg_dispose_drive()      finalizes adapter specifics of struct burn_drive
+                        on destruction. Releases resources which were aquired
+                        underneath scsi_enumerate_drives().
+ 
+sg_drive_is_open()      tells wether libburn has the given drive in use.
+
+sg_grab()               opens the drive for SCSI commands and ensures
+                        undisturbed access.
+
+sg_release()            closes a drive opened by sg_grab()
+
+sg_issue_command()      sends a SCSI command to the drive, receives reply,
+                        and evaluates wether the command succeeded or shall
+                        be retried or finally failed.
+
+sg_obtain_scsi_adr()    tries to obtain SCSI address parameters.
+
+
+burn_os_is_2k_seekrw()  tells whether the given path leads to a file object
+                        that can be used in 2 kB granularity by lseek(2),
+                        read(2), and possibly write(2) if not read-only..
+                        E.g. a USB stick or a hard disk.
+
+burn_os_stdio_capacity()  estimates the emulated media space of stdio-drives.
+
+burn_os_open_track_src()  opens a disk file in a way that allows best
+                        throughput with file reading and/or SCSI write command
+                        transmission.
+
+burn_os_alloc_buffer()  allocates a memory area that is suitable for file
+                        descriptors issued by burn_os_open_track_src().
+                        The buffer size may be rounded up for alignment
+                        reasons.
+
+burn_os_free_buffer()   delete a buffer obtained by burn_os_alloc_buffer().
+
+Porting hints are marked by the text "PORTING:".
+Send feedback to libburn-hackers@pykix.org .
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+
+/** PORTING : ------- OS dependent headers and definitions ------ */
+
+#include <unistd.h>
+#include <stropts.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdlib.h>
+#include <dirent.h>
+
+#ifdef Libburn_os_has_statvfS
+#include <sys/statvfs.h>
+#endif /* Libburn_os_has_stavtfS */
+
+#include <sys/dkio.h>
+#include <sys/vtoc.h>
+
+#include <sys/scsi/impl/uscsi.h>
+
+/* >>> need a size determination call for random access devices.
+       e.g. USB sticks.
+*/
+#ifdef __linux
+/* for ioctl(BLKGETSIZE) */
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#endif
+
+
+/* The waiting time before eventually retrying a failed SCSI command.
+   Before each retry wait Libburn_sg_linux_retry_incR longer than with
+   the previous one.
+*/
+#define Libburn_sg_solaris_retry_usleeP 100000
+#define Libburn_sg_solaris_retry_incR   100000
+
+
+/** PORTING : ------ libburn portable headers and definitions ----- */
+
+#include "transport.h"
+#include "drive.h"
+#include "sg.h"
+#include "spc.h"
+#include "sbc.h"
+#include "debug.h"
+#include "toc.h"
+#include "util.h"
+
+#include "libdax_msgs.h"
+extern struct libdax_msgs *libdax_messenger;
+
+
+/* is in portable part of libburn */
+int burn_drive_is_banned(char *device_address);
+int burn_drive_resolve_link(char *path, char adr[],
+			 int *recursion_count, int flag); /* drive.c */
+
+/* Whether to log SCSI commands:
+   bit0= log in /tmp/libburn_sg_command_log
+   bit1= log to stderr
+   bit2= flush every line
+*/
+extern int burn_sg_log_scsi;
+
+
+/* ------------------------------------------------------------------------ */
+/* PORTING:   Private definitions. Port only if needed by public functions. */
+/*            (Public functions are listed below)                           */
+/* ------------------------------------------------------------------------ */
+
+
+/* Storage object is in libburn/init.c
+   whether to strive for exclusive access to the drive
+*/
+extern int burn_sg_open_o_excl;
+
+
+/* ------------------------------------------------------------------------ */
+/* PORTING: Private functions. Port only if needed by public functions      */
+/*          (Public functions are listed below)                             */
+/* ------------------------------------------------------------------------ */
+
+
+static int sg_close_drive(struct burn_drive * d)
+{
+	if (d->fd != -1) {
+		close(d->fd);
+		d->fd = -1;
+		return 1;
+	}
+	return 0;
+}
+
+
+static int decode_btl_number(char **cpt, int stopper, int *no)
+{
+  *no = 0;
+  for ((*cpt)++; **cpt != stopper; (*cpt)++) {
+    if (**cpt < '0' || **cpt > '9')
+      return 0;
+    *no = *no * 10 + **cpt - '0';
+  }
+  return 1;
+}
+
+
+/* Read bus, target, lun from name "cXtYdZs2".
+   Return 0 if name is not of the desired form.
+*/
+static int decode_btl_solaris(char *name, int *busno, int *tgtno, int *lunno,
+                        int flag)
+{
+  char *cpt;
+  int ret;
+
+  *busno = *tgtno = *lunno = -1;
+  cpt = name;
+  if (*cpt != 'c')
+    return 0;
+  ret = decode_btl_number(&cpt, 't', busno);
+  if (ret <= 0)
+    return ret;
+  ret = decode_btl_number(&cpt, 'd', tgtno);
+  if (ret <= 0)
+    return ret;
+  ret = decode_btl_number(&cpt, 's', lunno);
+  if (ret <= 0)
+    return ret;
+  cpt++;
+  if (*cpt != '2' || *(cpt + 1) != 0)
+    return 0;
+  return 1;
+}
+
+
+static int start_enum_cXtYdZs2(burn_drive_enumerator_t *idx, int flag)
+{
+	DIR *dir;
+
+	idx->dir = NULL;
+	dir = opendir("/dev/rdsk");
+	if (dir == NULL) {
+		libdax_msgs_submit(libdax_messenger, -1,
+		    0x0002000c, LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
+	"Cannot start device file enumeration. opendir(\"/dev/rdsk\") failed.",
+		    errno, 0);
+		return 0;
+	}
+	idx->dir = dir;
+	return 1;
+}
+
+
+static int next_enum_cXtYdZs2(burn_drive_enumerator_t *idx,
+				char adr[], int adr_size, int flag)
+{ 
+	int busno, tgtno, lunno, ret, fd = -1;
+	char volpath[160];
+	struct dirent *entry;
+	struct dk_cinfo cinfo;
+	DIR *dir;
+
+	dir = idx->dir;
+	while (1) {
+		errno = 0;
+		entry = readdir(dir);
+		if (entry == NULL) {
+			if (errno) {
+				libdax_msgs_submit(libdax_messenger,
+						-1, 0x0002000d,
+				LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
+	"Cannot enumerate next device. readdir() from \"/dev/rdsk\" failed.",
+						errno, 0);
+				return -1;
+			}
+	break;
+		}
+		if (strlen(entry->d_name) > sizeof(volpath) - 11)
+	continue;
+		ret = decode_btl_solaris(entry->d_name,
+					&busno, &tgtno, &lunno, 0);
+		if (ret <= 0)
+	continue; /* not cXtYdZs2 */
+
+		sprintf(volpath, "/dev/rdsk/%s", entry->d_name);
+		if (burn_drive_is_banned(volpath))
+	continue; 
+
+		fd = open(volpath, O_RDONLY | O_NDELAY);
+		if (fd < 0)
+	continue;
+		/* See man dkio */
+		ret = ioctl(fd, DKIOCINFO, &cinfo);
+		close(fd);
+		if (ret < 0)
+	continue;
+		if (cinfo.dki_ctype != DKC_CDROM)
+	continue;
+		if (adr_size <= strlen(volpath))
+			return -1;
+		strcpy(adr, volpath);
+		return 1;
+	}
+	return 0;
+}
+
+
+static int end_enum_cXtYdZs2(burn_drive_enumerator_t *idx, int flag)
+{
+	DIR *dir;
+
+	dir = idx->dir;
+	if(dir != NULL)
+		closedir(dir);
+	idx->dir = NULL;
+	return 1;
+}
+
+
+/* ----------------------------------------------------------------------- */
+/* PORTING: Private functions which contain publicly needed functionality. */
+/*          Their portable part must be performed. So it is probably best  */
+/*          to replace the non-portable part and to call these functions   */
+/*          in your port, too.                                             */
+/* ----------------------------------------------------------------------- */
+
+
+/** Wraps a detected drive into libburn structures and hands it over to
+    libburn drive list.
+*/
+static void enumerate_common(char *fname,
+				int bus_no, int host_no,
+				int channel_no, int target_no, int lun_no)
+{
+	int ret;
+	struct burn_drive out;
+
+	/* General libburn drive setup */
+	burn_setup_drive(&out, fname);
+
+	/* This transport adapter uses SCSI-family commands and models
+	   (seems the adapter would know better than its boss, if ever) */
+	ret = burn_scsi_setup_drive(&out, bus_no, host_no, channel_no,
+                                 target_no, lun_no, 0);
+        if (ret <= 0)
+                return;
+
+	/* PORTING: ------------------- non portable part --------------- */
+
+	/* Transport adapter is Solaris uscsi */
+	/* Adapter specific handles and data */
+	out.fd = -1;
+
+	/* PORTING: ---------------- end of non portable part ------------ */
+
+	/* Adapter specific functions with standardized names */
+	out.grab = sg_grab;
+	out.release = sg_release;
+	out.drive_is_open = sg_drive_is_open;
+	out.issue_command = sg_issue_command;
+	/* Finally register drive and inquire drive information */
+	burn_drive_finish_enum(&out);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* PORTING:           Public functions. These MUST be ported.               */
+/* ------------------------------------------------------------------------ */
+
+
+/** Returns the id string  of the SCSI transport adapter and eventually
+    needed operating system facilities.
+    This call is usable even if sg_initialize() was not called yet. In that
+    case a preliminary constant message might be issued if detailed info is
+    not available yet.
+    @param msg   returns id string
+    @param flag  unused yet, submit 0
+    @return      1 = success, <=0 = failure
+*/
+int sg_id_string(char msg[1024], int flag)
+{
+	sprintf(msg, "internal Solaris uscsi adapter sg-solaris");
+	return 1;
+}
+
+
+/** Performs global initialization of the SCSI transport adapter and eventually
+    needed operating system facilities. Checks for compatibility of supporting
+    software components.
+    @param msg   returns ids and/or error messages of eventual helpers
+    @param flag  unused yet, submit 0
+    @return      1 = success, <=0 = failure
+*/ 
+int sg_initialize(char msg[1024], int flag)
+{
+	return sg_id_string(msg, 0);
+}
+
+
+/** Performs global finalization of the SCSI transport adapter and eventually
+    needed operating system facilities. Releases globally aquired resources.
+    @param flag  unused yet, submit 0
+    @return      1 = success, <=0 = failure
+*/ 
+int sg_shutdown(int flag)
+{
+	return 1;
+}
+
+
+/** Finalizes BURN_OS_TRANSPORT_DRIVE_ELEMENTS, the components of
+    struct burn_drive which are defined in os-*.h.
+    The eventual initialization of those components was made underneath
+    scsi_enumerate_drives().
+    This will be called when a burn_drive gets disposed.
+    @param d     the drive to be finalized
+    @param flag  unused yet, submit 0
+    @return      1 = success, <=0 = failure
+*/
+int sg_dispose_drive(struct burn_drive *d, int flag)
+{
+	return 1;
+}
+
+
+/** Returns the next index number and the next enumerated drive address.
+    The enumeration has to cover all available and accessible drives. It is
+    allowed to return addresses of drives which are not available but under
+    some (even exotic) circumstances could be available. It is on the other
+    hand allowed, only to hand out addresses which can really be used right
+    in the moment of this call. (This implementation chooses the latter.)
+    @param idx An opaque handle. Make no own theories about it.
+    @param adr Takes the reply
+    @param adr_size Gives maximum size of reply including final 0
+    @param initialize  1 = start new,
+                       0 = continue, use no other values for now
+                      -1 = finish
+    @return 1 = reply is a valid address , 0 = no further address available
+           -1 = severe error (e.g. adr_size too small)
+*/
+int sg_give_next_adr(burn_drive_enumerator_t *idx,
+		     char adr[], int adr_size, int initialize)
+{
+	int ret;
+
+	if (initialize == 1) {
+		ret = start_enum_cXtYdZs2(idx, 0);
+		if (ret <= 0)
+			return ret;
+	} else if (initialize == -1) {
+		ret = end_enum_cXtYdZs2(idx, 0);
+		return 0;
+	}
+	ret = next_enum_cXtYdZs2(idx, adr, adr_size, 0);
+	return ret;
+}
+
+
+/** Brings all available, not-whitelist-banned, and accessible drives into
+    libburn's list of drives.
+*/
+int scsi_enumerate_drives(void)
+{
+	burn_drive_enumerator_t idx;
+	int initialize = 1, ret, i_bus_no = -1;
+        int i_host_no = -1, i_channel_no = -1, i_target_no = -1, i_lun_no = -1;
+	char buf[4096];
+
+	while(1) {
+		ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
+		initialize = 0;
+		if (ret <= 0)
+	break;
+		if (burn_drive_is_banned(buf))
+	continue; 
+		sg_obtain_scsi_adr(buf, &i_bus_no, &i_host_no,
+				&i_channel_no, &i_target_no, &i_lun_no);
+		enumerate_common(buf,
+				i_bus_no, i_host_no, i_channel_no,
+				i_target_no, i_lun_no);
+	}
+	sg_give_next_adr(&idx, buf, sizeof(buf), -1);
+	return 1;
+}
+
+
+/** Tells whether libburn has the given drive in use or exclusively reserved.
+    If it is "open" then libburn will eventually call sg_release() on it when
+    it is time to give up usage resp. reservation.
+*/
+/** Published as burn_drive.drive_is_open() */
+int sg_drive_is_open(struct burn_drive * d)
+{
+	return (d->fd != -1);
+}
+
+
+/** Opens the drive for SCSI commands and - if burn activities are prone
+    to external interference on your system - obtains an exclusive access lock
+    on the drive. (Note: this is not physical tray locking.)
+    A drive that has been opened with sg_grab() will eventually be handed
+    over to sg_release() for closing and unreserving. 
+*/  
+int sg_grab(struct burn_drive *d)
+{
+	char msg[4096];
+	int os_errno, ret;
+	struct dk_cinfo cinfo;
+
+	if (d->fd != -1) {
+		d->released = 0;
+		return 1;
+	}
+	d->fd = open(d->devname, O_RDONLY | O_NDELAY);
+	if (d->fd == -1) {
+		os_errno = errno;
+		sprintf(msg, "Could not grab drive '%s'", d->devname);
+		libdax_msgs_submit(libdax_messenger, d->global_index,
+			0x00020003,
+			LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
+			msg, os_errno, 0);
+		return 0;
+	}
+	ret = ioctl(d->fd, DKIOCINFO, &cinfo);
+	if (ret < 0)
+		goto revoke;
+	if (cinfo.dki_ctype != DKC_CDROM)
+		goto revoke;
+
+	/* >>> obtain eventual locks */;
+
+	d->released = 0;
+	return 1;
+revoke:;
+	sprintf(msg, "Could not grab drive '%s'. Not a CDROM device.",
+		 d->devname);
+	libdax_msgs_submit(libdax_messenger, d->global_index,
+			0x00020003,
+			LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
+			msg, 0, 0);
+	return 0;
+}
+
+
+/** PORTING: Is mainly about the call to sg_close_drive() and whether it
+             implements the demanded functionality.
+*/
+/** Gives up the drive for SCSI commands and releases eventual access locks.
+    (Note: this is not physical tray locking.) 
+*/
+int sg_release(struct burn_drive *d)
+{
+	if (d->fd < 0) {
+		burn_print(1, "release an ungrabbed drive.  die\n");
+		return 0;
+	}
+	sg_close_drive(d);
+	return 0;
+}
+
+
+/** Sends a SCSI command to the drive, receives reply and evaluates wether
+    the command succeeded or shall be retried or finally failed.
+    Returned SCSI errors shall not lead to a return value indicating failure.
+    The callers get notified by c->error. An SCSI failure which leads not to
+    a retry shall be notified via scsi_notify_error().
+    The Libburn_log_sg_commandS facility might be of help when problems with
+    a drive have to be examined. It shall stay disabled for normal use.
+    @return: 1 success , <=0 failure
+*/
+int sg_issue_command(struct burn_drive *d, struct command *c)
+{
+	int i, usleep_time, timeout_ms, no_retry = 0, ret;
+	time_t start_time;
+	struct uscsi_cmd cgc;
+        static FILE *fp = NULL;
+
+	c->error = 0;
+	memset(c->sense, 0, sizeof(c->sense));
+	if (d->fd == -1)
+		return 0;
+
+	if (burn_sg_log_scsi & 1) {
+		if (fp == NULL) {
+			fp= fopen("/tmp/libburn_sg_command_log", "a");
+			fprintf(fp,
+			    "\n-----------------------------------------\n");
+		}
+	}
+	if (burn_sg_log_scsi & 3)
+		scsi_log_cmd(c,fp,0);
+
+	memset (&cgc, 0, sizeof (struct uscsi_cmd));
+	/* No error messages, no retries,
+           do not execute with other commands, request sense data
+	*/
+	cgc.uscsi_flags = USCSI_SILENT | USCSI_DIAGNOSE | USCSI_ISOLATE
+				| USCSI_RQENABLE;
+	cgc.uscsi_timeout = 200;
+	cgc.uscsi_cdb = (caddr_t) c->opcode;
+	cgc.uscsi_bufaddr = (caddr_t) c->page->data;
+	if (c->dir == TO_DRIVE) {
+		cgc.uscsi_flags |= USCSI_WRITE;
+		cgc.uscsi_buflen = c->page->bytes;
+	} else if (c->dir == FROM_DRIVE) {
+		cgc.uscsi_flags |= USCSI_READ;
+		if (c->dxfer_len >= 0)
+			cgc.uscsi_buflen = c->dxfer_len;
+		else
+			cgc.uscsi_buflen = BUFFER_SIZE;
+		/* touch page so we can use valgrind */
+		memset(c->page->data, 0, BUFFER_SIZE);
+	} else {
+		cgc.uscsi_buflen = 0;
+	}
+	cgc.uscsi_cdblen  = c->oplen;
+	cgc.uscsi_rqlen = sizeof(c->sense);
+	cgc.uscsi_rqbuf = (caddr_t) c->sense;
+
+	/* retry-loop */
+	start_time = time(NULL);
+	timeout_ms = 200000;
+	for(i = 0; ; i++) {
+
+		ret = ioctl(d->fd, USCSICMD, &cgc);
+
+		/* For cgc.uscsi_status see SAM-3 5.3.1, Table 22
+		   0 = GOOD , 2 = CHECK CONDITION : Sense Data are delivered
+		   8 = BUSY
+		*/
+		if (ret != 0 &&
+		    cgc.uscsi_status != 2 && cgc.uscsi_status != 8) {
+			libdax_msgs_submit(libdax_messenger,
+				d->global_index, 0x0002010c,
+				LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
+				"Failed to transfer command to drive",
+				errno, 0);
+			sg_close_drive(d);
+			d->released = 1;
+			d->busy = BURN_DRIVE_IDLE;
+			c->error = 1;
+			return -1;
+		}
+
+		c->sense[2] &= 15;
+
+		if (cgc.uscsi_status == 8) {
+			/* >>> fake BUSY sense */;
+		}
+
+		/* >>> valid sense:  cgc.uscsi_rqlen - cgc.uscsi_rqresid */;
+
+		if (c->sense[2] || c->sense[12] || c->sense[13]) {
+			if (no_retry || !c->retry) {
+				c->error = 1;
+				goto ex;
+			}
+			switch (scsi_error(d, c->sense, 18)) {
+			case RETRY:
+				if (burn_sg_log_scsi & 3) {
+					/* >>> Need own duration time
+					       measurement. Then remove bit1 */
+					scsi_log_err(c, fp, c->sense, 0,
+							(c->error != 0) | 2);
+					scsi_log_cmd(c,fp,0);
+				}
+				break;
+			case FAIL:
+				c->error = 1;
+				goto ex;
+			}
+			/* 
+			   Calming down retries and breaking up endless cycle
+			*/
+			usleep_time = Libburn_sg_solaris_retry_usleeP +
+					i * Libburn_sg_solaris_retry_incR;
+			if (time(NULL) + usleep_time / 1000000 - start_time >
+			    timeout_ms / 1000 + 1) {
+				c->error = 1;
+				goto ex;
+			}
+			usleep(usleep_time);
+		} else
+			break; /* retry-loop */
+	} /* end of retry-loop */
+
+ex:;
+	if (c->error)
+		scsi_notify_error(d, c, c->sense, 18, 0);
+
+	if (burn_sg_log_scsi & 3) 
+		/* >>> Need own duration time measurement. Then remove bit1 */
+		scsi_log_err(c, fp, c->sense, 0, (c->error != 0) | 2);
+	return 1;
+}
+
+/* >>> */
+
+/** Tries to obtain SCSI address parameters.
+    @return  1 is success , 0 is failure
+*/
+int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
+                       int *target_no, int *lun_no)
+{
+	int ret;
+
+	/* Try to guess from path */
+	if (strncmp("/dev/rdsk/", path, 10) == 0) {
+		ret = decode_btl_solaris(path + 10,
+					bus_no, target_no, lun_no, 0);
+		if (ret > 0) {
+			*host_no = *bus_no;
+			*channel_no = 0;
+			return 1;
+		}
+	}
+	*bus_no = *host_no = *channel_no = *target_no = *lun_no = -1;
+
+	/* >>> Could need a ioctl which gives SCSI numbers */;
+
+	return (0);
+}
+
+
+/** Tells wether a text is a persistent address as listed by the enumeration
+    functions.
+*/
+int sg_is_enumerable_adr(char* adr)
+{
+	burn_drive_enumerator_t idx;
+	int initialize = 1, ret;
+	char buf[64];
+
+	while(1) {
+		ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
+		initialize = 0;
+		if (ret <= 0)
+	break;
+		if (strcmp(adr, buf) == 0) {
+			sg_give_next_adr(&idx, buf, sizeof(buf), -1);
+			return 1;
+		}
+	}
+	sg_give_next_adr(&idx, buf, sizeof(buf), -1);
+	return (0);
+}
+
+
+
+/* Return 1 if the given path leads to a regular file or a device that can be
+   seeked, read, and possibly written with 2 kB granularity. 
+*/
+int burn_os_is_2k_seekrw(char *path, int flag)
+{
+	struct stat stbuf;
+
+	if (stat(path, &stbuf) == -1)
+		return 0;
+	if (S_ISREG(stbuf.st_mode))
+		return 1;
+	if (S_ISBLK(stbuf.st_mode))
+		return 1;
+	return 0;
+}
+
+
+/** Estimate the potential payload capacity of a file address.
+    @param path  The address of the file to be examined. If it does not
+                 exist yet, then the directory will be inquired.
+    @param bytes The pointed value gets modified, but only if an estimation is
+                 possible.
+    @return      -2 = cannot perform necessary operations on file object
+                 -1 = neither path nor dirname of path exist
+                  0 = could not estimate size capacity of file object
+                  1 = estimation has been made, bytes was set
+*/
+int burn_os_stdio_capacity(char *path, off_t *bytes)
+{
+	struct stat stbuf;
+
+#ifdef Libburn_os_has_statvfS
+	struct statvfs vfsbuf;
+#endif
+
+	char testpath[4096], *cpt;
+	long blocks;
+	off_t add_size = 0;
+
+	testpath[0] = 0;
+	blocks = *bytes / 512;
+	if (stat(path, &stbuf) == -1) {
+		strcpy(testpath, path);
+		cpt = strrchr(testpath, '/');
+		if(cpt == NULL)
+			strcpy(testpath, ".");
+		else if(cpt == testpath)
+			testpath[1] = 0;
+		else
+			*cpt = 0;
+		if (stat(testpath, &stbuf) == -1)
+			return -1;
+
+#ifdef __linux
+
+	/* GNU/Linux specific determination of block device size */
+	} else if(S_ISBLK(stbuf.st_mode)) {
+		int open_mode = O_RDONLY, fd, ret;
+
+		fd = open(path, open_mode);
+		if (fd == -1)
+			return -2;
+		ret = ioctl(fd, BLKGETSIZE, &blocks);
+		close(fd);
+		if (ret == -1)
+			return -2;
+		*bytes = ((off_t) blocks) * (off_t) 512;
+
+#endif /* __linux */
+
+
+		/* >>> ioctl to determine capacity of block device
+			? DKIOCGEXTVTOC , man dkio ?
+			? DKIOCEXTPARTINFO ,
+			  struct extpart_info.p_length * 512, man dkio ?
+		*/;
+
+
+	} else if(S_ISREG(stbuf.st_mode)) {
+		add_size = stbuf.st_blocks * (off_t) 512;
+		strcpy(testpath, path);
+	} else
+		return 0;
+
+	if (testpath[0]) {	
+
+#ifdef Libburn_os_has_statvfS
+
+		if (statvfs(testpath, &vfsbuf) == -1)
+			return -2;
+		*bytes = add_size + ((off_t) vfsbuf.f_frsize) *
+						(off_t) vfsbuf.f_bavail;
+
+#else /* Libburn_os_has_statvfS */
+
+		return 0;
+
+#endif /* ! Libburn_os_has_stavtfS */
+
+	}
+	return 1;
+}
+
+
+/* ts A91122 : an interface to open(O_DIRECT) or similar OS tricks. */
+
+#ifdef Libburn_read_o_direcT
+
+	/* No special O_DIRECT-like precautions are implemented here */
+
+#endif /* Libburn_read_o_direcT */
+
+
+int burn_os_open_track_src(char *path, int open_flags, int flag)
+{
+	int fd;
+
+	fd = open(path, open_flags);
+	return fd;
+}
+
+
+void *burn_os_alloc_buffer(size_t amount, int flag)
+{
+	void *buf = NULL;
+
+	buf = calloc(1, amount);
+	return buf;
+}
+
+
+int burn_os_free_buffer(void *buffer, size_t amount, int flag)
+{
+	if (buffer == NULL)
+		return 0;
+	free(buffer);
+	return 1;
+}
+
diff --git a/libburn/trunk/libburn/sg.c b/libburn/trunk/libburn/sg.c
index e855b390..1ee17e63 100644
--- a/libburn/trunk/libburn/sg.c
+++ b/libburn/trunk/libburn/sg.c
@@ -1,7 +1,8 @@
 
 /* sg.c
    Switcher for operating system dependent transport level modules of libburn.
-   Copyright (C) 2009 Thomas Schmitt <scdbackup@gmx.net>, provided under GPLv2+
+   Copyright (C) 2009 - 2010 Thomas Schmitt <scdbackup@gmx.net>, 
+   provided under GPLv2+
 */
 
 #ifdef HAVE_CONFIG_H
@@ -10,6 +11,11 @@
 #endif
 
 
+#ifdef Libburn_use_sg_dummY
+
+#include "sg-dummy.c"
+
+#else
 #ifdef Libburn_use_libcdiO
 
 #include "sg-libcdio.c"
@@ -29,6 +35,11 @@
 
 #include "sg-linux.c"
 
+#else
+#ifdef __sun
+
+#include "sg-solaris.c"
+
 #else
 
 /* The dummy adapter formally fulfills the expectations of libburn towards
@@ -51,8 +62,10 @@ static int intentional_compiler_warning(void)
 
 #include "sg-dummy.c"
 
+#endif /* ! __sun */
 #endif /* ! __linux */
 #endif /* ! __FreeBSD_kernel__ */
 #endif /* ! __FreeBSD__ */
 #endif /* ! Libburn_use_libcdiO */
+#endif /* ! Libburn_use_sg_dummY */