[U-Boot] [RFC, 2/2] NVMe: add nvme commands
Zhikang Zhang
zhikang.zhang at nxp.com
Thu Apr 6 08:40:34 UTC 2017
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 at nxp.com>
Signed-off-by: Wenbin Song <wenbin.song at nxp.com>
---
cmd/Kconfig | 9 +++
cmd/Makefile | 1 +
cmd/nvme.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
disk/part.c | 6 ++
doc/README.nvme | 52 +++++++++++++++++
5 files changed, 242 insertions(+)
create mode 100644 cmd/nvme.c
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 91bd3fb..0cad1fb 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -430,6 +430,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 566fed9..e2a7bb0 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -114,6 +114,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..5c8bf42
--- /dev/null
+++ b/cmd/nvme.c
@@ -0,0 +1,174 @@
+/*
+ * 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 = -1;
+
+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;
+ if (argc > 1)
+ devnum = (int)simple_strtoul(argv[1], NULL, 10);
+ else
+ devnum = nvme_curr_device;
+ nvme_print_info(devnum);
+ 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;
+
+ if (nvme_curr_device < 0) {
+ nvme_curr_device = nvme_initialize();
+ if (nvme_curr_device < 0) {
+ puts("No nvme device available\n");
+ return CMD_RET_FAILURE;
+ }
+ }
+ 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 4e37735..01b6aa9 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 892e0fb..af95574 100644
--- a/doc/README.nvme
+++ b/doc/README.nvme
@@ -10,8 +10,60 @@ CONFIG_NVME enables basic NVMe device support
NVMe is a basic device which mounted on PCIe bus,
so is depends on CONFIG_PCI.
CONFIG_SYS_NVME_MAX_DEVICE configs the max num of NVMe devices
+CONFIG_CMD_NVME enables basic NVMe command
2. Driver Model Support:
Use block device(CONFIG_BLK)'s structure to support nvme's DM.
Use UCLASS_PCI as a parent uclass.
+
+3. 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
+
+3.0 How to know the information of all the NVMe hard disk?
+
+ => nvme info
+
+3.1 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.2 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
+
+3.3 How to raw read the kernel.itb from a NVMe hard disk?
+
+ load kernel.itb
+ => nvme read a0000000 0 11000
+
+ boot
+ => bootm a0000000
+
+3.4 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
--
2.1.0.27.g96db324
More information about the U-Boot
mailing list