BERTRAND Joël <[EMAIL PROTECTED]> wrote:

Hi,

> I use a Snapscan 1236s with xsane on an i386 (K6-III/400, 256 MB,
> Adaptec 2940U, kernel 2.6.20.1) without any trouble. If I use the same
> scanner on an U2 (2xUltraSPARC-II/296 MHz, 2 GB, Happymeal-ESP, kernel
> 2.6.21-rc7), sane-find-scanner does not find any scanner but this
> scanner is shown in /proc/scsi/scsi. Both stations run lenny.

[Summary for sane-devel]
This is the old "Linux SG3 interface does not work in
32/64bit mixed environments". The most recent reference to this
problem I could find is the discussion that took place on sane-devel
(and some other lists at the same time) back in early 2003.


This bug made me dig a bit into this issue this afternoon; I don't
remember reading any of that yet, so here is what I found:

 - sanei_scsi doesn't work using the Linux SG3 interface in 32/64bit
   mixed environments
 - sg3-utils' sg_inq, which does something equivalent to what
   sane-find-scanner does, that is sending SCSI INQUIRY commands, does
   work

As it turns out, sanei_scsi uses the asynchronous SG3 interface (using
read/write calls on /dev/sgX), and sg3-utils now uses the SG_IO ioctl
interface.

The SG_IO ioctl benefits from the 32/64bit ioctl compatibility layer,
hence sg3-utils has no problems in a 32/64bit mixed environment.


So, in a nutshell, sanei_scsi needs to move to SG_IO instead of the
current interface if we want to support the more and more common mixed
environment case.


Attached is a proof of concept patch, tested on a Microtek scanner
(microtek2 backend); the scanner works like a charm with this code, it
feels like it even goes faster than using the async interface on the
same machine (with a 32bit kernel, last time I tried it took something
like 10 minutes to scan an A4 page with the default settings on an idle
machine, it's under 1 minute now).


I am not entirely sure that my patch behaves properly when an error
occurs; I don't know anything about sanei_scsi (well, didn't know
anything until today), so if someone familiar with sanei_scsi could
take a look, maybe we could fix this bug for good :-)

(note: with the SG_IO ioctl, we're loosing command queuing to the
scanner; doesn't look terribly important to me given how my test
turned out ...)


Bertrand, feel free to try this patch on your sparc64; as I said, it
works fine here (at least as long as nothing goes wrong ;), but better
keep your finger on the scanner's power button just in case. Tell us
how it goes.


That's a saturday afternoon well spent.

JB.

-- 
 Julien BLACHE - Debian & GNU/Linux Developer - <[EMAIL PROTECTED]> 
 
 Public key available on <http://www.jblache.org> - KeyID: F5D6 5169 
 GPG Fingerprint : 935A 79F1 C8B3 3521 FD62 7CC7 CD61 4FD7 F5D6 5169 

Switch sanei_scsi to the SG_IO ioctl interface, instead of the
asynchronous SG3 read/write interface.

Makes it possible to use SCSI scanners in 32/64bit mixed environments,
thanks to the ioctl 32bit compatibility layer, which is NOT possible
using the SG3 interface.

  -- Julien BLACHE <[EMAIL PROTECTED]>

--- sanei_scsi.c	2007-02-07 08:16:53.000000000 +0100
+++ sanei_scsi.c	2007-04-28 20:16:03.430381793 +0200
@@ -207,10 +207,6 @@
 # include <ddk/ntddscsi.h>
 #endif
 
-#ifdef DISABLE_LINUX_SG_IO
-#undef SG_IO
-#endif /* DISABLE_LINUX_SG_IO */
-
 #ifndef USE
 # define USE STUBBED_INTERFACE
 #endif
@@ -1852,6 +1848,7 @@
   fdparms *fdp;
   struct req *rp;
   int retries;
+  int ret;
 
   if (!req)
     return;
