Commit 47104b0d authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

[PATCH] usb-storage: use usb_reset_composite_device

This patch (as701) modifies usb-storage to take advantage of the new
usb_reset_composite_device() API.  Now we will be able to safely request
port resets even if other drivers are bound to a mass-storage device.
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 7de18d8b
...@@ -286,11 +286,7 @@ static int bus_reset(struct scsi_cmnd *srb) ...@@ -286,11 +286,7 @@ static int bus_reset(struct scsi_cmnd *srb)
int result; int result;
US_DEBUGP("%s called\n", __FUNCTION__); US_DEBUGP("%s called\n", __FUNCTION__);
mutex_lock(&(us->dev_mutex));
result = usb_stor_port_reset(us); result = usb_stor_port_reset(us);
mutex_unlock(&us->dev_mutex);
return result < 0 ? FAILED : SUCCESS; return result < 0 ? FAILED : SUCCESS;
} }
......
...@@ -703,16 +703,19 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) ...@@ -703,16 +703,19 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
* device reset. */ * device reset. */
Handle_Errors: Handle_Errors:
/* Let the SCSI layer know we are doing a reset, set the /* Set the RESETTING bit, and clear the ABORTING bit so that
* RESETTING bit, and clear the ABORTING bit so that the reset * the reset may proceed. */
* may proceed. */
scsi_lock(us_to_host(us)); scsi_lock(us_to_host(us));
usb_stor_report_bus_reset(us);
set_bit(US_FLIDX_RESETTING, &us->flags); set_bit(US_FLIDX_RESETTING, &us->flags);
clear_bit(US_FLIDX_ABORTING, &us->flags); clear_bit(US_FLIDX_ABORTING, &us->flags);
scsi_unlock(us_to_host(us)); scsi_unlock(us_to_host(us));
/* We must release the device lock because the pre_reset routine
* will want to acquire it. */
mutex_unlock(&us->dev_mutex);
result = usb_stor_port_reset(us); result = usb_stor_port_reset(us);
mutex_lock(&us->dev_mutex);
if (result < 0) { if (result < 0) {
scsi_lock(us_to_host(us)); scsi_lock(us_to_host(us));
usb_stor_report_device_reset(us); usb_stor_report_device_reset(us);
...@@ -1196,31 +1199,30 @@ int usb_stor_Bulk_reset(struct us_data *us) ...@@ -1196,31 +1199,30 @@ int usb_stor_Bulk_reset(struct us_data *us)
0, us->ifnum, NULL, 0); 0, us->ifnum, NULL, 0);
} }
/* Issue a USB port reset to the device. But don't do anything if /* Issue a USB port reset to the device. The caller must not hold
* there's more than one interface in the device, so that other users * us->dev_mutex.
* are not affected. */ */
int usb_stor_port_reset(struct us_data *us) int usb_stor_port_reset(struct us_data *us)
{ {
int result, rc; int result, rc_lock;
result = rc_lock =
usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
if (result < 0)
US_DEBUGP("unable to lock device for reset: %d\n", result);
else {
/* Were we disconnected while waiting for the lock? */
if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
result = -EIO; result = -EIO;
US_DEBUGP("No reset during disconnect\n"); US_DEBUGP("No reset during disconnect\n");
} else if (us->pusb_dev->actconfig->desc.bNumInterfaces != 1) {
result = -EBUSY;
US_DEBUGP("Refusing to reset a multi-interface device\n");
} else { } else {
result = rc = result = usb_reset_composite_device(
usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf); us->pusb_dev, us->pusb_intf);
if (result < 0) { US_DEBUGP("usb_reset_composite_device returns %d\n",
US_DEBUGP("unable to lock device for reset: %d\n",
result); result);
} else {
result = usb_reset_device(us->pusb_dev);
if (rc)
usb_unlock_device(us->pusb_dev);
US_DEBUGP("usb_reset_device returns %d\n", result);
} }
if (rc_lock)
usb_unlock_device(us->pusb_dev);
} }
return result; return result;
} }
...@@ -220,6 +220,37 @@ static int storage_resume(struct usb_interface *iface) ...@@ -220,6 +220,37 @@ static int storage_resume(struct usb_interface *iface)
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
/*
* The next two routines get called just before and just after
* a USB port reset, whether from this driver or a different one.
*/
static void storage_pre_reset(struct usb_interface *iface)
{
struct us_data *us = usb_get_intfdata(iface);
US_DEBUGP("%s\n", __FUNCTION__);
/* Make sure no command runs during the reset */
mutex_lock(&us->dev_mutex);
}
static void storage_post_reset(struct usb_interface *iface)
{
struct us_data *us = usb_get_intfdata(iface);
US_DEBUGP("%s\n", __FUNCTION__);
/* Report the reset to the SCSI core */
scsi_lock(us_to_host(us));
usb_stor_report_bus_reset(us);
scsi_unlock(us_to_host(us));
/* FIXME: Notify the subdrivers that they need to reinitialize
* the device */
mutex_unlock(&us->dev_mutex);
}
/* /*
* fill_inquiry_response takes an unsigned char array (which must * fill_inquiry_response takes an unsigned char array (which must
* be at least 36 characters) and populates the vendor name, * be at least 36 characters) and populates the vendor name,
...@@ -1002,6 +1033,8 @@ static struct usb_driver usb_storage_driver = { ...@@ -1002,6 +1033,8 @@ static struct usb_driver usb_storage_driver = {
.suspend = storage_suspend, .suspend = storage_suspend,
.resume = storage_resume, .resume = storage_resume,
#endif #endif
.pre_reset = storage_pre_reset,
.post_reset = storage_post_reset,
.id_table = storage_usb_ids, .id_table = storage_usb_ids,
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment