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
+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