[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