--- zzzz-none-000/linux-2.6.13.1/drivers/usb/storage/usb.c 2005-09-10 02:42:58.000000000 +0000 +++ ohio-7170-487/linux-2.6.13.1/drivers/usb/storage/usb.c 2007-12-17 12:52:04.000000000 +0000 @@ -390,11 +390,16 @@ /* If an abort request was received we need to signal that * the abort has finished. The proper test for this is * the TIMED_OUT flag, not srb->result == DID_ABORT, because - * a timeout/abort request might be received after all the - * USB processing was complete. */ - if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) + * the timeout might have occurred after the command had + * already completed with a different result code. */ + if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) { complete(&(us->notify)); + /* Allow USB transfers to resume */ + clear_bit(US_FLIDX_ABORTING, &us->flags); + clear_bit(US_FLIDX_TIMED_OUT, &us->flags); + } + /* finished working on this command */ us->srb = NULL; scsi_unlock(host); @@ -786,6 +791,7 @@ * any more commands. */ US_DEBUGP("-- sending exit command to thread\n"); + set_bit(US_FLIDX_DISCONNECTING, &us->flags); up(&us->sema); /* Call the destructor routine, if it exists */ @@ -816,6 +822,49 @@ usb_set_intfdata(us->pusb_intf, NULL); } +/* First stage of disconnect processing: stop all commands and remove + * the host */ +static void quiesce_and_remove_host(struct us_data *us) +{ + /* Prevent new USB transfers, stop the current command, and + * interrupt a SCSI-scan or device-reset delay */ + set_bit(US_FLIDX_DISCONNECTING, &us->flags); + usb_stor_stop_transport(us); + wake_up(&us->delay_wait); + + /* It doesn't matter if the SCSI-scanning thread is still running. + * The thread will exit when it sees the DISCONNECTING flag. */ + + /* Wait for the current command to finish, then remove the host */ + down(&us->dev_semaphore); + up(&us->dev_semaphore); + + /* queuecommand won't accept any new commands and the control + * thread won't execute a previously-queued command. If there + * is such a command pending, complete it with an error. */ + if (us->srb) { + us->srb->result = DID_NO_CONNECT << 16; + scsi_lock(us_to_host(us)); + us->srb->scsi_done(us->srb); + us->srb = NULL; + scsi_unlock(us_to_host(us)); + } + + /* Now we own no commands so it's safe to remove the SCSI host */ + scsi_remove_host(us_to_host(us)); +} + +/* Second stage of disconnect processing: deallocate all resources */ +static void release_everything(struct us_data *us) +{ + usb_stor_release_resources(us); + dissociate_dev(us); + + /* Drop our reference to the host; the SCSI core will free it + * (and "us" along with it) when the refcount becomes 0. */ + scsi_host_put(us_to_host(us)); +} + /* Thread to carry out delayed SCSI-device scanning */ static int usb_stor_scan_thread(void * __us) { @@ -870,11 +919,35 @@ { struct Scsi_Host *host; struct us_data *us; + struct usb_device *udev; const int id_index = id - storage_usb_ids; - int result; + int i, result; + unsigned short vendor, device; - US_DEBUGP("USB Mass Storage device detected\n"); + /* Filter out AVM mass storage devices... (copied from 2.4) =OS= 20060904 */ + static struct { unsigned short vendorId, deviceId; } black_list[] = { + { 0x057c, 0x62FF }, /* WLAN v 1.1 */ + { 0x057c, 0x84FF }, /* WLAN N */ + { 0x0000, 0x0000 } /* Terminating entry */ + } ; + + udev = interface_to_usbdev(intf); + vendor = (unsigned short) udev->descriptor.idVendor; + device = (unsigned short) udev->descriptor.idProduct; + for (i = 0; black_list[i].vendorId != 0; i++) { + if ( (black_list[i].vendorId == vendor) + && (black_list[i].deviceId == device) + ) { + printk ( + KERN_INFO "USB Mass Storage device (%04x:%04x) ignored!\n", + vendor, device + ); + return -ENODEV; + } + } + printk (KERN_INFO "USB Mass Storage device (%04x:%04x) detected...\n", vendor, device); + /* * Ask the SCSI layer to allocate a host structure, with extra * space at the end for our private us_data structure. @@ -956,7 +1029,7 @@ if (result < 0) { printk(KERN_WARNING USB_STORAGE "Unable to start the device-scanning thread\n"); - scsi_remove_host(host); + quiesce_and_remove_host(us); goto BadDevice; } atomic_inc(&total_threads); @@ -969,10 +1042,7 @@ /* We come here if there are any problems */ BadDevice: US_DEBUGP("storage_probe() failed\n"); - set_bit(US_FLIDX_DISCONNECTING, &us->flags); - usb_stor_release_resources(us); - dissociate_dev(us); - scsi_host_put(host); + release_everything(us); return result; } @@ -982,28 +1052,8 @@ struct us_data *us = usb_get_intfdata(intf); US_DEBUGP("storage_disconnect() called\n"); - - /* Prevent new USB transfers, stop the current command, and - * interrupt a SCSI-scan or device-reset delay */ - set_bit(US_FLIDX_DISCONNECTING, &us->flags); - usb_stor_stop_transport(us); - wake_up(&us->delay_wait); - - /* It doesn't matter if the SCSI-scanning thread is still running. - * The thread will exit when it sees the DISCONNECTING flag. */ - - /* Wait for the current command to finish, then remove the host */ - down(&us->dev_semaphore); - up(&us->dev_semaphore); - scsi_remove_host(us_to_host(us)); - - /* Wait for everything to become idle and release all our resources */ - usb_stor_release_resources(us); - dissociate_dev(us); - - /* Drop our reference to the host; the SCSI core will free it - * (and "us" along with it) when the refcount becomes 0. */ - scsi_host_put(us_to_host(us)); + quiesce_and_remove_host(us); + release_everything(us); } /***********************************************************************