Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2c2e4a2e authored by Pete Zaitcev's avatar Pete Zaitcev Committed by Greg Kroah-Hartman
Browse files

[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: default avatarPete Zaitcev <zaitcev@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent b31f821c
Loading
Loading
Loading
Loading
+59 −7
Original line number Original line Diff line number Diff line
@@ -14,7 +14,6 @@
 *  -- special case some senses, e.g. 3a/0 -> no media present, reduce retries
 *  -- special case some senses, e.g. 3a/0 -> no media present, reduce retries
 *  -- verify the 13 conditions and do bulk resets
 *  -- verify the 13 conditions and do bulk resets
 *  -- kill last_pipe and simply do two-state clearing on both pipes
 *  -- kill last_pipe and simply do two-state clearing on both pipes
 *  -- verify protocol (bulk) from USB descriptors (maybe...)
 *  -- highmem
 *  -- highmem
 *  -- move top_sense and work_bcs into separate allocations (if they survive)
 *  -- move top_sense and work_bcs into separate allocations (if they survive)
 *     for cache purists and esoteric architectures.
 *     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,
static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
    int stalled_pipe);
    int stalled_pipe);
static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd);
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 void ub_reset_task(void *arg);
static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun);
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,
static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
    struct ub_capacity *ret);
    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);
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))
	if (atomic_read(&sc->poison))
		return -ENXIO;
		return -ENXIO;


	ub_reset_enter(sc);
	ub_reset_enter(sc, urq->current_try);


	if (urq->current_try >= 3)
	if (urq->current_try >= 3)
		return -EIO;
		return -EIO;
@@ -1019,8 +1020,6 @@ static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
 * No exceptions.
 * No exceptions.
 *
 *
 * Host is assumed locked.
 * 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)
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
 * 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) {
	if (sc->reset) {
		/* This happens often on multi-LUN devices. */
		/* This happens often on multi-LUN devices. */
		return;
		return;
	}
	}
	sc->reset = 1;
	sc->reset = try + 1;


#if 0 /* Not needed because the disconnect waits for us. */
#if 0 /* Not needed because the disconnect waits for us. */
	unsigned long flags;
	unsigned long flags;
@@ -1750,6 +1751,11 @@ static void ub_reset_task(void *arg)
	if (atomic_read(&sc->poison)) {
	if (atomic_read(&sc->poison)) {
		printk(KERN_NOTICE "%s: Not resetting disconnected device\n",
		printk(KERN_NOTICE "%s: Not resetting disconnected device\n",
		    sc->name); /* P3 This floods. Remove soon. XXX */
		    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) {
	} else if (sc->dev->actconfig->desc.bNumInterfaces != 1) {
		printk(KERN_NOTICE "%s: Not resetting multi-interface device\n",
		printk(KERN_NOTICE "%s: Not resetting multi-interface device\n",
		    sc->name); /* P3 This floods. Remove soon. XXX */
		    sc->name); /* P3 This floods. Remove soon. XXX */
@@ -2140,6 +2146,52 @@ static void ub_probe_timeout(unsigned long arg)
	complete(cop);
	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.
 * Get number of LUNs by the way of Bulk GetMaxLUN command.
 */
 */