[PATCH 2/2] uas: Fix reset handling for externally triggered reset

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Handle usb-device resets not triggered from uas_eh_bus_reset_handler(), when
this happens, disable cmd queuing during the reset, and wait for existing
requests to finish in pre_reset.

Signed-off-by: Hans de Goede <hdegoede@xxxxxxxxxx>
---
 drivers/usb/storage/uas.c | 47 ++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 42 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index 92fa51c..9969632 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -18,6 +18,7 @@
 #include <linux/usb/uas.h>
 
 #include <scsi/scsi.h>
+#include <scsi/scsi_eh.h>
 #include <scsi/scsi_dbg.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
@@ -820,10 +821,7 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
 	usb_kill_anchored_urbs(&devinfo->sense_urbs);
 	usb_kill_anchored_urbs(&devinfo->data_urbs);
 	uas_zap_dead(devinfo);
-	uas_free_streams(devinfo);
 	err = usb_reset_device(udev);
-	if (!err)
-		uas_configure_endpoints(devinfo);
 	devinfo->resetting = 0;
 
 	usb_unlock_device(udev);
@@ -1030,13 +1028,52 @@ set_alt0:
 
 static int uas_pre_reset(struct usb_interface *intf)
 {
-/* XXX: Need to return 1 if it's not our device in error handling */
+	struct Scsi_Host *shost = usb_get_intfdata(intf);
+	struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
+	unsigned long flags;
+	int empty;
+
+	/* Block new requests */
+	spin_lock_irqsave(shost->host_lock, flags);
+	scsi_block_requests(shost);
+	spin_unlock_irqrestore(shost->host_lock, flags);
+
+	/* Flush work queue (uas_do_work is re-entrant safe) */
+	uas_do_work(&devinfo->work);
+	spin_lock_irqsave(&devinfo->lock, flags);
+	empty = list_empty(&devinfo->work_list);
+	spin_unlock_irqrestore(&devinfo->lock, flags);
+	if (!empty) {
+		shost_printk(KERN_ERR, shost,
+			     "%s: flush work queue failed\n", __func__);
+		return 1;
+	}
+
+	/* Wait for any pending requests to complete */
+	if (usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 5000) == 0) {
+		shost_printk(KERN_ERR, shost, "%s: timed out\n", __func__);
+		return 1;
+	}
+
+	uas_free_streams(devinfo);
+
 	return 0;
 }
 
 static int uas_post_reset(struct usb_interface *intf)
 {
-/* XXX: Need to return 1 if it's not our device in error handling */
+	struct Scsi_Host *shost = usb_get_intfdata(intf);
+	struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
+	unsigned long flags;
+
+	uas_configure_endpoints(devinfo);
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	scsi_report_bus_reset(shost, 0);
+	spin_unlock_irqrestore(shost->host_lock, flags);
+
+	scsi_unblock_requests(shost);
+
 	return 0;
 }
 
-- 
1.8.3.1

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




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux