diff options
Diffstat (limited to 'drivers/usb/storage/usb.c')
-rw-r--r-- | drivers/usb/storage/usb.c | 79 |
1 files changed, 51 insertions, 28 deletions
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 77e7fc258aa2..cb4c770baf32 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c | |||
@@ -90,7 +90,9 @@ | |||
90 | #ifdef CONFIG_USB_STORAGE_JUMPSHOT | 90 | #ifdef CONFIG_USB_STORAGE_JUMPSHOT |
91 | #include "jumpshot.h" | 91 | #include "jumpshot.h" |
92 | #endif | 92 | #endif |
93 | 93 | #ifdef CONFIG_USB_STORAGE_ONETOUCH | |
94 | #include "onetouch.h" | ||
95 | #endif | ||
94 | 96 | ||
95 | /* Some informational data */ | 97 | /* Some informational data */ |
96 | MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>"); | 98 | MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>"); |
@@ -786,6 +788,7 @@ static void usb_stor_release_resources(struct us_data *us) | |||
786 | * any more commands. | 788 | * any more commands. |
787 | */ | 789 | */ |
788 | US_DEBUGP("-- sending exit command to thread\n"); | 790 | US_DEBUGP("-- sending exit command to thread\n"); |
791 | set_bit(US_FLIDX_DISCONNECTING, &us->flags); | ||
789 | up(&us->sema); | 792 | up(&us->sema); |
790 | 793 | ||
791 | /* Call the destructor routine, if it exists */ | 794 | /* Call the destructor routine, if it exists */ |
@@ -816,6 +819,49 @@ static void dissociate_dev(struct us_data *us) | |||
816 | usb_set_intfdata(us->pusb_intf, NULL); | 819 | usb_set_intfdata(us->pusb_intf, NULL); |
817 | } | 820 | } |
818 | 821 | ||
822 | /* First stage of disconnect processing: stop all commands and remove | ||
823 | * the host */ | ||
824 | static void quiesce_and_remove_host(struct us_data *us) | ||
825 | { | ||
826 | /* Prevent new USB transfers, stop the current command, and | ||
827 | * interrupt a SCSI-scan or device-reset delay */ | ||
828 | set_bit(US_FLIDX_DISCONNECTING, &us->flags); | ||
829 | usb_stor_stop_transport(us); | ||
830 | wake_up(&us->delay_wait); | ||
831 | |||
832 | /* It doesn't matter if the SCSI-scanning thread is still running. | ||
833 | * The thread will exit when it sees the DISCONNECTING flag. */ | ||
834 | |||
835 | /* Wait for the current command to finish, then remove the host */ | ||
836 | down(&us->dev_semaphore); | ||
837 | up(&us->dev_semaphore); | ||
838 | |||
839 | /* queuecommand won't accept any new commands and the control | ||
840 | * thread won't execute a previously-queued command. If there | ||
841 | * is such a command pending, complete it with an error. */ | ||
842 | if (us->srb) { | ||
843 | us->srb->result = DID_NO_CONNECT << 16; | ||
844 | scsi_lock(us_to_host(us)); | ||
845 | us->srb->scsi_done(us->srb); | ||
846 | us->srb = NULL; | ||
847 | scsi_unlock(us_to_host(us)); | ||
848 | } | ||
849 | |||
850 | /* Now we own no commands so it's safe to remove the SCSI host */ | ||
851 | scsi_remove_host(us_to_host(us)); | ||
852 | } | ||
853 | |||
854 | /* Second stage of disconnect processing: deallocate all resources */ | ||
855 | static void release_everything(struct us_data *us) | ||
856 | { | ||
857 | usb_stor_release_resources(us); | ||
858 | dissociate_dev(us); | ||
859 | |||
860 | /* Drop our reference to the host; the SCSI core will free it | ||
861 | * (and "us" along with it) when the refcount becomes 0. */ | ||
862 | scsi_host_put(us_to_host(us)); | ||
863 | } | ||
864 | |||
819 | /* Thread to carry out delayed SCSI-device scanning */ | 865 | /* Thread to carry out delayed SCSI-device scanning */ |
820 | static int usb_stor_scan_thread(void * __us) | 866 | static int usb_stor_scan_thread(void * __us) |
821 | { | 867 | { |
@@ -956,7 +1002,7 @@ static int storage_probe(struct usb_interface *intf, | |||
956 | if (result < 0) { | 1002 | if (result < 0) { |
957 | printk(KERN_WARNING USB_STORAGE | 1003 | printk(KERN_WARNING USB_STORAGE |
958 | "Unable to start the device-scanning thread\n"); | 1004 | "Unable to start the device-scanning thread\n"); |
959 | scsi_remove_host(host); | 1005 | quiesce_and_remove_host(us); |
960 | goto BadDevice; | 1006 | goto BadDevice; |
961 | } | 1007 | } |
962 | atomic_inc(&total_threads); | 1008 | atomic_inc(&total_threads); |
@@ -969,10 +1015,7 @@ static int storage_probe(struct usb_interface *intf, | |||
969 | /* We come here if there are any problems */ | 1015 | /* We come here if there are any problems */ |
970 | BadDevice: | 1016 | BadDevice: |
971 | US_DEBUGP("storage_probe() failed\n"); | 1017 | US_DEBUGP("storage_probe() failed\n"); |
972 | set_bit(US_FLIDX_DISCONNECTING, &us->flags); | 1018 | release_everything(us); |
973 | usb_stor_release_resources(us); | ||
974 | dissociate_dev(us); | ||
975 | scsi_host_put(host); | ||
976 | return result; | 1019 | return result; |
977 | } | 1020 | } |
978 | 1021 | ||
@@ -982,28 +1025,8 @@ static void storage_disconnect(struct usb_interface *intf) | |||
982 | struct us_data *us = usb_get_intfdata(intf); | 1025 | struct us_data *us = usb_get_intfdata(intf); |
983 | 1026 | ||
984 | US_DEBUGP("storage_disconnect() called\n"); | 1027 | US_DEBUGP("storage_disconnect() called\n"); |
985 | 1028 | quiesce_and_remove_host(us); | |
986 | /* Prevent new USB transfers, stop the current command, and | 1029 | 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 | } | 1030 | } |
1008 | 1031 | ||
1009 | /*********************************************************************** | 1032 | /*********************************************************************** |