From: Keith Busch Date: Mon, 2 Feb 2015 16:57:49 +0000 (-0700) Subject: NVMe: Add show registers command X-Git-Tag: v0.1~82 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=08290ca94abc89faa3b5aebf368370d04b25958a;p=users%2Fsagi%2Fnvme-cli.git NVMe: Add show registers command 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 --- diff --git a/Documentation/nvme-show-regs.txt b/Documentation/nvme-show-regs.txt new file mode 100644 index 00000000..fff4460d --- /dev/null +++ b/Documentation/nvme-show-regs.txt @@ -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' + +DESCRIPTION +----------- +For the NVMe device given, sends an identify namespace command and +provides the result and returned structure. + +The 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 diff --git a/linux/nvme.h b/linux/nvme.h index b2130dcb..97364836 100644 --- a/linux/nvme.h +++ b/linux/nvme.h @@ -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 38351007..bdcb2312 100644 --- a/nvme.c +++ b/nvme.c @@ -34,6 +34,7 @@ #include #include +#include #include #include @@ -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;