summaryrefslogtreecommitdiff
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-23 08:44:27 +0200
commit63754da0893a1b9fc59c45a46fa5f6efb0d0956c (patch)
tree3d88296469f81bb9c2dc067e4e82d298c2415246
parentc349187277b6e3cc3d7d2f1e0460bd18f6ca8f26 (diff)
USB: UAS: fix disconnect by unplugging a hub
commit 325b008723b2dd31de020e85ab9d2e9aa4637d35 upstream. 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> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20200916094026.30085-2-oneukum@suse.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-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 698ba127b635..34dcd2e1b4fe 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -646,8 +646,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 */
@@ -682,6 +681,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, GFP_ATOMIC);
+ /*
+ * 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) {
@@ -692,6 +701,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
}
devinfo->cmnd[idx] = cmnd;
+zombie:
spin_unlock_irqrestore(&devinfo->lock, flags);
return 0;
}