post systems

Post

Putting an RTX 3090 in an HP ProLiant ML350 Gen9

We have been running low-bit quantization experiments on CPU only. It works, and it is slow enough that the feedback loop hurts — a context-depth sweep is most of an afternoon. The GPUs we already own are doing production work, so borrowing one was not an option. What we did have spare was an older dual-socket ML350 Gen9 tower with 512 GB of RAM, which is a good shape for MoE expert offload and had no GPU at all. So: a second-hand RTX 3090, blower-style, into an enterprise tower that was never designed for one.

From shutdown to the first successful lspci enumeration was 5 hours 40 minutes. During that window we changed the GPU power leads, the slots, the card seating, and BIOS settings — and I cannot honestly tell you which single change fixed it. The first version of this post claimed I could. It was wrong, and the corrected story is more useful.

§The fault signature

On the failed boots, the card’s blower spun but the GPU and its audio function were absent from lspci. dmesg had no useful NVIDIA or link-training event, and the server’s management controller did not identify a working device in the slot.

That is a pre-driver enumeration failure. It tells you that Linux never received a usable PCIe function — and nothing more. Auxiliary power, a partially seated power plug, a card-edge contact problem, slot or link behaviour, firmware, or a faulty card can all produce exactly this signature. Fan spin proves that some power reached the board; it does not prove that every required rail or contact path was correct.

§What changed — and what we did not prove

HPE does not use standard PCIe power connectors internally. The power distribution board exposes proprietary 10-pin GPU headers, and the official lead already in this server terminated in one 8-pin and one 6-pin plug — sized for the Tesla-era cards these machines were sold with. This RTX 3090 has two 8-pin sockets. The card did not enumerate with that lead, and I would not use that connector mismatch as the final wiring for this card.

I then supplied two full 8-pin plugs from two separate PDB outputs. The GPU still did not enumerate in slot 3. It remained absent after I moved it to slot 6, and it was still absent there after I manually forced global PCIe Gen1. So correct 8+8 power was not, by itself, the observed fix — which is the fact that breaks the tidy “it was the cable” story.

The first successful enumeration came when I moved the card from slot 6 back to slot 3 — which necessarily reseated its PCIe edge connector, and may well have disturbed the auxiliary plugs too; I did not record their handling at that step. Because multiple physical contacts changed together, I cannot distinguish a card-edge seating issue, an auxiliary-connector contact or odd pin, slot behaviour, or an interaction among them. A power-sense-pin explanation is possible, but nothing was measured that would establish it.

The attempts, compressed:

GPU power / placement PCIe setting Result
Official 8+6 lead, slot 3 Gen3 (max) absent
Two separate 8-pin feeds, slot 3 Gen3 (max) absent
Two separate 8-pin feeds, slot 6 Gen3 (max) absent
Two separate 8-pin feeds, slot 6 Forced Gen1 absent
Same power, card moved/reseated into slot 3 Gen1 first enumeration
One 10-pin → 8+8 lead, one PDB output, slot 3 Gen1 present
Same physical setup Restored to Gen3 present at Gen3 x16

Two things this table does support. First: fix the physical layer before touching BIOS options — every result taken while the card cannot enumerate is noise, and I spent hours in setup menus generating it. Second: when the failure signature is “absent, no error anywhere”, suspect contact in the broadest sense — power plugs, card seating, slot — and change one thing at a time, which is exactly what I failed to do.

After the card was visible, I deliberately simplified to one 10-pin → 8+8 lead from a single PDB output (sold for this purpose as ML350G9010-8P8A). The GPU stayed visible, trained at Gen3 x16 when I restored the BIOS setting, and later sustained 271–273 W of measured board power under a 275 W cap on that single lead. That establishes the final working configuration — one verified Gen9 lead, one PDB output, slot 3 (CPU1), Gen3 x16 — not the cause of the earlier failures.

On proprietary leads generally: the wires are all black, so verify ground and 12 V end-to-end with a meter and a pinout for the exact server generation before connecting a GPU. I saw marketplace leads labelled for other generations; I did not test them and would not publish claims about their pinouts. Meter, don’t trust.

§What the Gen1 detour actually showed

Forcing Gen1 through the Redfish API returned success and silently did nothing on this firmware — the NVMe stayed at 8 GT/s. Changing it manually in the setup menus did apply. The GPU still failed at Gen1 in slot 6, and it first appeared at Gen1 only after the move into slot 3, then stayed healthy when restored to Gen3 x16.

So Gen1 was neither necessary nor sufficient, and the general lesson stands: verify BIOS changes from the OS, not from the management API’s view of them. (Related: this generation’s “PCI Express 64-Bit BAR Support” toggle lives in the hidden Ctrl+A service options, not the normal menus — ours was already enabled.)

