diff options
| author | salmonik <salmonik@tuta.io> | 2026-08-01 01:42:25 +0200 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-08-01 01:42:25 +0200 |
| commit | 3be5c6c8ee43a4c84e3a071831cbf87cc343f585 (patch) | |
| tree | 884071bc751b9f8b26ffa9a10140d635dcc4cbde | |
| parent | ahci: scan all ports; fat: mount first valid FAT32 disk (diff) | |
| download | rs-dos-3be5c6c8ee43a4c84e3a071831cbf87cc343f585.tar.gz rs-dos-3be5c6c8ee43a4c84e3a071831cbf87cc343f585.zip | |
ahci: skip ATAPI ports and fast-fail on device abort
A CD-ROM (or any ATAPI device) on a scanned port previously made the
driver spin the full 100M-iteration timeout on IDENTIFY, then log a
scary 'timed out' (QEMU leaves ATAPI aborts pending in PxCI instead of
completing the slot; tfd=0x441 = ABRT).
- skip a port up-front when firmware set PxCMD.ATAPI (bit 24)
- bail out of the completion poll as soon as PxTFD.ERR is set, clear
the error bits and any wedged slot, and report the abort instead of
timing out — the port scan stays fast with a CD attached
Diffstat (limited to '')
| -rw-r--r-- | rsnix/src/ahci.rs | 27 |
1 files changed, 22 insertions, 5 deletions
diff --git a/rsnix/src/ahci.rs b/rsnix/src/ahci.rs index ea1a886..2efe3b4 100644 --- a/rsnix/src/ahci.rs +++ b/rsnix/src/ahci.rs | |||
| @@ -165,6 +165,13 @@ fn start_port(abar: usize, port_idx: u32) -> Option<Disk> { | |||
| 165 | wreg(port + P_CMD, CMD_FRE | CMD_SUD | CMD_DMAE); | 165 | wreg(port + P_CMD, CMD_FRE | CMD_SUD | CMD_DMAE); |
| 166 | wreg(port + P_CMD, CMD_ST | CMD_FRE | CMD_SUD | CMD_DMAE); | 166 | wreg(port + P_CMD, CMD_ST | CMD_FRE | CMD_SUD | CMD_DMAE); |
| 167 | 167 | ||
| 168 | // ATAPI (optical) devices reject ATA IDENTIFY — skip them so the | ||
| 169 | // scan doesn't waste a timeout on a CD-ROM. | ||
| 170 | if reg(port + P_CMD) & (1 << 24) != 0 { | ||
| 171 | crate::serial_println!("ahci: port {}: ATAPI (optical) device, skipping", port_idx); | ||
| 172 | return None; | ||
| 173 | } | ||
| 174 | |||
| 168 | let mut d = Disk { | 175 | let mut d = Disk { |
| 169 | port, | 176 | port, |
| 170 | clb, | 177 | clb, |
| @@ -175,7 +182,7 @@ fn start_port(abar: usize, port_idx: u32) -> Option<Disk> { | |||
| 175 | }; | 182 | }; |
| 176 | // IDENTIFY DEVICE as a sanity check + to learn the capacity. | 183 | // IDENTIFY DEVICE as a sanity check + to learn the capacity. |
| 177 | if issue(&d, ATA_IDENTIFY, 0, 1, false).is_err() { | 184 | if issue(&d, ATA_IDENTIFY, 0, 1, false).is_err() { |
| 178 | crate::serial_println!("ahci: IDENTIFY failed on port {}", port_idx); | 185 | crate::serial_println!("ahci: IDENTIFY failed on port {} (not an ATA disk?)", port_idx); |
| 179 | return None; | 186 | return None; |
| 180 | } | 187 | } |
| 181 | let id = unsafe { core::slice::from_raw_parts(d.buf as *const u16, 256) }; | 188 | let id = unsafe { core::slice::from_raw_parts(d.buf as *const u16, 256) }; |
| @@ -333,13 +340,20 @@ fn issue(d: &Disk, cmd: u8, lba: u64, count: u32, write: bool) -> Result<(), ()> | |||
| 333 | *hdr.add(3) = 0; | 340 | *hdr.add(3) = 0; |
| 334 | } | 341 | } |
| 335 | 342 | ||
| 336 | // Issue and poll. | 343 | // Issue and poll. Bail out as soon as the device reports an error |
| 344 | // (QEMU leaves ATAPI aborts pending in PxCI rather than completing | ||
| 345 | // the slot, so we must not wait for the timeout on those). | ||
| 337 | wreg(d.port + P_CI, 1); | 346 | wreg(d.port + P_CI, 1); |
| 338 | let mut i = 0; | 347 | let mut i = 0; |
| 339 | while reg(d.port + P_CI) & 1 != 0 && i < 100_000_000 { | 348 | while reg(d.port + P_CI) & 1 != 0 && i < 100_000_000 { |
| 349 | if reg(d.port + P_TFD) & 1 != 0 { | ||
| 350 | break; | ||
| 351 | } | ||
| 340 | i += 1; | 352 | i += 1; |
| 341 | } | 353 | } |
| 342 | if reg(d.port + P_CI) & 1 != 0 { | 354 | let tfd = reg(d.port + P_TFD); |
| 355 | let tfd_err = tfd & 1 != 0; | ||
| 356 | if reg(d.port + P_CI) & 1 != 0 && !tfd_err { | ||
| 343 | crate::serial_println!( | 357 | crate::serial_println!( |
| 344 | "ahci: command {:#x} lba={} cnt={} timed out (tfd={:#x} ci={:#x} cmd={:#x} prdbc={:#x})", | 358 | "ahci: command {:#x} lba={} cnt={} timed out (tfd={:#x} ci={:#x} cmd={:#x} prdbc={:#x})", |
| 345 | cmd, | 359 | cmd, |
| @@ -352,9 +366,12 @@ fn issue(d: &Disk, cmd: u8, lba: u64, count: u32, write: bool) -> Result<(), ()> | |||
| 352 | ); | 366 | ); |
| 353 | return Err(()); | 367 | return Err(()); |
| 354 | } | 368 | } |
| 355 | // Error? Clear any port error bits either way. | 369 | if tfd_err { |
| 356 | if reg(d.port + P_TFD) & 1 != 0 { | 370 | // Clear the error bits and any wedged slot so the port stays usable. |
| 357 | wreg(d.port + 0x30, 0xFFFF_FFFF); // PxSERR: clear | 371 | wreg(d.port + 0x30, 0xFFFF_FFFF); // PxSERR: clear |
| 372 | if reg(d.port + P_CI) & 1 != 0 { | ||
| 373 | wreg(d.port + P_CI, 1); | ||
| 374 | } | ||
| 358 | crate::serial_println!( | 375 | crate::serial_println!( |
| 359 | "ahci: command {:#x} error (tfd={:#x})", | 376 | "ahci: command {:#x} error (tfd={:#x})", |
| 360 | cmd, | 377 | cmd, |
