Hi Alan,

thanks for your quick reply.

I finally got the camera to work, although my impression is that I am
treating the symptoms rather than curing the disease...


It seems that the camera (Praktica Genius 1.3 using transparent SCSI and bulk-only transport) returns -EPIPE on every third read request(a series of partial reads seems to count as one read). The CSW following this error always has an illegal tag value which can be constructed from the value of the original tag (in fact it is bcb->Tag * 0x100 + 0x43) and a command status of 0x01. After clearing the bulk-in pipe one can proceed as usual.

The idea to handle this problem is to recognize in
usb_stor_Bulk_transport() that the problem has occured during a read and
to just resend the command in that case.

To be able to do so I added an error US_BULK_TRANSFER_STALLED which is
set if -EPIPE occurs in usb_stor_transfer_partial()
(US_BULK_TRANSFER_SHORT would not do). In usb_stor_Bulk_transport() a
flag is set if this error is encountered.

After reading the CSW package there are the following possibilities:

tag ok, flag not set:
        this should be the normal case if everything worked fine

tak ok, flag set:
        the -EPIPE in usb_stor_transfer_partial() was real, initiate normal
error handling

tag not ok, flag not set:
        the bug was triggered during the first attempt to get the CSW; the
proper thing to do would probably be to resend the command, I am just
assuming that the command would have been ok and fixing the status from
0x01 to 0x00

tag not ok, flag set:
        the bug was triggered in usb_stor_transfer_partial(), resend the command

I can't really imagine that this bug can go unnoticed in a driver, so I
imagine the driver within the camera is maybe assuming a special
sequence of statements that prevents this bug from being triggered.
However, I have no idea what this sequence could be...


Since I got the camera working I noticed some more odd things about it: - it returns only 8 bytes instead of the expected 255 on a MODE_SENSE command, the CSW data residue is 0 however; my impression is that it generally does this when sending too short an answer...

- it seems to hang completely on a WRITE_10 command, resets do not help,
one has to unplug it to get it going again (to avoid this, I am mounting
it read-only)

In case you are interested, I attached a patch to illustrate what I
actually did to get the camera working. It is merely intended for
illustration and not even formatted properly...

Best wishes,

Martin.

BTW, the patch includes the interrupt handling changes you sent to me..
and is against 2.4.21-rc6-vanilla


diff -b -u linux-2.4.21-rc6-vanilla/drivers/usb/storage/transport.c linux-2.4.21/drivers/usb/storage/transport.c --- linux-2.4.21-rc6-vanilla/drivers/usb/storage/transport.c Sat Jun 7 09:08:50 2003 +++ linux-2.4.21/drivers/usb/storage/transport.c Sun Jun 8 14:28:42 2003 @@ -523,6 +523,7 @@ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); usb_stor_clear_halt(us, pipe); + return US_BULK_TRANSFER_STALLED; }

        /* did we abort this command? */
@@ -1108,12 +1109,13 @@
        int pipe;
        int partial;
        int ret = USB_STOR_TRANSPORT_ERROR;
+       char redoCommand;

-       bcb = kmalloc(sizeof *bcb, in_interrupt() ? GFP_ATOMIC : GFP_NOIO);
+       bcb = kmalloc(sizeof *bcb, GFP_NOIO);
        if (!bcb) {
                return USB_STOR_TRANSPORT_ERROR;
        }
-       bcs = kmalloc(sizeof *bcs, in_interrupt() ? GFP_ATOMIC : GFP_NOIO);
+       bcs = kmalloc(sizeof *bcs, GFP_NOIO);
        if (!bcs) {
                kfree(bcb);
                return USB_STOR_TRANSPORT_ERROR;
@@ -1130,6 +1132,8 @@
        bcb->Length = srb->cmd_len;

        /* construct the pipe handle */
+do {
+redoCommand   = 0;
        pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);

        /* copy the command payload */
@@ -1170,6 +1174,7 @@

        /* if the command transfered well, then we go to the data stage */
        if (result == 0) {
+
                /* send/receive data payload, if there is any */
                if (bcb->DataTransferLength) {
                        usb_stor_transfer(srb, us);
@@ -1181,6 +1186,11 @@
                                ret = USB_STOR_TRANSPORT_ABORTED;
                                goto out;
                        }
+
+                       if (result == US_BULK_TRANSFER_STALLED) {
+                            redoCommand = 1;
+                            US_DEBUGP("Flagged redo possible\n");
+                       }
                }
        }

