Microtek, SCSI, and Sane-0.71....

Matto Marjanovic (maddog@mir.com)
Thu, 19 Mar 1998 14:11:13 -0500

Hiya,

For all those wondering what the verdict was on the SCSI errors in Microtek
scanners with SANE-0.71: I recompiled my kernel with all the copious scsi
debugging #define's set, and pieced together what was happening.

The short answer: The scanners generate predictable but unexplainable error
conditions. The best solution is probably to ignore them; following David's
suggestion, at the end of this message is a patch to "sanei/sanei_scsi.c"
which allows the backend's sense_handler to decide if an error condition is
really an error condition. (The patch is only for the Linux portion of the
SCSI code...)

Now, here's the synopsis of what happens in the Microtek E6, and the Linux
scsi code, for those who are interested:

In the E6 (and probably others), the TEST_UNIT_READY command returns a CHECK
CONDITION code precisely when it is called after START_SCAN, GET_SCAN_STATUS,
and READ_SCAN_DATA. This means that you are supposed the call REQUEST_SENSE
to see what is wrong. The sense data indicates "SCSI command or data error"
in the Microtek terminology, but I can't figure out what is wrong, because
the commands seem to execute properly.

Part of the problem here is that the interaction with the Linux scsi drivers
is a bit funny. In the 2.0.32 kernel, the scsi driver is split into three
levels: low, mid, and high. The card interface (in my case, aha152x) is
low, the overall manager scsi.c is mid, and the generic scsi interface sg.c
is high.
In my tests, the aha152x driver doesn't do anything unusual or stupid that I
can see (contrary to my original hunch). When the mid-level driver sees the
CHECK CONDITION code, it sends a REQUEST_SENSE command to the scanner on its
own volition. However, the scanner's sense data does *not* follow SCSI-II
standards (which is almost forgivable because the scanner does identify
itself as using the SCSI-I/CCS command set). This confuses the mid-level
driver, which decides it has done enough and returns a status result which
is a combination of DID_OK, DRIVER_SENSE, and SUGGEST_RETRY --- which means
"I tried getting sense information, and I suggest you retry the command".
The generic scsi high-level code gets this result, sees "DID_OK", figures
everything is fine, *clears* the result, and returns to the user code. This
is dumb, I think, because it could at least pass on the recommendations from
the mid-level driver.
Anyhow, the SANE scsi code ends up getting an "A-OK" result, although the
sense data is still in the sense buffer --- which is a good thing, because
if there were a real error, this is the only way to find out.

Some people have said that they had no problems with an Adaptec 2940 card
(the aic7xxx driver). It could be that the card/low-level driver are doing
the REQUEST_SENSE, getting confused, and not returning any codes in this case.

Anyhow, the best thing to do seems to be to let the backend's sense handler
decide when an error is really an error. Here is a patch which does that
for the Linux-specific code. Please tell me what you think.

-matt m.

===========================================================================

--- sanei_scsi.c-dist Sat Mar 7 00:55:21 1998
+++ sanei_scsi.c Thu Mar 19 13:40:06 1998
@@ -726,36 +726,44 @@
{
nread -= sizeof (req->cdb.hdr);

- if (req->cdb.hdr.result == 0
- && (req->cdb.hdr.sense_buffer[0] & 0x7f) == 0)
- {
- if (req->dst)
- memcpy (req->dst, req->cdb.data, nread);
-
- if (req->dst_len)
- *req->dst_len = nread;
-
- status = SANE_STATUS_GOOD;
- }
- else
+ /* check for errors, but let the sense_handler decide.... */
+ if ((req->cdb.hdr.result != 0) ||
+ ((req->cdb.hdr.sense_buffer[0] & 0x7f) != 0))
{
SANEI_SCSI_Sense_Handler handler
= fd_info[req->fd].sense_handler;
void *arg = fd_info[req->fd].sense_handler_arg;

- DBG(1, "sanei_scsi_req_wait: SCSI command failed: %s\n",
+ DBG(1, "sanei_scsi_req_wait: SCSI command complained: %s\n",
strerror (req->cdb.hdr.result));

if (req->cdb.hdr.result == EBUSY)
status = SANE_STATUS_DEVICE_BUSY;
else if (handler)
+ /* sense handler should return SANE_STATUS_GOOD if it
+ decided all was ok afterall */
status = (*handler) (req->fd, req->cdb.hdr.sense_buffer, arg);
else
status = SANE_STATUS_IO_ERROR;
}
+ else
+ {
+ status = SANE_STATUS_GOOD; /* i.e. no scsi error */
+ }
+
+ /* if we are ok so far, copy over the return data */
+ if (status == SANE_STATUS_GOOD)
+ {
+ if (req->dst)
+ memcpy (req->dst, req->cdb.data, nread);
+
+ if (req->dst_len)
+ *req->dst_len = nread;
+ }
+
}
}
-
+

/* dequeue and release processed request: */
ATOMIC(qhead = qhead->next;

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