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:
@@ -1,5 +1,25 @@
|
||||
# Changelog
|
||||
|
||||
## 0.13.3 (2026-04-24)
|
||||
|
||||
### Bug fix — `drive_has_disc` wedge recovery was dead code for TUR errors
|
||||
|
||||
The wedge-signature predicate introduced in 0.13.2 gated on
|
||||
`opcode == SCSI_INQUIRY (0x12)` — a holdover from when enumerate-time
|
||||
INQUIRY was the only path wedges surfaced on. `drive_has_disc` issues
|
||||
`TEST UNIT READY (0x00)`, so its wedge errors (`E4000: 0x00/0xff/0x00`)
|
||||
never matched the predicate and the SCSI-reset + USB-reset escalation
|
||||
never fired. Production result: the BU40N USB BD-RE stayed wedged
|
||||
indefinitely, with autorip logging `recovery exhausted` on the raw
|
||||
pass-through error while no recovery had actually been attempted.
|
||||
|
||||
Fix: drop the opcode constraint. Status byte `0xFF` is synthesised by
|
||||
our own `execute()` path when `poll()` on the SG fd times out; it's
|
||||
the ground-truth wedge marker regardless of which opcode was in flight.
|
||||
Doc comments on `is_wedge_signature` and `WEDGE_STATUS_BYTE` updated
|
||||
accordingly. Linux-only — macOS / Windows use sense-key-based wedge
|
||||
detection and are unaffected.
|
||||
|
||||
## 0.13.2 (2026-04-24)
|
||||
|
||||
### Public discovery + presence APIs; SCSI/USB primitives no longer
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "libfreemkv"
|
||||
version = "0.13.2"
|
||||
version = "0.13.3"
|
||||
edition = "2024"
|
||||
rust-version = "1.86"
|
||||
license = "AGPL-3.0-only"
|
||||
|
||||
+10
-9
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user