Update docs: async sg transport, Drive::read recovery phases
This commit is contained in:
@@ -42,7 +42,7 @@ libfreemkv (lib.rs)
|
|||||||
│
|
│
|
||||||
├── Drive Access
|
├── Drive Access
|
||||||
│ ├── drive Drive — open, identify, init, unlock, read (with recovery)
|
│ ├── drive Drive — open, identify, init, unlock, read (with recovery)
|
||||||
│ ├── scsi ScsiTransport trait + platform backends (SG_IO, IOKit, SPTI)
|
│ ├── scsi ScsiTransport trait + platform backends (sg async, IOKit, SPTI)
|
||||||
│ ├── platform/ Platform trait — per-chipset command handlers
|
│ ├── platform/ Platform trait — per-chipset command handlers
|
||||||
│ │ └── mt1959 MediaTek MT1959 driver (LG, ASUS, HP)
|
│ │ └── mt1959 MediaTek MT1959 driver (LG, ASUS, HP)
|
||||||
│ ├── profile DriveProfile loading, matching, bundled JSON
|
│ ├── profile DriveProfile loading, matching, bundled JSON
|
||||||
@@ -83,7 +83,7 @@ libfreemkv (lib.rs)
|
|||||||
```
|
```
|
||||||
Drive::open(Path::new("/dev/sg4"))
|
Drive::open(Path::new("/dev/sg4"))
|
||||||
│
|
│
|
||||||
├─ scsi::open() Open /dev/sg4 via SG_IO
|
├─ scsi::open() Open /dev/sg4 (async write/poll/read)
|
||||||
├─ DriveId::from_drive() INQUIRY + GET_CONFIG 010C
|
├─ DriveId::from_drive() INQUIRY + GET_CONFIG 010C
|
||||||
├─ profile::find_by_drive_id() Match against bundled profiles
|
├─ profile::find_by_drive_id() Match against bundled profiles
|
||||||
├─ Platform::new() Instantiate chipset driver (Mt1959)
|
├─ Platform::new() Instantiate chipset driver (Mt1959)
|
||||||
@@ -175,7 +175,7 @@ is baked into the library.
|
|||||||
|
|
||||||
| Platform | Transport | Status |
|
| Platform | Transport | Status |
|
||||||
|----------|-----------|--------|
|
|----------|-----------|--------|
|
||||||
| Linux | SG_IO ioctl on `/dev/sg*` | Supported |
|
| Linux | async sg write/poll/read on `/dev/sg*` | Supported |
|
||||||
| macOS | IOKit SCSITask | Supported |
|
| macOS | IOKit SCSITask | Supported |
|
||||||
| Windows | SPTI (`IOCTL_SCSI_PASS_THROUGH_DIRECT`) | Supported |
|
| Windows | SPTI (`IOCTL_SCSI_PASS_THROUGH_DIRECT`) | Supported |
|
||||||
|
|
||||||
|
|||||||
+21
-14
@@ -46,14 +46,20 @@ platform driver. The drive is ready for `wait_ready()` and `init()`.
|
|||||||
|
|
||||||
### read() with Recovery
|
### read() with Recovery
|
||||||
|
|
||||||
`Drive::read()` is the single read method. On error:
|
`Drive::read(lba, count, buf, recovery)` is the single read method. The
|
||||||
|
`recovery` parameter controls whether to attempt multi-phase recovery on
|
||||||
|
failure or return immediately (used by DiscStream's binary search for
|
||||||
|
single-sector probes).
|
||||||
|
|
||||||
1. Set minimum speed immediately
|
On error with `recovery = true`:
|
||||||
2. Reset device (close/reopen/TUR)
|
|
||||||
3. Wait 2s for drive to settle
|
1. **Phase 1 — gentle retry (5 attempts):** set min speed, sleep 30s, retry.
|
||||||
4. Retry at min speed, min batch (3 sectors)
|
Each retry has a hard wall-clock timeout via async SG_IO.
|
||||||
5. If still failing: skip sectors, zero-fill, log
|
2. **Phase 2 — fresh start:** close transport, reset device, reopen, reinit.
|
||||||
6. Stay at min speed for 500 MB after error (recovery window)
|
3. **Phase 3 — gentle retry on fresh connection (5 attempts).**
|
||||||
|
4. If all fail: return `Err(DiscRead)`. DiscStream handles it (binary search,
|
||||||
|
skip, zero-fill).
|
||||||
|
5. Stay at min speed for 500 MB after any recovery (recovery window).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -70,8 +76,6 @@ pub trait ScsiTransport: Send {
|
|||||||
data: &mut [u8],
|
data: &mut [u8],
|
||||||
timeout_ms: u32,
|
timeout_ms: u32,
|
||||||
) -> Result<ScsiResult>;
|
) -> Result<ScsiResult>;
|
||||||
|
|
||||||
fn reset(&mut self, device: &str) -> Result<()>;
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -82,15 +86,18 @@ descriptors or calls ioctls outside of a `ScsiTransport` implementation.
|
|||||||
|
|
||||||
| Platform | Implementation | Device |
|
| Platform | Implementation | Device |
|
||||||
|----------|---------------|--------|
|
|----------|---------------|--------|
|
||||||
| Linux | `SgIoTransport` — `ioctl(fd, SG_IO, &hdr)` | `/dev/sg*` |
|
| Linux | `SgIoTransport` — async `write`/`poll`/`read` on `/dev/sg*` | `/dev/sg*` |
|
||||||
| macOS | `MacScsiTransport` — IOKit SCSITask | IOKit service |
|
| macOS | `MacScsiTransport` — IOKit SCSITask | IOKit service |
|
||||||
| Windows | `WindowsScsiTransport` — SPTI | `\\.\CdRomN` |
|
| Windows | `WindowsScsiTransport` — SPTI | `\\.\CdRomN` |
|
||||||
|
|
||||||
The Linux backend opens with `O_RDWR | O_NONBLOCK`, constructs `sg_io_hdr`,
|
The Linux backend uses the sg driver's asynchronous interface: `write()` submits
|
||||||
and returns `ScsiResult` with status, bytes transferred, and sense data.
|
the command, `poll()` waits with an enforceable wall-clock timeout, `read()`
|
||||||
|
retrieves the result. If `poll()` times out, the fd is abandoned (closed in a
|
||||||
|
background thread) and a fresh fd opened — the kernel's USB error recovery
|
||||||
|
cannot block us. Opens with `O_RDWR | O_NONBLOCK`.
|
||||||
|
|
||||||
On non-zero SCSI status, the transport parses sense key, ASC, and ASCQ from the
|
On non-zero SCSI status, the transport parses sense key from the sense buffer
|
||||||
sense buffer and returns `Error::ScsiError`.
|
and returns `Error::ScsiError`.
|
||||||
|
|
||||||
### CDB Builders
|
### CDB Builders
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user