]> www.infradead.org Git - users/sagi/nvme-cli.git/commitdiff
NVMe: Add show registers command
authorKeith Busch <keith.busch@intel.com>
Mon, 2 Feb 2015 16:57:49 +0000 (09:57 -0700)
committerKeith Busch <keith.busch@intel.com>
Mon, 2 Feb 2015 16:57:49 +0000 (09:57 -0700)
This prints out the controller registers in human readable format. It uses
knowledge of the sysfs layout to map a character device to a pci resource.

Signed-off-by: Keith Busch <keith.busch@intel.com>
Documentation/nvme-show-regs.txt [new file with mode: 0644]
linux/nvme.h
nvme.c

diff --git a/Documentation/nvme-show-regs.txt b/Documentation/nvme-show-regs.txt
new file mode 100644 (file)
index 0000000..fff4460
--- /dev/null
@@ -0,0 +1,34 @@
+nvme-id-ns(1)
+=============
+
+NAME
+----
+nvme-show-regs - Reads and shows the defined NVMe controller registers.
+
+SYNOPSIS
+--------
+[verse]
+'nvme show-regs' <device>
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends an identify namespace command and
+provides the result and returned structure.
+
+The <device> parameter is mandatory and must be the nvme admin character
+device (ex: /dev/nvme0). The program uses knowledge of the sysfs layout
+to map the device to the pci resource stored there and mmaps the memory
+to get access to the registers.
+
+EXAMPLES
+--------
+* Has the program map the nvme pci controller registers and prints them
+in a human readable format:
++
+------------
+# nvme show-regs /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
index b2130dcb860bcbf4e9eee8fef45c06398de2fc81..97364836504b507e1e591b484a41d4b320a13fbc 100644 (file)
@@ -568,6 +568,22 @@ struct nvme_passthru_cmd {
        __u32   result;
 };
 
+struct nvme_bar {
+       __u64                   cap;    /* Controller Capabilities */
+       __u32                   vs;     /* Version */
+       __u32                   intms;  /* Interrupt Mask Set */
+       __u32                   intmc;  /* Interrupt Mask Clear */
+       __u32                   cc;     /* Controller Configuration */
+       __u32                   rsvd1;  /* Reserved */
+       __u32                   csts;   /* Controller Status */
+       __u32                   nssr;   /* NVM Subsystem Reset */
+       __u32                   aqa;    /* Admin Queue Attributes */
+       __u64                   asq;    /* Admin SQ Base Address */
+       __u64                   acq;    /* Admin CQ Base Address */
+       __u32                   cmbloc; /* Controller Memory Buffer Location */
+       __u32                   cmbsz;  /* Controller Memory Buffer Size */
+};
+
 #define nvme_admin_cmd nvme_passthru_cmd
 
 #define NVME_IOCTL_ID          _IO('N', 0x40)
diff --git a/nvme.c b/nvme.c
index 3835100740a98f1abf24dcf83ef72c67a634a21e..bdcb2312e85c4505226bbf9c23b711be6b5d26dd 100644 (file)
--- a/nvme.c
+++ b/nvme.c
@@ -34,6 +34,7 @@
 #include <linux/fs.h>
 
 #include <sys/ioctl.h>
+#include <sys/mman.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
@@ -67,6 +68,7 @@ static const char *devicename;
        ENTRY(RESV_REPORT, "resv-report", "Submit a Reservation Report, return results", resv_report) \
        ENTRY(FLUSH, "flush", "Submit a Flush command, return results", flush) \
        ENTRY(COMPARE, "compare", "Submit a Comapre command, return results", compare) \
+       ENTRY(REGISTERS, "show-regs", "Shows the controller registers. Requires admin character device", show_registers) \
        ENTRY(HELP, "help", "Display this help", help)
 
 #define ENTRY(i, n, h, f) \
@@ -1073,6 +1075,54 @@ static int fw_activate(int argc, char **argv)
        return err;
 }
 
+static int show_registers(int argc, char **argv)
+{
+       int opt, long_index, pci_fd;
+       char *base, path[512];
+       void *membase;
+       struct nvme_bar *bar;
+       static struct option opts[] = {};
+
+       while ((opt = getopt_long(argc, (char **)argv, "", opts,
+                                       &long_index)) != -1);
+       get_dev(optind, argc, argv);
+
+       if (!S_ISCHR(nvme_stat.st_mode)) {
+               fprintf(stderr, "%s is not character device\n", devicename);
+               exit(ENODEV);
+       }
+
+       base = basename(devicename);
+       sprintf(path, "/sys/class/misc/%s/device/resource0", base);
+       pci_fd = open(path, O_RDONLY);
+       if (pci_fd < 0) {
+               fprintf(stderr, "%s did not find a pci resource\n", devicename);
+               exit(ENODEV);
+       }
+
+       membase = mmap(0, getpagesize(), PROT_READ, MAP_SHARED, pci_fd, 0);
+       if (!membase) {
+               fprintf(stderr, "%s failed to map\n", devicename);
+               exit(ENODEV);
+       }
+
+       bar = membase;
+       printf("cap     : %"PRIx64"\n", (uint64_t)bar->cap);
+       printf("version : %x\n", bar->vs);
+       printf("intms   : %x\n", bar->intms);
+       printf("intmc   : %x\n", bar->intmc);
+       printf("cc      : %x\n", bar->cc);
+       printf("csts    : %x\n", bar->csts);
+       printf("nssr    : %x\n", bar->nssr);
+       printf("aqa     : %x\n", bar->aqa);
+       printf("asq     : %"PRIx64"\n", (uint64_t)bar->asq);
+       printf("acq     : %"PRIx64"\n", (uint64_t)bar->acq);
+       printf("cmbloc  : %x\n", bar->cmbloc);
+       printf("cmbsz   : %x\n", bar->cmbsz);
+
+       return 0;
+}
+
 static int format(int argc, char **argv)
 {
        int opt, err, long_index;
@@ -1091,7 +1141,6 @@ static int format(int argc, char **argv)
 
        while ((opt = getopt_long(argc, (char **)argv, "n:l:s:p:i:m:", opts,
                                                        &long_index)) != -1) {
-               
                switch (opt) {
                case 'n': get_int(optarg, &nsid); break;
                case 'l': get_byte(optarg, &lbaf); break;