diff options
Diffstat (limited to 'drivers/usb/storage/usb.c')
-rw-r--r-- | drivers/usb/storage/usb.c | 29 |
1 files changed, 19 insertions, 10 deletions
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 1185acac4b21..5ee19be52f65 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c | |||
@@ -55,6 +55,7 @@ | |||
55 | #include <linux/slab.h> | 55 | #include <linux/slab.h> |
56 | #include <linux/kthread.h> | 56 | #include <linux/kthread.h> |
57 | #include <linux/mutex.h> | 57 | #include <linux/mutex.h> |
58 | #include <linux/utsrelease.h> | ||
58 | 59 | ||
59 | #include <scsi/scsi.h> | 60 | #include <scsi/scsi.h> |
60 | #include <scsi/scsi_cmnd.h> | 61 | #include <scsi/scsi_cmnd.h> |
@@ -373,8 +374,12 @@ static int usb_stor_control_thread(void * __us) | |||
373 | /* lock access to the state */ | 374 | /* lock access to the state */ |
374 | scsi_lock(host); | 375 | scsi_lock(host); |
375 | 376 | ||
377 | /* did the command already complete because of a disconnect? */ | ||
378 | if (!us->srb) | ||
379 | ; /* nothing to do */ | ||
380 | |||
376 | /* indicate that the command is done */ | 381 | /* indicate that the command is done */ |
377 | if (us->srb->result != DID_ABORT << 16) { | 382 | else if (us->srb->result != DID_ABORT << 16) { |
378 | US_DEBUGP("scsi cmd done, result=0x%x\n", | 383 | US_DEBUGP("scsi cmd done, result=0x%x\n", |
379 | us->srb->result); | 384 | us->srb->result); |
380 | us->srb->scsi_done(us->srb); | 385 | us->srb->scsi_done(us->srb); |
@@ -524,7 +529,8 @@ static void get_device_info(struct us_data *us, const struct usb_device_id *id) | |||
524 | if (msg >= 0 && !(us->flags & US_FL_NEED_OVERRIDE)) | 529 | if (msg >= 0 && !(us->flags & US_FL_NEED_OVERRIDE)) |
525 | printk(KERN_NOTICE USB_STORAGE "This device " | 530 | printk(KERN_NOTICE USB_STORAGE "This device " |
526 | "(%04x,%04x,%04x S %02x P %02x)" | 531 | "(%04x,%04x,%04x S %02x P %02x)" |
527 | " has %s in unusual_devs.h\n" | 532 | " has %s in unusual_devs.h (kernel" |
533 | " %s)\n" | ||
528 | " Please send a copy of this message to " | 534 | " Please send a copy of this message to " |
529 | "<linux-usb-devel@lists.sourceforge.net>\n", | 535 | "<linux-usb-devel@lists.sourceforge.net>\n", |
530 | le16_to_cpu(ddesc->idVendor), | 536 | le16_to_cpu(ddesc->idVendor), |
@@ -532,7 +538,8 @@ static void get_device_info(struct us_data *us, const struct usb_device_id *id) | |||
532 | le16_to_cpu(ddesc->bcdDevice), | 538 | le16_to_cpu(ddesc->bcdDevice), |
533 | idesc->bInterfaceSubClass, | 539 | idesc->bInterfaceSubClass, |
534 | idesc->bInterfaceProtocol, | 540 | idesc->bInterfaceProtocol, |
535 | msgs[msg]); | 541 | msgs[msg], |
542 | UTS_RELEASE); | ||
536 | } | 543 | } |
537 | } | 544 | } |
538 | 545 | ||
@@ -836,32 +843,34 @@ static void dissociate_dev(struct us_data *us) | |||
836 | * the host */ | 843 | * the host */ |
837 | static void quiesce_and_remove_host(struct us_data *us) | 844 | static void quiesce_and_remove_host(struct us_data *us) |
838 | { | 845 | { |
846 | struct Scsi_Host *host = us_to_host(us); | ||
847 | |||
839 | /* Prevent new USB transfers, stop the current command, and | 848 | /* Prevent new USB transfers, stop the current command, and |
840 | * interrupt a SCSI-scan or device-reset delay */ | 849 | * interrupt a SCSI-scan or device-reset delay */ |
850 | scsi_lock(host); | ||
841 | set_bit(US_FLIDX_DISCONNECTING, &us->flags); | 851 | set_bit(US_FLIDX_DISCONNECTING, &us->flags); |
852 | scsi_unlock(host); | ||
842 | usb_stor_stop_transport(us); | 853 | usb_stor_stop_transport(us); |
843 | wake_up(&us->delay_wait); | 854 | wake_up(&us->delay_wait); |
844 | 855 | ||
845 | /* It doesn't matter if the SCSI-scanning thread is still running. | 856 | /* It doesn't matter if the SCSI-scanning thread is still running. |
846 | * The thread will exit when it sees the DISCONNECTING flag. */ | 857 | * The thread will exit when it sees the DISCONNECTING flag. */ |
847 | 858 | ||
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 | 859 | /* queuecommand won't accept any new commands and the control |
853 | * thread won't execute a previously-queued command. If there | 860 | * thread won't execute a previously-queued command. If there |
854 | * is such a command pending, complete it with an error. */ | 861 | * is such a command pending, complete it with an error. */ |
862 | mutex_lock(&us->dev_mutex); | ||
855 | if (us->srb) { | 863 | if (us->srb) { |
856 | us->srb->result = DID_NO_CONNECT << 16; | 864 | us->srb->result = DID_NO_CONNECT << 16; |
857 | scsi_lock(us_to_host(us)); | 865 | scsi_lock(host); |
858 | us->srb->scsi_done(us->srb); | 866 | us->srb->scsi_done(us->srb); |
859 | us->srb = NULL; | 867 | us->srb = NULL; |
860 | scsi_unlock(us_to_host(us)); | 868 | scsi_unlock(host); |
861 | } | 869 | } |
870 | mutex_unlock(&us->dev_mutex); | ||
862 | 871 | ||
863 | /* Now we own no commands so it's safe to remove the SCSI host */ | 872 | /* Now we own no commands so it's safe to remove the SCSI host */ |
864 | scsi_remove_host(us_to_host(us)); | 873 | scsi_remove_host(host); |
865 | } | 874 | } |
866 | 875 | ||
867 | /* Second stage of disconnect processing: deallocate all resources */ | 876 | /* Second stage of disconnect processing: deallocate all resources */ |