[PATCH] USB: ub 05 Bulk reset

For crying out loud, they have devices which do not like port resets.
So, do what usb-storage does and try both bulk and port resets.
We start with a port reset (which usb-storage does at the end of transport),
then do a Bulk reset, then a port reset again. This seems to work for me.

The code is getting dirtier and dirtier here, but I swear that I'll
do something about it (see those two new XXX). Honest.

Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Pete Zaitcev 2006-01-05 00:26:30 -08:00 committed by Greg Kroah-Hartman
parent b31f821c6d
commit 2c2e4a2e07

View file

@ -14,7 +14,6 @@
* -- 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.
@ -420,11 +419,13 @@ 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);
static void ub_reset_enter(struct ub_dev *sc, int try);
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);
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);
/*
@ -983,7 +984,7 @@ static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
if (atomic_read(&sc->poison))
return -ENXIO;
ub_reset_enter(sc);
ub_reset_enter(sc, urq->current_try);
if (urq->current_try >= 3)
return -EIO;
@ -1019,8 +1020,6 @@ static int ub_rw_cmd_retry(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)
{
@ -1703,16 +1702,18 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
/*
* Reset management
* XXX Move usb_reset_device to khubd. Hogging kevent is not a good thing.
* XXX Make usb_sync_reset asynchronous.
*/
static void ub_reset_enter(struct ub_dev *sc)
static void ub_reset_enter(struct ub_dev *sc, int try)
{
if (sc->reset) {
/* This happens often on multi-LUN devices. */
return;
}
sc->reset = 1;
sc->reset = try + 1;
#if 0 /* Not needed because the disconnect waits for us. */
unsigned long flags;
@ -1750,6 +1751,11 @@ static void ub_reset_task(void *arg)
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->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) {
printk(KERN_NOTICE "%s: Not resetting multi-interface device\n",
sc->name); /* P3 This floods. Remove soon. XXX */
@ -2140,6 +2146,52 @@ static void ub_probe_timeout(unsigned long arg)
complete(cop);
}
/*
* 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);
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
"%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.
*/