[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