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: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
5df2be6333
commit
b7b5d11fae
|
@ -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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
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);
|
||||||
|
|
Loading…
Reference in New Issue