Linux ATA/IDE development
 help / color / mirror / Atom feed
* Re: [PATCH] ahci: force 32-bit DMA for JMicron JMB582/JMB585
@ 2026-09-03 13:35 Roland Waltersson
  2026-09-03 21:40 ` Niklas Cassel
  0 siblings, 1 reply; 15+ messages in thread
From: Roland Waltersson @ 2026-09-03 13:35 UTC (permalink / raw)
  To: artmoty@gmail.com; +Cc: linux-ide@vger.kernel.org


(analysis provided by Claude)
Hello,

Commit 105c42566a55 ("ata: ahci: force 32-bit DMA for JMicron
JMB582/JMB585") makes a JMicron JMB585 unusable on our board.  I
believe the cause is not the quirk itself but a pre-existing gap in
ahci_start_fis_rx(), which the quirk newly exposes for this
controller.

Hardware
--------

  - congatec conga-TCR8 COM Express Type 6 module
    (AMD Ryzen Embedded 8000, Zen 4), BIOS TCR8R904 dated 2025-11-11
  - JMicron JMB585 SATA controller on our own carrier board,
    at PCI 0000:02:00.0
  - AMD-Vi IOMMU enabled, default (lazy DMA) domain type

Symptom
-------

The controller's link never comes up and the boot dies:

  ahci 0000:02:00.0: AMD-Vi: Event logged [IO_PAGE_FAULT domain=0x0001 address=0x80fffc0440 flags=0x0030]
  ahci 0000:02:00.0: AMD-Vi: Event logged [IO_PAGE_FAULT domain=0x0001 address=0x80fffc0000 flags=0x0010]
  ata2: softreset failed (1st FIS failed)
  ata2: reset failed, giving up

The disk never appears, so our initramfs cannot mount the rootfs and
switch_root panics with "Attempted to kill init!".

Analysis
--------

AHCI_HFLAG_32BIT_ONLY causes ahci_save_initial_config() to clear
HOST_CAP_64.  In ahci_start_fis_rx(), the upper halves of the command
list and FIS receive base addresses are written only when HOST_CAP_64
is set:

      if (hpriv->cap & HOST_CAP_64)
            writel((pp->cmd_slot_dma >> 16) >> 16,
                   port_mmio + PORT_LST_ADDR_HI);
      writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);

      if (hpriv->cap & HOST_CAP_64)
            writel((pp->rx_fis_dma >> 16) >> 16,
                   port_mmio + PORT_FIS_ADDR_HI);
      writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);

There is no else branch, so with the quirk active PxCLBU and PxFBU are
never written and retain whatever firmware left in them.

The fault addresses decompose accordingly:

  0x80fffc0000  ->  low 0xfffc0000, high 0x00000080
  0x80fffc0440  ->  low 0xfffc0440, high 0x00000080

The low halves are exactly the IOVAs dma-iommu hands out for a
32-bit-masked PCI device (the allocator works downward from the top of
the range, so the command list and FIS receive area land just under
4 GB).  The constant 0x80 in the high half is a value the kernel never
wrote; on this platform it places the DMA target at 512 GB, inside the
above-4G PCIe MMIO window.

This also explains why booting with iommu=off does not help: without
the IOMMU the transfer simply goes to that MMIO address silently
instead of faulting, and the FIS still never arrives.

Confirmation
------------

Reverting 105c42566a55 restores normal operation.  That is obviously
not a fix, since it reinstates the broken 64-bit DMA the commit exists
to prevent.


I have only reproduced this on 5.15.215 (the quirk reached us as
4fc637dcad14 in v5.15.209); I have not tested mainline.  The
ahci_start_fis_rx() code above is however unchanged in current
mainline, so I expect any AHCI_HFLAG_32BIT_ONLY controller sitting
behind an IOMMU whose firmware leaves PxCLBU/PxFBU non-zero to hit the
same problem.

I can test patches on this hardware.

Thanks,
Roland Waltersson

^ permalink raw reply	[flat|nested] 15+ messages in thread
* [PATCH] ahci: force 32-bit DMA for JMicron JMB582/JMB585
@ 2026-04-03  5:04 Arthur Husband
  2026-04-03  7:02 ` Damien Le Moal
                   ` (2 more replies)
  0 siblings, 3 replies; 15+ messages in thread
From: Arthur Husband @ 2026-04-03  5:04 UTC (permalink / raw)
  To: linux-ide; +Cc: dlemoal, cassel, artmoty

The JMicron JMB585 (and JMB582) SATA controllers advertise 64-bit DMA
support via the S64A bit in the AHCI CAP register, but their 64-bit DMA
implementation is defective. Under sustained I/O, DMA transfers targeting
addresses above 4GB silently corrupt data — writes land at incorrect
memory addresses with no errors logged.

This has been confirmed on multiple platforms (Minisforum N5 Pro,
Raspberry Pi, Unraid, Proxmox, TrueNAS) and is consistent with the
controller truncating or mishandling upper address bits during 64-bit
DMA transactions.

The failure pattern is identical to the ASMedia ASM1062 (commit
edb96a15dc18), which also falsely advertised 64-bit DMA and was fixed
with AHCI_HFLAG_32BIT_ONLY.

On the Minisforum N5 Pro specifically, the combination of the JMB585's
broken 64-bit DMA with the AMD Family 1Ah (Strix Point) IOMMU causes
silent data corruption that is only detectable via checksumming
filesystems (BTRFS/ZFS scrub). The corruption occurs when 32-bit IOVA
space is exhausted and the kernel transparently switches to 64-bit DMA
addresses.

Add device-specific PCI ID entries for the JMB582 (0x0582) and JMB585
(0x0585) before the generic JMicron class match, using a new board type
that combines AHCI_HFLAG_IGN_IRQ_IF_ERR (preserving existing behavior)
with AHCI_HFLAG_32BIT_ONLY to force 32-bit DMA masks.

Investigation and patch development assisted by Claude (Anthropic AI).

Signed-off-by: Arthur Husband <artmoty@gmail.com>
---
 drivers/ata/ahci.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index XXXXXXX..XXXXXXX 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -51,6 +51,7 @@ enum board_ids {
 	board_ahci,
 	board_ahci_43bit_dma,
 	board_ahci_ign_iferr,
+	board_ahci_jmb585,
 	board_ahci_no_debounce_delay,
 	board_ahci_no_msi,
 	/*
@@ -115,6 +116,14 @@ static const struct ata_port_info ahci_port_info[] = {
 		.udma_mask	= ATA_UDMA6,
 		.port_ops	= &ahci_ops,
 	},
+	/* JMicron JMB582/585: 64-bit DMA is broken, force 32-bit */
+	[board_ahci_jmb585] = {
+		AHCI_HFLAGS	(AHCI_HFLAG_IGN_IRQ_IF_ERR |
+				 AHCI_HFLAG_32BIT_ONLY),
+		.flags		= AHCI_FLAG_COMMON,
+		.pio_mask	= ATA_PIO4,
+		.udma_mask	= ATA_UDMA6,
+		.port_ops	= &ahci_ops,
+	},
 	[board_ahci_no_debounce_delay] = {
 		.flags		= AHCI_FLAG_COMMON,
 		.link_flags	= ATA_LFLAG_NO_DEBOUNCE_DELAY,
@@ -XXX,7 +XXX,12 @@ static const struct pci_device_id ahci_pci_tbl[] = {
 	...

-	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
+	/* JMicron JMB582/585: force 32-bit DMA (broken 64-bit implementation) */
+	{ PCI_VDEVICE(JMICRON, 0x0582), board_ahci_jmb585 },
+	{ PCI_VDEVICE(JMICRON, 0x0585), board_ahci_jmb585 },
+
+	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },

--

^ permalink raw reply	[flat|nested] 15+ messages in thread
* [PATCH] ahci: force 32-bit DMA for JMicron JMB582/JMB585
@ 2026-04-03  5:02 Arthur Husband
  0 siblings, 0 replies; 15+ messages in thread
From: Arthur Husband @ 2026-04-03  5:02 UTC (permalink / raw)
  To: linux-ide; +Cc: artmoty

The JMicron JMB585 (and JMB582) SATA controllers advertise 64-bit DMA
support via the S64A bit in the AHCI CAP register, but their 64-bit DMA
implementation is defective. Under sustained I/O, DMA transfers targeting
addresses above 4GB silently corrupt data — writes land at incorrect
memory addresses with no errors logged.

This has been confirmed on multiple platforms (Minisforum N5 Pro,
Raspberry Pi, Unraid, Proxmox, TrueNAS) and is consistent with the
controller truncating or mishandling upper address bits during 64-bit
DMA transactions.

The failure pattern is identical to the ASMedia ASM1062 (commit
edb96a15dc18), which also falsely advertised 64-bit DMA and was fixed
with AHCI_HFLAG_32BIT_ONLY.

On the Minisforum N5 Pro specifically, the combination of the JMB585's
broken 64-bit DMA with the AMD Family 1Ah (Strix Point) IOMMU causes
silent data corruption that is only detectable via checksumming
filesystems (BTRFS/ZFS scrub). The corruption occurs when 32-bit IOVA
space is exhausted and the kernel transparently switches to 64-bit DMA
addresses.

Add device-specific PCI ID entries for the JMB582 (0x0582) and JMB585
(0x0585) before the generic JMicron class match, using a new board type
that combines AHCI_HFLAG_IGN_IRQ_IF_ERR (preserving existing behavior)
with AHCI_HFLAG_32BIT_ONLY to force 32-bit DMA masks.

Investigation and patch development assisted by Claude (Anthropic AI).

Signed-off-by: Arthur Husband <artmoty@gmail.com>
---
 drivers/ata/ahci.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index XXXXXXX..XXXXXXX 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -51,6 +51,7 @@ enum board_ids {
 	board_ahci,
 	board_ahci_43bit_dma,
 	board_ahci_ign_iferr,
+	board_ahci_jmb585,
 	board_ahci_no_debounce_delay,
 	board_ahci_no_msi,
 	/*
@@ -115,6 +116,14 @@ static const struct ata_port_info ahci_port_info[] = {
 		.udma_mask	= ATA_UDMA6,
 		.port_ops	= &ahci_ops,
 	},
+	/* JMicron JMB582/585: 64-bit DMA is broken, force 32-bit */
+	[board_ahci_jmb585] = {
+		AHCI_HFLAGS	(AHCI_HFLAG_IGN_IRQ_IF_ERR |
+				 AHCI_HFLAG_32BIT_ONLY),
+		.flags		= AHCI_FLAG_COMMON,
+		.pio_mask	= ATA_PIO4,
+		.udma_mask	= ATA_UDMA6,
+		.port_ops	= &ahci_ops,
+	},
 	[board_ahci_no_debounce_delay] = {
 		.flags		= AHCI_FLAG_COMMON,
 		.link_flags	= ATA_LFLAG_NO_DEBOUNCE_DELAY,
@@ -XXX,7 +XXX,12 @@ static const struct pci_device_id ahci_pci_tbl[] = {
 	...

-	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
+	/* JMicron JMB582/585: force 32-bit DMA (broken 64-bit implementation) */
+	{ PCI_VDEVICE(JMICRON, 0x0582), board_ahci_jmb585 },
+	{ PCI_VDEVICE(JMICRON, 0x0585), board_ahci_jmb585 },
+
+	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },

--

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2026-09-05 12:26 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-03 13:35 [PATCH] ahci: force 32-bit DMA for JMicron JMB582/JMB585 Roland Waltersson
2026-09-03 21:40 ` Niklas Cassel
2026-09-03 22:36   ` Mario Limonciello
2026-09-04  5:20     ` Roland Waltersson
2026-09-04 11:14       ` Niklas Cassel
2026-09-04 12:38         ` Mario Limonciello
2026-09-04 12:50           ` Niklas Cassel
2026-09-04 16:55             ` Mikael Etienne
2026-09-05 11:38               ` Alvin Lim
2026-09-05 12:26                 ` Mario Limonciello
  -- strict thread matches above, loose matches on Subject: below --
2026-04-03  5:04 Arthur Husband
2026-04-03  7:02 ` Damien Le Moal
2026-04-03  8:12 ` Niklas Cassel
2026-04-03  8:19 ` Niklas Cassel
2026-04-03  5:02 Arthur Husband

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox