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