|
@@ -786,6 +786,7 @@ static void usb_stor_release_resources(struct us_data *us)
|
|
|
* any more commands.
|
|
|
*/
|
|
|
US_DEBUGP("-- sending exit command to thread\n");
|
|
|
+ set_bit(US_FLIDX_DISCONNECTING, &us->flags);
|
|
|
up(&us->sema);
|
|
|
|
|
|
/* Call the destructor routine, if it exists */
|
|
@@ -816,6 +817,36 @@ static void dissociate_dev(struct us_data *us)
|
|
|
usb_set_intfdata(us->pusb_intf, NULL);
|
|
|
}
|
|
|
|
|
|
+/* First stage of disconnect processing: stop all commands and remove
|
|
|
+ * the host */
|
|
|
+static void quiesce_and_remove_host(struct us_data *us)
|
|
|
+{
|
|
|
+ /* Prevent new USB transfers, stop the current command, and
|
|
|
+ * interrupt a SCSI-scan or device-reset delay */
|
|
|
+ set_bit(US_FLIDX_DISCONNECTING, &us->flags);
|
|
|
+ usb_stor_stop_transport(us);
|
|
|
+ wake_up(&us->delay_wait);
|
|
|
+
|
|
|
+ /* It doesn't matter if the SCSI-scanning thread is still running.
|
|
|
+ * The thread will exit when it sees the DISCONNECTING flag. */
|
|
|
+
|
|
|
+ /* Wait for the current command to finish, then remove the host */
|
|
|
+ down(&us->dev_semaphore);
|
|
|
+ up(&us->dev_semaphore);
|
|
|
+ scsi_remove_host(us_to_host(us));
|
|
|
+}
|
|
|
+
|
|
|
+/* Second stage of disconnect processing: deallocate all resources */
|
|
|
+static void release_everything(struct us_data *us)
|
|
|
+{
|
|
|
+ usb_stor_release_resources(us);
|
|
|
+ dissociate_dev(us);
|
|
|
+
|
|
|
+ /* Drop our reference to the host; the SCSI core will free it
|
|
|
+ * (and "us" along with it) when the refcount becomes 0. */
|
|
|
+ scsi_host_put(us_to_host(us));
|
|
|
+}
|
|
|
+
|
|
|
/* Thread to carry out delayed SCSI-device scanning */
|
|
|
static int usb_stor_scan_thread(void * __us)
|
|
|
{
|
|
@@ -956,7 +987,7 @@ static int storage_probe(struct usb_interface *intf,
|
|
|
if (result < 0) {
|
|
|
printk(KERN_WARNING USB_STORAGE
|
|
|
"Unable to start the device-scanning thread\n");
|
|
|
- scsi_remove_host(host);
|
|
|
+ quiesce_and_remove_host(us);
|
|
|
goto BadDevice;
|
|
|
}
|
|
|
atomic_inc(&total_threads);
|
|
@@ -969,10 +1000,7 @@ static int storage_probe(struct usb_interface *intf,
|
|
|
/* We come here if there are any problems */
|
|
|
BadDevice:
|
|
|
US_DEBUGP("storage_probe() failed\n");
|
|
|
- set_bit(US_FLIDX_DISCONNECTING, &us->flags);
|
|
|
- usb_stor_release_resources(us);
|
|
|
- dissociate_dev(us);
|
|
|
- scsi_host_put(host);
|
|
|
+ release_everything(us);
|
|
|
return result;
|
|
|
}
|
|
|
|
|
@@ -982,28 +1010,8 @@ static void storage_disconnect(struct usb_interface *intf)
|
|
|
struct us_data *us = usb_get_intfdata(intf);
|
|
|
|
|
|
US_DEBUGP("storage_disconnect() called\n");
|
|
|
-
|
|
|
- /* Prevent new USB transfers, stop the current command, and
|
|
|
- * interrupt a SCSI-scan or device-reset delay */
|
|
|
- set_bit(US_FLIDX_DISCONNECTING, &us->flags);
|
|
|
- usb_stor_stop_transport(us);
|
|
|
- wake_up(&us->delay_wait);
|
|
|
-
|
|
|
- /* It doesn't matter if the SCSI-scanning thread is still running.
|
|
|
- * The thread will exit when it sees the DISCONNECTING flag. */
|
|
|
-
|
|
|
- /* Wait for the current command to finish, then remove the host */
|
|
|
- down(&us->dev_semaphore);
|
|
|
- up(&us->dev_semaphore);
|
|
|
- scsi_remove_host(us_to_host(us));
|
|
|
-
|
|
|
- /* Wait for everything to become idle and release all our resources */
|
|
|
- usb_stor_release_resources(us);
|
|
|
- dissociate_dev(us);
|
|
|
-
|
|
|
- /* Drop our reference to the host; the SCSI core will free it
|
|
|
- * (and "us" along with it) when the refcount becomes 0. */
|
|
|
- scsi_host_put(us_to_host(us));
|
|
|
+ quiesce_and_remove_host(us);
|
|
|
+ release_everything(us);
|
|
|
}
|
|
|
|
|
|
/***********************************************************************
|