A reset based on usb_reset_device() will reset the whole
host, not just a bus. We should use the correct entry.

Signed-off-by: Oliver Neukum <oneu...@suse.com>
---
 drivers/usb/storage/uas.c | 33 +++++++++++++++++++++++++++++++--
 1 file changed, 31 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index 31ff1a0..f1eaa93 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -57,7 +57,9 @@ struct uas_dev_info {
        spinlock_t lock;
        struct work_struct work;
        struct completion deathknell;
-       bool aborted;
+       bool aborted; /* a reply to a TASK ABORT was seen */
+       bool tmf_catastrophic; /* TMF failed, retry useless */
+       bool tmf_error; /* tmf may be retried after error handling */
 };
 
 enum {
@@ -492,6 +494,20 @@ static void uas_tmf_cmplt(struct urb *urb)
        if (status < 0) {
                devinfo->deathrow = NULL;
                complete(&devinfo->deathknell);
+               switch (status) {
+               case -ESHUTDOWN:
+               case -ENODEV:
+                       devinfo->tmf_catastrophic = true;
+                       break;
+               case -EPIPE:
+               /* small packages, hence no partial transmission */
+               case -EILSEQ:
+               case -EPROTO:
+                       devinfo->tmf_error = true;
+                       break;
+               default:
+                       break;
+               }
        }
 
        /*
@@ -794,6 +810,7 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
        struct urb *data_out_urb = NULL;
        unsigned long flags;
        int err, time;
+       int success = FAILED;
 
        spin_lock_irqsave(&devinfo->lock, flags);
 
@@ -804,6 +821,8 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
 
        init_completion(&devinfo->deathknell);
        devinfo->deathrow = cmnd;
+       devinfo->tmf_catastrophic = false;
+       devinfo->tmf_error = false;
        usb_fill_bulk_urb(devinfo->management_urb,
                          devinfo->udev,
                          devinfo->cmd_pipe, /* shared */
@@ -819,6 +838,12 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
        err = usb_submit_urb(devinfo->management_urb, GFP_NOIO);
        if (err < 0) /* unkillable */
                goto give_up;
+       else
+               /*
+                * SCSI has the convention that a potential
+                * ABORT is to be reported as SUCCESS
+                */
+               success = SUCCESS;
 
        time = wait_for_completion_timeout(&devinfo->deathknell, 
USB_CTRL_GET_TIMEOUT);
        /* in case of timeout */
@@ -831,6 +856,10 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
                cmnd->result = DID_ABORT << 16;
                cmnd->scsi_done(cmnd);
        }
+       if (devinfo->tmf_catastrophic)
+               success = FAST_IO_FAIL;
+       else if (devinfo->tmf_error)
+               success = FAILED;
 
 give_up:
 
@@ -854,7 +883,7 @@ give_up:
                usb_put_urb(data_out_urb);
        }
 
-       return FAILED;
+       return success;
 }
 
 static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to