Hi, Greg,

Andrew told me to pipe through your tree. If you clone it from -mm, the
attached incremental diff against -mm should be appropriate. Please let
me know if you need a diff against Linus's tree or if you have any other
problems with this patch.

-- Pete

---------------------------------------------------------------------
Update ub:
 - Add a queue of commands, thus wiping out a bunch of XXX'es
 - Remove usb_endpoint_running to make it compatible with Stern's as331

Signed-off-by: Pete Zaitcev <[EMAIL PROTECTED]>

diff -urp -X dontdiff linux-2.6.8-rc2-mm2/drivers/block/ub.c 
linux-2.6.8-rc2-mm2-ub/drivers/block/ub.c
--- linux-2.6.8-rc2-mm2/drivers/block/ub.c      2004-08-04 23:27:34.000000000 -0700
+++ linux-2.6.8-rc2-mm2-ub/drivers/block/ub.c   2004-08-06 00:14:26.696102821 -0700
@@ -8,20 +8,23 @@
  * and is not licensed separately. See file COPYING for details.
  *
  * TODO (sorted by decreasing priority)
+ *  -- ZIP does "ub: resid 18 len 0 act 0" and whole transport quits (toggles?)
  *  -- set readonly flag for CDs, set removable flag for CF readers
  *  -- do inquiry and verify we got a disk and not a tape (for LUN mismatch)
  *  -- support pphaneuf's SDDR-75 with two LUNs (also broken capacity...)
  *  -- special case some senses, e.g. 3a/0 -> no media present, reduce retries
- *  -- normal queue instead of sc->busy and friends (needed for revalidation)
  *  -- do something about spin-down devices, they are extremely dangerous
- *     (we need to find one first though)
+ *     (ZIP is one. Needs spin-up command as well.)
  *  -- verify the 13 conditions and do bulk resets
  *  -- normal pool of commands instead of cmdv[]?
+ *  -- kill last_pipe and simply do two-state clearing on both pipes
  *  -- verify protocol (bulk) from USB descriptors (maybe...)
  *  -- highmem and sg
  *  -- move top_sense and work_bcs into separate allocations (if they survive)
  *     for cache purists and esoteric architectures.
  *  -- prune comments, they are too volumnous
