Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ahci: warn about remapped NVMe devices

Some Intel ahci implementations have a completely broken remapping mode
where they hide one or more NVMe devices behind the bar of an AHCI device.

Intel refuses to let the OS reprogram the BIOS to switch out of this
mode at runtime, and so far we're not come up with another good way
to undo the mess that the Chipset people created. So for now the only
thing we can do is to alert users about this situation and switch to the
faster and much saner so called "AHCI" mode insted of the RAID mode in
the BIOS so that the BIOS does not hide the NVMe devices from us.

The sitation is even worse as at least one vendor (thanks a lot Lenovo..)
has started hardcoding their BIOS into the "RAID" mode even for laptops
that don't use AHCI _at all_ and just have a single NVMe device. For now
there is an unspported Linux-only BIOS that undoes this braindamage,
but we'll have to see if things are getting better or worse from here.

Based on an earlier patch from Dan Williams <dan.j.williams@intel.com>.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Tejun Heo <tj@kernel.org>

authored by

Christoph Hellwig and committed by
Tejun Heo
aecec8b6 bfa9cb3e

+39
+39
drivers/ata/ahci.c
··· 46 46 #include <scsi/scsi_host.h> 47 47 #include <scsi/scsi_cmnd.h> 48 48 #include <linux/libata.h> 49 + #include <linux/ahci-remap.h> 50 + #include <linux/io-64-nonatomic-lo-hi.h> 49 51 #include "ahci.h" 50 52 51 53 #define DRV_NAME "ahci" ··· 1402 1400 } 1403 1401 #endif 1404 1402 1403 + static void ahci_remap_check(struct pci_dev *pdev, int bar, 1404 + struct ahci_host_priv *hpriv) 1405 + { 1406 + int i, count = 0; 1407 + u32 cap; 1408 + 1409 + /* 1410 + * Check if this device might have remapped nvme devices. 1411 + */ 1412 + if (pdev->vendor != PCI_VENDOR_ID_INTEL || 1413 + pci_resource_len(pdev, bar) < SZ_512K || 1414 + bar != AHCI_PCI_BAR_STANDARD || 1415 + !(readl(hpriv->mmio + AHCI_VSCAP) & 1)) 1416 + return; 1417 + 1418 + cap = readq(hpriv->mmio + AHCI_REMAP_CAP); 1419 + for (i = 0; i < AHCI_MAX_REMAP; i++) { 1420 + if ((cap & (1 << i)) == 0) 1421 + continue; 1422 + if (readl(hpriv->mmio + ahci_remap_dcc(i)) 1423 + != PCI_CLASS_STORAGE_EXPRESS) 1424 + continue; 1425 + 1426 + /* We've found a remapped device */ 1427 + count++; 1428 + } 1429 + 1430 + if (!count) 1431 + return; 1432 + 1433 + dev_warn(&pdev->dev, "Found %d remapped NVMe devices.\n", count); 1434 + dev_warn(&pdev->dev, "Switch your BIOS from RAID to AHCI mode to use them.\n"); 1435 + } 1436 + 1405 1437 static int ahci_get_irq_vector(struct ata_host *host, int port) 1406 1438 { 1407 1439 return pci_irq_vector(to_pci_dev(host->dev), port); ··· 1580 1544 hpriv->flags &= ~AHCI_HFLAG_32BIT_ONLY; 1581 1545 1582 1546 hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar]; 1547 + 1548 + /* detect remapped nvme devices */ 1549 + ahci_remap_check(pdev, ahci_pci_bar, hpriv); 1583 1550 1584 1551 /* must set flag prior to save config in order to take effect */ 1585 1552 if (ahci_broken_devslp(pdev))