Skip to content

nvme: fix controller init for Windows Server 2025 / Windows 11 24H2 - #1199

Draft
daberkow wants to merge 1 commit into
masterfrom
daberkow/nvme-win2025-bug
Draft

nvme: fix controller init for Windows Server 2025 / Windows 11 24H2#1199
daberkow wants to merge 1 commit into
masterfrom
daberkow/nvme-win2025-bug

Conversation

@daberkow

Copy link
Copy Markdown

The rewritten stornvme made Windows Server 2025 (26100) and Windows 11 24H2 not see any NVMe disk; Setup reports "a media driver your computer needs is missing" while Server 2019/2022 and Windows 10 install fine. Two defects in the NVMe emulation combine to cause this:

  1. AQA/ASQ/ACQ reads returned nothing while the controller was enabled. The spec restricts writes to these registers while CC.EN=1, but reads must always return the last-written value. stornvme reads ASQ back right after its first Identify Controller completes and treats the zero readback as a fatal adapter error (CM_PROB_FAILED_START, STATUS_ADAPTER_HARDWARE_ERROR), tearing the device down after exactly one successful admin command. Make the reads unconditional.

  2. Async Event Requests were completed with Invalid Opcode + DNR, on the rationale that QEMU does the same; that comment is stale (modern QEMU implements AER). stornvme ignores DNR and immediately resubmits, producing a permanent ~8k cmd/s admin loop during which boot of the installed OS never proceeds. Park AER permits, retaining them until controller reset, as the spec prescribes; no events are ever posted.

Verified on bhyve/Helios: Server 2025 installs end-to-end to the logon screen (4 parked AERs per controller at steady state), Windows 11 installs to OOBE, and Server 2022 still installs on the same build.

Known limitation: parked AER permits are not preserved across live migration export/import.

The rewritten stornvme in Windows Server 2025 (26100) and Windows 11 24H2
could not see any NVMe disk; Setup reports "a media driver your computer
needs is missing" while Server 2019/2022 and Windows 10 install fine.
Two defects in the NVMe emulation combine to cause this:

1. AQA/ASQ/ACQ reads returned nothing while the controller was enabled.
   The spec restricts *writes* to these registers while CC.EN=1, but
   reads must always return the last-written value. stornvme reads ASQ
   back right after its first Identify Controller completes and treats
   the zero readback as a fatal adapter error (CM_PROB_FAILED_START,
   STATUS_ADAPTER_HARDWARE_ERROR), tearing the device down after exactly
   one successful admin command. Make the reads unconditional.

2. Async Event Requests were completed with Invalid Opcode + DNR, on the
   rationale that QEMU does the same; that comment is stale (modern QEMU
   implements AER). stornvme ignores DNR and immediately resubmits,
   producing a permanent ~8k cmd/s admin loop during which boot of the
   installed OS never proceeds. Park AER permits, retaining them until
   controller reset, as the spec prescribes; no events are ever posted.

Verified on bhyve/Helios: Server 2025 installs end-to-end to the logon
screen (4 parked AERs per controller at steady state), Windows 11
installs to OOBE, and Server 2022 still installs on the same build.

Known limitation: parked AER permits are not preserved across live
migration export/import.

@iximeow iximeow left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

as i'd mentioned in chat: thanks for taking a look at this! it's good that server 2025 is relatively close to being OK with Propolis :) i realize this is something of a "draft/wdyt", i don't necessarily expect you to do things with this review but this hopefully demonstrates the bar i'd want us to hold ourselves to when looking at changing device emulation like this. getting into it:

The rewritten stornvme

what do you mean by rewritten? i didn't (quickly!) find anything about a substantial rewrite of Windows' NVMe driver lately, so i'm not sure how to read this or of we're just seeing some relatively minor additions to the driver that happen to interact poorly with our emulated device.

and treats the zero readback as a fatal adapter error (CM_PROB_FAILED_START, STATUS_ADAPTER_HARDWARE_ERROR)

i assume this is just determined empirically from "it now does not read as zero, and does not report that the hardware has errored"? was there a more direct debugging path that got you here?

stornvme ignores DNR and immediately resubmits,

bummer. i assume you found this with a bit of dtrace on the nvme probes?

Park AER permits, retaining them until controller reset, as the spec prescribes

"Park" is not an NVMe term of art, right? i think you mean to say that this patch accepts whatever the guest might have written to AsyncEventReq, and we just do nothing to ever fulfill that async event request. "Parking" at least to me sounds like it's gesturing at some NVMe idea of an "idle" AER which is mostly just confusing.

4 parked AERs per controller at steady state

how did you measure this? it's not directly exposed here, and it's not like there's a specific probe when AERs are received, is there some careful dtrace or is this just "added some println() and only saw four requests"?

migration, testing

it seems pretty straightforward to say we should be able to migrate oustanding AERs with the rest of the controller configuration, so unless we're under time pressure lets not make NVMe migration worse off? 😁

when i'd mentioned testcases earlier, i was thinking of, basically, the shape of test environment i'd set up in #966. clearly that's not in yet, so it's hard to build on that :) i'll get that sorted next week when i'm properly back and get you something reasonable to build on. but that's really where i think we'd want to remark that "such and such behavior is important for [at least] such and such guest, and is described by NVMe rev X.Y section A.B.C, ..." rather than on (kinda arbitrary) fields of controller state.

Comment on lines +1058 to +1062
// These registers may only be modified while the controller
// is disabled, but reads must always return the last value
// written (NVMe 1.0e Section 3.1; e.g. Windows Server 2025's
// stornvme reads ASQ back after enabling the controller and
// treats a mismatch as a fatal adapter error).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

what part of 1.0e section 3.1 says this, to you? I see 3.1.7 talks about AQA and in particular defines ACQS and ASQS as RW. from 3.1.7 it's not clear to me what the write semantic should be (do these hold the "next" admin queue settings, latched into place when CC.EN is next set to 1?)

the actual answer here looks to me to be 3.1.5 Offset 14h: CC - Controller Configuration where EN says these must simply not be written to. I'd actually strike the comment here (this is in the read path, you're allowed to read the register, it should read as what the device is configured for), and note this where we presumably drop the write if the controller is active.

Comment on lines +1374 to +1380
// Async Event Requests remain outstanding until an event
// occurs (which we never post) or the controller is
// reset; they do not receive an immediate completion.
// Completing them with an error instead sends some
// guests (e.g. Windows Server 2025's stornvme) into a
// tight resubmit loop, despite the do-not-retry flag.
state.parked_aers.push(permit);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would be curious about the qemu archaeology of either growing AER support or doing what this patch proposes; if the existing comment no longer describes qemu, what was qemu's change? if it's just "qemu supports AERs", well, okay then.

// Completing them with an error instead sends some
// guests (e.g. Windows Server 2025's stornvme) into a
// tight resubmit loop, despite the do-not-retry flag.
state.parked_aers.push(permit);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

also we definitely need to have correct error behavior when the guest creates more than AERL-many oustanding AERs, and we really ought to make sure the AER is sensible before deciding to imply we're tolerating it by not immediately completing with an error.

Comment on lines +203 to +205
/// Async Event Requests parked until an event is posted or the
/// controller is reset (see the AsyncEventReq admin command handling).
parked_aers: Vec<queue::Permit>,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

same nit here about "parked"; i'd just call these "outstanding AERs" and we should do ourselves the favor of at least retaining the log page an AER has registered interest in, at this point.

realistically, I think we would want something like a BTreeMap from log pages to outstanding event information or outstanding AERs. it's not like looking through a list of four entries for a matching AER is that bad, but that would help keep the semantics of things like

When the controller posts a completion queue entry for an outstanding Asynchronous Event Request command and thus reports an asynchronous event, subsequent events of that event type are automatically masked by the controller until the host clears that event.

a bit clearer.

// set. Do the same so that guest drivers that check for
// this can detect it and stop posting async events.
cmds::Completion::generic_err(bits::STS_INVAL_OPC).dnr()
// Async Event Requests remain outstanding until an event

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

what are the log pages that Server 2025 (and Windows 11) want to monitor? in 1.0e there's Error Information, SMART / Health Information, and Firmware Slot Information which are all mandatory and i can forgive just setting up AERs for those. but you said that Windows sets up four AERs - what's the last one!

later NVMe spec versions have many more log pages defined, but i'm not sure which are madatory or not, etc

@daberkow daberkow added bug Something that isn't working. storage Related to storage devices/backends. local storage Relating to the local storage project labels Aug 22, 2026
@daberkow
daberkow marked this pull request as draft August 22, 2026 13:49
@daberkow

Copy link
Copy Markdown
Author

Hi, I apologize Claude wrote some of that and I fully defer to you. This was meant as more of a proof of concept and a conversation starter about this issue. With Windows 11 and Server 2025 introducing things like DirectStorage, they have rewritten a lot of the NVMe driver, and it seems to be tripping up the NVMe interface.
Luckily, its very easy to test because the installer either sees storage and works or immediately throws and error that it cant find storage. I can put together an image for testing and we can work on this in the next few weeks. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something that isn't working. local storage Relating to the local storage project storage Related to storage devices/backends.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants