All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] ahci: force 32-bit DMA for JMicron JMB582/JMB585
@ 2026-09-06 11:48 snoep
  0 siblings, 0 replies; 20+ messages in thread
From: snoep @ 2026-09-06 11:48 UTC (permalink / raw)
  To: linux-ide@vger.kernel.org

Hi Niklas, all,

I have an additional JMB585 data point from a Raspberry Pi 5.

I ran Mikael's fio reproducer on a JMicron JMB585 (197b:0585).
There is one important limitation: the JMB585 on this Raspberry Pi 5
does not have an IOMMU group:

  iommu_group: NONE

Therefore this does not satisfy the specific request for a JMB582/JMB585
behind an Intel or ARM IOMMU in enforcing mode.

I still hope the results are useful, because this same Raspberry Pi 5
and Penta SATA HAT setup previously showed repeated EXT4 metadata
corruption which I have not yet been able to explain.

The previous investigation and actual filesystem errors are documented
here:

Radxa forum:
https://forum.radxa.com/t/repeated-ext4-metadata-corruption-on-raspberry-pi-5-with-penta-sata-hat-jmb585-despite-healthy-ssds-and-raid1/31393/6

Raspberry Pi forum:
https://forums.raspberrypi.com/viewtopic.php?p=2386959#p2386959

The original corruption occurred on an EXT4 filesystem on Linux md RAID1.
SMART and SATA CRC counters were clean, the RAID1 remained healthy, and
for one known bad EXT4 directory block both physical RAID members returned
the same data.

For this reproducer I used a single dedicated SSD behind the same JMB585.

Test system:

  Raspberry Pi 5, 8 GB
  JMicron JMB585, PCI ID 197b:0585
  Linux 6.18.34+rpt-rpi-2712
  fio 3.39
  Kingston SEDC500R960G
  AHCI driver
  PCIe Gen2
  io_uring

The 256 GiB canary used:

  bs=128k
  direct=1
  iodepth=32
  verify=crc32c
  verify_interval=4096

Test 1: normal Raspberry Pi PCIe configuration / 64-bit DMA

I did not enable:

  dtoverlay=pcie-32bit-dma-pi5

Runtime state:

  dma_mask_bits: 64
  consistent_dma_mask_bits: 64
  iommu_group: NONE

AHCI reported:

  flags: 64bit ncq sntf stag pm led clo pmp fbs pio slum part ccc apst boh

I wrote the 256 GiB canary once and completed more than 20 full
verify-only passes, approximately 5 TiB of verified reads.

No fio CRC32C verification failure occurred.

SMART remained clean and there were no relevant ATA/AHCI/EXT4 errors
in the kernel log.

Test 2: Raspberry Pi 32-bit PCIe DMA overlay

I then enabled:

  dtoverlay=pcie-32bit-dma-pi5

After reboot:

  dma_mask_bits: 31
  consistent_dma_mask_bits: 31
  iommu_group: NONE

I first verified the original 256 GiB canary written during the
64-bit DMA test. That complete verification passed.

I then wrote a new 256 GiB canary with the 31-bit DMA mask active and
ran exactly 20 verify-only passes.

Results:

  original 64-bit-written canary cross-check: PASS
  new 32-bit canary write: PASS
  32-bit verify passes: 20/20 PASS
  reads during the automated 32-bit test: 5376 GiB
  writes during the automated 32-bit test: 256.02 GiB

Final counters:

  Raw_Read_Error_Rate: 0
  SATA_Phy_Error_Count: 0
  Reported_Uncorrect: 0
  Reallocated_Event_Count: 0
  SATA_CRC_Error_Count: 0
  CRC_Error_Count: 0
  Read_Fail_Count: 0
  Interface CRC Errors: 0
  Command failed due to ICRC error: 0

So I was unable to reproduce the corruption on this Raspberry Pi 5
with either the normal 64-bit DMA configuration or the Raspberry Pi
32-bit PCIe DMA overlay.

Again, since this JMB585 has no IOMMU group, I do not consider this a
test of the Intel/ARM IOMMU enforcing-mode case.

However, I am still trying to determine what caused the repeated EXT4
metadata corruption in the original RAID1 setup, and I would appreciate
guidance on what would be most useful to test next.

Would repeating a sustained checksumming workload with the original
two-SSD md RAID1 setup be useful, or is there another workload, tracing
option, kernel configuration or test that would better help distinguish
between the JMB585/PCIe path, md RAID1, EXT4, or another component?

I have kept the test installation, both canary files and the complete
fio, SMART and kernel logs, so I can run additional tests if requested.

Kind regards,
Sven

^ permalink raw reply	[flat|nested] 20+ messages in thread
* 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; 20+ 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] 20+ 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; 20+ 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] 20+ messages in thread
* [PATCH] ahci: force 32-bit DMA for JMicron JMB582/JMB585
@ 2026-04-03  5:02 Arthur Husband
  0 siblings, 0 replies; 20+ 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] 20+ messages in thread

end of thread, other threads:[~2026-09-07 10:28 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <AM8P193MB2659454F98AD53DEB002CF8AA9B42@AM8P193MB2659.EURP193.PROD.OUTLOOK.COM>
2026-09-07 10:28 ` [PATCH] ahci: force 32-bit DMA for JMicron JMB582/JMB585 Niklas Cassel
2026-09-06 11:48 snoep
  -- strict thread matches above, loose matches on Subject: below --
2026-09-03 13:35 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
2026-09-06  5:05                   ` Alvin Lim
2026-09-06 19:27                     ` John Smith
2026-09-05 14:13               ` Lennert Buytenhek
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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.