summaryrefslogtreecommitdiff
path: root/drivers/usb/storage
diff options
context:
space:
mode:
authorOliver Neukum <oneukum@suse.com>2020-09-16 11:40:25 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2020-09-16 12:43:24 +0200
commiteb2a86ae8c544be0ab04aa8169390c0669bc7148 (patch)
tree25b5c6c956f09fe758ca8013c2e6ef8bd984e8eb /drivers/usb/storage
parent8dba20101aaf67462934e40cb5e6c3641f87d460 (diff)
USB: UAS: fix disconnect by unplugging a hub
The SCSI layer can go into an ugly loop if you ignore that a device is gone. You need to report an error in the command rather than in the return value of the queue method. We need to specifically check for ENODEV. The issue goes back to the introduction of the driver. Fixes: 115bb1ffa54c3 ("USB: Add UAS driver") Signed-off-by: Oliver Neukum <oneukum@suse.com> Link: https://lore.kernel.org/r/20200916094026.30085-2-oneukum@suse.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/storage')
-rw-r--r--drivers/usb/storage/uas.c14
1 files changed, 12 insertions, 2 deletions
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index c1123da43407..abf7e3d64234 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -662,8 +662,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
if (devinfo->resetting) {
cmnd->result = DID_ERROR << 16;
cmnd->scsi_done(cmnd);
- spin_unlock_irqrestore(&devinfo->lock, flags);
- return 0;
+ goto zombie;
}
/* Find a free uas-tag */
@@ -699,6 +698,16 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB);
err = uas_submit_urbs(cmnd, devinfo);
+ /*
+ * in case of fatal errors the SCSI layer is peculiar
+ * a command that has finished is a success for the purpose
+ * of queueing, no matter how fatal the error
+ */
+ if (err == -ENODEV) {
+ cmnd->result = DID_ERROR << 16;
+ cmnd->scsi_done(cmnd);
+ goto zombie;
+ }
if (err) {
/* If we did nothing, give up now */
if (cmdinfo->state & SUBMIT_STATUS_URB) {
@@ -709,6 +718,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
}
devinfo->cmnd[idx] = cmnd;
+zombie:
spin_unlock_irqrestore(&devinfo->lock, flags);
return 0;
}