From f1ab1f30fe52bea7dc5c647b0570d73d907b8d90 Mon Sep 17 00:00:00 2001
From: Jon Nettleton <jon@solid-run.com>
Date: Fri, 28 Jul 2017 08:54:09 +0200
Subject: [PATCH 1/6] nvme: Only support CONFIG_BLK

There is no reason to support devices that don't work with
CONFIG_BLK.  If needed the other drivers should be fixed.

Signed-off-by: Jon Nettleton <jon@solid-run.com>
---
 common/nvme.c         | 33 ---------------------------
 drivers/block/Kconfig |  1 +
 drivers/block/nvme.c  | 63 ---------------------------------------------------
 drivers/block/nvme.h  |  2 --
 include/nvme.h        | 10 +-------
 5 files changed, 2 insertions(+), 107 deletions(-)

diff --git a/common/nvme.c b/common/nvme.c
index ed3250f43f..cdbfa665a0 100644
--- a/common/nvme.c
+++ b/common/nvme.c
@@ -21,7 +21,6 @@ struct blk_desc *nvme_get_dev(int dev)
 }
 #endif
 
-#ifdef CONFIG_BLK
 struct udevice *udev;
 static unsigned long nvme_bread(struct udevice *dev, lbaint_t start,
 				lbaint_t blkcnt, void *dst)
