kopia lustrzana https://gitlab.com/sane-project/website
1140 wiersze
42 KiB
HTML
1140 wiersze
42 KiB
HTML
<!-- received="Sun Oct 31 11:21:55 1999 PST" -->
|
||
<!-- sent="Sun, 31 Oct 1999 18:29:44 +0100" -->
|
||
<!-- name="abel deuring" -->
|
||
<!-- email="a.deuring@satzbau-gmbh.de" -->
|
||
<!-- subject="modifications to sanei_scsi.c for the Linux SG driver 3" -->
|
||
<!-- id="" -->
|
||
<!-- inreplyto="" -->
|
||
<title>sane-devel: modifications to sanei_scsi.c for the Linux SG driver 3</title>
|
||
<h1>modifications to sanei_scsi.c for the Linux SG driver 3</h1>
|
||
<b>abel deuring</b> (<a href="mailto:a.deuring@satzbau-gmbh.de"><i>a.deuring@satzbau-gmbh.de</i></a>)<br>
|
||
<i>Sun, 31 Oct 1999 18:29:44 +0100</i>
|
||
<p>
|
||
<ul>
|
||
<li> <b>Messages sorted by:</b> <a href="date.html#243">[ date ]</a><a href="index.html#243">[ thread ]</a><a href="subject.html#243">[ subject ]</a><a href="author.html#243">[ author ]</a>
|
||
<!-- next="start" -->
|
||
<li> <b>Next message:</b> <a href="0244.html">Jason Joy: "Microtek Scanning"</a>
|
||
<li> <b>Previous message:</b> <a href="0242.html">Jean-François Straeten: "Re: GENIUS ColorPage-HR5 PRO ?"</a>
|
||
<!-- nextthread="start" -->
|
||
<!-- reply="end" -->
|
||
</ul>
|
||
<!-- body="start" -->
|
||
Dies ist eine mehrteilige Nachricht im MIME-Format.<br>
|
||
--------------698ACCDCA92710310744EF83<br>
|
||
Content-Type: text/plain; charset=us-ascii<br>
|
||
Content-Transfer-Encoding: 7bit<br>
|
||
<p>
|
||
Hi all!<br>
|
||
<p>
|
||
Douglas Gilbert is working on a new interface for Linux SG driver. The<br>
|
||
main benefit for Sane, as I see it, is the new structure "Sg_io_hdr",<br>
|
||
which has separate pointers for the command buffer, for the sense<br>
|
||
buffer, for data to be sent to the SCSI device, and for data read from<br>
|
||
the SCSI device. This means that sanei_scsi.c no longer needs to<br>
|
||
allocate its own buffer(s) for the data read from the scanner.<br>
|
||
Therefore, a scanner program consumes less memory and might be slightly<br>
|
||
faster by avoiding one memcpy.<br>
|
||
<p>
|
||
If (or when) the development kernels will support DMA to/from user<br>
|
||
memory, even another memcpy can be saved. Attached is a diff output for<br>
|
||
sanei_scsi.c and sanei_scsi.h against the version included in Sane<br>
|
||
1.0.1.<br>
|
||
<p>
|
||
While the patches to sanei_scsi.c do not affect compile time and run<br>
|
||
time compatibility with older SG drivers, you must download the new SG<br>
|
||
driver from <a href="http://www.torque.net/sg">http://www.torque.net/sg</a> and build a new kernel in order to<br>
|
||
try the new interface.<br>
|
||
<p>
|
||
In addition to the driver, a copy of sg_err.h from Douglas's sg3_utils<br>
|
||
package is required in the directory sane-1.0.1/sanei (the file is<br>
|
||
attached to this message). I renamed it to linux_sg3_err.h to make clear<br>
|
||
that it only meaningful for the Linux part of sanei_scsi.c.<br>
|
||
<p>
|
||
Abel<br>
|
||
--------------698ACCDCA92710310744EF83<br>
|
||
Content-Type: text/plain; charset=us-ascii; name="sanei_scsi-diff-sg3"<br>
|
||
Content-Transfer-Encoding: 7bit<br>
|
||
Content-Disposition: inline; filename="sanei_scsi-diff-sg3"<br>
|
||
<p>
|
||
--- sane-1.0.1-orig/sanei/sanei_scsi.c Sat Apr 17 22:18:18 1999<br>
|
||
+++ sane-1.0.1/sanei/sanei_scsi.c Sat Oct 30 00:50:39 1999<br>
|
||
@@ -194,6 +194,99 @@<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>
|
||
+# ifdef SG_IO<br>
|
||
+# include "linux_sg3_err.h" /* xxx contains several definitions of error codes */<br>
|
||
+# endif<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<n>" where 'n' is one of 0, 1, 2 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>
|
||
+/* take the definition of the ioctl parameter SG_IO as a<br>
|
||
+ compiler flag if the new SG driver is available<br>
|
||
+*/<br>
|
||
+ union<br>
|
||
+ {<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>
|
||
+#ifdef SG_IO<br>
|
||
+/* at present, Linux's SCSI system limits the sense buffer to 16 bytes<br>
|
||
+ which is definitely too small. Hoping that this will change at some time,<br>
|
||
+ let's set the sense buffer size to 64.<br>
|
||
+*/<br>
|
||
+#define SENSE_MAX 64<br>
|
||
+ struct <br>
|
||
+ {<br>
|
||
+ struct sg_io_hdr hdr;<br>
|
||
+ u_char sense_buffer[SENSE_MAX];<br>
|
||
+ } sg3;<br>
|
||
+#endif<br>
|
||
+ }<br>
|
||
+ sgdata;<br>
|
||
+ }<br>
|
||
+req;<br>
|
||
+<br>
|
||
+typedef struct Fdparms <br>
|
||
+ {<br>
|
||
+ int sg_queue_used, sg_queue_max;<br>
|
||
+ int buffersize;<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 +683,26 @@<br>
|
||
<br>
|
||
#endif /* USE_OS2_INTERFACE */<br>
|
||
<br>
|
||
+static int num_alloced = 0;<br>
|
||
+static int sg_version = 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 +728,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 +1021,125 @@<br>
|
||
}<br>
|
||
}<br>
|
||
#endif /* SGIOCSTL */<br>
|
||
+#if USE == LINUX_INTERFACE<br>
|
||
+ {<br>
|
||
+ SG_scsi_id sid;<br>
|
||
+ int ioctl_val;<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->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 enable<br>
|
||
+ command queueing.<br>
|
||
+ */<br>
|
||
+ if (0 == ioctl(fd, SG_GET_VERSION_NUM, &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 *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, &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 > *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>
|
||
+ fdpa->buffersize = *buffersize;<br>
|
||
+ }<br>
|
||
+ else <br>
|
||
+ {<br>
|
||
+ DBG(1, "sanei_scsi_open: cannot read SG buffer size - %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 buffer\n", <br>
|
||
+ *buffersize);<br>
|
||
+<br>
|
||
+ if (sg_version >= 20135)<br>
|
||
+ {<br>
|
||
+ DBG(1, "trying to enable low level command queueing\n");<br>
|
||
+ <br>
|
||
+ if (0 == ioctl(fd, SG_GET_SCSI_ID, &sid)) <br>
|
||
+ { <br>
|
||
+ DBG(1, "sanei_scsi_open: Host adapter queue depth: %i\n",<br>
|
||
+ sid.d_queue_depth);<br>
|
||
+ <br>
|
||
+ ioctl_val = 1;<br>
|
||
+ if(0 == ioctl(fd, SG_SET_COMMAND_Q, &ioctl_val)) <br>
|
||
+ {<br>
|
||
+ fdpa->sg_queue_max = sid.d_queue_depth;<br>
|
||
+ if (fdpa->sg_queue_max <= 0)<br>
|
||
+ fdpa->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 < *buffersize)<br>
|
||
+ *buffersize = sanei_scsi_max_request_size;<br>
|
||
+ fdpa->buffersize = *buffersize;<br>
|
||
+ }<br>
|
||
+ if (sg_version == 0)<br>
|
||
+ {<br>
|
||
+ DBG(1, "sanei_scsi_open: using old SG driver logic\n");<br>
|
||
+ }<br>
|
||
+ else<br>
|
||
+ {<br>
|
||
+ DBG(1, "sanei_scsi_open: SG driver can change buffer size at run time\n");<br>
|
||
+ if (fdpa->sg_queue_max > 1)<br>
|
||
+ DBG(1, "sanei_scsi_open: low level command queueing enabled\n");<br>
|
||
+ #ifdef SG_IO<br>
|
||
+ if (sg_version >= 30000)<br>
|
||
+ {<br>
|
||
+ DBG(1, "sanei_scsi_open: using new SG header structure\n");<br>
|
||
+ }<br>
|
||
+ #endif<br>
|
||
+ }<br>
|
||
+ }<br>
|
||
+#endif /* LINUX_INTERFACE */<br>
|
||
#endif /* !DECUNIX_INTERFACE */<br>
|
||
<br>
|
||
if (fd >= num_alloced)<br>
|
||
@@ -958,9 +1185,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 = 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, &cc1, 10);<br>
|
||
+ if (cc != cc1 && i >= 32768)<br>
|
||
+ wanted_buffersize = i;<br>
|
||
+ }<br>
|
||
+<br>
|
||
+ real_buffersize = wanted_buffersize;<br>
|
||
+ res = sanei_scsi_open_extended(dev, fdp, handler, handler_arg, <br>
|
||
+ &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 < *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)->sane_free_list;<br>
|
||
+ while (req) <br>
|
||
+ {<br>
|
||
+ next_req = req->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 +1521,180 @@<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>
|
||
-<br>
|
||
- if (!req || req->running)<br>
|
||
+ fdparms *fdp;<br>
|
||
+ struct req *rp;<br>
|
||
+ int retries;<br>
|
||
+ <br>
|
||
+ if (!req)<br>
|
||
return;<br>
|
||
<br>
|
||
+ fdp = (fdparms*) fd_info[req->fd].pdata;<br>
|
||
DBG (4, "sanei_scsi.issue: %p\n", req);<br>
|
||
<br>
|
||
- ATOMIC (req->running = 1;<br>
|
||
- nwritten = write (req->fd, &req->cdb, req->cdb.hdr.pack_len));<br>
|
||
+ rp = fdp->sane_qhead;<br>
|
||
+ while (rp && rp->running)<br>
|
||
+ rp = rp->next;<br>
|
||
+<br>
|
||
+ while (rp && fdp->sg_queue_used < fdp->sg_queue_max)<br>
|
||
+ {<br>
|
||
+ retries = 20;<br>
|
||
+ while (retries)<br>
|
||
+ {<br>
|
||
+#ifdef SG_IO<br>
|
||
+ if (sg_version < 30000)<br>
|
||
+ {<br>
|
||
+#endif<br>
|
||
+ ATOMIC (rp->running = 1;<br>
|
||
+ nwritten = write (rp->fd, &rp->sgdata.cdb, <br>
|
||
+ rp->sgdata.cdb.hdr.pack_len);<br>
|
||
+ if (nwritten != rp->sgdata.cdb.hdr.pack_len)<br>
|
||
+ {<br>
|
||
+ /* ENOMEM can easily happen, if both command queueing<br>
|
||
+ inside the SG driver and large buffers are used.<br>
|
||
+ Therefore, if ENOMEM does not occur for the first <br>
|
||
+ command in the queue, we simply try to issue<br>
|
||
+ it later again.<br>
|
||
+ */<br>
|
||
+ if ( errno == EAGAIN <br>
|
||
+ || (errno == ENOMEM && rp != fdp->sane_qhead))<br>
|
||
+ {<br>
|
||
+ /* don't try to send the data again, but<br>
|
||
+ wait for the next call to issue()<br>
|
||
+ */<br>
|
||
+ rp->running = 0;<br>
|
||
+ }<br>
|
||
+ }<br>
|
||
+ );<br>
|
||
+#ifdef SG_IO<br>
|
||
+ }<br>
|
||
+ else<br>
|
||
+ {<br>
|
||
+ ATOMIC (rp->running = 1;<br>
|
||
+ nwritten = write (rp->fd, &rp->sgdata.sg3.hdr, sizeof(Sg_io_hdr));<br>
|
||
+ if (nwritten < 0)<br>
|
||
+ {<br>
|
||
+ /* ENOMEM can easily happen, if both command queueing<br>
|
||
+ inside the SG driver and large buffers are used.<br>
|
||
+ Therefore, if ENOMEM does not occur for the first <br>
|
||
+ command in the queue, we simply try to issue<br>
|
||
+ it later again.<br>
|
||
+ */<br>
|
||
+ if ( errno == EAGAIN <br>
|
||
+ || (errno == ENOMEM && rp != fdp->sane_qhead))<br>
|
||
+ {<br>
|
||
+ /* don't try to send the data again, but<br>
|
||
+ wait for the next call to issue()<br>
|
||
+ */<br>
|
||
+ rp->running = 0;<br>
|
||
+ }<br>
|
||
+ }<br>
|
||
+ );<br>
|
||
+ }<br>
|
||
+#endif<br>
|
||
+ if (rp == fdp->sane_qhead && errno == EAGAIN)<br>
|
||
+ {<br>
|
||
+ retries--;<br>
|
||
+ usleep(10000);<br>
|
||
+ }<br>
|
||
+ else<br>
|
||
+ retries = 0;<br>
|
||
+ }<br>
|
||
<br>
|
||
- if (nwritten != req->cdb.hdr.pack_len)<br>
|
||
- {<br>
|
||
- DBG (1, "sanei_scsi.issue: bad write (errno=%s)\n",<br>
|
||
- strerror (errno));<br>
|
||
- req->done = 1;<br>
|
||
- if (errno == ENOMEM)<br>
|
||
- {<br>
|
||
- DBG (1, "sanei_scsi.issue: SG_BIG_BUF inconsistency? "<br>
|
||
- "Check file PROBLEMS.\n");<br>
|
||
- req->status = SANE_STATUS_NO_MEM;<br>
|
||
- }<br>
|
||
+#ifndef SG_IO<br>
|
||
+ if (nwritten != rp->sgdata.cdb.hdr.pack_len)<br>
|
||
+#else<br>
|
||
+ if ( (sg_version < 30000 && nwritten != rp->sgdata.cdb.hdr.pack_len)<br>
|
||
+/* xxx doesn't work yet with kernel 2.3.18: <br>
|
||
+ || (sg_version >= 30000 && nwritten < sizeof(Sg_io_hdr)))<br>
|
||
+*/<br>
|
||
+ || (sg_version >= 30000 && nwritten < 0))<br>
|
||
+#endif<br>
|
||
+ {<br>
|
||
+ if (rp->running)<br>
|
||
+ {<br>
|
||
+ DBG (1, "sanei_scsi.issue: bad write (errno=%i) %s %i\n",<br>
|
||
+ errno, strerror (errno), nwritten);<br>
|
||
+ rp->done = 1;<br>
|
||
+ if (errno == ENOMEM)<br>
|
||
+ {<br>
|
||
+ DBG (1, "sanei_scsi.issue: SG_BIG_BUF inconsistency? "<br>
|
||
+ "Check file PROBLEMS.\n");<br>
|
||
+ rp->status = SANE_STATUS_NO_MEM;<br>
|
||
+ }<br>
|
||
+ else<br>
|
||
+ rp->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: EAGAIN - cannot queue SCSI command. "<br>
|
||
+ "Trying again later.\n");<br>
|
||
+ }<br>
|
||
+ break; /* in case of an error don't try to queue more commands */<br>
|
||
+ }<br>
|
||
else<br>
|
||
- req->status = SANE_STATUS_IO_ERROR;<br>
|
||
+ fdp->sg_queue_used++;<br>
|
||
+ rp = rp->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->sane_qhead; req; req = next_req)<br>
|
||
{<br>
|
||
if (req->running && !req->done)<br>
|
||
- read (req->fd, &req->cdb, req->cdb.hdr.reply_len);<br>
|
||
+ {<br>
|
||
+#ifdef SG_IO<br>
|
||
+ if (sg_version < 30000)<br>
|
||
+#endif<br>
|
||
+ read (fd, &req->sgdata.cdb, req->sgdata.cdb.hdr.reply_len);<br>
|
||
+#ifdef SG_IO<br>
|
||
+ else<br>
|
||
+ read (fd, &req->sgdata.sg3.hdr, sizeof(Sg_io_hdr));<br>
|
||
+#endif<br>
|
||
+ ((fdparms*) fd_info[req->fd].pdata)->sg_queue_used--;<br>
|
||
+ }<br>
|
||
next_req = req->next;<br>
|
||
<br>
|
||
- req->next = free_list;<br>
|
||
- free_list = req;<br>
|
||
+ req->next = fdp->sane_free_list;<br>
|
||
+ fdp->sane_free_list = req;<br>
|
||
}<br>
|
||
- qhead = qtail = 0;<br>
|
||
+ fdp->sane_qhead = fdp->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 < num_alloced; i++)<br>
|
||
+ if (fd_info[i].in_use)<br>
|
||
+ {<br>
|
||
+ j++;<br>
|
||
+ fd = i;<br>
|
||
+ }<br>
|
||
+ <br>
|
||
+ assert(j < 2);<br>
|
||
+ <br>
|
||
+ if (fd < num_alloced)<br>
|
||
+ sanei_scsi_req_flush_all_extended(fd);<br>
|
||
}<br>
|
||
<br>
|
||
SANE_Status<br>
|
||
@@ -1296,17 +1703,27 @@<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->sane_free_list)<br>
|
||
{<br>
|
||
- req = free_list;<br>
|
||
- free_list = req->next;<br>
|
||
+ req = fdp->sane_free_list;<br>
|
||
+ fdp->sane_free_list = req->next;<br>
|
||
req->next = 0;<br>
|
||
}<br>
|
||
else<br>
|
||
{<br>
|
||
- size = (sizeof (*req) - sizeof (req->cdb.data)<br>
|
||
- + sanei_scsi_max_request_size);<br>
|
||
+#ifdef SG_IO<br>
|
||
+ if (sg_version < 30000)<br>
|
||
+#endif<br>
|
||
+ size = (sizeof (*req) - sizeof (req->sgdata.cdb.data)<br>
|
||
+ + fdp->buffersize);<br>
|
||
+#ifdef SG_IO<br>
|
||
+ else<br>
|
||
+ size = sizeof(*req);<br>
|
||
+#endif<br>
|
||
req = malloc (size);<br>
|
||
if (!req)<br>
|
||
{<br>
|
||
@@ -1321,24 +1738,72 @@<br>
|
||
req->status = SANE_STATUS_GOOD;<br>
|
||
req->dst = dst;<br>
|
||
req->dst_len = dst_size;<br>
|
||
- memset (&req->cdb.hdr, 0, sizeof (req->cdb.hdr));<br>
|
||
- req->cdb.hdr.pack_id = pack_id++;<br>
|
||
- req->cdb.hdr.pack_len = src_size + sizeof (req->cdb.hdr);<br>
|
||
- req->cdb.hdr.reply_len = (dst_size ? *dst_size : 0) + sizeof (req->cdb.hdr);<br>
|
||
- memcpy (&req->cdb.data, src, src_size);<br>
|
||
+#ifdef SG_IO<br>
|
||
+ if (sg_version < 30000)<br>
|
||
+ {<br>
|
||
+#endif<br>
|
||
+ memset (&req->sgdata.cdb.hdr, 0, sizeof (req->sgdata.cdb.hdr));<br>
|
||
+ req->sgdata.cdb.hdr.pack_id = pack_id++;<br>
|
||
+ req->sgdata.cdb.hdr.pack_len = src_size + sizeof (req->sgdata.cdb.hdr);<br>
|
||
+ req->sgdata.cdb.hdr.reply_len = (dst_size ? *dst_size : 0) <br>
|
||
+ + sizeof (req->sgdata.cdb.hdr);<br>
|
||
+ memcpy (&req->sgdata.cdb.data, src, src_size);<br>
|
||
+#ifdef SG_IO<br>
|
||
+ }<br>
|
||
+ else<br>
|
||
+ {<br>
|
||
+ memset (&req->sgdata.sg3.hdr, 0, sizeof (req->sgdata.sg3.hdr));<br>
|
||
+ req->sgdata.sg3.hdr.interface_id = 'S';<br>
|
||
+ req->sgdata.sg3.hdr.cmd_len = CDB_SIZE (*(u_char *) src);<br>
|
||
+ req->sgdata.sg3.hdr.iovec_count = 0;<br>
|
||
+ req->sgdata.sg3.hdr.mx_sb_len = SENSE_MAX;<br>
|
||
+ /* read or write? */<br>
|
||
+ if (dst_size && *dst_size)<br>
|
||
+ {<br>
|
||
+ assert (req->sgdata.sg3.hdr.cmd_len == src_size);<br>
|
||
+ req->sgdata.sg3.hdr.dxfer_direction = SG_DXFER_FROM_DEV;<br>
|
||
+ req->sgdata.sg3.hdr.dxfer_len = *dst_size;<br>
|
||
+ req->sgdata.sg3.hdr.dxferp = dst;<br>
|
||
+ }<br>
|
||
+ else if (req->sgdata.sg3.hdr.cmd_len < src_size)<br>
|
||
+ {<br>
|
||
+ req->sgdata.sg3.hdr.dxfer_direction = SG_DXFER_TO_DEV;<br>
|
||
+ req->sgdata.sg3.hdr.dxfer_len = src_size - req->sgdata.sg3.hdr.cmd_len;<br>
|
||
+ req->sgdata.sg3.hdr.dxferp = ((char*) src) + req->sgdata.sg3.hdr.cmd_len;<br>
|
||
+ }<br>
|
||
+ else<br>
|
||
+ {<br>
|
||
+ assert (req->sgdata.sg3.hdr.cmd_len == src_size);<br>
|
||
+ req->sgdata.sg3.hdr.dxfer_direction = SG_DXFER_NONE;<br>
|
||
+ }<br>
|
||
+ (const void*) req->sgdata.sg3.hdr.cmdp = src;<br>
|
||
+ req->sgdata.sg3.hdr.sbp = &(req->sgdata.sg3.sense_buffer[0]);<br>
|
||
+ /* 10 seconds should be ok even for slow scanners */<br>
|
||
+ req->sgdata.sg3.hdr.timeout = 10000;<br>
|
||
+ req->sgdata.sg3.hdr.flags = SG_FLAG_DIRECT_IO;<br>
|
||
+ req->sgdata.sg3.hdr.pack_id = pack_id++;<br>
|
||
+ req->sgdata.sg3.hdr.usr_ptr = 0;<br>
|
||
+ }<br>
|
||
+#endif<br>
|
||
<br>
|
||
req->next = 0;<br>
|
||
- ATOMIC (if (qtail)<br>
|
||
+ ATOMIC (if (fdp->sane_qtail)<br>
|
||
{<br>
|
||
- qtail->next = req;<br>
|
||
- qtail = req;<br>
|
||
+ fdp->sane_qtail->next = req;<br>
|
||
+ fdp->sane_qtail = req;<br>
|
||
}<br>
|
||
else<br>
|
||
- qhead = qtail = req);<br>
|
||
+ fdp->sane_qhead = fdp->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)->sg_queue_used,<br>
|
||
+ ((fdparms*) fd_info[fd].pdata)->sg_queue_max);<br>
|
||
+<br>
|
||
return SANE_STATUS_GOOD;<br>
|
||
}<br>
|
||
<br>
|
||
@@ -1349,7 +1814,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->fd].pdata)->sane_qhead);<br>
|
||
<br>
|
||
DBG (4, "sanei_scsi_req_wait: waiting for %p\n", req);<br>
|
||
<br>
|
||
@@ -1369,8 +1835,24 @@<br>
|
||
select (req->fd + 1, &readable, 0, 0, 0);<br>
|
||
<br>
|
||
/* now atomically read result and set DONE: */<br>
|
||
- ATOMIC (nread = read (req->fd, &req->cdb, req->cdb.hdr.reply_len);<br>
|
||
- req->done = 1);<br>
|
||
+#ifdef SG_IO<br>
|
||
+ if (sg_version < 30000)<br>
|
||
+ {<br>
|
||
+#endif<br>
|
||
+ ATOMIC (nread = read (req->fd, &req->sgdata.cdb, <br>
|
||
+ req->sgdata.cdb.hdr.reply_len);<br>
|
||
+ req->done = 1);<br>
|
||
+#ifdef SG_IO<br>
|
||
+ }<br>
|
||
+ else<br>
|
||
+ {<br>
|
||
+ ATOMIC (nread = read (req->fd, &req->sgdata.sg3.hdr, sizeof(Sg_io_hdr));<br>
|
||
+ req->done = 1);<br>
|
||
+ }<br>
|
||
+#endif<br>
|
||
+<br>
|
||
+ if (fd_info[req->fd].pdata)<br>
|
||
+ ((fdparms*) fd_info[req->fd].pdata)->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>
|
||
@@ -1387,47 +1869,93 @@<br>
|
||
}<br>
|
||
else<br>
|
||
{<br>
|
||
- nread -= sizeof (req->cdb.hdr);<br>
|
||
-<br>
|
||
- /* check for errors, but let the sense_handler decide.... */<br>
|
||
- if ((req->cdb.hdr.result != 0) ||<br>
|
||
- ((req->cdb.hdr.sense_buffer[0] & 0x7f) != 0))<br>
|
||
- {<br>
|
||
- SANEI_SCSI_Sense_Handler handler<br>
|
||
- = fd_info[req->fd].sense_handler;<br>
|
||
- void *arg = fd_info[req->fd].sense_handler_arg;<br>
|
||
-<br>
|
||
- DBG (1, "sanei_scsi_req_wait: SCSI command complained: %s\n",<br>
|
||
- strerror (req->cdb.hdr.result));<br>
|
||
-<br>
|
||
- if (req->cdb.hdr.result == EBUSY)<br>
|
||
- status = SANE_STATUS_DEVICE_BUSY;<br>
|
||
- else if (handler)<br>
|
||
- /* sense handler should return SANE_STATUS_GOOD if it<br>
|
||
- decided all was ok afterall */<br>
|
||
- status = (*handler) (req->fd, req->cdb.hdr.sense_buffer, arg);<br>
|
||
- else<br>
|
||
- status = SANE_STATUS_IO_ERROR;<br>
|
||
- }<br>
|
||
-<br>
|
||
- /* if we are ok so far, copy over the return data */<br>
|
||
- if (status == SANE_STATUS_GOOD)<br>
|
||
- {<br>
|
||
- if (req->dst)<br>
|
||
- memcpy (req->dst, req->cdb.data, nread);<br>
|
||
+#ifdef SG_IO<br>
|
||
+ if (sg_version < 30000)<br>
|
||
+ {<br>
|
||
+#endif<br>
|
||
+ nread -= sizeof (req->sgdata.cdb.hdr);<br>
|
||
<br>
|
||
- if (req->dst_len)<br>
|
||
- *req->dst_len = nread;<br>
|
||
- }<br>
|
||
+ /* check for errors, but let the sense_handler decide.... */<br>
|
||
+ if ( (req->sgdata.cdb.hdr.result != 0) ||<br>
|
||
+ ((req->sgdata.cdb.hdr.sense_buffer[0] & 0x7f) != 0))<br>
|
||
+ {<br>
|
||
+ SANEI_SCSI_Sense_Handler handler<br>
|
||
+ = fd_info[req->fd].sense_handler;<br>
|
||
+ void *arg = fd_info[req->fd].sense_handler_arg;<br>
|
||
+<br>
|
||
+ DBG (1, "sanei_scsi_req_wait: SCSI command complained: %s\n",<br>
|
||
+ strerror (req->sgdata.cdb.hdr.result));<br>
|
||
+<br>
|
||
+ if (req->sgdata.cdb.hdr.result == EBUSY)<br>
|
||
+ status = SANE_STATUS_DEVICE_BUSY;<br>
|
||
+ else if (handler)<br>
|
||
+ /* sense handler should return SANE_STATUS_GOOD if it<br>
|
||
+ decided all was ok afterall */<br>
|
||
+ status = (*handler) (req->fd, req->sgdata.cdb.hdr.sense_buffer, <br>
|
||
+ arg);<br>
|
||
+ else<br>
|
||
+ status = SANE_STATUS_IO_ERROR;<br>
|
||
+ }<br>
|
||
+<br>
|
||
+ /* if we are ok so far, copy over the return data */<br>
|
||
+ if (status == SANE_STATUS_GOOD)<br>
|
||
+ {<br>
|
||
+ if (req->dst)<br>
|
||
+ memcpy (req->dst, req->sgdata.cdb.data, nread);<br>
|
||
+<br>
|
||
+ if (req->dst_len)<br>
|
||
+ *req->dst_len = nread;<br>
|
||
+ }<br>
|
||
+#ifdef SG_IO<br>
|
||
+ } <br>
|
||
+ else<br>
|
||
+ {<br>
|
||
+ /* check for errors, but let the sense_handler decide.... */<br>
|
||
+ if ( (req->sgdata.sg3.hdr.info && SG_INFO_CHECK != 0)<br>
|
||
+ || (req->sgdata.sg3.hdr.sb_len_wr > 0 &&<br>
|
||
+ ((req->sgdata.sg3.sense_buffer[0] & 0x7f) != 0)))<br>
|
||
+ {<br>
|
||
+ SANEI_SCSI_Sense_Handler handler<br>
|
||
+ = fd_info[req->fd].sense_handler;<br>
|
||
+ void *arg = fd_info[req->fd].sense_handler_arg;<br>
|
||
+<br>
|
||
+ DBG (1, "sanei_scsi_req_wait: SCSI command complained: %s\n",<br>
|
||
+ strerror(errno));<br>
|
||
+<br>
|
||
+ /* the first three tests below are an replacement of the <br>
|
||
+ error "classification" as it was with the old SG driver,<br>
|
||
+ the fourth test is new.<br>
|
||
+ */<br>
|
||
+ if ( req->sgdata.sg3.hdr.host_status == SG_ERR_DID_NO_CONNECT<br>
|
||
+ || req->sgdata.sg3.hdr.host_status == SG_ERR_DID_BUS_BUSY<br>
|
||
+ || req->sgdata.sg3.hdr.host_status == SG_ERR_DID_TIME_OUT<br>
|
||
+ || req->sgdata.sg3.hdr.driver_status == DRIVER_BUSY)<br>
|
||
+ status = SANE_STATUS_DEVICE_BUSY;<br>
|
||
+ else if (handler)<br>
|
||
+ /* sense handler should return SANE_STATUS_GOOD if it<br>
|
||
+ decided all was ok afterall */<br>
|
||
+ status = (*handler) (req->fd, req->sgdata.sg3.sense_buffer, arg);<br>
|
||
+ else<br>
|
||
+ status = SANE_STATUS_IO_ERROR;<br>
|
||
+ }<br>
|
||
+<br>
|
||
+ if (status == SANE_STATUS_GOOD)<br>
|
||
+ {<br>
|
||
+ if (req->dst_len)<br>
|
||
+ *req->dst_len -= req->sgdata.sg3.hdr.resid;<br>
|
||
+ }<br>
|
||
+ }<br>
|
||
+#endif<br>
|
||
}<br>
|
||
}<br>
|
||
<br>
|
||
/* dequeue and release processed request: */<br>
|
||
- ATOMIC (qhead = qhead->next;<br>
|
||
- if (!qhead)<br>
|
||
- qtail = 0;<br>
|
||
- req->next = free_list;<br>
|
||
- free_list = req);<br>
|
||
+ ATOMIC (((fdparms*) fd_info[req->fd].pdata)->sane_qhead <br>
|
||
+ = ((fdparms*) fd_info[req->fd].pdata)->sane_qhead->next;<br>
|
||
+ if (!((fdparms*) fd_info[req->fd].pdata)->sane_qhead)<br>
|
||
+ ((fdparms*) fd_info[req->fd].pdata)->sane_qtail = 0;<br>
|
||
+ req->next = ((fdparms*) fd_info[req->fd].pdata)->sane_free_list;<br>
|
||
+ ((fdparms*) fd_info[req->fd].pdata)->sane_free_list = req);<br>
|
||
return status;<br>
|
||
}<br>
|
||
<br>
|
||
--- sane-1.0.1-orig/include/sane/sanei_scsi.h Thu May 14 08:08:22 1998<br>
|
||
+++ sane-1.0.1/include/sane/sanei_scsi.h Sat Sep 25 18:25:24 1999<br>
|
||
@@ -48,6 +48,31 @@<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>
|
||
+/* Let backends decide, which open call to use: <br>
|
||
+ if HAVE_SANEI_SCSI_OPEN_EXTENDED is defined, sanei_scsi_open_extended<br>
|
||
+ may be used.<br>
|
||
+ May also be used to decide, if sanei_scsi_req_flush_all or<br>
|
||
+ sanei_scsi_req_flush_all_extended should be used.<br>
|
||
+*/<br>
|
||
+#define HAVE_SANEI_SCSI_OPEN_EXTENDED<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 +101,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>
|
||
--- sane-1.0.1-orig/configure.in Sun Apr 4 00:44:56 1999<br>
|
||
+++ sane-1.0.1/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 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>
|
||
<p>
|
||
--------------698ACCDCA92710310744EF83<br>
|
||
Content-Type: text/plain; charset=us-ascii; name="linux_sg3_err.h"<br>
|
||
Content-Transfer-Encoding: 7bit<br>
|
||
Content-Disposition: inline; filename="linux_sg3_err.h"<br>
|
||
<p>
|
||
#ifndef SG_ERR_H<br>
|
||
#define SG_ERR_H<br>
|
||
#include <linux/../scsi/scsi.h> /* cope with silly includes */<br>
|
||
#include <linux/../scsi/sg.h><br>
|
||
<p>
|
||
/* Feel free to copy and modify this GPL-ed code into your applications. */<br>
|
||
<p>
|
||
/* Version 0.82 (991025) */<br>
|
||
<p>
|
||
<p>
|
||
/* Some of the following error/status codes are exchanged between the<br>
|
||
various layers of the SCSI sub-system in Linux and should never<br>
|
||
reach the user. They are placed here for completeness. What appears<br>
|
||
here is copied from drivers/scsi/scsi.h which is not visible in<br>
|
||
the user space. */<br>
|
||
<p>
|
||
/* The following are 'host_status' codes */<br>
|
||
#ifndef DID_OK<br>
|
||
#define DID_OK 0x00<br>
|
||
#endif<br>
|
||
#ifndef DID_NO_CONNECT<br>
|
||
#define DID_NO_CONNECT 0x01 /* Unable to connect before timeout */<br>
|
||
#define DID_BUS_BUSY 0x02 /* Bus remain busy until timeout */<br>
|
||
#define DID_TIME_OUT 0x03 /* Timed out for some other reason */<br>
|
||
#define DID_BAD_TARGET 0x04 /* Bad target (id?) */<br>
|
||
#define DID_ABORT 0x05 /* Told to abort for some other reason */<br>
|
||
#define DID_PARITY 0x06 /* Parity error (on SCSI bus) */<br>
|
||
#define DID_ERROR 0x07 /* Internal error */<br>
|
||
#define DID_RESET 0x08 /* Reset by somebody */<br>
|
||
#define DID_BAD_INTR 0x09 /* Received an unexpected interrupt */<br>
|
||
#define DID_PASSTHROUGH 0x0a /* Force command past mid-level */<br>
|
||
#define DID_SOFT_ERROR 0x0b /* The low-level driver wants a retry */<br>
|
||
#endif<br>
|
||
<p>
|
||
/* These defines are to isolate applictaions from kernel define changes */<br>
|
||
#define SG_ERR_DID_OK DID_OK<br>
|
||
#define SG_ERR_DID_NO_CONNECT DID_NO_CONNECT<br>
|
||
#define SG_ERR_DID_BUS_BUSY DID_BUS_BUSY<br>
|
||
#define SG_ERR_DID_TIME_OUT DID_TIME_OUT<br>
|
||
#define SG_ERR_DID_BAD_TARGET DID_BAD_TARGET<br>
|
||
#define SG_ERR_DID_ABORT DID_ABORT<br>
|
||
#define SG_ERR_DID_PARITY DID_PARITY<br>
|
||
#define SG_ERR_DID_ERROR DID_ERROR<br>
|
||
#define SG_ERR_DID_RESET DID_RESET<br>
|
||
#define SG_ERR_DID_BAD_INTR DID_BAD_INTR<br>
|
||
#define SG_ERR_DID_PASSTHROUGH DID_PASSTHROUGH<br>
|
||
#define SG_ERR_DID_SOFT_ERROR DID_SOFT_ERROR<br>
|
||
<p>
|
||
/* The following are 'driver_status' codes */<br>
|
||
#ifndef DRIVER_OK<br>
|
||
#define DRIVER_OK 0x00<br>
|
||
#endif<br>
|
||
#ifndef DRIVER_BUSY<br>
|
||
#define DRIVER_BUSY 0x01<br>
|
||
#define DRIVER_SOFT 0x02<br>
|
||
#define DRIVER_MEDIA 0x03<br>
|
||
#define DRIVER_ERROR 0x04<br>
|
||
#define DRIVER_INVALID 0x05<br>
|
||
#define DRIVER_TIMEOUT 0x06<br>
|
||
#define DRIVER_HARD 0x07<br>
|
||
#define DRIVER_SENSE 0x08 /* Sense_buffer has been set */<br>
|
||
<p>
|
||
/* Following "suggests" are "or-ed" with one of previous 8 entries */<br>
|
||
#define SUGGEST_RETRY 0x10<br>
|
||
#define SUGGEST_ABORT 0x20<br>
|
||
#define SUGGEST_REMAP 0x30<br>
|
||
#define SUGGEST_DIE 0x40<br>
|
||
#define SUGGEST_SENSE 0x80<br>
|
||
#define SUGGEST_IS_OK 0xff<br>
|
||
#endif<br>
|
||
#ifndef DRIVER_MASK<br>
|
||
#define DRIVER_MASK 0x0f<br>
|
||
#endif<br>
|
||
#ifndef SUGGEST_MASK<br>
|
||
#define SUGGEST_MASK 0xf0<br>
|
||
#endif<br>
|
||
<p>
|
||
/* These defines are to isolate applictaions from kernel define changes */<br>
|
||
#define SG_ERR_DRIVER_OK DRIVER_OK<br>
|
||
#define SG_ERR_DRIVER_BUSY DRIVER_BUSY<br>
|
||
#define SG_ERR_DRIVER_SOFT DRIVER_SOFT<br>
|
||
#define SG_ERR_DRIVER_MEDIA DRIVER_MEDIA<br>
|
||
#define SG_ERR_DRIVER_ERROR DRIVER_ERROR<br>
|
||
#define SG_ERR_DRIVER_INVALID DRIVER_INVALID<br>
|
||
#define SG_ERR_DRIVER_TIMEOUT DRIVER_TIMEOUT<br>
|
||
#define SG_ERR_DRIVER_HARD DRIVER_HARD<br>
|
||
#define SG_ERR_DRIVER_SENSE DRIVER_SENSE<br>
|
||
#define SG_ERR_SUGGEST_RETRY SUGGEST_RETRY<br>
|
||
#define SG_ERR_SUGGEST_ABORT SUGGEST_ABORT<br>
|
||
#define SG_ERR_SUGGEST_REMAP SUGGEST_REMAP<br>
|
||
#define SG_ERR_SUGGEST_DIE SUGGEST_DIE<br>
|
||
#define SG_ERR_SUGGEST_SENSE SUGGEST_SENSE<br>
|
||
#define SG_ERR_SUGGEST_IS_OK SUGGEST_IS_OK<br>
|
||
#define SG_ERR_DRIVER_MASK DRIVER_MASK<br>
|
||
#define SG_ERR_SUGGEST_MASK SUGGEST_MASK<br>
|
||
<p>
|
||
<p>
|
||
<p>
|
||
/* The following "print" functions send ACSII to stdout */<br>
|
||
extern void sg_print_command(const unsigned char * command);<br>
|
||
extern void sg_print_sense(const char * leadin,<br>
|
||
const unsigned char * sense_buffer, int sb_len);<br>
|
||
extern void sg_print_status(int masked_status);<br>
|
||
extern void sg_print_host_status(int host_status);<br>
|
||
extern void sg_print_driver_status(int driver_status);<br>
|
||
<p>
|
||
/* sg_chk_n_print() returns 1 quietly if there are no errors/warnings<br>
|
||
else it prints to standard output and returns 0. */<br>
|
||
extern int sg_chk_n_print(const char * leadin, int masked_status,<br>
|
||
int host_status, int driver_status,<br>
|
||
const unsigned char * sense_buffer, int sb_len);<br>
|
||
#ifdef SG_IO<br>
|
||
extern int sg_chk_n_print3(const char * leadin, Sg_io_hdr * hp);<br>
|
||
#endif<br>
|
||
<p>
|
||
<p>
|
||
/* The following "category" function returns one of the following */<br>
|
||
#define SG_ERR_CAT_CLEAN 0 /* No errors or other information */<br>
|
||
#define SG_ERR_CAT_MEDIA_CHANGED 1 /* interpreted from sense buffer */<br>
|
||
#define SG_ERR_CAT_RESET 2 /* interpreted from sense buffer */<br>
|
||
#define SG_ERR_CAT_TIMEOUT 3<br>
|
||
#define SG_ERR_CAT_RECOVERED 4 /* Successful command after recovered err */<br>
|
||
#define SG_ERR_CAT_SENSE 98 /* Something else is in the sense buffer */<br>
|
||
#define SG_ERR_CAT_OTHER 99 /* Some other error/warning has occurred */<br>
|
||
<p>
|
||
extern int sg_err_category(int masked_status, int host_status,<br>
|
||
int driver_status, const unsigned char * sense_buffer,<br>
|
||
int sb_len);<br>
|
||
#ifdef SG_IO<br>
|
||
extern int sg_err_category3(Sg_io_hdr * hp);<br>
|
||
#endif<br>
|
||
<p>
|
||
<p>
|
||
/* Returns length of SCSI command given the opcode (first byte) */<br>
|
||
int sg_get_command_size(unsigned char opcode);<br>
|
||
<p>
|
||
#endif<br>
|
||
<p>
|
||
<p>
|
||
--------------698ACCDCA92710310744EF83--<br>
|
||
<p>
|
||
<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="0244.html">Jason Joy: "Microtek Scanning"</a>
|
||
<li> <b>Previous message:</b> <a href="0242.html">Jean-François Straeten: "Re: GENIUS ColorPage-HR5 PRO ?"</a>
|
||
<!-- nextthread="start" -->
|
||
<!-- reply="end" -->
|
||
</ul>
|