nfsd: filter lookup results in V4ROOT case
[safe/jmp/linux-2.6] / drivers / block / ub.c
index fe81d2f..c739b20 100644 (file)
@@ -8,34 +8,28 @@
  * and is not licensed separately. See file COPYING for details.
  *
  * TODO (sorted by decreasing priority)
- *  -- Kill first_open (Al Viro fixed the block layer now)
- *  -- Do resets with usb_device_reset (needs a thread context, use khubd)
+ *  -- Return sense now that rq allows it (we always auto-sense anyway).
  *  -- 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)
- *  -- special case some senses, e.g. 3a/0 -> no media present, reduce retries
  *  -- verify the 13 conditions and do bulk resets
- *  -- kill last_pipe and simply do two-state clearing on both pipes
- *  -- verify protocol (bulk) from USB descriptors (maybe...)
  *  -- highmem
  *  -- move top_sense and work_bcs into separate allocations (if they survive)
  *     for cache purists and esoteric architectures.
  *  -- Allocate structure for LUN 0 before the first ub_sync_tur, avoid NULL. ?
  *  -- prune comments, they are too volumnous
- *  -- Exterminate P3 printks
  *  -- Resove XXX's
- *  -- Redo "benh's retries", perhaps have spin-up code to handle them. V:D=?
  *  -- CLEAR, CLR2STS, CLRRS seem to be ripe for refactoring.
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/usb.h>
+#include <linux/usb_usual.h>
 #include <linux/blkdev.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/timer.h>
+#include <linux/scatterlist.h>
 #include <scsi/scsi.h>
 
 #define DRV_NAME "ub"
-#define DEVFS_NAME DRV_NAME
 
 #define UB_MAJOR 180
 
  */
 
 /*
- * Definitions which have to be scattered once we understand the layout better.
- */
-
-/* Transport (despite PR in the name) */
-#define US_PR_BULK     0x50            /* bulk only */
-
-/* Protocol */
-#define US_SC_SCSI     0x06            /* Transparent */
-
-/*
  * This many LUNs per USB device.
  * Every one of them takes a host, see UB_MAX_HOSTS.
  */
 /*
  */
 
-#define UB_MINORS_PER_MAJOR    8
+#define UB_PARTS_PER_LUN      8
 
 #define UB_MAX_CDB_SIZE      16                /* Corresponds to Bulk */
 
@@ -172,7 +156,7 @@ struct bulk_cs_wrap {
  */
 struct ub_dev;
 
-#define UB_MAX_REQ_SG  4
+#define UB_MAX_REQ_SG  9       /* cdrecord requires 32KB and maybe a header */
 #define UB_MAX_SECTORS 64
 
 /*
@@ -207,24 +191,11 @@ enum ub_scsi_cmd_state {
        UB_CMDST_DONE                   /* Final state */
 };
 
-static char *ub_scsi_cmd_stname[] = {
-       ".  ",
-       "Cmd",
-       "dat",
-       "c2s",
-       "sts",
-       "clr",
-       "crs",
-       "Sen",
-       "fin"
-};
-
 struct ub_scsi_cmd {
        unsigned char cdb[UB_MAX_CDB_SIZE];
        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;
        struct ub_scsi_cmd *next;
@@ -234,13 +205,12 @@ struct ub_scsi_cmd {
        unsigned char key, asc, ascq;   /* May be valid if error==-EIO */
 
        int stat_count;                 /* Retries getting status. */
+       unsigned int timeo;             /* jiffies until rq->timeout changes */
 
-       /*
-        * We do not support transfers from highmem pages
-        * because the underlying USB framework does not do what we need.
-        */
-       char *data;                     /* Requested buffer */
        unsigned int len;               /* Requested length */
+       unsigned int current_sg;
+       unsigned int nsg;               /* sgv[nsg] */
+       struct scatterlist sgv[UB_MAX_REQ_SG];
 
        struct ub_lun *lun;
        void (*done)(struct ub_dev *, struct ub_scsi_cmd *);
@@ -249,9 +219,7 @@ struct ub_scsi_cmd {
 
 struct ub_request {
        struct request *rq;
-       unsigned char dir;
-       unsigned int current_block;
-       unsigned int current_sg;
+       unsigned int current_try;
        unsigned int nsg;               /* sgv[nsg] */
        struct scatterlist sgv[UB_MAX_REQ_SG];
 };
@@ -265,28 +233,6 @@ struct ub_capacity {
 };
 
 /*
- * The SCSI command tracing structure.
- */
-
-#define SCMD_ST_HIST_SZ   8
-#define SCMD_TRACE_SZ    63            /* Less than 4KB of 61-byte lines */
-
-struct ub_scsi_cmd_trace {
-       int hcur;
-       unsigned int tag;
-       unsigned int req_size, act_size;
-       unsigned char op;
-       unsigned char dir;
-       unsigned char key, asc, ascq;
-       char st_hst[SCMD_ST_HIST_SZ];   
-};
-
-struct ub_scsi_trace {
-       int cur;
-       struct ub_scsi_cmd_trace vec[SCMD_TRACE_SZ];
-};
-
-/*
  * 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.
@@ -349,7 +295,6 @@ struct ub_lun {
        int changed;                    /* Media was changed */
        int removable;
        int readonly;
-       int first_open;                 /* Kludge. See ub_bd_open. */
 
        struct ub_request urq;
 
@@ -369,10 +314,12 @@ struct ub_lun {
  * The USB device instance.
  */
 struct ub_dev {
-       spinlock_t lock;
+       spinlock_t *lock;
        atomic_t poison;                /* The USB device is disconnected */
        int openc;                      /* protected by ub_lock! */
                                        /* kref is too implicit for our taste */
+       int reset;                      /* Reset is running */
+       int bad_resid;
        unsigned int tagcnt;
        char name[12];
        struct usb_device *dev;
@@ -400,29 +347,28 @@ struct ub_dev {
        struct bulk_cs_wrap work_bcs;
        struct usb_ctrlrequest work_cr;
 
-       int sg_stat[UB_MAX_REQ_SG+1];
-       struct ub_scsi_trace tr;
+       struct work_struct reset_work;
+       wait_queue_head_t reset_wait;
 };
 
 /*
  */
 static void ub_cleanup(struct ub_dev *sc);
-static int ub_bd_rq_fn_1(struct ub_lun *lun, struct request *rq);
-static int ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
-    struct ub_scsi_cmd *cmd, struct request *rq);
-static void ub_scsi_build_block(struct ub_lun *lun,
+static int ub_request_fn_1(struct ub_lun *lun, struct request *rq);
+static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
+    struct ub_scsi_cmd *cmd, struct ub_request *urq);
+static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
     struct ub_scsi_cmd *cmd, struct ub_request *urq);
-static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
-    struct ub_scsi_cmd *cmd, struct request *rq);
 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_request_advance(struct ub_dev *sc, struct ub_lun *lun,
+static void ub_end_rq(struct request *rq, unsigned int status);
+static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
     struct ub_request *urq, struct ub_scsi_cmd *cmd);
 static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
-static void ub_urb_complete(struct urb *urb, struct pt_regs *pt);
+static void ub_urb_complete(struct urb *urb);
 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_data_start(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 int __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);
@@ -431,20 +377,29 @@ 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,
     int stalled_pipe);
 static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd);
+static void ub_reset_enter(struct ub_dev *sc, int try);
+static void ub_reset_task(struct work_struct *work);
 static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun);
 static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
     struct ub_capacity *ret);
+static int ub_sync_reset(struct ub_dev *sc);
+static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe);
 static int ub_probe_lun(struct ub_dev *sc, int lnum);
 
 /*
  */
+#ifdef CONFIG_USB_LIBUSUAL
+
+#define ub_usb_ids  usb_storage_usb_ids
+#else
+
 static struct usb_device_id ub_usb_ids[] = {
-       // { USB_DEVICE_VER(0x0781, 0x0002, 0x0009, 0x0009) },  /* SDDR-31 */
        { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) },
        { }
 };
 
 MODULE_DEVICE_TABLE(usb, ub_usb_ids);
+#endif /* CONFIG_USB_LIBUSUAL */
 
 /*
  * Find me a way to identify "next free minor" for add_disk(),
@@ -456,134 +411,11 @@ MODULE_DEVICE_TABLE(usb, ub_usb_ids);
 #define UB_MAX_HOSTS  26
 static char ub_hostv[UB_MAX_HOSTS];
 
-static DEFINE_SPINLOCK(ub_lock);       /* Locks globals and ->openc */
-
-/*
- * The SCSI command tracing procedures.
- */
-
-static void ub_cmdtr_new(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-       int n;
-       struct ub_scsi_cmd_trace *t;
-
-       if ((n = sc->tr.cur + 1) == SCMD_TRACE_SZ) n = 0;
-       t = &sc->tr.vec[n];
-
-       memset(t, 0, sizeof(struct ub_scsi_cmd_trace));
-       t->tag = cmd->tag;
-       t->op = cmd->cdb[0];
-       t->dir = cmd->dir;
-       t->req_size = cmd->len;
-       t->st_hst[0] = cmd->state;
+#define UB_QLOCK_NUM 5
+static spinlock_t ub_qlockv[UB_QLOCK_NUM];
+static int ub_qlock_next = 0;
 
-       sc->tr.cur = n;
-       cmd->trace_index = n;
-}
-
-static void ub_cmdtr_state(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-       int n;
-       struct ub_scsi_cmd_trace *t;
-
-       t = &sc->tr.vec[cmd->trace_index];
-       if (t->tag == cmd->tag) {
-               if ((n = t->hcur + 1) == SCMD_ST_HIST_SZ) n = 0;
-               t->st_hst[n] = cmd->state;
-               t->hcur = n;
-       }
-}
-
-static void ub_cmdtr_act_len(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-       struct ub_scsi_cmd_trace *t;
-
-       t = &sc->tr.vec[cmd->trace_index];
-       if (t->tag == cmd->tag)
-               t->act_size = cmd->act_len;
-}
-
-static void ub_cmdtr_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
-    unsigned char *sense)
-{
-       struct ub_scsi_cmd_trace *t;
-
-       t = &sc->tr.vec[cmd->trace_index];
-       if (t->tag == cmd->tag) {
-               t->key = sense[2] & 0x0F;
-               t->asc = sense[12];
-               t->ascq = sense[13];
-       }
-}
-
-static ssize_t ub_diag_show(struct device *dev, struct device_attribute *attr,
-    char *page)
-{
-       struct usb_interface *intf;
-       struct ub_dev *sc;
-       struct list_head *p;
-       struct ub_lun *lun;
-       int cnt;
-       unsigned long flags;
-       int nc, nh;
-       int i, j;
-       struct ub_scsi_cmd_trace *t;
-
-       intf = to_usb_interface(dev);
-       sc = usb_get_intfdata(intf);
-       if (sc == NULL)
-               return 0;
-
-       cnt = 0;
-       spin_lock_irqsave(&sc->lock, flags);
-
-       cnt += sprintf(page + cnt,
-           "qlen %d qmax %d\n",
-           sc->cmd_queue.qlen, sc->cmd_queue.qmax);
-       cnt += sprintf(page + cnt,
-           "sg %d %d %d %d %d\n",
-           sc->sg_stat[0],
-           sc->sg_stat[1],
-           sc->sg_stat[2],
-           sc->sg_stat[3],
-           sc->sg_stat[4]);
-
-       list_for_each (p, &sc->luns) {
-               lun = list_entry(p, struct ub_lun, link);
-               cnt += sprintf(page + cnt,
-                   "lun %u changed %d removable %d readonly %d\n",
-                   lun->num, lun->changed, lun->removable, lun->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];
-
-               cnt += sprintf(page + cnt, "%08x %02x", t->tag, t->op);
-               if (t->op == REQUEST_SENSE) {
-                       cnt += sprintf(page + cnt, " [sense %x %02x %02x]",
-                                       t->key, t->asc, t->ascq);
-               } else {
-                       cnt += sprintf(page + cnt, " %c", UB_DIR_CHAR(t->dir));
-                       cnt += sprintf(page + cnt, " [%5d %5d]",
-                                       t->req_size, t->act_size);
-               }
-               if ((nh = t->hcur + 1) == SCMD_ST_HIST_SZ) nh = 0;
-               for (i = 0; i < SCMD_ST_HIST_SZ; i++) {
-                       cnt += sprintf(page + cnt, " %s",
-                                       ub_scsi_cmd_stname[(int)t->st_hst[nh]]);
-                       if (++nh == SCMD_ST_HIST_SZ) nh = 0;
-               }
-               cnt += sprintf(page + cnt, "\n");
-
-               if (++nc == SCMD_TRACE_SZ) nc = 0;
-       }
-
-       spin_unlock_irqrestore(&sc->lock, flags);
-       return cnt;
-}
-
-static DEVICE_ATTR(diag, S_IRUGO, ub_diag_show, NULL); /* N.B. World readable */
+static DEFINE_SPINLOCK(ub_lock);       /* Locks globals and ->openc */
 
 /*
  * The id allocator.
@@ -627,6 +459,24 @@ static void ub_id_put(int id)
 }
 
 /*
+ * This is necessitated by the fact that blk_cleanup_queue does not
+ * necesserily destroy the queue. Instead, it may merely decrease q->refcnt.
+ * Since our blk_init_queue() passes a spinlock common with ub_dev,
+ * we have life time issues when ub_cleanup frees ub_dev.
+ */
+static spinlock_t *ub_next_lock(void)
+{
+       unsigned long flags;
+       spinlock_t *ret;
+
+       spin_lock_irqsave(&ub_lock, flags);
+       ret = &ub_qlockv[ub_qlock_next];
+       ub_qlock_next = (ub_qlock_next + 1) % UB_QLOCK_NUM;
+       spin_unlock_irqrestore(&ub_lock, flags);
+       return ret;
+}
+
+/*
  * Downcount for deallocation. This rides on two assumptions:
  *  - once something is poisoned, its refcount cannot grow
  *  - opens cannot happen at this time (del_gendisk was done)
@@ -655,7 +505,7 @@ static void ub_cleanup(struct ub_dev *sc)
 {
        struct list_head *p;
        struct ub_lun *lun;
-       request_queue_t *q;
+       struct request_queue *q;
 
        while (!list_empty(&sc->luns)) {
                p = sc->luns.next;
@@ -681,6 +531,9 @@ static void ub_cleanup(struct ub_dev *sc)
                kfree(lun);
        }
 
+       usb_set_intfdata(sc->intf, NULL);
+       usb_put_intf(sc->intf);
+       usb_put_dev(sc->dev);
        kfree(sc);
 }
 
@@ -768,28 +621,35 @@ static struct ub_scsi_cmd *ub_cmdq_pop(struct ub_dev *sc)
  * The request function is our main entry point
  */
 
