Skip to content

Commit

Permalink
uas: improve device reset
Browse files Browse the repository at this point in the history
Add new function to unlink and abort requests from the work
list, call it on bus reset and disconnect where we kill all
in-flight urbs.  Also reorder calls in disconnect to first
cancel transfers, then remove the scsi hba.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Gerd Hoffmann authored and Greg Kroah-Hartman committed Jan 11, 2013
1 parent 5d39040 commit 4c45697
Showing 1 changed file with 44 additions and 1 deletion.
45 changes: 44 additions & 1 deletion drivers/usb/storage/uas.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ struct uas_cmd_info {
static int uas_submit_urbs(struct scsi_cmnd *cmnd,
struct uas_dev_info *devinfo, gfp_t gfp);
static void uas_do_work(struct work_struct *work);
static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller);

static DECLARE_WORK(uas_work, uas_do_work);
static DEFINE_SPINLOCK(uas_work_lock);
Expand Down Expand Up @@ -145,6 +146,45 @@ static void uas_do_work(struct work_struct *work)
}
}

static void uas_abort_work(struct uas_dev_info *devinfo)
{
struct uas_cmd_info *cmdinfo;
struct uas_cmd_info *temp;
struct list_head list;
unsigned long flags;

spin_lock_irq(&uas_work_lock);
list_replace_init(&uas_work_list, &list);
spin_unlock_irq(&uas_work_lock);

spin_lock_irqsave(&devinfo->lock, flags);
list_for_each_entry_safe(cmdinfo, temp, &list, list) {
struct scsi_pointer *scp = (void *)cmdinfo;
struct scsi_cmnd *cmnd = container_of(scp,
struct scsi_cmnd, SCp);
struct uas_dev_info *di = (void *)cmnd->device->hostdata;

if (di == devinfo) {
cmdinfo->state |= COMMAND_ABORTED;
cmdinfo->state &= ~IS_IN_WORK_LIST;
if (devinfo->resetting) {
/* uas_stat_cmplt() will not do that
* when a device reset is in
* progress */
cmdinfo->state &= ~COMMAND_INFLIGHT;
}
uas_try_complete(cmnd, __func__);
} else {
/* not our uas device, relink into list */
list_del(&cmdinfo->list);
spin_lock_irq(&uas_work_lock);
list_add_tail(&cmdinfo->list, &uas_work_list);
spin_unlock_irq(&uas_work_lock);
}
}
spin_unlock_irqrestore(&devinfo->lock, flags);
}

static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
{
struct sense_iu *sense_iu = urb->transfer_buffer;
Expand Down Expand Up @@ -750,6 +790,7 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
int err;

devinfo->resetting = 1;
uas_abort_work(devinfo);
usb_kill_anchored_urbs(&devinfo->cmd_urbs);
usb_kill_anchored_urbs(&devinfo->sense_urbs);
usb_kill_anchored_urbs(&devinfo->data_urbs);
Expand Down Expand Up @@ -995,10 +1036,12 @@ static void uas_disconnect(struct usb_interface *intf)
struct Scsi_Host *shost = usb_get_intfdata(intf);
struct uas_dev_info *devinfo = (void *)shost->hostdata[0];

scsi_remove_host(shost);
devinfo->resetting = 1;
uas_abort_work(devinfo);
usb_kill_anchored_urbs(&devinfo->cmd_urbs);
usb_kill_anchored_urbs(&devinfo->sense_urbs);
usb_kill_anchored_urbs(&devinfo->data_urbs);
scsi_remove_host(shost);
uas_free_streams(devinfo);
kfree(devinfo);
}
Expand Down

0 comments on commit 4c45697

Please sign in to comment.