From 0a9e5c9e58a089952f1c393b0930080610b72ca1 Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Thu, 25 May 2023 15:31:34 -0400 Subject: [PATCH] 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. --- .../drivers/disk/usb/usb_disk/usb_disk.cpp | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/add-ons/kernel/drivers/disk/usb/usb_disk/usb_disk.cpp b/src/add-ons/kernel/drivers/disk/usb/usb_disk/usb_disk.cpp index 30d585c3a3..98e9010b17 100644 --- a/src/add-ons/kernel/drivers/disk/usb/usb_disk/usb_disk.cpp +++ b/src/add-ons/kernel/drivers/disk/usb/usb_disk/usb_disk.cpp @@ -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); }