-static void ub_bd_rq_fn(request_queue_t *q)
+static void ub_request_fn(struct request_queue *q)
 {
        struct ub_lun *lun = q->queuedata;
        struct request *rq;
 
-       while ((rq = elv_next_request(q)) != NULL) {
-               if (ub_bd_rq_fn_1(lun, rq) != 0) {
+       while ((rq = blk_peek_request(q)) != NULL) {
+               if (ub_request_fn_1(lun, rq) != 0) {
                        blk_stop_queue(q);
                        break;
                }
        }
 }
 
-static int ub_bd_rq_fn_1(struct ub_lun *lun, struct request *rq)
+static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
 {
        struct ub_dev *sc = lun->udev;
        struct ub_scsi_cmd *cmd;
-       int rc;
+       struct ub_request *urq;
+       int n_elem;
 
-       if (atomic_read(&sc->poison) || lun->changed) {
-               blkdev_dequeue_request(rq);
-               ub_end_rq(rq, 0);
+       if (atomic_read(&sc->poison)) {
+               blk_start_request(rq);
+               ub_end_rq(rq, DID_NO_CONNECT << 16);
+               return 0;
+       }
+
+       if (lun->changed && !blk_pc_request(rq)) {
+               blk_start_request(rq);
+               ub_end_rq(rq, SAM_STAT_CHECK_CONDITION);
                return 0;
        }
 
@@ -799,93 +659,76 @@ static int ub_bd_rq_fn_1(struct ub_lun *lun, struct request *rq)
                return -1;
        memset(cmd, 0, sizeof(struct ub_scsi_cmd));
 
-       blkdev_dequeue_request(rq);
-       if (blk_pc_request(rq)) {
-               rc = ub_cmd_build_packet(sc, lun, cmd, rq);
-       } else {
-               rc = ub_cmd_build_block(sc, lun, cmd, rq);
-       }
-       if (rc != 0) {
-               ub_put_cmd(lun, cmd);
-               ub_end_rq(rq, 0);
-               return 0;
-       }
-       cmd->state = UB_CMDST_INIT;
-       cmd->lun = lun;
-       cmd->done = ub_rw_cmd_done;
-       cmd->back = &lun->urq;
-
-       cmd->tag = sc->tagcnt++;
-       if (ub_submit_scsi(sc, cmd) != 0) {
-               ub_put_cmd(lun, cmd);
-               ub_end_rq(rq, 0);
-               return 0;
-       }
-
-       return 0;
-}
-
-static int ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
-    struct ub_scsi_cmd *cmd, struct request *rq)
-{
-       struct ub_request *urq;
-       int ub_dir;
-       int n_elem;
+       blk_start_request(rq);
 
        urq = &lun->urq;
        memset(urq, 0, sizeof(struct ub_request));
-
-       if (rq_data_dir(rq) == WRITE)
-               ub_dir = UB_DIR_WRITE;
-       else
-               ub_dir = UB_DIR_READ;
+       urq->rq = rq;
 
        /*
         * get scatterlist from block layer
         */
+       sg_init_table(&urq->sgv[0], UB_MAX_REQ_SG);
        n_elem = blk_rq_map_sg(lun->disk->queue, rq, &urq->sgv[0]);
-       if (n_elem <= 0) {
+       if (n_elem < 0) {
+               /* Impossible, because blk_rq_map_sg should not hit ENOMEM. */
                printk(KERN_INFO "%s: failed request map (%d)\n",
-                   sc->name, n_elem); /* P3 */
-               return -1;              /* request with no s/g entries? */
+                   lun->name, n_elem);
+               goto drop;
        }
        if (n_elem > UB_MAX_REQ_SG) {   /* Paranoia */
                printk(KERN_WARNING "%s: request with %d segments\n",
-                   sc->name, n_elem);
-               return -1;
+                   lun->name, n_elem);
+               goto drop;
        }
        urq->nsg = n_elem;
-       sc->sg_stat[n_elem]++;
 
-       /*
-        * build the command
-        *
-        * The call to blk_queue_hardsect_size() guarantees that request
-        * is aligned, but it is given in terms of 512 byte units, always.
-        */
-       urq->current_block = rq->sector >> lun->capacity.bshift;
-       // nblks = rq->nr_sectors >> lun->capacity.bshift;
+       if (blk_pc_request(rq)) {
+               ub_cmd_build_packet(sc, lun, cmd, urq);
+       } else {
+               ub_cmd_build_block(sc, lun, cmd, urq);
+       }
+       cmd->state = UB_CMDST_INIT;
+       cmd->lun = lun;
+       cmd->done = ub_rw_cmd_done;
+       cmd->back = urq;
 
-       urq->rq = rq;
-       urq->current_sg = 0;
-       urq->dir = ub_dir;
+       cmd->tag = sc->tagcnt++;
+       if (ub_submit_scsi(sc, cmd) != 0)
+               goto drop;
 
-       ub_scsi_build_block(lun, cmd, urq);
+       return 0;
+
+drop:
+       ub_put_cmd(lun, cmd);
+       ub_end_rq(rq, DID_ERROR << 16);
        return 0;
 }
 
-static void ub_scsi_build_block(struct ub_lun *lun,
+static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
     struct ub_scsi_cmd *cmd, struct ub_request *urq)
 {
-       struct scatterlist *sg;
+       struct request *rq = urq->rq;
        unsigned int block, nblks;
 
-       sg = &urq->sgv[urq->current_sg];
+       if (rq_data_dir(rq) == WRITE)
+               cmd->dir = UB_DIR_WRITE;
+       else
+               cmd->dir = UB_DIR_READ;
 
-       block = urq->current_block;
-       nblks = sg->length >> (lun->capacity.bshift + 9);
+       cmd->nsg = urq->nsg;
+       memcpy(cmd->sgv, urq->sgv, sizeof(struct scatterlist) * cmd->nsg);
 
-       cmd->cdb[0] = (urq->dir == UB_DIR_READ)? READ_10: WRITE_10;
+       /*
+        * build the command
+        *
+        * The call to blk_queue_logical_block_size() guarantees that request
+        * is aligned, but it is given in terms of 512 byte units, always.
+        */
+       block = blk_rq_pos(rq) >> lun->capacity.bshift;
+       nblks = blk_rq_sectors(rq) >> lun->capacity.bshift;
+
+       cmd->cdb[0] = (cmd->dir == UB_DIR_READ)? READ_10: WRITE_10;
        /* 10-byte uses 4 bytes of LBA: 2147483648KB, 2097152MB, 2048GB */
        cmd->cdb[2] = block >> 24;
        cmd->cdb[3] = block >> 16;
@@ -895,36 +738,15 @@ static void ub_scsi_build_block(struct ub_lun *lun,
        cmd->cdb[8] = nblks;
        cmd->cdb_len = 10;
 
-       cmd->dir = urq->dir;
-       cmd->data = page_address(sg->page) + sg->offset;
-       cmd->len = sg->length;
+       cmd->len = blk_rq_bytes(rq);
 }
 
-static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
-    struct ub_scsi_cmd *cmd, struct request *rq)
+static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
+    struct ub_scsi_cmd *cmd, struct ub_request *urq)
 {
-       struct ub_request *urq;
-
-       urq = &lun->urq;
-       memset(urq, 0, sizeof(struct ub_request));
-       urq->rq = rq;
-       sc->sg_stat[0]++;
-
-       if (rq->data_len != 0 && rq->data == NULL) {
-               static int do_print = 1;
-               if (do_print) {
-                       printk(KERN_WARNING "%s: unmapped packet request"
-                           " flags 0x%lx length %d\n",
-                           sc->name, rq->flags, rq->data_len);
-                       do_print = 0;
-               }
-               return -1;
-       }
+       struct request *rq = urq->rq;
 
-       memcpy(&cmd->cdb, rq->cmd, rq->cmd_len);
-       cmd->cdb_len = rq->cmd_len;
-
-       if (rq->data_len == 0) {
+       if (blk_rq_bytes(rq) == 0) {
                cmd->dir = UB_DIR_NONE;
        } else {
                if (rq_data_dir(rq) == WRITE)
@@ -932,10 +754,20 @@ static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
                else
                        cmd->dir = UB_DIR_READ;
        }
-       cmd->data = rq->data;
-       cmd->len = rq->data_len;
 
-       return 0;
+       cmd->nsg = urq->nsg;
+       memcpy(cmd->sgv, urq->sgv, sizeof(struct scatterlist) * cmd->nsg);
+
+       memcpy(&cmd->cdb, rq->cmd, rq->cmd_len);
+       cmd->cdb_len = rq->cmd_len;
+
+       cmd->len = blk_rq_bytes(rq);
+
+       /*
+        * To reapply this to every URB is not as incorrect as it looks.
+        * In return, we avoid any complicated tracking calculations.
+        */
+       cmd->timeo = rq->timeout;
 }
 
 static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
@@ -943,77 +775,100 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
        struct ub_lun *lun = cmd->lun;
        struct ub_request *urq = cmd->back;
        struct request *rq;
-       int uptodate;
+       unsigned int scsi_status;
 
        rq = urq->rq;
 
-       if (blk_pc_request(rq)) {
-               /* UB_SENSE_SIZE is smaller than SCSI_SENSE_BUFFERSIZE */
-               memcpy(rq->sense, sc->top_sense, UB_SENSE_SIZE);
-               rq->sense_len = UB_SENSE_SIZE;
-       }
-
-       if (cmd->error == 0)
-               uptodate = 1;
-       else
-               uptodate = 0;
-
-       if (cmd->error == 0 && urq->current_sg+1 < urq->nsg) {
-               if (ub_request_advance(sc, lun, urq, cmd) == 0) {
-                       /* Stay on target... */
-                       return;
+       if (cmd->error == 0) {
+               if (blk_pc_request(rq)) {
+                       if (cmd->act_len >= rq->resid_len)
+                               rq->resid_len = 0;
+                       else
+                               rq->resid_len -= cmd->act_len;
+                       scsi_status = 0;
+               } else {
+                       if (cmd->act_len != cmd->len) {
+                               scsi_status = SAM_STAT_CHECK_CONDITION;
+                       } else {
+                               scsi_status = 0;
+                       }
+               }
+       } else {
+               if (blk_pc_request(rq)) {
+                       /* UB_SENSE_SIZE is smaller than SCSI_SENSE_BUFFERSIZE */
+                       memcpy(rq->sense, sc->top_sense, UB_SENSE_SIZE);
+                       rq->sense_len = UB_SENSE_SIZE;
+                       if (sc->top_sense[0] != 0)
+                               scsi_status = SAM_STAT_CHECK_CONDITION;
+                       else
+                               scsi_status = DID_ERROR << 16;
+               } else {
+                       if (cmd->error == -EIO &&
+                           (cmd->key == 0 ||
+                            cmd->key == MEDIUM_ERROR ||
+                            cmd->key == UNIT_ATTENTION)) {
+                               if (ub_rw_cmd_retry(sc, lun, urq, cmd) == 0)
+                                       return;
+                       }
+                       scsi_status = SAM_STAT_CHECK_CONDITION;
                }
-               uptodate = 0;
        }
 
        urq->rq = NULL;
 
        ub_put_cmd(lun, cmd);
-       ub_end_rq(rq, uptodate);
+       ub_end_rq(rq, scsi_status);
        blk_start_queue(lun->disk->queue);
 }
 
-static void ub_end_rq(struct request *rq, int uptodate)
+static void ub_end_rq(struct request *rq, unsigned int scsi_status)
 {
-       int rc;
+       int error;
 
-       rc = end_that_request_first(rq, uptodate, rq->hard_nr_sectors);
-       // assert(rc == 0);
-       end_that_request_last(rq);
+       if (scsi_status == 0) {
+               error = 0;
+       } else {
+               error = -EIO;
+               rq->errors = scsi_status;
+       }
+       __blk_end_request_all(rq, error);
 }
 
-static int ub_request_advance(struct ub_dev *sc, struct ub_lun *lun,
+static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
     struct ub_request *urq, struct ub_scsi_cmd *cmd)
 {
-       struct scatterlist *sg;
-       unsigned int nblks;
 
-       /* XXX This is temporary, until we sort out S/G in packet requests. */
-       if (blk_pc_request(urq->rq)) {
-               printk(KERN_WARNING
-                   "2-segment packet request completed\n"); /* P3 */
-               return -1;
-       }
+       if (atomic_read(&sc->poison))
+               return -ENXIO;
 
-       sg = &urq->sgv[urq->current_sg];
-       nblks = sg->length >> (lun->capacity.bshift + 9);
-       urq->current_block += nblks;
-       urq->current_sg++;
-       sg++;
+       ub_reset_enter(sc, urq->current_try);
+
+       if (urq->current_try >= 3)
+               return -EIO;
+       urq->current_try++;
+
+       /* Remove this if anyone complains of flooding. */
+       printk(KERN_DEBUG "%s: dir %c len/act %d/%d "
+           "[sense %x %02x %02x] retry %d\n",
+           sc->name, UB_DIR_CHAR(cmd->dir), cmd->len, cmd->act_len,
+           cmd->key, cmd->asc, cmd->ascq, urq->current_try);
 
        memset(cmd, 0, sizeof(struct ub_scsi_cmd));
-       ub_scsi_build_block(lun, cmd, urq);
+       ub_cmd_build_block(sc, lun, cmd, urq);
+
        cmd->state = UB_CMDST_INIT;
        cmd->lun = lun;
        cmd->done = ub_rw_cmd_done;
-       cmd->back = &lun->urq;
+       cmd->back = urq;
 
        cmd->tag = sc->tagcnt++;
-       if (ub_submit_scsi(sc, cmd) != 0) {
-               return -1;
-       }
 
+#if 0 /* Wasteful */
+       return ub_submit_scsi(sc, cmd);
+#else
+       ub_cmdq_add(sc, cmd);
        return 0;
+#endif
 }
 
 /*
@@ -1024,8 +879,6 @@ static int ub_request_advance(struct ub_dev *sc, struct ub_lun *lun,
  * No exceptions.
  *
  * Host is assumed locked.
- *
- * XXX We only support Bulk for the moment.
  */
 static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 {
@@ -1082,16 +935,9 @@ static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
        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_urb_complete, sc);
-       sc->work_urb.transfer_flags = URB_ASYNC_UNLINK;
-
-       /* Fill what we shouldn't be filling, because usb-storage did so. */
-       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: cmd #%d start failed (%d)\n", cmd->tag, rc); /* P3 */
                ub_complete(&sc->work_done);
                return rc;
        }
@@ -1100,7 +946,6 @@ static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
        add_timer(&sc->work_timer);
 
        cmd->state = UB_CMDST_CMD;
-       ub_cmdtr_state(sc, cmd);
        return 0;
 }
 
