[U-Boot,RFC,v2,2/2] NVMe: add nvme commands

Message ID 1492743689-40341-3-git-send-email-zhikang.zhang@nxp.com
State RFC
Delegated to: Tom Rini
Headers show

Commit Message

Zhikang Zhang April 21, 2017, 3:01 a.m.
Add nvme commands in U-Boot command line.

1. "nvme list" - show all available NVMe blk devices
2. "nvme info" - show current or a specific NVMe blk device
3. "nvme device" - show or set current device
4. "nvme part" - print partition table
5. "nvme read" - read data from NVMe blk device
6. "nvme write" - write data to NVMe blk device

Signed-off-by: Zhikang Zhang <zhikang.zhang@nxp.com>
Signed-off-by: Wenbin Song <wenbin.song@nxp.com>
---
Changes for v2:
	- remove the calling of "initialie" in fuction "do_nvmecops"
	- change the function "do_nvme_info" to support BLK uclass
---
 cmd/Kconfig     |   9 +++
 cmd/Makefile    |   1 +
 cmd/nvme.c      | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 disk/part.c     |   6 ++
 doc/README.nvme |  54 ++++++++++++++++++
 5 files changed, 243 insertions(+)
 create mode 100644 cmd/nvme.c

Patch

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 13dc46a..e30814b 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -502,6 +502,15 @@  config CMD_USB
 	help
 	  USB support.
 
+config CMD_NVME
+	bool "NVMe"
+	depends on NVME
+	help
+	  NVMe support.
+	  This enables nvme commands in command line
+	  You can use comamnd "nvme" to show what commands it supports
+	  such as "nvme info" "nvme list".
+
 config CMD_DFU
 	bool "dfu"
 	select USB_FUNCTION_DFU
diff --git a/cmd/Makefile b/cmd/Makefile
index 97c862f..941100e 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -111,6 +111,7 @@  obj-$(CONFIG_CMD_REISER) += reiser.o
 obj-$(CONFIG_CMD_REMOTEPROC) += remoteproc.o
 obj-$(CONFIG_SANDBOX) += host.o
 obj-$(CONFIG_CMD_SATA) += sata.o
+obj-$(CONFIG_CMD_NVME) += nvme.o
 obj-$(CONFIG_CMD_SF) += sf.o
 obj-$(CONFIG_SCSI) += scsi.o disk.o
 obj-$(CONFIG_CMD_SHA1SUM) += sha1sum.o