+ *  -- Exterminate P3 printks
+ *  -- Resove XXX's
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -144,9 +147,10 @@ struct ub_scsi_cmd {
        unsigned char cdb_len;
 
        unsigned char dir;              /* 0 - none, 1 - read, 3 - write. */
+       unsigned char trace_index;
        enum ub_scsi_cmd_state state;
        unsigned int tag;
-       unsigned int trace_index;
+       struct ub_scsi_cmd *next;
 
        int error;                      /* Return code - valid upon done */
        int act_len;                    /* Return size */
@@ -178,7 +182,7 @@ struct ub_capacity {
  */
 
 #define SCMD_ST_HIST_SZ   8
-#define SCMD_TRACE_SZ    15
+#define SCMD_TRACE_SZ    15    /* No more than 256 (trace_index) */
 
 struct ub_scsi_cmd_trace {
        int hcur;
@@ -196,6 +200,55 @@ struct ub_scsi_trace {
 };
 
 /*
+ * This is a direct take-off from linux/include/completion.h
+ * The difference is that I do not wait on this thing, just poll.
+ * When I want to wait (ub_probe), I just use the stock completion.
+ *
+ * Note that INIT_COMPLETION takes no lock. It is correct. But why
+ * in the bloody hell that thing takes struct instead of pointer to struct
+ * is quite beyond me. I just copied it from the stock completion.
+ */
+struct ub_completion {
+       unsigned int done;
+       spinlock_t lock;
+};
+
+static inline void ub_init_completion(struct ub_completion *x)
+{
+       x->done = 0;
+       spin_lock_init(&x->lock);
+}
+
+#define UB_INIT_COMPLETION(x)  ((x).done = 0)
+
+static void ub_complete(struct ub_completion *x)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&x->lock, flags);
+       x->done++;
+       spin_unlock_irqrestore(&x->lock, flags);
+}
+
+static int ub_is_completed(struct ub_completion *x)
+{
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&x->lock, flags);
+       ret = x->done;
+       spin_unlock_irqrestore(&x->lock, flags);
+       return ret;
+}
+
+/*
+ */
+struct ub_scsi_cmd_queue {
+       int qlen, qmax;
+       struct ub_scsi_cmd *head, *tail;
+};
+
+/*
  * The UB device instance.
  */
 struct ub_dev {
@@ -220,17 +273,17 @@ struct ub_dev {
        unsigned int send_ctrl_pipe;
        unsigned int recv_ctrl_pipe;
 
-       struct tasklet_struct urb_tasklet;
+       struct tasklet_struct tasklet;
 
        /* XXX Use Ingo's mempool (once we have more than one) */
        int cmda[1];
        struct ub_scsi_cmd cmdv[1];
 
-       int busy;
-       struct ub_scsi_cmd *top_cmd;    /* XXX Under ->busy until we have a queue */
+       struct ub_scsi_cmd_queue cmd_queue;
        struct ub_scsi_cmd top_rqs_cmd; /* REQUEST SENSE */
        unsigned char top_sense[UB_SENSE_SIZE];
 
+       struct ub_completion work_done;
        struct urb work_urb;
        int last_pipe;                  /* What might need clearing */
        struct bulk_cb_wrap work_bcb;
@@ -245,9 +298,11 @@ struct ub_dev {
 static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
 static void ub_end_rq(struct request *rq, int uptodate);
 static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
-static void ub_scsi_urb_complete(struct urb *urb, struct pt_regs *pt);
-static void ub_scsi_urb_action(unsigned long _dev);
+static void ub_urb_complete(struct urb *urb, struct pt_regs *pt);
+static void ub_scsi_action(unsigned long _dev);
+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_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,
@@ -351,6 +406,12 @@ static ssize_t ub_diag_show(struct devic
 
        cnt = 0;
        spin_lock_irqsave(&sc->lock, flags);
+
+       cnt += sprintf(page + cnt,
+           "qlen %d qmax %d changed %d removable %d readonly %d\n",
+           sc->cmd_queue.qlen, sc->cmd_queue.qmax,
+           sc->changed, sc->removable, sc->readonly);
+
        if ((nc = sc->tr.cur + 1) == SCMD_TRACE_SZ) nc = 0;
        for (j = 0; j < SCMD_TRACE_SZ; j++) {
                t = &sc->tr.vec[nc];
@@ -374,6 +435,7 @@ static ssize_t ub_diag_show(struct devic
 
                if (++nc == SCMD_TRACE_SZ) nc = 0;
        }
+
        spin_unlock_irqrestore(&sc->lock, flags);
        return cnt;
 }
@@ -455,6 +517,58 @@ static void ub_put_cmd(struct ub_dev *sc
 }
 
 /*
+ * The command queue.
+ */
+static void ub_cmdq_add(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+{
+       struct ub_scsi_cmd_queue *t = &sc->cmd_queue;
+
+       if (t->qlen++ == 0) {
+               t->head = cmd;
+               t->tail = cmd;
+       } else {
+               t->tail->next = cmd;
+               t->tail = cmd;
+       }
+
+       if (t->qlen > t->qmax)
+               t->qmax = t->qlen;
+}
+
+static void ub_cmdq_insert(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+{
+       struct ub_scsi_cmd_queue *t = &sc->cmd_queue;
+
+       if (t->qlen++ == 0) {
+               t->head = cmd;
+               t->tail = cmd;
+       } else {
+               cmd->next = t->head;
+               t->head = cmd;
+       }
+
+       if (t->qlen > t->qmax)
+               t->qmax = t->qlen;
+}
+
+static struct ub_scsi_cmd *ub_cmdq_pop(struct ub_dev *sc)
+{
+       struct ub_scsi_cmd_queue *t = &sc->cmd_queue;
+       struct ub_scsi_cmd *cmd;
+
+       if (t->qlen == 0)
+               return NULL;
+       if (--t->qlen == 0)
+               t->tail = NULL;
+       cmd = t->head;
+       t->head = cmd->next;
+       cmd->next = NULL;
+       return cmd;
+}
+
+#define ub_cmdq_peek(sc)  ((sc)->cmd_queue.head)
+
+/*
  * The request function is our main entry point
  */
 
@@ -605,10 +719,7 @@ static void ub_end_rq(struct request *rq
 }
 
 /*
- * Submit a SCSI operation.
- *
- * This is only called customarily from a soft interrupt or a process,
- * so it can call back without worrying about a recursion.
+ * Submit a regular SCSI operation (not an auto-sense).
  *
  * The Iron Law of Good Submit Routine is:
  * Zero return - callback is done, Nonzero return - callback is not done.
@@ -620,43 +731,30 @@ static void ub_end_rq(struct request *rq
  */
 static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 {
-       struct bulk_cb_wrap *bcb;
-       int rc;
-
-       /*
-        * We do not trap into BUG() here because the consequences are
-        * sporadic stack overflows. Better to warn than to die outright.
-        */
-       if (in_irq()) {
-               static int first_warning = 1;
-               if (first_warning) {
-                       printk(KERN_WARNING DRV_NAME ": "
-                           "submitting command from a hard irq\n");
-                       first_warning = 0;
-               }
-       }
-
-       /* XXX Set up a queue */
-       if (cmd != &sc->top_rqs_cmd) {  /* XXX This is getting out of hand. */
-               if (sc->busy)
-                       return -EBUSY;
-               sc->busy = 1;
-               sc->top_cmd = cmd;
-       } else {
-               if (!sc->busy) {
-                       return -EBUSY;
-               }
-       }
-
-       ub_cmdtr_new(sc, cmd);
 
        if (cmd->state != UB_CMDST_INIT ||
            (cmd->dir != UB_DIR_NONE && cmd->len == 0)) {
-               sc->top_cmd = NULL;
-               sc->busy = 0;
                return -EINVAL;
        }
 
+       ub_cmdq_add(sc, cmd);
+       /*
+        * We can call ub_scsi_dispatch(sc) right away here, but it's a little
+        * safer to jump to a tasklet, in case upper layers do something silly.
+        */
+       tasklet_schedule(&sc->tasklet);
+       return 0;
+}
+
+/*
+ * Submit the first URB for the queued command.
+ * This function does not deal with queueing in any way.
+ */
+static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+{
+       struct bulk_cb_wrap *bcb;
+       int rc;
+
        bcb = &sc->work_bcb;
 
        /* set up the command wrapper */
@@ -670,10 +768,11 @@ static int ub_submit_scsi(struct ub_dev 
        /* copy the command payload */
        memcpy(bcb->CDB, cmd->cdb, UB_MAX_CDB_SIZE);
 
+       UB_INIT_COMPLETION(sc->work_done);
+
        sc->last_pipe = sc->send_bulk_pipe;
        usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->send_bulk_pipe,
-           bcb, US_BULK_CB_WRAP_LEN,
-           ub_scsi_urb_complete, sc);
+           bcb, US_BULK_CB_WRAP_LEN, ub_urb_complete, sc);
        sc->work_urb.timeout = UB_URB_TIMEOUT;
 
        /* Fill what we shouldn't be filling, because usb-storage did so. */
@@ -682,14 +781,9 @@ static int ub_submit_scsi(struct ub_dev 
        sc->work_urb.status = 0;
 
        if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
-
                /* XXX Clear stalls */
-               printk("ub: cmd #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */
-
-               cmd->state = UB_CMDST_DONE;
-               ub_cmdtr_state(sc, cmd);
-               sc->busy = 0;
-               sc->top_cmd = NULL;
+               printk("ub: cmd #%d start failed (%d)\n", cmd->tag, rc); /* P3 */
+               ub_complete(&sc->work_done);
                return rc;
        }
 
@@ -705,31 +799,46 @@ static int ub_submit_scsi(struct ub_dev 
  * the sc->lock taken) and from an interrupt (while we do NOT have
  * the sc->lock taken). Therefore, bounce this off to a tasklet.
  */
-static void ub_scsi_urb_complete(struct urb *urb, struct pt_regs *pt)
+static void ub_urb_complete(struct urb *urb, struct pt_regs *pt)
 {
        struct ub_dev *sc = urb->context;
 
-       tasklet_schedule(&sc->urb_tasklet);
+       ub_complete(&sc->work_done);
+       tasklet_schedule(&sc->tasklet);
 }
 
-static void ub_scsi_urb_action(unsigned long _dev)
+static void ub_scsi_action(unsigned long _dev)
 {
        struct ub_dev *sc = (struct ub_dev *) _dev;
        unsigned long flags;
-       struct ub_scsi_cmd *cmd;
 
        spin_lock_irqsave(&sc->lock, flags);
-       if (sc->busy) {
-               cmd = sc->top_cmd;
-               if (cmd->state == UB_CMDST_SENSE) {     /* XXX Kludgy */
-                       cmd = &sc->top_rqs_cmd;
+       ub_scsi_dispatch(sc);
+       spin_unlock_irqrestore(&sc->lock, flags);
+}
+
+static void ub_scsi_dispatch(struct ub_dev *sc)
+{
+       struct ub_scsi_cmd *cmd;
+       int rc;
+
+       while ((cmd = ub_cmdq_peek(sc)) != NULL) {
+               if (cmd->state == UB_CMDST_DONE) {
+                       ub_cmdq_pop(sc);
+                       (*cmd->done)(sc, cmd);
+               } else if (cmd->state == UB_CMDST_INIT) {
+                       ub_cmdtr_new(sc, cmd);
+                       if ((rc = ub_scsi_cmd_start(sc, cmd)) == 0)
+                               break;
+                       cmd->error = rc;
+                       cmd->state = UB_CMDST_DONE;
+                       ub_cmdtr_state(sc, cmd);
+               } else {
+                       if (!ub_is_completed(&sc->work_done))
+                               break;
+                       ub_scsi_urb_compl(sc, cmd);
                }
-               ub_scsi_urb_compl(sc, cmd);
-       } else {
-               /* Never happens */
-               /* P3 */ printk("ub: Action on idle device\n");
        }
-       spin_unlock_irqrestore(&sc->lock, flags);
 }
 
 static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
@@ -764,9 +873,6 @@ static void ub_scsi_urb_compl(struct ub_
                 * We ignore the result for the halt clear.
                 */
 
-               /* reset the toggles and endpoint flags */
-               usb_endpoint_running(sc->dev, usb_pipeendpoint(sc->last_pipe),
-                       usb_pipeout(sc->last_pipe));
                usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe),
                        usb_pipeout(sc->last_pipe), 0);
 
@@ -789,9 +895,6 @@ static void ub_scsi_urb_compl(struct ub_
                 * We ignore the result for the halt clear.
                 */
 
-               /* reset the toggles and endpoint flags */
-               usb_endpoint_running(sc->dev, usb_pipeendpoint(sc->last_pipe),
-                       usb_pipeout(sc->last_pipe));
                usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe),
                        usb_pipeout(sc->last_pipe), 0);
 
@@ -826,32 +929,25 @@ static void ub_scsi_urb_compl(struct ub_
                        return;
                }
 
+               UB_INIT_COMPLETION(sc->work_done);
+
                if (cmd->dir == UB_DIR_READ)
                        pipe = sc->recv_bulk_pipe;
                else
                        pipe = sc->send_bulk_pipe;
                sc->last_pipe = pipe;
                usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe,
-                   cmd->data, cmd->len,
-                   ub_scsi_urb_complete, sc);
+                   cmd->data, cmd->len, ub_urb_complete, sc);
                sc->work_urb.timeout = UB_URB_TIMEOUT;
                sc->work_urb.actual_length = 0;
                sc->work_urb.error_count = 0;
                sc->work_urb.status = 0;
 
                if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
-
                        /* XXX Clear stalls */
                        printk("ub: data #%d submit failed (%d)\n", cmd->tag, rc); /* 
P3 */
-
-                       cmd->error = rc;
-                       cmd->state = UB_CMDST_DONE;
-                       ub_cmdtr_state(sc, cmd);
-                       if (cmd != &sc->top_rqs_cmd) {  /* XXX This is getting out of 
hand. */
-                               sc->busy = 0;
-                               sc->top_cmd = NULL;
-                       }
-                       (*cmd->done)(sc, cmd);
+                       ub_complete(&sc->work_done);
+                       ub_state_done(sc, cmd, rc);
                        return;
                }
 
@@ -927,10 +1023,12 @@ static void ub_scsi_urb_compl(struct ub_
                        /*
                         * 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_scsi_urb_complete, sc);
+                           US_BULK_CS_WRAP_LEN, ub_urb_complete, sc);
                        sc->work_urb.timeout = UB_URB_TIMEOUT;
                        sc->work_urb.actual_length = 0;
                        sc->work_urb.error_count = 0;
@@ -941,15 +1039,8 @@ static void ub_scsi_urb_compl(struct ub_
                                /* XXX Clear stalls */
                                printk("%s: CSW #%d submit failed (%d)\n",
                                   sc->name, cmd->tag, rc); /* P3 */
-
-                               cmd->error = rc;
-                               cmd->state = UB_CMDST_DONE;
-                               ub_cmdtr_state(sc, cmd);
-                               if (cmd != &sc->top_rqs_cmd) {  /* XXX This is getting 
out of hand. */
-                                       sc->busy = 0;
-                                       sc->top_cmd = NULL;
-                               }
-                               (*cmd->done)(sc, cmd);
+                               ub_complete(&sc->work_done);
+                               ub_state_done(sc, cmd, rc);
                                return;
                        }
                        return;
@@ -967,8 +1058,8 @@ static void ub_scsi_urb_compl(struct ub_
                         * to check. But it's not all right if the device
                         * counts disagree with our counts.
                         */
-                       /* P3 */ printk("ub: resid %d len %d act %d\n",
-                           rc, cmd->len, cmd->act_len);
+                       /* P3 */ printk("%s: resid %d len %d act %d\n",
+                           sc->name, rc, cmd->len, cmd->act_len);
                        goto Bad_End;
                }
 
@@ -980,8 +1071,8 @@ static void ub_scsi_urb_compl(struct ub_
                }
 
                if (bcs->Tag != cmd->tag) {
-                       /* P3 */ printk("ub: tag orig 0x%x reply 0x%x\n",
-                           cmd->tag, bcs->Tag);
+                       /* P3 */ printk("%s: tag orig 0x%x reply 0x%x\n",
+                           sc->name, cmd->tag, bcs->Tag);
                        goto Bad_End;
                }
 
@@ -993,7 +1084,7 @@ static void ub_scsi_urb_compl(struct ub_
                        return;
                case US_BULK_STAT_PHASE:
                        /* XXX We must reset the transport here */
-                       /* P3 */ printk("ub: status PHASE\n");
+                       /* P3 */ printk("%s: status PHASE\n", sc->name);
                        goto Bad_End;
                default:
                        printk(KERN_INFO "%s: unknown CSW status 0x%x\n",
@@ -1001,12 +1092,10 @@ static void ub_scsi_urb_compl(struct ub_
                        goto Bad_End;
                }
 
+               /* Not zeroing error to preserve a babble indicator */
                cmd->state = UB_CMDST_DONE;
                ub_cmdtr_state(sc, cmd);
-               if (cmd != &sc->top_rqs_cmd) {  /* XXX This is getting out of hand. */
-                       sc->busy = 0;
-                       sc->top_cmd = NULL;
-               }
+               ub_cmdq_pop(sc);
                (*cmd->done)(sc, cmd);
 
        } else if (cmd->state == UB_CMDST_SENSE) {
@@ -1019,14 +1108,7 @@ static void ub_scsi_urb_compl(struct ub_
                 */
                /* if ((cmd->top_sense[2] & 0x0F) == NO_SENSE) { foo } */
 
-               cmd->error = -EIO;
-               cmd->state = UB_CMDST_DONE;
-               ub_cmdtr_state(sc, cmd);
-               if (cmd != &sc->top_rqs_cmd) {  /* XXX This is getting out of hand. */
-                       sc->busy = 0;
-                       sc->top_cmd = NULL;
-               }
-               (*cmd->done)(sc, cmd);
+               ub_state_done(sc, cmd, -EIO);
        } else {
                printk(KERN_WARNING "%s: "
                    "wrong command state %d on device %u\n",
@@ -1036,13 +1118,20 @@ static void ub_scsi_urb_compl(struct ub_
        return;
 
 Bad_End: /* Little Excel is dead */
-       cmd->error = -EIO;
+       ub_state_done(sc, cmd, -EIO);
+}
+
+/*
+ * Factorization helper for the command state machine:
+ * Finish the command.
+ */
+static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc)
+{
+
+       cmd->error = rc;
        cmd->state = UB_CMDST_DONE;
        ub_cmdtr_state(sc, cmd);
-       if (cmd != &sc->top_rqs_cmd) {  /* XXX This is getting out of hand. */
-               sc->busy = 0;
-               sc->top_cmd = NULL;
-       }
+       ub_cmdq_pop(sc);
        (*cmd->done)(sc, cmd);
 }
 
@@ -1054,28 +1143,21 @@ static void ub_state_stat(struct ub_dev 
 {
        int rc;
 
+       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_scsi_urb_complete, sc);
+           &sc->work_bcs, US_BULK_CS_WRAP_LEN, ub_urb_complete, sc);
        sc->work_urb.timeout = UB_URB_TIMEOUT;
        sc->work_urb.actual_length = 0;
        sc->work_urb.error_count = 0;
        sc->work_urb.status = 0;
 
        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 */
-
-               cmd->error = rc;
-               cmd->state = UB_CMDST_DONE;
-               ub_cmdtr_state(sc, cmd);
-               if (cmd != &sc->top_rqs_cmd) {  /* XXX This is getting out of hand. */
-                       sc->busy = 0;
-                       sc->top_cmd = NULL;
-               }
-               (*cmd->done)(sc, cmd);
+               ub_complete(&sc->work_done);
+               ub_state_done(sc, cmd, rc);
                return;
        }
 
@@ -1110,27 +1192,15 @@ static void ub_state_sense(struct ub_dev
        scmd->back = cmd;
 
        scmd->tag = sc->tagcnt++;
-       if ((rc = ub_submit_scsi(sc, scmd)) != 0) {
-               printk(KERN_NOTICE "%s: "
-                   "unable to submit sense for device %u (%d)\n",
-                   sc->name, sc->dev->devnum, rc);
-               rc = -EIO;
-               goto error;
-       }
 
        cmd->state = UB_CMDST_SENSE;
        ub_cmdtr_state(sc, cmd);
+
+       ub_cmdq_insert(sc, scmd);
        return;
 
 error:
-       cmd->error = rc;
-       cmd->state = UB_CMDST_DONE;
-       ub_cmdtr_state(sc, cmd);
-       if (cmd != &sc->top_rqs_cmd) {  /* XXX This is getting out of hand. */
-               sc->busy = 0;
-               sc->top_cmd = NULL;
-       }
-       (*cmd->done)(sc, cmd);
+       ub_state_done(sc, cmd, rc);
 }
 
 /*
@@ -1142,6 +1212,7 @@ static int ub_submit_clear_stall(struct 
 {
        int endp;
        struct usb_ctrlrequest *cr;
+       int rc;
 
        endp = usb_pipeendpoint(stalled_pipe);
        if (usb_pipein (stalled_pipe))
@@ -1154,15 +1225,21 @@ static int ub_submit_clear_stall(struct 
        cr->wIndex = cpu_to_le16(endp);
        cr->wLength = cpu_to_le16(0);
 
+       UB_INIT_COMPLETION(sc->work_done);
+
        usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
            (unsigned char*) cr, NULL, 0,
-           ub_scsi_urb_complete, sc);
+           ub_urb_complete, sc);
        sc->work_urb.timeout = UB_CTRL_TIMEOUT;
        sc->work_urb.actual_length = 0;
        sc->work_urb.error_count = 0;
        sc->work_urb.status = 0;
 
-       return usb_submit_urb(&sc->work_urb, GFP_ATOMIC);
+       if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
+               ub_complete(&sc->work_done);
+               return rc;
+       }
+       return 0;
 }
 
 /*
@@ -1174,11 +1251,16 @@ static void ub_top_sense_done(struct ub_
 
        ub_cmdtr_sense(sc, scmd, sense);
 
-       if (!sc->busy) {        /* P3 */
+       if ((cmd = ub_cmdq_peek(sc)) == NULL) {
                printk(KERN_WARNING "%s: sense done while idle\n", sc->name);
                return;
        }
-       cmd = scmd->back;
+       if (cmd != scmd->back) {
+               printk(KERN_WARNING "%s: "
+                   "sense done for wrong command 0x%x on device %u\n",
+                   sc->name, cmd->tag, sc->dev->devnum);
+               return;
+       }
        if (cmd->state != UB_CMDST_SENSE) {
                printk(KERN_WARNING "%s: "
                    "sense done with bad cmd state %d on device %u\n",
@@ -1231,7 +1313,14 @@ int usb_stor_Bulk_max_lun(struct us_data
 static void ub_revalidate(struct ub_dev *sc)
 {
 
-       sc->capacity.nsec = 0;
+       sc->readonly = 0;       /* XXX Query this from the device */
+
+       /*
+        * XXX sd.c sets capacity to zero in such case. However, it doesn't
+        * work for us. In case of zero capacity, block layer refuses to
+        * have the /dev/uba opened (why?) Set capacity to some random value.
+        */
+       sc->capacity.nsec = 50;
        sc->capacity.bsize = 512;
        sc->capacity.bshift = 0;
 
@@ -1251,10 +1340,6 @@ static void ub_revalidate(struct ub_dev 
                        sc->capacity.bshift = 0;
                }
        }
-
-       /* XXX Set these to some reasonable values. */
-       sc->readonly = 0;
-       sc->removable = 1;
 }
 
 /*
@@ -1602,8 +1687,6 @@ static int ub_probe_clear_stall(struct u
 
        wait_for_completion(&compl);
 
-       /* reset the toggles and endpoint flags */
-       usb_endpoint_running(sc->dev, endp, usb_pipeout(sc->last_pipe));
        usb_settoggle(sc->dev, endp, usb_pipeout(sc->last_pipe), 0);
 
        return 0;
@@ -1675,9 +1758,12 @@ static int ub_probe(struct usb_interface
        memset(sc, 0, sizeof(struct ub_dev));
        spin_lock_init(&sc->lock);
        usb_init_urb(&sc->work_urb);
-       tasklet_init(&sc->urb_tasklet, ub_scsi_urb_action, (unsigned long)sc);
+       tasklet_init(&sc->tasklet, ub_scsi_action, (unsigned long)sc);
        atomic_set(&sc->poison, 0);
 
+       ub_init_completion(&sc->work_done);
+       sc->work_done.done = 1;         /* A little yuk, but oh well... */
+
        rc = -ENOSR;
        if ((sc->id = ub_id_get()) == -1)
                goto err_id;
@@ -1729,6 +1815,8 @@ static int ub_probe(struct usb_interface
         */
        ub_sync_tur(sc);
 
+       sc->removable = 1;              /* XXX Query this from the device */
+
        ub_revalidate(sc);
        /* This is pretty much a long term P3 */
        printk(KERN_INFO "%s: device %u capacity nsec %ld bsize %u\n",
@@ -1815,6 +1903,34 @@ static void ub_disconnect(struct usb_int
        atomic_set(&sc->poison, 1);
 
        /*
+        * Blow away queued commands.
+        *
+        * Actually, this never works, because before we get here
+        * the HCD terminates outstanding URB(s). It causes our
+        * SCSI command queue to advance, commands fail to submit,
+        * and the whole queue drains. So, we just use this code to
+        * print warnings.
+        */
+       spin_lock_irqsave(&sc->lock, flags);
+       {
+               struct ub_scsi_cmd *cmd;
+               int cnt = 0;
+               while ((cmd = ub_cmdq_pop(sc)) != NULL) {
+                       cmd->error = -ENOTCONN;
+                       cmd->state = UB_CMDST_DONE;
+                       ub_cmdtr_state(sc, cmd);
+                       ub_cmdq_pop(sc);
+                       (*cmd->done)(sc, cmd);
+                       cnt++;
+               }
+               if (cnt != 0) {
+                       printk(KERN_WARNING "%s: "
+                           "%d was queued after shutdown\n", sc->name, cnt);
+               }
+       }
+       spin_unlock_irqrestore(&sc->lock, flags);
+
+       /*
         * Unregister the upper layer, this waits for all commands to end.
         */
        if (disk->flags & GENHD_FL_UP)
@@ -1845,11 +1961,6 @@ static void ub_disconnect(struct usb_int
         * the rules a little.
         */
        spin_lock_irqsave(&sc->lock, flags);
-       if (sc->busy) {
-               printk(KERN_WARNING "%s: "
-                   "command is active after disconnect, status %d\n",
-                   sc->name, sc->top_cmd->state);
-       }
        if (sc->work_urb.status == -EINPROGRESS) {      /* janitors: ignore */
                printk(KERN_WARNING "%s: "
                    "URB is active after disconnect\n", sc->name);


-------------------------------------------------------
This SF.Net email is sponsored by OSTG. Have you noticed the changes on
Linux.com, ITManagersJournal and NewsForge in the past few weeks? Now,
one more big change to announce. We are now OSTG- Open Source Technology
Group. Come see the changes on the new OSTG site. www.ostg.com
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to