@@ -1112,9 +957,10 @@ static void ub_urb_timeout(unsigned long arg)
        struct ub_dev *sc = (struct ub_dev *) arg;
        unsigned long flags;
 
-       spin_lock_irqsave(&sc->lock, flags);
-       usb_unlink_urb(&sc->work_urb);
-       spin_unlock_irqrestore(&sc->lock, flags);
+       spin_lock_irqsave(sc->lock, flags);
+       if (!ub_is_completed(&sc->work_done))
+               usb_unlink_urb(&sc->work_urb);
+       spin_unlock_irqrestore(sc->lock, flags);
 }
 
 /*
@@ -1124,7 +970,7 @@ static void ub_urb_timeout(unsigned long arg)
  * 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_urb_complete(struct urb *urb, struct pt_regs *pt)
+static void ub_urb_complete(struct urb *urb)
 {
        struct ub_dev *sc = urb->context;
 
@@ -1137,10 +983,9 @@ static void ub_scsi_action(unsigned long _dev)
        struct ub_dev *sc = (struct ub_dev *) _dev;
        unsigned long flags;
 
-       spin_lock_irqsave(&sc->lock, flags);
-       del_timer(&sc->work_timer);
+       spin_lock_irqsave(sc->lock, flags);
        ub_scsi_dispatch(sc);
-       spin_unlock_irqrestore(&sc->lock, flags);
+       spin_unlock_irqrestore(sc->lock, flags);
 }
 
 static void ub_scsi_dispatch(struct ub_dev *sc)
@@ -1148,20 +993,19 @@ static void ub_scsi_dispatch(struct ub_dev *sc)
        struct ub_scsi_cmd *cmd;
        int rc;
 
-       while ((cmd = ub_cmdq_peek(sc)) != NULL) {
+       while (!sc->reset && (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;
+                       del_timer(&sc->work_timer);
                        ub_scsi_urb_compl(sc, cmd);
                }
        }
@@ -1171,20 +1015,24 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 {
        struct urb *urb = &sc->work_urb;
        struct bulk_cs_wrap *bcs;
-       int pipe;
+       int endp;
+       int len;
        int rc;
 
        if (atomic_read(&sc->poison)) {
-               /* A little too simplistic, I feel... */
-               goto Bad_End;
+               ub_state_done(sc, cmd, -ENODEV);
+               return;
        }
 
+       endp = usb_pipeendpoint(sc->last_pipe);
+       if (usb_pipein(sc->last_pipe))
+               endp |= USB_DIR_IN;
+
        if (cmd->state == UB_CMDST_CLEAR) {
                if (urb->status == -EPIPE) {
                        /*
                         * STALL while clearning STALL.
                         * The control pipe clears itself - nothing to do.
-                        * XXX Might try to reset the device here and retry.
                         */
                        printk(KERN_NOTICE "%s: stall on control pipe\n",
                            sc->name);
@@ -1195,19 +1043,12 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                 * We ignore the result for the halt clear.
                 */
 
-               /* reset the endpoint toggle */
-               usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe),
-                       usb_pipeout(sc->last_pipe), 0);
+               usb_reset_endpoint(sc->dev, endp);
 
                ub_state_sense(sc, cmd);
 
        } else if (cmd->state == UB_CMDST_CLR2STS) {
                if (urb->status == -EPIPE) {
-                       /*
-                        * STALL while clearning STALL.
-                        * The control pipe clears itself - nothing to do.
-                        * XXX Might try to reset the device here and retry.
-                        */
                        printk(KERN_NOTICE "%s: stall on control pipe\n",
                            sc->name);
                        goto Bad_End;
@@ -1217,19 +1058,12 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                 * We ignore the result for the halt clear.
                 */
 
-               /* reset the endpoint toggle */
-               usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe),
-                       usb_pipeout(sc->last_pipe), 0);
+               usb_reset_endpoint(sc->dev, endp);
 
                ub_state_stat(sc, cmd);
 
        } else if (cmd->state == UB_CMDST_CLRRS) {
                if (urb->status == -EPIPE) {
-                       /*
-                        * STALL while clearning STALL.
-                        * The control pipe clears itself - nothing to do.
-                        * XXX Might try to reset the device here and retry.
-                        */
                        printk(KERN_NOTICE "%s: stall on control pipe\n",
                            sc->name);
                        goto Bad_End;
@@ -1239,14 +1073,17 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                 * We ignore the result for the halt clear.
                 */
 
-               /* reset the endpoint toggle */
-               usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe),
-                       usb_pipeout(sc->last_pipe), 0);
+               usb_reset_endpoint(sc->dev, endp);
 
                ub_state_stat_counted(sc, cmd);
 
        } else if (cmd->state == UB_CMDST_CMD) {
-               if (urb->status == -EPIPE) {
+               switch (urb->status) {
+               case 0:
+                       break;
+               case -EOVERFLOW:
+                       goto Bad_End;
+               case -EPIPE:
                        rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);
                        if (rc != 0) {
                                printk(KERN_NOTICE "%s: "
@@ -1256,54 +1093,29 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                                 * This is typically ENOMEM or some other such shit.
                                 * Retrying is pointless. Just do Bad End on it...
                                 */
-                               goto Bad_End;
+                               ub_state_done(sc, cmd, rc);
+                               return;
                        }
                        cmd->state = UB_CMDST_CLEAR;
-                       ub_cmdtr_state(sc, cmd);
                        return;
-               }
-               if (urb->status != 0) {
-                       printk("ub: cmd #%d cmd status (%d)\n", cmd->tag, urb->status); /* P3 */
+               case -ESHUTDOWN:        /* unplug */
+               case -EILSEQ:           /* unplug timeout on uhci */
+                       ub_state_done(sc, cmd, -ENODEV);
+                       return;
+               default:
                        goto Bad_End;
                }
                if (urb->actual_length != US_BULK_CB_WRAP_LEN) {
-                       printk("ub: cmd #%d xferred %d\n", cmd->tag, urb->actual_length); /* P3 */
-                       /* XXX Must do reset here to unconfuse the device */
                        goto Bad_End;
                }
 
-               if (cmd->dir == UB_DIR_NONE) {
+               if (cmd->dir == UB_DIR_NONE || cmd->nsg < 1) {
                        ub_state_stat(sc, cmd);
                        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_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;
-
-               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 */
-                       ub_complete(&sc->work_done);
-                       ub_state_done(sc, cmd, rc);
-                       return;
-               }
-
-               sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;
-               add_timer(&sc->work_timer);
-
-               cmd->state = UB_CMDST_DATA;
-               ub_cmdtr_state(sc, cmd);
+               // udelay(125);         // usb-storage has this
+               ub_data_start(sc, cmd);
 
        } else if (cmd->state == UB_CMDST_DATA) {
                if (urb->status == -EPIPE) {
@@ -1312,14 +1124,10 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                                printk(KERN_NOTICE "%s: "
                                    "unable to submit clear (%d)\n",
                                    sc->name, rc);
-                               /*
-                                * This is typically ENOMEM or some other such shit.
-                                * Retrying is pointless. Just do Bad End on it...
-                                */
-                               goto Bad_End;
+                               ub_state_done(sc, cmd, rc);
+                               return;
                        }
                        cmd->state = UB_CMDST_CLR2STS;
-                       ub_cmdtr_state(sc, cmd);
                        return;
                }
                if (urb->status == -EOVERFLOW) {
@@ -1327,14 +1135,54 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                         * A babble? Failure, but we must transfer CSW now.
                         */
                        cmd->error = -EOVERFLOW;        /* A cheap trick... */
+                       ub_state_stat(sc, cmd);
+                       return;
+               }
+
+               if (cmd->dir == UB_DIR_WRITE) {
+                       /*
+                        * Do not continue writes in case of a failure.
+                        * Doing so would cause sectors to be mixed up,
+                        * which is worse than sectors lost.
+                        *
+                        * We must try to read the CSW, or many devices
+                        * get confused.
+                        */
+                       len = urb->actual_length;
+                       if (urb->status != 0 ||
+                           len != cmd->sgv[cmd->current_sg].length) {
+                               cmd->act_len += len;
+
+                               cmd->error = -EIO;
+                               ub_state_stat(sc, cmd);
+                               return;
+                       }
+
                } else {
+                       /*
+                        * If an error occurs on read, we record it, and
+                        * continue to fetch data in order to avoid bubble.
+                        *
+                        * As a small shortcut, we stop if we detect that
+                        * a CSW mixed into data.
+                        */
                        if (urb->status != 0)
-                               goto Bad_End;
+                               cmd->error = -EIO;
+
+                       len = urb->actual_length;
+                       if (urb->status != 0 ||
+                           len != cmd->sgv[cmd->current_sg].length) {
+                               if ((len & 0x1FF) == US_BULK_CS_WRAP_LEN)
+                                       goto Bad_End;
+                       }
                }
 
-               cmd->act_len = urb->actual_length;
-               ub_cmdtr_act_len(sc, cmd);
+               cmd->act_len += urb->actual_length;
 
+               if (++cmd->current_sg < cmd->nsg) {
+                       ub_data_start(sc, cmd);
+                       return;
+               }
                ub_state_stat(sc, cmd);
 
        } else if (cmd->state == UB_CMDST_STAT) {
@@ -1344,11 +1192,8 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                                printk(KERN_NOTICE "%s: "
                                    "unable to submit clear (%d)\n",
                                    sc->name, rc);
-                               /*
-                                * This is typically ENOMEM or some other such shit.
-                                * Retrying is pointless. Just do Bad End on it...
-                                */
-                               goto Bad_End;
+                               ub_state_done(sc, cmd, rc);
+                               return;
                        }
 
                        /*
@@ -1358,17 +1203,10 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                        cmd->error = -EIO;              /* A cheap trick... */
 
                        cmd->state = UB_CMDST_CLRRS;
-                       ub_cmdtr_state(sc, cmd);
                        return;
                }
