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
+53
-5
@@ -3460,11 +3460,10 @@ arch afterward, no wedge. `logs/20260825-073235/amd64/`, `logs/20260825-073417/a
|
||||
split between this item and "identify/configure endpoints" above didn't leave a
|
||||
separate line for it, but it's new work, not folded silently into either neighbor —
|
||||
see writeup)
|
||||
- [ ] Get one real SCSI READ(10) working end to end — first proof the whole stack works,
|
||||
before write. **Partially exercised, not satisfied**: the CBW→Data-In→CSW mechanism
|
||||
itself is confirmed working (see writeup below), but the SCSI command itself returns
|
||||
CSW status FAILED against the current test fixture -- this item stays open until a
|
||||
READ(10) actually returns PASS with real data, not just a well-formed CSW
|
||||
- [x] Get one real SCSI READ(10) working end to end — first proof the whole stack works,
|
||||
before write. **Done 2026-08-25**: the earlier CSW status FAILED was exactly the
|
||||
UNIT ATTENTION condition flagged (not root-caused) in the prior writeup — a TEST UNIT
|
||||
READY unit-init sequence ahead of READ(10) was the fix, see writeup below
|
||||
- [ ] Implement CBW/data/CSW for SCSI WRITE(10) — this is where the earlier "read/write,
|
||||
unquestionable" requirement actually gets satisfied
|
||||
- [ ] Implement basic error/stall recovery (CSW failure status, endpoint stall clear) — at
|
||||
@@ -3650,6 +3649,55 @@ the SET_CONFIGURATION completion handler) was removed after capture; only
|
||||
Re-verified probe-free afterward, all three architectures, clean boots with no BOT activity:
|
||||
`logs/20260825-092701/amd64/`, `logs/20260825-092842/aarch64/`, `logs/20260825-093048/riscv64/`.
|
||||
|
||||
**TEST UNIT READY unit-init sequence, done 2026-08-25 — READ(10) now returns PASS.** Root-causes
|
||||
the CSW status FAILED flagged but not chased down in the previous increment: SBC-3/SPC-4 give a
|
||||
freshly attached SCSI target's first command a standing UNIT ATTENTION (media-change/reset
|
||||
notice), cleared once any command is issued and answered — a bare READ(10) with no retry, which
|
||||
is all the previous probe sent, was always going to eat that condition rather than clear it.
|
||||
`xhci_bot_send_test_unit_ready()` builds and sends the CBW for SCSI TEST UNIT READY (SPC-4
|
||||
section 6.33, opcode `0x00`, 6-byte all-zero CDB, no data stage) — mirrors
|
||||
`xhci_bot_send_read10()`'s CBW-build shape but sets `dCBWDataTransferLength = 0` /
|
||||
`bot_expected_data_len = 0`, which the existing `XHCI_XFER_CBW_SENT` completion handler now
|
||||
checks to skip straight to CSW receive rather than a Data-In stage that would never arrive (BOT
|
||||
spec section 6.3: zero-length command means no data phase).
|
||||
|
||||
A new `bot_cmd_kind` field (`BOT_CMD_NONE`/`BOT_CMD_TEST_UNIT_READY`/`BOT_CMD_READ10`) tags which
|
||||
SCSI command a given CBW→CSW round trip actually is, since `XHCI_XFER_CSW_RECEIVED` alone can't
|
||||
tell a TUR completion from a READ10 completion — both take the identical CBW→(Data-In)→CSW
|
||||
shape. The CSW-receive handler now branches on it: a TUR CSW PASS chains into the real READ(10)
|
||||
(`XHCI_NEXT_ACTION_BOT_SEND_READ10`, same deferred-dispatch pattern as every other chained
|
||||
request in this driver); a TUR FAILED/PHASE ERROR retries TUR itself
|
||||
(`XHCI_NEXT_ACTION_BOT_SEND_TUR`), bounded by a new `bot_tur_retries` counter against
|
||||
`XHCI_BOT_TUR_MAX_RETRIES` (3) so a target that's never going to clear UNIT ATTENTION can't spin
|
||||
the driver forever; a READ10 CSW completion is unchanged (terminal, logged only — 2h's problem
|
||||
per the prior increment's own doc comment, still true).
|
||||
|
||||
`xhci_bot_read_block()` is the new intended entry point tying this together — latches
|
||||
lba/num_blocks/block_size, resets the retry counter, and kicks off with TUR rather than a bare
|
||||
READ10, so callers get the UNIT ATTENTION handling for free instead of reimplementing it.
|
||||
`xhci_bot_send_read10()` itself is unchanged in behavior, just now also reachable via this
|
||||
chain (low-level primitive, most callers should prefer `xhci_bot_read_block()`).
|
||||
|
||||
Verified live via a temporary probe (written, run once, log captured, then reverted per this
|
||||
project's own probe convention) hot-attaching `disk/usb-thumbdrive-test.img` through the running
|
||||
instance's QMP socket (`blockdev-add` + `device_add usb-storage,bus=xhci0.0`) rather than at
|
||||
QEMU launch — exercises the same live-hotplug path 2e/2f's own writeups already use, and avoids
|
||||
needing the `-device usb-storage` flag added to any of the three `qemu` Makefile targets. Full
|
||||
chain, byte-identical to the design: `device configured` → `CBW (TEST UNIT READY) submitted` →
|
||||
`CSW status = FAILED` → `unit not ready -- retrying TEST UNIT READY` → `CBW (TEST UNIT READY)
|
||||
submitted` → `CSW status = PASS` → `unit ready -- issuing READ10` → `CBW (READ10) submitted` →
|
||||
`BOT Data-In read submitted` → `BOT Data-In read completed` → `CSW status = PASS`, data
|
||||
residue 0 throughout. Captured on amd64 only this increment (`logs/20260825-112924/amd64/`) —
|
||||
unlike 2g's own writeups, the other two architectures were not separately hotplug-verified with
|
||||
the probe active, since the mechanism itself (CBW/CSW dispatch, deferred `next_action` chaining)
|
||||
is architecture-independent code already proven identical across all three arches by every
|
||||
earlier BOT increment; only the probe-removed acceptance boot was re-run on all three. The probe
|
||||
(`XHCI_NEXT_ACTION_BOT_PROBE_READ_BLOCK` and its trigger in the SET_CONFIGURATION completion
|
||||
handler) was removed after capture; only `xhci_bot_send_test_unit_ready()`/
|
||||
`xhci_bot_read_block()` and their Transfer Event handling remain. Re-verified probe-free
|
||||
afterward, all three architectures, clean boots with no BOT activity: `logs/20260825-113813/amd64/`,
|
||||
`logs/20260825-114114/aarch64/`, `logs/20260825-114321/riscv64/`.
|
||||
|
||||
**2h. Integration with the existing block subsystem**
|
||||
- [ ] Wire a working USB MSC device into `blk_subsys_attach_device()` (or
|
||||
`blk_subsys_add_raw_device()`, whichever fits — confirm which, since USB is
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Capsule Block Manifest — Auto-generated
|
||||
<!-- Generated by mkcapsule --manifest 2026-08-25T13:30:17Z -->
|
||||
<!-- Generated by mkcapsule --manifest 2026-08-25T15:42:49Z -->
|
||||
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
||||
<!-- Hand-written justifications and immutability notes live -->
|
||||
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
||||
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+107
-3
@@ -132,6 +132,7 @@ int xhci_cmd_address_device(xhci_dev_t *dev, uint32_t slot_id,
|
||||
int xhci_cmd_configure_endpoint(xhci_dev_t *dev, uint32_t slot_id);
|
||||
int xhci_bot_send_read10(xhci_dev_t *dev, uint32_t slot_id, uint32_t lba,
|
||||
uint16_t num_blocks, uint32_t block_size);
|
||||
int xhci_bot_send_test_unit_ready(xhci_dev_t *dev, uint32_t slot_id);
|
||||
int xhci_bot_read_data_in(xhci_dev_t *dev, uint32_t slot_id);
|
||||
int xhci_bot_receive_csw(xhci_dev_t *dev, uint32_t slot_id);
|
||||
int xhci_ep0_get_device_descriptor(xhci_dev_t *dev, uint32_t slot_id);
|
||||
@@ -313,6 +314,11 @@ int xhci_bringup(xhci_dev_t *dev)
|
||||
dev->bot_next_tag = 1;
|
||||
dev->bot_last_tag = 0;
|
||||
dev->bot_expected_data_len = 0;
|
||||
dev->bot_cmd_kind = BOT_CMD_NONE;
|
||||
dev->bot_tur_retries = 0;
|
||||
dev->bot_read10_lba = 0;
|
||||
dev->bot_read10_num_blocks = 0;
|
||||
dev->bot_read10_block_size = 0;
|
||||
dev->next_action = XHCI_NEXT_ACTION_NONE;
|
||||
dev->next_action_slot_id = 0;
|
||||
dev->next_action_length = 0;
|
||||
@@ -666,6 +672,8 @@ int xhci_bot_send_read10(xhci_dev_t *dev, uint32_t slot_id, uint32_t lba,
|
||||
uint32_t data_len = (uint32_t)num_blocks * block_size;
|
||||
if (data_len > sizeof(dev->bot_data_buf)) return -1;
|
||||
|
||||
dev->bot_cmd_kind = BOT_CMD_READ10;
|
||||
|
||||
usb_bot_cbw_t *cbw = &dev->bot_cbw;
|
||||
cbw->dCBWSignature = USB_BOT_CBW_SIGNATURE;
|
||||
cbw->dCBWTag = dev->bot_next_tag++;
|
||||
@@ -714,6 +722,51 @@ int xhci_bot_send_read10(xhci_dev_t *dev, uint32_t slot_id, uint32_t lba,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xhci_bot_send_test_unit_ready(xhci_dev_t *dev, uint32_t slot_id)
|
||||
{
|
||||
if (!dev || !dev->bulk_out_ring || !dev->bulk_in_ring) return -1;
|
||||
if (dev->bulk_out_ep_addr == 0 || dev->bulk_in_ep_addr == 0) return -1;
|
||||
|
||||
dev->bot_cmd_kind = BOT_CMD_TEST_UNIT_READY;
|
||||
|
||||
usb_bot_cbw_t *cbw = &dev->bot_cbw;
|
||||
cbw->dCBWSignature = USB_BOT_CBW_SIGNATURE;
|
||||
cbw->dCBWTag = dev->bot_next_tag++;
|
||||
dev->bot_last_tag = cbw->dCBWTag;
|
||||
dev->bot_expected_data_len = 0; /* no data stage -- BOT spec section 6.3 */
|
||||
cbw->dCBWDataTransferLength = 0;
|
||||
cbw->bmCBWFlags = 0; /* direction is irrelevant when length is 0 */
|
||||
cbw->bCBWLUN = USB_BOT_CBW_LUN_DEFAULT;
|
||||
cbw->bCBWCBLength = SCSI_CDB_LEN_TEST_UNIT_READY;
|
||||
for (uint32_t i = 0; i < sizeof(cbw->CBWCB); i++) cbw->CBWCB[i] = 0;
|
||||
cbw->CBWCB[0] = SCSI_CMD_TEST_UNIT_READY; /* opcode 0x00, every other CDB byte reserved/zero */
|
||||
|
||||
dev->transfer_purpose = XHCI_XFER_CBW_SENT;
|
||||
dev->pending_transfer_slot_id = slot_id;
|
||||
|
||||
xhci_bulk_out_enqueue_and_ring(dev, slot_id, (uint64_t)(uintptr_t)cbw,
|
||||
USB_BOT_CBW_LENGTH,
|
||||
(XHCI_TRB_TYPE_NORMAL << XHCI_TRB_CONTROL_TYPE_SHIFT) |
|
||||
XHCI_TRB_CONTROL_IOC);
|
||||
console_println("xhci: CBW (TEST UNIT READY) submitted");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xhci_bot_read_block(xhci_dev_t *dev, uint32_t slot_id, uint32_t lba,
|
||||
uint16_t num_blocks, uint32_t block_size)
|
||||
{
|
||||
if (!dev || !dev->bulk_out_ring || !dev->bulk_in_ring) return -1;
|
||||
if (dev->bulk_out_ep_addr == 0 || dev->bulk_in_ep_addr == 0) return -1;
|
||||
if ((uint32_t)num_blocks * block_size > sizeof(dev->bot_data_buf)) return -1;
|
||||
|
||||
dev->bot_read10_lba = lba;
|
||||
dev->bot_read10_num_blocks = num_blocks;
|
||||
dev->bot_read10_block_size = block_size;
|
||||
dev->bot_tur_retries = 0;
|
||||
|
||||
return xhci_bot_send_test_unit_ready(dev, slot_id);
|
||||
}
|
||||
|
||||
/* Enqueue one Normal TRB to the bulk IN Transfer Ring and ring its
|
||||
* doorbell -- same shape as xhci_bulk_out_enqueue_and_ring() (a BOT
|
||||
* Data-In or CSW read is, like a CBW send, always exactly one TRB), just
|
||||
@@ -1290,8 +1343,16 @@ void xhci_poll_events(void)
|
||||
/* Deferred (see xhci_dev_t's next_action doc
|
||||
* comment) rather than called directly --
|
||||
* same doorbell-ordering hazard as every
|
||||
* other chained request in this driver. */
|
||||
dev->next_action = XHCI_NEXT_ACTION_BOT_DATA_IN;
|
||||
* other chained request in this driver.
|
||||
* dCBWDataTransferLength == 0 (TEST UNIT
|
||||
* READY) means no Data-In stage exists --
|
||||
* BOT spec section 6.3 -- so skip straight to
|
||||
* CSW receive. */
|
||||
if (dev->bot_expected_data_len == 0) {
|
||||
dev->next_action = XHCI_NEXT_ACTION_BOT_CSW_RECEIVE;
|
||||
} else {
|
||||
dev->next_action = XHCI_NEXT_ACTION_BOT_DATA_IN;
|
||||
}
|
||||
dev->next_action_slot_id = xfer_slot_id;
|
||||
break;
|
||||
}
|
||||
@@ -1310,9 +1371,14 @@ void xhci_poll_events(void)
|
||||
* misread as a clean pass. */
|
||||
if (dev->bot_csw.dCSWSignature != USB_BOT_CSW_SIGNATURE) {
|
||||
console_println("xhci: CSW signature mismatch -- discarding");
|
||||
break;
|
||||
} else if (dev->bot_csw.dCSWTag != dev->bot_last_tag) {
|
||||
console_println("xhci: CSW tag mismatch -- discarding");
|
||||
} else if (dev->bot_csw.bCSWStatus == USB_BOT_CSW_STATUS_PASS) {
|
||||
break;
|
||||
}
|
||||
|
||||
int csw_pass = (dev->bot_csw.bCSWStatus == USB_BOT_CSW_STATUS_PASS);
|
||||
if (csw_pass) {
|
||||
console_println("xhci: CSW status = PASS");
|
||||
} else if (dev->bot_csw.bCSWStatus == USB_BOT_CSW_STATUS_FAILED) {
|
||||
console_println("xhci: CSW status = FAILED");
|
||||
@@ -1320,6 +1386,30 @@ void xhci_poll_events(void)
|
||||
console_println("xhci: CSW status = PHASE ERROR");
|
||||
}
|
||||
xhci_log_hex32("xhci: CSW data residue=", dev->bot_csw.dCSWDataResidue);
|
||||
|
||||
/* TEST UNIT READY completions chain into the
|
||||
* actual READ(10) once PASS, or retry (bounded)
|
||||
* on 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 doc comment in
|
||||
* xhci.h). READ10 completions are terminal --
|
||||
* this driver has no synchronous caller to
|
||||
* report back to yet (2h's problem). */
|
||||
if (dev->bot_cmd_kind == BOT_CMD_TEST_UNIT_READY) {
|
||||
if (csw_pass) {
|
||||
console_println("xhci: unit ready -- issuing READ10");
|
||||
dev->next_action = XHCI_NEXT_ACTION_BOT_SEND_READ10;
|
||||
dev->next_action_slot_id = xfer_slot_id;
|
||||
} else if (dev->bot_tur_retries < XHCI_BOT_TUR_MAX_RETRIES) {
|
||||
dev->bot_tur_retries++;
|
||||
console_println("xhci: unit not ready -- retrying TEST UNIT READY");
|
||||
dev->next_action = XHCI_NEXT_ACTION_BOT_SEND_TUR;
|
||||
dev->next_action_slot_id = xfer_slot_id;
|
||||
} else {
|
||||
console_println("xhci: unit still not ready -- giving up on READ10");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -1398,5 +1488,19 @@ void xhci_poll_events(void)
|
||||
if (xhci_bot_receive_csw(dev, next_slot_id) != 0) {
|
||||
console_println("xhci: deferred CSW receive setup failed");
|
||||
}
|
||||
} else if (dev->next_action == XHCI_NEXT_ACTION_BOT_SEND_TUR) {
|
||||
uint32_t next_slot_id = dev->next_action_slot_id;
|
||||
dev->next_action = XHCI_NEXT_ACTION_NONE;
|
||||
if (xhci_bot_send_test_unit_ready(dev, next_slot_id) != 0) {
|
||||
console_println("xhci: deferred TEST UNIT READY retry setup failed");
|
||||
}
|
||||
} else if (dev->next_action == XHCI_NEXT_ACTION_BOT_SEND_READ10) {
|
||||
uint32_t next_slot_id = dev->next_action_slot_id;
|
||||
dev->next_action = XHCI_NEXT_ACTION_NONE;
|
||||
if (xhci_bot_send_read10(dev, next_slot_id, dev->bot_read10_lba,
|
||||
dev->bot_read10_num_blocks,
|
||||
dev->bot_read10_block_size) != 0) {
|
||||
console_println("xhci: deferred READ10 setup failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user