Written by ChatGPT. This post was generated entirely by ChatGPT. The investigation and commands are real; the prose was not human-written.

Diagnosing Intel RST NVMe remapping, finding HP’s hidden AHCI setting, changing the PchSetup UEFI variable, and verifying native NVMe operation in NixOS

Status: Resolved successfully

Confirmed platform: HP 348 G7, motherboard 86CB, Insyde BIOS F.47

1. Overview and confirmed scope

This HP 348 G7 had a normal SATA hard disk that Linux could use, plus an internal M.2 NVMe device that the firmware appeared to recognize. Linux showed the SATA disk as /dev/sda, but it did not expose /dev/nvme0n1.

The problem was not partitioning, formatting, a missing mount point, or a physically absent device. Intel Rapid Storage Technology had remapped the NVMe device behind the chipset’s RAID-mode storage controller. The Linux AHCI driver could detect that a remapped NVMe existed, but it could not present the device as a normal NVMe block device.

On many laptops the solution is simply to change the storage mode in the BIOS from RAID or Intel RST to AHCI. On this HP model, the firmware supported AHCI but HP did not expose the required setting in the normal BIOS interface.

The final solution was to inspect the exact firmware running on this laptop, extract its UEFI setup forms, identify the hidden PchSetup variable and its offsets, back up the live variable, change the controller mode from RAID to AHCI, reboot, and verify that Linux could see the NVMe natively.

The critical persistent change was:

PchSetup[0x42] = 0x00   # AHCI

After reboot, the Intel controller changed from RAID device 8086:282a to AHCI device 8086:9d03, and the Intel Optane module appeared independently as NVMe device 8086:2522 at PCI address 03:00.0.

This document preserves the complete investigation, including dead ends, exact commands, firmware identifiers, offsets, hashes, warnings, write verification, post-reboot checks, and later conclusions.

The variable offsets in this document were reverse-engineered and verified for this exact combination:

Laptop:                     HP 348 G7
Motherboard:                HP 86CB
BIOS vendor:                Insyde
BIOS version:               F.47
BIOS release date:          03/24/2026
Platform firmware revision: 15.47
Embedded controller:        97.11

Do not assume that PchSetup offset 0x42, offset 0x61D, the variable size, or even the same GUID will be valid on another model or a later firmware version. Re-extract and inspect the IFR for any different board or BIOS release.

Writing a malformed UEFI variable can make a computer unable to complete POST. Recovery may require HP’s BIOS recovery procedure or an external SPI programmer. The procedure below succeeded on this machine, but it is not risk-free.

Before changing anything, keep the laptop on AC power. Preserve the original variable backup and the read-only SPI dump. Do not delete and recreate the EFI variable. If any write or verification command reports an error, stop.

If Windows is installed and configured for Intel RST, switching the controller to AHCI can stop that Windows installation from booting until its storage configuration is prepared for AHCI. This laptop’s active installation was NixOS on the SATA disk.

The relevant platform information was:

System manufacturer:         HP
System product:              HP 348 G7
Motherboard:                 HP 86CB
Motherboard/KBC version:     97.11
BIOS vendor:                 Insyde
BIOS version:                F.47
BIOS release date:           03/24/2026
Platform firmware revision:  15.47
Embedded controller revision: 97.11
Linux distribution:          NixOS
Kernel:                      Linux 6.18.36

The existing SATA disk was:

TOSHIBA MQ01ACF050
Approximately 465.8 GiB visible in Linux

The hidden M.2 device was later identified as:

INTEL MEMPEK1J016GA
Intel Optane Memory, nominally 16 GB
14.40 GB decimal / approximately 13.4 GiB in Linux
NVMe firmware: K4110400

The relevant PCI identities were:

Before the fix:
00:17.0 RAID bus controller [8086:282a]
Subsystem [103c:86cb]

After the fix:
00:17.0 SATA controller in AHCI mode [8086:9d03]
03:00.0 Intel NVMe Optane Memory [8086:2522]

Unique system serial numbers, UUIDs, and device serial numbers are intentionally omitted because they are not required to reproduce the diagnosis.

2. Original symptoms and diagnosis

Before the fix, lsblk showed only the SATA hard disk and zram. The layout was effectively:

NAME    SIZE    TYPE
sda     465.8G  disk
sda1    512M    part
sda2    8G      part
sda3    457.3G  part
zram0   3.8G    disk

The SATA partitions contained:

/dev/sda1   512 MiB   /boot
/dev/sda2   8 GiB     swap
/dev/sda3   ~457 GiB  / and /nix/store

There was no /dev/nvme0, /dev/ng0n1, or /dev/nvme0n1.

The absence of the NVMe from df -h was not decisive because df only lists mounted filesystems. A blank, unformatted, or unmounted disk would not appear there. The important evidence was that the device was absent from lsblk and nvme list.

That ruled out an ordinary filesystem or mount problem.