diff --git a/cmd/nvme.c b/cmd/nvme.c
new file mode 100644
index 0000000..8dc1f14
--- /dev/null
+++ b/cmd/nvme.c
@@ -0,0 +1,173 @@ 
+/*
+ * Copyright (C) 2017 NXP Semiconductors
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <part.h>
+#include <nvme.h>
+#include <linux/math64.h>
+
+static int nvme_curr_device;
+
+static int do_nvme_list(cmd_tbl_t *cmdtp, int flag,
+		int argc, char * const argv[])
+{
+	blk_list_devices(IF_TYPE_NVME);
+	return CMD_RET_SUCCESS;
+}
+
+static int do_nvme_info(cmd_tbl_t *cmdtp, int flag,
+		int argc, char * const argv[])
+{
+	int devnum;
+	struct udevice *udev;
+	int ret;
+	if (argc > 1)
+		devnum = (int)simple_strtoul(argv[1], NULL, 10);
+	else
+		devnum = nvme_curr_device;
+	ret = blk_get_device(IF_TYPE_NVME, devnum, &udev);
+	if (ret < 0)
+		return ret;
+
+	nvme_print_info(udev);
+	return CMD_RET_SUCCESS;
+}
+
+static int do_nvme_device(cmd_tbl_t *cmdtp, int flag,
+		int argc, char * const argv[])
+{
+	if (argc > 1) {
+		int devnum = (int)simple_strtoul(argv[1], NULL, 10);
+		if (!blk_show_device(IF_TYPE_NVME, devnum)) {
+			nvme_curr_device = devnum;
+			printf("... is now current device\n");
+		} else {
+			return CMD_RET_FAILURE;
+		}
+	} else {
+		blk_show_device(IF_TYPE_NVME, nvme_curr_device);
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
+static int do_nvme_part(cmd_tbl_t *cmdtp, int flag,
+		int argc, char * const argv[])
+{
+	if (argc > 1) {
+		int devnum = (int)simple_strtoul(argv[2], NULL, 10);
+		if (blk_print_part_devnum(IF_TYPE_NVME, devnum)) {
+			printf("\nNVME device %d not available\n", devnum);
+			return CMD_RET_FAILURE;
+		}
+	} else {
+		blk_print_part_devnum(IF_TYPE_NVME, nvme_curr_device);
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
+static int do_nvme_read(cmd_tbl_t *cmdtp, int flag, int argc,
+		char * const argv[])
+{
+	unsigned long time;
+	if (argc != 4)
+		return CMD_RET_USAGE;
+
+	ulong addr = simple_strtoul(argv[1], NULL, 16);
+	ulong cnt = simple_strtoul(argv[3], NULL, 16);
+	ulong n;
+	lbaint_t blk = simple_strtoul(argv[2], NULL, 16);
+
+	printf("\nNVME read: device %d block # %ld, count %ld ... ",
+	       nvme_curr_device, blk, cnt);
+
+	time = get_timer(0);
+	n = blk_read_devnum(IF_TYPE_NVME, nvme_curr_device, blk,
+			    cnt, (ulong *)addr);
+	time = get_timer(time);
+
+	printf("read: %s\n", (n == cnt) ? "OK" : "ERROR");
+	printf("%lu bytes read in %lu ms", cnt * 512, time);
+	if (time > 0) {
+		puts(" (");
+		print_size(div_u64(cnt * 512, time) * 1000, "/s");
+		puts(")");
+	}
+	puts("\n");
+	return (n == cnt) ? 0 : 1;
+}
+
+static int do_nvme_write(cmd_tbl_t *cmdtp, int flag, int argc,
+		char * const argv[])
+{
+	unsigned long time;
+	if (argc != 4)
+		return CMD_RET_USAGE;
+
+	ulong addr = simple_strtoul(argv[1], NULL, 16);
+	ulong cnt = simple_strtoul(argv[3], NULL, 16);
+	ulong n;
+	lbaint_t blk = simple_strtoul(argv[2], NULL, 16);
+
+	printf("\nNVME write: device %d block # %ld, count %ld ... ",
+	       nvme_curr_device, blk, cnt);
+
+	time = get_timer(0);
+	n = blk_write_devnum(IF_TYPE_NVME, nvme_curr_device, blk,
+			    cnt, (ulong *)addr);
+	time = get_timer(time);
+
+	printf("write: %s\n", (n == cnt) ? "OK" : "ERROR");
+	printf("%lu bytes read in %lu ms", cnt * 512, time);
+	if (time > 0) {
+		puts(" (");
+		print_size(div_u64(cnt * 512, time) * 1000, "/s");
+		puts(")");
+	}
+	puts("\n");
+	return (n == cnt) ? 0 : 1;
+}
+
+static cmd_tbl_t cmd_nvme[] = {
+	U_BOOT_CMD_MKENT(list, 1, 1, do_nvme_list, "", ""),
+	U_BOOT_CMD_MKENT(info, 2, 1, do_nvme_info, "", ""),
+	U_BOOT_CMD_MKENT(device, 2, 1, do_nvme_device, "", ""),
+	U_BOOT_CMD_MKENT(part, 2, 1, do_nvme_part, "", ""),
+	U_BOOT_CMD_MKENT(write, 4, 0, do_nvme_write, "", ""),
+	U_BOOT_CMD_MKENT(read, 4, 0, do_nvme_read, "", "")
+};
+
+static int do_nvmecops(cmd_tbl_t *cmdtp, int flag, int argc,
+		char * const argv[])
+{
+	cmd_tbl_t *cp;
+
+	cp = find_cmd_tbl(argv[1], cmd_nvme, ARRAY_SIZE(cmd_nvme));
+
+	argc--;
+	argv++;
+
+	if (cp == NULL || argc > cp->maxargs)
+		return CMD_RET_USAGE;
+
+	if (flag == CMD_FLAG_REPEAT && !cp->repeatable)
+		return CMD_RET_SUCCESS;
+
+	return cp->cmd(cmdtp, flag, argc, argv);
+}
+
+U_BOOT_CMD(
+	nvme, 8, 1, do_nvmecops,
+	"NVME sub system",
+	"\nnvme list - show all available NVME blk devices\n"
+	"nvme info [dev]- show current or a specific NVME blk device\n"
+	"nvme device [dev] - show or set current device\n"
+	"nvme part [dev] - print partition table\n"
+	"nvme read  addr blk# cnt\n"
+	"nvme write addr blk# cnt"
+);
diff --git a/disk/part.c b/disk/part.c
index cd44702..983104e 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -140,6 +140,12 @@  void dev_print (struct blk_desc *dev_desc)
 	case IF_TYPE_DOC:
 		puts("device type DOC\n");
 		return;
+	case IF_TYPE_NVME:
+		printf("Vendor: %s Rev: %s Prod: %s\n",
+		       dev_desc->vendor,
+		       dev_desc->revision,
+		       dev_desc->product);
+	break;
 	case IF_TYPE_UNKNOWN:
 		puts("device type unknown\n");
 		return;
diff --git a/doc/README.nvme b/doc/README.nvme
index b429715..9ecb314 100644
--- a/doc/README.nvme
+++ b/doc/README.nvme
@@ -28,3 +28,57 @@  You can also get/set other features through standard commands.
 NVMe Config Switches:
 ---------------------
 CONFIG_NVME		enables basic NVMe device support
+CONFIG_CMD_NVME		enables basic NVMe command
+
+
+NVMe usage in U-boot:
+---------------------
+
+Two ways to operate the hard disk
+
+* Raw read/write block from/to NVMe hard disk;
+* load read file from ext2/fat/ext4 filesytems in hard disk
+
+1 How to know the information of all the NVMe hard disk?
+
+	=> nvme info
+
+2 How to list all of the NVMe hard disks?
+
+	=> nvme list
+
+Device 0: Vendor: 0x8086 Rev: 8DV10131 Prod: CVFT535600LS400BGN
+	    Type: Hard Disk
+	    Capacity: 381554.0 MB = 372.6 GB (781422768 x 512)
+
+3 How to raw write the kernel.itb to a NVMe hard disk?
+
+	Notes: Hard disk sectors are normally 512 bytes, so
+		0x1000 sectors = 2 MBytes
+
+	wirte kernel.itb
+	=> tftp 80000000 /tftpboot/kernel.itb
+	=> nvme write 80000000 0 11000
+
+4 How to raw read the kernel.itb from a NVMe hard disk?
+
+	load kernel.itb
+	=> nvme read a0000000 0 11000
+
+	boot
+	=> bootm a0000000
+
+5 How to load image from fat filesystem in U-boot?
+
+	U-boot doesn't support fat write to hard disk, so
+	the files must be written by other means (e.g. linux).
+
+	=> fatls nvme 0:1
+	 32376967   kernel.itb
+	 22929408   100m
+
+	2 file(s), 0 dir(s)
+
+	=> fatload nvme 0:1 a0000000 /kernel.itb
+
+	=> bootm a0000000