nas08-scripts/NAS08-Kernel-Recovery-Summary.html

683 lines
28 KiB
HTML
Raw Permalink Normal View History

2026-07-26 21:34:22 -04:00
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>KingDezigns — NAS08 Kernel Recovery Summary</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500&family=IBM+Plex+Sans:wght@400;500&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #f7f6f2;
--surface: #ffffff;
--surface-alt: #f1f0eb;
--border: #e2e0d8;
--border-strong: #c8c5ba;
--text-primary: #1a1917;
--text-secondary: #6b6960;
--text-muted: #9b9890;
--green-bg: #eaf3de;
--green-border: #97c459;
--green-text: #2d5a0e;
--red-bg: #fcebeb;
--red-border: #f09595;
--red-text: #7a1f1f;
--amber-bg: #faeeda;
--amber-border: #fac775;
--amber-text: #633806;
--coral-bg: #faece7;
--coral-border: #f0997b;
--coral-text: #4a1b0c;
--mono: 'IBM Plex Mono', monospace;
--sans: 'IBM Plex Sans', sans-serif;
}
body {
font-family: var(--sans);
font-size: 14px;
background: var(--bg);
color: var(--text-primary);
line-height: 1.7;
padding: 2.5rem 1.5rem;
}
.page { max-width: 860px; margin: 0 auto; }
header {
border-bottom: 1px solid var(--border-strong);
padding-bottom: 1.25rem;
margin-bottom: 2rem;
}
header h1 {
font-family: var(--mono);
font-size: 18px;
font-weight: 500;
letter-spacing: -0.02em;
margin-bottom: 6px;
}
.meta {
font-size: 12px;
color: var(--text-muted);
font-family: var(--mono);
display: flex;
gap: 16px;
flex-wrap: wrap;
}
.section { margin-bottom: 2.25rem; }
.section-title {
font-family: var(--mono);
font-size: 11px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--text-muted);
margin-bottom: 1rem;
display: flex;
align-items: center;
gap: 10px;
}
.section-title::before {
content: attr(data-num);
background: var(--text-primary);
color: var(--bg);
font-size: 10px;
width: 18px;
height: 18px;
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.section-title::after {
content: '';
flex: 1;
height: 1px;
background: var(--border);
}
p { margin-bottom: 0.75rem; color: var(--text-primary); }
p:last-child { margin-bottom: 0; }
.badge-row { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 1rem; }
.badge {
font-family: var(--mono);
font-size: 11px;
padding: 3px 10px;
border-radius: 3px;
border: 1px solid var(--border);
background: var(--surface);
color: var(--text-secondary);
}
.badge.red { background: var(--red-bg); color: var(--red-text); border-color: var(--red-border); }
.badge.green { background: var(--green-bg); color: var(--green-text); border-color: var(--green-border); }
.badge.amber { background: var(--amber-bg); color: var(--amber-text); border-color: var(--amber-border); }
.step {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 6px;
padding: 1rem 1.25rem;
margin-bottom: 0.6rem;
}
.step-header {
font-family: var(--mono);
font-size: 12px;
font-weight: 500;
color: var(--text-secondary);
margin-bottom: 0.6rem;
display: flex;
align-items: center;
gap: 8px;
}
.step-num {
background: var(--surface-alt);
border: 1px solid var(--border);
border-radius: 50%;
width: 20px;
height: 20px;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 10px;
flex-shrink: 0;
color: var(--text-muted);
}
pre {
background: var(--surface-alt);
border: 1px solid var(--border);
border-radius: 4px;
padding: 10px 12px;
font-family: var(--mono);
font-size: 12px;
overflow-x: auto;
margin: 0.5rem 0;
white-space: pre;
line-height: 1.6;
}
code {
font-family: var(--mono);
font-size: 12px;
background: var(--surface-alt);
padding: 1px 5px;
border-radius: 3px;
border: 1px solid var(--border);
}
.why {
font-size: 12px;
color: var(--text-muted);
margin-top: 0.4rem;
padding-left: 2px;
}
.why::before { content: '↳ why: '; font-family: var(--mono); }
.result { font-size: 12px; margin-top: 0.35rem; padding-left: 2px; }
.result.pass { color: var(--green-text); }
.result.pass::before { content: '✓ '; font-family: var(--mono); }
.result.fail { color: var(--red-text); }
.result.fail::before { content: '✗ '; font-family: var(--mono); }
.result.neutral { color: var(--text-secondary); }
.result.neutral::before { content: '→ '; font-family: var(--mono); }
.callout { border-radius: 6px; padding: 1rem 1.25rem; margin-bottom: 0.75rem; }
.callout.coral { background: var(--coral-bg); border: 1px solid var(--coral-border); }
.callout.coral p { color: var(--coral-text); }
.callout.coral pre { background: #fdf0eb; border-color: var(--coral-border); }
.callout.amber { background: var(--amber-bg); border: 1px solid var(--amber-border); }
.callout.amber p { color: var(--amber-text); }
.callout.amber pre { background: #fdf5e6; border-color: var(--amber-border); }
.callout.amber code { background: #fdf5e6; border-color: var(--amber-border); color: var(--amber-text); }
.callout.green { background: var(--green-bg); border: 1px solid var(--green-border); }
.callout.green p { color: var(--green-text); }
.callout.green pre { background: #d8efc0; border-color: var(--green-border); }
.clue-label {
font-family: var(--mono);
font-size: 10px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.07em;
color: var(--amber-text);
margin-bottom: 8px;
}
.script-box { background: var(--surface); border: 1px solid var(--border); border-radius: 6px; overflow: hidden; }
.script-row { padding: 0.75rem 1.25rem; border-bottom: 1px solid var(--border); }
.script-row:last-child { border-bottom: none; }
.script-label { font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: 0.07em; color: var(--text-muted); margin-bottom: 6px; }
.script-row pre { margin: 0; }
table { width: 100%; border-collapse: collapse; font-size: 13px; background: var(--surface); border: 1px solid var(--border); border-radius: 6px; overflow: hidden; }
th { text-align: left; padding: 8px 14px; font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); background: var(--surface-alt); border-bottom: 1px solid var(--border); font-weight: 500; }
td { padding: 9px 14px; border-bottom: 1px solid var(--border); vertical-align: top; line-height: 1.5; }
tr:last-child td { border-bottom: none; }
.footer {
font-family: var(--mono);
font-size: 11px;
color: var(--text-muted);
margin-top: 2.5rem;
padding-top: 1rem;
border-top: 1px solid var(--border);
display: flex;
justify-content: space-between;
flex-wrap: wrap;
gap: 8px;
}
</style>
</head>
<body>
<div class="page">
<header>
<h1>KingDezigns — NAS08 Kernel Recovery Summary</h1>
<div class="meta">
<span>📅 May 1516, 2026</span>
<span>🖥 NAS08 — Raspberry Pi 5 Model B Rev 1.1</span>
<span>⚙️ OpenMediaVault 8.2.13 / Debian Trixie</span>
<span>🔌 Radxa Penta SATA HAT (JMB585)</span>
<span>🐧 Kernel 6.12.75 → 6.18.29 → rolled back → 6.18.29 (fixed)</span>
</div>
</header>
<!-- SECTION 1 — THE PROBLEM -->
<div class="section">
<div class="section-title" data-num="1">The problem</div>
<p>After a routine apt upgrade that included a kernel jump from 6.12 to 6.18 and a new <code>raspi-firmware</code> package, NAS08 lost all four SATA data drives connected via the Radxa Penta SATA HAT. ZFS reported no pools available and OMV could not see the drives.</p>
<div class="badge-row">
<span class="badge red">zpool status: no pools available</span>
<span class="badge red">ahci: failed to start port 0 (errno=-12)</span>
<span class="badge red">lsblk: sdb/sdc/sdd/sde missing</span>
<span class="badge red">BAR 0 [io size 0x0080]: can't assign; no space</span>
<span class="badge amber">DMA32: empty</span>
</div>
<p>The upgrade included <code>linux-image-6.18.29+rpt-rpi-2712</code>, <code>raspi-firmware 1:1.20260513-1</code>, and <code>openmediavault 8.2.13-1</code> among 20+ packages. The Radxa Penta SATA HAT uses a JMicron JMB585 PCIe SATA controller. An upstream kernel commit (ee95f3c) affecting the JMB585 chipset means kernel 6.18 now requires the <code>pcie-32bit-dma-pi5</code> device tree overlay for the controller to allocate DMA memory successfully. This overlay was present in <code>config.txt</code> but placed under the <code>[cm5]</code> conditional section, which is ignored on a Raspberry Pi 5 Model B. As a result, the overlay never loaded and the JMB585 had no DMA32 address space.</p>
</div>
<!-- SECTION 2 — DIAGNOSTIC COMMANDS -->
<div class="section">
<div class="section-title" data-num="2">Diagnostic commands run &amp; why</div>
<div class="step">
<div class="step-header"><span class="step-num">1</span> Confirm ZFS module is loaded</div>
<pre>lsmod | grep zfs</pre>
<p class="why">Rule out ZFS module as the cause — if it's not loaded, drives won't be visible to any pool.</p>
<p class="result pass">ZFS module loaded correctly — zfs and spl both present. Not the cause.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">2</span> Check running kernel vs installed kernels</div>
<pre>uname -r
dpkg -l | grep linux-image</pre>
<p class="why">Confirm which kernel booted and whether a version mismatch caused the issue.</p>
<p class="result neutral">Booted into 6.18.29 — confirmed the kernel jump from 6.12 happened. Both versions still installed.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">3</span> Check if OS sees the drives at all</div>
<pre>lsblk
ls /dev/disk/by-id/</pre>
<p class="why">Determine if the problem is at the ZFS layer or the OS/hardware layer.</p>
<p class="result fail">Only boot SSD visible. Data drives completely absent — hardware/driver level problem confirmed.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">4</span> Check dmesg for USB/SATA/PCIe errors</div>
<pre>dmesg | grep -iE "usb|sd|storage|attach|disconnect|reset" | grep -v "loop\|zram\|firmware" | tail -60</pre>
<p class="why">Identify whether drives were seen at boot and then lost, or never detected at all.</p>
<p class="result fail">Only one USB device detected at boot (boot SSD). No SATA drives enumerated. Pointed to PCIe HAT issue.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">5</span> Check PCIe controller visibility</div>
<pre>lspci</pre>
<p class="why">Confirm whether the JMicron JMB585 SATA controller on the Radxa HAT is being detected by the PCIe bus.</p>
<p class="result neutral">JMicron JMB585 visible at 0001:01:00.0 — controller detected but not functional.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">6</span> Check PCIe BAR assignment errors</div>
<pre>dmesg | grep -iE "pcie|pci|ahci|sata|asm|jmb|asmedia" | head -40</pre>
<p class="why">Identify why the detected controller isn't working — look for resource allocation failures.</p>
<p class="result fail">BAR 04 all failed to assign I/O space. PCI bridge showed zero-length address range. AHCI errno=-12 (ENOMEM).</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">7</span> Check DMA memory layout</div>
<pre>cat /proc/meminfo | grep -i cma
dmesg | grep -iE "cma|dma|coherent" | head -20</pre>
<p class="why">Determine why AHCI port start was failing with ENOMEM — check DMA zone availability.</p>
<p class="result fail">DMA32 zone empty. CmaFree: 0 kB. JMB585 forced into 32-bit DMA mode with no available DMA32 address space.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">8</span> Check hardware identity</div>
<pre>cat /proc/device-tree/model</pre>
<p class="why">Confirm exact hardware model — critical for applying the correct config.txt overlay section.</p>
<p class="result neutral">Raspberry Pi 5 Model B Rev 1.1 — confirmed Pi 5, not CM5. This meant the [cm5] section in config.txt was being ignored.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">9</span> Check config.txt overlay placement</div>
<pre>cat /boot/firmware/config.txt</pre>
<p class="why">Identify whether the pcie-32bit-dma-pi5 overlay was present and in the correct conditional section.</p>
<p class="result fail">Overlay was present but under [cm5] section — ignored on Pi 5. Moving it to [all] section was the fix.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">10</span> Check EEPROM version and config</div>
<pre>sudo rpi-eeprom-update
sudo rpi-eeprom-config</pre>
<p class="why">Determine if pci=pcie_bus_safe was coming from the EEPROM bootloader config.</p>
<p class="result neutral">EEPROM was 5 months out of date. Updated during recovery session.</p>
</div>
</div>
<!-- SECTION 3 — ROOT CAUSE -->
<div class="section">
<div class="section-title" data-num="3">Root cause</div>
<div class="callout coral">
<p>An upstream Linux kernel commit (ee95f3c) changed how the JMB585 PCIe SATA controller allocates DMA memory on kernel 6.18. The JMB585 now requires the <code>pcie-32bit-dma-pi5</code> device tree overlay to function correctly. This overlay was present in <code>/boot/firmware/config.txt</code> but placed under the <code>[cm5]</code> conditional section, which is silently ignored on a Raspberry Pi 5 Model B. As a result the overlay never loaded, the JMB585 had no DMA32 address space, and AHCI failed with ENOMEM on every port start attempt.</p>
</div>
<div class="callout amber">
<div class="clue-label">⚠ Key clue</div>
<p style="margin-bottom:6px;">The config.txt overlay section mismatch was the root cause. The overlay fix was correct — it was simply applied to the wrong conditional block during the initial recovery attempt.</p>
<pre># Wrong — ignored on Pi 5 Model B:
[cm5]
dtoverlay=pcie-32bit-dma-pi5
# Correct — applies to all Pi hardware:
[all]
dtoverlay=pcie-32bit-dma-pi5</pre>
<p style="margin-top:8px;">The kernel 6.18 requirement for <code>pcie-32bit-dma-pi5</code> on JMB585 hardware is documented upstream. Any Pi 5 running kernel 6.18 with this HAT requires this overlay in the <code>[all]</code> or <code>[pi5]</code> section of config.txt.</p>
</div>
<div class="callout green" style="margin-top:0.75rem;">
<p><strong>Resolution:</strong> Moved <code>dtoverlay=pcie-32bit-dma-pi5</code> from the <code>[cm5]</code> section to the <code>[all]</code> section in <code>/boot/firmware/config.txt</code>, then copied the 6.18.29 kernel binary back to <code>/boot/firmware/kernel_2712.img</code> and rebooted. All four SATA drives appeared immediately on kernel 6.18.</p>
</div>
</div>
<!-- SECTION 4 — RECOVERY PROCEDURE -->
<div class="section">
<div class="section-title" data-num="4">Recovery procedure applied</div>
<div class="step">
<div class="step-header"><span class="step-num">1</span> Roll back to kernel 6.12 (initial emergency recovery)</div>
<pre>sudo apt-mark hold raspi-firmware linux-image-rpi-2712 linux-image-rpi-v8 linux-image-6.18.29+rpt-rpi-2712 linux-image-6.18.29+rpt-rpi-v8
sudo cp /boot/vmlinuz-6.12.75+rpt-rpi-2712 /boot/firmware/kernel_2712.img
sudo cp /boot/vmlinuz-6.12.75+rpt-rpi-v8 /boot/firmware/kernel8.img
sudo reboot</pre>
<p class="why">Immediately restored drive visibility on 6.12 while the root cause was investigated. Holds prevented the firmware hook from re-upgrading kernel_2712.img on reboot.</p>
<p class="result pass">All four drives (sdb/sdc/sdd/sde) returned on 6.12.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">2</span> Fix the overlay placement in config.txt</div>
<pre>sudo nano /boot/firmware/config.txt
# Remove dtoverlay=pcie-32bit-dma-pi5 from the [cm5] section
# Add it to the [all] section instead:
[cm5]
dtoverlay=dwc2,dr_mode=host
[all]
dtoverlay=pcie-32bit-dma-pi5</pre>
<p class="why">The overlay was present but in the wrong conditional section. Moving it to [all] ensures it applies to the Pi 5 Model B hardware.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">3</span> Unhold packages and copy 6.18 kernel back</div>
<pre>sudo apt-mark unhold raspi-firmware linux-image-rpi-2712 linux-image-rpi-v8 linux-image-6.18.29+rpt-rpi-2712 linux-image-6.18.29+rpt-rpi-v8
sudo cp /boot/vmlinuz-6.18.29+rpt-rpi-2712 /boot/firmware/kernel_2712.img
sudo cp /boot/vmlinuz-6.18.29+rpt-rpi-v8 /boot/firmware/kernel8.img
sudo reboot</pre>
<p class="why">6.18 was already installed — only the kernel_2712.img binary needed updating. The overlay fix was now in place before boot.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">4</span> Verify and re-apply holds</div>
<pre>uname -r # should show 6.18.29+rpt-rpi-2712
lsblk # should show sdb sdc sdd sde
sudo zpool status
sudo apt-mark hold raspi-firmware linux-image-rpi-2712 linux-image-rpi-v8 linux-image-6.18.29+rpt-rpi-2712 linux-image-6.18.29+rpt-rpi-v8
sudo apt-mark showhold</pre>
<p class="result pass">All four drives present on 6.18.29. ZFS pool ONLINE. Holds re-applied to prevent uncontrolled kernel upgrades.</p>
</div>
</div>
<!-- SECTION 5 — EMERGENCY ROLLBACK -->
<div class="section">
<div class="section-title" data-num="5">Emergency rollback — if a future upgrade breaks drives again</div>
<p>If a future upgrade causes drives to disappear again, this is the fast rollback procedure. Takes less than 5 minutes.</p>
<div class="step">
<div class="step-header"><span class="step-num">1</span> Hold packages immediately</div>
<pre>sudo apt-mark hold raspi-firmware linux-image-rpi-2712 linux-image-rpi-v8 linux-image-6.18.29+rpt-rpi-2712 linux-image-6.18.29+rpt-rpi-v8</pre>
<p class="why">The z50-raspi-firmware hook overwrites kernel_2712.img on every apt operation. Hold first to stop this.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">2</span> Copy 6.12 kernel directly over the firmware kernel image</div>
<pre>sudo cp /boot/vmlinuz-6.12.75+rpt-rpi-2712 /boot/firmware/kernel_2712.img
sudo cp /boot/vmlinuz-6.12.75+rpt-rpi-v8 /boot/firmware/kernel8.img
# Verify sizes — should be 9698043 and 9695883
ls -la /boot/firmware/kernel_2712.img /boot/firmware/kernel8.img</pre>
<p class="why">raspi-firmware boots whichever kernel is in kernel_2712.img directly. Replacing it with 6.12 forces the rollback.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">3</span> Reboot and confirm</div>
<pre>sudo reboot
# After reboot:
uname -r # should show 6.12.75+rpt-rpi-2712
lsblk # should show sdb sdc sdd sde
sudo zpool status</pre>
<p class="result pass">Drives and ZFS pools return immediately on 6.12.</p>
</div>
</div>
<!-- SECTION 6 — SCRIPTS CREATED -->
<div class="section">
<div class="section-title" data-num="6">Scripts created this session</div>
<div class="script-box">
<div class="script-row">
<div class="script-label">NAS08 ZFS Health Report</div>
<pre>zfs_report_nas08.sh</pre>
</div>
<div class="script-row">
<div class="script-label">NAS16 ZFS Health Report</div>
<pre>zfs_report_nas16.sh</pre>
</div>
<div class="script-row">
<div class="script-label">Commands executed per run</div>
<pre>zpool status -v &lt;pool&gt;
zpool list -H -o name,size,alloc,free,frag,cap,health &lt;pool&gt;
zfs list -r -H -o name,used,avail,refer,mountpoint &lt;pool&gt;</pre>
</div>
<div class="script-row">
<div class="script-label">Deploy &amp; schedule (cron)</div>
<pre>chmod +x zfs_report_nas08.sh
sudo mv zfs_report_nas08.sh /opt/scripts/
# Add to crontab — runs daily at 7:00 AM:
0 7 * * * /opt/scripts/zfs_report_nas08.sh >> /var/log/zfs_report.log 2>&amp;1</pre>
</div>
<div class="script-row">
<div class="script-label">Email recipient</div>
<pre>rufus.king@kingdezigns.com</pre>
</div>
</div>
</div>
<!-- SECTION 7 — NAS16 PROTECTION -->
<div class="section">
<div class="section-title" data-num="7">NAS16 — apply same fix</div>
<p>NAS16 runs the identical Radxa Penta SATA HAT on a Raspberry Pi 5. It will hit the exact same kernel 6.18 / JMB585 DMA issue if updated without the overlay fix in place. SSH into NAS16 and follow these steps.</p>
<div class="step">
<div class="step-header"><span class="step-num">1</span> Hold kernel and firmware packages on NAS16</div>
<pre>sudo apt-mark hold raspi-firmware linux-image-rpi-2712 linux-image-rpi-v8
sudo apt-mark showhold</pre>
<p class="why">Prevents kernel 6.18 and new raspi-firmware from installing automatically while the config.txt fix is applied.</p>
<p class="result pass">Expected: all packages listed as held.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">2</span> Confirm hardware identity</div>
<pre>cat /proc/device-tree/model</pre>
<p class="why">Verify NAS16 is also a Pi 5 Model B so the [all] section placement is correct.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">3</span> Fix the overlay placement in config.txt</div>
<pre>sudo nano /boot/firmware/config.txt
# Ensure pcie-32bit-dma-pi5 is in the [all] section:
[all]
dtoverlay=pcie-32bit-dma-pi5</pre>
<p class="why">Same fix as NAS08 — overlay must be in [all], not [cm5], to apply on Pi 5 hardware.</p>
</div>
<div class="step">
<div class="step-header"><span class="step-num">4</span> Unhold, upgrade, and reboot</div>
<pre>sudo apt-mark unhold raspi-firmware linux-image-rpi-2712 linux-image-rpi-v8
sudo apt upgrade
sudo cp /boot/vmlinuz-6.18.29+rpt-rpi-2712 /boot/firmware/kernel_2712.img
sudo cp /boot/vmlinuz-6.18.29+rpt-rpi-v8 /boot/firmware/kernel8.img
sudo reboot</pre>
</div>
<div class="step">
<div class="step-header"><span class="step-num">5</span> Verify and re-hold</div>
<pre>uname -r
lsblk
sudo zpool status
sudo apt-mark hold raspi-firmware linux-image-rpi-2712 linux-image-rpi-v8 linux-image-6.18.29+rpt-rpi-2712 linux-image-6.18.29+rpt-rpi-v8</pre>
<p class="result pass">Expected: sdb sdc sdd sde all present, uname shows 6.18.x, ZFS ONLINE.</p>
</div>
</div>
<!-- SECTION 8 — LESSONS LEARNED -->
<div class="section">
<div class="section-title" data-num="8">Lessons learned</div>
<table>
<thead>
<tr><th>Lesson</th><th>Detail</th></tr>
</thead>
<tbody>
<tr>
<td>Always identify exact hardware before troubleshooting</td>
<td>Run <code>cat /proc/device-tree/model</code> at the start of every session. The initial recovery misidentified NAS08 as a CM5, which placed the overlay fix under [cm5] where it was silently ignored on the Pi 5 Model B.</td>
</tr>
<tr>
<td>Never update both NAS systems at the same time</td>
<td>Update NAS08 first, confirm stable for 48hrs, then update NAS16. This approach would have prevented both systems from failing simultaneously.</td>
</tr>
<tr>
<td>config.txt conditional sections are silently ignored</td>
<td>Overlays placed under [cm4] or [cm5] are completely ignored on Pi 5 Model B hardware. There is no warning or error. Always verify placement with <code>cat /proc/device-tree/model</code> first.</td>
</tr>
<tr>
<td>Kernel 6.18 requires pcie-32bit-dma-pi5 for JMB585</td>
<td>Upstream commit ee95f3c changed DMA behaviour for the JMB585 chipset. Any Pi 5 running kernel 6.18 with the Radxa Penta SATA HAT must have <code>dtoverlay=pcie-32bit-dma-pi5</code> in the <code>[all]</code> section of config.txt or drives will not appear.</td>
</tr>
<tr>
<td>Hold kernel packages on all Pi-based NAS systems</td>
<td>Kernel updates can silently break HAT compatibility. Always hold and update deliberately, never via unattended-upgrades.</td>
</tr>
<tr>
<td>raspi-firmware manages kernel_2712.img directly</td>
<td>The post-install hook z50-raspi-firmware copies the kernel directly to /boot/firmware/kernel_2712.img. Copying an older kernel binary over this file is the correct rollback mechanism. Hold raspi-firmware before doing so or it will be overwritten on next boot.</td>
</tr>
<tr>
<td>Always simulate before upgrading</td>
<td>Run <code>sudo apt upgrade --simulate 2>&1 | grep -E "raspi-firmware|linux-image|linux-headers|Inst|Remv"</code> before every upgrade. If any kernel or firmware packages appear as Inst lines, investigate before proceeding.</td>
</tr>
</tbody>
</table>
</div>
<!-- SECTION 9 — CONFIG FILE REFERENCE -->
<div class="section">
<div class="section-title" data-num="9">Current working config — NAS08</div>
<p>This is the known-good configuration for NAS08 on kernel 6.18.29 with all four SATA drives visible and ZFS healthy.</p>
<div class="script-box">
<div class="script-row">
<div class="script-label">/boot/firmware/config.txt — bottom section</div>
<pre># Enable PCIe
dtparam=pciex1
dtparam=pciex1_gen=3
[cm4]
otg_mode=1
[cm5]
dtoverlay=dwc2,dr_mode=host
[all]
dtoverlay=pcie-32bit-dma-pi5</pre>
</div>
<div class="script-row">
<div class="script-label">/boot/firmware/cmdline.txt</div>
<pre>console=serial0,115200 console=tty1 root=PARTUUID=57cb028e-02 rootfstype=ext4 fsck.repair=yes rootwait cfg80211.ieee80211_regdom=US</pre>
</div>
<div class="script-row">
<div class="script-label">Active kernel</div>
<pre>6.18.29+rpt-rpi-2712</pre>
</div>
<div class="script-row">
<div class="script-label">Held packages</div>
<pre>raspi-firmware
linux-image-rpi-2712
linux-image-rpi-v8
linux-image-6.18.29+rpt-rpi-2712
linux-image-6.18.29+rpt-rpi-v8</pre>
</div>
</div>
</div>
<!-- SECTION 10 — NETWORK MAP -->
<div class="section">
<div class="section-title" data-num="10">Network map — items to update</div>
<table>
<thead>
<tr><th>Item</th><th>Old value</th><th>New value</th></tr>
</thead>
<tbody>
<tr>
<td>NAS08 kernel version</td>
<td><code>6.12.75+rpt-rpi-2712</code></td>
<td><code>6.18.29+rpt-rpi-2712 (held)</code></td>
</tr>
<tr>
<td>NAS08 config.txt overlay</td>
<td><code>pcie-32bit-dma-pi5 under [cm5] — ignored</code></td>
<td><code>pcie-32bit-dma-pi5 under [all] — active</code></td>
</tr>
<tr>
<td>NAS08 raspi-firmware</td>
<td><code>auto-update enabled</code></td>
<td><code>held at 1:1.20260513-1</code></td>
</tr>
<tr>
<td>NAS16 kernel + overlay fix</td>
<td><code>6.12.75 — pending upgrade</code></td>
<td><code>apply config.txt fix first, then upgrade to 6.18.29</code></td>
</tr>
<tr>
<td>ZFS report scripts</td>
<td><code>not deployed</code></td>
<td><code>zfs_report_nas08.sh + zfs_report_nas16.sh — deploy to /opt/scripts/</code></td>
</tr>
</tbody>
</table>
</div>
<div class="footer">
<span>KingDezigns Home Network</span>
<span>Updated May 16, 2026</span>
</div>
</div>
</body>
</html>