ChangeSet 1.2329.2.5, 2005/01/14 16:23:14-08:00, [EMAIL PROTECTED] [PATCH] USB: Patch to fix ub looping with a tag mismatch
If a command times out, we resubmit a retry. Some devices, however, buffer everything we send and then eventually reply to a command we have timed out already. We receive a bad tag, send a new command, device replies to the one sent before, and so on without end. The fix is to flush pending replies if tags mismatch (by reading them). Signed-off-by: Pete Zaitcev <[EMAIL PROTECTED]> Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]> drivers/block/ub.c | 86 +++++++++++++++++++++++++++-------------------------- 1 files changed, 44 insertions(+), 42 deletions(-) diff -Nru a/drivers/block/ub.c b/drivers/block/ub.c --- a/drivers/block/ub.c 2005-01-17 13:50:26 -08:00 +++ b/drivers/block/ub.c 2005-01-17 13:50:26 -08:00 @@ -108,7 +108,8 @@ */ #define UB_URB_TIMEOUT (HZ*2) #define UB_DATA_TIMEOUT (HZ*5) /* ZIP does spin-ups in the data phase */ -#define UB_CTRL_TIMEOUT (HZ/2) /* 500ms ought to be enough to clear a stall */ +#define UB_STAT_TIMEOUT (HZ*5) /* Same spinups and eject for a dataless cmd. */ +#define UB_CTRL_TIMEOUT (HZ/2) /* 500ms ought to be enough to clear a stall */ /* * An instance of a SCSI command in transit. @@ -307,6 +308,7 @@ static void ub_scsi_dispatch(struct ub_dev *sc); static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd); static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc); +static void __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd); static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd); static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd); static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd, @@ -894,7 +896,7 @@ if (urb->status == -EPIPE) { /* * STALL while clearning STALL. - * A STALL is illegal on a control pipe! + * The control pipe clears itself - nothing to do. * XXX Might try to reset the device here and retry. */ printk(KERN_NOTICE "%s: " @@ -917,7 +919,7 @@ if (urb->status == -EPIPE) { /* * STALL while clearning STALL. - * A STALL is illegal on a control pipe! + * The control pipe clears itself - nothing to do. * XXX Might try to reset the device here and retry. */ printk(KERN_NOTICE "%s: " @@ -941,7 +943,8 @@ rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe); if (rc != 0) { printk(KERN_NOTICE "%s: " - "unable to submit clear for device %u (%d)\n", + "unable to submit clear for device %u" + " (code %d)\n", sc->name, sc->dev->devnum, rc); /* * This is typically ENOMEM or some other such shit. @@ -1001,7 +1004,8 @@ rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe); if (rc != 0) { printk(KERN_NOTICE "%s: " - "unable to submit clear for device %u (%d)\n", + "unable to submit clear for device %u" + " (code %d)\n", sc->name, sc->dev->devnum, rc); /* * This is typically ENOMEM or some other such shit. @@ -1033,7 +1037,8 @@ rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe); if (rc != 0) { printk(KERN_NOTICE "%s: " - "unable to submit clear for device %u (%d)\n", + "unable to submit clear for device %u" + " (code %d)\n", sc->name, sc->dev->devnum, rc); /* * This is typically ENOMEM or some other such shit. @@ -1061,33 +1066,7 @@ sc->name, sc->dev->devnum); goto Bad_End; } - - /* - * ub_state_stat only not dropping the count... - */ - UB_INIT_COMPLETION(sc->work_done); - - sc->last_pipe = sc->recv_bulk_pipe; - usb_fill_bulk_urb(&sc->work_urb, sc->dev, - sc->recv_bulk_pipe, &sc->work_bcs, - US_BULK_CS_WRAP_LEN, ub_urb_complete, sc); - sc->work_urb.transfer_flags = URB_ASYNC_UNLINK; - sc->work_urb.actual_length = 0; - sc->work_urb.error_count = 0; - sc->work_urb.status = 0; - - rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC); - if (rc != 0) { - /* XXX Clear stalls */ - printk("%s: CSW #%d submit failed (%d)\n", - sc->name, cmd->tag, rc); /* P3 */ - ub_complete(&sc->work_done); - ub_state_done(sc, cmd, rc); - return; - } - - sc->work_timer.expires = jiffies + UB_URB_TIMEOUT; - add_timer(&sc->work_timer); + __ub_state_stat(sc, cmd); return; } @@ -1108,17 +1087,31 @@ goto Bad_End; } +#if 0 if (bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN) && bcs->Signature != cpu_to_le32(US_BULK_CS_OLYMPUS_SIGN)) { - /* XXX Rate-limit, even for P3 tagged */ - /* P3 */ printk("ub: signature 0x%x\n", bcs->Signature); /* Windows ignores signatures, so do we. */ } +#endif if (bcs->Tag != cmd->tag) { - /* P3 */ printk("%s: tag orig 0x%x reply 0x%x\n", - sc->name, cmd->tag, bcs->Tag); - goto Bad_End; + /* + * This usually happens when we disagree with the + * device's microcode about something. For instance, + * a few of them throw this after timeouts. They buffer + * commands and reply at commands we timed out before. + * Without flushing these replies we loop forever. + */ + if (++cmd->stat_count >= 4) { + printk(KERN_NOTICE "%s: " + "tag mismatch orig 0x%x reply 0x%x " + "on device %u\n", + sc->name, cmd->tag, bcs->Tag, + sc->dev->devnum); + goto Bad_End; + } + __ub_state_stat(sc, cmd); + return; } switch (bcs->Status) { @@ -1174,9 +1167,9 @@ /* * Factorization helper for the command state machine: - * Submit a CSW read and go to STAT state. + * Submit a CSW read. */ -static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +static void __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) { int rc; @@ -1192,14 +1185,23 @@ if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { /* XXX Clear stalls */ - printk("ub: CSW #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */ + printk("%s: CSW #%d submit failed (%d)\n", sc->name, cmd->tag, rc); /* P3 */ ub_complete(&sc->work_done); ub_state_done(sc, cmd, rc); return; } - sc->work_timer.expires = jiffies + UB_URB_TIMEOUT; + sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT; add_timer(&sc->work_timer); +} + +/* + * Factorization helper for the command state machine: + * Submit a CSW read and go to STAT state. + */ +static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + __ub_state_stat(sc, cmd); cmd->stat_count = 0; cmd->state = UB_CMDST_STAT; ------------------------------------------------------- The SF.Net email is sponsored by: Beat the post-holiday blues Get a FREE limited edition SourceForge.net t-shirt from ThinkGeek. It's fun and FREE -- well, almost....http://www.thinkgeek.com/sfshirt _______________________________________________ linux-usb-devel@lists.sourceforge.net To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel