| From 325b008723b2dd31de020e85ab9d2e9aa4637d35 Mon Sep 17 00:00:00 2001 |
| From: Oliver Neukum <oneukum@suse.com> |
| Date: Wed, 16 Sep 2020 11:40:25 +0200 |
| Subject: USB: UAS: fix disconnect by unplugging a hub |
| |
| From: Oliver Neukum <oneukum@suse.com> |
| |
| 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> |
| |
| --- |
| drivers/usb/storage/uas.c | 14 ++++++++++++-- |
| 1 file changed, 12 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/usb/storage/uas.c |
| +++ b/drivers/usb/storage/uas.c |
| @@ -669,8 +669,7 @@ static int uas_queuecommand_lck(struct s |
| 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 */ |
| @@ -706,6 +705,16 @@ static int uas_queuecommand_lck(struct s |
| 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) { |
| @@ -716,6 +725,7 @@ static int uas_queuecommand_lck(struct s |
| } |
| |
| devinfo->cmnd[idx] = cmnd; |
| +zombie: |
| spin_unlock_irqrestore(&devinfo->lock, flags); |
| return 0; |
| } |