Репозиторий Sisyphus
Последнее обновление: 1 октября 2023 | Пакетов: 18631 | Посещений: 37515469
en ru br
Репозитории ALT
S:10.2-alt6
5.1: 10.2-alt1
4.1: IIIa9.8-alt4
4.0: IIIa9.8-alt4
3.0: IIIa9.8-alt3
www.altlinux.org/Changes

Группа :: Звук
Пакет: cdparanoia

 Главная   Изменения   Спек   Патчи   Sources   Загрузить   Gear   Bugs and FR  Repocop 

Патч: cdparanoia-III-alpha9.8.sgio.patch
Скачать


diff --exclude CVS -u -N -r cdparanoia-III-alpha9.8/interface/cdda_interface.h paranoia-III/interface/cdda_interface.h
--- cdparanoia-III-alpha9.8/interface/cdda_interface.h	2004-02-21 13:16:47.000000000 -0500
+++ cdparanoia-III-alpha9.8/interface/cdda_interface.h	2004-02-25 21:42:15.000000000 -0500
@@ -99,10 +99,46 @@
 
 } cdrom_drive;
 
+/* buffers for use with the scsi code.  d->sg_buffer is unused,
+   and d->sg points to this struct.  We can't really change struct
+   cdrom_drive without breaking binary compatibility, so we do this
+   instead. */
+struct sg_info {
+#ifdef SG_IO
+  struct sg_io_hdr *hdr;
+#else
+  struct sg_header *hdr;
+#endif
+
+  char *cmdp;
+  ssize_t cmd_len;
+  ssize_t cmdp_buffer_len;
+  
+  char *dxferp;
+  ssize_t dxferp_buffer_len;
+  ssize_t dxferp_max_buffer_len;
+
+  unsigned char bytefill;
+  int bytecheck;
+
+  int in_size;
+  int out_size;
+
+  int (*handle_scsi_cmd)(struct cdrom_drive *d);
+  void (*setup_scsi_cmd)(struct cdrom_drive *d,
+    char *cmdp, unsigned int cmd_len,
+    unsigned int in_size, unsigned int out_size);
+};
+
+
 #define IS_AUDIO(d,i) (!(d->disc_toc[i].bFlags & 0x04))
 
 /******** Identification/autosense functions */
 
+#ifdef SG_IO
+extern int check_fd_sgio(int fd);
+#endif
+
 extern cdrom_drive *cdda_find_a_cdrom(int messagedest, char **message);
 extern cdrom_drive *cdda_identify(const char *device, int messagedest,
 				  char **message);
diff --exclude CVS -u -N -r cdparanoia-III-alpha9.8/interface/interface.c paranoia-III/interface/interface.c
--- cdparanoia-III-alpha9.8/interface/interface.c	2004-02-21 13:16:49.000000000 -0500
+++ cdparanoia-III-alpha9.8/interface/interface.c	2004-02-25 11:17:37.000000000 -0500
@@ -30,7 +30,7 @@
 
     _clean_messages(d);
     if(d->cdda_device_name)free(d->cdda_device_name);
-    if(d->ioctl_device_name)free(d->ioctl_device_name);
+    if(d->ioctl_device_name && d->ioctl_device_name!=d->cdda_device_name)free(d->ioctl_device_name);
     if(d->drive_model)free(d->drive_model);
     if(d->cdda_fd!=-1)close(d->cdda_fd);
     if(d->ioctl_fd!=-1 && d->ioctl_fd!=d->cdda_fd)close(d->ioctl_fd);
diff --exclude CVS -u -N -r cdparanoia-III-alpha9.8/interface/scan_devices.c paranoia-III/interface/scan_devices.c
--- cdparanoia-III-alpha9.8/interface/scan_devices.c	2004-02-21 13:16:51.000000000 -0500
+++ cdparanoia-III-alpha9.8/interface/scan_devices.c	2004-02-26 19:26:15.000000000 -0500
@@ -14,8 +14,8 @@
 #include <pwd.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include "cdda_interface.h"
 #include "low_interface.h"
+#include "cdda_interface.h"
 #include "common_interface.h"
 #include "utils.h"
 
@@ -50,6 +50,8 @@
   "/dev/gscd",
   "/dev/optcd",NULL};
 
+extern void sg2_init_sg_info(cdrom_drive *d);
+extern void sgio_init_sg_info(cdrom_drive *d);
 /* Functions here look for a cdrom drive; full init of a drive type
    happens in interface.c */
 
@@ -117,8 +119,13 @@
   }
 #endif
 
-  d=cdda_identify_cooked(device,messagedest,messages);
+#ifdef SG_IO
+  d=cdda_identify_scsi(device,NULL,messagedest,messages);
+  if(!d)d=cdda_identify_cooked(device,messagedest,messages);
+#else
   if(!d)d=cdda_identify_scsi(device,NULL,messagedest,messages);
+  d=cdda_identify_cooked(device,messagedest,messages);
+#endif
 
 #ifdef CDDA_TEST
   if(!d)d=cdda_identify_test(device,messagedest,messages);
@@ -412,17 +419,19 @@
 	    "\nFound an accessible SCSI CDROM drive."
 	    "\nLooking at revision of the SG interface in use...","");
 
-  if(ioctl(d->cdda_fd,SG_GET_VERSION_NUM,&version)){
+  if((version = ioctl(d->cdda_fd,SG_GET_VERSION_NUM,&major)) < 0){
     /* Up, guess not. */
     idmessage(messagedest,messages,
 	      "\tOOPS!  Old 2.0/early 2.1/early 2.2.x (non-ac patch) style "
 	      "SG.\n\tCdparanoia no longer supports the old interface.\n","");
     return(0);
   }
-  major=version/10000;
-  version-=major*10000;
-  minor=version/100;
-  version-=minor*100;
+  if (!version)
+    version = major;
+
+  major = (version >> 16) & 0xff;
+  minor = (version >> 8) & 0xff;
+  version &= 0xff;
   
   sprintf(buffer,"\tSG interface version %d.%d.%d; OK.",
 	  major,minor,version);
@@ -431,6 +440,138 @@
   return(major);
 }
 
