aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/storage/usb.c62
1 files changed, 35 insertions, 27 deletions
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 77e7fc258aa2..255771151399 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -786,6 +786,7 @@ static void usb_stor_release_resources(struct us_data *us)
786 * any more commands. 786 * any more commands.
787 */ 787 */
788 US_DEBUGP("-- sending exit command to thread\n"); 788 US_DEBUGP("-- sending exit command to thread\n");
789 set_bit(US_FLIDX_DISCONNECTING, &us->flags);
789 up(&us->sema); 790 up(&us->sema);
790 791
791 /* Call the destructor routine, if it exists */ 792 /* Call the destructor routine, if it exists */
@@ -816,6 +817,36 @@ static void dissociate_dev(struct us_data *us)
816 usb_set_intfdata(us->pusb_intf, NULL); 817 usb_set_intfdata(us->pusb_intf, NULL);
817} 818}
818 819
820/* First stage of disconnect processing: stop all commands and remove
821 * the host */
822static void quiesce_and_remove_host(struct us_data *us)
823{
824 /* Prevent new USB transfers, stop the current command, and
825 * interrupt a SCSI-scan or device-reset delay */
826 set_bit(US_FLIDX_DISCONNECTING, &us->flags);
827 usb_stor_stop_transport(us);
828 wake_up(&us->delay_wait);
829
830 /* It doesn't matter if the SCSI-scanning thread is still running.
831 * The thread will exit when it sees the DISCONNECTING flag. */
832
833 /* Wait for the current command to finish, then remove the host */
834 down(&us->dev_semaphore);
835 up(&us->dev_semaphore);
836 scsi_remove_host(us_to_host(us));
837}
838
839/* Second stage of disconnect processing: deallocate all resources */
840static void release_everything(struct us_data *us)
841{
842 usb_stor_release_resources(us);
843 dissociate_dev(us);
844
845 /* Drop our reference to the host; the SCSI core will free it
846 * (and "us" along with it) when the refcount becomes 0. */
847 scsi_host_put(us_to_host(us));
848}
849
819/* Thread to carry out delayed SCSI-device scanning */ 850/* Thread to carry out delayed SCSI-device scanning */
820static int usb_stor_scan_thread(void * __us) 851static int usb_stor_scan_thread(void * __us)
821{ 852{
@@ -956,7 +987,7 @@ static int storage_probe(struct usb_interface *intf,
956 if (result < 0) { 987 if (result < 0) {
957 printk(KERN_WARNING USB_STORAGE 988 printk(KERN_WARNING USB_STORAGE
958 "Unable to start the device-scanning thread\n"); 989 "Unable to start the device-scanning thread\n");
959 scsi_remove_host(host); 990 quiesce_and_remove_host(us);
960 goto BadDevice; 991 goto BadDevice;
961 } 992 }
962 atomic_inc(&total_threads); 993 atomic_inc(&total_threads);
@@ -969,10 +1000,7 @@ static int storage_probe(struct usb_interface *intf,
969 /* We come here if there are any problems */ 1000 /* We come here if there are any problems */
970BadDevice: 1001BadDevice:
971 US_DEBUGP("storage_probe() failed\n"); 1002 US_DEBUGP("storage_probe() failed\n");
972 set_bit(US_FLIDX_DISCONNECTING, &us->flags); 1003 release_everything(us);
973 usb_stor_release_resources(us);
974 dissociate_dev(us);
975 scsi_host_put(host);
976 return result; 1004 return result;
977} 1005}
978 1006
@@ -982,28 +1010,8 @@ static void storage_disconnect(struct usb_interface *intf)
982 struct us_data *us = usb_get_intfdata(intf); 1010 struct us_data *us = usb_get_intfdata(intf);
983 1011
984 US_DEBUGP("storage_disconnect() called\n"); 1012 US_DEBUGP("storage_disconnect() called\n");
985 1013 quiesce_and_remove_host(us);
986 /* Prevent new USB transfers, stop the current command, and 1014 release_everything(us);
987 * interrupt a SCSI-scan or device-reset delay */
988 set_bit(US_FLIDX_DISCONNECTING, &us->flags);
989 usb_stor_stop_transport(us);
990 wake_up(&us->delay_wait);
991
992 /* It doesn't matter if the SCSI-scanning thread is still running.
993 * The thread will exit when it sees the DISCONNECTING flag. */
994
995 /* Wait for the current command to finish, then remove the host */
996 down(&us->dev_semaphore);
997 up(&us->dev_semaphore);
998 scsi_remove_host(us_to_host(us));
999
1000 /* Wait for everything to become idle and release all our resources */
1001 usb_stor_release_resources(us);
1002 dissociate_dev(us);
1003
1004 /* Drop our reference to the host; the SCSI core will free it
1005 * (and "us" along with it) when the refcount becomes 0. */
1006 scsi_host_put(us_to_host(us));
1007} 1015}
1008 1016
1009/*********************************************************************** 1017/***********************************************************************