[xiph-commits] r15193 - in trunk/cdparanoia: . interface
xiphmont at svn.xiph.org
xiphmont at svn.xiph.org
Thu Aug 21 09:08:55 PDT 2008
Author: xiphmont
Date: 2008-08-21 09:08:54 -0700 (Thu, 21 Aug 2008)
New Revision: 15193
Added:
trunk/cdparanoia/cachetest.c
Modified:
trunk/cdparanoia/interface/Makefile.in
trunk/cdparanoia/interface/cdda_interface.h
trunk/cdparanoia/interface/common_interface.c
trunk/cdparanoia/interface/cooked_interface.c
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
Log:
Commit ongoing work for cache changes; backpedalling a bit before moving forward.
Added: trunk/cdparanoia/cachetest.c
===================================================================
--- trunk/cdparanoia/cachetest.c (rev 0)
+++ trunk/cdparanoia/cachetest.c 2008-08-21 16:08:54 UTC (rev 15193)
@@ -0,0 +1,307 @@
+/*
+ * Copyright: GNU Public License 2 applies
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * cdparanoia (C) 2008 Monty <monty at xiph.org>
+ *
+ */
+
+/* we can ask most drives what their various caches' sizes are, but no
+ drive will tell if it caches redbook data. None should, many do,
+ and there's no way in (eg) MMAC/ATAPI to tell a drive not to. SCSI
+ drives have a FUA facility, but it's not clear how many ignore it.
+ For that reason, we need to empirically determine cache size used
+ for reads */
+
+int analyze_timing_and_cache(cdrom_drive *d){
+
+ /* Some assumptions about timing:
+
+ We can't perform cache determination timing based on looking at
+ average transfer times; on slow setups, the speed of a drive
+ reading sectors via PIO will not be reliably distinguishable from
+ the same drive returning data from the cache via pio. We need
+ something even more noticable and reliable: the seek time. A
+ seek will reliably be approximately 1.5 orders of magnitude
+ faster than a sequential sector access or cache hit, and slower
+ systems will also tend to have slower seeks. It is unlikely we'd
+ ever see a seek latency of under ~10ms given the synchronization
+ requirements of a CD and the maximum possible rotational
+ velocity.
+
+ Further complicating things, we have to watch the data collection
+ carefully as we're not always going to be on an unloaded system,
+ and we even have to guard against other apps accessing the drive
+ (something that should never happen on purpose, but could happen
+ by accident). As we know in our testing when seeks should never
+ occur, a sudden seek-sized latency popping up in the middle of a
+ collection is an indication that collection is possibly invalid.
+
+ A second cause of 'spurious latency' would be media damage; if
+ we're consistently hitting latency on the same sector during
+ initial collection, may need to move past it. */
+
+ int i,ret;
+ int firstsector=-1;
+ int lastsector=-1;
+ int firsttest=-1;
+ int lasttest=-1;
+ char buffer[80];
+ int max_retries=20;
+ float median;
+ int offset;
+ int debug = d->private->cache_debug;
+
+ /* set up a default pessimal take on drive behavior */
+ //d->private->cache_backseekflush=0;
+ //d->private->cache_sectors=1200;
+
+ cdmessage(d,"\nChecking drive timing behavior...");
+
+ /* find the longest stretch of available audio data */
+
+ for(i=0;i<d->tracks;i++){
+ if(cdda_track_audiop(d,i+1)==1){
+ if(firsttest == -1)
+ firsttest=cdda_track_firstsector(d,i+1);
+ lasttest=cdda_track_lastsector(d,i+1);
+ if(lasttest-firsttest > lastsector-firstsector){
+ firstsector=firsttest;
+ lastsector=lasttest;
+ }
+ }else{
+ firsttest=-1;
+ lasttest=-1;
+ }
+ }
+
+ if(firstsector==-1){
+ cdmessage(d,"\n\tNo audio on disc; Cannot determine timing behavior...");
+ return -1;
+ }
+
+ /* initial timing data collection of 100 sequential sectors; we need a median, verify an initial seek */
+ {
+ int x;
+ int current=100;
+ int histogram[10000];
+ int latency[current];
+ int retry;
+ offset = (lastsector - firstsector - current)*2/3 + firstsector;
+
+ for(retry=0;retry<max_retries;retry++){
+ int acc=0;
+ int prev=0;
+
+ if(retry){
+ offset-=current+1;
+ offset-=offset/32;
+ }
+ if(offset<firstsector)break;
+
+ memset(histogram,0,sizeof(histogram));
+ if((ret=d->read_audio(d,NULL,offset+current+1,1))<0){
+ /* media error! grr! retry elsewhere */
+ cdmessage(d,"\n\tWARNING: media error; picking new location and trying again.");
+ continue;
+ }
+
+ if(debug)
+ cdmessage(d,"\n\tSector timings (ms):\n\t");
+
+ for(i=0;i<current;i++){
+ if(d->read_audio(d,NULL,offset+i,1)<0){
+ /* media error! grr! retry elsewhere */
+ cdmessage(d,"\n\tWARNING: media error; picking new location and trying again.");
+ break;
+ }
+ x = d->private->last_milliseconds;
+ if(x>9999)x=9999;
+ if(x<0)x=0;
+ if(debug){
+ snprintf(buffer,80,"%d ",x);
+ cdmessage(d,buffer);
+ }
+
+ histogram[x]++;
+ latency[i]=x;
+ }
+ if(i<current){
+ offset-=current+1;
+ continue;
+ }
+
+ for(i=0;i<10000;i++){
+ prev=acc;
+ acc+=histogram[i];
+ if(acc>current/2){
+ if(debug){
+ cdmessage(d,"\n\tSurrounding histogram: ");
+ if(i){
+ snprintf(buffer,80,"%dms:%d ",i-1,acc-histogram[i]);
+ cdmessage(d,buffer);
+ }
+ snprintf(buffer,80,"%dms:%d ",i,acc);
+ cdmessage(d,buffer);
+ if(i<999){
+ snprintf(buffer,80,"%dms:%d ",i+1,acc+histogram[i+1]);
+ cdmessage(d,buffer);
+ }
+ cdmessage(d,"\n");
+ }
+ break;
+ }
+ }
+
+ median = (i*(acc-prev) + (i-1)*prev)/(float)acc;
+
+ if(debug){
+ snprintf(buffer,80,"\n\tsmall seek latency (%d sectors): %d ms",current,latency[0]);
+ cdmessage(d,buffer);
+ snprintf(buffer,80,"\n\tmedian read latency per sector: %.1f ms",median);
+ cdmessage(d,buffer);
+ }
+
+ /* verify slow spinup did not compromise median */
+ for(i=1;i<current;i++)
+ if(latency[i]>latency[i-1] || latency[i]<=(median+1.))break;
+ if(i>5){
+ if(debug)
+ cdmessage(d,"\n\tDrive appears to spin up slowly... retrying...");
+ offset-=current+1;
+ continue;
+ }
+
+ /* verify against spurious latency; any additional 5x blocks that
+ are not continuous with read start */
+ acc=0;
+ if(median<.6)median=.6;
+ for(i=5;i<current;i++)
+ if(latency[i]>median*10)acc++;
+
+ if(acc){
+ cderror(d,"\n\tWARNING: Read timing displayed bursts of unexpected"
+ "\n\tlatency; retrying for a clean read.\n");
+ continue;
+ }
+
+ break;
+ }
+
+ if(offset<firstsector){
+ cderror(d,"\n500: Unable to find sufficiently large area of"
+ "\n\tgood media to perform timing tests. Aborting.\n");
+ return -500;
+ }
+ if(retry==max_retries){
+ cderror(d,"\n500: Too many retries; aborting analysis.\n");
+ return -500;
+ }
+ }
+
+ /* look to see if drive is caching at all; read first sector N
+ times, if any reads are near or under the median latency, we're
+ caching */
+ {
+ for(i=0;i<max_retries;i++){
+ if(d->read_audio(d,NULL,offset,1)==1){
+ if(d->private->last_milliseconds<median*10) break;
+
+ }else{
+ /* error handling */
+ }
+ }
+
+ if(i<max_retries){
+ cdmessage(d,"\n\tCaching test result: DRIVE IS CACHING (bad)\n");
+ }else{
+ cdmessage(d,"\n\tCaching test result: Drive is not caching (good)\n");
+ d->private->cache_sectors=0;
+ return 0;
+ }
+ }
+
+
+
+
+
+
+
+ /* bisection search on cache size */
+
+ int lo=1;
+ int hi=15000;
+ int current=lo;
+ int under=1;
+ while(current <= hi && under){
+ int offset = (lastsector - firstsector - (current+1))/2+firstsector;
+ int i,j;
+ under=0;
+
+ {
+ char buffer[80];
+ snprintf(buffer,80,"\n\tTesting reads for caching (%d sectors):\n\t",current);
+ cdmessage(d,buffer);
+ }
+
+ for(i=0;i<10;i++){
+ int sofar=0;
+ int fulltime=0;
+
+ while(sofar<current){
+ for(j=0;;j++){
+ int readsectors = d->read_audio(d,NULL,offset+sofar,1);
+ if(readsectors<=0){
+ if(j==2){
+ d->enable_cdda(d,0);
+ cdmessage(d,"\n\tRead error while performing drive cache checks; aborting test.\n");
+ return(-1);
+ }
+ }else{
+ if(d->private->last_milliseconds==-1){
+ if(j==2){
+ d->enable_cdda(d,0);
+ cdmessage(d,"\n\tTiming error while performing drive cache checks; aborting test.\n");
+ return(-1);
+ }
+ }else{
+
+ if(sofar==0){
+ fprintf(stderr,">%d:%dms ",readsectors, d->private->last_milliseconds);
+ fulltime = d->private->last_milliseconds;
+ }
+ sofar+=readsectors;
+ break;
+ }
+ }
+ }
+ }
+ if(fulltime < median*10) under=1;
+ }
+ cdmessage(d,"\n");
+
+ current*=2;
+ }
+
+
+
+
+
+ /* XXXXXX IN PROGRESS */
+ cdmessage(d,"\n");
+ return 0;
+}
+
Modified: trunk/cdparanoia/interface/Makefile.in
===================================================================
--- trunk/cdparanoia/interface/Makefile.in 2008-08-19 22:44:14 UTC (rev 15192)
+++ trunk/cdparanoia/interface/Makefile.in 2008-08-21 16:08:54 UTC (rev 15193)
@@ -15,7 +15,7 @@
LDFLAGS=@LDFLAGS@ $(FLAGS)
AR=@AR@
RANLIB=@RANLIB@
-LIBS = -lm
+LIBS = -lm -lrt
CPPFLAGS+=-D_REENTRANT
OFILES = scan_devices.o common_interface.o cooked_interface.o interface.o\
Modified: trunk/cdparanoia/interface/cdda_interface.h
===================================================================
--- trunk/cdparanoia/interface/cdda_interface.h 2008-08-19 22:44:14 UTC (rev 15192)
+++ trunk/cdparanoia/interface/cdda_interface.h 2008-08-21 16:08:54 UTC (rev 15193)
@@ -121,10 +121,8 @@
/******** Drive oriented functions */
-extern int cdda_cache_sectors(cdrom_drive *d);
extern int cdda_speed_set(cdrom_drive *d, int speed);
extern void cdda_verbose_set(cdrom_drive *d,int err_action, int mes_action);
-extern void cdda_debug_set(cdrom_drive *d,int active);
extern char *cdda_messages(cdrom_drive *d);
extern char *cdda_errors(cdrom_drive *d);
Modified: trunk/cdparanoia/interface/common_interface.c
===================================================================
--- trunk/cdparanoia/interface/common_interface.c 2008-08-19 22:44:14 UTC (rev 15192)
+++ trunk/cdparanoia/interface/common_interface.c 2008-08-21 16:08:54 UTC (rev 15193)
@@ -168,294 +168,6 @@
}
}
-/* we can ask most drives what their various caches' sizes are, but no
- drive will tell if it caches redbook data. None should, many do,
- and there's no way in (eg) MMAC/ATAPI to tell a drive not to. SCSI
- drives have a FUA facility, but it's not clear how many ignore it.
- For that reason, we need to empirically determine cache size used
- for reads */
-
-int analyze_timing_and_cache(cdrom_drive *d){
-
- /* Some assumptions about timing:
-
- We can't perform cache determination timing based on looking at
- average transfer times; on slow setups, the speed of a drive
- reading sectors via PIO will not be reliably distinguishable from
- the same drive returning data from the cache via pio. We need
- something even more noticable and reliable: the seek time. A
- seek will reliably be approximately 1.5 orders of magnitude
- faster than a sequential sector access or cache hit, and slower
- systems will also tend to have slower seeks. It is unlikely we'd
- ever see a seek latency of under ~10ms given the synchronization
- requirements of a CD and the maximum possible rotational
- velocity.
-
- Further complicating things, we have to watch the data collection
- carefully as we're not always going to be on an unloaded system,
- and we even have to guard against other apps accessing the drive
- (something that should never happen on purpose, but could happen
- by accident). As we know in our testing when seeks should never
- occur, a sudden seek-sized latency popping up in the middle of a
- collection is an indication that collection is possibly invalid.
-
- A second cause of 'spurious latency' would be media damage; if
- we're consistently hitting latency on the same sector during
- initial collection, may need to move past it. */
-
- int i,ret;
- int firstsector=-1;
- int lastsector=-1;
- int firsttest=-1;
- int lasttest=-1;
- char buffer[80];
- int max_retries=20;
- float median;
- int offset;
- int debug = d->private->cache_debug;
-
- /* set up a default pessimal take on drive behavior */
- d->private->cache_backseekflush=0;
- d->private->cache_sectors=1200;
-
- cdmessage(d,"\nChecking drive timing behavior...");
-
- /* find the longest stretch of available audio data */
-
- for(i=0;i<d->tracks;i++){
- if(cdda_track_audiop(d,i+1)==1){
- if(firsttest == -1)
- firsttest=cdda_track_firstsector(d,i+1);
- lasttest=cdda_track_lastsector(d,i+1);
- if(lasttest-firsttest > lastsector-firstsector){
- firstsector=firsttest;
- lastsector=lasttest;
- }
- }else{
- firsttest=-1;
- lasttest=-1;
- }
- }
-
- if(firstsector==-1){
- cdmessage(d,"\n\tNo audio on disc; Cannot determine timing behavior...");
- return -1;
- }
-
- /* initial timing data collection of 100 sequential sectors; we need a median, verify an initial seek */
- {
- int x;
- int current=100;
- int histogram[10000];
- int latency[current];
- int retry;
- offset = (lastsector - firstsector - current)*2/3 + firstsector;
-
- for(retry=0;retry<max_retries;retry++){
- int acc=0;
- int prev=0;
-
- if(retry){
- offset-=current+1;
- offset-=offset/32;
- }
- if(offset<firstsector)break;
-
- memset(histogram,0,sizeof(histogram));
- if((ret=d->read_audio(d,NULL,offset+current+1,1))<0){
- /* media error! grr! retry elsewhere */
- cdmessage(d,"\n\tWARNING: media error; picking new location and trying again.");
- continue;
- }
-
- if(debug)
- cdmessage(d,"\n\tSector timings (ms):\n\t");
-
- for(i=0;i<current;i++){
- if(d->read_audio(d,NULL,offset+i,1)<0){
- /* media error! grr! retry elsewhere */
- cdmessage(d,"\n\tWARNING: media error; picking new location and trying again.");
- break;
- }
- x = d->private->last_milliseconds;
- if(x>9999)x=9999;
- if(x<0)x=0;
- if(debug){
- snprintf(buffer,80,"%d ",x);
- cdmessage(d,buffer);
- }
-
- histogram[x]++;
- latency[i]=x;
- }
- if(i<current){
- offset-=current+1;
- continue;
- }
-
- for(i=0;i<10000;i++){
- prev=acc;
- acc+=histogram[i];
- if(acc>current/2){
- if(debug){
- cdmessage(d,"\n\tSurrounding histogram: ");
- if(i){
- snprintf(buffer,80,"%dms:%d ",i-1,acc-histogram[i]);
- cdmessage(d,buffer);
- }
- snprintf(buffer,80,"%dms:%d ",i,acc);
- cdmessage(d,buffer);
- if(i<999){
- snprintf(buffer,80,"%dms:%d ",i+1,acc+histogram[i+1]);
- cdmessage(d,buffer);
- }
- cdmessage(d,"\n");
- }
- break;
- }
- }
-
- median = (i*(acc-prev) + (i-1)*prev)/(float)acc;
-
- if(debug){
- snprintf(buffer,80,"\n\tsmall seek latency (%d sectors): %d ms",current,latency[0]);
- cdmessage(d,buffer);
- snprintf(buffer,80,"\n\tmedian read latency per sector: %.1f ms",median);
- cdmessage(d,buffer);
- }
-
- /* verify slow spinup did not compromise median */
- for(i=1;i<current;i++)
- if(latency[i]>latency[i-1] || latency[i]<=(median+1.))break;
- if(i>5){
- if(debug)
- cdmessage(d,"\n\tDrive appears to spin up slowly... retrying...");
- offset-=current+1;
- continue;
- }
-
- /* verify against spurious latency; any additional 5x blocks that
- are not continuous with read start */
- acc=0;
- if(median<.6)median=.6;
- for(i=5;i<current;i++)
- if(latency[i]>median*10)acc++;
-
- if(acc){
- cderror(d,"\n\tWARNING: Read timing displayed bursts of unexpected"
- "\n\tlatency; retrying for a clean read.\n");
- continue;
- }
-
- break;
- }
-
- if(offset<firstsector){
- cderror(d,"\n500: Unable to find sufficiently large area of"
- "\n\tgood media to perform timing tests. Aborting.\n");
- return -500;
- }
- if(retry==max_retries){
- cderror(d,"\n500: Too many retries; aborting analysis.\n");
- return -500;
- }
- }
-
- /* look to see if drive is caching at all; read first sector N
- times, if any reads are near or under the median latency, we're
- caching */
- {
- for(i=0;i<max_retries;i++){
- if(d->read_audio(d,NULL,offset,1)==1){
- if(d->private->last_milliseconds<median*10) break;
-
- }else{
- /* error handling */
- }
- }
-
- if(i<max_retries){
- cdmessage(d,"\n\tCaching test result: DRIVE IS CACHING (bad)\n");
- }else{
- cdmessage(d,"\n\tCaching test result: Drive is not caching (good)\n");
- d->private->cache_sectors=0;
- return 0;
- }
- }
-
-
-
-
-
-
-
- /* bisection search on cache size */
-
- int lo=1;
- int hi=15000;
- int current=lo;
- int under=1;
- d->nsectors=1;
- while(current <= hi && under){
- int offset = (lastsector - firstsector - (current+1))/2+firstsector;
- int i,j;
- under=0;
-
- {
- char buffer[80];
- snprintf(buffer,80,"\n\tTesting reads for caching (%d sectors):\n\t",current);
- cdmessage(d,buffer);
- }
-
- for(i=0;i<10;i++){
- int sofar=0;
- int fulltime=0;
-
- while(sofar<current){
- for(j=0;;j++){
- int readsectors = d->read_audio(d,NULL,offset+sofar,current-sofar);
- if(readsectors<=0){
- if(j==2){
- d->enable_cdda(d,0);
- cdmessage(d,"\n\tRead error while performing drive cache checks; aborting test.\n");
- return(-1);
- }
- }else{
- if(d->private->last_milliseconds==-1){
- if(j==2){
- d->enable_cdda(d,0);
- cdmessage(d,"\n\tTiming error while performing drive cache checks; aborting test.\n");
- return(-1);
- }
- }else{
-
- if(sofar==0){
- fprintf(stderr,">%d:%dms ",readsectors, d->private->last_milliseconds);
- fulltime = d->private->last_milliseconds;
- }
- sofar+=readsectors;
- break;
- }
- }
- }
- }
- if(fulltime < median*10) under=1;
- }
- cdmessage(d,"\n");
-
- current*=2;
- }
-
-
-
-
-
- /* XXXXXX IN PROGRESS */
- cdmessage(d,"\n");
- return 0;
-}
-
-
/************************************************************************/
/* Here we fix up a couple of things that will never happen. yeah,
right. The multisession stuff is from Hannu's code; it assumes it
Modified: trunk/cdparanoia/interface/cooked_interface.c
===================================================================
--- trunk/cdparanoia/interface/cooked_interface.c 2008-08-19 22:44:14 UTC (rev 15192)
+++ trunk/cdparanoia/interface/cooked_interface.c 2008-08-21 16:08:54 UTC (rev 15193)
@@ -9,17 +9,17 @@
#include "low_interface.h"
#include "common_interface.h"
#include "utils.h"
-
+#include <time.h>
static int timed_ioctl(cdrom_drive *d, int fd, int command, void *arg){
- struct timeval tv1;
- struct timeval tv2;
- int ret1=gettimeofday(&tv1,NULL);
+ struct timespec tv1;
+ struct timespec tv2;
+ int ret1=clock_gettime(CLOCK_MONOTONIC,&tv1);
int ret2=ioctl(fd, command,arg);
- int ret3=gettimeofday(&tv2,NULL);
+ int ret3=clock_gettime(CLOCK_MONOTONIC,&tv2);
if(ret1<0 || ret3<0){
d->private->last_milliseconds=-1;
}else{
- d->private->last_milliseconds = (tv2.tv_sec-tv1.tv_sec)*1000. + (tv2.tv_usec-tv1.tv_usec)/1000.;
+ d->private->last_milliseconds = (tv2.tv_sec-tv1.tv_sec)*1000. + (tv2.tv_nsec-tv1.tv_nsec)/1000000.;
}
return ret2;
}
@@ -70,7 +70,6 @@
return(--tracks); /* without lead-out */
}
-
/* Set operating speed */
static int cooked_setspeed(cdrom_drive *d, int speed)
{
@@ -218,11 +217,6 @@
}
}
-
-int cooked_preinit_drive(cdrom_drive *d){
- d->set_speed = cooked_setspeed;
-}
-
/* set function pointers to use the ioctl routines */
int cooked_init_drive (cdrom_drive *d){
int ret;
@@ -280,6 +274,7 @@
d->enable_cdda = Dummy;
d->read_audio = cooked_read;
d->read_toc = cooked_readtoc;
+ d->set_speed = cooked_setspeed;
ret=d->tracks=d->read_toc(d);
if(d->tracks<1)
return(ret);
Modified: trunk/cdparanoia/interface/interface.c
===================================================================
--- trunk/cdparanoia/interface/interface.c 2008-08-19 22:44:14 UTC (rev 15192)
+++ trunk/cdparanoia/interface/interface.c 2008-08-21 16:08:54 UTC (rev 15193)
@@ -90,7 +90,6 @@
/* d->select_speed(d,d->maxspeed); most drives are full speed by default */
if(d->bigendianp==-1)d->bigendianp=data_bigendianp(d);
- analyze_timing_and_cache(d);
return(0);
}
@@ -134,10 +133,6 @@
d->errordest=err_action;
}
-void cdda_debug_set(cdrom_drive *d,int active){
- d->private->cache_debug=active;
-}
-
extern char *cdda_messages(cdrom_drive *d){
char *ret=d->messagebuf;
d->messagebuf=NULL;
Modified: trunk/cdparanoia/interface/low_interface.h
===================================================================
--- trunk/cdparanoia/interface/low_interface.h 2008-08-19 22:44:14 UTC (rev 15192)
+++ trunk/cdparanoia/interface/low_interface.h 2008-08-21 16:08:54 UTC (rev 15193)
@@ -99,11 +99,9 @@
struct cdda_private_data {
struct sg_header *sg_hd;
unsigned char *sg_buffer; /* points into sg_hd */
-
int last_milliseconds;
- int cache_backseekflush;
- int cache_sectors;
- int cache_debug;
+
+ int (*cache_clear) (struct cdrom_drive *d, int lba, int sectors);
};
#define MAX_RETRIES 8
@@ -111,10 +109,8 @@
#define MIN_BIG_BUFF_SIZE 4096
#define SG_OFF sizeof(struct sg_header)
-extern int cooked_preinit_drive (cdrom_drive *d);
extern int cooked_init_drive (cdrom_drive *d);
extern unsigned char *scsi_inquiry (cdrom_drive *d);
-extern int scsi_preinit_drive (cdrom_drive *d);
extern int scsi_init_drive (cdrom_drive *d);
#ifdef CDDA_TEST
extern int test_init_drive (cdrom_drive *d);
Modified: trunk/cdparanoia/interface/scan_devices.c
===================================================================
--- trunk/cdparanoia/interface/scan_devices.c 2008-08-19 22:44:14 UTC (rev 15192)
+++ trunk/cdparanoia/interface/scan_devices.c 2008-08-21 16:08:54 UTC (rev 15193)
@@ -265,8 +265,6 @@
d->nsectors=-1;
d->private=calloc(1,sizeof(*d->private));
idmessage(messagedest,messages,"\t\tCDROM sensed: %s\n",description);
-
- cooked_preinit_drive(d);
return(d);
}
@@ -755,8 +753,6 @@
strscat(d->drive_model,p+32,4);
idmessage(messagedest,messages,"\nCDROM model sensed sensed: %s",d->drive_model);
-
- scsi_preinit_drive(d);
return(d);
cdda_identify_scsi_fail:
Modified: trunk/cdparanoia/interface/scsi_interface.c
===================================================================
--- trunk/cdparanoia/interface/scsi_interface.c 2008-08-19 22:44:14 UTC (rev 15192)
+++ trunk/cdparanoia/interface/scsi_interface.c 2008-08-21 16:08:54 UTC (rev 15193)
@@ -11,6 +11,20 @@
#include "low_interface.h"
#include "common_interface.h"
#include "utils.h"
+#include <time.h>
+static int timed_ioctl(cdrom_drive *d, int fd, int command, void *arg){
+ struct timespec tv1;
+ struct timespec tv2;
+ int ret1=clock_gettime(CLOCK_MONOTONIC,&tv1);
+ int ret2=ioctl(fd, command,arg);
+ int ret3=clock_gettime(CLOCK_MONOTONIC,&tv2);
+ if(ret1<0 || ret3<0){
+ d->private->last_milliseconds=-1;
+ }else{
+ d->private->last_milliseconds = (tv2.tv_sec-tv1.tv_sec)*1000. + (tv2.tv_nsec-tv1.tv_nsec)/1000000.;
+ }
+ return ret2;
+}
/* hook */
static int Dummy (cdrom_drive *d,int s){
@@ -60,7 +74,7 @@
* still fail the wrong way. This needs some kernel-land investigation.
*/
if (!getenv("CDDA_IGNORE_BUFSIZE_LIMIT")) {
- cur=(cur>1024*32?1024*32:cur);
+ cur=(cur>1024*64?1024*64:cur);
}
d->nsectors=cur/CD_FRAMESIZE_RAW;
d->bigbuff=cur;
@@ -110,9 +124,7 @@
char ASC = sbp[12];
char ASCQ = sbp[13];
- if(status==0)
- return 0;
-
+ if(status==0)return 0;
if(status==8)return TR_BUSY;
if (sbp[0]) {
@@ -163,8 +175,8 @@
unsigned char bytefill,
int bytecheck,
unsigned char *sense_buffer){
- struct timeval tv1;
- struct timeval tv2;
+ struct timespec tv1;
+ struct timespec tv2;
int tret1,tret2;
int status = 0;
struct sg_header *sg_hd=d->private->sg_hd;
@@ -225,7 +237,7 @@
}
sigprocmask (SIG_BLOCK, &(d->sigset), NULL );
- tret1=gettimeofday(&tv1,NULL);
+ tret1=clock_gettime(CLOCK_MONOTONIC,&tv1);
errno=0;
status = write(d->cdda_fd, sg_hd, writebytes );
@@ -271,7 +283,7 @@
}
}
- tret2=gettimeofday(&tv2,NULL);
+ tret2=clock_gettime(CLOCK_MONOTONIC,&tv2);
errno=0;
status = read(d->cdda_fd, sg_hd, SG_OFF + out_size);
sigprocmask ( SIG_UNBLOCK, &(d->sigset), NULL );
@@ -310,7 +322,7 @@
if(tret1<0 || tret2<0){
d->private->last_milliseconds=-1;
}else{
- d->private->last_milliseconds = (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000;
+ d->private->last_milliseconds = (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_nsec-tv1.tv_nsec)/1000000;
}
return(0);
}
@@ -366,7 +378,7 @@
hdr.dxfer_direction = out_size ? SG_DXFER_FROM_DEV : SG_DXFER_NONE;
errno = 0;
- status = ioctl(d->ioctl_fd, SG_IO, &hdr);
+ status = timed_ioctl(d,d->ioctl_fd, SG_IO, &hdr);
if (status >= 0 && hdr.status){
status = check_sbp_error(hdr.status,hdr.sbp);
if(status) return status;
@@ -392,8 +404,10 @@
return(TR_ILLEGAL);
}
}
-
- d->private->last_milliseconds = hdr.duration;
+
+ /* Can't rely on .duration because we can't be certain kernel has HZ set to something useful */
+ /* d->private->last_milliseconds = hdr.duration; */
+
errno = 0;
return 0;
}
@@ -773,14 +787,40 @@
unsigned char cmd[12]={0xBB, 0, 0, 0, 0xff, 0xff, 0, 0, 0, 0};
unsigned char sense[SG_MAX_SENSE];
- speed=speed*44100*4/1024;
+ if(speed>=0)
+ speed=speed*44100*4/1024;
+ else
+ speed=-1;
cmd[2] = (speed >> 8) & 0xFF;
cmd[3] = (speed) & 0xFF;
- ret=handle_scsi_cmd(d,cmd,12,0,0,0,0,sense);
+ return handle_scsi_cmd(d,cmd,12,0,0,0,0,sense);
- return check_sbp_error(ret,sense);
}
+/* 'abuse' the set read ahead into manipulating the cache */
+static int mmc_cache_clear (cdrom_drive *d, int begin, int sectors){
+ int ret;
+ char b[80];
+ unsigned char cmd[12]={0xA7, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ unsigned char sense[SG_MAX_SENSE];
+ int end=begin+sectors;
+ begin--;
+
+ if(begin<0)return -1;
+
+ cmd[2] = (begin >> 24) & 0xFF;
+ cmd[3] = (begin >> 16) & 0xFF;
+ cmd[4] = (begin >> 8) & 0xFF;
+ cmd[5] = (begin) & 0xFF;
+
+ cmd[6] = (end >> 24) & 0xFF;
+ cmd[7] = (end >> 16) & 0xFF;
+ cmd[8] = (end >> 8) & 0xFF;
+ cmd[9] = (end) & 0xFF;
+
+ return handle_scsi_cmd(d,cmd,12,0,0,0,0,sense);
+}
+
/* 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, unsigned char *sense){
@@ -1154,6 +1194,7 @@
}
if(i>0)return(i);
+
}else
break;
}
@@ -1526,42 +1567,63 @@
return(-6);
}
-static void check_fua_bit(cdrom_drive *d){
- int16_t *buff=malloc(CD_FRAMESIZE_RAW);
+static void check_cache(cdrom_drive *d){
long i;
- if(d->read_audio==scsi_read_mmc)return;
- if(d->read_audio==scsi_read_mmc2)return;
- if(d->read_audio==scsi_read_mmc3)return;
- if(d->read_audio==scsi_read_mmcB)return;
- if(d->read_audio==scsi_read_mmc2B)return;
- if(d->read_audio==scsi_read_mmc3B)return;
+ if(d->read_audio==scsi_read_mmc ||
+ d->read_audio==scsi_read_mmc2 ||
+ d->read_audio==scsi_read_mmc3 ||
+ d->read_audio==scsi_read_mmcB ||
+ d->read_audio==scsi_read_mmc2B ||
+ d->read_audio==scsi_read_mmc3B){
- cdmessage(d,"This command set may use a Force Unit Access bit.");
- cdmessage(d,"\nChecking drive for FUA bit support...\n");
+ cdmessage(d,"\nThis command set may allow read cache control.");
+ cdmessage(d,"\nChecking drive for SET READ AHEAD command...\n");
+
+ for(i=1;i<=d->tracks;i++){
+ if(cdda_track_audiop(d,i)==1){
+ long firstsector=cdda_track_firstsector(d,i);
+ long lastsector=cdda_track_lastsector(d,i);
+
+ if(mmc_cache_clear(d,firstsector+1,lastsector-firstsector-1)==0){
+ cdmessage(d,"\tDrive accepted SET READ AHEAD command.\n");
+ d->private->cache_clear=mmc_cache_clear;
+ return;
+ }
+ }
+ }
+ cdmessage(d,"\tDrive rejected SET READ AHEAD command; using fallback.\n");
- d->enable_cdda(d,1);
- d->fua=1;
-
- for(i=1;i<=d->tracks;i++){
- if(cdda_track_audiop(d,i)==1){
- long firstsector=cdda_track_firstsector(d,i);
- long lastsector=cdda_track_lastsector(d,i);
- long sector=(firstsector+lastsector)>>1;
-
- if(d->read_audio(d,buff,sector,1)>0){
- cdmessage(d,"\tDrive accepted FUA bit.\n");
- d->enable_cdda(d,0);
- free(buff);
- return;
+ }else{
+
+ cdmessage(d,"This command set may use a Force Unit Access bit.");
+ cdmessage(d,"\nChecking drive for FUA bit support...\n");
+
+ d->enable_cdda(d,1);
+ d->fua=1;
+
+ for(i=1;i<=d->tracks;i++){
+ if(cdda_track_audiop(d,i)==1){
+ long firstsector=cdda_track_firstsector(d,i);
+ long lastsector=cdda_track_lastsector(d,i);
+ long sector=(firstsector+lastsector)>>1;
+
+ if(d->read_audio(d,NULL,sector,1)>0){
+ cdmessage(d,"\tDrive accepted FUA bit.\n");
+ d->enable_cdda(d,0);
+ return;
+ }
}
}
+
+ d->fua=0;
+ cdmessage(d,"\tDrive rejected FUA bit.\n");
+
+ /* we only use the FUA bit as a possible extra layer of
+ redundancy; too many drives accept it, but still don't force
+ unit access. Still use the old cachebusting algo. */
+ return;
}
-
- d->fua=0;
- cdmessage(d,"\tDrive rejected FUA bit.\n");
- free(buff);
- return;
}
static int check_atapi(cdrom_drive *d){
@@ -1653,11 +1715,6 @@
return (d->private->sg_buffer);
}
-int scsi_preinit_drive(cdrom_drive *d){
- d->set_speed = scsi_set_speed;
- return 0;
-}
-
int scsi_init_drive(cdrom_drive *d){
int ret;
@@ -1701,6 +1758,7 @@
d->read_toc = (!memcmp(d->drive_model, "IMS", 3) && !d->is_atapi) ? scsi_read_toc2 :
scsi_read_toc;
+ d->set_speed = scsi_set_speed;
if(!d->is_atapi){
unsigned sector_size= get_orig_sectorsize(d);
@@ -1720,7 +1778,7 @@
d->opened=1;
if((ret=verify_read_command(d)))return(ret);
- check_fua_bit(d);
+ check_cache(d);
d->error_retry=1;
d->private->sg_hd=realloc(d->private->sg_hd,d->nsectors*CD_FRAMESIZE_RAW + SG_OFF + 128);
Modified: trunk/cdparanoia/main.c
===================================================================
--- trunk/cdparanoia/main.c 2008-08-19 22:44:14 UTC (rev 15192)
+++ trunk/cdparanoia/main.c 2008-08-21 16:08:54 UTC (rev 15193)
@@ -38,7 +38,6 @@
#include "version.h"
#include "header.h"
-static int verbosedebug;
extern int verbose;
extern int quiet;
@@ -216,8 +215,6 @@
"OPTIONS:\n"
" -v --verbose : extra verbose operation\n"
-" -vv --verbose-debug : enable additional analysis debugging\n"
-" and testing output for developers\n"
" -q --quiet : quiet operation\n"
" -e --stderr-progress : force output of progress information to\n"
" stderr (for wrapper scripts)\n"
@@ -609,7 +606,6 @@
{"output-aifc",no_argument,NULL,'a'},
{"batch",no_argument,NULL,'B'},
{"verbose",no_argument,NULL,'v'},
- {"verbose-debug",no_argument,NULL,'*'},
{"quiet",no_argument,NULL,'q'},
{"version",no_argument,NULL,'V'},
{"query",no_argument,NULL,'Q'},
@@ -743,22 +739,14 @@
output_endian=1;
break;
case 'v':
- if(verbose==CDDA_MESSAGE_PRINTIT)
- verbosedebug=1;
verbose=CDDA_MESSAGE_PRINTIT;
quiet=0;
break;
- case '*':
- verbosedebug=1;
- verbose=CDDA_MESSAGE_PRINTIT;
- quiet=0;
- break;
case 's':
search=1;
break;
case 'q':
verbose=CDDA_MESSAGE_FORGETIT;
- verbosedebug=0;
quiet=1;
break;
case 'e':
@@ -906,8 +894,6 @@
else
cdda_verbose_set(d,CDDA_MESSAGE_PRINTIT,CDDA_MESSAGE_FORGETIT);
- cdda_debug_set(d,verbosedebug);
-
/* possibly force hand on endianness of drive, sector request size */
if(force_cdrom_endian!=-1){
d->bigendianp=force_cdrom_endian;
@@ -951,19 +937,6 @@
}
}
- /* We want the speed set to apply to cache and timing testing */
- if(force_cdrom_speed!=0){
- char buf[80];
- sprintf(buf,"\nAttempting to set speed to %dx... ",force_cdrom_speed);
- report(buf);
- if(cdda_speed_set(d,force_cdrom_speed)){
- report("\tFAILED.");
- exit(1);
- }else{
- report("\tdrive returned OK.");
- }
- }
-
switch(cdda_open(d)){
case -2:case -3:case -4:case -5:
report("\nUnable to open disc. Is there an audio CD in the drive?");
@@ -978,6 +951,18 @@
exit(1);
}
+ if(force_cdrom_speed!=0){
+ char buf[80];
+ sprintf(buf,"\nAttempting to set speed to %dx... ",force_cdrom_speed);
+ report(buf);
+ if(cdda_speed_set(d,force_cdrom_speed)){
+ report("\tFAILED.");
+ exit(1);
+ }else{
+ report("\tdrive returned OK.");
+ }
+ }
+
/* Dump the TOC */
if(query_only || verbose)display_toc(d);
if(query_only)exit(0);
More information about the commits
mailing list