MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");
-/* These are used to make sure the module doesn't unload before all the
- * threads have exited.
- */
-static atomic_t total_threads = ATOMIC_INIT(0);
-static DECLARE_COMPLETION(threads_gone);
-
-
/*
* The entries in this table correspond, line for line,
* with the entries of us_unusual_dev_list[].
{
struct us_data *us = usb_get_intfdata(iface);
- US_DEBUGP("%s\n", __FUNCTION__);
-
/* Wait until no command is running */
mutex_lock(&us->dev_mutex);
+ US_DEBUGP("%s\n", __FUNCTION__);
if (us->suspend_resume_hook)
(us->suspend_resume_hook)(us, US_SUSPEND);
+ /* When runtime PM is working, we'll set a flag to indicate
+ * whether we should autoresume when a SCSI request arrives. */
+
mutex_unlock(&us->dev_mutex);
return 0;
}
{
struct us_data *us = usb_get_intfdata(iface);
- US_DEBUGP("%s\n", __FUNCTION__);
+ mutex_lock(&us->dev_mutex);
+ US_DEBUGP("%s\n", __FUNCTION__);
if (us->suspend_resume_hook)
(us->suspend_resume_hook)(us, US_RESUME);
+ mutex_unlock(&us->dev_mutex);
return 0;
}
{
struct us_data *us = (struct us_data *)__us;
struct Scsi_Host *host = us_to_host(us);
- int autopm_rc;
for(;;) {
US_DEBUGP("*** thread sleeping.\n");
US_DEBUGP("*** thread awakened.\n");
- /* Autoresume the device */
- autopm_rc = usb_autopm_get_interface(us->pusb_intf);
-
/* lock the device pointers */
mutex_lock(&(us->dev_mutex));
us->srb->result = SAM_STAT_GOOD;
}
- /* Did the autoresume fail? */
- else if (autopm_rc < 0) {
- US_DEBUGP("Could not wake device\n");
- us->srb->result = DID_ERROR << 16;
- }
-
/* we've got a command, let's do it! */
else {
US_DEBUG(usb_stor_show_command(us->srb));
/* unlock the device pointers */
mutex_unlock(&us->dev_mutex);
-
- /* Start an autosuspend */
- if (autopm_rc == 0)
- usb_autopm_put_interface(us->pusb_intf);
} /* for (;;) */
/* Wait until we are told to stop */
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. */
-
/* 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. */
scsi_lock(host);
us->srb->scsi_done(us->srb);
us->srb = NULL;
+ complete(&us->notify); /* in case of an abort */
scsi_unlock(host);
}
mutex_unlock(&us->dev_mutex);
/* Now we own no commands so it's safe to remove the SCSI host */
scsi_remove_host(host);
+
+ /* Wait for the SCSI-scanning thread to stop */
+ wait_for_completion(&us->scanning_done);
}
/* Second stage of disconnect processing: deallocate all resources */
if (delay_use > 0) {
printk(KERN_DEBUG "usb-storage: waiting for device "
"to settle before scanning\n");
-retry:
- wait_event_interruptible_timeout(us->delay_wait,
+ wait_event_freezable_timeout(us->delay_wait,
test_bit(US_FLIDX_DISCONNECTING, &us->flags),
delay_use * HZ);
- if (try_to_freeze())
- goto retry;
}
/* If the device is still connected, perform the scanning */
/* Should we unbind if no devices were detected? */
}
- scsi_host_put(us_to_host(us));
- usb_autopm_put_interface(us->pusb_intf);
- complete_and_exit(&threads_gone, 0);
+ complete_and_exit(&us->scanning_done, 0);
}
return -ENOMEM;
}
+ /*
+ * Allow 16-byte CDBs and thus > 2TB
+ */
+ host->max_cmd_len = 16;
us = host_to_us(host);
memset(us, 0, sizeof(struct us_data));
mutex_init(&(us->dev_mutex));
init_MUTEX_LOCKED(&(us->sema));
init_completion(&(us->notify));
init_waitqueue_head(&us->delay_wait);
+ init_completion(&us->scanning_done);
/* Associate the us_data structure with the USB device */
result = associate_dev(us, intf);
goto BadDevice;
}
- /* Take a reference to the host for the scanning thread and
- * count it among all the threads we have launched. Then
- * start it up. */
- scsi_host_get(us_to_host(us));
- atomic_inc(&total_threads);
- usb_autopm_get_interface(intf); /* dropped in the scanning thread */
wake_up_process(th);
return 0;
.pre_reset = storage_pre_reset,
.post_reset = storage_post_reset,
.id_table = storage_usb_ids,
- .supports_autosuspend = 1,
};
static int __init usb_stor_init(void)
US_DEBUGP("-- calling usb_deregister()\n");
usb_deregister(&usb_storage_driver) ;
- /* Don't return until all of our control and scanning threads
- * have exited. Since each thread signals threads_gone as its
- * last act, we have to call wait_for_completion the right number
- * of times.
- */
- while (atomic_read(&total_threads) > 0) {
- wait_for_completion(&threads_gone);
- atomic_dec(&total_threads);
- }
-
usb_usual_clear_present(USB_US_TYPE_STOR);
}