sane-project-website/old-archive/1999-09/0127.html

812 wiersze
28 KiB
HTML

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

<!-- received="Mon Sep 20 13:30:22 1999 PDT" -->
<!-- sent="Mon, 20 Sep 1999 22:39:35 +0200" -->
<!-- name="abel deuring" -->
<!-- email="a.deuring@satzbau-gmbh.de" -->
<!-- subject="Re: SG_BIG_BUFF, glibc 2.1 weirdness ..." -->
<!-- id="" -->
<!-- inreplyto="SG_BIG_BUFF, glibc 2.1 weirdness ..." -->
<title>sane-devel: Re: SG_BIG_BUFF, glibc 2.1 weirdness ...</title>
<h1>Re: SG_BIG_BUFF, glibc 2.1 weirdness ...</h1>
<b>abel deuring</b> (<a href="mailto:a.deuring@satzbau-gmbh.de"><i>a.deuring@satzbau-gmbh.de</i></a>)<br>
<i>Mon, 20 Sep 1999 22:39:35 +0200</i>
<p>
<ul>
<li> <b>Messages sorted by:</b> <a href="date.html#127">[ date ]</a><a href="index.html#127">[ thread ]</a><a href="subject.html#127">[ subject ]</a><a href="author.html#127">[ author ]</a>
<!-- next="start" -->
<li> <b>Next message:</b> <a href="0128.html">Hugo.van.der.Kooij@caiw.nl: "Re: Error device I/O"</a>
<li> <b>Previous message:</b> <a href="0126.html">Oliver Rauch: "Re: Error device I/O"</a>
<!-- nextthread="start" -->
<!-- reply="end" -->
</ul>
<!-- body="start" -->
Hi all!<br>
<p>
At the end of the mail are some modifications to sanei_scsi.c to<br>
get a "better cooperation" with the new Linux SG driver.<br>
While this driver has been introduced in kernel version 2.2.6,<br>
SG version 2.1.34 or newer is required in order to<br>
take advantage of these modifications (SG 2.1.34 is part of the<br>
kernels 2.2.10 .. 2.2.12) Compilation and usage of the modifiled<br>
sanei_scsi.c with older SG drivers and kernels is of course<br>
possible as before, but the new functionality will not be available.<br>
On the other hand, there should not be any problem to use the SG<br>
driver 2.1.34 or 2.1.35 with kernel version 2.2.6 or newer.<br>
(Don't ask me about older kernels...) You can download the SG<br>
driver at <a href="http://www.torque.net/sg">http://www.torque.net/sg</a>.<br>
<p>
<p>
<p>
1. It is possible to set the buffer size for SCSI commands with<br>
the environment variable SANE_SG_BUFFERSIZE. The default <br>
buffersize can be changed with the configure option <br>
--enable-scsibuffersize=nnn. The latter may be useful if one <br>
wants to change the "default default" buffersize of 128 kB <br>
for saned. (Thanks to Andy for suggesting the configure option.)<br>
<p>
Defining a too big buffer size is often not such a good idea,<br>
because the kernel may need to swap other data in order to<br>
allocate the SG buffer. This can lead to a performance<br>
degradation.<br>
<p>
If the frontend fails for a large value in<br>
SANE_SG_BUFFERSIZE, set the environment variable<br>
SANE_DEBUG_SANEI_SCSI=1, and check, if you get the message<br>
"sanei_scsi_open: could not allocate SG buffer memory. <br>
wanted: 10000000 got: 2500096". (As you can see from this <br>
example, several megabytes are really too much :)<br>
<p>
In this case, you should decrease the value for SANE_SG_BUFFERSIZE.<br>
<p>
2. If you have the SG driver 2.1.35 installed, a backend can use<br>
the command queueing offered by the SG driver. This affects<br>
only the HP, Mustek, Microtek (not Microtek2) and Sharp<br>
backends. The usage of this "lower level" queueing avoids under<br>
certain conditions (higher scan resolution, additional<br>
"traffic" on the SCSI bus) many carriage stops for the<br>
Sharp JX250. Perhaps the improved queueing avoids some carriage <br>
stops for other scanners too.<br>
<p>
<p>
Technical details:<br>
<p>
The main compatibility problem between the new SG driver and<br>
sanei_scsi.c is that the new SG driver does not guarantee to allocate<br>
a buffer of the size specified with the SG_SET_RESERVED_SIZE<br>
ioctl call. It can theoretically even happen that there is no<br>
buffer at all (see<br>
<a href="http://www.torque.net/sg/p/scsi-generic_long.txt">http://www.torque.net/sg/p/scsi-generic_long.txt</a> for details).<br>
<p>
This means especially that there is no guarantee that two file<br>
handles will have the same buffer size: The SG driver allocates<br>
separate buffers for each file handle. Therefore, the static<br>
variable sanei_scsi_max_request_size becomes less useful.<br>
<p>
<p>
Andreas Beck made two suggestions to solve these problem:<br>
<p>
1. to define a second function<br>
<p>
sanei_scsi_open_extended(const char *dev, int *fdp,<br>
SANEI_SCSI_Sense_Handler handler,<br>
void *handler_arg, int *buffersize)<br>
<p>
This function tries to allocate a SG buffer of size *buffersize;<br>
the actual buffer size allocated by the SG driver is written into<br>
*buffersize on return. Please note that the SG driver does not<br>
guarantee to allocated even one page (4 kB on most platforms) of<br>
memory. Thus it is up to the backend to decide if the buffer is<br>
large enough.<br>
<p>
2. to define sanei_scsi_open as a "wrapper function" for<br>
sanei_scsi_open-extended. sanei_scsi_open can then ensure that<br>
sanei_scsi_max_request_size is not increased if a second file<br>
handle is opened.<br>
<p>
While I implemented Andy's suggestion for a wrapper function, I<br>
decided against the logic of setting an upper limit for<br>
sanei_scsi_max_request_size in a second open. Several<br>
backends start a separate reader process, and if a call to<br>
sanei_scsi_open decreasing sanei_scsi_max_request_size happens,<br>
while a reader process is running, the reader process would use<br>
the old value. (There are even more situations, where a backend <br>
might crash, if sanei_scsi_max_request_size changes.)<br>
<p>
Therefore, sanei_scsi_open ensures that the SG driver allocates <br>
exactly as much memory as requested, else it fails with <br>
SANE_STATUS_NO_MEM.<br>
<p>
<p>
Further, I changed sanei_scsi_req_flush_all. If a frontend<br>
attaches to two scanners, the old implementation would flush the<br>
commands sent to both scanners. Thus, I wrote another function<br>
sanei_scsi_req_flush_all_extended(int fd), which flushes the<br>
commands for only one file handle.<br>
<p>
sanei_scsi_req_flush_all is now a wrapper for the new function,<br>
and flushes the commands for a file handle, if there is only one<br>
opened file handle. If two or more file handles are open, the<br>
function bails out in an assert.<br>
<p>
<p>
The modifications to the queueing implementation do not affect<br>
the behaviour of sanei_scsi_req_enter / sanei_scsi_req_wait,<br>
so I don't explain them. Look into he source code if you are curious.<br>
<p>
<p>
I know that especially the introduction of sanei_scsi_open_extended<br>
can have a relatively big impact on the backends. The Sharp backend<br>
for example needs some cleanup regarding the time, at which it<br>
allocates a buffer. (For my tests of the new functions, I<br>
used some workaround. And I found an "asymmetry" in the backend<br>
regarding the functions which call sanei_scsi_open and<br>
sanei_scsi_close...) <br>
<p>
But the improved capabilities of the new SG driver are worth the<br>
changes, I think. And, frankly speaking, I don't think that<br>
global variables like sanei_scsi_max_request_size are the best<br>
invention since sliced bread, Let's get rid of it.<br>
<p>
<p>
Thanks to Douglas Gilbert and Andy Beck for answering many<br>
questions and giving many suggestions.<br>
<p>
Abel<br>
<p>
--- sanei_scsi.c-orig Sat Jul 3 16:59:46 1999<br>
+++ sanei_scsi.c Mon Sep 20 20:58:20 1999<br>
@@ -194,6 +194,76 @@<br>
#endif<br>
<br>
int sanei_scsi_max_request_size = MAX_DATA;<br>
+#if USE == LINUX_INTERFACE<br>
+/* the following #defines follow Douglas Gilbert's sample code<br>
+ to maintain run time compatibility with the old and the<br>
+ new SG driver for Linux<br>
+*/<br>
+#ifndef SG_SET_COMMAND_Q<br>
+#define SG_SET_COMMAND_Q 0x2271<br>
+#endif<br>
+#ifndef SG_SET_RESERVED_SIZE<br>
+#define SG_SET_RESERVED_SIZE 0x2275<br>
+#endif <br>
+#ifndef SG_GET_RESERVED_SIZE<br>
+#define SG_GET_RESERVED_SIZE 0x2272<br>
+#endif <br>
+#ifndef SG_GET_SCSI_ID<br>
+#define SG_GET_SCSI_ID 0x2276<br>
+#endif <br>
+#ifndef SG_GET_VERSION_NUM<br>
+#define SG_GET_VERSION_NUM 0x2282<br>
+#endif<br>
+<br>
+#ifndef SCSIBUFFERSIZE<br>
+#define SCSIBUFFERSIZE (128 * 1024)<br>
+#endif<br>
+<br>
+/* the struct returned by the SG ioctl call SG_GET_SCSI_ID changed<br>
+ from version 2.1.34 to 2.1.35, and we need the informations from<br>
+ the field s_queue_depth, which was introduced in 2.1.35.<br>
+ To get this file compiling also with older versions of sg.h, the <br>
+ struct is re-defined here.<br>
+*/<br>
+typedef struct xsg_scsi_id {<br>
+ int host_no; /* as in "scsi&lt;n&gt;" where 'n' is one of 0, 1, 2<br>
etc */<br>
+ int channel;<br>
+ int scsi_id; /* scsi id of target device */<br>
+ int lun;<br>
+ int scsi_type; /* TYPE_... defined in scsi/scsi.h */<br>
+ short h_cmd_per_lun;/* host (adapter) maximum commands per lun */<br>
+ short d_queue_depth;/* device (or adapter) maximum queue length */<br>
+ int unused1; /* probably find a good use, set 0 for now */<br>
+ int unused2; /* ditto */<br>
+} SG_scsi_id;<br>
+<br>
+typedef struct req<br>
+ {<br>
+ struct req *next;<br>
+ int fd;<br>
+ u_int running:1, done:1;<br>
+ SANE_Status status;<br>
+ size_t *dst_len;<br>
+ void *dst;<br>
+ struct<br>
+ {<br>
+ struct sg_header hdr;<br>
+ /* Make sure this is the last element, the real size is<br>
+ SG_BIG_BUFF and machine dependant */<br>
+ u_int8_t data[1];<br>
+ }<br>
+ cdb;<br>
+ }<br>
+req;<br>
+<br>
+typedef struct Fdparms <br>
+ {<br>
+ int sg_queue_used, sg_queue_max;<br>
+ req *sane_qhead, *sane_qtail, *sane_free_list;<br>
+ }<br>
+fdparms;<br>
+<br>
+#endif<br>
<br>
#if USE == FREEBSD_CAM_INTERFACE<br>
# define CAM_MAXDEVS 128<br>
@@ -590,12 +660,25 @@<br>
<br>
#endif /* USE_OS2_INTERFACE */<br>
<br>
+static int num_alloced = 0;<br>
+<br>
+#if USE == LINUX_INTERFACE<br>
+<br>
+SANE_Status<br>
+sanei_scsi_open_extended (const char *dev, int *fdp,<br>
+ SANEI_SCSI_Sense_Handler handler, <br>
+ void *handler_arg, int *buffersize)<br>
+<br>
+#else<br>
+<br>
SANE_Status<br>
sanei_scsi_open (const char *dev, int *fdp,<br>
SANEI_SCSI_Sense_Handler handler, void *handler_arg)<br>
+<br>
+#endif<br>
+<br>
{<br>
u_int bus = 0, target = 0, lun = 0, fake_fd = 0;<br>
- static int num_alloced = 0;<br>
char *real_dev = 0;<br>
void *pdata = 0;<br>
int fd;<br>
@@ -621,6 +704,7 @@<br>
sanei_scsi_max_request_size = atoi (buf);<br>
DBG (1, "sanei_scsi_open: sanei_scsi_max_request_size=%d bytes\n",<br>
sanei_scsi_max_request_size);<br>
+ close(fd);<br>
}<br>
}<br>
#endif<br>
@@ -913,6 +997,109 @@<br>
}<br>
}<br>
#endif /* SGIOCSTL */<br>
+#if USE == LINUX_INTERFACE<br>
+ {<br>
+ SG_scsi_id sid;<br>
+ int ioctl_val, sg_version;<br>
+ int real_buffersize;<br>
+ fdparms *fdpa = 0;<br>
+ <br>
+ pdata = fdpa = malloc(sizeof(fdparms));<br>
+ if (!pdata)<br>
+ {<br>
+ close(fd);<br>
+ return SANE_STATUS_NO_MEM;<br>
+ }<br>
+ memset(fdpa, 0, sizeof(fdparms));<br>
+ /* default: allow only one command to be sent to the SG driver <br>
+ */<br>
+ fdpa-&gt;sg_queue_max = 1;<br>
+<br>
+ /* Try to read the SG version. If the ioctl call is successful, <br>
+ we have the new SG driver, and we can increase the buffer size<br>
+ using another ioctl call. <br>
+ If we have SG version 2.1.35 or above, we can additionally<br>
enable<br>
+ command queueing.<br>
+ */<br>
+ if (0 == ioctl(fd, SG_GET_VERSION_NUM, &amp;sg_version))<br>
+ {<br>
+ DBG(1, "sanei_scsi_open: SG driver version: %i\n", sg_version);<br>
+<br>
+ /* try to reserve a SG buffer of the size specified by<br>
*buffersize<br>
+ */<br>
+ ioctl(fd, SG_SET_RESERVED_SIZE, buffersize);<br>
+<br>
+ /* the set call may not be able to allocate as much memory<br>
+ as requested, thus we read the actual buffer size.<br>
+<br>
+ NOTE: sanei_scsi_max_request_size is a global variable<br>
+ used for all devices/file handles, while version 2.0 and <br>
+ above of the SG driver allocate buffer memory for each <br>
+ opened file separately. Therefore, we have a possible <br>
+ inconsistency, if more than one file is opened and<br>
+ if the SG_GET_RESERVED_SIZE return different buffer sizes<br>
+ for different file handles. (See Douglas Gilbert's<br>
+ description of the SG driver for details:<br>
+ <a href="http://www.torque.net/sg/p/scsi-generic_long.txt">http://www.torque.net/sg/p/scsi-generic_long.txt</a>)<br>
+ <br>
+ For this reason, sanei_scsi_open does not allow to open <br>
+ two or more file handles simultaneously.<br>
+ */<br>
+ if (0 == ioctl(fd, SG_GET_RESERVED_SIZE, &amp;real_buffersize))<br>
+ {<br>
+ /* if we got more memory than requested, we stick with<br>
+ with the requested value, in order to allow<br>
+ sanei_scsi_open to check the buffer size exactly.<br>
+ */<br>
+ if (real_buffersize &gt; *buffersize)<br>
+ {<br>
+ sanei_scsi_max_request_size = *buffersize;<br>
+ }<br>
+ else<br>
+ {<br>
+ sanei_scsi_max_request_size = real_buffersize;<br>
+ *buffersize = real_buffersize;<br>
+ }<br>
+ }<br>
+ else <br>
+ {<br>
+ DBG(1, "sanei_scsi_open: cannot read SG buffer size -<br>
%s\n", <br>
+ strerror(errno));<br>
+ close(fd);<br>
+ return SANE_STATUS_NO_MEM;<br>
+ }<br>
+ DBG(1, "sanei_scsi_open_extended: using %i bytes as SCSI<br>
buffer\n", <br>
+ sanei_scsi_max_request_size);<br>
+<br>
+ if (sg_version &gt;= 20135)<br>
+ {<br>
+ DBG(1, "trying to enable low level command queueing\n");<br>
+ <br>
+ if (0 == ioctl(fd, SG_GET_SCSI_ID, &amp;sid)) <br>
+ { <br>
+ DBG(1, "sanei_scsi_open: Host adapter queue depth:<br>
%i\n",<br>
+ sid.d_queue_depth);<br>
+ <br>
+ ioctl_val = 1;<br>
+ if(0 == ioctl(fd, SG_SET_COMMAND_Q, &amp;ioctl_val)) <br>
+ {<br>
+ fdpa-&gt;sg_queue_max = sid.d_queue_depth;<br>
+ if (fdpa-&gt;sg_queue_max &lt;= 0)<br>
+ fdpa-&gt;sg_queue_max = 1;<br>
+ }<br>
+ }<br>
+ }<br>
+ }<br>
+ else<br>
+ {<br>
+ /* we have the old SG driver: */<br>
+ if (sanei_scsi_max_request_size &lt; *buffersize)<br>
+ *buffersize = sanei_scsi_max_request_size;<br>
+ }<br>
+ if (fdpa-&gt;sg_queue_max &gt; 1)<br>
+ DBG(1, "sanei_scsi_open: low level command queueing enabled\n");<br>
+ }<br>
+#endif /* LINUX_INTERFACE */<br>
#endif /* !DECUNIX_INTERFACE */<br>
<br>
if (fd &gt;= num_alloced)<br>
@@ -958,9 +1145,78 @@<br>
return SANE_STATUS_GOOD;<br>
}<br>
<br>
+#if USE == LINUX_INTERFACE<br>
+/* The "wrapper" for the old open call */<br>
+SANE_Status<br>
+sanei_scsi_open (const char *dev, int *fdp,<br>
+ SANEI_SCSI_Sense_Handler handler, void *handler_arg)<br>
+{<br>
+ int i, j = 0;<br>
+ int wanted_buffersize = SCSIBUFFERSIZE, real_buffersize;<br>
+ SANE_Status res;<br>
+ char *cc, *cc1;<br>
+<br>
+ cc = getenv("SANE_SG_BUFFERSIZE");<br>
+ if (cc)<br>
+ {<br>
+ i = strtol(cc, &amp;cc1, 10);<br>
+ if (cc != cc1 &amp;&amp; i &gt;= 32768)<br>
+ wanted_buffersize = i;<br>
+ }<br>
+<br>
+ real_buffersize = wanted_buffersize;<br>
+ res = sanei_scsi_open_extended(dev, fdp, handler, handler_arg, <br>
+ &amp;real_buffersize);<br>
+<br>
+ /* make sure that we got as much memory as we wanted, otherwise<br>
+ the backend might be confused<br>
+ */<br>
+ if (real_buffersize != wanted_buffersize)<br>
+ {<br>
+ DBG(1, "sanei_scsi_open: could not allocate SG buffer memory "<br>
+ "wanted: %i got: %i\n", wanted_buffersize, real_buffersize);<br>
+ sanei_scsi_close(*fdp);<br>
+ return SANE_STATUS_NO_MEM;<br>
+ }<br>
+<br>
+ return res;<br>
+}<br>
+#else<br>
+/* dummy for the proposed new open call */<br>
+sanei_scsi_open_extended (const char *dev, int *fdp,<br>
+ SANEI_SCSI_Sense_Handler handler, <br>
+ void *handler_arg, int *buffersize)<br>
+{<br>
+ SANE_Status res;<br>
+ res = sanei_scsi_open(dev, fdp, handler, handler_arg);<br>
+ if (sanei_scsi_max_request_size &lt; *buffersize)<br>
+ *buffersize = sanei_scsi_max_request_size;<br>
+ return res;<br>
+}<br>
+#endif<br>
+<br>
void<br>
sanei_scsi_close (int fd)<br>
{<br>
+#if USE == LINUX_INTERFACE<br>
+ if (fd_info[fd].pdata) <br>
+ {<br>
+ req *req, *next_req;<br>
+ <br>
+ /* make sure that there are no pending SCSI calls */<br>
+ sanei_scsi_req_flush_all_extended(fd);<br>
+<br>
+ req = ((fdparms*) fd_info[fd].pdata)-&gt;sane_free_list;<br>
+ while (req) <br>
+ {<br>
+ next_req = req-&gt;next;<br>
+ free(req);<br>
+ req = next_req;<br>
+ }<br>
+ free(fd_info[fd].pdata);<br>
+ }<br>
+#endif<br>
+<br>
fd_info[fd].in_use = 0;<br>
fd_info[fd].sense_handler = 0;<br>
fd_info[fd].sense_handler_arg = 0;<br>
@@ -1225,69 +1481,133 @@<br>
} \<br>
while (0)<br>
<br>
-static struct req<br>
- {<br>
- struct req *next;<br>
- int fd;<br>
- u_int running:1, done:1;<br>
- SANE_Status status;<br>
- size_t *dst_len;<br>
- void *dst;<br>
- struct<br>
- {<br>
- struct sg_header hdr;<br>
- /* Make sure this is the last element, the real size is<br>
- SG_BIG_BUFF and machine dependant */<br>
- u_int8_t data[1];<br>
- }<br>
- cdb;<br>
- }<br>
-*qhead, *qtail, *free_list;<br>
-<br>
static void<br>
issue (struct req *req)<br>
{<br>
ssize_t nwritten;<br>
+ fdparms *fdp;<br>
+ struct req *rp;<br>
+ int retries;<br>
<br>
- if (!req || req-&gt;running)<br>
+ if (!req)<br>
return;<br>
-<br>
+ fdp = (fdparms*) fd_info[req-&gt;fd].pdata;<br>
DBG (4, "sanei_scsi.issue: %p\n", req);<br>
<br>
- ATOMIC (req-&gt;running = 1;<br>
- nwritten = write (req-&gt;fd, &amp;req-&gt;cdb, req-&gt;cdb.hdr.pack_len));<br>
-<br>
- if (nwritten != req-&gt;cdb.hdr.pack_len)<br>
- {<br>
- DBG (1, "sanei_scsi.issue: bad write (errno=%s)\n",<br>
- strerror (errno));<br>
- req-&gt;done = 1;<br>
- if (errno == ENOMEM)<br>
- {<br>
- DBG (1, "sanei_scsi.issue: SG_BIG_BUF inconsistency? "<br>
- "Check file PROBLEMS.\n");<br>
- req-&gt;status = SANE_STATUS_NO_MEM;<br>
- }<br>
+ rp = fdp-&gt;sane_qhead;<br>
+ while (rp &amp;&amp; rp-&gt;running)<br>
+ rp = rp-&gt;next;<br>
+<br>
+ while (rp &amp;&amp; fdp-&gt;sg_queue_used &lt; fdp-&gt;sg_queue_max)<br>
+ {<br>
+ retries = 20;<br>
+ while (retries)<br>
+ {<br>
+ ATOMIC (rp-&gt;running = 1;<br>
+ nwritten = write (rp-&gt;fd, &amp;rp-&gt;cdb,<br>
rp-&gt;cdb.hdr.pack_len);<br>
+ if (nwritten != rp-&gt;cdb.hdr.pack_len)<br>
+ {<br>
+ /* ENOMEM can easily happen, if both command<br>
queueing<br>
+ inside the SG driver and large buffers are<br>
used.<br>
+ Therefore, if ENOMEM does not occur for the<br>
first <br>
+ command in the queue, we can simply try to<br>
issue<br>
+ it later again.<br>
+ */<br>
+ if ( errno == EAGAIN <br>
+ || (errno == ENOMEM &amp;&amp; rp !=<br>
fdp-&gt;sane_qhead))<br>
+ {<br>
+ /* don't try to send the data again, but<br>
+ wait for the next call to issue()<br>
+ */<br>
+ rp-&gt;running = 0;<br>
+ }<br>
+ }<br>
+ );<br>
+ if (rp == fdp-&gt;sane_qhead &amp;&amp; errno == EAGAIN)<br>
+ {<br>
+ retries--;<br>
+ usleep(10000);<br>
+ }<br>
+ else<br>
+ retries = 0;<br>
+ }<br>
+<br>
+ if (nwritten != rp-&gt;cdb.hdr.pack_len)<br>
+ {<br>
+ if (rp-&gt;running)<br>
+ {<br>
+ DBG (1, "sanei_scsi.issue: bad write (errno=%s)\n",<br>
+ strerror (errno));<br>
+ rp-&gt;done = 1;<br>
+ if (errno == ENOMEM)<br>
+ {<br>
+ DBG (1, "sanei_scsi.issue: SG_BIG_BUF inconsistency? "<br>
+ "Check file PROBLEMS.\n");<br>
+ rp-&gt;status = SANE_STATUS_NO_MEM;<br>
+ }<br>
+ else<br>
+ rp-&gt;status = SANE_STATUS_IO_ERROR;<br>
+ }<br>
+ else<br>
+ {<br>
+ if (errno == ENOMEM)<br>
+ DBG(1, "issue: ENOMEM - cannot queue SCSI command. "<br>
+ "Trying again later.\n");<br>
+ else<br>
+ DBG(1, "issue: cannot queue SCSI command. "<br>
+ "Trying again later.\n");<br>
+ }<br>
+ break; /* in case of an error don't try to queue more<br>
commands */<br>
+ }<br>
else<br>
- req-&gt;status = SANE_STATUS_IO_ERROR;<br>
+ fdp-&gt;sg_queue_used++;<br>
+ rp = rp-&gt;next;<br>
}<br>
}<br>
<br>
void<br>
-sanei_scsi_req_flush_all (void)<br>
+sanei_scsi_req_flush_all_extended (int fd)<br>
{<br>
+ fdparms *fdp;<br>
struct req *req, *next_req;<br>
<br>
- for (req = qhead; req; req = next_req)<br>
+ fdp = (fdparms*) fd_info[fd].pdata;<br>
+ for (req = fdp-&gt;sane_qhead; req; req = next_req)<br>
{<br>
if (req-&gt;running &amp;&amp; !req-&gt;done)<br>
- read (req-&gt;fd, &amp;req-&gt;cdb, req-&gt;cdb.hdr.reply_len);<br>
+ {<br>
+ read (fd, &amp;req-&gt;cdb, req-&gt;cdb.hdr.reply_len);<br>
+ ((fdparms*) fd_info[req-&gt;fd].pdata)-&gt;sg_queue_used--;<br>
+ }<br>
next_req = req-&gt;next;<br>
<br>
- req-&gt;next = free_list;<br>
- free_list = req;<br>
+ req-&gt;next = fdp-&gt;sane_free_list;<br>
+ fdp-&gt;sane_free_list = req;<br>
}<br>
- qhead = qtail = 0;<br>
+ fdp-&gt;sane_qhead = fdp-&gt;sane_qtail = 0;<br>
+}<br>
+<br>
+void<br>
+sanei_scsi_req_flush_all ()<br>
+{<br>
+ int fd, i, j = 0;<br>
+ <br>
+ /* sanei_scsi_open allows only one open file handle, so we<br>
+ can simply look for the first entry where in_use is set<br>
+ */<br>
+ +<br>
+ fd = num_alloced;<br>
+ for (i = 0; i &lt; num_alloced; i++)<br>
+ if (fd_info[i].in_use)<br>
+ {<br>
+ j++;<br>
+ fd = i;<br>
+ }<br>
+ <br>
+ assert(j &lt; 2);<br>
+ <br>
+ if (fd &lt; num_alloced)<br>
+ sanei_scsi_req_flush_all_extended(fd);<br>
}<br>
<br>
SANE_Status<br>
@@ -1296,11 +1616,14 @@<br>
{<br>
struct req *req;<br>
size_t size;<br>
+ fdparms *fdp;<br>
+<br>
+ fdp = (fdparms*) fd_info[fd].pdata;<br>
<br>
- if (free_list)<br>
+ if (fdp-&gt;sane_free_list)<br>
{<br>
- req = free_list;<br>
- free_list = req-&gt;next;<br>
+ req = fdp-&gt;sane_free_list;<br>
+ fdp-&gt;sane_free_list = req-&gt;next;<br>
req-&gt;next = 0;<br>
}<br>
else<br>
@@ -1328,17 +1651,23 @@<br>
memcpy (&amp;req-&gt;cdb.data, src, src_size);<br>
<br>
req-&gt;next = 0;<br>
- ATOMIC (if (qtail)<br>
+ ATOMIC (if (fdp-&gt;sane_qtail)<br>
{<br>
- qtail-&gt;next = req;<br>
- qtail = req;<br>
+ fdp-&gt;sane_qtail-&gt;next = req;<br>
+ fdp-&gt;sane_qtail = req;<br>
}<br>
else<br>
- qhead = qtail = req);<br>
+ fdp-&gt;sane_qhead = fdp-&gt;sane_qtail = req);<br>
<br>
DBG (4, "scsi_req_enter: entered %p\n", req);<br>
<br>
*idp = req;<br>
+ issue(req);<br>
+<br>
+ DBG(10, "scsi_req_enter: queue_used: %i, queue_max: %i\n",<br>
+ ((fdparms*) fd_info[fd].pdata)-&gt;sg_queue_used,<br>
+ ((fdparms*) fd_info[fd].pdata)-&gt;sg_queue_max);<br>
+<br>
return SANE_STATUS_GOOD;<br>
}<br>
<br>
@@ -1349,7 +1678,8 @@<br>
struct req *req = id;<br>
ssize_t nread = 0;<br>
<br>
- assert (req == qhead); /* we don't support out-of-order completion */<br>
+ /* we don't support out-of-order completion */<br>
+ assert (req == ((fdparms*)fd_info[req-&gt;fd].pdata)-&gt;sane_qhead);<br>
<br>
DBG (4, "sanei_scsi_req_wait: waiting for %p\n", req);<br>
<br>
@@ -1372,6 +1702,9 @@<br>
ATOMIC (nread = read (req-&gt;fd, &amp;req-&gt;cdb,<br>
req-&gt;cdb.hdr.reply_len);<br>
req-&gt;done = 1);<br>
<br>
+ if (fd_info[req-&gt;fd].pdata)<br>
+ ((fdparms*) fd_info[req-&gt;fd].pdata)-&gt;sg_queue_used--;<br>
+<br>
/* Now issue next command asap, if any. We can't do this<br>
earlier since the Linux kernel has space for just one big<br>
buffer. */<br>
@@ -1423,11 +1756,12 @@<br>
}<br>
<br>
/* dequeue and release processed request: */<br>
- ATOMIC (qhead = qhead-&gt;next;<br>
- if (!qhead)<br>
- qtail = 0;<br>
- req-&gt;next = free_list;<br>
- free_list = req);<br>
+ ATOMIC (((fdparms*) fd_info[req-&gt;fd].pdata)-&gt;sane_qhead <br>
+ = ((fdparms*) fd_info[req-&gt;fd].pdata)-&gt;sane_qhead-&gt;next;<br>
+ if (!((fdparms*) fd_info[req-&gt;fd].pdata)-&gt;sane_qhead)<br>
+ ((fdparms*) fd_info[req-&gt;fd].pdata)-&gt;sane_qtail = 0;<br>
+ req-&gt;next = ((fdparms*) fd_info[req-&gt;fd].pdata)-&gt;sane_free_list;<br>
+ ((fdparms*) fd_info[req-&gt;fd].pdata)-&gt;sane_free_list = req);<br>
return status;<br>
}<br>
<br>
<p>
--- sanei_scsi.h-orig Sat Sep 4 16:30:01 1999<br>
+++ sanei_scsi.h Mon Sep 20 21:05:35 1999<br>
@@ -48,6 +48,23 @@<br>
SANEI_SCSI_Sense_Handler sense_handler,<br>
void *sense_arg);<br>
<br>
+/* The extended open call allows a backend to ask for a specific<br>
+ buffer size. sanei_scsi_open tries to allocate a buffer of the<br>
+ size given by *buffersize upon entry to this function. If<br>
+ sanei_scsi_open_extended returns successfully, *buffersize<br>
+ contains the available buffer size. This value may be both<br>
+ smaller or larger than the value requested by the backend;<br>
+ it can even be zero. The backend must decide, if it got enough<br>
+ buffer memory to work.<br>
+ <br>
+ Note that the value of *buffersize may differ for different<br>
+ files.<br>
+*/<br>
+extern SANE_Status sanei_scsi_open_extended (<br>
+ const char * device_name, int * fd,<br>
+ SANEI_SCSI_Sense_Handler sense_handler, <br>
+ void *sense_arg, int *buffersize);<br>
+<br>
/* One or more scsi commands can be enqueued by calling req_enter().<br>
SRC is the pointer to the SCSI command and associated write data<br>
and SRC_SIZE is the length of the command and data. DST is a<br>
@@ -76,8 +93,13 @@<br>
const void * src, size_t src_size,<br>
void * dst, size_t * dst_size);<br>
<br>
-/* Flush all pending SCSI commands. */<br>
+/* Flush all pending SCSI commands. This function work only,<br>
+ if zero or one SCSI file handles are open.<br>
+*/<br>
extern void sanei_scsi_req_flush_all (void);<br>
+<br>
+/* Flush all SCSI commands pending for one handle */<br>
+extern void sanei_scsi_req_flush_all_extended (int fd);<br>
<br>
extern void sanei_scsi_close (int fd);<br>
<br>
--- configure.in-orig Sun Apr 4 00:44:56 1999<br>
+++ configure.in Mon Sep 20 20:41:44 1999<br>
@@ -192,10 +192,19 @@<br>
else<br>
DLL_PRELOAD=""<br>
fi<br>
+<br>
+AC_ARG_ENABLE(scsibuffersize, <br>
+ [ --enable-scsibuffersize=N <br>
+ specify the default size of the buffer for SCSI<br>
commands],<br>
+ [set_scsibuffersize="$enableval"], [set_scsibuffersize=131072])<br>
+CFLAGS="$CFLAGS -DSCSIBUFFERSIZE=$set_scsibuffersize"<br>
+echo "scsi buffersize: $set_scsibuffersize"<br>
+<br>
AC_SUBST(V_MAJOR)<br>
AC_SUBST(V_MINOR)<br>
AC_SUBST(V_REV)<br>
AC_SUBST(DLL_PRELOAD)<br>
+<br>
<br>
AC_OUTPUT([Makefile lib/Makefile sanei/Makefile frontend/Makefile<br>
japi/Makefile backend/Makefile include/Makefile doc/Makefile<br>
<p>
<pre>
--
Source code, list archive, and docs: <a href="http://www.mostang.com/sane/">http://www.mostang.com/sane/</a>
To unsubscribe: echo unsubscribe sane-devel | mail <a href="mailto:majordomo@mostang.com">majordomo@mostang.com</a>
</pre>
<!-- body="end" -->
<p>
<ul>
<!-- next="start" -->
<li> <b>Next message:</b> <a href="0128.html">Hugo.van.der.Kooij@caiw.nl: "Re: Error device I/O"</a>
<li> <b>Previous message:</b> <a href="0126.html">Oliver Rauch: "Re: Error device I/O"</a>
<!-- nextthread="start" -->
<!-- reply="end" -->
</ul>