@@ -1251,11 +1261,20 @@
                  le32_to_cpu(bcs->Signature), bcs->Tag,
                  bcs->Residue, bcs->Status);
        if (bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN) ||
-           bcs->Tag != bcb->Tag ||
+           (bcs->Tag != bcb->Tag && bcs->Tag != (bcb->Tag*0x100 + 0x43)) ||
            bcs->Status > US_BULK_STAT_PHASE || partial != 13) {
                US_DEBUGP("Bulk logical error\n");
                ret = USB_STOR_TRANSPORT_ERROR;
                goto out;
+       }
+
+} while ( redoCommand &&
+         bcs->Tag == (bcb->Tag*0x100 + 0x43) );
+
+       if ( bcs->Status == US_BULK_STAT_FAIL &&
+            bcs->Tag == (bcb->Tag*0x100 + 0x43) ) {
+            US_DEBUGP("Fixing bulk status\n");
+            bcs->Status = US_BULK_STAT_OK;
        }

        /* based on the status code, we report good or bad */
diff -b -u linux-2.4.21-rc6-vanilla/drivers/usb/storage/transport.h
linux-2.4.21/drivers/usb/storage/transport.h
--- linux-2.4.21-rc6-vanilla/drivers/usb/storage/transport.h    Sat Jun  7
09:05:04 2003
+++ linux-2.4.21/drivers/usb/storage/transport.h        Sun Jun  8 12:51:35 2003
@@ -119,8 +119,9 @@
  */
 #define US_BULK_TRANSFER_GOOD          0  /* good transfer                 */
 #define US_BULK_TRANSFER_SHORT         1  /* transfered less than expected */
-#define US_BULK_TRANSFER_FAILED                2  /* transfer died in the middle   */
-#define US_BULK_TRANSFER_ABORTED       3  /* transfer canceled             */
+#define US_BULK_TRANSFER_STALLED        2  /* pipe was cleared
     */
+#define US_BULK_TRANSFER_FAILED                3  /* transfer died in the middle   */
+#define US_BULK_TRANSFER_ABORTED       4  /* transfer canceled             */

 /*
  * Transport return codes
diff -b -u linux-2.4.21-rc6-vanilla/drivers/usb/storage/unusual_devs.h
linux-2.4.21/drivers/usb/storage/unusual_devs.h
--- linux-2.4.21-rc6-vanilla/drivers/usb/storage/unusual_devs.h Sat Jun
 7 09:08:50 2003
+++ linux-2.4.21/drivers/usb/storage/unusual_devs.h     Sun Jun  8 14:22:23 2003
@@ -53,6 +53,12 @@
                "CD-Writer+",
                US_SC_8070, US_PR_CB, NULL, 0),

+UNUSUAL_DEV(  0x0d64, 0x0107, 0x0100, 0x0100,
+                "Praktica",
+                "DC1.3",
+                US_SC_SCSI, US_PR_BULK, NULL,
+                US_FL_FIX_INQUIRY | US_FL_MODE_XLATE ),
+
 #ifdef CONFIG_USB_STORAGE_HP8200e
 UNUSUAL_DEV(  0x03f0, 0x0207, 0x0001, 0x0001,
                "HP",
.






------------------------------------------------------- This SF.net email is sponsored by: Etnus, makers of TotalView, The best thread debugger on the planet. Designed with thread debugging features you've never dreamed of, try TotalView 6 free at www.etnus.com. _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to