-               if (urb->status == -EOVERFLOW) {
-                       /*
-                        * XXX We are screwed here. Retrying is pointless,
-                        * because the pipelined data will not get in until
-                        * we read with a big enough buffer. We must reset XXX.
-                        */
-                       goto Bad_End;
-               }
+
+               /* Catch everything, including -EOVERFLOW and other nasties. */
                if (urb->status != 0)
                        goto Bad_End;
 
@@ -1414,16 +1252,19 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                        return;
                }
 
-               rc = le32_to_cpu(bcs->Residue);
-               if (rc != cmd->len - cmd->act_len) {
-                       /*
-                        * It is all right to transfer less, the caller has
-                        * to check. But it's not all right if the device
-                        * counts disagree with our counts.
-                        */
-                       /* P3 */ printk("%s: resid %d len %d act %d\n",
-                           sc->name, rc, cmd->len, cmd->act_len);
-                       goto Bad_End;
+               if (!sc->bad_resid) {
+                       len = le32_to_cpu(bcs->Residue);
+                       if (len != cmd->len - cmd->act_len) {
+                               /*
+                                * Only start ignoring if this cmd ended well.
+                                */
+                               if (cmd->len == cmd->act_len) {
+                                       printk(KERN_NOTICE "%s: "
+                                           "bad residual %d of %d, ignoring\n",
+                                           sc->name, len, cmd->len);
+                                       sc->bad_resid = 1;
+                               }
+                       }
                }
 
                switch (bcs->Status) {
@@ -1433,13 +1274,12 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                        ub_state_sense(sc, cmd);
                        return;
                case US_BULK_STAT_PHASE:
-                       /* XXX We must reset the transport here */
-                       /* P3 */ printk("%s: status PHASE\n", sc->name);
                        goto Bad_End;
                default:
                        printk(KERN_INFO "%s: unknown CSW status 0x%x\n",
                            sc->name, bcs->Status);
-                       goto Bad_End;
+                       ub_state_done(sc, cmd, -EINVAL);
+                       return;
                }
 
                /* Not zeroing error to preserve a babble indicator */
@@ -1448,7 +1288,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                        return;
                }
                cmd->state = UB_CMDST_DONE;
-               ub_cmdtr_state(sc, cmd);
                ub_cmdq_pop(sc);
                (*cmd->done)(sc, cmd);
 
@@ -1456,10 +1295,10 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                ub_state_done(sc, cmd, -EIO);
 
        } else {
-               printk(KERN_WARNING "%s: "
-                   "wrong command state %d\n",
+               printk(KERN_WARNING "%s: wrong command state %d\n",
                    sc->name, cmd->state);
-               goto Bad_End;
+               ub_state_done(sc, cmd, -EINVAL);
+               return;
        }
        return;
 
@@ -1469,6 +1308,42 @@ Bad_End: /* Little Excel is dead */
 
 /*
  * Factorization helper for the command state machine:
+ * Initiate a data segment transfer.
+ */
+static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+{
+       struct scatterlist *sg = &cmd->sgv[cmd->current_sg];
+       int pipe;
+       int rc;
+
+       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, sg_virt(sg),
+           sg->length, ub_urb_complete, sc);
+
+       if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
+               /* XXX Clear stalls */
+               ub_complete(&sc->work_done);
+               ub_state_done(sc, cmd, rc);
+               return;
+       }
+
+       if (cmd->timeo)
+               sc->work_timer.expires = jiffies + cmd->timeo;
+       else
+               sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;
+       add_timer(&sc->work_timer);
+
+       cmd->state = UB_CMDST_DATA;
+}
+
+/*
+ * 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)
@@ -1476,7 +1351,6 @@ 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);
        ub_cmdq_pop(sc);
        (*cmd->done)(sc, cmd);
 }
@@ -1494,10 +1368,6 @@ static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
        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;
 
        if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
                /* XXX Clear stalls */
@@ -1506,7 +1376,10 @@ static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                return -1;
        }
 
-       sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT;
+       if (cmd->timeo)
+               sc->work_timer.expires = jiffies + cmd->timeo;
+       else
+               sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT;
        add_timer(&sc->work_timer);
        return 0;
 }
@@ -1523,7 +1396,6 @@ static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 
        cmd->stat_count = 0;
        cmd->state = UB_CMDST_STAT;
-       ub_cmdtr_state(sc, cmd);
 }
 
 /*
@@ -1542,7 +1414,6 @@ static void ub_state_stat_counted(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                return;
 
        cmd->state = UB_CMDST_STAT;
-       ub_cmdtr_state(sc, cmd);
 }
 
 /*
@@ -1552,6 +1423,7 @@ static void ub_state_stat_counted(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 {
        struct ub_scsi_cmd *scmd;
+       struct scatterlist *sg;
        int rc;
 
        if (cmd->cdb[0] == REQUEST_SENSE) {
@@ -1560,12 +1432,17 @@ static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
        }
 
        scmd = &sc->top_rqs_cmd;
+       memset(scmd, 0, sizeof(struct ub_scsi_cmd));
        scmd->cdb[0] = REQUEST_SENSE;
        scmd->cdb[4] = UB_SENSE_SIZE;
        scmd->cdb_len = 6;
        scmd->dir = UB_DIR_READ;
        scmd->state = UB_CMDST_INIT;
-       scmd->data = sc->top_sense;
+       scmd->nsg = 1;
+       sg = &scmd->sgv[0];
+       sg_init_table(sg, UB_MAX_REQ_SG);
+       sg_set_page(sg, virt_to_page(sc->top_sense), UB_SENSE_SIZE,
+                       (unsigned long)sc->top_sense & (PAGE_SIZE-1));
        scmd->len = UB_SENSE_SIZE;
        scmd->lun = cmd->lun;
        scmd->done = ub_top_sense_done;
@@ -1574,7 +1451,6 @@ static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
        scmd->tag = sc->tagcnt++;
 
        cmd->state = UB_CMDST_SENSE;
-       ub_cmdtr_state(sc, cmd);
 
        ub_cmdq_insert(sc, scmd);
        return;
@@ -1609,10 +1485,6 @@ static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
 
        usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
            (unsigned char*) cr, NULL, 0, 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;
 
        if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
                ub_complete(&sc->work_done);
@@ -1628,15 +1500,10 @@ static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
  */
 static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
 {
-       unsigned char *sense = scmd->data;
+       unsigned char *sense = sc->top_sense;
        struct ub_scsi_cmd *cmd;
 
        /*
-        * Ignoring scmd->act_len, because the buffer was pre-zeroed.
-        */
-       ub_cmdtr_sense(sc, scmd, sense);
-
-       /*
         * Find the command which triggered the unit attention or a check,
         * save the sense into it, and advance its state machine.
         */
@@ -1651,12 +1518,14 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
                return;
        }
        if (cmd->state != UB_CMDST_SENSE) {
-               printk(KERN_WARNING "%s: "
-                   "sense done with bad cmd state %d\n",
+               printk(KERN_WARNING "%s: sense done with bad cmd state %d\n",
                    sc->name, cmd->state);
                return;
        }
 
+       /*
+        * Ignoring scmd->act_len, because the buffer was pre-zeroed.
+        */
        cmd->key = sense[2] & 0x0F;
        cmd->asc = sense[12];
        cmd->ascq = sense[13];
@@ -1665,6 +1534,107 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
 }
 
 /*
+ * Reset management
+ */
+
+static void ub_reset_enter(struct ub_dev *sc, int try)
+{
+
+       if (sc->reset) {
+               /* This happens often on multi-LUN devices. */
+               return;
+       }
+       sc->reset = try + 1;
+
+#if 0 /* Not needed because the disconnect waits for us. */
+       unsigned long flags;
+       spin_lock_irqsave(&ub_lock, flags);
+       sc->openc++;
+       spin_unlock_irqrestore(&ub_lock, flags);
+#endif
+
+#if 0 /* We let them stop themselves. */
+       struct ub_lun *lun;
+       list_for_each_entry(lun, &sc->luns, link) {
+               blk_stop_queue(lun->disk->queue);
+       }
+#endif
+
+       schedule_work(&sc->reset_work);
+}
+
+static void ub_reset_task(struct work_struct *work)
+{
+       struct ub_dev *sc = container_of(work, struct ub_dev, reset_work);
+       unsigned long flags;
+       struct ub_lun *lun;
+       int rc;
+
+       if (!sc->reset) {
+               printk(KERN_WARNING "%s: Running reset unrequested\n",
+                   sc->name);
+               return;
+       }
+
+       if (atomic_read(&sc->poison)) {
+               ;
+       } else if ((sc->reset & 1) == 0) {
+               ub_sync_reset(sc);
+               msleep(700);    /* usb-storage sleeps 6s (!) */
+               ub_probe_clear_stall(sc, sc->recv_bulk_pipe);
+               ub_probe_clear_stall(sc, sc->send_bulk_pipe);
+       } else if (sc->dev->actconfig->desc.bNumInterfaces != 1) {
+               ;
+       } else {
+               rc = usb_lock_device_for_reset(sc->dev, sc->intf);
+               if (rc < 0) {
+                       printk(KERN_NOTICE
+                           "%s: usb_lock_device_for_reset failed (%d)\n",
+                           sc->name, rc);
+               } else {
+                       rc = usb_reset_device(sc->dev);
+                       if (rc < 0) {
+                               printk(KERN_NOTICE "%s: "
+                                   "usb_lock_device_for_reset failed (%d)\n",
+                                   sc->name, rc);
+                       }
+                       usb_unlock_device(sc->dev);
+               }
+       }
+
+       /*
+        * In theory, no commands can be running while reset is active,
+        * so nobody can ask for another reset, and so we do not need any
+        * queues of resets or anything. We do need a spinlock though,
+        * to interact with block layer.
+        */
+       spin_lock_irqsave(sc->lock, flags);
+       sc->reset = 0;
+       tasklet_schedule(&sc->tasklet);
+       list_for_each_entry(lun, &sc->luns, link) {
+               blk_start_queue(lun->disk->queue);
+       }
+       wake_up(&sc->reset_wait);
+       spin_unlock_irqrestore(sc->lock, flags);
+}
+
+/*
+ * XXX Reset brackets are too much hassle to implement, so just stub them
+ * in order to prevent forced unbinding (which deadlocks solid when our
+ * ->disconnect method waits for the reset to complete and this kills keventd).
+ *
+ * XXX Tell Alan to move usb_unlock_device inside of usb_reset_device,
+ * or else the post_reset is invoked, and restats I/O on a locked device.
+ */
+static int ub_pre_reset(struct usb_interface *iface) {
+       return 0;
+}
+
+static int ub_post_reset(struct usb_interface *iface) {
+       return 0;
+}
+
+/*
  * This is called from a process context.
  */
 static void ub_revalidate(struct ub_dev *sc, struct ub_lun *lun)
