Skip to content

fix(async): complete block writes from OUTPUT_LAST status - #84

Open
gly11 wants to merge 9 commits into
mrmidi:devfrom
gly11:sbp2/fix-orb-pointer-completion
Open

fix(async): complete block writes from OUTPUT_LAST status#84
gly11 wants to merge 9 commits into
mrmidi:devfrom
gly11:sbp2/fix-orb-pointer-completion

Conversation

@gly11

@gly11 gly11 commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Summary

  • complete two-descriptor async block writes from the terminal OUTPUT_LAST descriptor
  • keep pending chains untouched until the terminal descriptor has a non-zero transfer status
  • add focused host tests for completed and still-pending OUTPUT_MOREOUTPUT_LAST chains
  • keep the ring releasable when the chain is recognized but the context has already stopped

Root cause

ASFW scans AT completions from the ring head. For a block write, the ring head is an immediate OUTPUT_MORE header and the payload is an OUTPUT_LAST descriptor. The tested OHCI controller records the completion status on OUTPUT_LAST while leaving the precursor status at zero. The scanner therefore treated a completed packet as pending forever, so the SBP-2 ORB_POINTER write kept its tLabel outstanding and the command path stalled after the first successful INQUIRY.

This behavior matches the Linux OHCI implementation, which assigns and reads packet completion from the chain's last descriptor. The same compatibility handling existed in the earlier SBP-2 bring-up work from #14 but was lost during the later async-stack refactor.

Impact

The fix is transport-level and applies to any async block write that uses the standard immediate-header plus payload descriptor chain. It does not add SBP-2-specific knowledge to the async layer.

Validation

Host and build

  • ATContextCompletionTests: 5/5 passed
  • full C++ host suite: 1,545 passed, 6 conditional skips
  • pinned XcodeGen regeneration produced no tracked project drift
  • Debug Xcode build with the experimental SCSI HBA enabled: succeeded with signing disabled on the original head
  • GitHub Build and Test check: passed on the stacked dev head

Hardware

Validated on an Epson V750 Pro / GT-X970 SBP-2 scanner with the rebuilt dext installed:

  • ASFWDriver 0.2.0/2 activated and enabled
  • scanner enumerated as an SBP-2 unit
  • SBP-2 login completed successfully
  • status blocks completed without ORB timeout, ORB-pointer write failure, or unmatched-response errors
  • target 0 / LUN 0 appeared in IORegistry and system_profiler
  • diagnostic log ring reported droppedRecords = 0

The original hardware blocker is resolved. This PR is ready for review.

Dependency and merge order

Depends on #88. This PR now targets dev and is stacked directly on the current #88 head.

Until #88 merges, GitHub's Files changed view for this PR will also include #88's CI/project-generation changes. The #84-specific review scope is the top two async commits and these three files:

  • ASFWDriver/Async/Contexts/ATContextBase.hpp
  • tests/async/ATContextCompletionTests.cpp
  • tests/async/CMakeLists.txt

Intended merge order:

  1. merge fix(build): pin XcodeGen for CI and local builds, stabilize test failure reporting #88 into dev;
  2. update fix(async): complete block writes from OUTPUT_LAST status #84 onto the resulting dev tip if GitHub does not collapse the stacked diff automatically, retaining only the two async commits;
  3. merge fix(async): complete block writes from OUTPUT_LAST status #84 after its checks pass.

Please merge #88 before #84.

@gly11
gly11 force-pushed the sbp2/fix-orb-pointer-completion branch 3 times, most recently from febe8f5 to 22db267 Compare July 26, 2026 10:43
@gly11
gly11 marked this pull request as ready for review July 27, 2026 13:12

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f0236dca2b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ASFWDriver/Async/Contexts/ATContextBase.hpp Outdated
gly11 added 8 commits July 28, 2026 18:17
The pin added earlier in this branch only bound CI. build.sh still ran
whatever xcodegen was on PATH, and it regenerates ASFW.xcodeproj on every
non-test-only build. Homebrew currently ships 2.46.0 while the pin was
2.45.4, and their output is not byte-identical -- 2.46.0 reorders the
pbxproj `targets` array. So a single ./build.sh on a brew-current machine
produces a project the drift check rejects, and that check's error message
tells you to regenerate, which reproduces the same diff.

Move the version and its SHA-256 into .xcodegen-version and have both the
workflow and build.sh read it, so the two can no longer disagree.

build.sh now stops with an actionable error when the installed version
differs, rather than warning and skipping regeneration: a build silently
missing a newly added source file is much harder to diagnose than a version
mismatch. --no-xcodegen builds the committed project as-is for machines that
can't install the pin.

Bump the pin to 2.46.0 to match what Homebrew ships today, and regenerate
ASFW.xcodeproj with it. The only change is the `targets` array ordering,
which has no semantic effect.

Document how to install the pinned release in README -- the same download,
pin, and checksum CI uses -- since "install the pinned version" isn't
actionable without it.
@gly11
gly11 force-pushed the sbp2/fix-orb-pointer-completion branch from bd3a8bb to 6594e52 Compare July 28, 2026 11:50
@gly11
gly11 changed the base branch from main to dev July 28, 2026 11:51
InspectChainTail() returns Pending for a recognized OUTPUT_MORE_IMMEDIATE +
OUTPUT_LAST chain whose tail status is still zero, and ScanCompletion() then
returns without consulting the orphan path. That is correct while the context
is running, but a quiesced context will never write a status, so the ring head
stayed pinned to the chain forever.

Gate the Pending result on the context still being live. run==0 && active==0
falls through to HandlePendingDescriptor(), restoring the drain that existed
before this branch was introduced.

The check is deliberately narrower than IsOrphanedDescriptor(): its second
clause (commandPtr != headIOVA) also matches a live chain whose command pointer
has advanced to a pending OUTPUT_LAST, which is the false positive the Pending
result was added to fix. Only the run/active bits are consulted here, so both
cases keep working.

Both references drain unconditionally once the context is stopped, rather than
inferring liveness during the scan:

  - Linux gates handle_at_packet()'s early return on !ctx->flushing and calls
    at_context_flush() after context_stop() (ohci.c:1364, 2000-2010), citing
    OHCI 1.2 draft clause 7.2.3.3 — hardware may leave unsent packets in the
    AT queues for software to drain.
  - AppleFWOHCI 5.5.9 calls resetDMA() after stopDMA() in handleBusResetInt()
    (symbol offsets 0x5fae-0x5fd2); resetDMA() frees every pending ATxElement
    regardless of status.

Apple can also afford to keep scanning past a zero-status element because its
pending set is a linked list; a single head cursor cannot. Correct the
ScanCompletion() doc comment accordingly. An explicit flush entry point is the
real fix and is left to a follow-up; this keeps the ring releasable meanwhile.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant