two patches for sanei_scsi.c

abel deuring (a.deuring@satzbau-gmbh.de)
Mon, 05 Jul 1999 23:22:52 +0200

Hi all!

After Doug Gilbert wrote on this list that his SG driver already
is able to handle queued SCSI commands, I decided to look closer
into sanei_scsi.c and into Doug's documentation of the SG driver.

The results are two patches; both should compile cleanly with
the old and the new SG driver.

The first patch listed below adds some code to sanei_scsi_open
in order to detect if the new or the old SG driver is being used,
and it tries to enable command queueing. If the new driver is
found, the patch tries to increase the size of the buffer
reserved by the SG driver. sanei_scsi_max_request_size (the
variable which formerly held the value of SG_BIG_BUFF) is set
to the buffer size returned by the sg driver as the actual
reserved buffer size. This should resolve the problem that
Sane uses a smaller buffer with the new SG driver than
neccessary. Unfortunately, this method to set
sanei_scsi_max_request_size did not work with the SG driver
version 2.1.31, only with 2.1.34. (To be precise: I did the
work on a Suse Linux 6.1 installation; kernel version 2.2.7)

The second patch is both more interesting and more questionable:

With this patch, sanei_scsi_req_enter immediately calls issue(),
which means that the SCSI command is immediately sent to the
scanner. Under certain circumstances, this can result in a
considerable performance gain:

With my P166 box, which has a SCSI disc with a Linux installation
and a Sharp JX250 connected to an Adaptec 2940, an A4-size gray
scale scan with 400 dpi needs approximately 20 seconds with the old
sanei_scsi_req_enter implementation; with the patched version
the scan time decreases to 12..13 seconds. (A note for people
looking for over-all speed figures: This _not_ the "cycle time"
for consecutive scans; it is the output of a command like
"time scanimage [options] > /tmp/testfile". For the "cycle time",
one must add the time needed by the scanner to move the carriage
back.) This shows the impressing capabilities of Doug's work --
and it shows, considering the surprisingly small modifications
reqired, that David prepared already everything in sanei_scsi.c
for command queueing.

Now for the questionable aspect of this patch: Since the commands
are sent immediately to the scanner by sanei_scsi_req_enter, the
scanner must be able to buffer these commands. If this fails,
both the scanner and the SG driver (or something else inside the
kernel) may become completely confused. This is the case for the
JX250, if more than two commands are queued. (A hint for JX250
users: make sure that in the file "sharp.conf", "option readqueue"
is set to 2, if you want to try this patch. If the patch should
find its way into the Sane package despite my own doubts about it,
I will remove this option, of course.)

In other words: The patch makes assumptions about the scanners
and the backends which are not neccessarily fulfilled. At present,
the patch should affect Mustek-, HP- and Sharp-scanners; the other
backends don't use sanei_scsi_req_enter, and should therefore not
be affected.

So, dear readers and co-developers, what do you think about
this patch? Personally, I would prefer an implementation of
command queueing, where the SG driver buffers the commands,
and sends the first command in the queue from within a call to
sg_read for the previous SCSI command -- but, as the Rolling
Stones pointed out some years ago: You can't always get what you
want. To avoid misunderstandings: This is not a critisism on
Doug's work -- he has done a great job with the SG driver. But
its capabilities put up a difficult question how to deal with
them in sanei_scsi.c.

Abel

PS: Doug, thanks for your quick answer to my questions about
command queueing with the SG driver!

-------------- Patch 1: ------------------

--- sanei_scsi.c Mon Jul 5 22:15:22 1999
+++ sanei_scsi.c.patch1 Mon Jul 5 22:24:41 1999
@@ -194,6 +194,22 @@
#endif

int sanei_scsi_max_request_size = MAX_DATA;
+#if USE == LINUX_INTERFACE
+/* to following #defines follow Doug Gilbert's sample code
+ to achieve run time compatibility with the old and the
+ new SG driver for Linux
+*/
+#ifndef SG_SET_COMMAND_Q
+#define SG_SET_COMMAND_Q 0x2271
+#endif
+#ifndef SG_SET_RESERVED_SIZE
+#define SG_SET_RESERVED_SIZE 0x2275
+#endif
+#ifndef SG_GET_RESERVED_SIZE
+#define SG_GET_RESERVED_SIZE 0x2272
+#endif
+int have_new_sg = 0;
+#endif

#if USE == FREEBSD_CAM_INTERFACE
# define CAM_MAXDEVS 128
@@ -913,6 +929,33 @@
}
}
#endif /* SGIOCSTL */
+#if USE == LINUX_INTERFACE
+ {
+ /* check for the SG version
+ */
+
+ int ioctl_val = 1;
+ /* try to enable command queueing. If this is successful, assume
+ that the new SG driver is installed, else assume that we
+ have the old driver
+ */
+ if(0 == ioctl(fd, SG_SET_COMMAND_Q, &ioctl_val))
+ {
+ have_new_sg = 1;
+ DBG(1, "sanei_scsi_open: command queueing enabled\n");
+
+ /* try to reserve a bigger SG buffer */
+ ioctl_val = 32 * 4096;
+ ioctl(fd, SG_SET_RESERVED_SIZE, &ioctl_val);
+
+ if (0 == ioctl(fd, SG_GET_RESERVED_SIZE, &ioctl_val))
+ sanei_scsi_max_request_size = ioctl_val;
+ else
+ DBG(1, "sanei_scsi_open: cannot read SG buffer size - %s\n",
strerror(errno));
+ DBG(1, "sanei_scsi_open: using %i bytes as SCSI buffer\n",
sanei_scsi_max_request_size);
+ }
+ }
+#endif
#endif /* !DECUNIX_INTERFACE */

if (fd >= num_alloced)

---------- Patch 2 (to be applied to sanei_scsi.c ------------
---------- containing the changes from patch 1): -------------

--- sanei_scsi.c Mon Jul 5 22:24:41 1999
+++ sanei_scsi.c.patch2 Mon Jul 5 22:15:22 1999
@@ -1290,16 +1290,39 @@
static void
issue (struct req *req)
{
- ssize_t nwritten;
+ ssize_t nwritten, count = 0;

if (!req || req->running)
return;

DBG (4, "sanei_scsi.issue: %p\n", req);

- ATOMIC (req->running = 1;
- nwritten = write (req->fd, &req->cdb, req->cdb.hdr.pack_len));
-
+ if (!have_new_sg)
+ {
+ ATOMIC (req->running = 1;
+ nwritten = write (req->fd, &req->cdb,
req->cdb.hdr.pack_len));
+ }
+ else
+ {
+ while (count < 100)
+ {
+ ATOMIC (nwritten = write (req->fd, &req->cdb,
req->cdb.hdr.pack_len);
+ if (nwritten !=req->cdb.hdr.pack_len
+ && errno == EAGAIN
+ && count < 100)
+ count++;
+ else
+ req->running = 1;
+ );
+ if (!req->running)
+ {
+ usleep(10000);
+ DBG(2, "sanei_scsi.issue: write call returned EAGAIN\n");
+ }
+ else
+ break;
+ }
+ }
if (nwritten != req->cdb.hdr.pack_len)
{
DBG (1, "sanei_scsi.issue: bad write (errno=%s)\n",
@@ -1382,6 +1405,8 @@
DBG (4, "scsi_req_enter: entered %p\n", req);

*idp = req;
+ if (have_new_sg)
+ issue(req);
return SANE_STATUS_GOOD;
}

--
Source code, list archive, and docs: http://www.mostang.com/sane/
To unsubscribe: echo unsubscribe sane-devel | mail majordomo@mostang.com