Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,20 @@ kind: track
opened: 2026-08-10
---

# The BOT/SCSI machine is still hand-written in the kernel
# A disk plugged in after boot is bound inside a scheduling pass

The xHCI port, protocol, teardown, recovery and enumeration machines are pure
crate code with a host simulator behind them, and the kernel drives them. The
mass-storage half is not: the BOT round trip and the SCSI bring-up above it are
still hand-written in the kernel's wait module, and that is the one call site
The BOT round trip and the SCSI bring-up above it are pure machines,
`toyos_xhci::bot::RoundTrip` and `toyos_xhci::scsi::BringUp`, and the kernel
drives both blocking, in place. For the read/write entry points that is the
caller's own time. For the bind it is not: `msc::bind` is the one call site
where a scheduling pass can still spend its transfer budget inside xHCI — for a
disk arriving *after* boot, which is one greppable path.

**What to build**, expressed the way recovery and enumeration already are: the
round trip (command block out, data, status in, one legal stall retry) and the
bring-up above it (test-unit-ready on a budget, sense, inquiry, read-capacity 10
then 16), with two drivers over the same machine — a blocking one for the
read/write entry points and a stepped one for the bind. Blocked on nothing but
its own size; folding it into the enumeration landing would have made that
unreviewable.
**What to build**: a stepped driver for the bind over the same two machines,
one act per pass, as enumeration has. Moving the bind to a thread that may
block — usbd, step 10 of
`issues/kernel/the-kernel-is-small-interrupts-post-and-threads-wait.md` — ends
this file as well.

After it, the pass-duration proof costs no new code: one guest gate measuring a
scheduling pass across a plug, plus the existing check-build's pass-cost
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Owner ruling, 2026-09-25: the kernel is to be super small, super performant
and safe. This track holds that, and supersedes the ordering of
`issues/kernel/every-wait-in-this-kernel-is-a-spin.md`,
`issues/kernel/every-driver-is-still-in-the-kernel.md` and
`issues/hardware/the-bot-scsi-machine-is-still-hand-written-in-the-kernel.md`,
`issues/hardware/a-disk-plugged-in-after-boot-is-bound-inside-a-scheduling-pass.md`,
which stay as the evidence each stage closes.

The design review of 2026-09-25 read the code and found the same shape three
Expand Down
4 changes: 2 additions & 2 deletions kernel/src/drivers/xhci/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::log;
use toyos_xhci::enumerate::{
self, ep0_packet_from_descriptor, initial_ep0_packet, Act, Enumeration, Learnt, Next, Request,
};
use toyos_xhci::job::{Await, Outcome, Stages};
use toyos_xhci::job::{Await, Outcome, Stages, CC_SUCCESS};
use toyos_xhci::port::{self, Reset};
use toyos_xhci::identity::UsbId;
use toyos_xhci::recovery;
Expand All @@ -14,7 +14,7 @@ use super::{deadline, Answer, Trb, TrbRing, What, XhciController, PAGE};
use super::{OFF_INPUT_CTX, OFF_DATA_BUF};
use super::{DEV_INT_RING, DEV_EP0_RING, DEV_OUT_CTX, DEV_REPORT, EP0_DCI};
use super::{TRB_ENABLE_SLOT, TRB_ADDRESS_DEVICE, TRB_CONFIGURE_EP, TRB_EVALUATE_CONTEXT};
use super::{enqueue_control, CC_SUCCESS};
use super::enqueue_control;

use super::hid::{HidType, HidRole, HidDevice};
use super::msc::{Bind, MscInterface, MscRings};
Expand Down
6 changes: 1 addition & 5 deletions kernel/src/drivers/xhci/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::log;
use super::pci::PciDevice;
use crate::sync::Lock;
use toyos_untrusted::Untrusted;
use toyos_xhci::job::{Await, Outcome, Outstanding, Stages};
use toyos_xhci::job::{Await, Outcome, Outstanding, Stages, CC_SHORT_PACKET, CC_SUCCESS};
use toyos_xhci::port::{self as portmachine, GaveUp, Gone, PortState, Reset, Step};
use toyos_xhci::call::AfterBreak;
use toyos_xhci::recovery::{self, Act, EndpointState, NeedsConfigure, Recovery};
Expand Down Expand Up @@ -111,10 +111,6 @@ const EVENT_TRANSFER: u32 = 32;
const EVENT_CMD_COMPLETE: u32 = 33;
const EVENT_PORT_STATUS_CHANGE: u32 = 34;

// CC_SHORT_PACKET is success with a residue, not an error — treating it as one is the classic mass-storage bug.
const CC_SUCCESS: u32 = 1;
const CC_STALL: u32 = 6;
const CC_SHORT_PACKET: u32 = 13;
const CC_CONTEXT_STATE_ERROR: u32 = 19;
/// Stopped, Stopped - Length Invalid and Stopped - Short Packet (Table 6-90): the transfer events a Stop Endpoint raises for the TRB it stopped inside (§4.6.9).
const CC_STOPPED: core::ops::RangeInclusive<u32> = 26..=28;
Expand Down
5 changes: 2 additions & 3 deletions kernel/src/drivers/xhci/wait/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,8 @@ mod depth_probe {
use crate::log;
use super::{deadline, enqueue_control, log_unrecoverable, Completion, Trb, TrbRing};
use super::{XhciController, EVENT_TRANSFER, EVENT_CMD_COMPLETE, USB_TIMEOUT_NS};
use super::{CC_SUCCESS, CC_SHORT_PACKET};
use toyos_xhci::call::NotTaken;
use toyos_xhci::job::Await;
use toyos_xhci::job::{Await, CC_SHORT_PACKET, CC_STALL, CC_SUCCESS};
use toyos_xhci::recovery::{Act, NeedsConfigure, Recovery};
use toyos_xhci::scan;

Expand Down Expand Up @@ -482,7 +481,7 @@ impl XhciController {
/// Take EP0 back out of Halted where `code` says the device stalled the
/// transfer, before the failure reaches a caller likely to send another one.
fn recover_after(&mut self, slot: u8, ctx_block: usize, ring: &mut TrbRing, code: u32) {
if code != super::CC_STALL {
if code != CC_STALL {
return;
}
if !self.restart_control_endpoint(slot, ctx_block, ring) {
Expand Down
Loading
Loading