Each disk in /api/hardware now carries a controller_slot, resolved from
the disk's sysfs device path: the deepest PCI address in that path is the
controller (bridges sit above it), normalised to lspci's slot format so it
matches pci_devices[].slot directly. NVMe falls back to the controller's
own sysfs link when the namespace resolves to a subsystem with no PCI
parent; zvols and other virtual devices get None.
Hardware page:
- The disk dialog shows its storage controller (click through to the
controller), and the PCI device dialog lists the disks attached to it.
- Storage controllers in the PCI Devices list get a badge with the
number of attached disks.
Storage view:
- /api/storage returns controller_slot on each physical disk plus a
controllers map (slot -> class, vendor, device, subsystem name,
driver), built from the cached `lspci -vmm` output so the Storage view
doesn't need the heavier /api/hardware enumeration.
- "Physical Disks & SMART Status" can group disks under their storage
controller, with a header showing the controller name, slot, driver
and disk count. Groups follow PCI slot order; disks with no resolvable
controller are listed last. USB disks keep their own section.
- The disk details dialog shows the storage controller on the Overview
tab.
- Grouping is opt-in via a new Storage Display card in Settings, stored
per browser (localStorage) and synced across open views, following the
existing nav-tab-order preference pattern. Off by default.
Also:
- Treat "IDE interface" as a storage controller, so SATA controllers left
in BIOS IDE mode (e.g. Intel 7 Series, ata_piix) appear in pci_devices
and disks behind them can be mapped.
- lspci prints "Device xxxx" when it has no subsystem name; that
placeholder is ignored so the chip name is shown instead.
- Add the missing sdevice field to the PCIDevice type.
Tests cover the sysfs path -> controller slot rule against real paths
from two PVE 9 hosts (SAS HBA, AHCI SATA, SATA in BIOS IDE mode, USB
behind a hub, NVMe behind chipset bridges), the non-zero PCI domain case
(Intel VMD), the NVMe multipath fallback, and get_storage_controllers'
lspci parsing including the "Device xxxx" placeholder and driver lookup.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>