+#ifdef SG_IO
+int get_sgio_fd(const char *device, int messagedest, char **messages) {
+	int fd;
+
+	if (!device)
+		return -errno;
+    	/* 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_EXCL|O_NONBLOCK);
+ 	if (fd < 0)
+    		return -errno;
+	return check_fd_sgio(fd);
+}
+
+/* removing generic_device breaks ABI; instead, just test both devices */
+static cdrom_drive *sgio_cdda_identify_scsi(const char *generic_device, 
+				const char *ioctl_device, int messagedest,
+				char **messages){
+  cdrom_drive *d = NULL;
+  char *device = NULL;
+  int fd = -1, g_fd = -1;
+  char *p;
+
+  /* with SG_IO in 2.6, we much prefer /dev/hdc and /dev/scd0, so
+   * test ioctl_device before testing generic_device */
+
+  /* we need to resolve any symlinks for the lookup code to work */
+  if (ioctl_device)
+    device = test_resolve_symlink(ioctl_device, messagedest, messages);
+  /* test again, in case symlink resolution failed */
+  if (device) {
+    fd = get_sgio_fd(ioctl_device, messagedest, messages);
+    if (fd < 0) {
+      /* ioctl_device didn't work, so we don't need to keep the strdup of its
+       * real path around */
+      free(device);
+      device = NULL;
+    }
+  }
+  if (fd < 0) {
+    if (!generic_device)
+      goto cdda_identify_scsi_fail_free;
+    device = test_resolve_symlink(generic_device, messagedest, messages);
+    /* test again, in case symlink resolution failed */
+    if (!device)
+      goto cdda_identify_scsi_fail_return;
+    g_fd = get_sgio_fd(device, messagedest, messages);
+    if (g_fd < 0)
+      goto cdda_identify_scsi_fail_free;
+    fd = g_fd;
+  }
+
+  d=calloc(1,sizeof(cdrom_drive));
+
+  d->drive_type=SCSI_CDROM_MAJOR;
+  d->cdda_fd=fd;
+  d->ioctl_fd=fd;
+  d->bigendianp=-1; /* We don't know yet... */
+  d->nsectors=-1;
+
+  d->interface=GENERIC_SCSI;
+
+  /* alloc our big buffer for scsi commands */
+  d->sg=calloc(1, sizeof (struct sg_info));
+  ((struct sg_info *)d->sg)->dxferp_max_buffer_len = CD_FRAMESIZE_RAW;
+  if (check_fd_sgio(d->cdda_fd)) 
+    sgio_init_sg_info(d);
+  else
+    sg2_init_sg_info(d);
+
+  /* get the lun -- this used to set 0 on failure, maybe still should */
+  d->lun = -1;
+
+  p = scsi_inquiry(d);
+  if (!p)
+    goto cdda_identify_scsi_fail_free_device;
+
+  /* It would seem some TOSHIBA CDROMs gets things wrong */
+ 
+  if (!strncmp (p + 8, "TOSHIBA", 7) &&
+      !strncmp (p + 16, "CD-ROM", 6) &&
+      p[0] == TYPE_DISK) {
+    p[0] = TYPE_ROM;
+    p[1] |= 0x80;     /* removable */
+  }
+
+  if (!p || (*p != TYPE_ROM && *p != TYPE_WORM)) {
+    idmessage(messagedest, messages,
+	      "\t\tDrive is neither a CDROM nor a WORM device\n", NULL);
+    goto cdda_identify_scsi_fail_free_device;
+  }
+
+  memcpy(d->inqbytes, p, 4);
+  d->cdda_device_name = device;
+  d->ioctl_device_name = device;
+
+  d->drive_model = calloc(1, 36);
+  strscat(d->drive_model, p+8, 8);
+  strscat(d->drive_model, p+16, 16);
+  strscat(d->drive_model, p+32, 4);
+
+  idmessage(messagedest, messages, "\nCDROM model sensed sensed: %s", d->drive_model);
+  
+  return d;
+  
+cdda_identify_scsi_fail_free_device:
+  if (d) {
+    if (d->drive_model)
+      free(d->drive_model);
+    if (d->sg) {
+      struct sg_info *sgi = (struct sg_info *)d->sg;
+      
+      if (sgi->cmdp_buffer_len)
+        free(sgi->cmdp);
+      if (sgi->dxferp_buffer_len)
+        free(sgi->dxferp);
+      if (sgi->hdr)
+        free(sgi->hdr);
+      free(d->sg);
+    }
+    free(d);
+  }
+  if (fd >= 0)
+    close(fd);
+cdda_identify_scsi_fail_free:
+  if (device)
+    free(device);
+cdda_identify_scsi_fail_return:
+  return NULL;
+}
+#endif
 cdrom_drive *cdda_identify_scsi(const char *generic_device, 
 				const char *ioctl_device, int messagedest,
 				char **messages){
@@ -444,6 +585,12 @@
   int type;
   char *p;
 
+#ifdef SG_IO
+  d = sgio_cdda_identify_scsi(generic_device, ioctl_device, messagedest, messages);
+  if (d)
+    return d;
+#endif
+
   if(generic_device)
     idmessage(messagedest,messages,"\tTesting %s for SCSI interface",
 	      generic_device);
@@ -580,7 +727,6 @@
 	      "major number",generic_device);
     goto cdda_identify_scsi_fail;
   }
-  
 
   d=calloc(1,sizeof(cdrom_drive));
 
@@ -601,8 +747,9 @@
   }
 
   /* malloc our big buffer for scsi commands */
-  d->sg=malloc(MAX_BIG_BUFF_SIZE);
-  d->sg_buffer=d->sg+SG_OFF;
+  d->sg=calloc(1, sizeof (struct sg_info));
+  ((struct sg_info *)d->sg)->dxferp_max_buffer_len = CD_FRAMESIZE_RAW;
+  sg2_init_sg_info(d);
 
   {
     /* get the lun */
@@ -614,6 +761,8 @@
   }
 
   p = scsi_inquiry(d);
+  if (!p)
+    goto cdda_identify_scsi_fail;
 
   /* It would seem some TOSHIBA CDROMs gets things wrong */
  
@@ -632,12 +781,11 @@
     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->drive_model=calloc(36,1);
+  d->drive_model=calloc(1, 36);
   strscat(d->drive_model,p+8,8);
   strscat(d->drive_model,p+16,16);
   strscat(d->drive_model,p+32,4);
@@ -647,6 +795,22 @@
   return(d);
   
 cdda_identify_scsi_fail:
+  if (d) {
+    if (d->drive_model)
+      free(d->drive_model);
+    if (d->sg) {
+      struct sg_info *sgi = (struct sg_info *)d->sg;
+      
+      if (sgi->cmdp_buffer_len)
+        free(sgi->cmdp);
+      if (sgi->dxferp_buffer_len)
+        free(sgi->dxferp);
+      if (sgi->hdr)
+        free(sgi->hdr);
+      free(d->sg);
+    }
+    free(d);
+  }
   if(generic_device)free((char *)generic_device);
   if(ioctl_device)free((char *)ioctl_device);
   if(i_fd!=-1)close(i_fd);
--- cdparanoia-III-alpha9.8/interface/scsi_interface.c.sgio	2001-03-23 20:15:46.000000000 -0500
+++ cdparanoia-III-alpha9.8/interface/scsi_interface.c	2004-03-30 14:19:29.826011776 -0500
@@ -3,6 +3,7 @@
  * Original interface.c Copyright (C) 1994-1997 
  *            Eissfeldt heiko@colossus.escape.de
  * Current blenderization Copyright (C) 1998-1999 Monty xiphmont@mit.edu
+ *                        Copyright 2004 Peter Jones <pjones@redhat.com>
  * 
  * Generic SCSI interface specific code.
  *
@@ -11,6 +12,7 @@
 #include "low_interface.h"
 #include "common_interface.h"
 #include "utils.h"
+#include "scsi_cmds.h"
 
 /* hook */
 static int Dummy (cdrom_drive *d,int s){
@@ -19,7 +21,290 @@
 
 #include "drive_exceptions.h"
 
-static void tweak_SG_buffer(cdrom_drive *d){
+static void reset_scsi(cdrom_drive *d){
+  struct sg_info *sgi = (struct sg_info *)d->sg;
+  struct sg_io_hdr *hdr = sgi->hdr;
+  unsigned char key, ASC, ASCQ;
+  int arg, ret, tries;
+  char cmd[6];
+
+  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");
+
+  tries = 0;
+  while(1) {
+    memcpy(cmd, SCSI_TEST_UNIT_READY_6, 6);
+    sgi->setup_scsi_cmd(d, cmd, 6, 0, 56);
+    ret = sgi->handle_scsi_cmd(d);
+
+    key = hdr->sbp[2] & 0xf;
+    ASC = hdr->sbp[12];
+    ASCQ = hdr->sbp[13];
+
+    if(key == 2 & ASC == 4 & ASCQ == 1 & tries < 10) {
+      tries++;
+      usleep(10);
+      continue;
+    }
+    break;
+  }
+
+  d->enable_cdda(d,1);
+}
+
+static int check_sbp_error(const char *sbp) {
+  char key = sbp[2] & 0xf;
+  char ASC = sbp[12];
+  char ASCQ = sbp[13];
+
+  if (sbp[0]) {
+    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;
+}
+
+#ifdef SG_IO
+int check_fd_sgio(int fd) {
+  struct sg_io_hdr hdr;
+
+  if (fd < 0)
+    return fd;
+
+  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) {
+      /* sr and ata give us EINVAL when SG_IO is supported
+       * but interface_id is bad. */
+      case EINVAL:
+      /* sg gives us ENOSYS when SG_IO is supported but
+       * interface_id is bad.  IMHO, this is wrong and 
+       * needs fixing in the kernel. */
+      case ENOSYS:
+        return fd;
+      /* everything else gives ENOTTY, I think.  I'm just
+       * going to be paranoid and reject everything else. */
+      default:
+        return -errno;
+    }
+  }
+  /* 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. */
+  return -1;
+}
+
+static void sgio_tweak_SG_buffer(cdrom_drive *d) {
+  int table, reserved, cur, err;
+  char buffer[256];
+
+  /* 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);
+
+  cur = 0;
+  /* this doesn't currently ever work, but someday somebody might
+     implement working sg lists with SG_IO devices, so who knows... */
+  table=1;
+  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);
+
+  cur=table*reserved;
+
+  ((struct sg_info *)d->sg)->dxferp_max_buffer_len = cur;
+
+  /* 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.
+   */
+#if 0
+  cur=(cur>1024*32?1024*32:cur);
+#endif
+  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);
+}
+
+static void sgio_setup_scsi_cmd(cdrom_drive *d,
+				char *cmdp,
+				unsigned int cmd_len,
+				unsigned int in_size,
+				unsigned int out_size) {
+  struct sg_info *sgi = (struct sg_info *)d->sg;
+  struct sg_io_hdr *hdr = sgi->hdr;
+
+  memset(hdr->cmdp, 0, sgi->cmdp_buffer_len);
+  memset(hdr->dxferp, sgi->bytefill, sgi->dxferp_buffer_len);
+  memcpy(hdr->cmdp, cmdp, cmd_len);
+
+  hdr->cmd_len = cmd_len;
+
+  sgi->in_size = in_size;
+  sgi->out_size = out_size;
+}
+
+static int sgio_handle_scsi_cmd(cdrom_drive *d) {
+  int status = 0;
+  struct sg_info *sgi = (struct sg_info *)d->sg;
+  struct sg_io_hdr *hdr = sgi->hdr;
+
+  if (sgi->in_size) {
+    hdr->dxfer_len = sgi->in_size;
+    hdr->dxfer_direction = SG_DXFER_TO_DEV;
+
+    errno = 0;
+    status = ioctl(d->cdda_fd, SG_IO, hdr);
+    if (status >= 0)
+      if (hdr->status)
+        status = check_sbp_error(hdr->sbp);
+    if (status < 0) 
+      return TR_EWRITE;
+  }
+  if (!sgi->in_size | sgi->out_size) {
+    hdr->dxfer_len = sgi->out_size;
+    hdr->dxfer_direction = sgi->out_size ? SG_DXFER_FROM_DEV : SG_DXFER_NONE;
+
+    errno = 0;
+    status = ioctl(d->cdda_fd, SG_IO, hdr);
+    if (status < 0)
+      return TR_EREAD;
+    if (status >= 0)
+      if (hdr->status)
+        status = check_sbp_error(hdr->sbp);
+  }
+  if (status)
+    return status;
+
+  errno = 0;
+  return 0;
+}
+
+void sgio_init_sg_info(cdrom_drive *d) {
+  struct sg_info *sgi = (struct sg_info *)d->sg;
+  struct sg_io_hdr *hdr;
+
+  hdr = calloc(sizeof (struct sg_io_hdr), 1);
+
+  sgi->cmdp = hdr->cmdp = calloc(128, 1);
+  sgi->cmdp_buffer_len = 128;
+
+  hdr->sbp = calloc(SG_MAX_SENSE,1);
+  hdr->mx_sb_len = SG_MAX_SENSE;
+
+  sgi->bytefill = '\xff';
+  sgi->bytecheck = 0;
+
+  hdr->timeout = 5000;
+  hdr->interface_id = 'S';
+
+  sgi->hdr = hdr;
+
+  sgi->setup_scsi_cmd = sgio_setup_scsi_cmd;
+  sgi->handle_scsi_cmd = sgio_handle_scsi_cmd;
+
+  sgio_tweak_SG_buffer(d);
+
+  sgi->dxferp = hdr->dxferp = calloc(sgi->dxferp_max_buffer_len, 1);
+  sgi->dxferp_buffer_len = sgi->dxferp_max_buffer_len;
+}
+#endif
+
+static void sg2_clear_garbage(cdrom_drive *d){
+  fd_set fdset;
+  struct timeval tv;
+  struct sg_header *sg_hd = (struct sg_header *)((struct sg_info *)d->sg)->hdr;
+  int flag = 0;
+
+  /* clear out any possibly preexisting garbage */
+  FD_ZERO(&fdset);
+  FD_SET(d->cdda_fd,&fdset);
+  tv.tv_sec=0;
+  tv.tv_usec=0;
+
+  /* I like select */
+  while(select(d->cdda_fd+1,&fdset,NULL,NULL,&tv)==1){
+    
+    sg_hd->twelve_byte = 0;
+    sg_hd->result = 0;
+    sg_hd->reply_len = SG_OFF;
+    read(d->cdda_fd, sg_hd, 1);
+
+    /* reset for select */
+    FD_ZERO(&fdset);
+    FD_SET(d->cdda_fd,&fdset);
+    tv.tv_sec=0;
+    tv.tv_usec=0;
+    if(!flag && d->report_all)
+      cdmessage(d,"Clearing previously returned data from SCSI buffer\n");
+    flag=1;
+  }
+}
+
+static void sg2_tweak_SG_buffer(cdrom_drive *d){
   int table,reserved;
   char buffer[256];
 
@@ -58,74 +343,47 @@
   if(ioctl(d->cdda_fd,SG_SET_COMMAND_Q,&reserved)){
     cdmessage(d,"\tCouldn't disable command queue!  Continuing anyway...\n");
   }
-
 }
 
-static void reset_scsi(cdrom_drive *d){
-  int arg;
-  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");
-  
-  d->enable_cdda(d,1);
-}
+/* process a complete scsi command. */
 
-static void clear_garbage(cdrom_drive *d){
-  fd_set fdset;
-  struct timeval tv;
-  struct sg_header *sg_hd=(struct sg_header *)d->sg;
-  int flag=0;
+static void sg2_setup_scsi_cmd(cdrom_drive *d,
+				char *cmdp,
+				unsigned int cmd_len,
+				unsigned int in_size,
+				unsigned int out_size) {
+  struct sg_info *sgi = (struct sg_info *)d->sg;
+  struct sg_header *hdr = (struct sg_header *)sgi->hdr;
 
-  /* clear out any possibly preexisting garbage */
-  FD_ZERO(&fdset);
-  FD_SET(d->cdda_fd,&fdset);
-  tv.tv_sec=0;
-  tv.tv_usec=0;
+  sgi->cmdp = (char *)hdr + sizeof (struct sg_header);
+  memcpy(sgi->cmdp, cmdp, cmd_len);
 
-  /* I like select */
-  while(select(d->cdda_fd+1,&fdset,NULL,NULL,&tv)==1){
-    
-    sg_hd->twelve_byte = 0;
-    sg_hd->result = 0;
-    sg_hd->reply_len = SG_OFF;
-    read(d->cdda_fd, sg_hd, 1);
+  sgi->dxferp = sgi->cmdp + cmd_len;
+  memset(sgi->dxferp, sgi->bytefill, sgi->dxferp_max_buffer_len - cmd_len);
 
-    /* reset for select */
-    FD_ZERO(&fdset);
-    FD_SET(d->cdda_fd,&fdset);
-    tv.tv_sec=0;
-    tv.tv_usec=0;
-    if(!flag && d->report_all)
-      cdmessage(d,"Clearing previously returned data from SCSI buffer\n");
-    flag=1;
-  }
+  sgi->in_size = in_size;
+  sgi->out_size = out_size;
 }
 
-/* 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) {
   int status = 0;
-  struct sg_header *sg_hd=(struct sg_header *)d->sg;
-  long writebytes=SG_OFF+cmd_len+in_size;
+  struct sg_info *sgi = (struct sg_info *)d->sg;
+  struct sg_header *sg_hd = (struct sg_header *)sgi->hdr;
+
+  int out_size = sgi->out_size;
+  int in_size = sgi->in_size;
+
+  long writebytes = (int)(sg_hd) + SG_OFF + sgi->cmd_len + sgi->in_size;
 
   /* generic scsi device services */
 
   /* clear out any possibly preexisting garbage */
-  clear_garbage(d);
+  sg2_clear_garbage(d);
 
-  memset(sg_hd,0,sizeof(sg_hd)); 
-  sg_hd->twelve_byte = cmd_len == 12;
+  memset(sg_hd,0, SG_OFF); 
+  sg_hd->twelve_byte = sgi->cmd_len == 12;
   sg_hd->result = 0;
-  sg_hd->reply_len = SG_OFF + out_size;
+  sg_hd->reply_len = SG_OFF + sgi->out_size;
 
   /* The following is one of the scariest hacks I've ever had to use.
      The idea is this: We want to know if a command fails.  The
@@ -135,8 +393,8 @@
      length for a command that doesn't take data) such that we can
      tell if the command failed.  Scared yet? */
 
-  if(bytecheck && out_size>in_size){
-    memset(d->sg_buffer+cmd_len+in_size,bytefill,out_size-in_size); 
+  if(sgi->bytecheck && out_size>in_size){
+    /* the memset for this is done in sg2_setup_scsi_cmd() */
     /* the size does not remove cmd_len due to the way the kernel
        driver copies buffers */
     writebytes+=(out_size-in_size);
@@ -224,40 +482,10 @@
     if(errno==0)errno=EIO;
     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);
-      }
-    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);
-    }
-  }
+  
+  status = check_sbp_error(sg_hd->sense_buffer);
+  if (status)
+    return status;
 
   /* still not foolproof; the following doesn't guarantee that we got
      all the data, just that the command was not rejected. */