@@ -34,19 +33,6 @@ static unsigned long nvme_bwrite(struct udevice *dev, lbaint_t start,
 {
 	return nvme_write(dev, start, blkcnt, buffer);
 }
-#else
-static unsigned long nvme_bread(struct blk_desc *block_dev, lbaint_t start,
-				lbaint_t blkcnt, void *dst)
-{
-	return nvme_read(block_dev->devnum, start, blkcnt, dst);
-}
-
-static unsigned long nvme_bwrite(struct blk_desc *block_dev, lbaint_t start,
-				 lbaint_t blkcnt, const void *buffer)
-{
-	return nvme_write(block_dev->devnum, start, blkcnt, buffer);
-}
-#endif
 
 int __nvme_initialize(void)
 {
@@ -54,25 +40,15 @@ int __nvme_initialize(void)
 	int i;
 
 	for (i = 0; i < CONFIG_SYS_NVME_MAX_DEVICE; i++) {
-#ifdef CONFIG_BLK
 		rc = init_nvme(udev);
 		if (!rc)
 			rc = scan_nvme(udev);
-#else
-		rc = init_nvme(i);
-		if (!rc)
-			rc = scan_nvme(i);
-#endif
 
 		if (!rc && nvme_dev_desc[i].lba > 0) {
 			nvme_dev_desc[i].if_type = IF_TYPE_NVME;
 			nvme_dev_desc[i].devnum = i;
 			nvme_dev_desc[i].part_type = PART_TYPE_UNKNOWN;
 			nvme_dev_desc[i].type = DEV_TYPE_HARDDISK;
-#ifndef CONFIG_BLK
-			nvme_dev_desc[i].block_read = nvme_bread;
-			nvme_dev_desc[i].block_write = nvme_bwrite;
-#endif
 
 			part_init(&nvme_dev_desc[i]);
 			ret = i;
@@ -88,7 +64,6 @@ int __nvme_initialize(void)
 }
 int nvme_initialize(void) __attribute__((weak, alias("__nvme_initialize")));
 
-#ifdef CONFIG_BLK
 static void nvme_name(char *str, int cardnum)
 {
 	sprintf(str, "nvme#%u", cardnum);
@@ -117,11 +92,3 @@ U_BOOT_DRIVER(nvme) = {
 	.priv_auto_alloc_size	= sizeof(struct nvme_ns),
 };
 U_BOOT_PCI_DEVICE(nvme, nvme_supported);
-#else
-U_BOOT_LEGACY_BLK(nvme) = {
-	.if_typename	= "nvme",
-	.if_type	= IF_TYPE_NVME,
-	.max_devs	= CONFIG_SYS_NVME_MAX_DEVICE,
-	.desc		= nvme_dev_desc,
-};
-#endif
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 129208f980..de1a3a50c1 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -63,6 +63,7 @@ endmenu
 config NVME
 	bool "Support NVMe devices"
 	depends on PCI
+	depends on BLK
 	help
 	  This option enables supporting for all NVMe devices.
 	  It supports the basic functions before using NVMe devices
diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c
index 2e06477206..80fbd27d95 100644
--- a/drivers/block/nvme.c
+++ b/drivers/block/nvme.c
@@ -549,13 +549,8 @@ static int nvme_get_info_from_identify(struct nvme_dev *dev)
 	if (ctrl->mdts)
 		dev->max_transfer_shift = (ctrl->mdts + shift);
 
-#ifdef CONFIG_BLK
 	dm_pci_read_config16(dev->pdev, PCI_VENDOR_ID, &vendor);
 	dm_pci_read_config16(dev->pdev, PCI_DEVICE_ID, &device);
-#else
-	pci_read_config_word(dev->pci_dev, PCI_VENDOR_ID, &vendor);
-	pci_read_config_word(dev->pci_dev, PCI_DEVICE_ID, &device);
-#endif
 	if ((vendor == PCI_VENDOR_ID_INTEL) &&
 	    (device == 0x0953) && ctrl->vs[3]) {
 		unsigned int max_transfer_shift;
@@ -571,22 +566,14 @@ static int nvme_get_info_from_identify(struct nvme_dev *dev)
 	return 0;
 }
 
-#ifdef CONFIG_BLK
 int init_nvme(struct udevice *udev)
-#else
-int init_nvme(int devnum)
-#endif
 {
 	static int init_done;
 	pci_dev_t pci_dev;
 	int ret;
-#ifdef CONFIG_BLK
 	struct nvme_ns *ns = dev_get_priv(udev);
 	struct nvme_dev *dev = ns->dev;
 	int devnum = trailing_strtol(udev->name);
-#else
-	struct nvme_dev *dev;
-#endif
 	u32 val;
 	u64 cap;
 
@@ -611,15 +598,9 @@ int init_nvme(int devnum)
 
 	dev->instance = nvme_info.idx - 1;
 	INIT_LIST_HEAD(&dev->namespaces);
-#ifdef CONFIG_BLK
 	dev->pdev = udev;
 	dev->bar = dm_pci_map_bar(udev, PCI_BASE_ADDRESS_0,
 			PCI_REGION_MEM);
-#else
-	dev->pci_dev = pci_dev;
-	dev->bar = pci_map_bar(dev->pci_dev, PCI_BASE_ADDRESS_0,
-			PCI_REGION_MEM);
-#endif
 	if (readl(&dev->bar->csts) == -1) {
 		ret = -ENODEV;
 		printf("Error: nvme%d: Out of Memory!\n", nvme_info.idx - 1);
@@ -644,25 +625,13 @@ int init_nvme(int devnum)
 
 	/* Try to enable I/O accesses and bus-mastering */
 	val = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
-#ifdef CONFIG_BLK
 	dm_pci_write_config32(udev, PCI_COMMAND, val);
-#else
-	pci_write_config_dword(dev->pci_dev, PCI_COMMAND, val);
-#endif
 
 	/* Print a debug message with the IO base address */
-#ifdef CONFIG_BLK
 	dm_pci_read_config32(udev, PCI_BASE_ADDRESS_0, &val);
-#else
-	pci_read_config_dword(dev->pci_dev, PCI_BASE_ADDRESS_0, &val);
-#endif
 
 	/* Make sure it worked */
-#ifdef CONFIG_BLK
 	dm_pci_read_config32(udev, PCI_COMMAND, &val);
-#else
-	pci_read_config_dword(dev->pci_dev, PCI_COMMAND, &val);
-#endif
 	if (!(val & PCI_COMMAND_MEMORY)) {
 		printf("Can't enable I/O memory\n");
 		ret = -ENOSPC;
@@ -732,18 +701,11 @@ static struct nvme_ns *find_ns_by_devnum(int devnum)
 	return NULL;
 }
 
-#ifdef CONFIG_BLK
 int scan_nvme(struct udevice *udev)
 {
 	struct nvme_ns *ns = dev_get_priv(udev);
 	struct nvme_dev *dev = ns->dev;
 	int devnum = trailing_strtol(udev->name);
-#else
-int scan_nvme(int devnum)
-{
-	struct nvme_ns *ns;
-	struct nvme_dev *dev;
-#endif
 	int ret;
 	u8 flbas;
 	u16 vendor;
@@ -783,15 +745,10 @@ int scan_nvme(int devnum)
 	nvme_dev_desc[devnum].lba = ns->mode_select_num_blocks;
 	nvme_dev_desc[devnum].log2blksz = ns->lba_shift;
 	nvme_dev_desc[devnum].blksz = 1 << ns->lba_shift;
-#ifdef CONFIG_BLK
 	nvme_dev_desc[devnum].bdev = dev->pdev;
 	dm_pci_read_config16(dev->pdev, PCI_VENDOR_ID, &vendor);
 	udev->priv = ns;
 	udev->uclass_platdata = (void *)&nvme_dev_desc[devnum];
-#else
-	nvme_dev_desc[devnum].priv = (void *)ns;
-	pci_read_config_word(dev->pci_dev, PCI_VENDOR_ID, &vendor);
-#endif
 	sprintf(vendor_c, "0x%.4x", vendor);
 	memcpy(nvme_dev_desc[devnum].product,
 	       dev->serial, sizeof(dev->serial));
@@ -895,13 +852,9 @@ static void print_metadata_cap(u8 mc, int devnum)
 
 int nvme_print_info(int devnum)
 {
-#ifdef CONFIG_BLK
 	struct udevice *udev;
 	blk_get_device(IF_TYPE_NVME, devnum, &udev);
 	struct nvme_ns *ns = dev_get_priv(udev);
-#else
-	struct nvme_ns *ns = nvme_dev_desc[devnum].priv;
-#endif
 	if (!ns) {
 		printf("Can not find device %d\n", devnum);
 		return -EINVAL;
@@ -927,20 +880,12 @@ int nvme_print_info(int devnum)
 	return 0;
 }
 
-#ifdef CONFIG_BLK
 ulong nvme_write(struct udevice *udev, ulong blknr, lbaint_t blkcnt,
 		const void *buffer)
 {
 	struct nvme_ns *ns = dev_get_priv(udev);
 	struct nvme_dev *dev = ns->dev;
 	int devnum = ns->devnum;
-#else
-ulong nvme_write(int devnum, ulong blknr, lbaint_t blkcnt,
-		const void *buffer)
-{
-	struct nvme_ns *ns = nvme_dev_desc[devnum].priv;
-	struct nvme_dev *dev = ns->dev;
-#endif
 	struct nvme_command c;
 	int status;
 	u64 prp2;
@@ -987,20 +932,12 @@ ulong nvme_write(int devnum, ulong blknr, lbaint_t blkcnt,
 	return (total_len - temp_len) >> nvme_dev_desc[devnum].log2blksz;
 }
 
-#ifdef CONFIG_BLK
 ulong nvme_read(struct udevice *udev, ulong blknr, lbaint_t blkcnt,
 		void *buffer)
 {
 	struct nvme_ns *ns = dev_get_priv(udev);
 	struct nvme_dev *dev = ns->dev;
 	int devnum = ns->devnum;
-#else
-ulong nvme_read(int devnum, ulong blknr, lbaint_t blkcnt,
-		void *buffer)
-{
-	struct nvme_ns *ns = nvme_dev_desc[devnum].priv;
-	struct nvme_dev *dev = ns->dev;
-#endif
 	struct nvme_command c;
 	int status;
 	u64 prp2;
diff --git a/drivers/block/nvme.h b/drivers/block/nvme.h
index 9345f90a1c..f0fad95b7b 100644
--- a/drivers/block/nvme.h
+++ b/drivers/block/nvme.h
@@ -61,9 +61,7 @@ struct nvme_dev {
 	struct nvme_queue **queues;
 	u32 __iomem *dbs;
 	unsigned int cardnum;
-#ifdef CONFIG_BLK
 	struct udevice *pdev;
-#endif
 	pci_dev_t pci_dev;
 	int instance;
 	uint8_t *hw_addr;
diff --git a/include/nvme.h b/include/nvme.h
index 3f8f94f462..e13de19163 100644
--- a/include/nvme.h
+++ b/include/nvme.h
@@ -7,22 +7,14 @@
 #ifndef __NVME_H__
 #define __NVME_H__
 #include <part.h>
+#include <pci.h>
 
-#ifdef CONFIG_BLK
 int init_nvme(struct udevice *udev);
 int scan_nvme(struct udevice *udev);
 ulong nvme_read(struct udevice *udev, ulong blknr, lbaint_t blkcnt,
 		void *buffer);
 ulong nvme_write(struct udevice *udev, ulong blknr, lbaint_t blkcnt,
 		const void *buffer);
-#else
-int init_nvme(int devnum);
-int scan_nvme(int devnum);
-ulong nvme_read(int devnum, ulong blknr, lbaint_t blkcnt,
-		void *buffer);
-ulong nvme_write(int devnum, ulong blknr, lbaint_t blkcnt,
-		const void *buffer);
-#endif
 int nvme_print_info(int devnum);
 int nvme_initialize(void);
 int __nvme_initialize(void);
-- 
2.11.1


From 5de8da9db30a54db6239f0947d61ef92043aac30 Mon Sep 17 00:00:00 2001
From: Jon Nettleton <jon@solid-run.com>
Date: Fri, 28 Jul 2017 09:00:48 +0200
Subject: [PATCH 2/6] NVMe: correctly identify NVMe Device.

IF_TYPE_NVME is not an unknown device any longer.

Signed-off-by: Jon Nettleton <jon@solid-run.com>
---
 disk/part.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/disk/part.c b/disk/part.c
index 983104e349..8a5d29923c 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -271,6 +271,9 @@ static void print_part_header(const char *type, struct blk_desc *dev_desc)
 	case IF_TYPE_HOST:
 		puts("HOST");
 		break;
+	case IF_TYPE_NVME:
+		puts("NVME");
+		break;
 	default:
 		puts ("UNKNOWN");
 		break;
-- 
2.11.1


From 81c8d7935b345bd9fb659e2a368bf1dab6325212 Mon Sep 17 00:00:00 2001
From: Jon Nettleton <jon@solid-run.com>
Date: Fri, 28 Jul 2017 09:04:08 +0200
Subject: [PATCH 3/6] NVMe: Only increment device if probing is successful

Any time along the init process we should make sure and decrement
the nvme id if we fail.  Otherwise constant probing will keep
incrementing the device counter.

Signed-off-by: Jon Nettleton <jon@solid-run.com>
---
 drivers/block/nvme.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c
index 80fbd27d95..39eb066b6d 100644
--- a/drivers/block/nvme.c
+++ b/drivers/block/nvme.c
@@ -585,13 +585,13 @@ int init_nvme(struct udevice *udev)
 	pci_dev  = pci_find_devices(nvme_supported, nvme_info.idx++);
 	if (pci_dev == -1) {
 		printf("Error: can't find pci device \"nvme%d\"\n",
-		       nvme_info.idx - 1);
+		       --nvme_info.idx);
 		return -ENODEV;
 	}
 
 	dev = malloc(sizeof(*dev));
 	if (dev == NULL) {
-		printf("Error: nvme%d: Out of Memory!\n", nvme_info.idx - 1);
+		printf("Error: nvme%d: Out of Memory!\n", --nvme_info.idx);
 		return -ENOMEM;
 	}
 	memset(dev, 0, sizeof(*dev));
@@ -603,7 +603,7 @@ int init_nvme(struct udevice *udev)
 			PCI_REGION_MEM);
 	if (readl(&dev->bar->csts) == -1) {
 		ret = -ENODEV;
-		printf("Error: nvme%d: Out of Memory!\n", nvme_info.idx - 1);
+		printf("Error: nvme%d: Out of Memory!\n", --nvme_info.idx);
 		goto free_nvme;
 	}
 
-- 
2.11.1


From eca9727cc11832e9e1e8ecab174189242424bb5d Mon Sep 17 00:00:00 2001
From: Jon Nettleton <jon@solid-run.com>
Date: Fri, 28 Jul 2017 09:06:11 +0200
Subject: [PATCH 4/6] NVMe: fix number of blocks detection.

NVMe should use the nsze value from the queried device.  This will
reflect the total number of blocks of the device and fixes detecting
my Samsung 960 EVO 256GB.

Original:
Capacity: 40386.6 MB = 39.4 GB (82711872 x 512)

Fixed:
Capacity: 238475.1 MB = 232.8 GB (488397168 x 512)
Signed-off-by: Jon Nettleton <jon@solid-run.com>
---
 drivers/block/nvme.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c
index 39eb066b6d..6d2437503b 100644
--- a/drivers/block/nvme.c
+++ b/drivers/block/nvme.c
@@ -739,7 +739,7 @@ int scan_nvme(struct udevice *udev)
 	flbas = id->flbas & NVME_NS_FLBAS_LBA_MASK;
 	ns->flbas = flbas;
 	ns->lba_shift = id->lbaf[flbas].ds;
-	ns->mode_select_num_blocks = le64_to_cpu(id->nuse);
+	ns->mode_select_num_blocks = le64_to_cpu(id->nsze);
 	ns->mode_select_block_len = 1 << ns->lba_shift;
 	list_add(&ns->list, &dev->namespaces);
 	nvme_dev_desc[devnum].lba = ns->mode_select_num_blocks;
-- 
2.11.1


From 92637e5499af333913284a9d8324b7ad861b7c54 Mon Sep 17 00:00:00 2001
From: Jon Nettleton <jon@solid-run.com>
Date: Fri, 28 Jul 2017 09:10:22 +0200
Subject: [PATCH 5/6] NVMe: Detect devices that are class Storage Express

This adds support to detect the catchall PCI class for NVMe devices.
It allows the drivers to work with most NVMe devices that don't need
specific detection due to quirks etc.  Tested against a Samsung
960 EVO drive.

Signed-off-by: Jon Nettleton <jon@solid-run.com>
---
 common/nvme.c        | 2 ++
 drivers/block/nvme.c | 6 +++++-
 include/pci_ids.h    | 1 +
 3 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/common/nvme.c b/common/nvme.c
index cdbfa665a0..253e5bb7c2 100644
--- a/common/nvme.c
+++ b/common/nvme.c
@@ -12,8 +12,10 @@ struct blk_desc nvme_dev_desc[CONFIG_SYS_NVME_MAX_DEVICE];
 
 struct pci_device_id nvme_supported[] = {
 		{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0953) },
+		{ PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_EXPRESS, 0xffffff) },	
 		{}
 };
+
 #ifdef CONFIG_PARTITIONS
 struct blk_desc *nvme_get_dev(int dev)
 {
diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c
index 6d2437503b..26d6400a22 100644
--- a/drivers/block/nvme.c
+++ b/drivers/block/nvme.c
@@ -582,7 +582,11 @@ int init_nvme(struct udevice *udev)
 		return 0;
 	}
 
-	pci_dev  = pci_find_devices(nvme_supported, nvme_info.idx++);
+	pci_dev = pci_find_class(PCI_CLASS_STORAGE_EXPRESS, nvme_info.idx++);
+	if (pci_dev == -1) {
+		pci_dev = pci_find_devices(nvme_supported, nvme_info.idx);
+	}
+
 	if (pci_dev == -1) {
 		printf("Error: can't find pci device \"nvme%d\"\n",
 		       --nvme_info.idx);
diff --git a/include/pci_ids.h b/include/pci_ids.h
index ab6aa58adb..fdda679cc0 100644
--- a/include/pci_ids.h
+++ b/include/pci_ids.h
@@ -21,6 +21,7 @@
 #define PCI_CLASS_STORAGE_SATA		0x0106
 #define PCI_CLASS_STORAGE_SATA_AHCI	0x010601
 #define PCI_CLASS_STORAGE_SAS		0x0107
+#define PCI_CLASS_STORAGE_EXPRESS	0x010802
 #define PCI_CLASS_STORAGE_OTHER		0x0180
 
 #define PCI_BASE_CLASS_NETWORK		0x02
-- 
2.11.1


From 98bcf3c2dbc0b611e4895b391bce7903597ecf3a Mon Sep 17 00:00:00 2001
From: Jon Nettleton <jon@solid-run.com>
Date: Fri, 28 Jul 2017 09:13:56 +0200
Subject: [PATCH 6/6] NVMe: match printf types to make GCC 6 happy.

This mistyping was making gcc 6 unhappy, so fix it up.

Signed-off-by: Jon Nettleton <jon@solid-run.com>
---
 cmd/nvme.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/cmd/nvme.c b/cmd/nvme.c
index 5c8bf42bc9..49864baf4e 100644
--- a/cmd/nvme.c
+++ b/cmd/nvme.c
@@ -77,7 +77,7 @@ static int do_nvme_read(cmd_tbl_t *cmdtp, int flag, int argc,
 	ulong n;
 	lbaint_t blk = simple_strtoul(argv[2], NULL, 16);
 
-	printf("\nNVME read: device %d block # %ld, count %ld ... ",
+	printf("\nNVME read: device %d block # %llu, count %lu ... ",
 	       nvme_curr_device, blk, cnt);
 
 	time = get_timer(0);
@@ -108,7 +108,7 @@ static int do_nvme_write(cmd_tbl_t *cmdtp, int flag, int argc,
 	ulong n;
 	lbaint_t blk = simple_strtoul(argv[2], NULL, 16);
 
-	printf("\nNVME write: device %d block # %ld, count %ld ... ",
+	printf("\nNVME write: device %d block # %llu, count %lu ... ",
 	       nvme_curr_device, blk, cnt);
 
 	time = get_timer(0);
-- 
2.11.1

