Replaced single I/O queue pair with dynamic allocation of up to 8 pairs
using NVMe Set Features command (Feature ID 0x07, Number of Queues).
Cross-referenced with Linux 7.1 nvme_set_queue_count() in drivers/nvme/host/core.c.
Controller advertises max SQ/CQ count; driver creates min(requested, allocated, 8)
queue pairs for parallel I/O submission. Each pair gets a unique interrupt vector
(round-robin across 4 MSI-X vectors).
Previous behavior: hardcoded qid=1 only. New behavior: qid 1..N based on
controller capabilities. Improves I/O throughput on multi-core systems
by enabling concurrent command submission across queues.
IMPROVEMENT-PLAN.md §10.1: validates P0 .unwrap→.expect safety fix.
4 tests validating the buffer size invariants documented in
the scsi/mod.rs SAFETY comment:
- all_command_structs_fit_in_command_buffer:
Verifies Inquiry, ModeSense6/10, RequestSense, ReadCapacity10,
Read16, Write16 all fit within the 16-byte command_buffer
- standard_inquiry_data_fits_in_inquiry_buffer:
Verifies StandardInquiryData (36 bytes) fits in inquiry_buffer (259)
- response_structs_match_expected_sizes:
Verifies ModeParamHeader6 (4), ModeParamHeader10 (8),
ReadCapacity10ParamData (8) fixed sizes
- plain_from_bytes_is_safe_for_buffers:
Round-trip verifies plain::from_bytes succeeds on properly
sized buffers — validates that the .expect() calls in the
res_* methods will never panic
All 4 tests pass. usbscsid now has 4 tests (was 0).
IMPROVEMENT-PLAN.md §10.1.6: critical safety fix.
usbscsid main.rs had 3 runtime unwrap sites that would panic
the daemon on transient errors:
1. Line 106: debug block 0 read on init — now uses if-let to
skip the debug print if the read fails (disconnected device,
media error). The device still registers its scheme.
2. Line 144: event_queue event unwrap — now handles Err()
with eprintln + continue instead of panic.
3. Line 147: scheme.tick() unwrap — now handles Err()
with eprintln instead of panic.
Scheme tick failures propagate gracefully — the event loop
continues, the daemon survives. This matches the Linux 7.1
pattern of logging USB errors without crashing the daemon.
IMPROVEMENT-PLAN.md §10.1 item 1: critical safety fix.
usbscsid scsi/mod.rs had 17 plain::from_mut_bytes/from_bytes/slice_from_bytes
.unwrap() calls on compile-time-fixed-size buffers. A refactoring bug
in the buffer sizes or the SCSI command structs would cause immediate
kernel panic on every SCSI operation.
Fix: replace each .unwrap() with .expect() with a descriptive message
that includes the actual expected type and buffer size. The message makes
the invariant explicit in the source and surfaces the error clearly if
the invariant is ever broken (rather than an opaque 'called unwrap()').
Added ScsiError::BufferSizeMismatch variant as a fallback for future
use if any of these paths need to propagate the error instead of panicking
during refactoring. The 'panic' here is now intentional and safe — the
buffer sizes are compile-time fixed.
cross-references IMPROVEMENT-PLAN.md §10.1.1
Cross-referenced with Linux 7.1 drivers/usb/storage/usb.c and SPC-3 §6.27.
Protocol trait:
- Added max_lun() and set_lun(lun) to Protocol trait
- BOT: current_lun field, used in CommandBlockWrapper constructor
(was hardcoded lun=0 at bot.rs:212)
- UAS: current_lun field, used in CommandIU.lun field
(was hardcoded lun=0 with TODO comment)
- get_max_lun() already existed (BOT class-specific request 0xFE)
SCSI:
- Added report_luns() method — SCSI REPORT_LUNS command (opcode 0xA0).
Returns Vec<u64> of 8-byte LUN addresses per SPC-3 format.
Handles big-endian LUN list length and per-entry parsing.
- Import opcodes::Opcode
main.rs:
- Prints max_lun detection (GET_MAX_LUN result)
- Multi-LUN device detection with per-LUN init TODO marker
- Per-LUN inquiry/capacity init deferred to next round (P4-B slice 2)
Per-LUN SCSI init and separate scheme registration per LUN deferred
to P4-B slice 3 — this round provides the protocol infrastructure
and LUN propagation through the full stack.
Infrastructure:
- XhciEndpCtlReq::Transfer gains stream_id: u16 field (serde default=0
for backward compatibility)
- scheme.rs execute_transfer: fixed hardcoded stream_id=1 ring lookup
to use caller-provided stream_id
- transfer() method gains stream_id parameter; all existing callers
pass 0 (non-stream endpoints)
- driver_interface: generic_transfer_stream() with stream_id parameter,
transfer_write_sid() / transfer_read_sid() public stream-aware methods
UAS (usbscsid):
- init() detects stream support via endp_desc.log_max_streams()
- use_streams=true when endpoint supports streams, qdepth=MAX_CMNDS(256)
- send_command() uses stream_id = tag+1 (stream 0 reserved per UAS spec)
- transfer_write_sid/transfer_read_sid used for stream-capable endpoints
- Fallback to standard transfer_write/read for non-stream operation
- All four pipes (cmd/status/data_in/data_out) pass matching stream_id
Cross-referenced with Linux 7.1 xhci-ring.c stream ring management and
uas.c tagged command submission.
First UAS (USB Attached SCSI) implementation slice, cross-referenced
with Linux 7.1 drivers/usb/storage/uas.c and uas-detect.h.
protocol/uas.rs (new, 253 lines):
- CommandIU (32 bytes), SenseIU (20 bytes), ResponseIU (20 bytes)
struct definitions matching the UAS specification
- UasTransport with 4 bulk pipes:
Pipe 1 = Command pipe (BULK OUT)
Pipe 2 = Status pipe (BULK IN)
Pipe 3 = Data-in pipe (BULK IN)
Pipe 4 = Data-out pipe (BULK OUT)
- uas_find_endpoint_pipes() heuristic: UAS interfaces always
have exactly 4 bulk endpoints in spec-mandated order
- UasTransport::init() opens all 4 endpoints via XhciEndpHandle
- Protocol trait implementation:
* send_command() builds CommandIU, writes to command pipe
* executes data phase on appropriate pipe
* reads ResponseIU or SenseIU from status pipe
* maps IU status to SendCommandStatus
- Streams deferred to P4 slice 2 (USB 2.0 sequential, no
CBW/CSW overhead)
protocol/mod.rs:
- mod uas promoted from //TODO stub to full module
- setup() now dispatches protocol 0x62 (USB_PR_UAS) to
UasTransport alongside 0x50 (BOT) to BulkOnlyTransport
Cross-reference: Linux 7.1
- drivers/usb/storage/uas.c: uas_configure_endpoints()
- drivers/usb/storage/uas-detect.h: uas_find_endpoints()
- drivers/usb/storage/uas.c: struct uas_dev_info pipe model
- include/uapi/linux/usb/ch11.h: USB_PR_UAS = 0x62
This means USB 3.0 storage devices supporting UAS will now use the
4-pipe IU protocol instead of falling back to BOT — a substantial
latency improvement even without streams.
usbscsid (P1-B complete):
- zero panic!() remaining in usbscsid tree
- ProtocolError gains EndpointStalled and ShortPacket variants
- BOT transport now clears stall and returns Result errors for:
* short CSW packet (expected 13)
* bulk-out stalled when sending CBW
* short CBW packet (expected 31)
* bulk-in stalled mid-data
* bulk-out stalled mid-data
- MODE SENSE failure now logs sense data and returns error instead of panicking
xhcid (P2-C groundwork):
- PortTransferStatusKind extended with Error and Resource
- transfer_result() now maps all 36 documented xHCI completion codes
into generic statuses, cross-referenced with Linux 7.1
xhci-ring.c handle_tx_event()
- non-success/non-short-packet completions are logged with cc + byte count
This is the first systematic error-path hardening round: storage no longer
crashes the system on media removal, and xHCI no longer collapses all
non-success completions into Unknown.
All 5 panic!() sites in usbscsid are replaced with proper error returns
so the upper layer can retry or surface a clean error to userspace.
A USB stick disconnect mid-transfer no longer crashes the system.
Changes:
protocol/mod.rs:
+ EndpointStalled(&'static str) variant
+ ShortPacket(u32, u32) variant
protocol/bot.rs (4 stall panics):
- panic!() -> log::warn!() + clear_stall_*() + return Err(EndpointStalled)
protocol/bot.rs (1 short-packet panic):
- panic!() -> log::warn!() + return Err(ShortPacket)
scsi/mod.rs (1 debug panic):
- panic!() -> log::error!() + return Err(ProtocolError)
Cross-reference: Linux 7.1 drivers/usb/storage/transport.c uses
-EPIPE, -ETIME, -EIO, -ENODEV, -EILSEQ, -EPROTO for every error
path. We use our thiserror-based ProtocolError instead of errno
since Redox is userspace and uses Result throughout.
After this commit, grep -rn 'panic!' drivers/storage/usbscsid/src/
returns zero results. P1-B done.