diff options
| -rw-r--r-- | drivers/usb/storage/usb.c | 22 |
1 files changed, 14 insertions, 8 deletions
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 1185acac4b21..04c3bec81201 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c | |||
| @@ -373,8 +373,12 @@ static int usb_stor_control_thread(void * __us) | |||
| 373 | /* lock access to the state */ | 373 | /* lock access to the state */ |
| 374 | scsi_lock(host); | 374 | scsi_lock(host); |
| 375 | 375 | ||
| 376 | /* did the command already complete because of a disconnect? */ | ||
| 377 | if (!us->srb) | ||
| 378 | ; /* nothing to do */ | ||
| 379 | |||
| 376 | /* indicate that the command is done */ | 380 | /* indicate that the command is done */ |
| 377 | if (us->srb->result != DID_ABORT << 16) { | 381 | else if (us->srb->result != DID_ABORT << 16) { |
| 378 | US_DEBUGP("scsi cmd done, result=0x%x\n", | 382 | US_DEBUGP("scsi cmd done, result=0x%x\n", |
| 379 | us->srb->result); | 383 | us->srb->result); |
| 380 | us->srb->scsi_done(us->srb); | 384 | us->srb->scsi_done(us->srb); |
| @@ -836,32 +840,34 @@ static void dissociate_dev(struct us_data *us) | |||
| 836 | * the host */ | 840 | * the host */ |
| 837 | static void quiesce_and_remove_host(struct us_data *us) | 841 | static void quiesce_and_remove_host(struct us_data *us) |
| 838 | { | 842 | { |
| 843 | struct Scsi_Host *host = us_to_host(us); | ||
| 844 | |||
| 839 | /* Prevent new USB transfers, stop the current command, and | 845 | /* Prevent new USB transfers, stop the current command, and |
| 840 | * interrupt a SCSI-scan or device-reset delay */ | 846 | * interrupt a SCSI-scan or device-reset delay */ |
| 847 | scsi_lock(host); | ||
| 841 | set_bit(US_FLIDX_DISCONNECTING, &us->flags); | 848 | set_bit(US_FLIDX_DISCONNECTING, &us->flags); |
| 849 | scsi_unlock(host); | ||
| 842 | usb_stor_stop_transport(us); | 850 | usb_stor_stop_transport(us); |
| 843 | wake_up(&us->delay_wait); | 851 | wake_up(&us->delay_wait); |
| 844 | 852 | ||
| 845 | /* It doesn't matter if the SCSI-scanning thread is still running. | 853 | /* It doesn't matter if the SCSI-scanning thread is still running. |
| 846 | * The thread will exit when it sees the DISCONNECTING flag. */ | 854 | * The thread will exit when it sees the DISCONNECTING flag. */ |
| 847 | 855 | ||
| 848 | /* Wait for the current command to finish, then remove the host */ | ||
| 849 | mutex_lock(&us->dev_mutex); | ||
| 850 | mutex_unlock(&us->dev_mutex); | ||
| 851 | |||
| 852 | /* queuecommand won't accept any new commands and the control | 856 | /* queuecommand won't accept any new commands and the control |
| 853 | * thread won't execute a previously-queued command. If there | 857 | * thread won't execute a previously-queued command. If there |
| 854 | * is such a command pending, complete it with an error. */ | 858 | * is such a command pending, complete it with an error. */ |
| 859 | mutex_lock(&us->dev_mutex); | ||
| 855 | if (us->srb) { | 860 | if (us->srb) { |
| 856 | us->srb->result = DID_NO_CONNECT << 16; | 861 | us->srb->result = DID_NO_CONNECT << 16; |
| 857 | scsi_lock(us_to_host(us)); | 862 | scsi_lock(host); |
| 858 | us->srb->scsi_done(us->srb); | 863 | us->srb->scsi_done(us->srb); |
| 859 | us->srb = NULL; | 864 | us->srb = NULL; |
| 860 | scsi_unlock(us_to_host(us)); | 865 | scsi_unlock(host); |
| 861 | } | 866 | } |
| 867 | mutex_unlock(&us->dev_mutex); | ||
| 862 | 868 | ||
| 863 | /* Now we own no commands so it's safe to remove the SCSI host */ | 869 | /* Now we own no commands so it's safe to remove the SCSI host */ |
| 864 | scsi_remove_host(us_to_host(us)); | 870 | scsi_remove_host(host); |
| 865 | } | 871 | } |
| 866 | 872 | ||
| 867 | /* Second stage of disconnect processing: deallocate all resources */ | 873 | /* Second stage of disconnect processing: deallocate all resources */ |