@@ -1699,18 +1669,13 @@ static void ub_revalidate(struct ub_dev *sc, struct ub_lun *lun)
  * This is mostly needed to keep refcounting, but also to support
  * media checks on removable media drives.
  */
-static int ub_bd_open(struct inode *inode, struct file *filp)
+static int ub_bd_open(struct block_device *bdev, fmode_t mode)
 {
-       struct gendisk *disk = inode->i_bdev->bd_disk;
-       struct ub_lun *lun;
-       struct ub_dev *sc;
+       struct ub_lun *lun = bdev->bd_disk->private_data;
+       struct ub_dev *sc = lun->udev;
        unsigned long flags;
        int rc;
 
-       if ((lun = disk->private_data) == NULL)
-               return -ENXIO;
-       sc = lun->udev;
-
        spin_lock_irqsave(&ub_lock, flags);
        if (atomic_read(&sc->poison)) {
                spin_unlock_irqrestore(&ub_lock, flags);
@@ -1719,40 +1684,20 @@ static int ub_bd_open(struct inode *inode, struct file *filp)
        sc->openc++;
        spin_unlock_irqrestore(&ub_lock, flags);
 
-       /*
-        * This is a workaround for a specific problem in our block layer.
-        * In 2.6.9, register_disk duplicates the code from rescan_partitions.
-        * However, if we do add_disk with a device which persistently reports
-        * a changed media, add_disk calls register_disk, which does do_open,
-        * which will call rescan_paritions for changed media. After that,
-        * register_disk attempts to do it all again and causes double kobject
-        * registration and a eventually an oops on module removal.
-        *
-        * The bottom line is, Al Viro says that we should not allow
-        * bdev->bd_invalidated to be set when doing add_disk no matter what.
-        */
-       if (lun->first_open) {
-               lun->first_open = 0;
-               if (lun->changed) {
-                       rc = -ENOMEDIUM;
-                       goto err_open;
-               }
-       }
-
        if (lun->removable || lun->readonly)
-               check_disk_change(inode->i_bdev);
+               check_disk_change(bdev);
 
        /*
         * The sd.c considers ->media_present and ->changed not equivalent,
         * under some pretty murky conditions (a failure of READ CAPACITY).
         * We may need it one day.
         */
-       if (lun->removable && lun->changed && !(filp->f_flags & O_NDELAY)) {
+       if (lun->removable && lun->changed && !(mode & FMODE_NDELAY)) {
                rc = -ENOMEDIUM;
                goto err_open;
        }
 
-       if (lun->readonly && (filp->f_mode & FMODE_WRITE)) {
+       if (lun->readonly && (mode & FMODE_WRITE)) {
                rc = -EROFS;
                goto err_open;
        }
@@ -1766,9 +1711,8 @@ err_open:
 
 /*
  */
-static int ub_bd_release(struct inode *inode, struct file *filp)
+static int ub_bd_release(struct gendisk *disk, fmode_t mode)
 {
-       struct gendisk *disk = inode->i_bdev->bd_disk;
        struct ub_lun *lun = disk->private_data;
        struct ub_dev *sc = lun->udev;
 
@@ -1779,17 +1723,17 @@ static int ub_bd_release(struct inode *inode, struct file *filp)
 /*
  * The ioctl interface.
  */
-static int ub_bd_ioctl(struct inode *inode, struct file *filp,
+static int ub_bd_ioctl(struct block_device *bdev, fmode_t mode,
     unsigned int cmd, unsigned long arg)
 {
-       struct gendisk *disk = inode->i_bdev->bd_disk;
+       struct gendisk *disk = bdev->bd_disk;
        void __user *usermem = (void __user *) arg;
 
-       return scsi_cmd_ioctl(filp, disk, cmd, usermem);
+       return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, usermem);
 }
 
 /*
- * This is called once a new disk was seen by the block layer or by ub_probe().
+ * This is called by check_disk_change if we reported a media change.
  * The main onjective here is to discover the features of the media such as
  * the capacity, read-only status, etc. USB storage generally does not
  * need to be spun up, but if we needed it, this would be the place.
@@ -1805,7 +1749,7 @@ static int ub_bd_revalidate(struct gendisk *disk)
        ub_revalidate(lun->udev, lun);
 
        /* XXX Support sector size switching like in sr.c */
-       blk_queue_hardsect_size(disk->queue, lun->capacity.bsize);
+       blk_queue_logical_block_size(disk->queue, lun->capacity.bsize);
        set_capacity(disk, lun->capacity.nsec);
        // set_disk_ro(sdkp->disk, lun->readonly);
 
@@ -1845,11 +1789,11 @@ static int ub_bd_media_changed(struct gendisk *disk)
        return lun->changed;
 }
 
-static struct block_device_operations ub_bd_fops = {
+static const struct block_device_operations ub_bd_fops = {
        .owner          = THIS_MODULE,
        .open           = ub_bd_open,
        .release        = ub_bd_release,
-       .ioctl          = ub_bd_ioctl,
+       .locked_ioctl   = ub_bd_ioctl,
        .media_changed  = ub_bd_media_changed,
        .revalidate_disk = ub_bd_revalidate,
 };
@@ -1877,9 +1821,8 @@ static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun)
        init_completion(&compl);
 
        rc = -ENOMEM;
-       if ((cmd = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
+       if ((cmd = kzalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
                goto err_alloc;
-       memset(cmd, 0, ALLOC_SIZE);
 
        cmd->cdb[0] = TEST_UNIT_READY;
        cmd->cdb_len = 6;
@@ -1889,16 +1832,14 @@ static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun)
        cmd->done = ub_probe_done;
        cmd->back = &compl;
 
-       spin_lock_irqsave(&sc->lock, flags);
+       spin_lock_irqsave(sc->lock, flags);
        cmd->tag = sc->tagcnt++;
 
        rc = ub_submit_scsi(sc, cmd);
-       spin_unlock_irqrestore(&sc->lock, flags);
+       spin_unlock_irqrestore(sc->lock, flags);
 
-       if (rc != 0) {
-               printk("ub: testing ready: submit error (%d)\n", rc); /* P3 */
+       if (rc != 0)
                goto err_submit;
-       }
 
        wait_for_completion(&compl);
 
@@ -1920,6 +1861,7 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
     struct ub_capacity *ret)
 {
        struct ub_scsi_cmd *cmd;
+       struct scatterlist *sg;
        char *p;
        enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) + 8 };
        unsigned long flags;
@@ -1931,41 +1873,39 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
        init_completion(&compl);
 
        rc = -ENOMEM;
-       if ((cmd = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
+       if ((cmd = kzalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
                goto err_alloc;
-       memset(cmd, 0, ALLOC_SIZE);
        p = (char *)cmd + sizeof(struct ub_scsi_cmd);
 
        cmd->cdb[0] = 0x25;
        cmd->cdb_len = 10;
        cmd->dir = UB_DIR_READ;
        cmd->state = UB_CMDST_INIT;
-       cmd->data = p;
+       cmd->nsg = 1;
+       sg = &cmd->sgv[0];
+       sg_init_table(sg, UB_MAX_REQ_SG);
+       sg_set_page(sg, virt_to_page(p), 8, (unsigned long)p & (PAGE_SIZE-1));
        cmd->len = 8;
        cmd->lun = lun;
        cmd->done = ub_probe_done;
        cmd->back = &compl;
 
-       spin_lock_irqsave(&sc->lock, flags);
+       spin_lock_irqsave(sc->lock, flags);
        cmd->tag = sc->tagcnt++;
 
        rc = ub_submit_scsi(sc, cmd);
-       spin_unlock_irqrestore(&sc->lock, flags);
+       spin_unlock_irqrestore(sc->lock, flags);
 
-       if (rc != 0) {
-               printk("ub: reading capacity: submit error (%d)\n", rc); /* P3 */
+       if (rc != 0)
                goto err_submit;
-       }
 
        wait_for_completion(&compl);
 
        if (cmd->error != 0) {
-               printk("ub: reading capacity: error %d\n", cmd->error); /* P3 */
                rc = -EIO;
                goto err_read;
        }
        if (cmd->act_len != 8) {
-               printk("ub: reading capacity: size %d\n", cmd->act_len); /* P3 */
                rc = -EIO;
                goto err_read;
        }
@@ -1979,7 +1919,6 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
        case 2048:      shift = 2;      break;
        case 4096:      shift = 3;      break;
        default:
-               printk("ub: Bad sector size %u\n", bsize); /* P3 */
                rc = -EDOM;
                goto err_inv_bsize;
        }
@@ -1999,7 +1938,7 @@ err_alloc:
 
 /*
  */
-static void ub_probe_urb_complete(struct urb *urb, struct pt_regs *pt)
+static void ub_probe_urb_complete(struct urb *urb)
 {
        struct completion *cop = urb->context;
        complete(cop);
@@ -2012,6 +1951,49 @@ static void ub_probe_timeout(unsigned long arg)
 }
 
 /*
+ * Reset with a Bulk reset.
+ */
+static int ub_sync_reset(struct ub_dev *sc)
+{
+       int ifnum = sc->intf->cur_altsetting->desc.bInterfaceNumber;
+       struct usb_ctrlrequest *cr;
+       struct completion compl;
+       struct timer_list timer;
+       int rc;
+
+       init_completion(&compl);
+
+       cr = &sc->work_cr;
+       cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+       cr->bRequest = US_BULK_RESET_REQUEST;
+       cr->wValue = cpu_to_le16(0);
+       cr->wIndex = cpu_to_le16(ifnum);
+       cr->wLength = cpu_to_le16(0);
+
+       usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
+           (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl);
+
+       if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) {
+               printk(KERN_WARNING
+                    "%s: Unable to submit a bulk reset (%d)\n", sc->name, rc);
+               return rc;
+       }
+
+       init_timer(&timer);
+       timer.function = ub_probe_timeout;
+       timer.data = (unsigned long) &compl;
+       timer.expires = jiffies + UB_CTRL_TIMEOUT;
+       add_timer(&timer);
+
+       wait_for_completion(&compl);
+
+       del_timer_sync(&timer);
+       usb_kill_urb(&sc->work_urb);
+
+       return sc->work_urb.status;
+}
+
+/*
  * Get number of LUNs by the way of Bulk GetMaxLUN command.
  */
 static int ub_sync_getmaxlun(struct ub_dev *sc)
@@ -2041,22 +2023,9 @@ static int ub_sync_getmaxlun(struct ub_dev *sc)
 
        usb_fill_control_urb(&sc->work_urb, sc->dev, sc->recv_ctrl_pipe,
            (unsigned char*) cr, p, 1, ub_probe_urb_complete, &compl);
-       sc->work_urb.transfer_flags = 0;
-       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_KERNEL)) != 0) {
-               if (rc == -EPIPE) {
-                       printk("%s: Stall at GetMaxLUN, using 1 LUN\n",
-                            sc->name); /* P3 */
-               } else {
-                       printk(KERN_WARNING
-                            "%s: Unable to submit GetMaxLUN (%d)\n",
-                            sc->name, rc);
-               }
+       if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0)
                goto err_submit;
-       }
 
        init_timer(&timer);
        timer.function = ub_probe_timeout;
@@ -2069,9 +2038,10 @@ static int ub_sync_getmaxlun(struct ub_dev *sc)
        del_timer_sync(&timer);
        usb_kill_urb(&sc->work_urb);
 
+       if ((rc = sc->work_urb.status) < 0)
+               goto err_io;
+
        if (sc->work_urb.actual_length != 1) {
-               printk("%s: GetMaxLUN returned %d bytes\n", sc->name,
-                   sc->work_urb.actual_length); /* P3 */
                nluns = 0;
        } else {
                if ((nluns = *p) == 55) {
@@ -2082,13 +2052,12 @@ static int ub_sync_getmaxlun(struct ub_dev *sc)
                        if (nluns > UB_MAX_LUNS)
                                nluns = UB_MAX_LUNS;
                }
-               printk("%s: GetMaxLUN returned %d, using %d LUNs\n", sc->name,
-                   *p, nluns); /* P3 */
        }
 
        kfree(p);
        return nluns;
 
+err_io:
 err_submit:
        kfree(p);
 err_alloc:
@@ -2121,10 +2090,6 @@ static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe)
 
        usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
            (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl);
-       sc->work_urb.transfer_flags = 0;
-       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_KERNEL)) != 0) {
                printk(KERN_WARNING
@@ -2143,8 +2108,7 @@ static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe)
        del_timer_sync(&timer);
        usb_kill_urb(&sc->work_urb);
 
-       /* reset the endpoint toggle */
-       usb_settoggle(sc->dev, endp, usb_pipeout(sc->last_pipe), 0);
+       usb_reset_endpoint(sc->dev, endp);
 
        return 0;
 }
@@ -2170,29 +2134,30 @@ static int ub_get_pipes(struct ub_dev *sc, struct usb_device *dev,
                ep = &altsetting->endpoint[i].desc;
 
                /* Is it a BULK endpoint? */
-               if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-                               == USB_ENDPOINT_XFER_BULK) {
+               if (usb_endpoint_xfer_bulk(ep)) {
                        /* BULK in or out? */
-                       if (ep->bEndpointAddress & USB_DIR_IN)
-                               ep_in = ep;
-                       else
-                               ep_out = ep;
+                       if (usb_endpoint_dir_in(ep)) {
+                               if (ep_in == NULL)
+                                       ep_in = ep;
+                       } else {
+                               if (ep_out == NULL)
+                                       ep_out = ep;
+                       }
                }
        }
 
        if (ep_in == NULL || ep_out == NULL) {
-               printk(KERN_NOTICE "%s: failed endpoint check\n",
-                   sc->name);
-               return -EIO;
+               printk(KERN_NOTICE "%s: failed endpoint check\n", sc->name);
+               return -ENODEV;
        }
 
        /* Calculate and store the pipe values */
        sc->send_ctrl_pipe = usb_sndctrlpipe(dev, 0);
        sc->recv_ctrl_pipe = usb_rcvctrlpipe(dev, 0);
        sc->send_bulk_pipe = usb_sndbulkpipe(dev,
-               ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+               usb_endpoint_num(ep_out));
        sc->recv_bulk_pipe = usb_rcvbulkpipe(dev, 
-               ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+               usb_endpoint_num(ep_in));
 
        return 0;
 }
