diff options
-rw-r--r-- | drivers/usb/storage/scsiglue.c | 20 | ||||
-rw-r--r-- | drivers/usb/storage/usb.c | 11 |
2 files changed, 17 insertions, 14 deletions
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index d34dc9f417f0..4837524eada7 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c | |||
@@ -227,42 +227,42 @@ static int queuecommand(struct scsi_cmnd *srb, | |||
227 | ***********************************************************************/ | 227 | ***********************************************************************/ |
228 | 228 | ||
229 | /* Command timeout and abort */ | 229 | /* Command timeout and abort */ |
230 | /* This is always called with scsi_lock(host) held */ | ||
231 | static int command_abort(struct scsi_cmnd *srb) | 230 | static int command_abort(struct scsi_cmnd *srb) |
232 | { | 231 | { |
233 | struct us_data *us = host_to_us(srb->device->host); | 232 | struct us_data *us = host_to_us(srb->device->host); |
234 | 233 | ||
235 | US_DEBUGP("%s called\n", __FUNCTION__); | 234 | US_DEBUGP("%s called\n", __FUNCTION__); |
236 | 235 | ||
236 | /* us->srb together with the TIMED_OUT, RESETTING, and ABORTING | ||
237 | * bits are protected by the host lock. */ | ||
238 | scsi_lock(us_to_host(us)); | ||
239 | |||
237 | /* Is this command still active? */ | 240 | /* Is this command still active? */ |
238 | if (us->srb != srb) { | 241 | if (us->srb != srb) { |
242 | scsi_unlock(us_to_host(us)); | ||
239 | US_DEBUGP ("-- nothing to abort\n"); | 243 | US_DEBUGP ("-- nothing to abort\n"); |
240 | return FAILED; | 244 | return FAILED; |
241 | } | 245 | } |
242 | 246 | ||
243 | /* Set the TIMED_OUT bit. Also set the ABORTING bit, but only if | 247 | /* Set the TIMED_OUT bit. Also set the ABORTING bit, but only if |
244 | * a device reset isn't already in progress (to avoid interfering | 248 | * a device reset isn't already in progress (to avoid interfering |
245 | * with the reset). To prevent races with auto-reset, we must | 249 | * with the reset). Note that we must retain the host lock while |
246 | * stop any ongoing USB transfers while still holding the host | 250 | * calling usb_stor_stop_transport(); otherwise it might interfere |
247 | * lock. */ | 251 | * with an auto-reset that begins as soon as we release the lock. */ |
248 | set_bit(US_FLIDX_TIMED_OUT, &us->flags); | 252 | set_bit(US_FLIDX_TIMED_OUT, &us->flags); |
249 | if (!test_bit(US_FLIDX_RESETTING, &us->flags)) { | 253 | if (!test_bit(US_FLIDX_RESETTING, &us->flags)) { |
250 | set_bit(US_FLIDX_ABORTING, &us->flags); | 254 | set_bit(US_FLIDX_ABORTING, &us->flags); |
251 | usb_stor_stop_transport(us); | 255 | usb_stor_stop_transport(us); |
252 | } | 256 | } |
257 | scsi_unlock(us_to_host(us)); | ||
253 | 258 | ||
254 | /* Wait for the aborted command to finish */ | 259 | /* Wait for the aborted command to finish */ |
255 | wait_for_completion(&us->notify); | 260 | wait_for_completion(&us->notify); |
256 | |||
257 | /* Reacquire the lock and allow USB transfers to resume */ | ||
258 | clear_bit(US_FLIDX_ABORTING, &us->flags); | ||
259 | clear_bit(US_FLIDX_TIMED_OUT, &us->flags); | ||
260 | return SUCCESS; | 261 | return SUCCESS; |
261 | } | 262 | } |
262 | 263 | ||
263 | /* This invokes the transport reset mechanism to reset the state of the | 264 | /* This invokes the transport reset mechanism to reset the state of the |
264 | * device */ | 265 | * device */ |
265 | /* This is always called with scsi_lock(host) held */ | ||
266 | static int device_reset(struct scsi_cmnd *srb) | 266 | static int device_reset(struct scsi_cmnd *srb) |
267 | { | 267 | { |
268 | struct us_data *us = host_to_us(srb->device->host); | 268 | struct us_data *us = host_to_us(srb->device->host); |
@@ -279,7 +279,6 @@ static int device_reset(struct scsi_cmnd *srb) | |||
279 | } | 279 | } |
280 | 280 | ||
281 | /* Simulate a SCSI bus reset by resetting the device's USB port. */ | 281 | /* Simulate a SCSI bus reset by resetting the device's USB port. */ |
282 | /* This is always called with scsi_lock(host) held */ | ||
283 | static int bus_reset(struct scsi_cmnd *srb) | 282 | static int bus_reset(struct scsi_cmnd *srb) |
284 | { | 283 | { |
285 | struct us_data *us = host_to_us(srb->device->host); | 284 | struct us_data *us = host_to_us(srb->device->host); |
@@ -291,7 +290,6 @@ static int bus_reset(struct scsi_cmnd *srb) | |||
291 | result = usb_stor_port_reset(us); | 290 | result = usb_stor_port_reset(us); |
292 | up(&(us->dev_semaphore)); | 291 | up(&(us->dev_semaphore)); |
293 | 292 | ||
294 | /* lock the host for the return */ | ||
295 | return result < 0 ? FAILED : SUCCESS; | 293 | return result < 0 ? FAILED : SUCCESS; |
296 | } | 294 | } |
297 | 295 | ||
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index cb4c770baf32..f9a9bfa1aef5 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c | |||
@@ -392,11 +392,16 @@ SkipForAbort: | |||
392 | /* If an abort request was received we need to signal that | 392 | /* If an abort request was received we need to signal that |
393 | * the abort has finished. The proper test for this is | 393 | * the abort has finished. The proper test for this is |
394 | * the TIMED_OUT flag, not srb->result == DID_ABORT, because | 394 | * the TIMED_OUT flag, not srb->result == DID_ABORT, because |
395 | * a timeout/abort request might be received after all the | 395 | * the timeout might have occurred after the command had |
396 | * USB processing was complete. */ | 396 | * already completed with a different result code. */ |
397 | if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) | 397 | if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) { |
398 | complete(&(us->notify)); | 398 | complete(&(us->notify)); |
399 | 399 | ||
400 | /* Allow USB transfers to resume */ | ||
401 | clear_bit(US_FLIDX_ABORTING, &us->flags); | ||
402 | clear_bit(US_FLIDX_TIMED_OUT, &us->flags); | ||
403 | } | ||
404 | |||
400 | /* finished working on this command */ | 405 | /* finished working on this command */ |
401 | us->srb = NULL; | 406 | us->srb = NULL; |
402 | scsi_unlock(host); | 407 | scsi_unlock(host); |