usb_disk: Retry actions after reset_recovery.

This is mostly important for B_GET_MEDIA_STATUS, which actually will
retry actions if the err_act is set appropriately.

Following this change, stalls are now fully recoverable without causing
the file descriptors of the mounted partition to be cleared, and the
system can resume normal operation without a problem.

Fixes part of #15569.
May help with #16745, #18185, #17543, #18421.
This commit is contained in:
Augustin Cavalier
2023-05-25 15:47:40 -04:00
parent 0a9e5c9e58
commit c098332d7b
@@ -585,13 +585,18 @@ usb_disk_clear_halt(usb_pipe pipe)
void void
usb_disk_reset_recovery(disk_device *device) usb_disk_reset_recovery(disk_device *device, err_act *_action)
{ {
TRACE("reset recovery\n");
usb_disk_mass_storage_reset(device); usb_disk_mass_storage_reset(device);
usb_disk_clear_halt(device->bulk_in); usb_disk_clear_halt(device->bulk_in);
usb_disk_clear_halt(device->bulk_out); usb_disk_clear_halt(device->bulk_out);
if (device->is_ufi) if (device->is_ufi)
usb_disk_clear_halt(device->interrupt); usb_disk_clear_halt(device->interrupt);
if (_action != NULL)
*_action = err_act_retry;
} }
@@ -735,8 +740,8 @@ usb_disk_operation_interrupt(device_lun *lun, uint8* operation,
usb_disk_clear_halt(directionIn ? device->bulk_in : device->bulk_out); usb_disk_clear_halt(directionIn ? device->bulk_in : device->bulk_out);
} else { } else {
TRACE_ALWAYS("sending or receiving of the data failed\n"); TRACE_ALWAYS("sending or receiving of the data failed\n");
usb_disk_reset_recovery(device); usb_disk_reset_recovery(device, _action);
return B_ERROR; return B_IO_ERROR;
} }
} }
} }
@@ -755,7 +760,7 @@ usb_disk_operation_interrupt(device_lun *lun, uint8* operation,
if (result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("receiving the command status interrupt failed\n"); TRACE_ALWAYS("receiving the command status interrupt failed\n");
usb_disk_reset_recovery(device); usb_disk_reset_recovery(device, _action);
return result; return result;
} }
@@ -799,8 +804,8 @@ usb_disk_operation_bulk(device_lun *lun, uint8* operation,
// sending the command block wrapper failed // sending the command block wrapper failed
TRACE_ALWAYS("sending the command block wrapper failed: %s\n", TRACE_ALWAYS("sending the command block wrapper failed: %s\n",
strerror(device->status)); strerror(device->status));
usb_disk_reset_recovery(device); usb_disk_reset_recovery(device, _action);
return B_ERROR; return B_IO_ERROR;
} }
size_t transferedData = 0; size_t transferedData = 0;
@@ -820,8 +825,8 @@ usb_disk_operation_bulk(device_lun *lun, uint8* operation,
} else { } else {
TRACE_ALWAYS("sending or receiving of the data failed: %s\n", TRACE_ALWAYS("sending or receiving of the data failed: %s\n",
strerror(device->status)); strerror(device->status));
usb_disk_reset_recovery(device); usb_disk_reset_recovery(device, _action);
return B_ERROR; return B_IO_ERROR;
} }
} }
} }
@@ -837,7 +842,7 @@ usb_disk_operation_bulk(device_lun *lun, uint8* operation,
if (result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("receiving the command status wrapper failed: %s\n", TRACE_ALWAYS("receiving the command status wrapper failed: %s\n",
strerror(result)); strerror(result));
usb_disk_reset_recovery(device); usb_disk_reset_recovery(device, _action);
return result; return result;
} }
@@ -846,7 +851,7 @@ usb_disk_operation_bulk(device_lun *lun, uint8* operation,
// the command status wrapper is not valid // the command status wrapper is not valid
TRACE_ALWAYS("command status wrapper is not valid: %#" B_PRIx32 "\n", TRACE_ALWAYS("command status wrapper is not valid: %#" B_PRIx32 "\n",
status.signature); status.signature);
usb_disk_reset_recovery(device); usb_disk_reset_recovery(device, _action);
return B_ERROR; return B_ERROR;
} }
@@ -891,7 +896,7 @@ usb_disk_operation_bulk(device_lun *lun, uint8* operation,
// a protocol or device error occured // a protocol or device error occured
TRACE_ALWAYS("phase error in operation %#" B_PRIx8 "\n", TRACE_ALWAYS("phase error in operation %#" B_PRIx8 "\n",
operation[0]); operation[0]);
usb_disk_reset_recovery(device); usb_disk_reset_recovery(device, _action);
return B_ERROR; return B_ERROR;
} }
@@ -899,7 +904,7 @@ usb_disk_operation_bulk(device_lun *lun, uint8* operation,
{ {
// command status wrapper is not meaningful // command status wrapper is not meaningful
TRACE_ALWAYS("command status wrapper has invalid status\n"); TRACE_ALWAYS("command status wrapper has invalid status\n");
usb_disk_reset_recovery(device); usb_disk_reset_recovery(device, _action);
return B_ERROR; return B_ERROR;
} }
} }