usb_disk: Cancel queued transfers when clearing HALTs.

XHCI, at least, has "sticky" HALT states which must be cleared at
the controller level. Invoking cancel_queued_transfers takes care
of this.

This fixes USB disks spontaneously unmounting whenever stalls occur.
However, trying to read anything from the mounted partition results
in "Bad file descriptor", probably due to media-status error propagation.
This commit is contained in:
Augustin Cavalier 2023-05-25 15:31:34 -04:00
parent 1886d5692e
commit 0a9e5c9e58

View File

@ -576,14 +576,22 @@ usb_disk_get_max_lun(disk_device *device)
}
static void
usb_disk_clear_halt(usb_pipe pipe)
{
gUSBModule->cancel_queued_transfers(pipe);
gUSBModule->clear_feature(pipe, USB_FEATURE_ENDPOINT_HALT);
}
void
usb_disk_reset_recovery(disk_device *device)
{
usb_disk_mass_storage_reset(device);
gUSBModule->clear_feature(device->bulk_in, USB_FEATURE_ENDPOINT_HALT);
gUSBModule->clear_feature(device->bulk_out, USB_FEATURE_ENDPOINT_HALT);
usb_disk_clear_halt(device->bulk_in);
usb_disk_clear_halt(device->bulk_out);
if (device->is_ufi)
gUSBModule->clear_feature(device->interrupt, USB_FEATURE_ENDPOINT_HALT);
usb_disk_clear_halt(device->interrupt);
}
@ -724,8 +732,7 @@ usb_disk_operation_interrupt(device_lun *lun, uint8* operation,
// sending or receiving of the data failed
if (device->status == B_DEV_STALLED) {
TRACE("stall while transfering data\n");
gUSBModule->clear_feature(directionIn ? device->bulk_in
: device->bulk_out, USB_FEATURE_ENDPOINT_HALT);
usb_disk_clear_halt(directionIn ? device->bulk_in : device->bulk_out);
} else {
TRACE_ALWAYS("sending or receiving of the data failed\n");
usb_disk_reset_recovery(device);
@ -742,8 +749,7 @@ usb_disk_operation_interrupt(device_lun *lun, uint8* operation,
// in case of a stall or error clear the stall and try again
TRACE("Error receiving interrupt: %s. Retrying...\n",
strerror(result));
gUSBModule->clear_feature(device->bulk_in,
USB_FEATURE_ENDPOINT_HALT);
usb_disk_clear_halt(device->bulk_in);
result = usb_disk_receive_csw_interrupt(device, &status);
}
@ -810,8 +816,7 @@ usb_disk_operation_bulk(device_lun *lun, uint8* operation,
// sending or receiving of the data failed
if (device->status == B_DEV_STALLED) {
TRACE("stall while transfering data\n");
gUSBModule->clear_feature(directionIn ? device->bulk_in
: device->bulk_out, USB_FEATURE_ENDPOINT_HALT);
usb_disk_clear_halt(directionIn ? device->bulk_in : device->bulk_out);
} else {
TRACE_ALWAYS("sending or receiving of the data failed: %s\n",
strerror(device->status));
@ -825,7 +830,7 @@ usb_disk_operation_bulk(device_lun *lun, uint8* operation,
result = usb_disk_receive_csw_bulk(device, &status);
if (result != B_OK) {
// in case of a stall or error clear the stall and try again
gUSBModule->clear_feature(device->bulk_in, USB_FEATURE_ENDPOINT_HALT);
usb_disk_clear_halt(device->bulk_in);
result = usb_disk_receive_csw_bulk(device, &status);
}