@@ -2209,15 +2174,19 @@ static int ub_probe(struct usb_interface *intf,
        int rc;
        int i;
 
+       if (usb_usual_check_type(dev_id, USB_US_TYPE_UB))
+               return -ENXIO;
+
        rc = -ENOMEM;
-       if ((sc = kmalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL)
+       if ((sc = kzalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL)
                goto err_core;
-       memset(sc, 0, sizeof(struct ub_dev));
-       spin_lock_init(&sc->lock);
+       sc->lock = ub_next_lock();
        INIT_LIST_HEAD(&sc->luns);
        usb_init_urb(&sc->work_urb);
        tasklet_init(&sc->tasklet, ub_scsi_action, (unsigned long)sc);
        atomic_set(&sc->poison, 0);
+       INIT_WORK(&sc->reset_work, ub_reset_task);
+       init_waitqueue_head(&sc->reset_wait);
 
        init_timer(&sc->work_timer);
        sc->work_timer.data = (unsigned long) sc;
@@ -2231,17 +2200,20 @@ static int ub_probe(struct usb_interface *intf,
        // sc->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
        usb_set_intfdata(intf, sc);
        usb_get_dev(sc->dev);
-       // usb_get_intf(sc->intf);      /* Do we need this? */
+       /*
+        * Since we give the interface struct to the block level through
+        * disk->driverfs_dev, we have to pin it. Otherwise, block_uevent
+        * oopses on close after a disconnect (kernels 2.6.16 and up).
+        */
+       usb_get_intf(sc->intf);
 
        snprintf(sc->name, 12, DRV_NAME "(%d.%d)",
            sc->dev->bus->busnum, sc->dev->devnum);
 
        /* XXX Verify that we can handle the device (from descriptors) */
 
-       ub_get_pipes(sc, sc->dev, intf);
-
-       if (device_create_file(&sc->intf->dev, &dev_attr_diag) != 0)
-               goto err_diag;
+       if (ub_get_pipes(sc, sc->dev, intf) != 0)
+               goto err_dev_desc;
 
        /*
         * At this point, all USB initialization is done, do upper layer.
@@ -2254,8 +2226,10 @@ static int ub_probe(struct usb_interface *intf,
         * This is needed to clear toggles. It is a problem only if we do
         * `rmmod ub && modprobe ub` without disconnects, but we like that.
         */
+#if 0 /* iPod Mini fails if we do this (big white iPod works) */
        ub_probe_clear_stall(sc, sc->recv_bulk_pipe);
        ub_probe_clear_stall(sc, sc->send_bulk_pipe);
+#endif
 
        /*
         * The way this is used by the startup code is a little specific.
@@ -2272,7 +2246,7 @@ static int ub_probe(struct usb_interface *intf,
         * has to succeed, so we clear checks with an additional one here.
         * In any case it's not our business how revaliadation is implemented.
         */
-       for (i = 0; i < 3; i++) {       /* Retries for benh's key */
+       for (i = 0; i < 3; i++) {  /* Retries for the schwag key from KS'04 */
                if ((rc = ub_sync_tur(sc, NULL)) <= 0) break;
                if (rc != 0x6) break;
                msleep(10);
@@ -2280,19 +2254,8 @@ static int ub_probe(struct usb_interface *intf,
 
        nluns = 1;
        for (i = 0; i < 3; i++) {
-               if ((rc = ub_sync_getmaxlun(sc)) < 0) {
-                       /* 
-                        * Some devices (i.e. Iomega Zip100) need this --
-                        * apparently the bulk pipes get STALLed when the
-                        * GetMaxLUN request is processed.
-                        * XXX I have a ZIP-100, verify it does this.
-                        */
-                       if (rc == -EPIPE) {
-                               ub_probe_clear_stall(sc, sc->recv_bulk_pipe);
-                               ub_probe_clear_stall(sc, sc->send_bulk_pipe);
-                       }
+               if ((rc = ub_sync_getmaxlun(sc)) < 0)
                        break;
-               }
                if (rc != 0) {
                        nluns = rc;
                        break;
@@ -2305,10 +2268,9 @@ static int ub_probe(struct usb_interface *intf,
        }
        return 0;
 
-       /* device_remove_file(&sc->intf->dev, &dev_attr_diag); */
-err_diag:
+err_dev_desc:
        usb_set_intfdata(intf, NULL);
-       // usb_put_intf(sc->intf);
+       usb_put_intf(sc->intf);
        usb_put_dev(sc->dev);
        kfree(sc);
 err_core:
@@ -2318,14 +2280,13 @@ err_core:
 static int ub_probe_lun(struct ub_dev *sc, int lnum)
 {
        struct ub_lun *lun;
-       request_queue_t *q;
+       struct request_queue *q;
        struct gendisk *disk;
        int rc;
 
        rc = -ENOMEM;
-       if ((lun = kmalloc(sizeof(struct ub_lun), GFP_KERNEL)) == NULL)
+       if ((lun = kzalloc(sizeof(struct ub_lun), GFP_KERNEL)) == NULL)
                goto err_alloc;
-       memset(lun, 0, sizeof(struct ub_lun));
        lun->num = lnum;
 
        rc = -ENOSR;
@@ -2333,31 +2294,27 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
                goto err_id;
 
        lun->udev = sc;
-       list_add(&lun->link, &sc->luns);
 
        snprintf(lun->name, 16, DRV_NAME "%c(%d.%d.%d)",
            lun->id + 'a', sc->dev->bus->busnum, sc->dev->devnum, lun->num);
 
        lun->removable = 1;             /* XXX Query this from the device */
        lun->changed = 1;               /* ub_revalidate clears only */
-       lun->first_open = 1;
        ub_revalidate(sc, lun);
 
        rc = -ENOMEM;
-       if ((disk = alloc_disk(UB_MINORS_PER_MAJOR)) == NULL)
+       if ((disk = alloc_disk(UB_PARTS_PER_LUN)) == NULL)
                goto err_diskalloc;
 
-       lun->disk = disk;
        sprintf(disk->disk_name, DRV_NAME "%c", lun->id + 'a');
-       sprintf(disk->devfs_name, DEVFS_NAME "/%c", lun->id + 'a');
        disk->major = UB_MAJOR;
-       disk->first_minor = lun->id * UB_MINORS_PER_MAJOR;
+       disk->first_minor = lun->id * UB_PARTS_PER_LUN;
        disk->fops = &ub_bd_fops;
        disk->private_data = lun;
-       disk->driverfs_dev = &sc->intf->dev;    /* XXX Many to one ok? */
+       disk->driverfs_dev = &sc->intf->dev;
 
        rc = -ENOMEM;
-       if ((q = blk_init_queue(ub_bd_rq_fn, &sc->lock)) == NULL)
+       if ((q = blk_init_queue(ub_request_fn, sc->lock)) == NULL)
                goto err_blkqinit;
 
        disk->queue = q;
@@ -2367,9 +2324,11 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
        blk_queue_max_phys_segments(q, UB_MAX_REQ_SG);
        blk_queue_segment_boundary(q, 0xffffffff);      /* Dubious. */
        blk_queue_max_sectors(q, UB_MAX_SECTORS);
-       blk_queue_hardsect_size(q, lun->capacity.bsize);
+       blk_queue_logical_block_size(q, lun->capacity.bsize);
 
+       lun->disk = disk;
        q->queuedata = lun;
+       list_add(&lun->link, &sc->luns);
 
        set_capacity(disk, lun->capacity.nsec);
        if (lun->removable)
@@ -2382,7 +2341,6 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
 err_blkqinit:
        put_disk(disk);
 err_diskalloc:
-       list_del(&lun->link);
        ub_id_put(lun->id);
 err_id:
        kfree(lun);
@@ -2393,9 +2351,7 @@ err_alloc:
 static void ub_disconnect(struct usb_interface *intf)
 {
        struct ub_dev *sc = usb_get_intfdata(intf);
-       struct list_head *p;
        struct ub_lun *lun;
-       struct gendisk *disk;
        unsigned long flags;
 
        /*
@@ -2408,13 +2364,18 @@ static void ub_disconnect(struct usb_interface *intf)
        spin_unlock_irqrestore(&ub_lock, flags);
 
        /*
-        * Fence stall clearnings, operations triggered by unlinkings and so on.
+        * Fence stall clearings, operations triggered by unlinkings and so on.
         * We do not attempt to unlink any URBs, because we do not trust the
         * unlink paths in HC drivers. Also, we get -84 upon disconnect anyway.
         */
        atomic_set(&sc->poison, 1);
 
        /*
+        * Wait for reset to end, if any.
+        */
+       wait_event(sc->reset_wait, !sc->reset);
+
+       /*
         * Blow away queued commands.
         *
         * Actually, this never works, because before we get here
@@ -2423,14 +2384,13 @@ static void ub_disconnect(struct usb_interface *intf)
         * and the whole queue drains. So, we just use this code to
         * print warnings.
         */
-       spin_lock_irqsave(&sc->lock, flags);
+       spin_lock_irqsave(sc->lock, flags);
        {
                struct ub_scsi_cmd *cmd;
                int cnt = 0;
-               while ((cmd = ub_cmdq_pop(sc)) != NULL) {
+               while ((cmd = ub_cmdq_peek(sc)) != NULL) {
                        cmd->error = -ENOTCONN;
                        cmd->state = UB_CMDST_DONE;
-                       ub_cmdtr_state(sc, cmd);
                        ub_cmdq_pop(sc);
                        (*cmd->done)(sc, cmd);
                        cnt++;
@@ -2440,41 +2400,34 @@ static void ub_disconnect(struct usb_interface *intf)
                            "%d was queued after shutdown\n", sc->name, cnt);
                }
        }
-       spin_unlock_irqrestore(&sc->lock, flags);
+       spin_unlock_irqrestore(sc->lock, flags);
 
        /*
         * Unregister the upper layer.
         */
-       list_for_each (p, &sc->luns) {
-               lun = list_entry(p, struct ub_lun, link);
-               disk = lun->disk;
-               if (disk->flags & GENHD_FL_UP)
-                       del_gendisk(disk);
+       list_for_each_entry(lun, &sc->luns, link) {
+               del_gendisk(lun->disk);
                /*
                 * I wish I could do:
-                *    set_bit(QUEUE_FLAG_DEAD, &q->queue_flags);
+                *    queue_flag_set(QUEUE_FLAG_DEAD, q);
                 * As it is, we rely on our internal poisoning and let
                 * the upper levels to spin furiously failing all the I/O.
                 */
        }
 
        /*
-        * Taking a lock on a structure which is about to be freed
-        * is very nonsensual. Here it is largely a way to do a debug freeze,
-        * and a bracket which shows where the nonsensual code segment ends.
-        *
         * Testing for -EINPROGRESS is always a bug, so we are bending
         * the rules a little.
         */
-       spin_lock_irqsave(&sc->lock, flags);
+       spin_lock_irqsave(sc->lock, flags);
        if (sc->work_urb.status == -EINPROGRESS) {      /* janitors: ignore */
                printk(KERN_WARNING "%s: "
                    "URB is active after disconnect\n", sc->name);
        }
-       spin_unlock_irqrestore(&sc->lock, flags);
+       spin_unlock_irqrestore(sc->lock, flags);
 
        /*
-        * There is virtually no chance that other CPU runs times so long
+        * There is virtually no chance that other CPU runs a timeout so long
         * after ub_urb_complete should have called del_timer, but only if HCD
         * didn't forget to deliver a callback on unlink.
         */
@@ -2485,42 +2438,36 @@ static void ub_disconnect(struct usb_interface *intf)
         * and no URBs left in transit.
         */
 
-       device_remove_file(&sc->intf->dev, &dev_attr_diag);
-       usb_set_intfdata(intf, NULL);
-       // usb_put_intf(sc->intf);
-       sc->intf = NULL;
-       usb_put_dev(sc->dev);
-       sc->dev = NULL;
-
        ub_put(sc);
 }
 
 static struct usb_driver ub_driver = {
-       .owner =        THIS_MODULE,
        .name =         "ub",
        .probe =        ub_probe,
        .disconnect =   ub_disconnect,
        .id_table =     ub_usb_ids,
+       .pre_reset =    ub_pre_reset,
+       .post_reset =   ub_post_reset,
 };
 
 static int __init ub_init(void)
 {
        int rc;
+       int i;
 
-       /* P3 */ printk("ub: sizeof ub_scsi_cmd %zu ub_dev %zu ub_lun %zu\n",
-                       sizeof(struct ub_scsi_cmd), sizeof(struct ub_dev), sizeof(struct ub_lun));
+       for (i = 0; i < UB_QLOCK_NUM; i++)
+               spin_lock_init(&ub_qlockv[i]);
 
        if ((rc = register_blkdev(UB_MAJOR, DRV_NAME)) != 0)
                goto err_regblkdev;
-       devfs_mk_dir(DEVFS_NAME);
 
        if ((rc = usb_register(&ub_driver)) != 0)
                goto err_register;
 
+       usb_usual_set_present(USB_US_TYPE_UB);
        return 0;
 
 err_register:
-       devfs_remove(DEVFS_NAME);
        unregister_blkdev(UB_MAJOR, DRV_NAME);
 err_regblkdev:
        return rc;
@@ -2530,8 +2477,8 @@ static void __exit ub_exit(void)
 {
        usb_deregister(&ub_driver);
 
-       devfs_remove(DEVFS_NAME);
        unregister_blkdev(UB_MAJOR, DRV_NAME);
+       usb_usual_clear_present(USB_US_TYPE_UB);
 }
 
 module_init(ub_init);