v0.13.3: broaden is_wedge_signature — fix dead-code wedge recovery

0.13.2's is_wedge_signature gated on opcode=SCSI_INQUIRY (0x12), but
drive_has_disc issues TEST UNIT READY (0x00). Production wedge errors
(E4000: 0x00/0xff/0x00) never matched → SCSI reset + USB reset
escalation never fired.

Drop the opcode gate. Status byte 0xFF is synthesised by our own
execute() path on poll() timeout — it's the ground-truth wedge
marker for any opcode.

Linux-only; macOS/Windows use sense-key-based wedge detection.
This commit is contained in:
MattJackson
2026-04-24 19:26:11 -07:00
parent e27b82ce5b
commit cc05ef2a3a
3 changed files with 31 additions and 10 deletions
+10 -9
View File
@@ -694,25 +694,26 @@ fn recover_then_probe(path: &Path, original: Error) -> Result<bool> {
Err(original)
}
/// Wedge signature: `Error::ScsiError` with INQUIRY opcode (0x12) and
/// status byte 0xFF. 0xFF isn't a valid SCSI status — the kernel synthesises
/// it when the device gives no answer, which is the real-world signature
/// of a USB Mass Storage layer wedge.
/// Wedge signature: `Error::ScsiError` with status byte 0xFF, for any
/// opcode. 0xFF isn't a real SCSI status — our own `execute()` path
/// synthesises it when poll() times out waiting for the kernel to
/// deliver a response. That timeout is the ground-truth signature of
/// the USB Mass Storage layer wedging; opcode-in-flight is incidental.
fn is_wedge_signature(err: &Error) -> bool {
matches!(
err,
Error::ScsiError {
opcode: crate::scsi::SCSI_INQUIRY,
status: WEDGE_STATUS_BYTE,
..
}
)
}
/// Synthesised SCSI status byte returned by the Linux SG driver when
/// the kernel got no useful response from the device — the wedge
/// signature. Real SCSI statuses are GOOD (0x00), CHECK_CONDITION (0x02),
/// BUSY (0x08), etc.; 0xFF is reserved/invalid in the spec.
/// Synthesised SCSI status byte returned by our own transport when
/// poll() on the SG fd times out — the wedge signature. Real SCSI
/// statuses are GOOD (0x00), CHECK_CONDITION (0x02), BUSY (0x08), etc.;
/// 0xFF is reserved/invalid in the spec, so we can't collide with a
/// real device response. Applies to any opcode (TUR, INQUIRY, READ, …).
const WEDGE_STATUS_BYTE: u8 = 0xFF;
/// Settle time after `USBDEVFS_RESET` returns. The kernel re-enumerates