The necessary utilities did not need to be installed permanently. The newer Nix command was used with its experimental features enabled for each invocation:

nix --extra-experimental-features 'nix-command flakes' \
  shell nixpkgs#pciutils nixpkgs#nvme-cli nixpkgs#dmidecode

The classic equivalent is:

nix-shell -p pciutils nvme-cli dmidecode

For firmware extraction and analysis:

nix --extra-experimental-features 'nix-command flakes' \
  shell nixpkgs#uefitool nixpkgs#ifrextractor-rs \
  nixpkgs#binutils nixpkgs#file

For SPI-flash probing and reading:

nix --extra-experimental-features 'nix-command flakes' \
  shell nixpkgs#flashrom

For chattr and the later read-only badblocks test:

nix --extra-experimental-features 'nix-command flakes' \
  shell nixpkgs#e2fsprogs

Entering a new temporary Nix shell can lose non-exported shell variables. This mattered later when $VAR was empty after starting a shell for chattr. Recreate or export important variables after entering a new shell.

The most useful initial command was:

sudo dmesg | grep -i nvme

The kernel reported:

ahci 0000:00:17.0: Found 1 remapped NVMe devices.

Expanding the context made the diagnosis explicit:

sudo dmesg | grep -i -A5 -B5 'remapped NVMe'

The important output was:

ahci 0000:00:17.0: Found 1 remapped NVMe devices.
ahci 0000:00:17.0: Switch your BIOS from RAID to AHCI mode to use them.
ahci 0000:00:17.0: AHCI vers 0001.0301, 32 command slots, 6 Gbps, RAID mode

This proved three things:

  1. An NVMe device physically existed.
  2. The Intel chipset had remapped it behind the RAID/RST storage controller.
  3. Linux wanted the firmware switched from RAID to AHCI.

The investigation therefore changed from finding a missing disk to finding a vendor-hidden controller-mode setting.

The initial PCI check was:

lspci -nn | grep -iE 'nvme|non-volatile|raid|vmd|sata'

It showed:

00:17.0 RAID bus controller [0104]: Intel Corporation 82801 Mobile SATA Controller [RAID mode] [8086:282a] (rev 21)

There was no independent Non-Volatile memory controller entry.

The controller-specific check was:

lspci -nnk -s 00:17.0

Its relevant output was:

00:17.0 RAID bus controller [0104]: Intel Corporation 82801 Mobile SATA Controller [RAID mode] [8086:282a] (rev 21)
        Subsystem: Hewlett-Packard Company Device [103c:86cb]
        Kernel driver in use: ahci
        Kernel modules: ahci

The Linux driver was ahci, but the PCI device itself was still configured by the firmware as RAID mode. That distinction explained why the SATA disk worked while the remapped NVMe did not.

The native NVMe topology was absent:

sudo nvme list

The result was:

Failed to scan topology: No such file or directory

Linux also exposed the exact remap count through sysfs:

cat /sys/bus/pci/devices/0000:00:17.0/remapped_nvme

The result was:

1

Exactly one NVMe device was hidden behind Intel RST.

The normal solution would be to open the BIOS and change a setting named SATA Mode, SATA Operation, Storage Controller Mode, Intel RST, or similar from RAID/RST to AHCI.

The HP 348 G7 firmware did not show this option. Its normal BIOS interface had no usable advanced storage page and no exposed RAID/AHCI selector.

This did not mean that AHCI was absent from the firmware. It meant HP had suppressed the selector from the user-facing setup interface.

The platform was identified with:

sudo dmidecode -t system
sudo dmidecode -t baseboard
sudo dmidecode -t bios

The essential results were:

Manufacturer: HP
Product Name: HP 348 G7
Base Board Product Name: 86CB
BIOS Vendor: Insyde
BIOS Version: F.47
Release Date: 03/24/2026
Platform Firmware Revision: 15.47
Embedded Controller Firmware Revision: 97.11

The exact board and firmware version must be known before trusting a variable offset.

3. Approaches that did not solve the problem

Linux includes hp_bioscfg, which can expose HP firmware settings under sysfs. It was tested before attempting lower-level firmware analysis:

sudo modprobe hp_bioscfg
lsmod | grep hp_bioscfg
sudo dmesg | grep -i hp_bioscfg | tail -50

The module loaded, but the firmware rejected a command:

hp_bioscfg: Returned error 0x4, "Invalid command type"

The sysfs interface existed at:

/sys/class/firmware-attributes/hp-bioscfg/

It exposed Sure Start and authentication-related data, plus pending-reboot state, but no SATA, AHCI, RAID, RST, Optane, or storage-controller attribute.

The useful inspection commands were:

sudo find -L /sys/class/firmware-attributes/hp-bioscfg \
  -maxdepth 5 -type f -print
grep -RHiE 'SATA|AHCI|RAID|RST|Optane|Storage|Controller' \
  /sys/class/firmware-attributes/*/attributes/ 2>/dev/null

No supported HP/Linux setting could perform the required change.

The HP F.47 SoftPaq was:

sp172856.exe

It was downloaded and inspected without executing it:

mkdir -p ~/hp-bios-f47
cd ~/hp-bios-f47

curl -fLO \
  https://ftp.hp.com/pub/softpaq/sp172501-173000/sp172856.exe

file sp172856.exe
ls -lh sp172856.exe
7z l sp172856.exe

The outer package was a 39,425,792-byte Windows executable containing a 39,148,048-byte Insydeflash.exe.

It was extracted with:

mkdir extracted
7z x sp172856.exe -oextracted

The inner package was an Insyde iFdPacker/7-Zip SFX image. BIOSUtilities was used to unpack its obfuscated payload:

nix --extra-experimental-features 'nix-command flakes' \
  shell nixpkgs#git nixpkgs#python313 \
  nixpkgs#python313Packages.pip nixpkgs#p7zip

cd ~/hp-bios-f47
git clone --depth=1 https://github.com/platomav/BIOSUtilities.git
cd BIOSUtilities

python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

mkdir -p ~/hp-bios-f47/bios-unpacked

python main.py \
  ~/hp-bios-f47/extracted/Insydeflash.exe \
  -o ~/hp-bios-f47/bios-unpacked \
  -u InsydeIfdExtract \
  -e

The extracted payload contained several .fd images. Recorded sizes included:

086CB.fd    9,177,600 bytes
086CD.fd   18,354,944 bytes
086D7.fd    9,177,600 bytes
086D9.fd   18,354,944 bytes

The package also contained tools and configuration files including:

HPFlashWinx64.exe
HpBiosUpdate.efi
BiosMgmt.efi
HpBiosMgmt.efi
DevFwUpdate.efi
FWUpdLcl.exe
H2OFFT64.sys
platform.ini

The board mapping in platform.ini proved that 086CB.fd belonged to this laptop:

FD#11=PCI,0,0,0,2C,FFFFFFFF,86CB103C,086CB.fd

It also included:

PlatformName6=86CB

However, 086CB.fd did not contain directly usable UEFI firmware-volume signatures:

grep -abo '_FVH' 086CB.fd

There was no output. Direct IFR extraction returned:

No IFR data found

uefiextract also could not unpack it. The correct HP image was still encrypted, encoded, wrapped, or otherwise transformed for HP/Insyde’s update process. It was useful for identifying the right board payload, but not for direct firmware reverse engineering.

A Windows-based copy/export path through HP’s utilities was considered, but it was unnecessary once a Linux-only route succeeded.

4. Extracting the live firmware and finding the hidden settings

The firmware already installed in the laptop’s SPI flash had necessarily been transformed into the form used by the hardware. Instead of continuing to reverse HP’s update packaging, the installed BIOS region was read directly with flashrom.

Only a probe was attempted first:

mkdir -p ~/hp-bios-f47/live
cd ~/hp-bios-f47/live

nix --extra-experimental-features 'nix-command flakes' \
  shell nixpkgs#flashrom nixpkgs#uefitool \
  nixpkgs#ifrextractor-rs nixpkgs#binutils

sudo flashrom -p internal --flash-name

The first attempt identified the chipset but failed to map the PCI Express configuration region:

Found chipset "Intel Kaby Lake U w/ iHDCP2.2 Prem.".
pcilib: Cannot map ecam region: Operation not permitted.

Kernel lockdown was not active, and /proc/cmdline did not contain iomem=relaxed.

The following NixOS setting was temporarily added:

boot.kernelParams = [ "iomem=relaxed" ];

The next boot was built and started:

sudo nixos-rebuild boot
sudo reboot

For a flake-based configuration, the equivalent rebuild may be:

sudo nixos-rebuild boot --flake /etc/nixos#hp348
sudo reboot

After reboot, the parameter was verified:

cat /proc/cmdline

The output now included:

iomem=relaxed

This setting reduces /dev/mem protection. It was used only to permit the read and was removed after the investigation.

After iomem=relaxed was active, the probe found:

Chipset: Intel Kaby Lake U w/ iHDCP2.2 Prem.
Flash: Winbond W25Q64BV/W25Q64CV/W25Q64FV
Capacity: 8192 kB

The Intel flash descriptor reported:

FREG0: Flash Descriptor region (0x00000000-0x00000fff) is read-only.
FREG1: BIOS region (0x00200000-0x007fffff) is read-write.
FREG2: Management Engine region (0x00001000-0x001fffff) is locked.
PR0: 0x006d6000-0x007fffff is read-only.
PR1: 0x00200000-0x0021ffff is read-only.

flashrom warned that the laptop’s embedded controller was not positively identified and that even probing or reading can theoretically cause abnormal fan, backlight, or power behavior. The read was therefore performed once, on AC power, without suspend.

Only the BIOS region was read:

mkdir -p ~/hp-bios-f47/live
cd ~/hp-bios-f47/live

sudo flashrom -p internal --ifd -i bios -r live-bios.bin

The successful lines were:

Reading ich descriptor... done.
Using region: "bios".
Reading flash... done.

The dump was 8.0 MiB and had this SHA-256 hash:

6906154e4cf73cccc8b395c985c7c932aaace9923ac21657421f247dda43bfd5  live-bios.bin

The commands used to preserve its identity were:

ls -lh live-bios.bin
sha256sum live-bios.bin
file live-bios.bin

Unlike the encrypted HP .fd, the live dump contained real UEFI firmware-volume headers:

grep -abo '_FVH' live-bios.bin | head -20

The recorded offsets were:

2433064:_FVH
2768944:_FVH
3297320:_FVH
6570024:_FVH
7172136:_FVH
7190814:_FVH
7312208:_FVH

Important prohibitions during this stage were:

Do not use -w or --write.
Do not use -E or --erase.
Do not use --noverify-all.
Do not use laptop-force options.
Do not use ich_spi_force=yes.

The full live BIOS image can include NVRAM and machine-specific data. It should be kept private.

The firmware-analysis tools were entered again after the dump:

cd ~/hp-bios-f47/live

nix --extra-experimental-features 'nix-command flakes' \
  shell nixpkgs#uefitool nixpkgs#ifrextractor-rs \
  nixpkgs#binutils nixpkgs#file

command -v uefiextract
command -v uefifind
command -v ifrextractor

On this NixOS environment, the UEFITool commands were lowercase.

Direct IFR extraction from the complete SPI image returned no result because the useful forms were inside compressed firmware sections:

ifrextractor live-bios.bin list | tee live-ifr-list.txt
ifrextractor live-bios.bin

Both reported:

No IFR data found

The full firmware tree was therefore decompressed:

uefiextract live-bios.bin
echo "exit=$?"
ls -lah

Every decompressed file was checked for IFR:

mkdir -p ifr-results

find live-bios.bin.dump -type f -print0 |
while IFS= read -r -d '' f; do
    if ifrextractor "$f" list 2>/dev/null | grep -qv 'No IFR data found'; then
        echo "===== IFR FOUND: $f ====="
        ifrextractor "$f" list
        safe="$(echo "$f" | tr '/ ' '__')"
        ifrextractor "$f" > "ifr-results/${safe}.txt" 2>/dev/null
    fi
done

The extracted results were searched for the storage controls:

grep -RniE \
  'AHCI|SATA|RAID|RST|Optane|VMD|Storage|Controller' \
  ifr-results/

UTF-16LE firmware strings were also searched:

find live-bios.bin.dump -type f -print0 |
while IFS= read -r -d '' f; do
    x="$(
      strings -el "$f" 2>/dev/null |
      grep -iE 'AHCI|SATA|RAID|RST|Optane|VMD|Storage Controller|Controller Mode' ||
      true
    )"

    if [ -n "$x" ]; then
        echo
        echo "===== $f ====="
        echo "$x"
    fi
done | tee firmware-storage-strings.txt

This exposed the hidden setup forms and their exact variable definitions.

The extracted IFR identified this variable store:

Name: PchSetup
GUID: 4570B7F1-ADE8-4943-8DC3-406472842384
Variable-data size: 0x662 bytes

The hidden SATA selector was:

Setting: SATA Mode Selection
Offset:  0x42
AHCI:    0
RAID:    1
Default: RAID
Manufacturing default: RAID

The same variable contained PCIe storage remapping controls:

Port 1:  0x615
Port 3:  0x617
Port 5:  0x619
Port 7:  0x61B
Port 9:  0x61D
Port 11: 0x61F

Their values were:

Not RST Controlled: 0
RST Controlled:     1

This proved that HP had hidden the AHCI control from the visible BIOS rather than removing it from the firmware.

Linux exposed the exact variable at:

/sys/firmware/efi/efivars/PchSetup-4570b7f1-ade8-4943-8dc3-406472842384

It was located and measured with:

sudo ls -l /sys/firmware/efi/efivars/ | grep -i pchsetup

VAR="/sys/firmware/efi/efivars/PchSetup-4570b7f1-ade8-4943-8dc3-406472842384"

sudo stat -c '%n %s bytes' "$VAR"

The efivarfs file was exactly:

1638 bytes

That size is four bytes of efivarfs attributes followed by 0x662, or 1634, bytes of variable data. Every IFR data offset therefore had to be read at file position 4 + offset.

The SATA mode was checked with:

sudo od -An -tx1 -j $((4 + 0x42)) -N 1 "$VAR"

It returned:

01

All remapping offsets were checked with:

for off in 0x615 0x617 0x619 0x61B 0x61D 0x61F; do
  printf 'PchSetup offset 0x%X = ' "$off"
  sudo od -An -tx1 -j $((4 + off)) -N 1 "$VAR"
done

The live values were:

PchSetup offset 0x615 = 00
PchSetup offset 0x617 = 00
PchSetup offset 0x619 = 00
PchSetup offset 0x61B = 00
PchSetup offset 0x61D = 01
PchSetup offset 0x61F = 00

This established the exact pre-change state:

PchSetup[0x42]  = 0x01   # RAID
PchSetup[0x61D] = 0x01   # PCIe storage Port 9 RST-controlled

The target prepared during the investigation was:

PchSetup[0x42]  = 0x00   # AHCI
PchSetup[0x61D] = 0x00   # Port 9 not RST-controlled

5. Applying the firmware-variable fix safely

An initial attempt to copy the efivarfs pseudo-file with cp failed:

cp: cannot lseek ...: Illegal seek

It created an empty destination whose SHA-256 was the standard empty-file hash:

e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

That empty file was not a valid backup.

The variable was instead streamed with cat:

VAR="/sys/firmware/efi/efivars/PchSetup-4570b7f1-ade8-4943-8dc3-406472842384"

sudo cat "$VAR" > ~/hp-bios-f47/PchSetup.before.bin

It was verified with:

ls -lh ~/hp-bios-f47/PchSetup.before.bin
stat -c '%s bytes' ~/hp-bios-f47/PchSetup.before.bin
sha256sum ~/hp-bios-f47/PchSetup.before.bin
od -An -tx4 -N 4 ~/hp-bios-f47/PchSetup.before.bin

The valid backup identity was:

Size:       1638 bytes
SHA-256:    799039a89c17616eac626b2bf887fea6b261da569ddc523b02e24ed995a87cbb
Attributes: 0x00000007

The attributes 0x00000007 represent the normal non-volatile, boot-service-access, and runtime-access flags.

The two important bytes in the backup were confirmed:

od -An -tx1 -j $((4 + 0x42)) -N 1 \
  ~/hp-bios-f47/PchSetup.before.bin

od -An -tx1 -j $((4 + 0x61D)) -N 1 \
  ~/hp-bios-f47/PchSetup.before.bin

Both returned 01.

A human-readable hex dump was also saved:

od -Ax -tx1 ~/hp-bios-f47/PchSetup.before.bin \
  > ~/hp-bios-f47/PchSetup.before.hex

The live efivarfs variable was not edited while preparing the new data. A normal file was copied from the verified backup:

cp ~/hp-bios-f47/PchSetup.before.bin \
   ~/hp-bios-f47/PchSetup.ahci.bin

Only the SATA-mode byte was changed:

printf '\x00' | dd \
  of=~/hp-bios-f47/PchSetup.ahci.bin \
  bs=1 seek=$((4 + 0x42)) count=1 \
  conv=notrunc status=none

Only the Port-9 RST-remapping byte was changed:

printf '\x00' | dd \
  of=~/hp-bios-f47/PchSetup.ahci.bin \
  bs=1 seek=$((4 + 0x61D)) count=1 \
  conv=notrunc status=none

The prepared file was checked before any firmware write:

stat -c '%s bytes' ~/hp-bios-f47/PchSetup.ahci.bin

od -An -tx4 -N 4 ~/hp-bios-f47/PchSetup.ahci.bin

od -An -tx1 -j $((4 + 0x42)) -N 1 \
  ~/hp-bios-f47/PchSetup.ahci.bin

od -An -tx1 -j $((4 + 0x61D)) -N 1 \
  ~/hp-bios-f47/PchSetup.ahci.bin

The results were:

1638 bytes
00000007
00
00

The most important check compared every byte:

cmp -l \
  ~/hp-bios-f47/PchSetup.before.bin \
  ~/hp-bios-f47/PchSetup.ahci.bin

It reported exactly two differences:

  71   1   0
1570   1   0

cmp -l numbers byte positions starting from one. File position 71 corresponds to the four-byte header plus data offset 0x42. File position 1570 corresponds to the four-byte header plus data offset 0x61D. No other byte changed.

The live variable was protected with the immutable attribute:

VAR="/sys/firmware/efi/efivars/PchSetup-4570b7f1-ade8-4943-8dc3-406472842384"
sudo lsattr "$VAR"

The output included:

----i-----------------

chattr was obtained through e2fsprogs:

nix --extra-experimental-features 'nix-command flakes' \
  shell nixpkgs#e2fsprogs

Because the new shell lost the unexported value of $VAR, it was set again with export:

export VAR="/sys/firmware/efi/efivars/PchSetup-4570b7f1-ade8-4943-8dc3-406472842384"

The immutable flag was then removed:

sudo chattr -i "$VAR"
sudo lsattr "$VAR"

The i was confirmed absent before proceeding.

The complete 1638-byte efivarfs file, including its original four-byte attribute header, was written in one operation:

sudo dd \
  if="$HOME/hp-bios-f47/PchSetup.ahci.bin" \
  of="$VAR" \
  bs=1638 count=1 \
  conv=notrunc

The successful result was:

1+0 records in
1+0 records out
1638 bytes copied

If this command produces any error, do not delete or recreate the variable. Stop and preserve the current state.

The live offsets were immediately checked:

sudo od -An -tx1 -j $((4 + 0x42)) -N 1 "$VAR"
sudo od -An -tx1 -j $((4 + 0x61D)) -N 1 "$VAR"

Both returned:

00
00

The complete live variable was streamed back to a normal file:

sudo cat "$VAR" > ~/hp-bios-f47/PchSetup.after-write.bin

It was compared byte-for-byte against the prepared image:

cmp \
  ~/hp-bios-f47/PchSetup.ahci.bin \
  ~/hp-bios-f47/PchSetup.after-write.bin \
  && echo "PchSetup write verified"

The confirmation was:

PchSetup write verified

The immutable protection was restored:

sudo chattr +i "$VAR"
sudo lsattr "$VAR"

The i flag was visible again.

Only after the full write verified was the machine rebooted:

sudo reboot

6. Verification, cleanup, and preserved recovery files

After NixOS returned, the PCI state was checked:

lspci -nn | grep -iE 'raid|sata|nvme|non-volatile'

The result was:

00:17.0 SATA controller [0106]: Intel Corporation Sunrise Point-LP SATA Controller [AHCI mode] [8086:9d03] (rev 21)
03:00.0 Non-Volatile memory controller [0108]: Intel Corporation NVMe Optane Memory Series [8086:2522]

This was the fundamental success condition. The controller was no longer 8086:282a RAID mode, and the Optane device now existed independently on the PCI bus.

Kernel initialization was checked with:

sudo dmesg | grep -iE 'ahci|nvme|rst'

The relevant result was:

nvme nvme0: pci function 0000:03:00.0
nvme nvme0: 4/0/0 default/read/poll queues
 nvme0n1:
ahci 0000:00:17.0: AHCI vers 0001.0301, 32 command slots, 6 Gbps, SATA mode
ahci 0000:00:17.0: 2/2 ports implemented (port mask 0x3)

The old messages were gone:

Found 1 remapped NVMe devices.
Switch your BIOS from RAID to AHCI mode to use them.

The block-device view was checked with:

lsblk -o NAME,MODEL,SERIAL,SIZE,TYPE,FSTYPE,MOUNTPOINTS

The relevant result, with unique serials omitted here, was:

sda      TOSHIBA MQ01ACF050   465.8G disk
sda1                             512M part vfat /boot
sda2                               8G part swap [SWAP]
sda3                           457.3G part ext4 / /nix/store
zram0                            3.8G disk swap [SWAP]
nvme0n1 INTEL MEMPEK1J016GA     13.4G disk

Native NVMe enumeration was checked with:

sudo nvme list

The device appeared as:

Node:       /dev/nvme0n1
Generic:    /dev/ng0n1
Model:      INTEL MEMPEK1J016GA
Capacity:   14.40 GB
LBA format: 512 B
Firmware:   K4110400

nvme0n1 did not appear in df -h because it was still a raw, unmounted block device. That was expected.

The live variable was checked again:

VAR="/sys/firmware/efi/efivars/PchSetup-4570b7f1-ade8-4943-8dc3-406472842384"

sudo od -An -tx1 -j $((4 + 0x42)) -N 1 "$VAR"
sudo od -An -tx1 -j $((4 + 0x61D)) -N 1 "$VAR"

The post-reboot values were:

PchSetup[0x42]  = 00
PchSetup[0x61D] = 01

HP firmware restored the Port-9 RST field at 0x61D to 01, but it did not restore the SATA-mode byte. The NVMe nevertheless remained exposed natively at 03:00.0 and the old remapping warning remained absent.

The conclusion is that PchSetup[0x42] = 00 is the critical persistent change. The Port-9 field is either ignored or disabled when the controller itself is operating in AHCI mode. It should now be left alone.

iomem=relaxed was needed only for the read-only SPI access. After the firmware analysis succeeded, it was removed from boot.kernelParams.

The boot configuration was rebuilt:

sudo nixos-rebuild boot

After the following reboot, /proc/cmdline should no longer contain iomem=relaxed.

There is no reason to leave the relaxed physical-memory policy enabled for normal use.

At minimum, preserve these files privately:

~/hp-bios-f47/live/live-bios.bin
~/hp-bios-f47/PchSetup.before.bin
~/hp-bios-f47/PchSetup.before.hex
~/hp-bios-f47/PchSetup.ahci.bin
~/hp-bios-f47/PchSetup.after-write.bin

The most important identities are:

live-bios.bin
SHA-256: 6906154e4cf73cccc8b395c985c7c932aaace9923ac21657421f247dda43bfd5

PchSetup.before.bin
Size:    1638 bytes
SHA-256: 799039a89c17616eac626b2bf887fea6b261da569ddc523b02e24ed995a87cbb

Do not publish the complete SPI dump casually. It can contain machine-specific NVRAM data.

7. Drive health, replacement, and Linux installation

Once the module was visible, its SMART log was inspected:

sudo nvme smart-log /dev/nvme0

The recorded values included:

critical_warning:       0
temperature:            31 °C
available_spare:        100%
percentage_used:        2%
Data Units Read:        35,085,334, approximately 17.96 TB
Data Units Written:     20,922,590, approximately 10.71 TB
power_cycles:           4780
power_on_hours:         6484
unsafe_shutdowns:       566
media_errors:           1544
num_err_log_entries:    146

The endurance, spare, temperature, and critical-warning values looked good, but the historical media-error count required investigation.

The NVMe error log contained genuine historical unrecovered read errors, including repeated entries around these LBAs:

0xbc8d
0xbc98
0xa105

This did not mean the AHCI change caused the errors. NVMe error logs persist across reboots, and the module had previously operated as an Optane/RST cache.

The counters were recorded:

sudo nvme smart-log /dev/nvme0 | \
  grep -E 'media_errors|num_err_log_entries'

The known LBAs were read directly:

sudo dd if=/dev/nvme0n1 of=/dev/null \
  bs=512 skip=$((0xbc8d)) count=1 \
  iflag=direct status=progress

sudo dd if=/dev/nvme0n1 of=/dev/null \
  bs=512 skip=$((0xbc98)) count=1 \
  iflag=direct status=none

sudo dd if=/dev/nvme0n1 of=/dev/null \
  bs=512 skip=$((0xa105)) count=1 \
  iflag=direct status=none

All three reads succeeded.

Because the device was empty and only about 14 GB, a complete read-only scan was practical:

sudo badblocks -sv /dev/nvme0n1

The result was:

Pass completed, 0 bad blocks found. (0/0/0 errors)

The counters remained unchanged:

media_errors:        1544
num_err_log_entries: 146

dmesg showed no new NVMe I/O or medium errors.

The most reasonable interpretation is that the errors are historical rather than currently reproducible. The module is not obviously worn out, but its history makes it unsuitable for irreplaceable data. It is more appropriate for non-critical cache, temporary storage, scratch space, or possibly swap.

Never use badblocks -w on a device whose contents must be preserved. The -w mode is destructive. The scan above used the default read-only mode.

The controller-mode setting is stored in the laptop’s UEFI/NVRAM, not on the Optane module. Replacing the module should not undo PchSetup[0x42] = 00.

The current module is an M.2 2280 PCIe NVMe device. A sensible replacement is:

Form factor: M.2 2280
Interface:   PCIe NVMe
Generation:  Gen3 is the safest direct match
Capacity:    500 GB or 1 TB is a practical choice

HP sold the 348 G7 with conventional PCIe NVMe storage as well as the 16 GB Optane configuration, so the slot was designed to accept a normal NVMe SSD. A modern Gen4 SSD will usually negotiate down to the system’s supported PCIe generation, although there is little benefit in paying extra for very high Gen4 or Gen5 performance on this platform.

Capacity options originally sold by HP are not necessarily firmware capacity limits. A standard 1 TB M.2 2280 NVMe SSD is a reasonable choice, although any replacement should still be purchased from a seller with a usable return policy.

Linux can be installed directly on a replacement NVMe because the slot is now exposed as a normal native PCIe NVMe controller. The successful evidence is:

03:00.0 Non-Volatile memory controller
nvme nvme0: pci function 0000:03:00.0

A clean installation can place an EFI System Partition and the Linux root filesystem on the NVMe. The existing SATA hard disk can remain secondary storage for backups or bulk data.

During installation, identify disks by model or /dev/disk/by-id/... rather than assuming that a particular device will always be named /dev/nvme0n1 or /dev/sda.

It is sensible to leave the old SATA installation intact until the new NVMe installation boots reliably. Once verified, the SATA disk can be repurposed if desired.

8. Persistence, BIOS updates, and recovery

Ordinary reboot and shutdown have already been tested. PchSetup[0x42] remained 00, as expected for a non-volatile UEFI variable.

Replacing the NVMe, reinstalling Linux, replacing the SATA disk, or losing normal operating-system state should not normally reset this firmware setting.

The events most likely to restore RAID mode are loading BIOS defaults, choosing a factory-default or BIOS-reset function, performing a BIOS recovery, clearing firmware settings, replacing the motherboard, or installing a BIOS update that resets or migrates NVRAM.

The practical risk assessment is:

EventReversion risk
Normal rebootVery low; tested successfully
Normal shutdown and power-onVery low
Replacing the NVMe SSDLow
Reinstalling LinuxEssentially none
Removing or replacing the SATA diskVery low
Loading BIOS defaultsHigh
Choosing Restore Factory DefaultsHigh
BIOS recovery procedureMeaningful to high
BIOS firmware updatePossible; verify afterward
Motherboard replacementEffectively certain

No percentage can be assigned because HP does not document the persistence of this hidden variable.

After a BIOS update, first check the observable storage state. Do not immediately repeat the old write procedure.

Run:

lspci -nn | grep -iE 'raid|sata|nvme|non-volatile'

If the output still contains an AHCI SATA controller and an independent non-volatile memory controller, nothing needs to be changed.

Check the live byte if the same variable still exists:

VAR="/sys/firmware/efi/efivars/PchSetup-4570b7f1-ade8-4943-8dc3-406472842384"

sudo od -An -tx1 \
  -j $((4 + 0x42)) -N 1 "$VAR"

If it still returns 00, the machine remains in AHCI mode.

If a future BIOS resets it to 01, re-extract and inspect that new BIOS version’s IFR before writing anything. Do not assume that the F.47 offset remains valid in F.48, F.49, or any later release.

If the NVMe disappears again, start with:

lspci -nn | grep -iE 'raid|sata|nvme|non-volatile'
sudo dmesg | grep -iE 'ahci|nvme|rst|remapped'
lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINTS

The known broken state is:

00:17.0 RAID bus controller [8086:282a]
Found 1 remapped NVMe devices.
Switch your BIOS from RAID to AHCI mode to use them.

The known working state is:

00:17.0 SATA controller [AHCI mode] [8086:9d03]
03:00.0 Non-Volatile memory controller [8086:2522]
/dev/nvme0n1 exists

On the confirmed F.47/86CB combination only, inspect the live value:

VAR="/sys/firmware/efi/efivars/PchSetup-4570b7f1-ade8-4943-8dc3-406472842384"

sudo stat -c '%n %s bytes' "$VAR"
sudo od -An -tx1 -j $((4 + 0x42)) -N 1 "$VAR"

Expected working result:

Size: 1638 bytes
Value at 0x42: 00

Before considering any rewrite, verify the board and BIOS again:

sudo dmidecode -t baseboard
sudo dmidecode -t bios

Also verify that the preserved original backup still matches:

stat -c '%s bytes' ~/hp-bios-f47/PchSetup.before.bin
sha256sum ~/hp-bios-f47/PchSetup.before.bin

The confirmed identity is:

1638 bytes
799039a89c17616eac626b2bf887fea6b261da569ddc523b02e24ed995a87cbb

If the BIOS version is no longer F.47, stop and re-derive the variable layout from the new firmware.

Do not guess a setup offset from another HP model or BIOS version.

Do not write to the complete SPI flash just to change this setting. The successful fix changed a UEFI setup variable; flashrom was used only for a read-only BIOS-region dump.

Do not use flashrom -w, --write, -E, --erase, --noverify-all, or laptop-force options for this procedure.

Do not delete and recreate the PchSetup efivarfs file if a write fails.

Do not write a single byte directly into the efivarfs pseudo-file. Preserve the complete four-byte attributes header and update the complete verified variable in one operation.

Do not proceed if the prepared image differs from the backup anywhere except the intended byte positions.

Do not leave iomem=relaxed enabled after the SPI read is finished.

Do not treat the absence of a raw disk from df -h as proof that the kernel cannot see it. Use lsblk, lspci, dmesg, and nvme list.

Do not assume the Optane module’s historical SMART counters were caused by the AHCI change. The counters did not increase, the logged LBAs read successfully, and a complete read-only scan found no current bad blocks.

9. Final conclusions

The NVMe device was physically present but hidden from Linux by Intel RST NVMe remapping while the PCH storage controller operated in RAID mode.

HP’s visible BIOS did not expose the necessary controller-mode selector, and the supported hp_bioscfg Linux interface did not expose it either.

HP’s distributed 086CB.fd image was the correct board image but remained unsuitable for direct UEFI parsing. Reading the installed BIOS region from SPI flash produced a valid UEFI image whose decompressed IFR exposed the hidden settings.

For HP 348 G7 board 86CB on Insyde F.47, the relevant variable was:

PchSetup-4570b7f1-ade8-4943-8dc3-406472842384

The decisive setting was:

Offset 0x42
RAID = 1
AHCI = 0

Changing the live value from 01 to 00, verifying the complete 1638-byte variable, and rebooting changed the machine to native AHCI/NVMe operation.

The final verified state was:

Intel SATA controller in AHCI mode: 8086:9d03
Intel Optane exposed as native NVMe: 8086:2522
Linux device: /dev/nvme0n1

The setting survived reboot. The Port-9 RST byte reverted to 01, but this did not matter once the controller’s SATA-mode byte remained 00.

The original problem is resolved: Intel RST NVMe remapping is no longer preventing Linux from accessing the internal M.2 device, and the slot can now be used with a normal NVMe SSD and as a Linux boot device.