diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2005-12-21 16:03:09 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-12-21 16:03:09 -0800 |
commit | 8f201a7bdcb0d5b5a2987d01e1433f0a09968d6d (patch) | |
tree | 8d5d5a77750fd9dc81aee6bcea57b49569333d06 /usb | |
parent | 7c772cc08c3d4b7d2437c1d69b88bb9cfac954cf (diff) | |
download | patches-8f201a7bdcb0d5b5a2987d01e1433f0a09968d6d.tar.gz |
usb and pci patches added
Diffstat (limited to 'usb')
-rw-r--r-- | usb/usb-asix.c-add-linksys-usb200m-rev-2-ids.patch | 30 | ||||
-rw-r--r-- | usb/usb-limiting-of-resource-use-in-skeleton-driver.patch | 118 | ||||
-rw-r--r-- | usb/usb-replace-__setup-with-__module_param_call.patch | 56 | ||||
-rw-r--r-- | usb/usb-storage-fix-unusual_devs.h-order.patch | 47 | ||||
-rw-r--r-- | usb/usb-ub-00-implement-retries-and-resets.patch | 748 | ||||
-rw-r--r-- | usb/usb-ub-01-rename.patch | 44 | ||||
-rw-r--r-- | usb/usb-ub-02-removed-unused-variable.patch | 34 | ||||
-rw-r--r-- | usb/usb-zd1201-make-sysfs-device-symlink.patch | 43 |
8 files changed, 1120 insertions, 0 deletions
diff --git a/usb/usb-asix.c-add-linksys-usb200m-rev-2-ids.patch b/usb/usb-asix.c-add-linksys-usb200m-rev-2-ids.patch new file mode 100644 index 0000000000000..41922512223cc --- /dev/null +++ b/usb/usb-asix.c-add-linksys-usb200m-rev-2-ids.patch @@ -0,0 +1,30 @@ +From dhollis@davehollis.com Mon Dec 19 11:01:27 2005 +From: David Hollis <dhollis@davehollis.com> +Subject: USB: asix.c - Add Linksys USB200M Rev 2 ids +To: Greg KH <greg@kroah.com> +Date: Mon, 19 Dec 2005 13:58:38 -0500 +Message-Id: <1135018718.26911.3.camel@dhollis-lnx.sunera.com> + +Attached patch adds device IDs for the Linksys USB200M Rev 2 device +which uses the AX88772 chipset. + +Signed-off-by: David Hollis <dhollis@davehollis.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/net/asix.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- gregkh-2.6.orig/drivers/usb/net/asix.c ++++ gregkh-2.6/drivers/usb/net/asix.c +@@ -912,6 +912,10 @@ static const struct usb_device_id produc + // ASIX AX88772 10/100 + USB_DEVICE (0x0b95, 0x7720), + .driver_info = (unsigned long) &ax88772_info, ++}, { ++ // Linksys USB200M Rev 2 ++ USB_DEVICE (0x13b1, 0x0018), ++ .driver_info = (unsigned long) &ax88772_info, + }, + { }, // END + }; diff --git a/usb/usb-limiting-of-resource-use-in-skeleton-driver.patch b/usb/usb-limiting-of-resource-use-in-skeleton-driver.patch new file mode 100644 index 0000000000000..816d8321232ff --- /dev/null +++ b/usb/usb-limiting-of-resource-use-in-skeleton-driver.patch @@ -0,0 +1,118 @@ +From oliver@neukum.org Wed Dec 21 12:26:29 2005 +From: Oliver Neukum <oliver@neukum.org> +To: Greg KH <greg@kroah.com> +Subject: USB: Limiting of resource use in skeleton driver +Date: Wed, 21 Dec 2005 19:27:29 +0100 +Content-Disposition: inline +Message-Id: <200512211927.29612.oliver@neukum.org> + +this introduces limits whose lack in the skeleton driver someone recently +complained about. + +Signed-off-by: Oliver Neukum <oliver@neukum.name> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/usb-skeleton.c | 25 ++++++++++++++++++------- + 1 file changed, 18 insertions(+), 7 deletions(-) + +--- gregkh-2.6.orig/drivers/usb/usb-skeleton.c ++++ gregkh-2.6/drivers/usb/usb-skeleton.c +@@ -39,10 +39,15 @@ MODULE_DEVICE_TABLE (usb, skel_table); + /* Get a minor range for your devices from the usb maintainer */ + #define USB_SKEL_MINOR_BASE 192 + ++/* our private defines. if this grows any larger, use your own .h file */ ++#define MAX_TRANSFER ( PAGE_SIZE - 512 ) ++#define WRITES_IN_FLIGHT 8 ++ + /* Structure to hold all of our device specific stuff */ + struct usb_skel { + struct usb_device * udev; /* the usb device for this device */ + struct usb_interface * interface; /* the interface for this device */ ++ struct semaphore limit_sem; /* limiting the number of writes in progress */ + unsigned char * bulk_in_buffer; /* the buffer to receive data */ + size_t bulk_in_size; /* the size of the receive buffer */ + __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ +@@ -152,6 +157,7 @@ static void skel_write_bulk_callback(str + /* free up our allocated buffer */ + usb_buffer_free(urb->dev, urb->transfer_buffer_length, + urb->transfer_buffer, urb->transfer_dma); ++ up(&dev->limit_sem); + } + + static ssize_t skel_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos) +@@ -160,6 +166,7 @@ static ssize_t skel_write(struct file *f + int retval = 0; + struct urb *urb = NULL; + char *buf = NULL; ++ size_t writesize = max(count, MAX_TRANSFER); + + dev = (struct usb_skel *)file->private_data; + +@@ -167,6 +174,9 @@ static ssize_t skel_write(struct file *f + if (count == 0) + goto exit; + ++ /* limit the number of URBs in flight to stop a user from using up all RAM */ ++ down (&dev->limit_sem); ++ + /* create a urb, and a buffer for it, and copy the data to the urb */ + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { +@@ -174,13 +184,13 @@ static ssize_t skel_write(struct file *f + goto error; + } + +- buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma); ++ buf = usb_buffer_alloc(dev->udev, writesize, GFP_KERNEL, &urb->transfer_dma); + if (!buf) { + retval = -ENOMEM; + goto error; + } + +- if (copy_from_user(buf, user_buffer, count)) { ++ if (copy_from_user(buf, user_buffer, writesize)) { + retval = -EFAULT; + goto error; + } +@@ -188,7 +198,7 @@ static ssize_t skel_write(struct file *f + /* initialize the urb properly */ + usb_fill_bulk_urb(urb, dev->udev, + usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), +- buf, count, skel_write_bulk_callback, dev); ++ buf, writesize, skel_write_bulk_callback, dev); + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + /* send the data out the bulk port */ +@@ -202,11 +212,12 @@ static ssize_t skel_write(struct file *f + usb_free_urb(urb); + + exit: +- return count; ++ return writesize; + + error: +- usb_buffer_free(dev->udev, count, buf, urb->transfer_dma); ++ usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma); + usb_free_urb(urb); ++ up(&dev->limit_sem); + return retval; + } + +@@ -238,13 +249,13 @@ static int skel_probe(struct usb_interfa + int retval = -ENOMEM; + + /* allocate memory for our device state and initialize it */ +- dev = kmalloc(sizeof(*dev), GFP_KERNEL); ++ dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + err("Out of memory"); + goto error; + } +- memset(dev, 0x00, sizeof(*dev)); + kref_init(&dev->kref); ++ sema_init(&dev->limit_sem, WRITES_IN_FLIGHT); + + dev->udev = usb_get_dev(interface_to_usbdev(interface)); + dev->interface = interface; diff --git a/usb/usb-replace-__setup-with-__module_param_call.patch b/usb/usb-replace-__setup-with-__module_param_call.patch new file mode 100644 index 0000000000000..e4166b02d2a98 --- /dev/null +++ b/usb/usb-replace-__setup-with-__module_param_call.patch @@ -0,0 +1,56 @@ +From zaitcev@redhat.com Tue Dec 20 14:19:40 2005 +Date: Tue, 20 Dec 2005 14:15:04 -0800 +From: Pete Zaitcev <zaitcev@redhat.com> +To: greg@kroah.com +Cc: zaitcev@redhat.com +Subject: usb: replace __setup("nousb") with __module_param_call +Message-Id: <20051220141504.31441a41.zaitcev@redhat.com> + +Fedora users complain that passing "nousbstorage" to the installer causes +the rest of the USB support to disappear. The installer uses kernel command +line as a way to pass options through Syslinux. The problem stems from the +use of strncmp() in obsolete_checksetup(). + +I used __module_param_call() instead of module_param because I wanted to +preserve the old syntax in grub.conf, and it's the only macro which allows +to remove the prefix. + +The fix is tested to accept the option "nousb" correctly now. + +Signed-off-by: Pete Zaitcev <zaitcev@redhat.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/core/usb.c | 13 +------------ + 1 file changed, 1 insertion(+), 12 deletions(-) + +--- gregkh-2.6.orig/drivers/usb/core/usb.c ++++ gregkh-2.6/drivers/usb/core/usb.c +@@ -46,7 +46,6 @@ + const char *usbcore_name = "usbcore"; + + static int nousb; /* Disable USB when built into kernel image */ +- /* Not honored on modular build */ + + + /** +@@ -1093,18 +1092,8 @@ struct bus_type usb_bus_type = { + .resume = usb_generic_resume, + }; + +-#ifndef MODULE +- +-static int __init usb_setup_disable(char *str) +-{ +- nousb = 1; +- return 1; +-} +- + /* format to disable USB on kernel command line is: nousb */ +-__setup("nousb", usb_setup_disable); +- +-#endif ++__module_param_call("", nousb, param_set_bool, param_get_bool, &nousb, 0444); + + /* + * for external read access to <nousb> diff --git a/usb/usb-storage-fix-unusual_devs.h-order.patch b/usb/usb-storage-fix-unusual_devs.h-order.patch new file mode 100644 index 0000000000000..ace2f3beb8942 --- /dev/null +++ b/usb/usb-storage-fix-unusual_devs.h-order.patch @@ -0,0 +1,47 @@ +From phil@ipom.com Sun Dec 18 21:36:08 2005 +Message-ID: <43A6455A.9020406@ipom.com> +Date: Sun, 18 Dec 2005 21:30:02 -0800 +From: Phil Dibowitz <phil@ipom.com> +To: Greg KH <greg@kroah.com>, USB Storage list <usb-storage@lists.one-eyed-alien.net> +Subject: USB Storage: Fix unusual_devs.h order + +Alan Stern pointed out there was an ordering issue in unusual_devs.h, +and this patch fixes it. + +Signed-off-by: Phil Dibowitz <phil@ipom.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/storage/unusual_devs.h | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +--- gregkh-2.6.orig/drivers/usb/storage/unusual_devs.h ++++ gregkh-2.6/drivers/usb/storage/unusual_devs.h +@@ -79,13 +79,6 @@ UNUSUAL_DEV( 0x03f0, 0x0307, 0x0001, 0x + US_SC_8070, US_PR_USBAT, init_usbat, 0), + #endif + +-/* Patch submitted by Mihnea-Costin Grigore <mihnea@zulu.ro> */ +-UNUSUAL_DEV( 0x040d, 0x6205, 0x0003, 0x0003, +- "VIA Technologies Inc.", +- "USB 2.0 Card Reader", +- US_SC_DEVICE, US_PR_DEVICE, NULL, +- US_FL_IGNORE_RESIDUE ), +- + /* Reported by Sebastian Kapfer <sebastian_kapfer@gmx.net> + * and Olaf Hering <olh@suse.de> (different bcd's, same vendor/product) + * for USB floppies that need the SINGLE_LUN enforcement. +@@ -96,6 +89,13 @@ UNUSUAL_DEV( 0x0409, 0x0040, 0x0000, 0x + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_SINGLE_LUN ), + ++/* Patch submitted by Mihnea-Costin Grigore <mihnea@zulu.ro> */ ++UNUSUAL_DEV( 0x040d, 0x6205, 0x0003, 0x0003, ++ "VIA Technologies Inc.", ++ "USB 2.0 Card Reader", ++ US_SC_DEVICE, US_PR_DEVICE, NULL, ++ US_FL_IGNORE_RESIDUE ), ++ + /* Deduced by Jonathan Woithe <jwoithe@physics.adelaide.edu.au> + * Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message + * always fails and confuses drive. diff --git a/usb/usb-ub-00-implement-retries-and-resets.patch b/usb/usb-ub-00-implement-retries-and-resets.patch new file mode 100644 index 0000000000000..e3c976cac065b --- /dev/null +++ b/usb/usb-ub-00-implement-retries-and-resets.patch @@ -0,0 +1,748 @@ +From zaitcev@redhat.com Sat Dec 17 02:17:55 2005 +Date: Sat, 17 Dec 2005 02:16:43 -0800 +From: Pete Zaitcev <zaitcev@redhat.com> +To: greg@kroah.com +Cc: zaitcev@redhat.com +Subject: usb: ub 00 implement retries and resets +Message-Id: <20051217021643.01ff8b56.zaitcev@redhat.com> + +Implement command retries and resets in ub. It is advantageous for users +to know if their devices are getting bad. However, failing every I/O +is not practical if you have a external USB enclosure with a hard drive. + +Signed-off-by: Pete Zaitcev <zaitcev@redhat.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/block/ub.c | 404 +++++++++++++++++++++++++++++++++++++---------------- + 1 file changed, 287 insertions(+), 117 deletions(-) + +--- gregkh-2.6.orig/drivers/block/ub.c ++++ gregkh-2.6/drivers/block/ub.c +@@ -9,7 +9,6 @@ + * + * 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) + * -- 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 +@@ -234,6 +233,13 @@ struct ub_scsi_cmd { + void *back; + }; + ++struct ub_request { ++ struct request *rq; ++ unsigned int current_try; ++ unsigned int nsg; /* sgv[nsg] */ ++ struct scatterlist sgv[UB_MAX_REQ_SG]; ++}; ++ + /* + */ + struct ub_capacity { +@@ -329,6 +335,8 @@ struct ub_lun { + int readonly; + int first_open; /* Kludge. See ub_bd_open. */ + ++ struct ub_request urq; ++ + /* Use Ingo's mempool if or when we have more than one command. */ + /* + * Currently we never need more than one command for the whole device. +@@ -349,6 +357,7 @@ struct ub_dev { + 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 */ + unsigned int tagcnt; + char name[12]; + struct usb_device *dev; +@@ -376,6 +385,9 @@ struct ub_dev { + struct bulk_cs_wrap work_bcs; + struct usb_ctrlrequest work_cr; + ++ struct work_struct reset_work; ++ wait_queue_head_t reset_wait; ++ + int sg_stat[6]; + struct ub_scsi_trace tr; + }; +@@ -384,12 +396,14 @@ struct ub_dev { + */ + static void ub_cleanup(struct ub_dev *sc); + static int ub_request_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 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_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 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_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_scsi_action(unsigned long _dev); +@@ -404,6 +418,8 @@ static void ub_state_sense(struct ub_dev + 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); ++static void ub_reset_task(void *arg); + 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); +@@ -516,6 +532,9 @@ static ssize_t ub_diag_show(struct devic + spin_lock_irqsave(&sc->lock, flags); + + cnt += sprintf(page + cnt, ++ "poison %d reset %d\n", ++ atomic_read(&sc->poison), sc->reset); ++ cnt += sprintf(page + cnt, + "qlen %d qmax %d\n", + sc->cmd_queue.qlen, sc->cmd_queue.qmax); + cnt += sprintf(page + cnt, +@@ -764,7 +783,8 @@ static int ub_request_fn_1(struct ub_lun + { + 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); +@@ -772,65 +792,70 @@ static int ub_request_fn_1(struct ub_lun + return 0; + } + ++ if (lun->urq.rq != NULL) ++ return -1; + if ((cmd = ub_get_cmd(lun)) == NULL) + return -1; + memset(cmd, 0, sizeof(struct ub_scsi_cmd)); + + blkdev_dequeue_request(rq); ++ ++ urq = &lun->urq; ++ memset(urq, 0, sizeof(struct ub_request)); ++ urq->rq = rq; ++ ++ /* ++ * get scatterlist from block layer ++ */ ++ n_elem = blk_rq_map_sg(lun->disk->queue, rq, &urq->sgv[0]); ++ if (n_elem < 0) { ++ printk(KERN_INFO "%s: failed request map (%d)\n", ++ lun->name, n_elem); /* P3 */ ++ goto drop; ++ } ++ if (n_elem > UB_MAX_REQ_SG) { /* Paranoia */ ++ printk(KERN_WARNING "%s: request with %d segments\n", ++ lun->name, n_elem); ++ goto drop; ++ } ++ urq->nsg = n_elem; ++ sc->sg_stat[n_elem < 5 ? n_elem : 5]++; ++ + if (blk_pc_request(rq)) { +- rc = ub_cmd_build_packet(sc, lun, cmd, rq); ++ ub_cmd_build_packet(sc, lun, cmd, urq); + } 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; ++ ub_cmd_build_block(sc, lun, cmd, urq); + } + cmd->state = UB_CMDST_INIT; + cmd->lun = lun; + cmd->done = ub_rw_cmd_done; +- cmd->back = rq; ++ cmd->back = urq; + + cmd->tag = sc->tagcnt++; +- if (ub_submit_scsi(sc, cmd) != 0) { +- ub_put_cmd(lun, cmd); +- ub_end_rq(rq, 0); +- return 0; +- } ++ if (ub_submit_scsi(sc, cmd) != 0) ++ goto drop; + + return 0; ++ ++drop: ++ ub_put_cmd(lun, cmd); ++ ub_end_rq(rq, 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) ++static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun, ++ struct ub_scsi_cmd *cmd, struct ub_request *urq) + { +- int ub_dir; +- int n_elem; ++ struct request *rq = urq->rq; + unsigned int block, nblks; + + if (rq_data_dir(rq) == WRITE) +- ub_dir = UB_DIR_WRITE; ++ cmd->dir = UB_DIR_WRITE; + else +- ub_dir = UB_DIR_READ; +- cmd->dir = ub_dir; ++ cmd->dir = UB_DIR_READ; + +- /* +- * get scatterlist from block layer +- */ +- n_elem = blk_rq_map_sg(lun->disk->queue, rq, &cmd->sgv[0]); +- if (n_elem <= 0) { +- printk(KERN_INFO "%s: failed request map (%d)\n", +- sc->name, n_elem); /* P3 */ +- return -1; /* request with no s/g entries? */ +- } +- if (n_elem > UB_MAX_REQ_SG) { /* Paranoia */ +- printk(KERN_WARNING "%s: request with %d segments\n", +- sc->name, n_elem); +- return -1; +- } +- cmd->nsg = n_elem; +- sc->sg_stat[n_elem < 5 ? n_elem : 5]++; ++ cmd->nsg = urq->nsg; ++ memcpy(cmd->sgv, urq->sgv, sizeof(struct scatterlist) * cmd->nsg); + + /* + * build the command +@@ -841,7 +866,7 @@ static int ub_cmd_build_block(struct ub_ + block = rq->sector >> lun->capacity.bshift; + nblks = rq->nr_sectors >> lun->capacity.bshift; + +- cmd->cdb[0] = (ub_dir == UB_DIR_READ)? READ_10: WRITE_10; ++ 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; +@@ -852,14 +877,12 @@ static int ub_cmd_build_block(struct ub_ + cmd->cdb_len = 10; + + cmd->len = rq->nr_sectors * 512; +- +- return 0; + } + +-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) + { +- int n_elem; ++ struct request *rq = urq->rq; + + if (rq->data_len == 0) { + cmd->dir = UB_DIR_NONE; +@@ -868,40 +891,26 @@ static int ub_cmd_build_packet(struct ub + cmd->dir = UB_DIR_WRITE; + else + cmd->dir = UB_DIR_READ; +- + } + +- /* +- * get scatterlist from block layer +- */ +- n_elem = blk_rq_map_sg(lun->disk->queue, rq, &cmd->sgv[0]); +- if (n_elem < 0) { +- printk(KERN_INFO "%s: failed request map (%d)\n", +- sc->name, n_elem); /* P3 */ +- return -1; +- } +- if (n_elem > UB_MAX_REQ_SG) { /* Paranoia */ +- printk(KERN_WARNING "%s: request with %d segments\n", +- sc->name, n_elem); +- return -1; +- } +- cmd->nsg = n_elem; +- sc->sg_stat[n_elem < 5 ? n_elem : 5]++; ++ 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 = rq->data_len; +- +- return 0; + } + + static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) + { +- struct request *rq = cmd->back; + struct ub_lun *lun = cmd->lun; ++ struct ub_request *urq = cmd->back; ++ struct request *rq; + int uptodate; + ++ rq = urq->rq; ++ + if (cmd->error == 0) { + uptodate = 1; + +@@ -922,9 +931,16 @@ static void ub_rw_cmd_done(struct ub_dev + rq->errors = SAM_STAT_CHECK_CONDITION; + else + rq->errors = DID_ERROR << 16; ++ } else { ++ if (cmd->error == -EIO) { ++ if (ub_rw_cmd_retry(sc, lun, urq, cmd) == 0) ++ return; ++ } + } + } + ++ urq->rq = NULL; ++ + ub_put_cmd(lun, cmd); + ub_end_rq(rq, uptodate); + blk_start_queue(lun->disk->queue); +@@ -939,6 +955,41 @@ static void ub_end_rq(struct request *rq + end_that_request_last(rq); + } + ++static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun, ++ struct ub_request *urq, struct ub_scsi_cmd *cmd) ++{ ++ ++ if (atomic_read(&sc->poison)) ++ return -ENXIO; ++ ++ ub_reset_enter(sc); ++ ++ if (urq->current_try >= 3) ++ return -EIO; ++ urq->current_try++; ++ /* P3 */ printk("%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_cmd_build_block(sc, lun, cmd, urq); ++ ++ cmd->state = UB_CMDST_INIT; ++ cmd->lun = lun; ++ cmd->done = ub_rw_cmd_done; ++ cmd->back = urq; ++ ++ cmd->tag = sc->tagcnt++; ++ ++#if 0 /* Wasteful */ ++ return ub_submit_scsi(sc, cmd); ++#else ++ ub_cmdq_add(sc, cmd); ++ return 0; ++#endif ++} ++ + /* + * Submit a regular SCSI operation (not an auto-sense). + * +@@ -1069,7 +1120,7 @@ static void ub_scsi_dispatch(struct ub_d + 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); +@@ -1092,11 +1143,12 @@ static void ub_scsi_urb_compl(struct ub_ + { + struct urb *urb = &sc->work_urb; + struct bulk_cs_wrap *bcs; ++ 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; + } + + if (cmd->state == UB_CMDST_CLEAR) { +@@ -1104,7 +1156,6 @@ static void ub_scsi_urb_compl(struct ub_ + /* + * 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); +@@ -1123,11 +1174,6 @@ static void ub_scsi_urb_compl(struct ub_ + + } 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; +@@ -1145,11 +1191,6 @@ static void ub_scsi_urb_compl(struct ub_ + + } 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; +@@ -1166,7 +1207,12 @@ static void ub_scsi_urb_compl(struct ub_ + 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: " +@@ -1176,17 +1222,20 @@ static void ub_scsi_urb_compl(struct ub_ + * 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) { ++ 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) { +- /* XXX Must do reset here to unconfuse the device */ + goto Bad_End; + } + +@@ -1205,11 +1254,8 @@ static void ub_scsi_urb_compl(struct ub_ + 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); +@@ -1218,14 +1264,50 @@ static void ub_scsi_urb_compl(struct ub_ + if (urb->status == -EOVERFLOW) { + /* + * A babble? Failure, but we must transfer CSW now. +- * XXX This is going to end in perpetual babble. Reset. + */ + cmd->error = -EOVERFLOW; /* A cheap trick... */ + ub_state_stat(sc, cmd); + return; + } +- if (urb->status != 0) +- goto Bad_End; ++ ++ 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; ++ ub_cmdtr_act_len(sc, cmd); ++ ++ 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) ++ 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); +@@ -1243,11 +1325,8 @@ static void ub_scsi_urb_compl(struct ub_ + 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; + } + + /* +@@ -1260,14 +1339,8 @@ static void ub_scsi_urb_compl(struct ub_ + 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; + +@@ -1313,15 +1386,15 @@ static void ub_scsi_urb_compl(struct ub_ + return; + } + +- rc = le32_to_cpu(bcs->Residue); +- if (rc != cmd->len - cmd->act_len) { ++ len = le32_to_cpu(bcs->Residue); ++ if (len != 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); ++ sc->name, len, cmd->len, cmd->act_len); + goto Bad_End; + } + +@@ -1332,13 +1405,13 @@ static void ub_scsi_urb_compl(struct ub_ + 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 */ +@@ -1358,7 +1431,8 @@ static void ub_scsi_urb_compl(struct ub_ + printk(KERN_WARNING "%s: " + "wrong command state %d\n", + sc->name, cmd->state); +- goto Bad_End; ++ ub_state_done(sc, cmd, -EINVAL); ++ return; + } + return; + +@@ -1606,6 +1680,93 @@ static void ub_top_sense_done(struct ub_ + } + + /* ++ * Reset management ++ */ ++ ++static void ub_reset_enter(struct ub_dev *sc) ++{ ++ ++ if (sc->reset) { ++ /* This happens often on multi-LUN devices. */ ++ return; ++ } ++ sc->reset = 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 list_head *p; ++ struct ub_lun *lun; ++ list_for_each(p, &sc->luns) { ++ lun = list_entry(p, struct ub_lun, link); ++ blk_stop_queue(lun->disk->queue); ++ } ++#endif ++ ++ schedule_work(&sc->reset_work); ++} ++ ++static void ub_reset_task(void *arg) ++{ ++ struct ub_dev *sc = arg; ++ unsigned long flags; ++ struct list_head *p; ++ struct ub_lun *lun; ++ int lkr, rc; ++ ++ if (!sc->reset) { ++ printk(KERN_WARNING "%s: Running reset unrequested\n", ++ sc->name); ++ return; ++ } ++ ++ if (atomic_read(&sc->poison)) { ++ printk(KERN_NOTICE "%s: Not resetting disconnected device\n", ++ sc->name); /* P3 This floods. Remove soon. XXX */ ++ } else if (sc->dev->actconfig->desc.bNumInterfaces != 1) { ++ printk(KERN_NOTICE "%s: Not resetting multi-interface device\n", ++ sc->name); /* P3 This floods. Remove soon. XXX */ ++ } else { ++ if ((lkr = usb_lock_device_for_reset(sc->dev, sc->intf)) < 0) { ++ printk(KERN_NOTICE ++ "%s: usb_lock_device_for_reset failed (%d)\n", ++ sc->name, lkr); ++ } 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); ++ } ++ ++ if (lkr) ++ 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(p, &sc->luns) { ++ lun = list_entry(p, struct ub_lun, link); ++ blk_start_queue(lun->disk->queue); ++ } ++ wake_up(&sc->reset_wait); ++ spin_unlock_irqrestore(&sc->lock, flags); ++} ++ ++/* + * This is called from a process context. + */ + static void ub_revalidate(struct ub_dev *sc, struct ub_lun *lun) +@@ -2140,7 +2301,7 @@ static int ub_get_pipes(struct ub_dev *s + if (ep_in == NULL || ep_out == NULL) { + printk(KERN_NOTICE "%s: failed endpoint check\n", + sc->name); +- return -EIO; ++ return -ENODEV; + } + + /* Calculate and store the pipe values */ +@@ -2178,6 +2339,8 @@ static int ub_probe(struct usb_interface + 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, sc); ++ init_waitqueue_head(&sc->reset_wait); + + init_timer(&sc->work_timer); + sc->work_timer.data = (unsigned long) sc; +@@ -2198,7 +2361,8 @@ static int ub_probe(struct usb_interface + + /* XXX Verify that we can handle the device (from descriptors) */ + +- ub_get_pipes(sc, sc->dev, intf); ++ if (ub_get_pipes(sc, sc->dev, intf) != 0) ++ goto err_dev_desc; + + if (device_create_file(&sc->intf->dev, &dev_attr_diag) != 0) + goto err_diag; +@@ -2269,6 +2433,7 @@ static int ub_probe(struct usb_interface + + /* 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_dev(sc->dev); +@@ -2376,6 +2541,11 @@ static void ub_disconnect(struct usb_int + 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 +@@ -2388,7 +2558,7 @@ static void ub_disconnect(struct usb_int + { + 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); diff --git a/usb/usb-ub-01-rename.patch b/usb/usb-ub-01-rename.patch new file mode 100644 index 0000000000000..b57ba7bb04e5e --- /dev/null +++ b/usb/usb-ub-01-rename.patch @@ -0,0 +1,44 @@ +From zaitcev@redhat.com Sat Dec 17 02:38:38 2005 +Date: Sat, 17 Dec 2005 02:34:12 -0800 +From: Pete Zaitcev <zaitcev@redhat.com> +To: greg@kroah.com +Cc: zaitcev@redhat.com, jgarzik@redhat.com +Subject: usb: ub 01 rename +Message-Id: <20051217023412.54e37b60.zaitcev@redhat.com> + +Rename misleading UB_MINORS_PER_MAJOR into UB_PARTS_PER_LUN. + +Signed-off-by: Pete Zaitcev <zaitcev@redhat.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/block/ub.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- gregkh-2.6.orig/drivers/block/ub.c ++++ gregkh-2.6/drivers/block/ub.c +@@ -113,7 +113,7 @@ + /* + */ + +-#define UB_MINORS_PER_MAJOR 8 ++#define UB_PARTS_PER_LUN 8 + + #define UB_MAX_CDB_SIZE 16 /* Corresponds to Bulk */ + +@@ -2471,13 +2471,13 @@ static int ub_probe_lun(struct ub_dev *s + 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'); + 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; diff --git a/usb/usb-ub-02-removed-unused-variable.patch b/usb/usb-ub-02-removed-unused-variable.patch new file mode 100644 index 0000000000000..54f0dcea5196d --- /dev/null +++ b/usb/usb-ub-02-removed-unused-variable.patch @@ -0,0 +1,34 @@ +From zaitcev@redhat.com Sat Dec 17 02:43:51 2005 +Date: Sat, 17 Dec 2005 02:38:46 -0800 +From: Pete Zaitcev <zaitcev@redhat.com> +To: greg@kroah.com +Cc: zaitcev@redhat.com +Subject: usb: ub 02 Removed unused variable +Message-Id: <20051217023846.371889c1.zaitcev@redhat.com> + +From: Daniel Marjamaki <daniel.marjamaki@comhem.se> + +Removed an unused variable + +Signed-off-by: Daniel Marjamaki <daniel.marjamaki@comhem.se> +Signed-off-by: Pete Zaitcev <zaitcev@redhat.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/block/ub.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +--- gregkh-2.6.orig/drivers/block/ub.c ++++ gregkh-2.6/drivers/block/ub.c +@@ -948,10 +948,7 @@ static void ub_rw_cmd_done(struct ub_dev + + static void ub_end_rq(struct request *rq, int uptodate) + { +- int rc; +- +- rc = end_that_request_first(rq, uptodate, rq->hard_nr_sectors); +- // assert(rc == 0); ++ end_that_request_first(rq, uptodate, rq->hard_nr_sectors); + end_that_request_last(rq); + } + diff --git a/usb/usb-zd1201-make-sysfs-device-symlink.patch b/usb/usb-zd1201-make-sysfs-device-symlink.patch new file mode 100644 index 0000000000000..8003d211c9f11 --- /dev/null +++ b/usb/usb-zd1201-make-sysfs-device-symlink.patch @@ -0,0 +1,43 @@ +From linux-usb-devel-admin@lists.sourceforge.net Sun Dec 18 21:48:07 2005 +From: Nathan Lynch <ntl@pobox.com> +Cc: pe1rxq@amsat.org +Message-ID: <20051219054137.GA17414@localhost.localdomain> +Content-Disposition: inline +Subject: USB: zd1201: make sysfs device symlink +Date: Sun, 18 Dec 2005 23:41:38 -0600 + +Noticed that my zd1201 adapter isn't "seen" by hal and NetworkManager. +The problem seems to be that unlike other network device drivers I +checked, zd1201 does not do a SET_NETDEV_DEV(), which makes it so a +"device" symlink is created under /sys/class/net/wlan0. + +With the following patch the device symlink shows up, and now I am +happily using NetworkManager to control the adapter: + +$ ls -l /sys/class/net/wlan0 +total 0 +-r--r--r-- 1 root root 4096 Dec 18 13:42 address +-r--r--r-- 1 root root 4096 Dec 18 13:42 addr_len +-r--r--r-- 1 root root 4096 Dec 18 13:42 broadcast +-r--r--r-- 1 root root 4096 Dec 18 13:42 carrier +lrwxrwxrwx 1 root root 0 Dec 18 13:42 device -> ../../../devices/pci0001:10/0001:10:1b.1/usb4/4-1 +-r--r--r-- 1 root root 4096 Dec 18 13:42 features + +Signed-off-by: Nathan Lynch <ntl@pobox.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/net/zd1201.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- gregkh-2.6.orig/drivers/usb/net/zd1201.c ++++ gregkh-2.6/drivers/usb/net/zd1201.c +@@ -1829,6 +1829,8 @@ static int zd1201_probe(struct usb_inter + if (err) + goto err_net; + ++ SET_NETDEV_DEV(zd->dev, &usb->dev); ++ + err = register_netdev(zd->dev); + if (err) + goto err_net; |