NAME
----
-nvme-show-regs - Reads and shows the defined NVMe controller registers.
+nvme-show-regs - Reads and shows the defined NVMe controller registers for
+NVMe over PCIe or the controller properties for NVMe over Fabrics.
SYNOPSIS
--------
DESCRIPTION
-----------
-For the NVMe device given, sends an identify namespace command and
+For the NVMe over PCIe device given, sends an identify namespace command and
provides the result and returned structure.
+For the NVMe over Fabrics device given, sends a fabric 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.
+device (ex: /dev/nvme0). For NVMe over PCIe, 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. For NVMe over Fabrics, the programs
+sends a fabric command to get the properties of the target NVMe controller.
+Only the supported properties are displayed.
OPTIONS
-------
-H::
--human-readable::
- Display registers in human readable format.
+ Display registers or supported properties in human readable format.
EXAMPLES
--------
-* Show the nvme pci controller registers in a binary format:
+* Show the NVMe over PCIe controller registers or the NVMe over Fabric controller
+properties in a binary format:
+
------------
# nvme show-regs /dev/nvme0
------------
-* Show the nvme pci controller registers in a human readable format:
+* Show the NVMe over PCIe controller registers or the NVMe over Fabric controller
+properties in a human readable format:
+
------------
# nvme show-regs /dev/nvme0 -H
ENTRY("reset", "Resets the controller", reset)
ENTRY("subsystem-reset", "Resets the controller", subsystem_reset)
ENTRY("ns-rescan", "Rescans the NVME namespaces", ns_rescan)
- ENTRY("show-regs", "Shows the controller registers. Requires admin character device", show_registers)
+ ENTRY("show-regs", "Shows the controller registers or properties. Requires character device", show_registers)
ENTRY("discover", "Discover NVMeoF subsystems", discover_cmd)
ENTRY("connect-all", "Discover and Connect to NVMeoF subsystems", connect_all_cmd)
ENTRY("connect", "Connect to NVMeoF subsystem", connect_cmd)
data_len, data, result);
}
+int nvme_property(int fd, __u8 fctype, __le32 off, __le64 *value, __u8 attrib)
+{
+ int err;
+ struct nvmf_property_get_command *prop_get_cmd;
+ struct nvmf_property_set_command *prop_set_cmd;
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_fabrics_command,
+ };
+
+ if (!value) {
+ errno = EINVAL;
+ return -errno;
+ }
+ if (fctype == nvme_fabrics_type_property_get){
+ prop_get_cmd = (struct nvmf_property_get_command *)&cmd;
+ prop_get_cmd->fctype = nvme_fabrics_type_property_get;
+ prop_get_cmd->offset = off;
+ prop_get_cmd->attrib = attrib;
+ }
+ else if(fctype == nvme_fabrics_type_property_set) {
+ prop_set_cmd = (struct nvmf_property_set_command *)&cmd;
+ prop_set_cmd->fctype = nvme_fabrics_type_property_set;
+ prop_set_cmd->offset = off;
+ prop_set_cmd->attrib = attrib;
+ prop_set_cmd->value = *value;
+ }
+ else {
+ errno = EINVAL;
+ return -errno;
+ }
+
+ err = nvme_submit_admin_passthru(fd, &cmd);
+ if (!err && fctype == nvme_fabrics_type_property_get) {
+ *value = cpu_to_le64(cmd.result);
+ }
+
+ return err;
+}
+
+int nvme_get_properties(int fd, void **pbar)
+{
+ __le64 value64;
+ __le32 off;
+ int err, ret = -EINVAL;
+ bool is64bit;
+ int size = getpagesize();
+
+ *pbar = malloc(size);
+ if (!*pbar)
+ return ret;
+
+ memset(*pbar, 0xff, size);
+ for (off = NVME_REG_CAP; off <= NVME_REG_CMBSZ; off += 4) {
+ switch (off) {
+ case NVME_REG_CAP:
+ case NVME_REG_ASQ:
+ case NVME_REG_ACQ:
+ is64bit = true;
+ break;
+ default:
+ is64bit = false;
+ }
+ err = nvme_property(fd, nvme_fabrics_type_property_get,
+ off, &value64, is64bit ? 1: 0);
+ if (err) {
+ if (is64bit)
+ off += 4;
+ continue;
+ }
+ ret = 0;
+ if (is64bit)
+ *(uint64_t *)(*pbar + off) = le64_to_cpu(value64);
+ else
+ *(uint32_t *)(*pbar + off) = le32_to_cpu(value64);
+ }
+
+ return ret;
+}
+
int nvme_get_feature(int fd, __u32 nsid, __u8 fid, __u8 sel, __u32 cdw11,
__u32 data_len, void *data, __u32 *result)
{
__u32 data_len, __u32 dw12, void *data, __u32 *result);
int nvme_dir_recv(int fd, __u32 nsid, __u16 dspec, __u8 dtype, __u8 doper,
__u32 data_len, __u32 dw12, void *data, __u32 *result);
+int nvme_get_properties(int fd, void **pbar);
#endif /* _NVME_LIB_H */
return le32_to_cpu(*p) | ((uint64_t)le32_to_cpu(*(p + 1)) << 32);
}
-void show_ctrl_registers(void *bar, unsigned int mode)
+void show_ctrl_registers(void *bar, unsigned int mode, bool fabrics)
{
uint64_t cap, asq, acq;
uint32_t vs, intms, intmc, cc, csts, nssr, aqa, cmbsz, cmbloc;
cmbsz = mmio_read32(bar + NVME_REG_CMBSZ);
if (human) {
- printf("cap : %"PRIx64"\n", cap);
- show_registers_cap((struct nvme_bar_cap *)&cap);
-
- printf("version : %x\n", vs);
- show_registers_version(vs);
-
- printf("intms : %x\n", intms);
- printf("\tInterrupt Vector Mask Set (IVMS): %x\n\n", intms);
-
- printf("intmc : %x\n", intmc);
- printf("\tInterrupt Vector Mask Clear (IVMC): %x\n\n", intmc);
-
- printf("cc : %x\n", cc);
- show_registers_cc(cc);
-
- printf("csts : %x\n", csts);
- show_registers_csts(csts);
-
- printf("nssr : %x\n", nssr);
- printf("\tNVM Subsystem Reset Control (NSSRC): %u\n\n", nssr);
-
- printf("aqa : %x\n", aqa);
- show_registers_aqa(aqa);
-
- printf("asq : %"PRIx64"\n", asq);
- printf("\tAdmin Submission Queue Base (ASQB): %"PRIx64"\n\n",
- asq);
-
- printf("acq : %"PRIx64"\n", acq);
- printf("\tAdmin Completion Queue Base (ACQB): %"PRIx64"\n\n",
- acq);
-
- printf("cmbloc : %x\n", cmbloc);
- show_registers_cmbloc(cmbloc, cmbsz);
-
- printf("cmbsz : %x\n", cmbsz);
- show_registers_cmbsz(cmbsz);
+ if (cap != 0xffffffff) {
+ printf("cap : %"PRIx64"\n", cap);
+ show_registers_cap((struct nvme_bar_cap *)&cap);
+ }
+ if (vs != 0xffffffff) {
+ printf("version : %x\n", vs);
+ show_registers_version(vs);
+ }
+ if (cc != 0xffffffff) {
+ printf("cc : %x\n", cc);
+ show_registers_cc(cc);
+ }
+ if (csts != 0xffffffff) {
+ printf("csts : %x\n", csts);
+ show_registers_csts(csts);
+ }
+ if (nssr != 0xffffffff) {
+ printf("nssr : %x\n", nssr);
+ printf("\tNVM Subsystem Reset Control (NSSRC): %u\n\n", nssr);
+ }
+ if (!fabrics) {
+ printf("intms : %x\n", intms);
+ printf("\tInterrupt Vector Mask Set (IVMS): %x\n\n",
+ intms);
+
+ printf("intmc : %x\n", intmc);
+ printf("\tInterrupt Vector Mask Clear (IVMC): %x\n\n",
+ intmc);
+ printf("aqa : %x\n", aqa);
+ show_registers_aqa(aqa);
+
+ printf("asq : %"PRIx64"\n", asq);
+ printf("\tAdmin Submission Queue Base (ASQB): %"PRIx64"\n\n",
+ asq);
+
+ printf("acq : %"PRIx64"\n", acq);
+ printf("\tAdmin Completion Queue Base (ACQB): %"PRIx64"\n\n",
+ acq);
+
+ printf("cmbloc : %x\n", cmbloc);
+ show_registers_cmbloc(cmbloc, cmbsz);
+
+ printf("cmbsz : %x\n", cmbsz);
+ show_registers_cmbsz(cmbsz);
+ }
} else {
- printf("cap : %"PRIx64"\n", cap);
- printf("version : %x\n", vs);
- printf("intms : %x\n", intms);
- printf("intmc : %x\n", intmc);
- printf("cc : %x\n", cc);
- printf("csts : %x\n", csts);
- printf("nssr : %x\n", nssr);
- printf("aqa : %x\n", aqa);
- printf("asq : %"PRIx64"\n", asq);
- printf("acq : %"PRIx64"\n", acq);
- printf("cmbloc : %x\n", cmbloc);
- printf("cmbsz : %x\n", cmbsz);
+ if (cap != 0xffffffff)
+ printf("cap : %"PRIx64"\n", cap);
+ if (vs != 0xffffffff)
+ printf("version : %x\n", vs);
+ if (cc != 0xffffffff)
+ printf("cc : %x\n", cc);
+ if (csts != 0xffffffff)
+ printf("csts : %x\n", csts);
+ if (nssr != 0xffffffff)
+ printf("nssr : %x\n", nssr);
+ if (!fabrics) {
+ printf("intms : %x\n", intms);
+ printf("intmc : %x\n", intmc);
+ printf("aqa : %x\n", aqa);
+ printf("asq : %"PRIx64"\n", asq);
+ printf("acq : %"PRIx64"\n", acq);
+ printf("cmbloc : %x\n", cmbloc);
+ printf("cmbsz : %x\n", cmbsz);
+ }
}
}
void show_smart_log(struct nvme_smart_log *smart, unsigned int nsid, const char *devname);
void show_fw_log(struct nvme_firmware_log_page *fw_log, const char *devname);
void show_effects_log(struct nvme_effects_log_page *effects);
-void show_ctrl_registers(void *bar, unsigned int mode);
+void show_ctrl_registers(void *bar, unsigned int mode, bool fabrics);
void show_nvme_id_ns_descs(void *data);
void nvme_feature_show_fields(__u32 fid, unsigned int result, unsigned char *buf);
static void *get_registers(void)
{
- int pci_fd;
+ int fd;
char *base, path[512];
void *membase;
base = nvme_char_from_block((char *)devicename);
sprintf(path, "/sys/class/nvme/%s/device/resource0", base);
- pci_fd = open(path, O_RDONLY);
- if (pci_fd < 0) {
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
sprintf(path, "/sys/class/misc/%s/device/resource0", base);
- pci_fd = open(path, O_RDONLY);
+ fd = open(path, O_RDONLY);
}
- if (pci_fd < 0) {
+ if (fd < 0) {
fprintf(stderr, "%s did not find a pci resource\n", base);
return NULL;
}
- membase = mmap(NULL, getpagesize(), PROT_READ, MAP_SHARED, pci_fd, 0);
+ membase = mmap(NULL, getpagesize(), PROT_READ, MAP_SHARED, fd, 0);
if (membase == MAP_FAILED) {
fprintf(stderr, "%s failed to map\n", base);
return NULL;
"in binary or human-readable format";
const char *human_readable = "show info in readable format";
void *bar;
- int fd;
+ int fd, err;
+ bool fabrics = true;
struct config {
int human_readable;
if (fd < 0)
return fd;
- bar = get_registers();
+ err = nvme_get_properties(fd, &bar);
+ if (err) {
+ bar = get_registers();
+ fabrics = false;
+ }
if (!bar)
return ENODEV;
+ show_ctrl_registers(bar, cfg.human_readable ? HUMAN : 0, fabrics);
- show_ctrl_registers(bar, cfg.human_readable ? HUMAN : 0);
+ if (fabrics)
+ free(bar);
return 0;
}