aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/storage/scsiglue.c4
-rw-r--r--drivers/usb/storage/transport.c50
-rw-r--r--drivers/usb/storage/usb.c33
3 files changed, 59 insertions, 28 deletions
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 5f11e19eaae3..5715291ba540 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -286,11 +286,7 @@ static int bus_reset(struct scsi_cmnd *srb)
286 int result; 286 int result;
287 287
288 US_DEBUGP("%s called\n", __FUNCTION__); 288 US_DEBUGP("%s called\n", __FUNCTION__);
289
290 mutex_lock(&(us->dev_mutex));
291 result = usb_stor_port_reset(us); 289 result = usb_stor_port_reset(us);
292 mutex_unlock(&us->dev_mutex);
293
294 return result < 0 ? FAILED : SUCCESS; 290 return result < 0 ? FAILED : SUCCESS;
295} 291}
296 292
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 038f4582ca0b..19b25c5cafd4 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -703,16 +703,19 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
703 * device reset. */ 703 * device reset. */
704 Handle_Errors: 704 Handle_Errors:
705 705
706 /* Let the SCSI layer know we are doing a reset, set the 706 /* Set the RESETTING bit, and clear the ABORTING bit so that
707 * RESETTING bit, and clear the ABORTING bit so that the reset 707 * the reset may proceed. */
708 * may proceed. */
709 scsi_lock(us_to_host(us)); 708 scsi_lock(us_to_host(us));
710 usb_stor_report_bus_reset(us);
711 set_bit(US_FLIDX_RESETTING, &us->flags); 709 set_bit(US_FLIDX_RESETTING, &us->flags);
712 clear_bit(US_FLIDX_ABORTING, &us->flags); 710 clear_bit(US_FLIDX_ABORTING, &us->flags);
713 scsi_unlock(us_to_host(us)); 711 scsi_unlock(us_to_host(us));
714 712
713 /* We must release the device lock because the pre_reset routine
714 * will want to acquire it. */
715 mutex_unlock(&us->dev_mutex);
715 result = usb_stor_port_reset(us); 716 result = usb_stor_port_reset(us);
717 mutex_lock(&us->dev_mutex);
718
716 if (result < 0) { 719 if (result < 0) {
717 scsi_lock(us_to_host(us)); 720 scsi_lock(us_to_host(us));
718 usb_stor_report_device_reset(us); 721 usb_stor_report_device_reset(us);
@@ -1196,31 +1199,30 @@ int usb_stor_Bulk_reset(struct us_data *us)
1196 0, us->ifnum, NULL, 0); 1199 0, us->ifnum, NULL, 0);
1197} 1200}
1198 1201
1199/* Issue a USB port reset to the device. But don't do anything if 1202/* Issue a USB port reset to the device. The caller must not hold
1200 * there's more than one interface in the device, so that other users 1203 * us->dev_mutex.
1201 * are not affected. */ 1204 */
1202int usb_stor_port_reset(struct us_data *us) 1205int usb_stor_port_reset(struct us_data *us)
1203{ 1206{
1204 int result, rc; 1207 int result, rc_lock;
1205 1208
1206 if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { 1209 result = rc_lock =
1207 result = -EIO; 1210 usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
1208 US_DEBUGP("No reset during disconnect\n"); 1211 if (result < 0)
1209 } else if (us->pusb_dev->actconfig->desc.bNumInterfaces != 1) { 1212 US_DEBUGP("unable to lock device for reset: %d\n", result);
1210 result = -EBUSY; 1213 else {
1211 US_DEBUGP("Refusing to reset a multi-interface device\n"); 1214 /* Were we disconnected while waiting for the lock? */
1212 } else { 1215 if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
1213 result = rc = 1216 result = -EIO;
1214 usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf); 1217 US_DEBUGP("No reset during disconnect\n");
1215 if (result < 0) {
1216 US_DEBUGP("unable to lock device for reset: %d\n",
1217 result);
1218 } else { 1218 } else {
1219 result = usb_reset_device(us->pusb_dev); 1219 result = usb_reset_composite_device(
1220 if (rc) 1220 us->pusb_dev, us->pusb_intf);
1221 usb_unlock_device(us->pusb_dev); 1221 US_DEBUGP("usb_reset_composite_device returns %d\n",
1222 US_DEBUGP("usb_reset_device returns %d\n", result); 1222 result);
1223 } 1223 }
1224 if (rc_lock)
1225 usb_unlock_device(us->pusb_dev);
1224 } 1226 }
1225 return result; 1227 return result;
1226} 1228}
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 0142fe82f6b8..e232c7c89909 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -221,6 +221,37 @@ static int storage_resume(struct usb_interface *iface)
221#endif /* CONFIG_PM */ 221#endif /* CONFIG_PM */
222 222
223/* 223/*
224 * The next two routines get called just before and just after
225 * a USB port reset, whether from this driver or a different one.
226 */
227
228static void storage_pre_reset(struct usb_interface *iface)
229{
230 struct us_data *us = usb_get_intfdata(iface);
231
232 US_DEBUGP("%s\n", __FUNCTION__);
233
234 /* Make sure no command runs during the reset */
235 mutex_lock(&us->dev_mutex);
236}
237
238static void storage_post_reset(struct usb_interface *iface)
239{
240 struct us_data *us = usb_get_intfdata(iface);
241
242 US_DEBUGP("%s\n", __FUNCTION__);
243
244 /* Report the reset to the SCSI core */
245 scsi_lock(us_to_host(us));
246 usb_stor_report_bus_reset(us);
247 scsi_unlock(us_to_host(us));
248
249 /* FIXME: Notify the subdrivers that they need to reinitialize
250 * the device */
251 mutex_unlock(&us->dev_mutex);
252}
253
254/*
224 * fill_inquiry_response takes an unsigned char array (which must 255 * fill_inquiry_response takes an unsigned char array (which must
225 * be at least 36 characters) and populates the vendor name, 256 * be at least 36 characters) and populates the vendor name,
226 * product name, and revision fields. Then the array is copied 257 * product name, and revision fields. Then the array is copied
@@ -1002,6 +1033,8 @@ static struct usb_driver usb_storage_driver = {
1002 .suspend = storage_suspend, 1033 .suspend = storage_suspend,
1003 .resume = storage_resume, 1034 .resume = storage_resume,
1004#endif 1035#endif
1036 .pre_reset = storage_pre_reset,
1037 .post_reset = storage_post_reset,
1005 .id_table = storage_usb_ids, 1038 .id_table = storage_usb_ids,
1006}; 1039};
1007 1040