During boot on GCE c4a-metal instances, the NVMe driver failed to attach
because bus_get_domain() returned a garbage NUMA domain ID, leading to a
kernel panic during MSI-X allocation.
In the FreeBSD Newbus architecture, only the immediate parent bus knows
the layout of its child's Instance Variables (IVARs). acpi0 knows the
layout of struct acpi_device for its direct children, while pci0 knows
struct pci_devinfo for PCI devices.
When bus_get_domain() is called on a grandchild PCI device (e.g. nvme0
under pci1 -> pcib1 -> pci0), the request delegates up to acpi0.
However, acpi_get_domain_method() incorrectly passed the original
grandchild device_t to acpi_read_ivar(), casting a struct pci_devinfo
pointer to struct acpi_device. This type confusion read garbage data
from the PCI device info structure as the domain ID.
Fix this by walking up the device tree in acpi_get_domain_method() to
identify the ancestor that is a direct child of acpi0 (the PCI Host
Bridge, e.g. pcib0). The ACPI domain IVAR is then safely read from this
direct child. This pattern matches existing ancestor-walking logic in
acpi_get_cpus().
Note: The SRAT, DSDT, and APIC dumps are on freebsd.org/~ziaee/tmp/c4a-*
Authored by: Jasper Tran O'Leary <jtranoleary@google.com>
Sponsored by: Google Cloud