@@ -266,10 +494,11 @@
      commands still get through.  Perhaps no data comes back even
      though the target reports success? */
 
-  if(bytecheck && in_size+cmd_len<out_size){
+  if(sgi->bytecheck && sgi->in_size+sgi->cmd_len<sgi->out_size){
     long i,flag=0;
-    for(i=in_size;i<out_size;i++)
-      if(d->sg_buffer[i]!=bytefill){
+    for(i=sgi->in_size; i<sgi->out_size; i++)
+      /* XXX check this offset */
+      if((sgi->dxferp[i])!=(sgi->bytefill)){
 	flag=1;
 	break;
       }
@@ -284,61 +513,67 @@
   return(0);
 }
 
-/* Group 1 (10b) command */
+void sg2_init_sg_info(cdrom_drive *d) {
+  struct sg_info *sgi = (struct sg_info *)d->sg;
+  struct sg_header *hdr;
 
-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);
-
-  d->sg_buffer[1]=d->lun<<5;
-  d->sg_buffer[2]=0x3F&page;
-  d->sg_buffer[8]=size+4;
+  hdr = calloc(sizeof (struct sg_header)+sgi->dxferp_max_buffer_len, 1);
 
-  if (handle_scsi_cmd (d, 10, 0, size+4,'\377',1)) return(1);
+  sgi->cmdp = (char *)hdr + sizeof (struct sg_header);
+  sgi->cmdp_buffer_len = 0;
 
-  {
-    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 */
-
-    b[0]=b[1]-3;
-    b[1]=b[2];
-    b[2]=b[3];
-    b[3]=b[7];
+  sgi->bytefill = '\xff';
+  sgi->bytecheck = 1;
 
-    memmove(b+4,b+8,size);
-  }
-  return(0);
+  sgi->setup_scsi_cmd = sg2_setup_scsi_cmd;
+  sgi->handle_scsi_cmd = sg2_handle_scsi_cmd;
+
+  sg2_tweak_SG_buffer(d);
+
+  // sgi->dxferp = hdr + sizeof (struct sg_header);
+  sgi->dxferp = NULL;
+  sgi->dxferp_buffer_len = 0;
+}
+
+static int mode_sense_atapi(cdrom_drive *d, int size, int page) { 
+  char *buffer;
+
+  ((struct sg_info *)d->sg)->setup_scsi_cmd(d, SCSI_MODE_SENSE_10(page,size), 10, 0, size);
+
+  buffer = ((struct sg_info *)d->sg)->dxferp;
+#if 0
+  buffer[1]=d->lun<<5;
+#endif
+
+  if (((struct sg_info *)d->sg)->handle_scsi_cmd(d))
+    return 1;
+
+  if(buffer[0])return(1); /* Handles only up to 256 bytes */
+  if(buffer[6])return(1); /* Handles only up to 256 bytes */
+
+  buffer[0]=buffer[1]-3; 
+  buffer[1]=buffer[2];
+  buffer[2]=buffer[3];
+  buffer[3]=buffer[7];
+
+  memmove(buffer+4,buffer+8,size);
+  return 0;
 }
 
 /* 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);
+  char *buffer;
+  ((struct sg_info *)d->sg)->setup_scsi_cmd(d, SCSI_MODE_SENSE_6(page, size), 6, 0, size);
   
-  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);
-  return(0);
+  buffer = ((struct sg_info *)d->sg)->dxferp;
+#if 0
+  buffer[1]=d->lun<<5;
+#endif
+
+  if (((struct sg_info *)d->sg)->handle_scsi_cmd(d))
+    return 1;
+  return 0;
 }
 
 static int mode_sense(cdrom_drive *d,int size,int page){
@@ -347,80 +582,77 @@
   return(mode_sense_scsi(d,size,page));
 }
 
-static int mode_select(cdrom_drive *d,int density,int secsize){
-  /* short circut the way Heiko does it; less flexible, but shorter */
-  if(d->is_atapi){
-    unsigned char *mode = d->sg_buffer + 18;
+static int atapi_mode_select(cdrom_drive *d, int density, int secsize) {
+  unsigned char *mode;
 
-    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;
-
-    /* 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 */
+  ((struct sg_info *)d->sg)->setup_scsi_cmd(d, SCSI_MODE_SELECT_10, 10, 16, 0);
+  memcpy(((struct sg_info *)d->sg)->dxferp,(char []) { 
+      /* 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 */
+    16);
+
+  mode = ((struct sg_info *)d->sg)->dxferp;
+#if 0
+  mode[1] |= d->lun << 5;
+#endif
+  /* prepare to read cds in the previous mode */
+  mode[8] = density;
+  mode[14] = secsize >> 8;   /* block length "msb" */
+  mode[15] = secsize & 0xFF; /* block length lsb */
+
+  /* do the scsi cmd */
+  return ((struct sg_info *)d->sg)->handle_scsi_cmd(d);
+}
+
+static int scsi_mode_select(cdrom_drive *d, int density, int secsize) {
+  unsigned char *mode;
+
+  ((struct sg_info *)d->sg)->setup_scsi_cmd(d, SCSI_MODE_SELECT_6, 6, 12, 0);
+  memcpy(((struct sg_info *)d->sg)->dxferp,(char []) {
+      /* mode section */
+      0, 
+      0, 0, 
+      8,       /* Block Descriptor Length */
+      0,       /* Density Code */
+      0, 0, 0, /* # of Blocks */
+      0,       /* reserved */
+      0, 0, 0},/* Blocklen */
+    12);
+    
+  /* prepare to read cds in the previous mode */
+  mode = ((struct sg_info *)d->sg)->dxferp;
+  mode [4] = density;
+  mode [10] =  secsize >> 8;   /* block length "msb" */
+  mode [11] =  secsize & 0xFF; /* block length lsb */
 
     /* do the scsi cmd */
-    return(handle_scsi_cmd (d,10, 16, 0,0,0));
-
-  }else{
-    unsigned char *mode = d->sg_buffer + 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 */
+  return ((struct sg_info *)d->sg)->handle_scsi_cmd(d);
+}
 
-    /* do the scsi cmd */
-    return(handle_scsi_cmd (d,6, 12, 0,0,0));
-  }
+static int mode_select(cdrom_drive *d, int density, int secsize) {
+  /* short circut the way Heiko does it; less flexible, but shorter */
+  if (d->is_atapi)
+    return atapi_mode_select(d, density, secsize);
+  return scsi_mode_select(d, density, secsize);
 }
 
 /* get current sector size from SCSI cdrom drive */
 static unsigned int get_orig_sectorsize(cdrom_drive *d){
-  if(mode_sense(d,12,0x01))return(-1);
+  if (mode_sense(d,12,0x01))
+    return -1;
+
+  d->orgdens = ((struct sg_info *)d->sg)->dxferp[4];
+  
+  d->orgsize = (int)(((struct sg_info *)d->sg)->dxferp[10]<<8);
+  d->orgsize += (int)((struct sg_info *)d->sg)->dxferp[11];
 
-  d->orgdens = d->sg_buffer[4];
-  return(d->orgsize = ((int)(d->sg_buffer[10])<<8)+d->sg_buffer[11]);
+  return d->orgsize;
 }
 
 /* switch CDROM scsi drives to given sector size  */
@@ -463,23 +695,23 @@
    fails on at least one Kodak drive. */
 
 static int scsi_read_toc (cdrom_drive *d){
+  struct sg_info *sgi = (struct sg_info *)d->sg;
   int i,first,last;
   unsigned tracks;
-
-  /* READTOC, MSF format flag, res, res, res, res, Start track, len msb,
-     len lsb, flags */
+  scsi_TOC *toc;
 
   /* 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;
-
-  if (handle_scsi_cmd (d,10, 0, 12,'\377',1)){
+  sgi->setup_scsi_cmd(d, SCSI_READ_TOC(1), 10, 0, 12);
+#if 0
+  sgi->dxferp[1] = d->lun << 5;
+#endif
+  if (sgi->handle_scsi_cmd(d)) {
     cderror(d,"004: Unable to read table of contents header\n");
     return(-4);
   }
 
-  first=d->sg_buffer[2];
-  last=d->sg_buffer[3];
+  first = sgi->dxferp[2];
+  last = sgi->dxferp[3];
   tracks=last-first+1;
 
   if (last > MAXTRK || first > MAXTRK || last<0 || first<0) {
@@ -488,335 +720,208 @@
   }
 
   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;
+    sgi->setup_scsi_cmd(d, SCSI_READ_TOC(i), 10, 0, 12);
+#if 0    
+    sgi->dxferp[1] = d->lun << 5;
+#endif
     
-    if (handle_scsi_cmd (d,10, 0, 12,'\377',1)){
+    if (sgi->handle_scsi_cmd(d)) {
       cderror(d,"005: Unable to read table of contents entry\n");
       return(-5);
     }
-    {
-      scsi_TOC *toc=(scsi_TOC *)(d->sg_buffer+4);
-
-      d->disc_toc[i-first].bFlags=toc->bFlags;
-      d->disc_toc[i-first].bTrack=i;
-      d->disc_toc[i-first].dwStartSector= d->adjust_ssize * 
-	(((int)(toc->start_MSB)<<24) | 
-	 (toc->start_1<<16)|
-	 (toc->start_2<<8)|
-	 (toc->start_LSB));
-    }
-  }
+    toc = (scsi_TOC *)(sgi->dxferp+4);
+    d->disc_toc[i-first].bFlags = toc->bFlags;
+    d->disc_toc[i-first].bTrack = i;
+    d->disc_toc[i-first].dwStartSector = 
+      d->adjust_ssize * (
+        ((int)(toc->start_MSB)<<24) | (toc->start_1 << 16) |
+        (toc->start_2 << 8) | (toc->start_LSB)
+      );
+  }
+
+  sgi->setup_scsi_cmd(d, SCSI_READ_TOC(0xAA), 10, 0, 12);
+#if 0    
+  sgi->dxferp[1] = d->lun << 5;
+#endif
 
-  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;
-    
-  if (handle_scsi_cmd (d,10, 0, 12,'\377',1)){
+  if (sgi->handle_scsi_cmd(d)) {
     cderror(d,"002: Unable to read table of contents lead-out\n");
     return(-2);
   }
-  {
-    scsi_TOC *toc=(scsi_TOC *)(d->sg_buffer+4);
-    
-    d->disc_toc[i-first].bFlags=toc->bFlags;
-    d->disc_toc[i-first].bTrack=0xAA;
-    d->disc_toc[i-first].dwStartSector= d->adjust_ssize * 
-	(((int)(toc->start_MSB)<<24) | 
-	 (toc->start_1<<16)|
-	 (toc->start_2<<8)|
-	 (toc->start_LSB));
-  }
+  
+  toc = (scsi_TOC *)(sgi->dxferp+4);
+  d->disc_toc[i-first].bFlags = toc->bFlags;
+  d->disc_toc[i-first].bTrack = 0xAA;
+  d->disc_toc[i-first].dwStartSector = 
+    d->adjust_ssize * (
+      ((int)(toc->start_MSB)<<24) | (toc->start_1 << 16) |
+      (toc->start_2 << 8) | (toc->start_LSB)
+    );
 
   d->cd_extra = FixupTOC(d,tracks+1); /* include lead-out */
-  return(tracks);
+  return tracks;
 }
 
 /* a contribution from Boris for IMS cdd 522 */
 /* check this for ACER/Creative/Foo 525,620E,622E, etc? */
 static int scsi_read_toc2 (cdrom_drive *d){
-  u_int32_t foo,bar;
+  struct sg_info *sgi = (struct sg_info *)d->sg;
+  u_int32_t msb,lsb;
 
   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;
-
-  if (handle_scsi_cmd (d,10, 0, 256,'\377',1)){
+  sgi->setup_scsi_cmd(d, CDD522_READ_TOC(1), 10, 0, 256);
+  if (sgi->handle_scsi_cmd(d)) {
     cderror(d,"004: Unable to read table of contents header\n");
     return(-4);
   }
 
   /* copy to our structure and convert start sector */
-  tracks = d->sg_buffer[1];
+  tracks = sgi->dxferp[1];
   if (tracks > MAXTRK) {
     cderror(d,"003: CDROM reporting illegal number of tracks\n");
     return(-3);
   }
 
   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;
+    sgi->setup_scsi_cmd(d, CDD522_READ_TOC(i+1), 10, 0, 256);
     
-    if (handle_scsi_cmd (d,10, 0, 256,'\377',1)){
+    if (sgi->handle_scsi_cmd(d)) {
       cderror(d,"005: Unable to read table of contents entry\n");
       return(-5);
     }
     
-    d->disc_toc[i].bFlags = d->sg_buffer[10];
+    d->disc_toc[i].bFlags = sgi->dxferp[10];
     d->disc_toc[i].bTrack = i + 1;
 
-    d->disc_toc[i].dwStartSector= d->adjust_ssize * 
-	(((signed char)(d->sg_buffer[2])<<24) | 
-	 (d->sg_buffer[3]<<16)|
-	 (d->sg_buffer[4]<<8)|
-	 (d->sg_buffer[5]));
+    d->disc_toc[i].dwStartSector = d->adjust_ssize * (
+        ((signed char)(sgi->dxferp[2])<<24) | 
+	(sgi->dxferp[3]<<16) |
+	(sgi->dxferp[4]<<8) |
+	(sgi->dxferp[5])
+      );
   }
 
   d->disc_toc[i].bFlags = 0;
   d->disc_toc[i].bTrack = i + 1;
-  memcpy (&foo, d->sg_buffer+2, 4);
-  memcpy (&bar, d->sg_buffer+6, 4);
-  d->disc_toc[i].dwStartSector = d->adjust_ssize * (be32_to_cpu(foo) +
-						    be32_to_cpu(bar));
-
-  d->disc_toc[i].dwStartSector= d->adjust_ssize * 
-    ((((signed char)(d->sg_buffer[2])<<24) | 
-      (d->sg_buffer[3]<<16)|
-      (d->sg_buffer[4]<<8)|
-      (d->sg_buffer[5]))+
-     
-     ((((signed char)(d->sg_buffer[6])<<24) | 
-       (d->sg_buffer[7]<<16)|
-       (d->sg_buffer[8]<<8)|
-       (d->sg_buffer[9]))));
-
+  memcpy (&msb, sgi->dxferp+2, 4);
+  memcpy (&lsb, sgi->dxferp+6, 4);
+  d->disc_toc[i].dwStartSector = d->adjust_ssize *
+      (be32_to_cpu(msb) + be32_to_cpu(lsb));
+
+  d->disc_toc[i].dwStartSector= d->adjust_ssize * (
+    ((((signed char)(sgi->dxferp[2])<<24) | 
+        (sgi->dxferp[3]<<16) |
+        (sgi->dxferp[4]<<8) |
+        (sgi->dxferp[5])
+      ) + (
+        ((signed char)(sgi->dxferp[6])<<24) | 
+        (sgi->dxferp[7]<<16) |
+        (sgi->dxferp[8]<<8) |
+        (sgi->dxferp[9])))
+    );
 
   d->cd_extra = FixupTOC(d,tracks+1);
-  return(tracks);
+  return tracks;
 }
 
 /* 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 generic_scsi_read(cdrom_drive *d, void *p, long begin, long sectors,
+    char *read_cmd, int len, int in_size, int out_size) {
+  struct sg_info *sgi = (struct sg_info *)d->sg;
   int ret;
-  memcpy(d->sg_buffer,(char []){0x28, 0, 0, 0, 0, 0, 0, 0, 0, 0},10);
-
-  if(d->fua)
-    d->sg_buffer[1]=0x08;
 
-  d->sg_buffer[1]|=d->lun<<5;
+  sgi->setup_scsi_cmd(d, read_cmd, len, in_size, out_size);
+#if 0    
+  sgi->dxferp[1] = d->lun << 5;
+#endif
 
-  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)))
-    return(ret);
-  if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
-  return(0);
+  ret = sgi->handle_scsi_cmd(d);
+  if (ret)
+    return ret;
+  if (p)
+    memcpy(p, sgi->dxferp, sectors * CD_FRAMESIZE_RAW);
+  return 0;
 }
 
-static int i_read_A8 (cdrom_drive *d, void *p, long begin, long sectors){
-  int ret;
-  memcpy(d->sg_buffer,(char []){0xA8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},12);
-
-  if(d->fua)
-    d->sg_buffer[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)))
-    return(ret);
-  if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
-  return(0);
+static int i_read_28(cdrom_drive *d, void *p, long begin, long sectors){
+  return generic_scsi_read(d, p, begin, sectors,
+    SCSI_READ_10(d->fua, begin, sectors), 10, 0, sectors * CD_FRAMESIZE_RAW);
 }
 
-static int i_read_D4_10 (cdrom_drive *d, void *p, long begin, long sectors){
-  int ret;
-  memcpy(d->sg_buffer,(char []){0xd4, 0, 0, 0, 0, 0, 0, 0, 0, 0},10);
-
-  if(d->fua)
-    d->sg_buffer[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)))
-    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){
+  return generic_scsi_read(d, p, begin, sectors,
+    SCSI_READ_12(d->fua, begin, sectors), 12, 0, sectors * CD_FRAMESIZE_RAW);
 }
 
-static int i_read_D4_12 (cdrom_drive *d, void *p, long begin, long sectors){
-  int ret;
-  memcpy(d->sg_buffer,(char []){0xd4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},12);
-
-  if(d->fua)
-    d->sg_buffer[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)))
-    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){
+  return generic_scsi_read(d, p, begin, sectors,
+    D4_READ_10(begin, sectors), 10, 0, sectors * CD_FRAMESIZE_RAW);
 }
 
-static int i_read_D5 (cdrom_drive *d, void *p, long begin, long sectors){
-  int ret;
-  memcpy(d->sg_buffer,(char []){0xd5, 0, 0, 0, 0, 0, 0, 0, 0, 0},10);
-
-  if(d->fua)
-    d->sg_buffer[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)))
-    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){
+  return generic_scsi_read(d, p, begin, sectors,
+    D4_READ_12(begin, sectors), 12, 0, sectors * CD_FRAMESIZE_RAW);
 }
 
-static int i_read_D8 (cdrom_drive *d, void *p, long begin, long sectors){
-  int ret;
-  memcpy(d->sg_buffer,(char []){0xd8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},12);
-
-  if(d->fua)
-    d->sg_buffer[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)))
-    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){
+  return generic_scsi_read(d, p, begin, sectors,
+    D5_READ_10(begin, sectors), 10, 0, sectors * CD_FRAMESIZE_RAW);
 }
 
-static int i_read_mmc (cdrom_drive *d, void *p, long begin, long sectors){
-  int ret;
-  /*  if(begin<=12007 && begin+sectors>12000){
-    errno=EIO;
-    return(TR_ILLEGAL);
-  }*/
-
-  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)))
-    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){
+  return generic_scsi_read(d, p, begin, sectors,
+    D8_READ_12(begin, sectors), 12, 0, sectors * CD_FRAMESIZE_RAW);
 }
 
-static int i_read_mmc2 (cdrom_drive *d, void *p, long begin, long sectors){
-  int ret;
-  memcpy(d->sg_buffer,(char []){0xbe, 0, 0, 0, 0, 0, 0, 0, 0, 0xf8, 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)))
-    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){
+  return generic_scsi_read(d, p, begin, sectors,
+    READ_CD_12(begin, sectors), 12, 0, sectors * CD_FRAMESIZE_RAW);
 }
 
-static int i_read_mmc3 (cdrom_drive *d, void *p, long begin, long sectors){
-  int ret;
-  memcpy(d->sg_buffer,(char []){0xbe, 4, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0},12);
+static int i_read_mmc2(cdrom_drive *d, void *p, long begin, long sectors){
+  char cmd[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)))
-    return(ret);
-  if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
-  return(0);
+  memcpy(cmd, READ_CD_12(begin, sectors), 12);
+  cmd[9] = 0xf8;
+  return generic_scsi_read(d, p, begin, sectors,
+    cmd, 12, 0, sectors * CD_FRAMESIZE_RAW);
 }
 
-/* straight from the MMC3 spec */
-static inline void LBA_to_MSF(long lba,
-			      unsigned char *M, 
-			      unsigned char *S, 
-			      unsigned char *F){
-  if(lba>=-150){
-    *M=(lba+150)/(60*75);
-    lba-=(*M)*60*75;
-    *S=(lba+150)/75;
-    lba-=(*S)*75;
-    *F=(lba+150);
-  }else{
-    *M=(lba+450150)/(60*75);
-    lba-=(*M)*60*75;
-    *S=(lba+450150)/75;
-    lba-=(*S)*75;
-    *F=(lba+450150);
-  }
-}
-
-
-static int i_read_msf (cdrom_drive *d, void *p, long begin, long sectors){
-  int ret;
-  memcpy(d->sg_buffer,(char []){0xb9, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0},12);
+static int i_read_mmc3(cdrom_drive *d, void *p, long begin, long sectors){
+  char cmd[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);
+  memcpy(cmd, READ_CD_12(begin, sectors), 12);
+  cmd[1] = 4;  
+  cmd[9] = 0xf8;
+  return generic_scsi_read(d, p, begin, sectors,
+    cmd, 12, 0, sectors * CD_FRAMESIZE_RAW);
+}
 
-  if((ret=handle_scsi_cmd(d,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
-    return(ret);
-  if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
-  return(0);
+static int i_read_msf(cdrom_drive *d, void *p, long begin, long sectors){
+  return generic_scsi_read(d, p, begin, sectors,
+    READ_CD_MSF_12(begin, sectors), 12, 0, sectors * CD_FRAMESIZE_RAW);
 }
 
 static int i_read_msf2 (cdrom_drive *d, void *p, long begin, long sectors){
-  int ret;
-  memcpy(d->sg_buffer,(char []){0xb9, 0, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0},12);
+  char cmd[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)))
-    return(ret);
-  if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
-  return(0);
+  memcpy(cmd, READ_CD_MSF_12(begin, sectors), 12);
+  cmd[9] = 0xf8;
+  return generic_scsi_read(d, p, begin, sectors,
+    cmd, 12, 0, sectors * CD_FRAMESIZE_RAW);
 }
 
 static int i_read_msf3 (cdrom_drive *d, void *p, long begin, long sectors){
-  int ret;
-  memcpy(d->sg_buffer,(char []){0xb9, 4, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0},12);
+  char cmd[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)))
-    return(ret);
-  if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
-  return(0);
+  memcpy(cmd, READ_CD_MSF_12(begin, sectors), 12);
+  cmd[1] = 4;
+  cmd[9] = 0xf8;
+  return generic_scsi_read(d, p, begin, sectors,
+    cmd, 12, 0, sectors * CD_FRAMESIZE_RAW);
 }
 
 static long scsi_read_map (cdrom_drive *d, void *p, long begin, long sectors,
@@ -824,6 +929,10 @@
   int retry_count,err;
   char *buffer=(char *)p;
 
+  struct sg_info *sgi = (struct sg_info *)d->sg;
+  struct sg_io_hdr *hdr = sgi->hdr;
+  unsigned char key, ASC, ASCQ;
+
   /* read d->nsectors at a time, max. */
   sectors=(sectors>d->nsectors?d->nsectors:sectors);
   sectors=(sectors<1?1:sectors);
@@ -832,17 +941,32 @@
   
   while(1) {
     if((err=map(d,(p?buffer:NULL),begin,sectors))){
+      /* Dunno if we even need this now that scsi_reset does it,
+       * but try to take "device is becoming ready" into account */
+      key = hdr->sbp[2] & 0xf;
+      ASC = hdr->sbp[12];
+      ASCQ = hdr->sbp[13];
+
+      if(key == 2 & ASC == 4 & ASCQ == 1) {
+        if(retry_count > MAX_RETRIES-1) {
+	  char b[256];
+	  sprintf(b,"010: Unable to access sector %ld\n",
+	    begin);
+	  cderror(d,b);
+	  return(-10);
+	} else {
+	  retry_count++;
+	  usleep(100);
+	  continue;
+	}
+      }
       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]));
+		key, ASC, ASCQ);
 	cdmessage(d,b);
 	sprintf(b,"                 Transport error: %s\n",strerror_tr[err]);
 	cdmessage(d,b);
@@ -852,9 +976,7 @@
 	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]));
+		key, ASC, ASCQ);
 	fprintf(stderr,"                 Transport error: %s\n",strerror_tr[err]);
 	fprintf(stderr,"                 System error: %s\n",strerror(errno));
       }
@@ -1014,7 +1136,7 @@
 static int count_2352_bytes(cdrom_drive *d){
   long i;
   for(i=2351;i>=0;i--)
-    if(d->sg_buffer[i]!=(unsigned char)'\177')
+    if(((struct sg_info *)d->sg)->dxferp[i]!=(unsigned char)'\177')
       return(((i+3)>>2)<<2);
 
   return(0);
@@ -1023,7 +1145,7 @@
 static int verify_nonzero(cdrom_drive *d){
   long i,flag=0;
   for(i=0;i<2352;i++)
-    if(d->sg_buffer[i]!=0){
+    if(((struct sg_info *)d->sg)->dxferp[i]!=0){
       flag=1;
       break;
     }
@@ -1307,7 +1429,17 @@
   return;
 }
 
-static int check_atapi(cdrom_drive *d){
+static int check_sgio(cdrom_drive *d) {
+  int fd = d->cdda_fd;
+
+#ifdef SG_IO
+  if (fd == check_fd_sgio(fd))
+    return 1;
+#endif
+  return 0;
+}
+
+static int check_atapi(cdrom_drive *d, int using_sgio){
   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 */
@@ -1321,7 +1453,7 @@
     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))
+      if (!using_sgio && ioctl(fd,SG_SET_TRANSFORM,0))
 	cderror(d,"\tCouldn't disable kernel command translation layer\n");
       d->is_atapi=1;
     }else{
@@ -1340,7 +1472,7 @@
   d->is_mmc=0;
   if(mode_sense(d,22,0x2A)==0){
   
-    b=d->sg_buffer;
+    b=((struct sg_info *)d->sg)->dxferp;
     b+=b[3]+4;
     
     if((b[0]&0x3F)==0x2A){
@@ -1380,21 +1512,27 @@
 }
 
 /* request vendor brand and model */
-unsigned char *scsi_inquiry(cdrom_drive *d){
-  memcpy(d->sg_buffer,(char[]){ 0x12,0,0,0,56,0},6);
+unsigned char *scsi_inquiry(cdrom_drive *d) {
+  static char ret[56];
+  struct sg_info *sgi = (struct sg_info *)d->sg;
 
-  if(handle_scsi_cmd(d,6, 0, 56,'\377',1)) {
+  if (sgi->hdr == NULL)
+    scsi_init_drive(d);
+
+  sgi->setup_scsi_cmd(d, SCSI_INQUIRY_6(56), 6, 0, 56);
+  if (sgi->handle_scsi_cmd(d)) {
     cderror(d,"008: Unable to identify CDROM model\n");
-    return(NULL);
+    return NULL;
   }
-  return (d->sg_buffer);
+  memcpy(ret, ((struct sg_info *)d->sg)->dxferp, 56);
+  return ret;
 }
 
-
 int scsi_init_drive(cdrom_drive *d){
-  int ret;
+  int ret, is_sgio;
 
-  check_atapi(d);
+  is_sgio = check_sgio(d);
+  check_atapi(d, is_sgio);
   check_mmc(d);
 
   /* generic Sony type defaults; specialize from here */
@@ -1451,15 +1589,16 @@
   if(d->tracks<1)
     return(d->tracks);
 
-  tweak_SG_buffer(d);
   d->opened=1;
 
   if((ret=verify_read_command(d)))return(ret);
   check_fua_bit(d);
 
   d->error_retry=1;
-  d->sg=realloc(d->sg,d->nsectors*CD_FRAMESIZE_RAW + SG_OFF + 128);
-  d->sg_buffer=d->sg+SG_OFF;
+#if 0
+  ((struct sg_info *)d->sg)=realloc(((struct sg_info *)d->sg),d->nsectors*CD_FRAMESIZE_RAW + SG_OFF + 128);
+  ((struct sg_info *)d->sg)_buffer=((struct sg_info *)d->sg)+SG_OFF;
+#endif
   d->report_all=1;
   return(0);
 }
--- cdparanoia-III-alpha9.8/interface/scsi_cmds.h.sgio	2004-03-30 12:46:03.306332320 -0500
+++ cdparanoia-III-alpha9.8/interface/scsi_cmds.h	2004-03-30 14:09:53.760587032 -0500
@@ -0,0 +1,197 @@
+/******************************************************************
+ * CopyPolicy: GNU General Public License version 2
+ * Copyright 2004 Peter Jones <pjones@redhat.com>
+ * 
+ * macros to generate scsi commands.
+ *
+ ******************************************************************/
+
+#ifndef _SCSI_CMDS_H
+#define _SCSI_CMDS_H 1
+#include <scsi/scsi.h>
+
+/* from the MMC3 spec, rewritten as seperate macros */
+#define LBA_to_M(lba) (lba>=-150?((lba+150)/(60*75)):((lba+450150)/(60*75)))
+#define LBA_to_S(lba) (lba>=-150?((lba+150)/75):((lba+450150)/75))
+#define LBA_to_F(lba) (lba>=-150?(lba+150):(lba+450150))
+
+/* Group 1 (10b) command */
+#define SCSI_TWELVE_BYTE(a,b,c,d,e,f,g,h,i,j,k,l) ((char []) {a,b,c,d,e,f,g,h,i,j,k,l})
+#define SCSI_READ_12(fua, a, l) SCSI_TWELVE_BYTE( \
+	READ_12,		/* READ_10 */ \
+	(fua & 1) << 3,		/* force unit access */ \
+	(a >> 24) & 0xff,	/* lba byte 3 */ \
+	(a >> 16) & 0xff,	/* lba byte 2 */ \
+	(a >> 8) & 0xff,	/* lba byte 1 */ \
+	a & 0xff,		/* lba byte 0 */ \
+	0,			/* reserved */ \
+	(l >> 24) & 0xff,	/* len byte 3 */ \
+	(l >> 16) & 0xff,	/* len byte 2 */ \
+	(l >> 8) & 0xff,	/* len byte 1 */ \
+	l & 0xff,		/* len byte 0 */ \
+	0			/* control */ \
+)
+#define D4_READ_12(a, l) SCSI_TWELVE_BYTE( \
+	0xD4,			/* 0xD4 */ \
+	0,			/* lun */ \
+	0,			/* ? */ \
+	(a >> 16) & 0xff,	/* lba byte 2 */ \
+	(a >> 8) & 0xff,	/* lba byte 1 */ \
+	a & 0xff,		/* lba byte 0 */ \
+	0,			/* reserved */ \
+	0,			/* ? */ \
+	0,			/* ? */ \
+	l & 0xff,		/* len byte 0 */ \
+	0, 0			/* ? */ \
+)
+#define D8_READ_12(a, l) SCSI_TWELVE_BYTE( \
+	0xD8,			/* 0xD4 */ \
+	0,			/* lun */ \
+	0,			/* ? */ \
+	(a >> 16) & 0xff,	/* lba byte 2 */ \
+	(a >> 8) & 0xff,	/* lba byte 1 */ \
+	a & 0xff,		/* lba byte 0 */ \
+	0,			/* reserved */ \
+	0,			/* ? */ \
+	0,			/* ? */ \
+	l & 0xff,		/* len byte 0 */ \
+	0, 0			/* ? */ \
+)
+#define READ_CD_12(a, l) SCSI_TWELVE_BYTE( \
+	0xBE,			/* 0xD4 */ \
+	0,			/* ? */ \
+	(a >> 24) & 0xff,	/* lba byte 3 */ \
+	(a >> 16) & 0xff,	/* lba byte 2 */ \
+	(a >> 8) & 0xff,	/* lba byte 1 */ \
+	a & 0xff,		/* lba byte 0 */ \
+	(l >> 16) & 0xff,	/* len byte 2 */ \
+	(l >> 8) & 0xff,	/* len byte 1 */ \
+	l & 0xff,		/* len byte 0 */ \
+	10,			/* ecc */ \
+	0, 0			/* ? */ \
+)
+#define READ_CD_MSF_12(a, l) SCSI_TWELVE_BYTE( \
+	0xB9,			/* 0xD4 */ \
+	0,			/* ? */ \
+	0,			/* ? */ \
+	LBA_to_M((a)),		/* start M */ \
+	LBA_to_S((a)),		/* start S */ \
+	LBA_to_F((a)),		/* start F */ \
+	LBA_to_M((a)+(l)),	/* start M */ \
+	LBA_to_S((a)+(l)),	/* start S */ \
+	LBA_to_F((a)+(l)),	/* start F */ \
+	10,			/* ecc */ \
+	0, 0			/* ? */ \
+)
+
+#define SCSI_TEN_BYTE(a,b,c,d,e,f,g,h,i,j) ((char []) {a,b,c,d,e,f,g,h,i,j})
+#define SCSI_MODE_SENSE_10(page, size) SCSI_TEN_BYTE( \
+	MODE_SENSE_10,	/* MODE_SENSE */ \
+	0x00,		/* reserved */ \
+	page & 0x3F,		/* page */ \
+	0,		/* reserved */ \
+	0,		/* reserved */ \
+	0,		/* reserved */ \
+	0,		/* reserved */ \
+	0,		/* MSB (0) */ \
+	size,		/* sizeof(modesense - SG_OFF) */ \
+	0		/* reserved */ \
+)
+#define SCSI_MODE_SELECT_10 SCSI_TEN_BYTE( \
+	MODE_SELECT_10,	/* MODE_SELECT */ \
+	0x10,		/* no save page */ \
+	0,		/* reserved */ \
+	0,		/* reserved */ \
+	0,		/* reserved */ \
+	0,		/* reserved */ \
+	0,		/* reserved */ \
+	0,		/* reserved */ \
+	12,		/* sizeof(mode) */ \
+	0		/* reserved */ \
+)
+#define SCSI_READ_TOC(track_number) SCSI_TEN_BYTE( \
+	READ_TOC,	/* READ_TOC */ \
+	0,		/* MSF format */ \
+	0,		\
+	0,		\
+	0,		\
+	0,		\
+	track_number,	/* start track */ \
+	0,		/* len msb */ \
+	12,		/* len lsb */ \
+	0		/* flags */ \
+)
+/* a contribution from Boris for IMS cdd 522 */
+/* check this for ACER/Creative/Foo 525,620E,622E, etc? */
+#define CDD522_READ_TOC(track_number) SCSI_TEN_BYTE( \
+	0xE5,		/* CDD522_READ_TOC */ \
+	0, 0, 0, 0,	/* res */ \
+	track_number,	/* start track */ \
+	0, 0, 0, 0	/* ? */ \
+)
+#define SCSI_READ_10(fua, a, l) SCSI_TEN_BYTE( \
+	READ_10,		/* READ_10 */ \
+	(fua?8:0),		/* force unit access */ \
+	(a >> 24) & 0xff,	/* lba byte 3 */ \
+	(a >> 16) & 0xff,	/* lba byte 2 */ \
+	(a >> 8) & 0xff,	/* lba byte 1 */ \
+	a & 0xff,		/* lba byte 0 */ \
+	0,			/* reserved */ \
+	(l >> 8) & 0xff,	/* len byte 1 */ \
+	l & 0xff,		/* len byte 0 */ \
+	0			/* control */ \
+)
+#define D4_READ_10(a, l) SCSI_TEN_BYTE( \
+	0xD4,			/* 0xD4 */ \
+	0,			/* ? */ \
+	0,			/* ? */ \
+	(a >> 16) & 0xff,	/* lba byte 2 */ \
+	(a >> 8) & 0xff,	/* lba byte 1 */ \
+	a & 0xff,		/* lba byte 0 */ \
+	0,			/* reserved */ \
+	0,			/* ? */ \
+	l & 0xff,		/* len byte 0 */ \
+	0			/* control */ \
+)
+#define D5_READ_10(a, l) SCSI_TEN_BYTE( \
+	0xD5,			/* 0xD5 */ \
+	0,			/* lun */ \
+	0,			/* ? */ \
+	(a >> 16) & 0xff,	/* lba byte 2 */ \
+	(a >> 8) & 0xff,	/* lba byte 1 */ \
+	a & 0xff,		/* lba byte 0 */ \
+	0,			/* reserved */ \
+	0,			/* ? */ \
+	l & 0xff,		/* len byte 0 */ \
+	0			/* control */ \
+)
+
+
+#define SCSI_SIX_BYTE(a,b,c,d,e,f) ((char []) {a,b,c,d,e,f})
+#define SCSI_MODE_SENSE_6(page, size) SCSI_SIX_BYTE( \
+	MODE_SENSE,	/* MODE_SENSE */ \
+	0x00,		/* return block descriptor/lun */ \
+	page & 0x3F,		/* page */ \
+	0,		/* reserved */ \
+	size,		/* sizeof(modesense - SG_OFF) */ \
+	0		/* control */  \
+)
+#define SCSI_MODE_SELECT_6 SCSI_SIX_BYTE( \
+	MODE_SELECT,	/* MODE_SELECT */ \
+	0x10,		/* no save page */ \
+	0,		/* reserved */ \
+	0,		/* reserved */ \
+	12,		/* sizeof(mode) */ \
+	0		/* reserved */ \
+)
+#define SCSI_INQUIRY_6(len) SCSI_SIX_BYTE( \
+	INQUIRY,	/* INQUIRY */ \
+	0, 0, 0,	/* ? */ \
+	len, 0		/* len, ? */ \
+)
+#define SCSI_TEST_UNIT_READY_6 SCSI_SIX_BYTE( \
+	TEST_UNIT_READY,/* TEST_UNIT_READY */ \
+	0, 0, 0, 0,	/* reserved */ \
+	0		/* control */ \
+)
+#endif
 
дизайн и разработка: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
текущий майнтейнер: Michael Shigorin