@@ -1876,6 +1873,7 @@
 	      ATOMIC (rp->running = 1;
 		      nwritten = write (rp->fd, &rp->sgdata.cdb,
 					rp->sgdata.cdb.hdr.pack_len);
+		      ret = 0;
 		      if (nwritten != rp->sgdata.cdb.hdr.pack_len)
 		      {
 		      /* ENOMEM can easily happen, if both command queueing
@@ -1898,9 +1896,9 @@
 	  else
 	    {
 	      ATOMIC (rp->running = 1;
-		      nwritten =
-		      write (rp->fd, &rp->sgdata.sg3.hdr, sizeof (Sg_io_hdr));
-		      if (nwritten < 0)
+		      ret = ioctl(rp->fd, SG_IO, &rp->sgdata.sg3.hdr);
+		      nwritten = 0;
+		      if (ret < 0)
 		      {
 		      /* ENOMEM can easily happen, if both command queuein
 		         inside the SG driver and large buffers are used.
@@ -1908,13 +1906,20 @@
 		         command in the queue, we simply try to issue
 		         it later again.
 		       */
-		      if (errno == EAGAIN
-			  || (errno == ENOMEM && rp != fdp->sane_qhead))
-		      {
-		      /* don't try to send the data again, but
-		         wait for the next call to issue()
-		       */
-		      rp->running = 0;}
+			if (errno == EAGAIN
+			    || (errno == ENOMEM && rp != fdp->sane_qhead))
+			  {
+			    /* don't try to send the data again, but
+			       wait for the next call to issue()
+			    */
+			    rp->running = 0;
+			  }
+			else /* game over */
+			  {
+			    rp->running = 0;
+			    rp->done = 1;
+			    rp->status = SANE_STATUS_IO_ERROR;
+			  }
 		      }
 	      );
 	      IF_DBG (if (DBG_LEVEL >= 255)
@@ -1934,16 +1939,21 @@
 	  if (nwritten != rp->sgdata.cdb.hdr.pack_len)
 #else
 	  if ((sg_version < 30000 && nwritten != rp->sgdata.cdb.hdr.pack_len)
-/* xxx doesn't work yet with kernel 2.3.18:
-          || (sg_version >= 30000 && nwritten < sizeof(Sg_io_hdr)))
-*/
-	      || (sg_version >= 30000 && nwritten < 0))
+	      || (sg_version >= 30000 && ret < 0))
 #endif
 	    {
 	      if (rp->running)
 		{
-		  DBG (1, "sanei_scsi.issue: bad write (errno=%i) %s %li\n",
-		       errno, strerror (errno), (long)nwritten);
+#ifdef SG_IO
+		  if (sg_version < 30000)
+#endif
+		    DBG (1, "sanei_scsi.issue: bad write (errno=%i) %s %li\n",
+			 errno, strerror (errno), (long)nwritten);
+#ifdef SG_IO
+		  else if (sg_version > 30000)
+		    DBG (1, "sanei_scsi.issue: SG_IO ioctl error (errno=%i, ret=%d) %s\n",
+			 errno, ret, strerror (errno));
+#endif
 		  rp->done = 1;
 		  if (errno == ENOMEM)
 		    {
@@ -1966,11 +1976,20 @@
 	      break;		/* in case of an error don't try to queue more commands */
 	    }
 	  else
-	    req->status = SANE_STATUS_IO_ERROR;
+	    {
+#ifdef SG_IO
+	      if (sg_version < 30000)
+#endif
+		req->status = SANE_STATUS_IO_ERROR;
+#ifdef SG_IO
+	      else if (sg_version > 30000) /* SG_IO is synchronous, we're all set */
+		req->status = SANE_STATUS_GOOD;
+#endif
+	    }
 	  fdp->sg_queue_used++;
 	  rp = rp->next;
-	}
     }
+}
 
   void sanei_scsi_req_flush_all_extended (int fd)
   {
@@ -2009,6 +2028,7 @@
 	req->next = fdp->sane_free_list;
 	fdp->sane_free_list = req;
       }
+
     fdp->sane_qhead = fdp->sane_qtail = 0;
   }
 
@@ -2197,18 +2217,18 @@
       }
     else
       {
-	fd_set readable;
-
-	/* wait for command completion: */
-	FD_ZERO (&readable);
-	FD_SET (req->fd, &readable);
-	select (req->fd + 1, &readable, 0, 0, 0);
-
-	/* now atomically read result and set DONE: */
 #ifdef SG_IO
 	if (sg_version < 30000)
 	  {
 #endif
+	    fd_set readable;
+
+	    /* wait for command completion: */
+	    FD_ZERO (&readable);
+	    FD_SET (req->fd, &readable);
+	    select (req->fd + 1, &readable, 0, 0, 0);
+
+	    /* now atomically read result and set DONE: */
 	    ATOMIC (nread = read (req->fd, &req->sgdata.cdb,
 				  req->sgdata.cdb.hdr.reply_len);
 		    req->done = 1);
@@ -2218,10 +2238,10 @@
 	  {
 	    IF_DBG (if (DBG_LEVEL >= 255)
 		    system ("cat /proc/scsi/sg/debug 1>&2");)
-	      ATOMIC (nread =
-		      read (req->fd, &req->sgdata.sg3.hdr,
-			    sizeof (Sg_io_hdr));
-		      req->done = 1);
+
+	      /* set DONE: */
+	      nread = 0; /* unused in this code path */
+	      req->done = 1;
 	  }
 #endif
 

Reply via email to