[xiph-commits] r11804 - in trunk/cdparanoia: . interface paranoia

xiphmont at svn.xiph.org xiphmont at svn.xiph.org
Tue Aug 29 12:06:10 PDT 2006


Author: xiphmont
Date: 2006-08-29 12:06:04 -0700 (Tue, 29 Aug 2006)
New Revision: 11804

Modified:
   trunk/cdparanoia/interface/Makefile.in
   trunk/cdparanoia/interface/cdda_interface.h
   trunk/cdparanoia/interface/interface.c
   trunk/cdparanoia/interface/low_interface.h
   trunk/cdparanoia/interface/scan_devices.c
   trunk/cdparanoia/interface/scsi_interface.c
   trunk/cdparanoia/main.c
   trunk/cdparanoia/paranoia/Makefile.in
   trunk/cdparanoia/version.h
Log:
SG_IO support for upcoming cdparanoia 10. Also looks for buggy
SG_DXFER_TO_FROM_DEVICE in the block layer of modern kernels.



Modified: trunk/cdparanoia/interface/Makefile.in
===================================================================
--- trunk/cdparanoia/interface/Makefile.in	2006-08-28 10:11:26 UTC (rev 11803)
+++ trunk/cdparanoia/interface/Makefile.in	2006-08-29 19:06:04 UTC (rev 11804)
@@ -9,7 +9,7 @@
 @SET_MAKE@
 FLAGS=@SBPCD_H@ @UCDROM_H@ @TYPESIZES@ @CFLAGS@
 OPT=@OPT@ $(FLAGS)
-DEBUG=@DEBUG@ $(FLAGS) -DCDDA_TEST
+DEBUG=@DEBUG@ -DCDDA_TEST
 CC=@CC@
 LD=@CC@
 LDFLAGS=@LDFLAGS@ $(FLAGS)

Modified: trunk/cdparanoia/interface/cdda_interface.h
===================================================================
--- trunk/cdparanoia/interface/cdda_interface.h	2006-08-28 10:11:26 UTC (rev 11803)
+++ trunk/cdparanoia/interface/cdda_interface.h	2006-08-29 19:06:04 UTC (rev 11804)
@@ -30,9 +30,11 @@
 } TOC;
 
 /* interface types */
-#define GENERIC_SCSI	0
-#define COOKED_IOCTL	1
-#define TEST_INTERFACE	2
+#define GENERIC_SCSI	 0
+#define COOKED_IOCTL	 1
+#define TEST_INTERFACE	 2
+#define SGIO_SCSI	 3
+#define SGIO_SCSI_BUGGY1 4
 
 #define CDDA_MESSAGE_FORGETIT 0
 #define CDDA_MESSAGE_PRINTIT 1
@@ -81,6 +83,11 @@
   int is_mmc;
 
   /* SCSI command buffer and offset pointers */
+  /* this should have been private hidden data, but it isn't.  At
+     this point, sg and sg_buffer are treated internally as void *
+     pointing to internal private data, which is correct even if it is
+     semantically confusing.  This problem will be corrected in the
+     next major release increment. */
   unsigned char *sg;
   unsigned char *sg_buffer;
   unsigned char inqbytes[4];

Modified: trunk/cdparanoia/interface/interface.c
===================================================================
--- trunk/cdparanoia/interface/interface.c	2006-08-28 10:11:26 UTC (rev 11803)
+++ trunk/cdparanoia/interface/interface.c	2006-08-29 19:06:04 UTC (rev 11804)
@@ -47,6 +47,7 @@
   if(d->opened)return(0);
 
   switch(d->interface){
+  case SGIO_SCSI:  
   case GENERIC_SCSI:  
     if((ret=scsi_init_drive(d)))
       return(ret);

Modified: trunk/cdparanoia/interface/low_interface.h
===================================================================
--- trunk/cdparanoia/interface/low_interface.h	2006-08-28 10:11:26 UTC (rev 11803)
+++ trunk/cdparanoia/interface/low_interface.h	2006-08-29 19:06:04 UTC (rev 11804)
@@ -50,11 +50,6 @@
 
 #include "cdda_interface.h"
 
-#define MAX_RETRIES 8
-#define MAX_BIG_BUFF_SIZE 65536
-#define MIN_BIG_BUFF_SIZE 4096
-#define SG_OFF sizeof(struct sg_header)
-
 #ifndef SG_EMULATED_HOST
 /* old kernel version; the check for the ioctl is still runtime, this
    is just to build */
@@ -63,6 +58,44 @@
 #define SG_GET_TRANSFORM 0x2205
 #endif
 
+#ifndef SG_IO
+/* old kernel version; the usage is all runtime-safe, this is just to
+   build */
+typedef struct sg_io_hdr
+{
+  int interface_id;           /* [i] 'S' for SCSI generic (required) */
+  int dxfer_direction;        /* [i] data transfer direction  */
+  unsigned char cmd_len;      /* [i] SCSI command length ( <= 16 bytes) */
+  unsigned char mx_sb_len;    /* [i] max length to write to sbp */
+  unsigned short int iovec_count; /* [i] 0 implies no scatter gather */
+  unsigned int dxfer_len;     /* [i] byte count of data transfer */
+  void * dxferp;              /* [i], [*io] points to data transfer memory
+                                 or scatter gather list */
+  unsigned char * cmdp;       /* [i], [*i] points to command to perform */
+  unsigned char * sbp;        /* [i], [*o] points to sense_buffer memory */
+  unsigned int timeout;       /* [i] MAX_UINT->no timeout (unit: millisec) */
+  unsigned int flags;         /* [i] 0 -> default, see SG_FLAG... */
+  int pack_id;                /* [i->o] unused internally (normally) */
+  void * usr_ptr;             /* [i->o] unused internally */
+  unsigned char status;       /* [o] scsi status */
+  unsigned char masked_status;/* [o] shifted, masked scsi status */
+  unsigned char msg_status;   /* [o] messaging level data (optional) */
+  unsigned char sb_len_wr;    /* [o] byte count actually written to sbp */
+  unsigned short int host_status; /* [o] errors from host adapter */
+  unsigned short int driver_status;/* [o] errors from software driver */
+  int resid;                  /* [o] dxfer_len - actual_transferred */
+  unsigned int duration;      /* [o] time taken by cmd (unit: millisec) */
+  unsigned int info;          /* [o] auxiliary information */
+} sg_io_hdr_t;
+
+
+#endif
+
+#define MAX_RETRIES 8
+#define MAX_BIG_BUFF_SIZE 65536
+#define MIN_BIG_BUFF_SIZE 4096
+#define SG_OFF sizeof(struct sg_header)
+
 extern int  cooked_init_drive (cdrom_drive *d);
 extern unsigned char *scsi_inquiry (cdrom_drive *d);
 extern int  scsi_init_drive (cdrom_drive *d);

Modified: trunk/cdparanoia/interface/scan_devices.c
===================================================================
--- trunk/cdparanoia/interface/scan_devices.c	2006-08-28 10:11:26 UTC (rev 11803)
+++ trunk/cdparanoia/interface/scan_devices.c	2006-08-29 19:06:04 UTC (rev 11804)
@@ -1,6 +1,6 @@
 /******************************************************************
  * CopyPolicy: GNU Public License 2 applies
- * Copyright (C) 1998 Monty xiphmont at mit.edu
+ * Copyright (C) 2006 Monty xiphmont at mit.edu
  * 
  * Autoscan for or verify presence of a cdrom device
  * 
@@ -117,13 +117,15 @@
   }
 #endif
 
-  d=cdda_identify_cooked(device,messagedest,messages);
-  if(!d)d=cdda_identify_scsi(device,NULL,messagedest,messages);
-
+  /* an IDE device may have scsi-ide support, SG_IO support and cooked
+     support.  Prefer the SCSI variants, they give the most control */
+  d=cdda_identify_scsi(NULL,device,messagedest,messages);
+  if(!d)d=cdda_identify_cooked(device,messagedest,messages);
+  
 #ifdef CDDA_TEST
   if(!d)d=cdda_identify_test(device,messagedest,messages);
 #endif
-  
+
   return(d);
 }
 
@@ -446,13 +448,66 @@
   return(major);
 }
 
