Stop documenting the recovery API that 1.6.0 deleted
Disc::sweep, Disc::patch, Disc::copy, SweepOptions and PatchOptions have zero occurrences in src/ — recovery moved to freemkv-engine — but they were still documented in 30 places across README.md, TROUBLESHOOTING.md, six files under docs/, seven src/ doc comments and a Cargo.toml comment. README.md is the crate's GitHub front page and carried a full multi-pass code example that cannot compile. Two of the src/ references were intra-doc LINKS to deleted items ([`disc::Disc::copy`], [`disc::Disc::patch`] in scsi/mod.rs). They produced no warning on a normal `cargo doc` only because they sit on pub(crate) items; `--document-private-items` reports both, and they are gone now. The README example is deleted rather than rewritten against the engine's API: libfreemkv documenting a downstream crate's API on its own front page is the drift that produced this, and it cannot even depend on it. The src/ references become plain code spans naming freemkv_engine::recovery::* — deliberately not links, for the same reason. docs/rip-recovery.md was 202 lines about relocated code. It now documents only what this crate owns — Drive::read, SenseFamily, DiscStream's adaptive batch halving — plus the read-path design constraints, which belong with the code that enforces them, and points at freemkv-engine/src/recovery/ for the strategy. api-design.md's module tree is regenerated from the real src/disc/ and src/drive/ layouts instead of hand-patched; it had listed sweep.rs, patch.rs, mapfile.rs and read_error.rs, none of which exist. Three stale facts surfaced while rewriting and are corrected: the read timeouts are 10 s / 60 s, not the documented 1.5 s / 30 s; Drive::reset and SgIoTransport::reset no longer exist at all, so "no SCSI reset from any read path" is now stated as the stronger fact it has become; and verify_title, listed as a progress-emitting operation, was removed entirely. CHANGELOG.md keeps its references — those are the historical record of the releases that shipped the API.
This commit is contained in:
+4
-4
@@ -715,19 +715,19 @@ impl Drive {
|
||||
/// SCSI reset.
|
||||
///
|
||||
/// `recovery=true` uses [`crate::scsi::READ_RECOVERY_TIMEOUT_MS`] (60 s,
|
||||
/// matches sg_dd) for the `Disc::patch` pass; `recovery=false` uses
|
||||
/// [`crate::scsi::READ_TIMEOUT_MS`] (10 s) for `Disc::copy`'s fast
|
||||
/// matches sg_dd) for the `freemkv_engine::recovery::patch` pass; `recovery=false` uses
|
||||
/// [`crate::scsi::READ_TIMEOUT_MS`] (10 s) for `freemkv_engine::recovery::copy`'s fast
|
||||
/// skip-forward sweep. Both budgets are generous enough that the drive
|
||||
/// can finish ECC recovery on a marginal sector — pre-0.13.21 this was
|
||||
/// 1.5 s on the fast path which forced the kernel mid-layer to time
|
||||
/// out and escalate while we waited anyway. On any failure returns
|
||||
/// `Err(DiscRead)` immediately; orchestration (`Disc::patch` multi-pass,
|
||||
/// `Err(DiscRead)` immediately; orchestration (`freemkv_engine::recovery::patch` multi-pass,
|
||||
/// `DiscStream` adaptive batch halving) handles retry policy.
|
||||
///
|
||||
/// Inline retry phases (5× gentle + reset+reopen + 5× more) were
|
||||
/// removed in 0.13.6: on some USB-SATA bridges the inline reset wedged
|
||||
/// drive firmware without ever recovering a sector. The remaining
|
||||
/// recovery layers (Disc::patch multi-pass, DiscStream batch halving)
|
||||
/// recovery layers (freemkv_engine::recovery::patch multi-pass, DiscStream batch halving)
|
||||
/// do not touch the wedge-prone reset path.
|
||||
pub fn read(&mut self, lba: u32, count: u16, buf: &mut [u8], recovery: bool) -> Result<usize> {
|
||||
// Bulk path: FUA off (the drive cache IS the streaming throughput).
|
||||
|
||||
+1
-1
@@ -1032,7 +1032,7 @@ impl Error {
|
||||
/// REQUEST, BLANK CHECK, kernel `IoError`, and any non-SCSI variant.
|
||||
/// Caller-agnostic predicate — describes a property of the *error*,
|
||||
/// not what one specific call site should do with it. Used by
|
||||
/// `Disc::copy`'s hysteresis dispatch.
|
||||
/// `freemkv_engine::recovery::copy`'s hysteresis dispatch.
|
||||
pub fn is_marginal_read(&self) -> bool {
|
||||
self.scsi_sense()
|
||||
.map(crate::scsi::ScsiSense::is_marginal)
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
//! One stream type for all disc sources. The source is a SectorSource —
|
||||
//! Drive (hardware) or FileSectorSource (file). DiscStream doesn't care.
|
||||
//!
|
||||
//! Read-only. For disc→ISO (raw sector copy), use `Disc::copy()`.
|
||||
//! Read-only. For disc→ISO (raw sector copy), use `freemkv_engine::recovery::copy`.
|
||||
|
||||
use crate::disc::{DiscTitle, Extent};
|
||||
use crate::drive::extract_scsi_context;
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@
|
||||
//! output.finish()?;
|
||||
//! ```
|
||||
//!
|
||||
//! For disc→ISO (raw sector copy), use `Disc::copy()` instead.
|
||||
//! For disc→ISO (raw sector copy), use `freemkv_engine::recovery::copy` instead.
|
||||
|
||||
// Public modules — types here are intentionally part of the consumable API.
|
||||
pub mod disc;
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
//! | fvi:// | -- | Yes | file path (required) — per-picture video index |
|
||||
//!
|
||||
//! Bare paths without a scheme are rejected.
|
||||
//! For disc→ISO (raw sector copy), use `Disc::copy()` instead.
|
||||
//! For disc→ISO (raw sector copy), use `freemkv_engine::recovery::copy` instead.
|
||||
//!
|
||||
//! Note: `disc://` cannot be opened through [`input`]; it returns
|
||||
//! [`crate::error::Error::DiscUrlNotDirect`]. Live-disc input must go
|
||||
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
//! Pipeline-progress reporting for the rip pipeline.
|
||||
//!
|
||||
//! Architecture rule: ONE progress signal type. Every long-running
|
||||
//! pipeline operation (`Disc::copy`, `Disc::patch`, `verify_title`) emits the
|
||||
//! pipeline operation (`freemkv_engine::recovery::{copy, patch}`) emits the
|
||||
//! same [`PassProgress`] shape via the [`Progress`] trait. Consumers (autorip)
|
||||
//! compute their own single derived view from these fields and never reach
|
||||
//! into per-pass internals.
|
||||
@@ -18,12 +18,12 @@
|
||||
/// (reverse)", "Scrape", "Mux") or just use a generic "Pass N" label.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum PassKind {
|
||||
/// `Disc::copy` — initial sweep across the entire disc.
|
||||
/// `freemkv_engine::recovery::copy` — initial sweep across the entire disc.
|
||||
Sweep,
|
||||
/// `Disc::patch` retry pass with `block_sectors >= 2`. `reverse=true`
|
||||
/// `freemkv_engine::recovery::patch` retry pass with `block_sectors >= 2`. `reverse=true`
|
||||
/// means walking bad ranges from highest to lowest LBA.
|
||||
Trim { reverse: bool },
|
||||
/// `Disc::patch` final pass at 1 sector per block.
|
||||
/// `freemkv_engine::recovery::patch` final pass at 1 sector per block.
|
||||
Scrape { reverse: bool },
|
||||
/// Demux ISO → output (MKV / M2TS / network). Single phase that runs
|
||||
/// after all rip passes complete. The library's mux pipeline does not
|
||||
|
||||
+6
-6
@@ -44,7 +44,7 @@ pub const AACS_KEY_CLASS: u8 = 0x02;
|
||||
pub(crate) const TUR_TIMEOUT_MS: u32 = 5_000;
|
||||
|
||||
/// Timeout for content READ commands (READ_10 / READ_12) on the fast
|
||||
/// path — the [`disc::Disc::copy`] sweep that bisects-on-failure.
|
||||
/// path — the `freemkv_engine::recovery::copy` sweep that bisects-on-failure.
|
||||
///
|
||||
/// 10 s is calibrated from live empirical data on an LG BU40N + Initio
|
||||
/// 1618L bridge ripping a UHD with marginal sectors:
|
||||
@@ -67,7 +67,7 @@ pub(crate) const TUR_TIMEOUT_MS: u32 = 5_000;
|
||||
pub(crate) const READ_TIMEOUT_MS: u32 = 10_000;
|
||||
|
||||
/// Timeout for content READ commands on the recovery path —
|
||||
/// [`disc::Disc::patch`]'s targeted retries on bad ranges. Matches
|
||||
/// `freemkv_engine::recovery::patch`'s targeted retries on bad ranges. Matches
|
||||
/// `sg_dd`'s 60 s ceiling: long enough that any sector the drive can
|
||||
/// recover at all gets the time to do so, short enough that an
|
||||
/// unresponsive bus is detected before the per-range watchdog fires.
|
||||
@@ -77,7 +77,7 @@ pub(crate) const READ_TIMEOUT_MS: u32 = 10_000;
|
||||
/// safety ceiling, not a steady-state cost.
|
||||
///
|
||||
/// Historical note (2026-05-08): briefly lowered to 2 s with a 5×
|
||||
/// inline retry loop in `Disc::patch` to mimic the kernel `sr_mod`
|
||||
/// inline retry loop in `freemkv_engine::recovery::patch` to mimic the kernel `sr_mod`
|
||||
/// driver's auto-retry pattern. The synthetic logic worked but on the
|
||||
/// live drive each "2 s" read paid ~1.5 s of kernel SCSI mid-layer
|
||||
/// error escalation on top, so 5× retries took ~17 s per LBA and
|
||||
@@ -237,7 +237,7 @@ impl ScsiSense {
|
||||
///
|
||||
/// `false` for HARDWARE ERROR, DATA PROTECT, UNIT ATTENTION,
|
||||
/// ILLEGAL REQUEST, BLANK CHECK, and any unknown key. Used
|
||||
/// by [`Error::is_marginal_read`] / `Disc::copy`'s hysteresis
|
||||
/// by [`Error::is_marginal_read`] / `freemkv_engine::recovery::copy`'s hysteresis
|
||||
/// dispatch.
|
||||
pub fn is_marginal(&self) -> bool {
|
||||
matches!(
|
||||
@@ -1022,8 +1022,8 @@ mod parse_sense_tests {
|
||||
#[cfg(test)]
|
||||
mod scsi_sense_predicate_tests {
|
||||
//! Classification of [`ScsiSense`] predicate methods against SPC-4
|
||||
//! §4.5.6 Table 28 sense keys. These drive `Disc::copy` hysteresis
|
||||
//! and `Disc::patch` routing; a misclassification here silently
|
||||
//! §4.5.6 Table 28 sense keys. These drive `freemkv_engine::recovery::copy` hysteresis
|
||||
//! and `freemkv_engine::recovery::patch` routing; a misclassification here silently
|
||||
//! changes which sectors get retried vs. marked unreadable.
|
||||
use super::*;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user