scsi: promote SenseFamily to a lib-level SCSI-fact primitive

Moved SenseFamily::from_sense_key + is_wedge_family from disc/read_error.rs
into scsi/mod.rs (with its own tests) and re-exported at the crate root.
This is pure SCSI sense-code classification -- objective hardware fact, zero
recovery-policy opinion -- so it belongs in the library primitives, unlike
the retry-DECISION state machine (ReadCtx/PassSummary/ReadAction/
handle_read_error) built on top of it, which is freemkv's specific recovery
strategy and is moving to freemkv-engine next.

disc/read_error.rs and disc/section_recover.rs now import SenseFamily from
crate::scsi instead of defining/re-exporting their own copy. No behavior
change. Precommit green on Rust 1.86 (fmt+clippy+test).
This commit is contained in:
MattJackson
2026-07-28 11:32:13 -07:00
parent 05fd7fcbfa
commit 227545fabc
4 changed files with 73 additions and 32 deletions
+1 -30
View File
@@ -11,6 +11,7 @@
use crate::error::Error;
use crate::scsi;
use crate::scsi::SenseFamily;
/// In-flight bookkeeping a read loop must keep across iterations. The
/// handler reads and mutates this. Caller owns the storage.
@@ -122,36 +123,6 @@ pub struct ReadCtx {
pub marginal_recovered: u64,
}
/// Coarse classification of a SCSI sense key for diagnostic logging.
/// Wedge-family events (Hardware + IllegalRequest) get their own
/// transition log when the sense family changes.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SenseFamily {
NotReady,
Medium,
Hardware,
IllegalRequest,
Other,
}
impl SenseFamily {
pub fn from_sense_key(sense_key: u8) -> Self {
match sense_key {
scsi::SENSE_KEY_NOT_READY => SenseFamily::NotReady,
scsi::SENSE_KEY_MEDIUM_ERROR => SenseFamily::Medium,
scsi::SENSE_KEY_HARDWARE_ERROR => SenseFamily::Hardware,
scsi::SENSE_KEY_ILLEGAL_REQUEST => SenseFamily::IllegalRequest,
_ => SenseFamily::Other,
}
}
/// True for the "wedge family" — Hardware + IllegalRequest are
/// the senses the BU40N firmware returns in its fast-fail state.
pub fn is_wedge_family(self) -> bool {
matches!(self, SenseFamily::Hardware | SenseFamily::IllegalRequest)
}
}
impl ReadCtx {
/// Initial context for a Pass 1 sweep. The job is "fast and
/// accurate, get the most data in the shortest time" — Pass N
+1 -1
View File
@@ -33,7 +33,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Instant;
use super::patch::{SubRanges, recovery_read};
use super::read_error::SenseFamily;
use crate::scsi::SenseFamily;
use crate::sector::SectorSource;
/// One 2048-byte sector.