+int check_sgio(const char *device, int messagedest, char **messages){
+  int fd;
+  struct sg_io_hdr hdr;
+
+  if (!device) return 0;
+
+  /* we don't really care what type of device it is -- if it can do
+   * SG_IO, then we'll put it through the normal mmc/atapi/etc tests
+   * later, but it's good enough for now. */
+  fd = open(device, O_RDWR|O_NONBLOCK);
+  if (fd < 0){
+    idperror(messagedest,messages,
+	     "\t\tCould not access device %d to test for SG_IO support",device);    
+    return 0;
+  }
+
+  memset(&hdr, 0, sizeof (struct sg_io_hdr));
+  /* First try with interface_id = 'A'; for all but the sg case,
+   * that'll get us a -EINVAL if it supports SG_IO, and some other
+   * error for all other cases. */
+  hdr.interface_id = 'A';
+  if (ioctl(fd, SG_IO, &hdr)) {
+    switch (errno) {
+    case EINVAL: /* sr and ata give us EINVAL when SG_IO is
+		  * supported but interface_id is bad. */
+      
+    case ENOSYS: /* sg gives us ENOSYS when SG_IO is supported but
+		  * interface_id is bad.  IMHO, this is wrong and
+		  * needs fixing in the kernel. */
+      
+      close(fd);
+      return 1;
+      
+    default: /* everything else gives ENOTTY, I think.  I'm just
+	      * going to be paranoid and reject everything else. */
+      
+      close(fd);
+      return 0;
+      
+    }
+  }
+  /* if we get here, something is dreadfuly wrong. ioctl(fd,SG_IO,&hdr)
+   * handled SG_IO, but took hdr.interface_id = 'A' as valid, and an empty
+   * command as good.  Don't trust it. */
+  close(fd);
+  return 0;
+}
+
+/* scanning is always done by specifying a device name in
+   specialized_device; generic_device is only filled when the generic device
+   force option is used, and in that case, use of SG (not SGIO) should indeed be
+   forced */
 cdrom_drive *cdda_identify_scsi(const char *generic_device, 
-				const char *ioctl_device, int messagedest,
+				const char *specialized_device, int messagedest,
 				char **messages){
-  
+
   cdrom_drive *d=NULL;
   struct stat i_st;
   struct stat g_st;
+  int use_sgio=1;
   int i_fd=-1, i;
   int g_fd=-1;
   int version;
@@ -460,50 +515,38 @@
   char *p;
 
   if(generic_device)
-    idmessage(messagedest,messages,"\tTesting %s for SCSI interface",
+    idmessage(messagedest,messages,"\tTesting %s for SCSI/MMC interface",
 	      generic_device);
   else
-    if(ioctl_device)
-    idmessage(messagedest,messages,"\tTesting %s for SCSI interface",
-	      ioctl_device);
+    if(specialized_device)
+      idmessage(messagedest,messages,"\tTesting %s for SCSI/MMC interface",
+		specialized_device);
+  
 
-
-  /* Do this first; it's wasteful, but the messages make more sense */
   if(generic_device){
+    use_sgio = 0;
+    idmessage(messagedest,messages,"\t\tgeneric device forced; not testing for SG_IO interface",
+	      generic_device);
+    
     if(stat(generic_device,&g_st)){
       idperror(messagedest,messages,"\t\tCould not access device %s",
 	       generic_device);
       return(NULL);
     }
+
     if((int)(g_st.st_rdev>>8)!=SCSI_GENERIC_MAJOR){
-      if((int)(g_st.st_rdev>>8)!=SCSI_CDROM_MAJOR){
-	idmessage(messagedest,messages,"\t\t%s is not a SCSI device",
-		  generic_device);
-	return(NULL);
-      }else{
-	char *temp=(char *)generic_device;
-	generic_device=ioctl_device;
-	ioctl_device=temp;
-      }
+      idmessage(messagedest,messages,"\t\t%s is not a generic SCSI device",
+		generic_device);
+      return(NULL);
     }
   }
-  if(ioctl_device){
-    if(stat(ioctl_device,&i_st)){
+  
+  if(specialized_device){ 
+    if(stat(specialized_device,&i_st)){
       idperror(messagedest,messages,"\t\tCould not access device %s",
-	       ioctl_device);
+	       specialized_device);
       return(NULL);
     }
-    if((int)(i_st.st_rdev>>8)!=SCSI_CDROM_MAJOR){
-      if((int)(i_st.st_rdev>>8)!=SCSI_GENERIC_MAJOR){
-	idmessage(messagedest,messages,"\t\t%s is not a SCSI device",
-		  ioctl_device);
-	return(NULL);
-      }else{
-	char *temp=(char *)generic_device;
-	generic_device=ioctl_device;
-	ioctl_device=temp;
-      }
-    }
   }
 
   /* we need to resolve any symlinks for the lookup code to work */
@@ -511,126 +554,163 @@
   if(generic_device){
     generic_device=test_resolve_symlink(generic_device,messagedest,messages);
     if(generic_device==NULL)goto cdda_identify_scsi_fail;
-
   }
-  if(ioctl_device){
-    ioctl_device=test_resolve_symlink(ioctl_device,messagedest,messages);
-    if(ioctl_device==NULL)goto cdda_identify_scsi_fail;
-
+  if(specialized_device){
+    specialized_device=test_resolve_symlink(specialized_device,messagedest,messages);
+    if(specialized_device==NULL)goto cdda_identify_scsi_fail;
   }
 
-  if(!generic_device || !ioctl_device){
-    if(generic_device){
-      ioctl_device=
-	scsi_match(generic_device,scsi_cdrom_prefixes,
-		   devfs_scsi_test,devfs_scsi_cd,
-		   "\t\tNo cdrom device found to match generic device %s",
-		   messagedest,messages);
+  /* sgio is always preferred if it's there, unless user has forced the generic scsi device name */
+  if(use_sgio){
+    if(check_sgio(specialized_device,messagedest,messages)){
+      idmessage(messagedest,messages,"\t\tSG_IO device: %s",specialized_device);
     }else{
-      generic_device=
-	scsi_match(ioctl_device,scsi_generic_prefixes,
-		   devfs_scsi_test,devfs_scsi_generic,
-		   "\t\tNo generic SCSI device found to match CDROM device %s",
-		   messagedest,messages);
-      if(!generic_device)	
-	goto cdda_identify_scsi_fail;
+      idmessage(messagedest,messages,"\t\tno SG_IO support for device: %s",specialized_device);
+      use_sgio=0;
     }
   }
   
-  idmessage(messagedest,messages,"\t\tgeneric device: %s",generic_device);
-  idmessage(messagedest,messages,"\t\tioctl device: %s",(ioctl_device?
-							 ioctl_device:
-							 "not found"));
-  
-  if(stat(generic_device,&g_st)){
-    idperror(messagedest,messages,"\t\tCould not access generic SCSI device "
-	     "%s",generic_device);
+  if(!use_sgio){
 
-    goto cdda_identify_scsi_fail;
+    /* was a generic device passed in as the specialized device name? */
+    if(specialized_device){ 
+      if((int)(i_st.st_rdev>>8)==SCSI_GENERIC_MAJOR){
+	char *temp=(char *)generic_device;
+	generic_device=specialized_device;
+	specialized_device=temp;
+      }
+      
+      if(!generic_device || !specialized_device){
+	if(generic_device){
+	  specialized_device=
+	    scsi_match(generic_device,scsi_cdrom_prefixes,
+		       devfs_scsi_test,devfs_scsi_cd,
+		       "\t\tNo cdrom device found to match generic device %s",
+		       messagedest,messages);
+	}else{
+	  generic_device=
+	    scsi_match(specialized_device,scsi_generic_prefixes,
+		       devfs_scsi_test,devfs_scsi_generic,
+		       "\t\tNo generic SCSI device found to match CDROM device %s",
+		       messagedest,messages);
+	  if(!generic_device)	
+	    goto cdda_identify_scsi_fail;
+	}
+      }
+    }
+    
+    idmessage(messagedest,messages,"\t\tgeneric device: %s",generic_device);
+    idmessage(messagedest,messages,"\t\tioctl device: %s",(specialized_device?
+							   specialized_device:
+							   "not found"));
+    if(specialized_device){
+      if(stat(specialized_device,&i_st)){
+	idperror(messagedest,messages,"\t\tCould not access cdrom device "
+		 "%s",specialized_device);
+	goto cdda_identify_scsi_fail;
+      }
+    }
+
+    if(stat(generic_device,&g_st)){
+      idperror(messagedest,messages,"\t\tCould not access generic SCSI device "
+	       "%s",generic_device);
+      
+      goto cdda_identify_scsi_fail;
+    }
   }
 
-  if(ioctl_device) {
-    i_fd=open(ioctl_device,O_RDONLY|O_NONBLOCK|O_EXCL);
+  if(specialized_device) {
     for(i=0; (i<10) && (i_fd==-1); i++) {
-      fprintf(stderr, "Error trying to open %s exclusively (%s). retrying in 1 second.\n", ioctl_device, strerror(errno));
+      if(use_sgio)
+	i_fd=open(specialized_device,O_RDWR|O_NONBLOCK|O_EXCL);
+      else
+	i_fd=open(specialized_device,O_RDONLY|O_NONBLOCK|O_EXCL);
+      if(i_fd!=-1)break;
+      fprintf(stderr, "Error trying to open %s exclusively (%s). retrying in 1 second.\n", specialized_device, strerror(errno));
       usleep(1000000 + 100000.0 * rand()/(RAND_MAX+1.0));
-      i_fd=open(ioctl_device,O_RDONLY|O_NONBLOCK|O_EXCL);
     }
   }
-  g_fd=open(generic_device,O_RDWR|O_EXCL);
-  for(i=0; (i<10) && (g_fd==-1); i++) {
-    fprintf(stderr, "Error trying to open %s exclusively (%s). retrying in 1 second.\n", generic_device, strerror(errno));
-    usleep(1000000 + 100000.0 * rand()/(RAND_MAX+1.0));
+
+  if(generic_device) {
     g_fd=open(generic_device,O_RDWR|O_EXCL);
+    for(i=0; (i<10) && (g_fd==-1); i++) {
+      fprintf(stderr, "Error trying to open %s exclusively (%s). retrying in 1 second.\n", generic_device, strerror(errno));
+      usleep(1000000 + 100000.0 * rand()/(RAND_MAX+1.0));
+      g_fd=open(generic_device,O_RDWR|O_EXCL);
+    }
   }
   
-  if(ioctl_device && i_fd==-1)
-    idperror(messagedest,messages,"\t\tCould not open SCSI cdrom device "
-	     "%s (continuing)",ioctl_device);
-
-  if(g_fd==-1){
+  if(specialized_device && i_fd==-1){
+    idperror(messagedest,messages,"\t\tCould not open cdrom device "
+	     "%s (continuing)",specialized_device);
+    goto cdda_identify_scsi_fail;
+  }
+  
+  if(generic_device && g_fd==-1){
     idperror(messagedest,messages,"\t\tCould not open generic SCSI device "
 	     "%s",generic_device);
     goto cdda_identify_scsi_fail;
   }
-
+    
   if(i_fd!=-1){
-    if(stat(ioctl_device,&i_st)){
-      idperror(messagedest,messages,"\t\tCould not access SCSI cdrom device "
-	       "%s",ioctl_device);
-      goto cdda_identify_scsi_fail;
-    }
-
     type=(int)(i_st.st_rdev>>8);
 
-    if(type==SCSI_CDROM_MAJOR){
-      if (!S_ISBLK(i_st.st_mode)) {
-	idmessage(messagedest,messages,"\t\tSCSI CDROM device %s not a "
-		  "block device",ioctl_device);
+    if(!use_sgio){
+      if(type==SCSI_CDROM_MAJOR){
+	if (!S_ISBLK(i_st.st_mode)) {
+	  idmessage(messagedest,messages,"\t\tSCSI CDROM device %s not a "
+		    "block device",specialized_device);
+	  goto cdda_identify_scsi_fail;
+	}
+      }else{
+	idmessage(messagedest,messages,"\t\tSCSI CDROM device %s has wrong "
+		  "major number",specialized_device);
 	goto cdda_identify_scsi_fail;
       }
-    }else{
-      idmessage(messagedest,messages,"\t\tSCSI CDROM device %s has wrong "
-		"major number",ioctl_device);
-      goto cdda_identify_scsi_fail;
     }
   }
-
-  if((int)(g_st.st_rdev>>8)==SCSI_GENERIC_MAJOR){
-    if (!S_ISCHR(g_st.st_mode)) {
-      idmessage(messagedest,messages,"\t\tGeneric SCSI device %s not a "
-		"char device",generic_device);
+  
+  if(g_fd != -1){
+    if((int)(g_st.st_rdev>>8)==SCSI_GENERIC_MAJOR){
+      if (!S_ISCHR(g_st.st_mode)) {
+	idmessage(messagedest,messages,"\t\tGeneric SCSI device %s not a "
+		  "char device",generic_device);
+	goto cdda_identify_scsi_fail;
+      }
+    }else{
+      idmessage(messagedest,messages,"\t\tGeneric SCSI device %s has wrong "
+		"major number",generic_device);
       goto cdda_identify_scsi_fail;
     }
-  }else{
-    idmessage(messagedest,messages,"\t\tGeneric SCSI device %s has wrong "
-	      "major number",generic_device);
-    goto cdda_identify_scsi_fail;
   }
-  
 
   d=calloc(1,sizeof(cdrom_drive));
-
   d->drive_type=type;
   d->cdda_fd=g_fd;
   d->ioctl_fd=i_fd;
   d->bigendianp=-1; /* We don't know yet... */
   d->nsectors=-1;
 
-  version=verify_SG_version(d,messagedest,messages);
-  switch(version){
-  case -1:case 0:case 1:
-    d->interface=GENERIC_SCSI;
-    goto cdda_identify_scsi_fail;
-  case 2:case 3:
-    d->interface=GENERIC_SCSI;
-    break;
+  if(use_sgio){
+    d->interface=SGIO_SCSI;
+    d->sg_buffer=d->sg=malloc(MAX_BIG_BUFF_SIZE);
+    g_fd=d->cdda_fd=dup(d->ioctl_fd);
+  }else{
+    version=verify_SG_version(d,messagedest,messages);
+    switch(version){
+    case -1:case 0:case 1:
+      d->interface=GENERIC_SCSI;
+      goto cdda_identify_scsi_fail;
+    case 2:case 3:
+      d->interface=GENERIC_SCSI;
+      break;
+    }
+
+    /* malloc our big buffer for scsi commands */
+    d->sg=malloc(MAX_BIG_BUFF_SIZE);
+    d->sg_buffer=d->sg+SG_OFF;
   }
 
-  /* malloc our big buffer for scsi commands */
-  d->sg=malloc(MAX_BIG_BUFF_SIZE);
-  d->sg_buffer=d->sg+SG_OFF;
-
   {
     /* get the lun */
     scsiid lun;
@@ -640,10 +720,37 @@
       d->lun=lun.lun;
   }
 
-  p = scsi_inquiry(d);
+  p = (char *)scsi_inquiry(d);
 
+  if (!p){
+
+    /* 2.6 kernels have a bug where the block layer implements
+         SG_DXFER_TO_FROM_DEVICE as a read operation instead of write.
+         I've submitted a kernel patch, but it will take a while to
+         propogate.  Work around it for now. --Monty */
+
+    if(d->interface == SGIO_SCSI){
+      /* test the inquiry with the workaround */
+      d->interface = SGIO_SCSI_BUGGY1;
+      p = (char *)scsi_inquiry(d);
+
+      if(p){
+	idmessage(messagedest,messages,
+		  "\t\tThis kernel's block layer has a buggy SG_DXFER_TO_FROM_DEVICE;\n\t\t   activating workaround.\n",NULL);
+      }else{
+	/* Failed for some reason other than the buggy ioctl(); set the interface type back */
+	d->interface = SGIO_SCSI;
+      }
+    }
+  }
+
+  if (!p){
+    idmessage(messagedest,messages,
+	      "\t\tInquiry command failed; unable to probe drive\n",NULL);
+    goto cdda_identify_scsi_fail;
+  }
+  
   /* It would seem some TOSHIBA CDROMs gets things wrong */
- 
   if (p &&
       !strncmp (p + 8, "TOSHIBA", 7) &&
       !strncmp (p + 16, "CD-ROM", 6) &&
@@ -652,18 +759,16 @@
     p[1] |= 0x80;     /* removable */
   }
 
-  if (!p || (*p != TYPE_ROM && *p != TYPE_WORM)) {
+  if (*p != TYPE_ROM && *p != TYPE_WORM) {
     idmessage(messagedest,messages,
 	      "\t\tDrive is neither a CDROM nor a WORM device\n",NULL);
-    free(d->sg);
-    free(d);
     goto cdda_identify_scsi_fail;
   }
 
   d->drive_model=calloc(36,1);
   memcpy(d->inqbytes,p,4);
   d->cdda_device_name=copystring(generic_device);
-  d->ioctl_device_name=copystring(ioctl_device);
+  d->ioctl_device_name=copystring(specialized_device);
 
   d->drive_model=calloc(36,1);
   strscat(d->drive_model,p+8,8);
@@ -676,9 +781,13 @@
   
 cdda_identify_scsi_fail:
   if(generic_device)free((char *)generic_device);
-  if(ioctl_device)free((char *)ioctl_device);
+  if(specialized_device)free((char *)specialized_device);
   if(i_fd!=-1)close(i_fd);
   if(g_fd!=-1)close(g_fd);
+  if(d){
+    if(d->sg)free(d->sg);
+    free(d);
+  }
   return(NULL);
 }
 
@@ -714,10 +823,6 @@
     fd=open(filename,O_RDONLY|O_EXCL);
   }
   
-  if(ioctl_device && i_fd==-1)
-    idperror(messagedest,messages,"\t\tCould not open SCSI cdrom device "
-	     "%s (continuing)",ioctl_device);
-  
   if(fd==-1){
     idperror(messagedest,messages,"\t\tCould not open file %s",filename);
     return(NULL);

Modified: trunk/cdparanoia/interface/scsi_interface.c
===================================================================
--- trunk/cdparanoia/interface/scsi_interface.c	2006-08-28 10:11:26 UTC (rev 11803)
+++ trunk/cdparanoia/interface/scsi_interface.c	2006-08-29 19:06:04 UTC (rev 11804)
@@ -2,7 +2,7 @@
  * CopyPolicy: GNU Public License 2 applies
  * Original interface.c Copyright (C) 1994-1997 
  *            Eissfeldt heiko at colossus.escape.de
- * Current blenderization Copyright (C) 1998-1999 Monty xiphmont at mit.edu
+ * Current blenderization Copyright (C) 1998-2006 Monty xiphmont at mit.edu
  * 
  * Generic SCSI interface specific code.
  *
@@ -18,64 +18,59 @@
 }
 
 #include "drive_exceptions.h"
-
-static void tweak_SG_buffer(cdrom_drive *d){
-  int table,reserved;
+static void tweak_SG_buffer(cdrom_drive *d) {
+  int table, reserved, cur, err;
   char buffer[256];
 
-  /* maximum transfer size? */
-  if(ioctl(d->cdda_fd,SG_GET_RESERVED_SIZE,&reserved)){
-    /* Up, guess not. */
-    cdmessage(d,"\tCould not get scatter/gather buffer size.\n");
-    return;
-  }
+  /* SG_SET_RESERVED_SIZE doesn't actually allocate or reserve anything.
+   * what it _does_ do is give you an error if you ask for a value
+   * larger than q->max_sectors (the length of the device's bio request
+   * queue).  So we walk it up from 1 sector until it fails, then get
+   * the value we set it to last.
+   */
+  /* start with 2 frames, round down to our queue's sector size */
+  cur = 1;
+  do {
+    cur <<= 1; reserved = cur * (1<<9);
+    err = ioctl(d->cdda_fd, SG_SET_RESERVED_SIZE, &reserved);
+  } while(err >= 0);
+  ioctl(d->cdda_fd, SG_GET_RESERVED_SIZE, &reserved);
 
-  if(ioctl(d->cdda_fd,SG_GET_SG_TABLESIZE,&table))table=1;
-  {
-    int cur;
+  /* this doesn't currently ever work, but someday somebody might
+     implement working sg lists with SG_IO devices, so who knows... */
+  if (ioctl(d->cdda_fd, SG_GET_SG_TABLESIZE, &table) < 0)
+    table=1;
 
-    sprintf(buffer,"\tDMA scatter/gather table entries: %d\n\t"
-	    "table entry size: %d bytes\n\t"
-	    "maximum theoretical transfer: %d sectors\n",
-	    table,reserved,table*reserved/CD_FRAMESIZE_RAW);
-    cdmessage(d,buffer);
+  sprintf(buffer,"\tDMA scatter/gather table entries: %d\n\t"
+      "table entry size: %d bytes\n\t"
+      "maximum theoretical transfer: %d sectors\n",
+      table, reserved, table*reserved/CD_FRAMESIZE_RAW);
+  cdmessage(d,buffer);
 
-    cur=table*reserved;
+  cur=table*reserved;
 
-    /* not too much; new kernels have trouble with DMA allocation, so
-       be more conservative: 32kB max until I test more thoroughly.
-       Note from RedHat: "Ee don't always get -ENOMEM.  Sometimes USB drives 
-       still fail the wrong way.  This needs some kernel-land investigation.
-    */
-
+  /* so since we never go above q->max_sectors, we should never get -EIO.
+   * we might still get -ENOMEM, but we back off for that later.  Monty
+   * had an old comment: "not too much; new kernels have trouble with DMA
+   * "allocation, so be more conservative: 32kB max until I test more 
+   * thoroughly".  We're not currently honoring that, because we should
+   * always get -ENOMEM.
+   *
+   * Updated: but we don't always get -ENOMEM.  Sometimes USB drives 
+   * still fail the wrong way.  This needs some kernel-land investigation.
+   */
+  if (!getenv("CDDA_IGNORE_BUFSIZE_LIMIT")) {
     cur=(cur>1024*32?1024*32:cur);
-    d->nsectors=cur/CD_FRAMESIZE_RAW;
-    d->bigbuff=cur;
-
-    sprintf(buffer,"\tSetting default read size to %d sectors (%d bytes).\n\n",
-	    d->nsectors,d->nsectors*CD_FRAMESIZE_RAW);
-    cdmessage(d,buffer);
-  } 
-
-  /* Disable command queue; we don't need it, no reason to have it on */
-  reserved=0;
-  if(ioctl(d->cdda_fd,SG_SET_COMMAND_Q,&reserved)){
-    cdmessage(d,"\tCouldn't disable command queue!  Continuing anyway...\n");
   }
+  d->nsectors=cur/CD_FRAMESIZE_RAW;
+  d->bigbuff=cur;
 
-}
+  sprintf(buffer,"\tSetting default read size to %d sectors (%d bytes).\n\n",
+      d->nsectors,d->nsectors*CD_FRAMESIZE_RAW);
 
-static void reset_scsi(cdrom_drive *d){
-  int arg;
-  d->enable_cdda(d,0);
+  if(cur==0) exit(1);
 
-  cdmessage(d,"sending SG SCSI reset... ");
-  if(ioctl(d->cdda_fd,SG_SCSI_RESET,&arg))
-    cdmessage(d,"FAILED: EBUSY\n");
-  else
-    cdmessage(d,"OK\n");
-  
-  d->enable_cdda(d,1);
+  cdmessage(d,buffer);
 }
 
 static void clear_garbage(cdrom_drive *d){
@@ -109,14 +104,61 @@
   }
 }
 
+static int check_sbp_error(const unsigned char *sbp) {
+  if (sbp[0]) {
+    char key = sbp[2] & 0xf;
+    char ASC = sbp[12];
+    char ASCQ = sbp[13];
+    
+    switch (key){
+    case 0:
+      if (errno==0)
+	errno = EIO;
+      return(TR_UNKNOWN);
+    case 1:
+      break;
+    case 2:
+      if (errno==0)
+	errno = EBUSY;
+      return(TR_BUSY);
+    case 3: 
+      if ((ASC==0x0C) & (ASCQ==0x09)) {
+	/* loss of streaming */
+	if (errno==0)
+	  errno = EIO;
+	return(TR_STREAMING);
+      } else {
+	if (errno==0)
+	  errno = EIO;
+	return(TR_MEDIUM);
+      }
+    case 4:
+      if (errno==0)
+	errno = EIO;
+      return(TR_FAULT);
+    case 5:
+      if (errno==0)
+	errno = EINVAL;
+      return(TR_ILLEGAL);
+    default:
+      if (errno==0)
+	errno = EIO;
+      return(TR_UNKNOWN);
+    }
+  }
+  return 0;
+}
+
 /* process a complete scsi command. */
-static int handle_scsi_cmd(cdrom_drive *d,
-			   unsigned int cmd_len, 
-			   unsigned int in_size, 
-			   unsigned int out_size,
-
-			   unsigned char bytefill,
-			   int bytecheck){
+static int sg2_handle_scsi_cmd(cdrom_drive *d,
+			       unsigned char *cmd,
+			       unsigned int cmd_len, 
+			       unsigned int in_size, 
+			       unsigned int out_size,       
+			       unsigned char bytefill,
+			       int bytecheck,
+			       unsigned char *sense_buffer){
+  
   int status = 0;
   struct sg_header *sg_hd=(struct sg_header *)d->sg;
   long writebytes=SG_OFF+cmd_len+in_size;
@@ -127,6 +169,8 @@
   clear_garbage(d);
 
   memset(sg_hd,0,sizeof(sg_hd)); 
+  memset(sense_buffer,0,SG_MAX_SENSE); 
+  memcpy(d->sg_buffer,cmd,cmd_len);
   sg_hd->twelve_byte = cmd_len == 12;
   sg_hd->result = 0;
   sg_hd->reply_len = SG_OFF + out_size;
@@ -221,6 +265,7 @@
   errno=0;
   status = read(d->cdda_fd, sg_hd, SG_OFF + out_size);
   sigprocmask ( SIG_UNBLOCK, &(d->sigset), NULL );
+  memcpy(sense_buffer,sg_hd->sense_buffer,SG_MAX_SENSE);
 
   if (status<0)return(TR_EREAD);
 
@@ -229,48 +274,124 @@
     return(TR_EREAD);
   }
 
-  if(sg_hd->sense_buffer[0]){
-    char key=sg_hd->sense_buffer[2]&0xf;
-    char ASC=sg_hd->sense_buffer[12];
-    char ASCQ=sg_hd->sense_buffer[13];
-    switch(key){
-    case 0:
-      if(errno==0)errno=EIO;
-      return(TR_UNKNOWN);
-    case 1:
-      break;
-    case 2:
-      if(errno==0)errno=EBUSY;
-      return(TR_BUSY);
-    case 3: 
-      if(ASC==0x0C && ASCQ==0x09){
-	/* loss of streaming */
-	if(errno==0)errno=EIO;
-	return(TR_STREAMING);
-      }else{
-	if(errno==0)errno=EIO;
-	return(TR_MEDIUM);
+  status = check_sbp_error(sense_buffer);
+  if(status)return status;
+
+  /* Failed/Partial DMA transfers occasionally get through.  Why?  No clue,
+     but it's been demonstrated in practice that we occasionally get
+     fewer bytes than we request with no indication anything went
+     wrong. */
+  
+  if(bytecheck && in_size+cmd_len<out_size){
+    long i,flag=0;
+    for(i=in_size;i<out_size;i++)
+      if(d->sg_buffer[i]!=bytefill){
+	flag=1;
+	break;
       }
-    case 4:
-      if(errno==0)errno=EIO;
-      return(TR_FAULT);
-    case 5:
-      if(errno==0)errno=EINVAL;
+    
+    if(!flag){
+      errno=EINVAL;
       return(TR_ILLEGAL);
-    default:
-      if(errno==0)errno=EIO;
-      return(TR_UNKNOWN);
     }
   }
 
-  /* still not foolproof; the following doesn't guarantee that we got
-     all the data, just that the command was not rejected. */
+  errno=0;
+  return(0);
+}
 
-  /* Why do this with the above sense stuff?  For some reason,
-     commands still get through.  Perhaps no data comes back even
-     though the target reports success? */
+static void print_cmd_error(cdrom_drive *d, char *direction, unsigned char *cmdp, int cmdlen) {
+  char ebuf[1024];
+  unsigned char tmp[2];
+  int x=0;
 
-  if(bytecheck && in_size+cmd_len<out_size){
+  sprintf(ebuf, "\nError %s command: ", direction);
+  cdmessage(d, ebuf);
+  tmp[1] = 0;
+  while (x < cmdlen) {
+    if (x % 8 == 0)
+      cdmessage(d, " ");
+    if (x % 16 == 0) {
+      cdmessage(d, "\n");
+      if (x+1 < cmdlen)
+        cdmessage(d, "\t");
+    }   
+    tmp[0] = cmdp[x];
+    sprintf(ebuf, "%02x ", tmp[0]);
+    cdmessage(d, ebuf);
+    x++;
+  }
+  if (!(x % 16 == 0))
+    cdmessage(d, "\n");
+}
+
+static int sgio_handle_scsi_cmd(cdrom_drive *d,
+				unsigned char *cmd,
+				unsigned int cmd_len, 
+				unsigned int in_size, 
+				unsigned int out_size,       
+				unsigned char bytefill,
+				int bytecheck,
+				unsigned char *sense){
+
+  int status = 0;
+  struct sg_io_hdr hdr;
+
+  memset(&hdr,0,sizeof(hdr));
+  memset(sense,0,sizeof(sense));
+  
+  hdr.cmdp = cmd;
+  hdr.cmd_len = cmd_len;
+  hdr.sbp = sense;
+  hdr.mx_sb_len = SG_MAX_SENSE;
+  hdr.timeout = 50000;
+  hdr.interface_id = 'S';
+  hdr.dxferp =  d->sg_buffer;
+  hdr.flags = SG_FLAG_DIRECT_IO;  /* direct IO if we can get it */
+
+  /* scary buffer fill hack */
+  if(bytecheck && out_size>in_size)
+    memset(hdr.dxferp+in_size,bytefill,out_size-in_size); 
+
+
+  if (in_size) {
+    hdr.dxfer_len = in_size;
+    hdr.dxfer_direction = SG_DXFER_TO_DEV;
+    
+    errno = 0;
+    status = ioctl(d->ioctl_fd, SG_IO, &hdr);
+    if (status >= 0 && hdr.status)
+      status = check_sbp_error(hdr.sbp);
+    if (status < 0) {
+      print_cmd_error(d, "writing", hdr.cmdp, cmd_len);
+      return TR_EWRITE;
+    }
+  }
+
+  if (!in_size | out_size) {
+    hdr.dxfer_len = out_size;
+
+    if(bytecheck && d->interface != SGIO_SCSI_BUGGY1)
+      hdr.dxfer_direction = out_size ? SG_DXFER_TO_FROM_DEV : SG_DXFER_NONE;
+    else
+      hdr.dxfer_direction = out_size ? SG_DXFER_FROM_DEV : SG_DXFER_NONE;
+
+    errno = 0;
+    status = ioctl(d->ioctl_fd, SG_IO, &hdr);
+    if (status >= 0 && hdr.status)
+      status = check_sbp_error(hdr.sbp);
+    if (status < 0) {
+      print_cmd_error(d, "reading", hdr.cmdp, cmd_len);
+      return TR_EREAD;
+    }
+  }
+
+  /* Failed/Partial DMA transfers occasionally get through.  Why?  No clue,
+     but it's been demonstrated in practice that we occasionally get
+     fewer bytes than we request with no indication anything went
+     wrong. */
+  
+  if(bytecheck && in_size<out_size){
     long i,flag=0;
     for(i=in_size;i<out_size;i++)
       if(d->sg_buffer[i]!=bytefill){
@@ -283,35 +404,86 @@
       return(TR_ILLEGAL);
     }
   }
+  
+  errno = 0;
+  return 0;
+}
 
-  errno=0;
-  return(0);
+static int handle_scsi_cmd(cdrom_drive *d,
+			   unsigned char *cmd,
+			   unsigned int cmd_len, 
+			   unsigned int in_size, 
+			   unsigned int out_size,       
+			   unsigned char bytefill,
+			   int bytecheck,
+			   unsigned char *sense){
+
+  if(d->interface == SGIO_SCSI || d->interface == SGIO_SCSI_BUGGY1)
+    return sgio_handle_scsi_cmd(d,cmd,cmd_len,in_size,out_size,bytefill,bytecheck,sense);
+  return sg2_handle_scsi_cmd(d,cmd,cmd_len,in_size,out_size,bytefill,bytecheck,sense);
+
 }
 
-/* Group 1 (10b) command */
+static int test_unit_ready(cdrom_drive *d){
+  unsigned char sense[SG_MAX_SENSE];
+  unsigned char key, ASC, ASCQ;
+  unsigned char cmd[6] =  { 0x00, /* TEST_UNIT_READY */	
+			    0, /* reserved */
+			    0, /* reserved */
+			    0, /* reserved */
+			    0, /* reserved */
+			    0};/* control */		
 
+  handle_scsi_cmd(d, cmd, 6, 0, 56, 0,0, sense);
+
+  key = d->sg_buffer[2] & 0xf;
+  ASC = d->sg_buffer[12];
+  ASCQ = d->sg_buffer[13];
+  
+  if(key == 2 && ASC == 4 && ASCQ == 1) return 0;
+  return 1;
+}
+
+static void reset_scsi(cdrom_drive *d){
+  int arg,tries=0;
+  d->enable_cdda(d,0);
+
+  cdmessage(d,"sending SG SCSI reset... ");
+  if(ioctl(d->cdda_fd,SG_SCSI_RESET,&arg))
+    cdmessage(d,"FAILED: EBUSY\n");
+  else
+    cdmessage(d,"OK\n");
+
+  while(1) {
+    if(test_unit_ready(d))break;
+    tries++;
+    usleep(10);
+  }
+  
+  d->enable_cdda(d,1);
+}
+
 static int mode_sense_atapi(cdrom_drive *d,int size,int page){ 
-  memcpy(d->sg_buffer,  
-	 (char [])  {0x5A,   /* MODE_SENSE */
-		       0x00, /* reserved */
-		       0x00, /* page */
-		       0,    /* reserved */
-		       0,    /* reserved */
-		       0,    /* reserved */
-		       0,    /* reserved */
-		       0,    /* MSB (0) */
-		       0,    /* sizeof(modesense - SG_OFF) */
-		       0},   /* reserved */ 
-         10);
+  unsigned char sense[SG_MAX_SENSE];
+  unsigned char cmd[10]= {0x5A,   /* MODE_SENSE */
+			  0x00, /* reserved */
+			  0x00, /* page */
+			  0,    /* reserved */
+			  0,    /* reserved */
+			  0,    /* reserved */
+			  0,    /* reserved */
+			  0,    /* MSB (0) */
+			  0,    /* sizeof(modesense - SG_OFF) */
+			  0};   /* reserved */ 
 
-  d->sg_buffer[1]=d->lun<<5;
-  d->sg_buffer[2]=0x3F&page;
-  d->sg_buffer[8]=size+4;
+  cmd[1]=d->lun<<5;
+  cmd[2]=0x3F&page;
+  cmd[8]=size+4;
 
-  if (handle_scsi_cmd (d, 10, 0, size+4,'\377',1)) return(1);
+  if (handle_scsi_cmd (d, cmd, 10, 0, size+4,'\377',1,sense)) return(1);
 
   {
-    char *b=d->sg_buffer;
+    unsigned char *b=d->sg_buffer;
     if(b[0])return(1); /* Handles only up to 256 bytes */
     if(b[6])return(1); /* Handles only up to 256 bytes */
 
@@ -328,20 +500,19 @@
 /* group 0 (6b) command */
 
 static int mode_sense_scsi(cdrom_drive *d,int size,int page){  
-  memcpy(d->sg_buffer,  
-	 (char [])  {0x1A,   /* MODE_SENSE */
-		       0x00, /* return block descriptor/lun */
-		       0x00, /* page */
-		       0,    /* reserved */
-		       0,   /* sizeof(modesense - SG_OFF) */
-		       0},   /* control */ 
-         6);
+  unsigned char sense[SG_MAX_SENSE];
+  unsigned char cmd[6]={0x1A, /* MODE_SENSE */
+			0x00, /* return block descriptor/lun */
+			0x00, /* page */
+			0,    /* reserved */
+			0,    /* sizeof(modesense - SG_OFF) */
+			0};   /* control */ 
   
-  d->sg_buffer[1]=d->lun<<5;
-  d->sg_buffer[2]=(0x3F&page);
-  d->sg_buffer[4]=size;
-
-  if (handle_scsi_cmd (d, 6, 0, size, '\377',1)) return(1);
+  cmd[1]=d->lun<<5;
+  cmd[2]=(0x3F&page);
+  cmd[4]=size;
+  
+  if (handle_scsi_cmd (d, cmd, 6, 0, size, '\377',1, sense)) return(1);
   return(0);
 }
 
@@ -351,71 +522,71 @@
   return(mode_sense_scsi(d,size,page));
 }
 
+/* Current SG/SGIO impleemntations specifically disallow mode set
+   unless running as root (or setuid).  One can see why (could be
+   disastrous on, eg, a SCSI disk), but it curtails what we can do
+   with older SCSI cdroms. */
 static int mode_select(cdrom_drive *d,int density,int secsize){
   /* short circut the way Heiko does it; less flexible, but shorter */
+  unsigned char sense[SG_MAX_SENSE];
   if(d->is_atapi){
-    unsigned char *mode = d->sg_buffer + 18;
-
-    memcpy(d->sg_buffer,
-	   (char []) { 0x55, /* MODE_SELECT */
-			 0x10, /* no save page */
-			 0, /* reserved */
-			 0, /* reserved */
-			 0, /* reserved */
-			 0, /* reserved */
-			 0, /* reserved */
-			 0, /* reserved */
-			 12, /* sizeof(mode) */
-			 0, /* reserved */
-
-			 /* mode parameter header */
-			 0, 0, 0, 0,  0, 0, 0, 
-			 8, /* Block Descriptor Length */
-
-			 /* descriptor block */
-			 0,       /* Density Code */
-			 0, 0, 0, /* # of Blocks */
-			 0,       /* reserved */
-			 0, 0, 0},/* Blocklen */
-	   26);
-
-    d->sg_buffer[1]|=d->lun<<5;
-
+    unsigned char cmd[26] = { 0x55, /* MODE_SELECT */
+			      0x10, /* no save page */
+			      0,    /* reserved */
+			      0,    /* reserved */
+			      0,    /* reserved */
+			      0,    /* reserved */
+			      0,    /* reserved */
+			      0,    /* reserved */
+			      12,   /* sizeof(mode) */
+			      0,    /* reserved */
+			      
+			      /* mode parameter header */
+			      0, 0, 0, 0,  0, 0, 0, 
+			      8, /* Block Descriptor Length */
+			      
+			      /* descriptor block */
+			      0,       /* Density Code */
+			      0, 0, 0, /* # of Blocks */
+			      0,       /* reserved */
+			      0, 0, 0};/* Blocklen */
+    unsigned char *mode = cmd + 18;
+    
+    
+    cmd[1]|=d->lun<<5;
+    
     /* prepare to read cds in the previous mode */
     mode [0] = density;
-    mode [6] =  secsize >> 8;   /* block length "msb" */
-    mode [7] =  secsize & 0xFF; /* block length lsb */
+    mode [6] = secsize >> 8;   /* block length "msb" */
+    mode [7] = secsize & 0xFF; /* block length lsb */
 
     /* do the scsi cmd */
-    return(handle_scsi_cmd (d,10, 16, 0,0,0));
+    return(handle_scsi_cmd (d,cmd,10, 16, 0,0,0,sense));
 
   }else{
-    unsigned char *mode = d->sg_buffer + 10;
+    unsigned char cmd[18] = { 0x15, /* MODE_SELECT */
+			      0x10, /* no save page */
+			      0, /* reserved */
+			      0, /* reserved */
+			      12, /* sizeof(mode) */
+			      0, /* reserved */
+			      /* mode section */
+			      0, 
+			      0, 0, 
+			      8,       /* Block Descriptor Length */
+			      0,       /* Density Code */
+			      0, 0, 0, /* # of Blocks */
+			      0,       /* reserved */
+			      0, 0, 0};/* Blocklen */
+    unsigned char *mode = cmd + 10;
 
-    memcpy(d->sg_buffer,
-	   (char []) { 0x15, /* MODE_SELECT */
-			 0x10, /* no save page */
-			 0, /* reserved */
-			 0, /* reserved */
-			 12, /* sizeof(mode) */
-			 0, /* reserved */
-			 /* mode section */
-			 0, 
-			 0, 0, 
-			 8,       /* Block Descriptor Length */
-			 0,       /* Density Code */
-			 0, 0, 0, /* # of Blocks */
-			 0,       /* reserved */
-			 0, 0, 0},/* Blocklen */
-	   18);
-
     /* prepare to read cds in the previous mode */
     mode [0] = density;
     mode [6] =  secsize >> 8;   /* block length "msb" */
     mode [7] =  secsize & 0xFF; /* block length lsb */
 
     /* do the scsi cmd */
-    return(handle_scsi_cmd (d,6, 12, 0,0,0));
+    return(handle_scsi_cmd (d,cmd,6, 12, 0,0,0,sense));
   }
 }
 
@@ -474,10 +645,11 @@
      len lsb, flags */
 
   /* read the header first */
-  memcpy(d->sg_buffer, (char []){ 0x43, 0, 0, 0, 0, 0, 1, 0, 12, 0}, 10);
-  d->sg_buffer[1]=d->lun<<5;
+  unsigned char sense[SG_MAX_SENSE];
+  unsigned char cmd[10] = { 0x43, 0, 0, 0, 0, 0, 1, 0, 12, 0};
+  cmd[1]=d->lun<<5;
 
-  if (handle_scsi_cmd (d,10, 0, 12,'\377',1)){
+  if (handle_scsi_cmd (d,cmd,10, 0, 12,'\377',1,sense)){
     cderror(d,"004: Unable to read table of contents header\n");
     return(-4);
   }
@@ -492,11 +664,11 @@
   }
 
   for (i = first; i <= last; i++){
-    memcpy(d->sg_buffer, (char []){ 0x43, 0, 0, 0, 0, 0, 0, 0, 12, 0}, 10);
-    d->sg_buffer[1]=d->lun<<5;
-    d->sg_buffer[6]=i;
+    memcpy(cmd, (char []){ 0x43, 0, 0, 0, 0, 0, 0, 0, 12, 0}, 10);
+    cmd[1]=d->lun<<5;
+    cmd[6]=i;
     
-    if (handle_scsi_cmd (d,10, 0, 12,'\377',1)){
+    if (handle_scsi_cmd (d,cmd, 10, 0, 12,'\377',1,sense)){
       cderror(d,"005: Unable to read table of contents entry\n");
       return(-5);
     }
@@ -513,11 +685,11 @@
     }
   }
 
-  memcpy(d->sg_buffer, (char []){ 0x43, 0, 0, 0, 0, 0, 0, 0, 12, 0}, 10);
-  d->sg_buffer[1]=d->lun<<5;
-  d->sg_buffer[6]=0xAA;
+  memcpy(cmd, (char []){ 0x43, 0, 0, 0, 0, 0, 0, 0, 12, 0}, 10);
+  cmd[1]=d->lun<<5;
+  cmd[6]=0xAA;
     
-  if (handle_scsi_cmd (d,10, 0, 12,'\377',1)){
+  if (handle_scsi_cmd (d,cmd,10, 0, 12,'\377',1,sense)){
     cderror(d,"002: Unable to read table of contents lead-out\n");
     return(-2);
   }
@@ -545,11 +717,12 @@
   int i;
   unsigned tracks;
 
-  memcpy(d->sg_buffer, (char[]){ 0xe5, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 10);
-  d->sg_buffer[5]=1;
-  d->sg_buffer[8]=255;
+  unsigned char cmd[10] = { 0xe5, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  unsigned char sense[SG_MAX_SENSE];
+  cmd[5]=1;
+  cmd[8]=255;
 
-  if (handle_scsi_cmd (d,10, 0, 256,'\377',1)){
+  if (handle_scsi_cmd (d,cmd,10, 0, 256,'\377',1,sense)){
     cderror(d,"004: Unable to read table of contents header\n");
     return(-4);
   }
@@ -562,11 +735,11 @@
   }
 
   for (i = 0; i < tracks; i++){
-    memcpy(d->sg_buffer, (char[]){ 0xe5, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 10);
-    d->sg_buffer[5]=i+1;
-    d->sg_buffer[8]=255;
+    memcpy(cmd, (char[]){ 0xe5, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 10);
+    cmd[5]=i+1;
+    cmd[8]=255;
     
-    if (handle_scsi_cmd (d,10, 0, 256,'\377',1)){
+    if (handle_scsi_cmd (d,cmd,10, 0, 256,'\377',1,sense)){
       cderror(d,"005: Unable to read table of contents entry\n");
       return(-5);
     }
@@ -606,158 +779,153 @@
 
 /* These do one 'extra' copy in the name of clean code */
 
-static int i_read_28 (cdrom_drive *d, void *p, long begin, long sectors){
+static int i_read_28 (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
   int ret;
-  memcpy(d->sg_buffer,(char []){0x28, 0, 0, 0, 0, 0, 0, 0, 0, 0},10);
+  unsigned char cmd[10]={0x28, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 
   if(d->fua)
-    d->sg_buffer[1]=0x08;
+    cmd[1]=0x08;
 
-  d->sg_buffer[1]|=d->lun<<5;
+  cmd[1]|=d->lun<<5;
 
-  d->sg_buffer[3] = (begin >> 16) & 0xFF;
-  d->sg_buffer[4] = (begin >> 8) & 0xFF;
-  d->sg_buffer[5] = begin & 0xFF;
-  d->sg_buffer[8] = sectors;
-  if((ret=handle_scsi_cmd(d,10,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
+  cmd[3] = (begin >> 16) & 0xFF;
+  cmd[4] = (begin >> 8) & 0xFF;
+  cmd[5] = begin & 0xFF;
+  cmd[8] = sectors;
+  if((ret=handle_scsi_cmd(d,cmd,10,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
     return(ret);
   if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
   return(0);
 }
 
-static int i_read_A8 (cdrom_drive *d, void *p, long begin, long sectors){
+static int i_read_A8 (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
   int ret;
-  memcpy(d->sg_buffer,(char []){0xA8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},12);
-
+  unsigned char cmd[12]={0xA8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  
   if(d->fua)
-    d->sg_buffer[1]=0x08;
+    cmd[1]=0x08;
+  
+  cmd[1]|=d->lun<<5;
 
-  d->sg_buffer[1]|=d->lun<<5;
-
-  d->sg_buffer[3] = (begin >> 16) & 0xFF;
-  d->sg_buffer[4] = (begin >> 8) & 0xFF;
-  d->sg_buffer[5] = begin & 0xFF;
-  d->sg_buffer[9] = sectors;
-  if((ret=handle_scsi_cmd(d,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
+  cmd[3] = (begin >> 16) & 0xFF;
+  cmd[4] = (begin >> 8) & 0xFF;
+  cmd[5] = begin & 0xFF;
+  cmd[9] = sectors;
+  if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
     return(ret);
   if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
   return(0);
 }
 
-static int i_read_D4_10 (cdrom_drive *d, void *p, long begin, long sectors){
+static int i_read_D4_10 (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
   int ret;
-  memcpy(d->sg_buffer,(char []){0xd4, 0, 0, 0, 0, 0, 0, 0, 0, 0},10);
-
+  unsigned char cmd[10]={0xd4, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  
   if(d->fua)
-    d->sg_buffer[1]=0x08;
+    cmd[1]=0x08;
 
-  d->sg_buffer[1]|=d->lun<<5;
-  d->sg_buffer[3] = (begin >> 16) & 0xFF;
-  d->sg_buffer[4] = (begin >> 8) & 0xFF;
-  d->sg_buffer[5] = begin & 0xFF;
-  d->sg_buffer[8] = sectors;
-  if((ret=handle_scsi_cmd(d,10,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
+  cmd[1]|=d->lun<<5;
+  cmd[3] = (begin >> 16) & 0xFF;
+  cmd[4] = (begin >> 8) & 0xFF;
+  cmd[5] = begin & 0xFF;
+  cmd[8] = sectors;
+  if((ret=handle_scsi_cmd(d,cmd,10,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
     return(ret);
   if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
   return(0);
 }
 
-static int i_read_D4_12 (cdrom_drive *d, void *p, long begin, long sectors){
+static int i_read_D4_12 (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
   int ret;
-  memcpy(d->sg_buffer,(char []){0xd4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},12);
+  unsigned char cmd[12]={0xd4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 
   if(d->fua)
-    d->sg_buffer[1]=0x08;
+    cmd[1]=0x08;
 
-  d->sg_buffer[1]|=d->lun<<5;
-  d->sg_buffer[3] = (begin >> 16) & 0xFF;
-  d->sg_buffer[4] = (begin >> 8) & 0xFF;
-  d->sg_buffer[5] = begin & 0xFF;
-  d->sg_buffer[9] = sectors;
-  if((ret=handle_scsi_cmd(d,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
+  cmd[1]|=d->lun<<5;
+  cmd[3] = (begin >> 16) & 0xFF;
+  cmd[4] = (begin >> 8) & 0xFF;
+  cmd[5] = begin & 0xFF;
+  cmd[9] = sectors;
+  if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
     return(ret);
   if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
   return(0);
 }
 
-static int i_read_D5 (cdrom_drive *d, void *p, long begin, long sectors){
+static int i_read_D5 (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
   int ret;
-  memcpy(d->sg_buffer,(char []){0xd5, 0, 0, 0, 0, 0, 0, 0, 0, 0},10);
+  unsigned char cmd[10]={0xd5, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 
   if(d->fua)
-    d->sg_buffer[1]=0x08;
+    cmd[1]=0x08;
 
-  d->sg_buffer[1]|=d->lun<<5;
-  d->sg_buffer[3] = (begin >> 16) & 0xFF;
-  d->sg_buffer[4] = (begin >> 8) & 0xFF;
-  d->sg_buffer[5] = begin & 0xFF;
-  d->sg_buffer[8] = sectors;
-  if((ret=handle_scsi_cmd(d,10,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
+  cmd[1]|=d->lun<<5;
+  cmd[3] = (begin >> 16) & 0xFF;
+  cmd[4] = (begin >> 8) & 0xFF;
+  cmd[5] = begin & 0xFF;
+  cmd[8] = sectors;
+  if((ret=handle_scsi_cmd(d,cmd,10,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
     return(ret);
   if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
   return(0);
 }
 
-static int i_read_D8 (cdrom_drive *d, void *p, long begin, long sectors){
+static int i_read_D8 (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
   int ret;
-  memcpy(d->sg_buffer,(char []){0xd8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},12);
+  unsigned char cmd[12]={0xd8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 
   if(d->fua)
-    d->sg_buffer[1]=0x08;
+    cmd[1]=0x08;
 
-  d->sg_buffer[1]|=d->lun<<5;
-  d->sg_buffer[3] = (begin >> 16) & 0xFF;
-  d->sg_buffer[4] = (begin >> 8) & 0xFF;
-  d->sg_buffer[5] = begin & 0xFF;
-  d->sg_buffer[9] = sectors;
-  if((ret=handle_scsi_cmd(d,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
+  cmd[1]|=d->lun<<5;
+  cmd[3] = (begin >> 16) & 0xFF;
+  cmd[4] = (begin >> 8) & 0xFF;
+  cmd[5] = begin & 0xFF;
+  cmd[9] = sectors;
+  if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
     return(ret);
   if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
   return(0);
 }
 
-static int i_read_mmc (cdrom_drive *d, void *p, long begin, long sectors){
+static int i_read_mmc (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
   int ret;
-  /*  if(begin<=12007 && begin+sectors>12000){
-    errno=EIO;
-    return(TR_ILLEGAL);
-  }*/
+  unsigned char cmd[12]={0xbe, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0};
 
-  memcpy(d->sg_buffer,(char []){0xbe, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0},12);
-
-  d->sg_buffer[3] = (begin >> 16) & 0xFF;
-  d->sg_buffer[4] = (begin >> 8) & 0xFF;
-  d->sg_buffer[5] = begin & 0xFF;
-  d->sg_buffer[8] = sectors;
-  if((ret=handle_scsi_cmd(d,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
+  cmd[3] = (begin >> 16) & 0xFF;
+  cmd[4] = (begin >> 8) & 0xFF;
+  cmd[5] = begin & 0xFF;
+  cmd[8] = sectors;
+  if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
     return(ret);
   if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
   return(0);
 }
 
-static int i_read_mmc2 (cdrom_drive *d, void *p, long begin, long sectors){
+static int i_read_mmc2 (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
   int ret;
-  memcpy(d->sg_buffer,(char []){0xbe, 0, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0},12);
+  unsigned char cmd[12]={0xbe, 0, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0};
 
-  d->sg_buffer[3] = (begin >> 16) & 0xFF;
-  d->sg_buffer[4] = (begin >> 8) & 0xFF;
-  d->sg_buffer[5] = begin & 0xFF;
-  d->sg_buffer[8] = sectors;
-  if((ret=handle_scsi_cmd(d,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
+  cmd[3] = (begin >> 16) & 0xFF;
+  cmd[4] = (begin >> 8) & 0xFF;
+  cmd[5] = begin & 0xFF;
+  cmd[8] = sectors;
+  if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
     return(ret);
   if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
   return(0);
 }
 
-static int i_read_mmc3 (cdrom_drive *d, void *p, long begin, long sectors){
+static int i_read_mmc3 (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
   int ret;
-  memcpy(d->sg_buffer,(char []){0xbe, 4, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0},12);
+  unsigned char cmd[12]={0xbe, 4, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0};
 
-  d->sg_buffer[3] = (begin >> 16) & 0xFF;
-  d->sg_buffer[4] = (begin >> 8) & 0xFF;
-  d->sg_buffer[5] = begin & 0xFF;
-  d->sg_buffer[8] = sectors;
-  if((ret=handle_scsi_cmd(d,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
+  cmd[3] = (begin >> 16) & 0xFF;
+  cmd[4] = (begin >> 8) & 0xFF;
+  cmd[5] = begin & 0xFF;
+  cmd[8] = sectors;
+  if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
     return(ret);
   if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
   return(0);
@@ -784,47 +952,50 @@
 }
 
 
-static int i_read_msf (cdrom_drive *d, void *p, long begin, long sectors){
+static int i_read_msf (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
   int ret;
-  memcpy(d->sg_buffer,(char []){0xb9, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0},12);
+  unsigned char cmd[12]={0xb9, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0};
 
-  LBA_to_MSF(begin,d->sg_buffer+3,d->sg_buffer+4,d->sg_buffer+5);
-  LBA_to_MSF(begin+sectors,d->sg_buffer+6,d->sg_buffer+7,d->sg_buffer+8);
+  LBA_to_MSF(begin,cmd+3,cmd+4,cmd+5);
+  LBA_to_MSF(begin+sectors,cmd+6,cmd+7,cmd+8);
 
-  if((ret=handle_scsi_cmd(d,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
+  if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
     return(ret);
   if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
   return(0);
 }
 
-static int i_read_msf2 (cdrom_drive *d, void *p, long begin, long sectors){
+static int i_read_msf2 (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
   int ret;
-  memcpy(d->sg_buffer,(char []){0xb9, 0, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0},12);
+  unsigned char cmd[12]={0xb9, 0, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0};
 
-  LBA_to_MSF(begin,d->sg_buffer+3,d->sg_buffer+4,d->sg_buffer+5);
-  LBA_to_MSF(begin+sectors,d->sg_buffer+6,d->sg_buffer+7,d->sg_buffer+8);
+  LBA_to_MSF(begin,cmd+3,cmd+4,cmd+5);
+  LBA_to_MSF(begin+sectors,cmd+6,cmd+7,cmd+8);
 
-  if((ret=handle_scsi_cmd(d,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
+  if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
     return(ret);
   if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
   return(0);
 }
 
-static int i_read_msf3 (cdrom_drive *d, void *p, long begin, long sectors){
+static int i_read_msf3 (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
   int ret;
-  memcpy(d->sg_buffer,(char []){0xb9, 4, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0},12);
-
-  LBA_to_MSF(begin,d->sg_buffer+3,d->sg_buffer+4,d->sg_buffer+5);
-  LBA_to_MSF(begin+sectors,d->sg_buffer+6,d->sg_buffer+7,d->sg_buffer+8);
-
-  if((ret=handle_scsi_cmd(d,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
+  unsigned char cmd[12]={0xb9, 4, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0};
+  
+  LBA_to_MSF(begin,cmd+3,cmd+4,cmd+5);
+  LBA_to_MSF(begin+sectors,cmd+6,cmd+7,cmd+8);
+  
+  if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
     return(ret);
   if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
   return(0);
 }
 
+
 static long scsi_read_map (cdrom_drive *d, void *p, long begin, long sectors,
-			  int (*map)(cdrom_drive *, void *, long, long)){
+			   int (*map)(cdrom_drive *, void *, long, long, 
+				      unsigned char *)){
+  unsigned char sense[SG_MAX_SENSE];
   int retry_count,err;
   char *buffer=(char *)p;
 
@@ -835,18 +1006,17 @@
   retry_count=0;
   
   while(1) {
-    if((err=map(d,(p?buffer:NULL),begin,sectors))){
+    if((err=map(d,(p?buffer:NULL),begin,sectors,sense))){
       if(d->report_all){
-	struct sg_header *sg_hd=(struct sg_header *)d->sg;
 	char b[256];
 
 	sprintf(b,"scsi_read error: sector=%ld length=%ld retry=%d\n",
 		begin,sectors,retry_count);
 	cdmessage(d,b);
 	sprintf(b,"                 Sense key: %x ASC: %x ASCQ: %x\n",
-		(int)(sg_hd->sense_buffer[2]&0xf),
-		(int)(sg_hd->sense_buffer[12]),
-		(int)(sg_hd->sense_buffer[13]));
+		(int)(sense[2]&0xf),
+		(int)(sense[12]),
+		(int)(sense[13]));
 	cdmessage(d,b);
 	sprintf(b,"                 Transport error: %s\n",strerror_tr[err]);
 	cdmessage(d,b);
@@ -856,9 +1026,9 @@
 	fprintf(stderr,"scsi_read error: sector=%ld length=%ld retry=%d\n",
 		begin,sectors,retry_count);
 	fprintf(stderr,"                 Sense key: %x ASC: %x ASCQ: %x\n",
-		(int)(sg_hd->sense_buffer[2]&0xf),
-		(int)(sg_hd->sense_buffer[12]),
-		(int)(sg_hd->sense_buffer[13]));
+		(int)(sense[2]&0xf),
+		(int)(sense[12]),
+		(int)(sense[13]));
 	fprintf(stderr,"                 Transport error: %s\n",strerror_tr[err]);
 	fprintf(stderr,"                 System error: %s\n",strerror(errno));
       }
@@ -1313,8 +1483,7 @@
 
 static int check_atapi(cdrom_drive *d){
   int atapiret=-1;
-  int fd = d->cdda_fd; /* this is the correct fd (not ioctl_fd), as the 
-			  generic device is the device we need to check */
+  int fd = d->cdda_fd; /* check the device we'll actually be using to read */
 			  
   cdmessage(d,"\nChecking for SCSI emulation...\n");
 
@@ -1323,10 +1492,16 @@
     return(-1);
   } else {
     if(atapiret==1){
-      cdmessage(d,"\tDrive is ATAPI (using SCSI host adaptor emulation)\n");
-      /* Disable kernel SCSI command translation layer for access through sg */
-      if (ioctl(fd,SG_SET_TRANSFORM,0))
-	cderror(d,"\tCouldn't disable kernel command translation layer\n");
+      if(d->interface == SGIO_SCSI){
+	cdmessage(d,"\tDrive is ATAPI (using SG_IO host adaptor emulation)\n");
+      }else if(d->interface == SGIO_SCSI_BUGGY1){
+	cdmessage(d,"\tDrive is ATAPI (using SG_IO host adaptor emulation with workarounds)\n");
+      }else{
+	cdmessage(d,"\tDrive is ATAPI (using SCSI host adaptor emulation)\n");
+	/* Disable kernel SCSI command translation layer for access through sg */
+	if (ioctl(fd,SG_SET_TRANSFORM,0))
+	  cderror(d,"\tCouldn't disable kernel command translation layer\n");
+      }
       d->is_atapi=1;
     }else{
       cdmessage(d,"\tDrive is SCSI\n");
@@ -1338,7 +1513,7 @@
 }  
 
 static int check_mmc(cdrom_drive *d){
-  char *b;
+  unsigned char *b;
   cdmessage(d,"\nChecking for MMC style command set...\n");
 
   d->is_mmc=0;
@@ -1385,9 +1560,10 @@
 
 /* request vendor brand and model */
 unsigned char *scsi_inquiry(cdrom_drive *d){
-  memcpy(d->sg_buffer,(char[]){ 0x12,0,0,0,56,0},6);
-
-  if(handle_scsi_cmd(d,6, 0, 56,'\377',1)) {
+  unsigned char sense[SG_MAX_SENSE];
+  unsigned char cmd[6]={ 0x12,0,0,0,56,0 };
+  
+  if(handle_scsi_cmd(d,cmd,6, 0, 56,'\377',1,sense)) {
     cderror(d,"008: Unable to identify CDROM model\n");
     return(NULL);
   }

Modified: trunk/cdparanoia/main.c
===================================================================
--- trunk/cdparanoia/main.c	2006-08-28 10:11:26 UTC (rev 11803)
+++ trunk/cdparanoia/main.c	2006-08-29 19:06:04 UTC (rev 11804)
@@ -15,7 +15,7 @@
  *   along with this program; if not, write to the Free Software
  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * cdparanoia (C) 1998 Monty <xiphmont at mit.edu>
+ * cdparanoia (C) 2006 Monty <monty at xiph.org>
  *
  * last changes:
  *   22.01.98 - first version
@@ -341,7 +341,7 @@
 "  C) extract from track 1, time 0:30.12 to 1:10.00:\n"
 "       cdparanoia \"1[:30.12]-1[1:10]\"\n\n"
 
-"Submit bug reports to xiphmont at mit.edu\n\n");
+"Submit bug reports to paranoia at xiph.org\n\n");
 }
 
 long callbegin;

Modified: trunk/cdparanoia/paranoia/Makefile.in
===================================================================
--- trunk/cdparanoia/paranoia/Makefile.in	2006-08-28 10:11:26 UTC (rev 11803)
+++ trunk/cdparanoia/paranoia/Makefile.in	2006-08-29 19:06:04 UTC (rev 11804)
@@ -10,7 +10,7 @@
 @SET_MAKE@
 FLAGS=@TYPESIZES@ @CFLAGS@
 OPT=@OPT@ $(FLAGS)
-DEBUG=@DEBUG@ $(FLAGS)
+DEBUG=@DEBUG@ 
 CC=@CC@
 LD=@CC@
 LDFLAGS=@LDFLAGS@ $(FLAGS)

Modified: trunk/cdparanoia/version.h
===================================================================
--- trunk/cdparanoia/version.h	2006-08-28 10:11:26 UTC (rev 11803)
+++ trunk/cdparanoia/version.h	2006-08-29 19:06:04 UTC (rev 11804)
@@ -1,13 +1,13 @@
 /******************************************************************
  * CopyPolicy: GNU Public License 2 applies
  * 
- * cdda_paranoia generation III release 9.8
- * Copyright (C) 2001 Monty monty at xiph.org, xiphmont at mit.edu
+ * cdda_paranoia generation III release 10.0
+ * Copyright (C) 2006 Monty monty at xiph.org
  *
  ******************************************************************/
 
 
-#define VERSION "cdparanoia III release 9.8 (March 23, 2001)\n"\
-                "(C) 2001 Monty <monty at xiph.org> and Xiphophorus\n\n"\
+#define VERSION "cdparanoia III release 10.0 (August 21, 2006)\n"\
+                "(C) 2006 Monty <monty at xiph.org> and Xiph.Org\n\n"\
 		"Report bugs to paranoia at xiph.org\n"\
 		"http://www.xiph.org/paranoia/\n"



More information about the commits mailing list