Artemis Milestone 2g: TEST UNIT READY unit-init sequence -- READ(10) now PASSes
Roots out the CSW status FAILED left unexplained in the prior increment: a freshly attached SCSI target's standing UNIT ATTENTION condition, which a bare READ(10) with no retry can never clear. xhci_bot_send_test_unit_ready() sends SCSI TEST UNIT READY (SPC-4 6.33) ahead of the real command; the CSW handler now tags command kind (bot_cmd_kind) to distinguish a TUR completion from a READ10 completion, chains TUR PASS into the real READ(10), and bounded-retries TUR on FAILED/PHASE ERROR (bot_tur_retries, capped at XHCI_BOT_TUR_MAX_RETRIES). xhci_bot_read_block() is the new intended entry point tying lba/num_blocks/block_size + the TUR-first sequencing together. Verified live via a temporary probe (hot-attached disk/usb-thumbdrive-test.img through the running instance's QMP socket), captured on amd64: full chain CBW(TUR) -> FAILED -> retry -> PASS -> CBW(READ10) -> Data-In -> CSW PASS. Probe reverted after capture; all three architectures re-verified clean, probe-free boot to ok>. FABRIC-2.md Section X 2g updated with the writeup. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
c54ea24aaf
commit
65effbd1ba
@@ -306,6 +306,20 @@ typedef struct {
|
||||
#define SCSI_CMD_READ10 0x28u
|
||||
#define SCSI_CDB_LEN_READ10 10u
|
||||
|
||||
/* SCSI TEST UNIT READY (SPC-4 section 6.33) -- 6-byte CDB, all-zero apart
|
||||
* from the opcode, no data stage. Convention (not spec-mandated, but
|
||||
* standard SCSI target behavior): the first command a target sees after
|
||||
* attach fails with CHECK CONDITION/UNIT ATTENTION (media/reset notice),
|
||||
* clearing on the next command -- issuing this ahead of a real data
|
||||
* command and retrying it a bounded number of times on failure is the
|
||||
* standard way to drain that condition before trusting a READ/WRITE. */
|
||||
#define SCSI_CMD_TEST_UNIT_READY 0x00u
|
||||
#define SCSI_CDB_LEN_TEST_UNIT_READY 6u
|
||||
|
||||
/* Bounded retry count for SCSI TEST UNIT READY before giving up -- see
|
||||
* xhci_dev_t's bot_tur_retries doc comment. */
|
||||
#define XHCI_BOT_TUR_MAX_RETRIES 3u
|
||||
|
||||
/* Bulk-Only Transport Command Status Wrapper (same spec, section 5.2) --
|
||||
* received device-to-host on the bulk IN endpoint after the Data-In
|
||||
* stage, closing out every SCSI command. Fixed 13-byte wire layout; same
|
||||
|
||||
@@ -171,6 +171,29 @@ typedef struct {
|
||||
uint8_t bot_data_buf[512];
|
||||
uint32_t bot_expected_data_len;
|
||||
|
||||
/* Milestone 2g follow-up: TEST UNIT READY unit-init sequence, ahead of
|
||||
* a real READ(10). bot_cmd_kind says which SCSI command the CBW/CSW
|
||||
* currently in flight actually is, since XHCI_XFER_CSW_RECEIVED alone
|
||||
* doesn't distinguish a TUR completion from a READ10 completion --
|
||||
* both go through the identical CBW->Data-In(if any)->CSW chain.
|
||||
* bot_tur_retries counts TUR attempts that came back FAILED/PHASE
|
||||
* ERROR (a fresh SCSI target's standard first-command UNIT ATTENTION
|
||||
* behavior, not a driver defect -- see SCSI_CMD_TEST_UNIT_READY's own
|
||||
* doc comment in xhci.h); capped at XHCI_BOT_TUR_MAX_RETRIES. The
|
||||
* pending bot_read10_* fields latch a caller's requested READ(10) so
|
||||
* it can be issued once TUR reports PASS -- xhci_bot_read_block() is
|
||||
* the entry point that stages these and kicks off TUR first, rather
|
||||
* than callers driving xhci_bot_send_read10() directly. */
|
||||
enum {
|
||||
BOT_CMD_NONE = 0,
|
||||
BOT_CMD_TEST_UNIT_READY,
|
||||
BOT_CMD_READ10
|
||||
} bot_cmd_kind;
|
||||
uint32_t bot_tur_retries;
|
||||
uint32_t bot_read10_lba;
|
||||
uint16_t bot_read10_num_blocks;
|
||||
uint32_t bot_read10_block_size;
|
||||
|
||||
/* Deferred chaining: a doorbell ring (new control transfer) must
|
||||
* never happen synchronously from inside xhci_poll_events()'s event-
|
||||
* processing loop, before ERDP has been updated for the event
|
||||
@@ -189,7 +212,9 @@ typedef struct {
|
||||
XHCI_NEXT_ACTION_CONFIGURE_ENDPOINT,
|
||||
XHCI_NEXT_ACTION_SET_CONFIG,
|
||||
XHCI_NEXT_ACTION_BOT_DATA_IN,
|
||||
XHCI_NEXT_ACTION_BOT_CSW_RECEIVE
|
||||
XHCI_NEXT_ACTION_BOT_CSW_RECEIVE,
|
||||
XHCI_NEXT_ACTION_BOT_SEND_TUR,
|
||||
XHCI_NEXT_ACTION_BOT_SEND_READ10
|
||||
} next_action;
|
||||
uint32_t next_action_slot_id;
|
||||
uint16_t next_action_length;
|
||||
@@ -381,10 +406,73 @@ int xhci_cmd_configure_endpoint(xhci_dev_t *dev, uint32_t slot_id);
|
||||
*
|
||||
* Returns 0 if the CBW was posted, -1 if a prerequisite is missing or
|
||||
* the requested transfer size exceeds dev->bot_data_buf.
|
||||
*
|
||||
* Low-level primitive -- sets dev->bot_cmd_kind = BOT_CMD_READ10 but does
|
||||
* not run TEST UNIT READY first. Most callers want xhci_bot_read_block()
|
||||
* below instead; this is called directly only by xhci_poll_events()'s own
|
||||
* deferred dispatch (XHCI_NEXT_ACTION_BOT_SEND_READ10, once a prior TUR
|
||||
* has reported PASS) and by xhci_bot_read_block() itself when unit-ready
|
||||
* confirmation isn't wanted.
|
||||
*/
|
||||
int xhci_bot_send_read10(xhci_dev_t *dev, uint32_t slot_id, uint32_t lba,
|
||||
uint16_t num_blocks, uint32_t block_size);
|
||||
|
||||
/*
|
||||
* xhci_bot_send_test_unit_ready — build a Command Block Wrapper for SCSI
|
||||
* TEST UNIT READY (6-byte CDB, no data
|
||||
* stage) and submit it on the bulk OUT
|
||||
* Transfer Ring. Sets
|
||||
* dev->bot_expected_data_len = 0 so
|
||||
* xhci_poll_events()'s CBW-completion
|
||||
* handler skips the Data-In stage and
|
||||
* goes straight to CSW receive, per BOT
|
||||
* spec section 6.3 (host expects no
|
||||
* data). dev->bot_cmd_kind is set to
|
||||
* BOT_CMD_TEST_UNIT_READY so the CSW
|
||||
* handler knows to interpret the result
|
||||
* as a unit-ready check, not a data
|
||||
* command.
|
||||
*
|
||||
* Requires the same bulk endpoint/ring prerequisites as
|
||||
* xhci_bot_send_read10() -- refuses if any are missing.
|
||||
*
|
||||
* Called by xhci_bot_read_block() to start its TUR-then-READ10 sequence,
|
||||
* and by xhci_poll_events()'s own deferred dispatch
|
||||
* (XHCI_NEXT_ACTION_BOT_SEND_TUR) to retry a failed TUR -- not intended
|
||||
* to be called directly by other code.
|
||||
*
|
||||
* Returns 0 if the CBW was posted, -1 if a prerequisite is missing.
|
||||
*/
|
||||
int xhci_bot_send_test_unit_ready(xhci_dev_t *dev, uint32_t slot_id);
|
||||
|
||||
/*
|
||||
* xhci_bot_read_block — the real entry point for reading a block from the
|
||||
* attached SCSI device. Latches lba/num_blocks/
|
||||
* block_size into dev->bot_read10_*, resets
|
||||
* dev->bot_tur_retries to 0, and issues a TEST
|
||||
* UNIT READY first rather than a bare READ(10).
|
||||
*
|
||||
* A freshly attached SCSI target conventionally fails its first command
|
||||
* with CHECK CONDITION/UNIT ATTENTION until that condition is drained
|
||||
* (see SCSI_CMD_TEST_UNIT_READY's own doc comment in xhci.h) -- this
|
||||
* function's whole purpose is absorbing that via a bounded number of TUR
|
||||
* retries (XHCI_BOT_TUR_MAX_RETRIES) before the actual READ(10) is ever
|
||||
* sent, rather than making every caller reimplement that sequencing.
|
||||
* xhci_poll_events()'s deferred dispatch chains TUR -> (retry TUR |
|
||||
* READ10) -> Data-In -> CSW automatically once this call kicks it off;
|
||||
* the eventual result (PASS/FAILED, or "gave up after N TUR retries") is
|
||||
* only ever logged, matching xhci_bot_send_read10()'s own current scope
|
||||
* -- there is still no synchronous "did the read succeed, here's the
|
||||
* data" API (2h's problem, per xhci_bot_send_read10()'s doc comment).
|
||||
*
|
||||
* Returns 0 if TEST UNIT READY was posted, -1 if a prerequisite is
|
||||
* missing or the requested transfer size exceeds dev->bot_data_buf (the
|
||||
* same check xhci_bot_send_read10() performs, done up front here so a
|
||||
* bad request is rejected before spending a TUR round-trip on it).
|
||||
*/
|
||||
int xhci_bot_read_block(xhci_dev_t *dev, uint32_t slot_id, uint32_t lba,
|
||||
uint16_t num_blocks, uint32_t block_size);
|
||||
|
||||
/*
|
||||
* xhci_bot_read_data_in — submit a Normal TRB on the bulk IN Transfer
|
||||
* Ring to read dev->bot_expected_data_len bytes
|
||||
|
||||
Reference in New Issue
Block a user