diff options
Diffstat (limited to 'drivers/usb/storage/usb.c')
-rw-r--r-- | drivers/usb/storage/usb.c | 42 |
1 files changed, 30 insertions, 12 deletions
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 1185acac4b21..8d7bdcb5924d 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); |
@@ -478,7 +483,7 @@ static struct us_unusual_dev *find_unusual(const struct usb_device_id *id) | |||
478 | } | 483 | } |
479 | 484 | ||
480 | /* Get the unusual_devs entries and the string descriptors */ | 485 | /* Get the unusual_devs entries and the string descriptors */ |
481 | static void get_device_info(struct us_data *us, const struct usb_device_id *id) | 486 | static int get_device_info(struct us_data *us, const struct usb_device_id *id) |
482 | { | 487 | { |
483 | struct usb_device *dev = us->pusb_dev; | 488 | struct usb_device *dev = us->pusb_dev; |
484 | struct usb_interface_descriptor *idesc = | 489 | struct usb_interface_descriptor *idesc = |
@@ -495,6 +500,11 @@ static void get_device_info(struct us_data *us, const struct usb_device_id *id) | |||
495 | unusual_dev->useTransport; | 500 | unusual_dev->useTransport; |
496 | us->flags = USB_US_ORIG_FLAGS(id->driver_info); | 501 | us->flags = USB_US_ORIG_FLAGS(id->driver_info); |
497 | 502 | ||
503 | if (us->flags & US_FL_IGNORE_DEVICE) { | ||
504 | printk(KERN_INFO USB_STORAGE "device ignored\n"); | ||
505 | return -ENODEV; | ||
506 | } | ||
507 | |||
498 | /* | 508 | /* |
499 | * This flag is only needed when we're in high-speed, so let's | 509 | * This flag is only needed when we're in high-speed, so let's |
500 | * disable it if we're in full-speed | 510 | * disable it if we're in full-speed |
@@ -524,7 +534,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)) | 534 | if (msg >= 0 && !(us->flags & US_FL_NEED_OVERRIDE)) |
525 | printk(KERN_NOTICE USB_STORAGE "This device " | 535 | printk(KERN_NOTICE USB_STORAGE "This device " |
526 | "(%04x,%04x,%04x S %02x P %02x)" | 536 | "(%04x,%04x,%04x S %02x P %02x)" |
527 | " has %s in unusual_devs.h\n" | 537 | " has %s in unusual_devs.h (kernel" |
538 | " %s)\n" | ||
528 | " Please send a copy of this message to " | 539 | " Please send a copy of this message to " |
529 | "<linux-usb-devel@lists.sourceforge.net>\n", | 540 | "<linux-usb-devel@lists.sourceforge.net>\n", |
530 | le16_to_cpu(ddesc->idVendor), | 541 | le16_to_cpu(ddesc->idVendor), |
@@ -532,8 +543,11 @@ static void get_device_info(struct us_data *us, const struct usb_device_id *id) | |||
532 | le16_to_cpu(ddesc->bcdDevice), | 543 | le16_to_cpu(ddesc->bcdDevice), |
533 | idesc->bInterfaceSubClass, | 544 | idesc->bInterfaceSubClass, |
534 | idesc->bInterfaceProtocol, | 545 | idesc->bInterfaceProtocol, |
535 | msgs[msg]); | 546 | msgs[msg], |
547 | UTS_RELEASE); | ||
536 | } | 548 | } |
549 | |||
550 | return 0; | ||
537 | } | 551 | } |
538 | 552 | ||
539 | /* Get the transport settings */ | 553 | /* Get the transport settings */ |
@@ -836,32 +850,34 @@ static void dissociate_dev(struct us_data *us) | |||
836 | * the host */ | 850 | * the host */ |
837 | static void quiesce_and_remove_host(struct us_data *us) | 851 | static void quiesce_and_remove_host(struct us_data *us) |
838 | { | 852 | { |
853 | struct Scsi_Host *host = us_to_host(us); | ||
854 | |||
839 | /* Prevent new USB transfers, stop the current command, and | 855 | /* Prevent new USB transfers, stop the current command, and |
840 | * interrupt a SCSI-scan or device-reset delay */ | 856 | * interrupt a SCSI-scan or device-reset delay */ |
857 | scsi_lock(host); | ||
841 | set_bit(US_FLIDX_DISCONNECTING, &us->flags); | 858 | set_bit(US_FLIDX_DISCONNECTING, &us->flags); |
859 | scsi_unlock(host); | ||
842 | usb_stor_stop_transport(us); | 860 | usb_stor_stop_transport(us); |
843 | wake_up(&us->delay_wait); | 861 | wake_up(&us->delay_wait); |
844 | 862 | ||
845 | /* It doesn't matter if the SCSI-scanning thread is still running. | 863 | /* It doesn't matter if the SCSI-scanning thread is still running. |
846 | * The thread will exit when it sees the DISCONNECTING flag. */ | 864 | * The thread will exit when it sees the DISCONNECTING flag. */ |
847 | 865 | ||
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 | 866 | /* queuecommand won't accept any new commands and the control |
853 | * thread won't execute a previously-queued command. If there | 867 | * thread won't execute a previously-queued command. If there |
854 | * is such a command pending, complete it with an error. */ | 868 | * is such a command pending, complete it with an error. */ |
869 | mutex_lock(&us->dev_mutex); | ||
855 | if (us->srb) { | 870 | if (us->srb) { |
856 | us->srb->result = DID_NO_CONNECT << 16; | 871 | us->srb->result = DID_NO_CONNECT << 16; |
857 | scsi_lock(us_to_host(us)); | 872 | scsi_lock(host); |
858 | us->srb->scsi_done(us->srb); | 873 | us->srb->scsi_done(us->srb); |
859 | us->srb = NULL; | 874 | us->srb = NULL; |
860 | scsi_unlock(us_to_host(us)); | 875 | scsi_unlock(host); |
861 | } | 876 | } |
877 | mutex_unlock(&us->dev_mutex); | ||
862 | 878 | ||
863 | /* Now we own no commands so it's safe to remove the SCSI host */ | 879 | /* Now we own no commands so it's safe to remove the SCSI host */ |
864 | scsi_remove_host(us_to_host(us)); | 880 | scsi_remove_host(host); |
865 | } | 881 | } |
866 | 882 | ||
867 | /* Second stage of disconnect processing: deallocate all resources */ | 883 | /* Second stage of disconnect processing: deallocate all resources */ |
@@ -960,7 +976,9 @@ static int storage_probe(struct usb_interface *intf, | |||
960 | * of the match from the usb_device_id table, so we can find the | 976 | * of the match from the usb_device_id table, so we can find the |
961 | * corresponding entry in the private table. | 977 | * corresponding entry in the private table. |
962 | */ | 978 | */ |
963 | get_device_info(us, id); | 979 | result = get_device_info(us, id); |
980 | if (result) | ||
981 | goto BadDevice; | ||
964 | 982 | ||
965 | /* Get the transport, protocol, and pipe settings */ | 983 | /* Get the transport, protocol, and pipe settings */ |
966 | result = get_transport(us); | 984 | result = get_transport(us); |