§The other PCIe problem: the NVMe carrier

The GPU was not the only card that disappeared during this work. On the first post-install boot the NVMe controller was also absent and its ZFS pool with it. Reseating brought it back — and later, restoring the bus from Gen1 to Gen3 left the GPU healthy but made the NVMe controller vanish in its then-current slot. In one placement it trained at Gen3 x1; at Gen1 it reported x4. I relocated the carrier to a CPU2-connected slot, where it came back and eventually settled at Gen3 x4, and the ZFS pool imported cleanly every time the controller was present — no data loss, just absence.

The warning worth carrying: physical connector size, electrical lane width, slot topology, seating, and Gen3 signal margin all affect what enumerates and at what width. After every card move, check every PCIe device with lspci, read LnkSta for negotiated width and speed, and verify your storage pools — before declaring the GPU problem solved. I would describe what we saw as link and placement sensitivity rather than a proven bad slot; the transcript does not isolate which.

§Driver, on a Proxmox host

I installed NVIDIA’s .run package (580.95.05) with --dkms: the build succeeded against the running 6.8 Proxmox kernel and registered with DKMS for future kernel rebuilds (registration verified; an actual kernel bump has not been through it yet). Blacklist nouveau first — it grabs the card — then update-initramfs -u and reboot. I did not test the distribution’s nvidia-driver packages or the CUDA-repo route on this host, so I make no claim about them.

The power limit went on before any load: nvidia-smi -pl 275, made persistent with a systemd oneshot running nvidia-smi -pm 1 then -pl 275. I did not test 350 W and did not measure the PDB header’s current rating or connector temperature — the conservative cap is exactly that, a conservative cap on a header of unmeasured rating.

§Validating a second-hand card

Two things a spec sheet cannot tell you about a used card: whether the memory is silently wrong, and whether it cooks.

This card exposes no ECC, so a memory fault can corrupt a numerical result without any report — in an inference workload that surfaces as a quality regression you would blame on your own code. (Bad memory can also fail loudly; the silent case is the one worth ruling out.) memtest_vulkan, two ~10-minute passes: zero errors. Zero with a witness rather than zero by assumption.

nvidia-smi reports Memory Current Temp: N/A on this card, so for the number that matters on a 3090 — the GDDR6X junction — I used the open-source gddr6 utility, which produced stable, repeatable readings. Measured across a 10-minute memtest_vulkan run at the 275 W cap:

idle peak under load
GDDR6X junction 34–36 °C (pre-load probe); 42 °C min in-run 92 °C (620 samples)
GPU core 26 °C 75 °C
Power 8 W 271–273 W (cap 275)
Sustained memory bandwidth 540–648 GB/s

The only limit reason active at any point was the software power cap; the sampled thermal-slowdown counters stayed at zero for the whole run. Those results gave me no measured reason to open the card up and repad it — a card idling in the mid-30s is not showing cooked-pad behaviour — though they do not by themselves prove pad condition.

§A clock that looks broken and isn’t

During the memory test the core clock sat around 885 MHz against the card’s reported 2100 MHz maximum. That looks like a sick card. The measurements say otherwise: memory utilisation was pinned, board power was riding the 275 W cap, and the active limit reason was the software cap — never thermal. A memory-saturating test being power-limited with a low core clock is consistent behaviour, not a fault. I have not yet run a compute-bound clock test, so I will not quote a number for one.

Read the throttle reason, not the clock — and read the idle temperature, not just the peak.

§Two fans, two numbers

There are two separate fan readings in this build and it is easy to conflate them. The RTX 3090’s own blower idles at 30% (from nvidia-smi). The chassis fans, read from the management controller, sat at 35% on two of eight positions (18% on two more, the rest at zero) while everything in the box measured 21–43 °C. The result is audibly noisier than the server was before the card went in. I have not isolated why the chassis controller holds those speeds — by the time I looked, the GPU, NVMe carrier, NIC, slot layout and BIOS state had all changed — so the fan-noise investigation is its own job for another day.

§Next

The point of all this is throughput on quantization work, so what comes next is running real workloads and reporting what the numbers look like, rather than what a spec sheet implies. There is also an orchestration layer that shares this single card across several tenants with admission control and leases, since 24 GB does not go far and nothing on a GeForce card gives you hardware isolation. That is its own post.

I did not find a confirmed report of this exact card in this exact server in the searching done along the way, which is the main reason this is written down.


Revised 2026-08-13. The first version of this post claimed the root cause was the 8+6 power lead, with a sense-pin mechanism. An audit of the session transcript showed that 8+8 power was already connected during several failed attempts, and that first success coincided with reseating the card — so the cause was never isolated, and several supporting claims were research assertions rather than measurements. This version reports what was actually observed. The meta-lesson: change one thing at a time, and write down which thing you changed.