aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2016-12-02 13:31:03 -0500
committerTejun Heo <tj@kernel.org>2016-12-05 14:31:24 -0500
commitaecec8b60422118b52e3347430ba9382e57d6d76 (patch)
tree18201426039369667148624586fc68d14174dfe4
parentbfa9cb3e110cc02f2120e021bc853773bfd61b74 (diff)
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>
-rw-r--r--drivers/ata/ahci.c39
1 files changed, 39 insertions, 0 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index ba5f11cebee2..516a689c5f5f 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -46,6 +46,8 @@
46#include <scsi/scsi_host.h> 46#include <scsi/scsi_host.h>
47#include <scsi/scsi_cmnd.h> 47#include <scsi/scsi_cmnd.h>
48#include <linux/libata.h> 48#include <linux/libata.h>
49#include <linux/ahci-remap.h>
50#include <linux/io-64-nonatomic-lo-hi.h>
49#include "ahci.h" 51#include "ahci.h"
50 52
51#define DRV_NAME "ahci" 53#define DRV_NAME "ahci"
@@ -1400,6 +1402,40 @@ static irqreturn_t ahci_thunderx_irq_handler(int irq, void *dev_instance)
1400} 1402}
1401#endif 1403#endif
1402 1404
1405static void ahci_remap_check(struct pci_dev *pdev, int bar,
1406 struct ahci_host_priv *hpriv)
1407{
1408 int i, count = 0;
1409 u32 cap;
1410
1411 /*
1412 * Check if this device might have remapped nvme devices.
1413 */
1414 if (pdev->vendor != PCI_VENDOR_ID_INTEL ||
1415 pci_resource_len(pdev, bar) < SZ_512K ||
1416 bar != AHCI_PCI_BAR_STANDARD ||
1417 !(readl(hpriv->mmio + AHCI_VSCAP) & 1))
1418 return;
1419
1420 cap = readq(hpriv->mmio + AHCI_REMAP_CAP);
1421 for (i = 0; i < AHCI_MAX_REMAP; i++) {
1422 if ((cap & (1 << i)) == 0)
1423 continue;
1424 if (readl(hpriv->mmio + ahci_remap_dcc(i))
1425 != PCI_CLASS_STORAGE_EXPRESS)
1426 continue;
1427
1428 /* We've found a remapped device */
1429 count++;
1430 }
1431
1432 if (!count)
1433 return;
1434
1435 dev_warn(&pdev->dev, "Found %d remapped NVMe devices.\n", count);
1436 dev_warn(&pdev->dev, "Switch your BIOS from RAID to AHCI mode to use them.\n");
1437}
1438
1403static int ahci_get_irq_vector(struct ata_host *host, int port) 1439static int ahci_get_irq_vector(struct ata_host *host, int port)
1404{ 1440{
1405 return pci_irq_vector(to_pci_dev(host->dev), port); 1441 return pci_irq_vector(to_pci_dev(host->dev), port);
@@ -1545,6 +1581,9 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
1545 1581
1546 hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar]; 1582 hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
1547 1583
1584 /* detect remapped nvme devices */
1585 ahci_remap_check(pdev, ahci_pci_bar, hpriv);
1586
1548 /* must set flag prior to save config in order to take effect */ 1587 /* must set flag prior to save config in order to take effect */
1549 if (ahci_broken_devslp(pdev)) 1588 if (ahci_broken_devslp(pdev))
1550 hpriv->flags |= AHCI_HFLAG_NO_DEVSLP; 1589 hpriv->flags |= AHCI_HFLAG_NO_DEVSLP;