Commit b7b5d11f authored by Hans de Goede's avatar Hans de Goede Committed by Greg Kroah-Hartman

uas: Fix resetting flag handling

- Make sure we always hold the lock when setting / checking resetting
- Check resetting before checking urb->status
- Add missing check for resetting to uas_data_cmplt
- Add missing check for resetting to uas_do_work
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 5df2be63
...@@ -129,6 +129,10 @@ static void uas_do_work(struct work_struct *work) ...@@ -129,6 +129,10 @@ static void uas_do_work(struct work_struct *work)
int err; int err;
spin_lock_irqsave(&devinfo->lock, flags); spin_lock_irqsave(&devinfo->lock, flags);
if (devinfo->resetting)
goto out;
list_for_each_entry(cmdinfo, &devinfo->inflight_list, list) { list_for_each_entry(cmdinfo, &devinfo->inflight_list, list) {
struct scsi_pointer *scp = (void *)cmdinfo; struct scsi_pointer *scp = (void *)cmdinfo;
struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd, struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
...@@ -143,6 +147,7 @@ static void uas_do_work(struct work_struct *work) ...@@ -143,6 +147,7 @@ static void uas_do_work(struct work_struct *work)
else else
schedule_work(&devinfo->work); schedule_work(&devinfo->work);
} }
out:
spin_unlock_irqrestore(&devinfo->lock, flags); spin_unlock_irqrestore(&devinfo->lock, flags);
} }
...@@ -322,6 +327,11 @@ static void uas_stat_cmplt(struct urb *urb) ...@@ -322,6 +327,11 @@ static void uas_stat_cmplt(struct urb *urb)
unsigned long flags; unsigned long flags;
u16 tag; u16 tag;
spin_lock_irqsave(&devinfo->lock, flags);
if (devinfo->resetting)
goto out;
if (urb->status) { if (urb->status) {
if (urb->status == -ENOENT) { if (urb->status == -ENOENT) {
dev_err(&urb->dev->dev, "stat urb: killed, stream %d\n", dev_err(&urb->dev->dev, "stat urb: killed, stream %d\n",
...@@ -330,27 +340,17 @@ static void uas_stat_cmplt(struct urb *urb) ...@@ -330,27 +340,17 @@ static void uas_stat_cmplt(struct urb *urb)
dev_err(&urb->dev->dev, "stat urb: status %d\n", dev_err(&urb->dev->dev, "stat urb: status %d\n",
urb->status); urb->status);
} }
usb_free_urb(urb); goto out;
return;
}
if (devinfo->resetting) {
usb_free_urb(urb);
return;
} }
spin_lock_irqsave(&devinfo->lock, flags);
tag = be16_to_cpup(&iu->tag) - 1; tag = be16_to_cpup(&iu->tag) - 1;
if (tag == 0) if (tag == 0)
cmnd = devinfo->cmnd; cmnd = devinfo->cmnd;
else else
cmnd = scsi_host_find_tag(shost, tag - 1); cmnd = scsi_host_find_tag(shost, tag - 1);
if (!cmnd) { if (!cmnd)
usb_free_urb(urb); goto out;
spin_unlock_irqrestore(&devinfo->lock, flags);
return;
}
cmdinfo = (void *)&cmnd->SCp; cmdinfo = (void *)&cmnd->SCp;
switch (iu->iu_id) { switch (iu->iu_id) {
...@@ -391,6 +391,7 @@ static void uas_stat_cmplt(struct urb *urb) ...@@ -391,6 +391,7 @@ static void uas_stat_cmplt(struct urb *urb)
scmd_printk(KERN_ERR, cmnd, scmd_printk(KERN_ERR, cmnd,
"Bogus IU (%d) received on status pipe\n", iu->iu_id); "Bogus IU (%d) received on status pipe\n", iu->iu_id);
} }
out:
usb_free_urb(urb); usb_free_urb(urb);
spin_unlock_irqrestore(&devinfo->lock, flags); spin_unlock_irqrestore(&devinfo->lock, flags);
} }
...@@ -404,6 +405,7 @@ static void uas_data_cmplt(struct urb *urb) ...@@ -404,6 +405,7 @@ static void uas_data_cmplt(struct urb *urb)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&devinfo->lock, flags); spin_lock_irqsave(&devinfo->lock, flags);
if (cmdinfo->data_in_urb == urb) { if (cmdinfo->data_in_urb == urb) {
sdb = scsi_in(cmnd); sdb = scsi_in(cmnd);
cmdinfo->state &= ~DATA_IN_URB_INFLIGHT; cmdinfo->state &= ~DATA_IN_URB_INFLIGHT;
...@@ -413,7 +415,13 @@ static void uas_data_cmplt(struct urb *urb) ...@@ -413,7 +415,13 @@ static void uas_data_cmplt(struct urb *urb)
} }
if (sdb == NULL) { if (sdb == NULL) {
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
} else if (urb->status) { goto out;
}
if (devinfo->resetting)
goto out;
if (urb->status) {
if (urb->status != -ECONNRESET) { if (urb->status != -ECONNRESET) {
uas_log_cmd_state(cmnd, __func__); uas_log_cmd_state(cmnd, __func__);
scmd_printk(KERN_ERR, cmnd, scmd_printk(KERN_ERR, cmnd,
...@@ -426,6 +434,7 @@ static void uas_data_cmplt(struct urb *urb) ...@@ -426,6 +434,7 @@ static void uas_data_cmplt(struct urb *urb)
sdb->resid = sdb->length - urb->actual_length; sdb->resid = sdb->length - urb->actual_length;
} }
uas_try_complete(cmnd, __func__); uas_try_complete(cmnd, __func__);
out:
spin_unlock_irqrestore(&devinfo->lock, flags); spin_unlock_irqrestore(&devinfo->lock, flags);
} }
...@@ -732,6 +741,7 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd) ...@@ -732,6 +741,7 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
struct scsi_device *sdev = cmnd->device; struct scsi_device *sdev = cmnd->device;
struct uas_dev_info *devinfo = sdev->hostdata; struct uas_dev_info *devinfo = sdev->hostdata;
struct usb_device *udev = devinfo->udev; struct usb_device *udev = devinfo->udev;
unsigned long flags;
int err; int err;
err = usb_lock_device_for_reset(udev, devinfo->intf); err = usb_lock_device_for_reset(udev, devinfo->intf);
...@@ -742,14 +752,21 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd) ...@@ -742,14 +752,21 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
} }
shost_printk(KERN_INFO, sdev->host, "%s start\n", __func__); shost_printk(KERN_INFO, sdev->host, "%s start\n", __func__);
spin_lock_irqsave(&devinfo->lock, flags);
devinfo->resetting = 1; devinfo->resetting = 1;
spin_unlock_irqrestore(&devinfo->lock, flags);
uas_abort_inflight(devinfo, DID_RESET, __func__); uas_abort_inflight(devinfo, DID_RESET, __func__);
usb_kill_anchored_urbs(&devinfo->cmd_urbs); usb_kill_anchored_urbs(&devinfo->cmd_urbs);
usb_kill_anchored_urbs(&devinfo->sense_urbs); usb_kill_anchored_urbs(&devinfo->sense_urbs);
usb_kill_anchored_urbs(&devinfo->data_urbs); usb_kill_anchored_urbs(&devinfo->data_urbs);
uas_zap_dead(devinfo); uas_zap_dead(devinfo);
err = usb_reset_device(udev); err = usb_reset_device(udev);
spin_lock_irqsave(&devinfo->lock, flags);
devinfo->resetting = 0; devinfo->resetting = 0;
spin_unlock_irqrestore(&devinfo->lock, flags);
usb_unlock_device(udev); usb_unlock_device(udev);
...@@ -1049,8 +1066,12 @@ static void uas_disconnect(struct usb_interface *intf) ...@@ -1049,8 +1066,12 @@ static void uas_disconnect(struct usb_interface *intf)
{ {
struct Scsi_Host *shost = usb_get_intfdata(intf); struct Scsi_Host *shost = usb_get_intfdata(intf);
struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata; struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
unsigned long flags;
spin_lock_irqsave(&devinfo->lock, flags);
devinfo->resetting = 1; devinfo->resetting = 1;
spin_unlock_irqrestore(&devinfo->lock, flags);
cancel_work_sync(&devinfo->work); cancel_work_sync(&devinfo->work);
uas_abort_inflight(devinfo, DID_NO_CONNECT, __func__); uas_abort_inflight(devinfo, DID_NO_CONNECT, __func__);
usb_kill_anchored_urbs(&devinfo->cmd_urbs); usb_kill_anchored_urbs(&devinfo->cmd_urbs);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment