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