From a83038521030738bd8a3c88190aa6e45f228d66e Mon Sep 17 00:00:00 2001 From: Tokunori Ikegami Date: Mon, 5 Feb 2024 22:07:13 +0900 Subject: [PATCH] nvme: Add support for get-reg and set-reg commands The get-reg command is to output single register. The set-reg command is to write nvme register. Signed-off-by: Tokunori Ikegami --- Documentation/nvme-get-reg.txt | 168 +++++ Documentation/nvme-id-ns-granularity.txt | 0 Documentation/nvme-id-uuid.txt | 0 Documentation/nvme-list-secondary.txt | 0 Documentation/nvme-nvme-mi-recv.txt | 0 Documentation/nvme-nvme-mi-send.txt | 0 Documentation/nvme-set-property.txt | 4 +- Documentation/nvme-set-reg.txt | 116 +++ Documentation/nvme-virt-mgmt.txt | 0 common.h | 21 + nvme-builtin.h | 2 + nvme-print-stdout.c | 877 ++++++++++++----------- nvme-print.c | 205 +++++- nvme-print.h | 5 + nvme.c | 718 ++++++++++++++++++- nvme.h | 4 + subprojects/libnvme.wrap | 2 +- 17 files changed, 1678 insertions(+), 444 deletions(-) create mode 100644 Documentation/nvme-get-reg.txt mode change 100755 => 100644 Documentation/nvme-id-ns-granularity.txt mode change 100755 => 100644 Documentation/nvme-id-uuid.txt mode change 100755 => 100644 Documentation/nvme-list-secondary.txt mode change 100755 => 100644 Documentation/nvme-nvme-mi-recv.txt mode change 100755 => 100644 Documentation/nvme-nvme-mi-send.txt create mode 100644 Documentation/nvme-set-reg.txt mode change 100755 => 100644 Documentation/nvme-virt-mgmt.txt diff --git a/Documentation/nvme-get-reg.txt b/Documentation/nvme-get-reg.txt new file mode 100644 index 0000000000..073bcdf691 --- /dev/null +++ b/Documentation/nvme-get-reg.txt @@ -0,0 +1,168 @@ +nvme-get-reg(1) +=============== + +NAME +---- +nvme-get-reg - Read and show the defined NVMe controller register + +SYNOPSIS +-------- +[verse] +'nvme get-reg' [--offset=, -O ] [--human-readable | -H] + [--cap | -c] [--vs | -V] [--cmbloc | -m] [--cmbsz | -M] + [--bpinfo | -b] [--cmbsts | -S] [--cmbebs | -E] + [--cmbswtp | -W] [--crto | -r] [--pmrcap | -P] + [--pmrsts | -t] [--pmrebs | -e] [--pmrswtp | -w] + [--intms | -i] [--intmc | -I] [--cc | -C] [--csts | -T] + [--nssr | -n] [--aqa | -a] [--asq | -A] [--acq | -q] + [--bprsel | -B] [--bpmbl | -p] [--cmbmsc | -s] + [--nssd | -N] [--pmrctl | -R] [--pmrmscl | -l] + [--pmrmscu | -u] + [--output-format= | -o ] [--verbose | -v] + +DESCRIPTION +----------- +Read and show the defined NVMe controller register. + +OPTIONS +------- +-O :: +--offset=:: + offset of the requested register + +-H:: +--human-readable:: + show register in readable format + +-c:: +--cap:: + CAP=0x0 register offset + +-V:: +--vs:: + VS=0x8 register offset + +-m:: +--cmbloc:: + CMBLOC=0x38 register offset + +-M:: +--cmbsz:: + CMBSZ=0x3c register offset + +-b:: +--bpinfo:: + BPINFO=0x40 register offset + +-S:: +--cmbsts:: + CMBSTS=0x58 register offset + +-E:: +--cmbebs:: + CMBEBS=0x5c register offset + +-W:: +--cmbswtp:: + CMBSWTP=0x60 register offset + +-r:: +--crto:: + CRTO=0x68 register offset + +-P:: +--pmrcap:: + PMRCAP=0xe00 register offset + +-t:: +--pmrsts:: + PMRSTS=0xe08 register offset + +-e:: +--pmrebs:: + PMREBS=0xe0c register offset + +-w:: +--pmrswtp:: + PMRSWTP=0xe10 register offset + +-i:: +--intms:: + INTMS=0xc register offset + +-I:: +--intmc:: + INTMC=0x10 register offset + +-C:: +--cc:: + CC=0x14 register offset + +-T:: +--csts:: + CSTS=0x1c register offset + +-n:: +--nssr:: + NSSR=0x20 register offset + +-a:: +--aqa:: + AQA=0x24 register offset + +-A:: +--asq:: + ASQ=0x28 register offset + +-q:: +--acq:: + ACQ=0x30 register offset + +-B:: +--bprsel:: + BPRSEL=0x44 register offset + +-p:: +--bpmbl:: + BPMBL=0x48 register offset + +-s:: +--cmbmsc:: + CMBMSC=0x50 register offset + +-N:: +--nssd:: + NSSD=0x64 register offset + +-R:: +--pmrctl:: + PMRCTL=0xe04 register offset + +-l:: +--pmrmscl:: + PMRMSCL=0xe14 register offset + +-u:: +--pmrmscu:: + PMRMSCU=0xe18 register offset + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + +EXAMPLES +-------- +* The following will run the get-reg command with offset 0 ++ +------------ +# nvme get-reg /dev/nvme0 --offset=0x0 --human-readable +------------ + +NVME +---- +Part of the nvme-user suite. diff --git a/Documentation/nvme-id-ns-granularity.txt b/Documentation/nvme-id-ns-granularity.txt old mode 100755 new mode 100644 diff --git a/Documentation/nvme-id-uuid.txt b/Documentation/nvme-id-uuid.txt old mode 100755 new mode 100644 diff --git a/Documentation/nvme-list-secondary.txt b/Documentation/nvme-list-secondary.txt old mode 100755 new mode 100644 diff --git a/Documentation/nvme-nvme-mi-recv.txt b/Documentation/nvme-nvme-mi-recv.txt old mode 100755 new mode 100644 diff --git a/Documentation/nvme-nvme-mi-send.txt b/Documentation/nvme-nvme-mi-send.txt old mode 100755 new mode 100644 diff --git a/Documentation/nvme-set-property.txt b/Documentation/nvme-set-property.txt index 22a513c8b2..ddc267d6b0 100644 --- a/Documentation/nvme-set-property.txt +++ b/Documentation/nvme-set-property.txt @@ -23,8 +23,8 @@ OPTIONS --offset:: The offset of the property. --V:: ---value: +-V :: +--value=:: The value of the property to be set. -o :: diff --git a/Documentation/nvme-set-reg.txt b/Documentation/nvme-set-reg.txt new file mode 100644 index 0000000000..8b1ae4828c --- /dev/null +++ b/Documentation/nvme-set-reg.txt @@ -0,0 +1,116 @@ +nvme-set-reg(1) +=============== + +NAME +---- +nvme-set-reg - Writes and shows the defined NVMe controller register + +SYNOPSIS +-------- +[verse] +'nvme set-reg' [--offset=, -O ] + [--value= | -V ] [--mmio32 | -M] + [--intms= | -i] [--intmc= | -I ] + [--cc= | -C ] [--csts= | -T ] + [--nssr= | -n ] [--aqa= | -a ] + [--asq= | -A ] [--acq= | -q ] + [--bprsel= | -B ] [--bpmbl= | -p ] + [--cmbmsc= | -s ] [--nssd= | -N ] + [--pmrctl= | -R ] [--pmrmscl= | -l ] + [--pmrmscu= | -u ] + [--output-format= | -o ] [--verbose | -v] + +DESCRIPTION +----------- +Writes and shows the defined NVMe controller register. + +OPTIONS +------- +-O :: +--offset=:: + offset of the requested register + +--mmio32:: +-M:: + Access 64-bit registers as 2 32-bit + +-i :: +--intms=:: + INTMS=0xc register offset + +-I :: +--intmc=:: + INTMC=0x10 register offset + +-C :: +--cc=:: + CC=0x14 register offset + +-T :: +--csts=:: + CSTS=0x1c register offset + +-n :: +--nssr=:: + NSSR=0x20 register offset + +-a :: +--aqa=:: + AQA=0x24 register offset + +-A :: +--asq=:: + ASQ=0x28 register offset + +-q :: +--acq=:: + ACQ=0x30 register offset + +-B :: +--bprsel=:: + BPRSEL=0x44 register offset + +-p :: +--bpmbl=:: + BPMBL=0x48 register offset + +-s :: +--cmbmsc=:: + CMBMSC=0x50 register offset + +-N :: +--nssd=:: + NSSD=0x64 register offset + +-R :: +--pmrctl=:: + PMRCTL=0xe04 register offset + +-l :: +--pmrmscl=:: + PMRMSCL=0xe14 register offset + +-u :: +--pmrmscu=:: + PMRMSCU=0xe18 register offset + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + +EXAMPLES +-------- +* The following will run the get-reg command with offset 0 ++ +------------ +# nvme get-reg /dev/nvme0 --offset=0x0 --human-readable +------------ + +NVME +---- +Part of the nvme-user suite. diff --git a/Documentation/nvme-virt-mgmt.txt b/Documentation/nvme-virt-mgmt.txt old mode 100755 new mode 100644 diff --git a/common.h b/common.h index b1161189b3..a4f4f99de2 100644 --- a/common.h +++ b/common.h @@ -3,6 +3,7 @@ #define _COMMON_H #include +#include #include "ccan/endian/endian.h" @@ -35,4 +36,24 @@ static inline uint64_t mmio_read64(void *addr) return ((uint64_t)high << 32) | low; } +static inline void mmio_write32(void *addr, uint32_t value) +{ + leint32_t *p = addr; + + *p = cpu_to_le32(value); +} + +/* Access 64-bit registers as 2 32-bit if write32 flag set; Some devices fail 64-bit MMIO. */ +static inline void mmio_write64(void *addr, uint64_t value, bool write32) +{ + uint64_t *p = addr; + + if (write32) { + mmio_write32(addr, value); + mmio_write32((uint32_t *)addr + 1, value >> 32); + return; + } + + *p = cpu_to_le64(value); +} #endif diff --git a/nvme-builtin.h b/nvme-builtin.h index 2d2bead38b..d95b12ce41 100644 --- a/nvme-builtin.h +++ b/nvme-builtin.h @@ -89,6 +89,8 @@ COMMAND_LIST( ENTRY("subsystem-reset", "Resets the subsystem", subsystem_reset) ENTRY("ns-rescan", "Rescans the NVME namespaces", ns_rescan) ENTRY("show-regs", "Shows the controller registers or properties. Requires character device", show_registers) + ENTRY("set-reg", "Set a register and show the resulting value", set_register) + ENTRY("get-reg", "Get a register and show the resulting value", get_register) 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) diff --git a/nvme-print-stdout.c b/nvme-print-stdout.c index 4409609da6..03516d4025 100644 --- a/nvme-print-stdout.c +++ b/nvme-print-stdout.c @@ -183,7 +183,7 @@ static void stdout_predictable_latency_per_nvmset( le64_to_cpu(plpns_log->dtwin_wt)); printf("DTWIN Time Maximum: %"PRIu64"\n", le64_to_cpu(plpns_log->dtwin_tmax)); - printf("NDWIN Time Minimum High: %"PRIu64" \n", + printf("NDWIN Time Minimum High: %"PRIu64"\n", le64_to_cpu(plpns_log->ndwin_tmin_hi)); printf("NDWIN Time Minimum Low: %"PRIu64"\n", le64_to_cpu(plpns_log->ndwin_tmin_lo)); @@ -203,17 +203,13 @@ static void stdout_predictable_latency_event_agg_log( __u64 num_entries; num_entries = le64_to_cpu(pea_log->num_entries); - printf("Predictable Latency Event Aggregate Log for"\ - " device: %s\n", devname); + printf("Predictable Latency Event Aggregate Log for device: %s\n", devname); - printf("Number of Entries Available: %"PRIu64"\n", - (uint64_t)num_entries); + printf("Number of Entries Available: %"PRIu64"\n", (uint64_t)num_entries); num_iter = min(num_entries, log_entries); - for (int i = 0; i < num_iter; i++) { - printf("Entry[%d]: %u\n", i + 1, - le16_to_cpu(pea_log->entries[i])); - } + for (int i = 0; i < num_iter; i++) + printf("Entry[%d]: %u\n", i + 1, le16_to_cpu(pea_log->entries[i])); } static void stdout_persistent_event_log_rci(__le32 pel_header_rci) @@ -224,7 +220,7 @@ static void stdout_persistent_event_log_rci(__le32 pel_header_rci) __u8 rcpit = (rci & 0x30000) >> 16; __u16 rcpid = rci & 0xffff; - if(rsvd19) + if (rsvd19) printf(" [31:19] : %#x\tReserved\n", rsvd19); printf("\tReporting Context Exists (RCE): %s(%u)\n", rce ? "true" : "false", rce); @@ -321,16 +317,16 @@ static void stdout_persistent_event_log(void *pevent_log_info, le32_to_cpu(pevent_log_head->rci)); if (human) stdout_persistent_event_log_rci(pevent_log_head->rci); - printf("Supported Events Bitmap: \n"); + printf("Supported Events Bitmap:\n"); for (int i = 0; i < 32; i++) { if (pevent_log_head->seb[i] == 0) continue; stdout_add_bitmap(i, pevent_log_head->seb[i]); } } else { - printf("No log data can be shown with this log len at least " \ - "512 bytes is required or can be 0 to read the complete "\ - "log page after context established\n"); + printf("No log data can be shown with this log len at least %s%s", + "512 bytes is required or can be 0 to read the complete ", + "log page after context established\n"); return; } printf("\n"); @@ -366,12 +362,12 @@ static void stdout_persistent_event_log(void *pevent_log_info, switch (pevent_entry_head->etype) { case NVME_PEL_SMART_HEALTH_EVENT: smart_event = pevent_log_info + offset; - printf("Smart Health Event Entry: \n"); + printf("Smart Health Event Entry:\n"); stdout_smart_log(smart_event, NVME_NSID_ALL, devname); break; case NVME_PEL_FW_COMMIT_EVENT: fw_commit_event = pevent_log_info + offset; - printf("FW Commit Event Entry: \n"); + printf("FW Commit Event Entry:\n"); printf("Old Firmware Revision: %"PRIu64" (%s)\n", le64_to_cpu(fw_commit_event->old_fw_rev), util_fw_to_string((char *)&fw_commit_event->old_fw_rev)); @@ -390,7 +386,7 @@ static void stdout_persistent_event_log(void *pevent_log_info, break; case NVME_PEL_TIMESTAMP_EVENT: ts_change_event = pevent_log_info + offset; - printf("Time Stamp Change Event Entry: \n"); + printf("Time Stamp Change Event Entry:\n"); printf("Previous Timestamp: %"PRIu64"\n", le64_to_cpu(ts_change_event->previous_timestamp)); printf("Milliseconds Since Reset: %"PRIu64"\n", @@ -402,11 +398,11 @@ static void stdout_persistent_event_log(void *pevent_log_info, por_info_list = por_info_len / sizeof(*por_event); - printf("Power On Reset Event Entry: \n"); + printf("Power On Reset Event Entry:\n"); fw_rev = pevent_log_info + offset; printf("Firmware Revision: %"PRIu64" (%s)\n", le64_to_cpu(*fw_rev), util_fw_to_string((char *)fw_rev)); - printf("Reset Information List: \n"); + printf("Reset Information List:\n"); for (int i = 0; i < por_info_list; i++) { por_event = pevent_log_info + offset + @@ -432,7 +428,7 @@ static void stdout_persistent_event_log(void *pevent_log_info, break; case NVME_PEL_CHANGE_NS_EVENT: ns_event = pevent_log_info + offset; - printf("Change Namespace Event Entry: \n"); + printf("Change Namespace Event Entry:\n"); printf("Namespace Management CDW10: %u\n", le32_to_cpu(ns_event->nsmgt_cdw10)); printf("Namespace Size: %"PRIu64"\n", @@ -440,42 +436,35 @@ static void stdout_persistent_event_log(void *pevent_log_info, printf("Namespace Capacity: %"PRIu64"\n", le64_to_cpu(ns_event->nscap)); printf("Formatted LBA Size: %u\n", ns_event->flbas); - printf("End-to-end Data Protection Type Settings: %u\n", - ns_event->dps); - printf("Namespace Multi-path I/O and Namespace Sharing" \ - " Capabilities: %u\n", ns_event->nmic); - printf("ANA Group Identifier: %u\n", - le32_to_cpu(ns_event->ana_grp_id)); + printf("End-to-end Data Protection Type Settings: %u\n", ns_event->dps); + printf("Namespace Multi-path I/O and Namespace Sharing Capabilities: %u\n", + ns_event->nmic); + printf("ANA Group Identifier: %u\n", le32_to_cpu(ns_event->ana_grp_id)); printf("NVM Set Identifier: %u\n", le16_to_cpu(ns_event->nvmset_id)); printf("Namespace ID: %u\n", le32_to_cpu(ns_event->nsid)); break; case NVME_PEL_FORMAT_START_EVENT: format_start_event = pevent_log_info + offset; - printf("Format NVM Start Event Entry: \n"); - printf("Namespace Identifier: %u\n", - le32_to_cpu(format_start_event->nsid)); - printf("Format NVM Attributes: %u\n", - format_start_event->fna); + printf("Format NVM Start Event Entry:\n"); + printf("Namespace Identifier: %u\n", le32_to_cpu(format_start_event->nsid)); + printf("Format NVM Attributes: %u\n", format_start_event->fna); printf("Format NVM CDW10: %u\n", - le32_to_cpu(format_start_event->format_nvm_cdw10)); + le32_to_cpu(format_start_event->format_nvm_cdw10)); break; case NVME_PEL_FORMAT_COMPLETION_EVENT: format_cmpln_event = pevent_log_info + offset; - printf("Format NVM Completion Event Entry: \n"); - printf("Namespace Identifier: %u\n", - le32_to_cpu(format_cmpln_event->nsid)); + printf("Format NVM Completion Event Entry:\n"); + printf("Namespace Identifier: %u\n", le32_to_cpu(format_cmpln_event->nsid)); printf("Smallest Format Progress Indicator: %u\n", - format_cmpln_event->smallest_fpi); - printf("Format NVM Status: %u\n", - format_cmpln_event->format_nvm_status); + format_cmpln_event->smallest_fpi); + printf("Format NVM Status: %u\n", format_cmpln_event->format_nvm_status); printf("Completion Information: %u\n", - le16_to_cpu(format_cmpln_event->compln_info)); - printf("Status Field: %u\n", - le32_to_cpu(format_cmpln_event->status_field)); + le16_to_cpu(format_cmpln_event->compln_info)); + printf("Status Field: %u\n", le32_to_cpu(format_cmpln_event->status_field)); break; case NVME_PEL_SANITIZE_START_EVENT: sanitize_start_event = pevent_log_info + offset; - printf("Sanitize Start Event Entry: \n"); + printf("Sanitize Start Event Entry:\n"); printf("SANICAP: %u\n", sanitize_start_event->sani_cap); printf("Sanitize CDW10: %u\n", le32_to_cpu(sanitize_start_event->sani_cdw10)); @@ -484,7 +473,7 @@ static void stdout_persistent_event_log(void *pevent_log_info, break; case NVME_PEL_SANITIZE_COMPLETION_EVENT: sanitize_cmpln_event = pevent_log_info + offset; - printf("Sanitize Completion Event Entry: \n"); + printf("Sanitize Completion Event Entry:\n"); printf("Sanitize Progress: %u\n", le16_to_cpu(sanitize_cmpln_event->sani_prog)); printf("Sanitize Status: %u\n", @@ -494,7 +483,7 @@ static void stdout_persistent_event_log(void *pevent_log_info, break; case NVME_PEL_SET_FEATURE_EVENT: set_feat_event = pevent_log_info + offset; - printf("Set Feature Event Entry: \n"); + printf("Set Feature Event Entry:\n"); dword_cnt = set_feat_event->layout & 0x03; fid = le32_to_cpu(set_feat_event->cdw_mem[0]) & 0x000f; cdw11 = le32_to_cpu(set_feat_event->cdw_mem[1]); @@ -511,7 +500,7 @@ static void stdout_persistent_event_log(void *pevent_log_info, break; case NVME_PEL_THERMAL_EXCURSION_EVENT: thermal_exc_event = pevent_log_info + offset; - printf("Thermal Excursion Event Entry: \n"); + printf("Thermal Excursion Event Entry:\n"); printf("Over Temperature: %u\n", thermal_exc_event->over_temp); printf("Threshold: %u\n", thermal_exc_event->threshold); break; @@ -528,8 +517,7 @@ static void stdout_endurance_group_event_agg_log( struct nvme_aggregate_predictable_lat_event *endurance_log, __u64 log_entries, __u32 size, const char *devname) { - printf("Endurance Group Event Aggregate Log for"\ - " device: %s\n", devname); + printf("Endurance Group Event Aggregate Log for device: %s\n", devname); printf("Number of Entries Available: %"PRIu64"\n", le64_to_cpu(endurance_log->num_entries)); @@ -578,8 +566,8 @@ static void stdout_lba_status_log(void *lba_status, __u32 size, offset += sizeof(*range_desc); } } else { - printf("Number of LBA Range Descriptors (NLRD) set to %#x for "\ - "NS element %d\n", num_lba_desc, ele); + printf("Number of LBA Range Descriptors (NLRD) set to %#x for %s%d%s", + num_lba_desc, "NS element ", ele, "\n"); } } } @@ -700,6 +688,7 @@ static void stdout_boot_part_log(void *bp_log, const char *devname, static const char *eomip_to_string(__u8 eomip) { const char *string; + switch (eomip) { case NVME_PHY_RX_EOM_NOT_STARTED: string = "Not Started"; @@ -735,6 +724,7 @@ static void stdout_eom_printable_eye(struct nvme_eom_lane_desc *lane) { char *eye = (char *)lane->eye_desc; int i, j; + for (i = 0; i < lane->nrows; i++) { for (j = 0; j < lane->ncols; j++) printf("%c", eye[i * lane->ncols + j]); @@ -798,9 +788,8 @@ static void stdout_phy_rx_eom_log(struct nvme_phy_rx_eom_log *log, __u16 control printf("Estimated Time for Better Quality: %u\n", le16_to_cpu(log->etbetter)); printf("Estimated Time for Best Quality: %u\n", le16_to_cpu(log->etbest)); - if (log->eomip == NVME_PHY_RX_EOM_COMPLETED) { + if (log->eomip == NVME_PHY_RX_EOM_COMPLETED) stdout_phy_rx_eom_descs(log); - } } static void stdout_media_unit_stat_log(struct nvme_media_unit_stat_log *mus_log) @@ -929,13 +918,13 @@ static void stdout_fdp_events(struct nvme_fdp_events_log *log) if (event->type == NVME_FDP_EVENT_REALLOC) { struct nvme_fdp_event_realloc *mr; + mr = (struct nvme_fdp_event_realloc *)&event->type_specific; printf(" Number of LBAs Moved (NLBAM): %"PRIu16"\n", le16_to_cpu(mr->nlbam)); - if (mr->flags & NVME_FDP_EVENT_REALLOC_F_LBAV) { + if (mr->flags & NVME_FDP_EVENT_REALLOC_F_LBAV) printf(" Logical Block Address (LBA): 0x%"PRIx64"\n", le64_to_cpu(mr->lba)); - } } if (event->flags & NVME_FDP_EVENT_F_LV) { @@ -980,7 +969,7 @@ static void stdout_supported_cap_config_log(struct nvme_supported_cap_config_lis le16_to_cpu(cap->cap_config_desc[i].domainid)); egcn = le16_to_cpu(cap->cap_config_desc[i].egcn); printf("Number of Endurance Group Configuration Descriptors: %u\n", egcn); - for(j = 0; j < egcn; j++) { + for (j = 0; j < egcn; j++) { printf("Endurance Group Identifier: %u\n", le16_to_cpu(cap->cap_config_desc[i].egcd[j].endgid)); printf("Capacity Adjustment Factor: %u\n", @@ -996,20 +985,20 @@ static void stdout_supported_cap_config_log(struct nvme_supported_cap_config_lis cap->cap_config_desc[i].egcd[j].end_est))); egsets = le16_to_cpu(cap->cap_config_desc[i].egcd[j].egsets); printf("Number of NVM Sets: %u\n", egsets); - for(k = 0; k < egsets; k++) { + for (k = 0; k < egsets; k++) { printf("NVM Set %d Identifier: %u\n", i, le16_to_cpu(cap->cap_config_desc[i].egcd[j].nvmsetid[k])); } - chan_desc = (struct nvme_end_grp_chan_desc *) \ - ((cap->cap_config_desc[i].egcd[j].nvmsetid[0]) * (sizeof(__u16)*egsets)); + chan_desc = (struct nvme_end_grp_chan_desc *) + (sizeof(__u16) * egsets * cap->cap_config_desc[i].egcd[j].nvmsetid[0]); egchans = le16_to_cpu(chan_desc->egchans); printf("Number of Channels: %u\n", egchans); - for(l = 0; l < egchans; l++) { + for (l = 0; l < egchans; l++) { printf("Channel Identifier: %u\n", le16_to_cpu(chan_desc->chan_config_desc[l].chanid)); chmus = le16_to_cpu(chan_desc->chan_config_desc[l].chmus); printf("Number of Channel Media Units: %u\n", chmus); - for(m = 0; m < chmus; m++) { + for (m = 0; m < chmus; m++) { printf("Media Unit Identifier: %u\n", le16_to_cpu(chan_desc->chan_config_desc[l].mu_config_desc[m].muid)); printf("Media Unit Descriptor Length: %u\n", @@ -1131,7 +1120,7 @@ static void stdout_registers_version(__u32 vs) (vs & 0x0000ff00) >> 8); } -static void stdout_registers_cc_ams (__u8 ams) +static void stdout_registers_cc_ams(__u8 ams) { printf("\tArbitration Mechanism Selected (AMS): "); switch (ams) { @@ -1150,7 +1139,7 @@ static void stdout_registers_cc_ams (__u8 ams) } } -static void stdout_registers_cc_shn (__u8 shn) +static void stdout_registers_cc_shn(__u8 shn) { printf("\tShutdown Notification (SHN): "); switch (shn) { @@ -1238,14 +1227,23 @@ static void stdout_registers_aqa(__u32 aqa) } -static void stdout_registers_cmbloc(__u32 cmbloc, __u32 cmbsz) +static bool stdout_registers_cmbloc_support(__u32 cmbsz) { - static const char *enforced[] = { "Enforced", "Not Enforced" }; + if (cmbsz) + return true; - if (cmbsz == 0) { + return false; +} + +static void stdout_registers_cmbloc(__u32 cmbloc, bool support) +{ + static const char * const enforced[] = { "Enforced", "Not Enforced" }; + + if (!support) { printf("\tController Memory Buffer feature is not supported\n\n"); return; } + printf("\tOffset (OFST): 0x%x (See cmbsz.szu for granularity)\n", (cmbloc & 0xfffff000) >> 12); @@ -1342,12 +1340,12 @@ static void stdout_registers_bpmbl(uint64_t bpmbl) static void stdout_registers_cmbmsc(uint64_t cmbmsc) { printf("\tController Base Address (CBA): %" PRIx64 "\n", - (cmbmsc & 0xfffffffffffff000) >> 12); + (cmbmsc & 0xfffffffffffff000) >> 12); printf("\tController Memory Space Enable (CMSE): %" PRIx64 "\n", - (cmbmsc & 0x0000000000000002) >> 1); - printf("\tCapabilities Registers Enabled (CRE): CMBLOC and "\ - "CMBSZ registers are%senabled\n\n", - (cmbmsc & 0x0000000000000001) ? " " : " NOT "); + (cmbmsc & 0x0000000000000002) >> 1); + printf("\tCapabilities Registers Enabled (CRE): CMBLOC and %s%s%s", + "CMBSZ registers are", cmbmsc & 0x0000000000000001 ? " " : " NOT ", + "enabled\n\n"); } static void stdout_registers_cmbsts(__u32 cmbsts) @@ -1356,11 +1354,34 @@ static void stdout_registers_cmbsts(__u32 cmbsts) (cmbsts & 0x00000001)); } +static void stdout_registers_cmbebs(__u32 cmbebs) +{ + printf("\tCMB Elasticity Buffer Size Base (CMBWBZ): %x\n", cmbebs >> 8); + printf("\tRead Bypass Behavior : %s%s%s", + "memory reads not conflicting with memory writes in the CMB Elasticity Buffer ", + (cmbebs & 0x10) ? "SHALL" : "MAY", + " bypass those memory writes\n"); + printf("\tCMB Elasticity Buffer Size Units (CMBSZU): %s\n", + nvme_register_unit_to_string(cmbebs & 0xf)); +} + +static void stdout_registers_cmbswtp(__u32 cmbswtp) +{ + printf("\tCMB Sustained Write Throughput (CMBSWTV): %x\n", cmbswtp >> 8); + printf("\tCMB Sustained Write Throughput Units (CMBSWTU): %s/second\n", + nvme_register_unit_to_string(cmbswtp & 0xf)); +} + +static void stdout_registers_nssd(__u32 nssd) +{ + printf("\tNVM Subsystem Shutdown Control (NSSC): %x\n\n", nssd); +} + static void stdout_registers_pmrcap(__u32 pmrcap) { - printf("\tController Memory Space Supported (CMSS): "\ - "Referencing PMR with host supplied addresses is %s\n", - ((pmrcap & 0x01000000) >> 24) ? "Supported" : "Not Supported"); + printf("\tController Memory Space Supported (CMSS): %s%s%s", + "Referencing PMR with host supplied addresses is ", + (pmrcap & 0x01000000) >> 24 ? "Supported" : "Not Supported", "\n"); printf("\tPersistent Memory Region Timeout (PMRTO): %x\n", (pmrcap & 0x00ff0000) >> 16); printf("\tPersistent Memory Region Write Barrier Mechanisms (PMRWBM): %x\n", @@ -1375,34 +1396,41 @@ static void stdout_registers_pmrcap(__u32 pmrcap) (pmrcap & 0x00000008) ? "supported" : "not supported"); } +static bool stdout_registers_pmrctl_ready(__u32 pmrctl) +{ + if (pmrctl & 1) + return true; + + return false; +} + static void stdout_registers_pmrctl(__u32 pmrctl) { - printf("\tEnable (EN): PMR is %s\n", (pmrctl & 0x00000001) ? - "READY" : "Disabled"); + printf("\tEnable (EN): PMR is %s\n", + stdout_registers_pmrctl_ready(pmrctl) ? "READY" : "Disabled"); } -static void stdout_registers_pmrsts(__u32 pmrsts, __u32 pmrctl) +static void stdout_registers_pmrsts(__u32 pmrsts, bool ready) { - printf("\tController Base Address Invalid (CBAI): %x\n", - (pmrsts & 0x00001000) >> 12); + printf("\tController Base Address Invalid (CBAI): %x\n", (pmrsts & 0x1000) >> 12); printf("\tHealth Status (HSTS): %s\n", - nvme_register_pmr_hsts_to_string((pmrsts & 0x00000e00) >> 9)); - printf("\tNot Ready (NRDY): "\ - "The Persistent Memory Region is %s to process "\ - "PCI Express memory read and write requests\n", - (pmrsts & 0x00000100) == 0 && (pmrctl & 0x00000001) ? - "READY" : "Not Ready"); - printf("\tError (ERR): %x\n", (pmrsts & 0x000000ff)); + nvme_register_pmr_hsts_to_string((pmrsts & 0xe00) >> 9)); + printf("\tNot Ready (NRDY): %s%s%s%s", + "The Persistent Memory Region is ", + !(pmrsts & 0x100) && ready ? "READY" : "Not Ready", " to process ", + "PCI Express memory read and write requests\n"); + printf("\tError (ERR): %x\n", (pmrsts & 0xff)); } static void stdout_registers_pmrebs(__u32 pmrebs) { printf("\tPMR Elasticity Buffer Size Base (PMRWBZ): %x\n", (pmrebs & 0xffffff00) >> 8); - printf("\tRead Bypass Behavior : memory reads not conflicting with memory writes "\ - "in the PMR Elasticity Buffer %s bypass those memory writes\n", - (pmrebs & 0x00000010) ? "SHALL" : "MAY"); + printf("\tRead Bypass Behavior : %s%s%s%s", + "memory reads not conflicting with memory writes ", + "in the PMR Elasticity Buffer ", (pmrebs & 0x00000010) ? "SHALL" : "MAY", + " bypass those memory writes\n"); printf("\tPMR Elasticity Buffer Size Units (PMRSZU): %s\n", - nvme_register_pmr_pmrszu_to_string(pmrebs & 0x0000000f)); + nvme_register_pmr_pmrszu_to_string(pmrebs & 0x0000000f)); } static void stdout_registers_pmrswtp(__u32 pmrswtp) @@ -1415,174 +1443,200 @@ static void stdout_registers_pmrswtp(__u32 pmrswtp) static void stdout_registers_pmrmscl(uint32_t pmrmscl) { - printf("\tController Base Address (CBA): %#x\n", - (pmrmscl & 0xfffff000) >> 12); - printf("\tController Memory Space Enable (CMSE): %#x\n\n", - (pmrmscl & 0x00000002) >> 1); + printf("\tController Base Address (CBA): %#x\n", (pmrmscl & 0xfffff000) >> 12); + printf("\tController Memory Space Enable (CMSE): %#x\n\n", (pmrmscl & 0x00000002) >> 1); } static void stdout_registers_pmrmscu(uint32_t pmrmscu) { - printf("\tController Base Address (CBA): %#x\n", - pmrmscu); + printf("\tController Base Address (CBA): %#x\n", pmrmscu); } -void stdout_ctrl_registers(void *bar, bool fabrics) +static void stdout_ctrl_register_human(int offset, uint64_t value64, bool *support) { - uint64_t cap, asq, acq, bpmbl, cmbmsc; - uint32_t vs, intms, intmc, cc, csts, nssr, crto, aqa, cmbsz, cmbloc, bpinfo, - bprsel, cmbsts, pmrcap, pmrctl, pmrsts, pmrebs, pmrswtp, - pmrmscl, pmrmscu; - int human = stdout_print_ops.flags & VERBOSE; - - cap = mmio_read64(bar + NVME_REG_CAP); - vs = mmio_read32(bar + NVME_REG_VS); - intms = mmio_read32(bar + NVME_REG_INTMS); - intmc = mmio_read32(bar + NVME_REG_INTMC); - cc = mmio_read32(bar + NVME_REG_CC); - csts = mmio_read32(bar + NVME_REG_CSTS); - nssr = mmio_read32(bar + NVME_REG_NSSR); - crto = mmio_read32(bar + NVME_REG_CRTO); - aqa = mmio_read32(bar + NVME_REG_AQA); - asq = mmio_read64(bar + NVME_REG_ASQ); - acq = mmio_read64(bar + NVME_REG_ACQ); - cmbloc = mmio_read32(bar + NVME_REG_CMBLOC); - cmbsz = mmio_read32(bar + NVME_REG_CMBSZ); - bpinfo = mmio_read32(bar + NVME_REG_BPINFO); - bprsel = mmio_read32(bar + NVME_REG_BPRSEL); - bpmbl = mmio_read64(bar + NVME_REG_BPMBL); - cmbmsc = mmio_read64(bar + NVME_REG_CMBMSC); - cmbsts = mmio_read32(bar + NVME_REG_CMBSTS); - pmrcap = mmio_read32(bar + NVME_REG_PMRCAP); - pmrctl = mmio_read32(bar + NVME_REG_PMRCTL); - pmrsts = mmio_read32(bar + NVME_REG_PMRSTS); - pmrebs = mmio_read32(bar + NVME_REG_PMREBS); - pmrswtp = mmio_read32(bar + NVME_REG_PMRSWTP); - pmrmscl = mmio_read32(bar + NVME_REG_PMRMSCL); - pmrmscu = mmio_read32(bar + NVME_REG_PMRMSCU); + uint32_t value32 = (uint32_t)value64; - if (human) { - if (cap != 0xffffffff) { - printf("cap : %"PRIx64"\n", cap); - stdout_registers_cap((struct nvme_bar_cap *)&cap); - } - if (vs != 0xffffffff) { - printf("version : %x\n", vs); - stdout_registers_version(vs); - } - if (cc != 0xffffffff) { - printf("cc : %x\n", cc); - stdout_registers_cc(cc); - } - if (csts != 0xffffffff) { - printf("csts : %x\n", csts); - stdout_registers_csts(csts); - } - if (nssr != 0xffffffff) { - printf("nssr : %x\n", nssr); - printf("\tNVM Subsystem Reset Control (NSSRC): %u\n\n", - nssr); - } - if (crto != 0xffffffff) { - printf("crto : %x\n", crto); - stdout_registers_crto(crto); - } - if (!fabrics) { - printf("intms : %x\n", intms); - printf("\tInterrupt Vector Mask Set (IVMS): %x\n\n", - intms); + switch (offset) { + case NVME_REG_CAP: + stdout_registers_cap((struct nvme_bar_cap *)&value64); + break; + case NVME_REG_VS: + stdout_registers_version(value64); + break; + case NVME_REG_INTMS: + printf("\tInterrupt Vector Mask Set (IVMS): %x\n\n", value32); + break; + case NVME_REG_INTMC: + printf("\tInterrupt Vector Mask Clear (IVMC): %x\n\n", value32); + break; + case NVME_REG_CC: + stdout_registers_cc(value32); + break; + case NVME_REG_CSTS: + stdout_registers_csts(value32); + break; + case NVME_REG_NSSR: + printf("\tNVM Subsystem Reset Control (NSSRC): %u\n\n", value32); + break; + case NVME_REG_AQA: + stdout_registers_aqa(value32); + break; + case NVME_REG_ASQ: + printf("\tAdmin Submission Queue Base (ASQB): %"PRIx64"\n\n", value64); + break; + case NVME_REG_ACQ: + printf("\tAdmin Completion Queue Base (ACQB): %"PRIx64"\n\n", value64); + break; + case NVME_REG_CMBLOC: + stdout_registers_cmbloc(value32, support ? *support : true); + break; + case NVME_REG_CMBSZ: + stdout_registers_cmbsz(value32); + break; + case NVME_REG_BPINFO: + stdout_registers_bpinfo(value32); + break; + case NVME_REG_BPRSEL: + stdout_registers_bprsel(value32); + break; + case NVME_REG_BPMBL: + stdout_registers_bpmbl(value64); + break; + case NVME_REG_CMBMSC: + stdout_registers_cmbmsc(value64); + break; + case NVME_REG_CMBSTS: + stdout_registers_cmbsts(value32); + break; + case NVME_REG_CMBEBS: + stdout_registers_cmbebs(value32); + break; + case NVME_REG_CMBSWTP: + stdout_registers_cmbswtp(value32); + break; + case NVME_REG_NSSD: + stdout_registers_nssd(value32); + break; + case NVME_REG_CRTO: + stdout_registers_crto(value32); + break; + case NVME_REG_PMRCAP: + stdout_registers_pmrcap(value32); + break; + case NVME_REG_PMRCTL: + stdout_registers_pmrctl(value32); + break; + case NVME_REG_PMRSTS: + stdout_registers_pmrsts(value32, support ? *support : true); + break; + case NVME_REG_PMREBS: + stdout_registers_pmrebs(value32); + break; + case NVME_REG_PMRSWTP: + stdout_registers_pmrswtp(value32); + break; + case NVME_REG_PMRMSCL: + stdout_registers_pmrmscl(value32); + break; + case NVME_REG_PMRMSCU: + stdout_registers_pmrmscu(value32); + break; + default: + printf("unknown register: 0x%04x (%s), value: 0x%"PRIx64"\n", + offset, nvme_register_to_string(offset), value64); + break; + } +} - printf("intmc : %x\n", intmc); - printf("\tInterrupt Vector Mask Clear (IVMC): %x\n\n", - intmc); - printf("aqa : %x\n", aqa); - stdout_registers_aqa(aqa); +static void stdout_ctrl_register(int offset, uint64_t value64) +{ + bool human = stdout_print_ops.flags & VERBOSE; + uint32_t value32 = (uint32_t)value64; - printf("asq : %"PRIx64"\n", asq); - printf("\tAdmin Submission Queue Base (ASQB): %"PRIx64"\n\n", - asq); + if (human) + printf("%s: ", nvme_register_to_string(offset)); + else + printf("register: 0x%04x (%s), value: ", offset, nvme_register_to_string(offset)); - printf("acq : %"PRIx64"\n", acq); - printf("\tAdmin Completion Queue Base (ACQB): %"PRIx64"\n\n", - acq); + if (nvme_is_64bit_reg(offset)) + printf("0x%"PRIx64"\n", value64); + else + printf("0x%x\n", value32); - printf("cmbloc : %x\n", cmbloc); - stdout_registers_cmbloc(cmbloc, cmbsz); + if (human) + stdout_ctrl_register_human(offset, value64, NULL); +} - printf("cmbsz : %x\n", cmbsz); - stdout_registers_cmbsz(cmbsz); +static void stdout_ctrl_register_support(void *bar, int offset, bool human, bool support) +{ + bool reg64 = nvme_is_64bit_reg(offset); + uint64_t value = reg64 ? mmio_read64(bar + offset) : mmio_read32(bar + offset); - printf("bpinfo : %x\n", bpinfo); - stdout_registers_bpinfo(bpinfo); + printf("%-8s: ", nvme_register_symbol_to_string(offset)); - printf("bprsel : %x\n", bprsel); - stdout_registers_bprsel(bprsel); + if (reg64) + printf("%"PRIx64"\n", value); + else + printf("%x\n", (uint32_t)value); - printf("bpmbl : %"PRIx64"\n", bpmbl); - stdout_registers_bpmbl(bpmbl); + if (human) + stdout_ctrl_register_human(offset, value, &support); +} - printf("cmbmsc : %"PRIx64"\n", cmbmsc); - stdout_registers_cmbmsc(cmbmsc); +void stdout_ctrl_registers(void *bar, bool fabrics) +{ + uint64_t cap = mmio_read64(bar + NVME_REG_CAP); + uint32_t vs = mmio_read32(bar + NVME_REG_VS); + uint32_t cc = mmio_read32(bar + NVME_REG_CC); + uint32_t csts = mmio_read32(bar + NVME_REG_CSTS); + uint32_t nssr = mmio_read32(bar + NVME_REG_NSSR); + uint32_t crto = mmio_read32(bar + NVME_REG_CRTO); + uint32_t cmbsz = mmio_read32(bar + NVME_REG_CMBSZ); + uint32_t pmrctl = mmio_read32(bar + NVME_REG_PMRCTL); + bool human = stdout_print_ops.flags & VERBOSE ? true : false; - printf("cmbsts : %x\n", cmbsts); - stdout_registers_cmbsts(cmbsts); + if (cap != -1) + stdout_ctrl_register_support(bar, NVME_REG_CAP, human, true); - printf("pmrcap : %x\n", pmrcap); - stdout_registers_pmrcap(pmrcap); + if (vs != -1) + stdout_ctrl_register_support(bar, NVME_REG_VS, human, true); - printf("pmrctl : %x\n", pmrctl); - stdout_registers_pmrctl(pmrctl); + if (cc != -1) + stdout_ctrl_register_support(bar, NVME_REG_CC, human, true); - printf("pmrsts : %x\n", pmrsts); - stdout_registers_pmrsts(pmrsts, pmrctl); + if (csts != -1) + stdout_ctrl_register_support(bar, NVME_REG_CSTS, human, true); - printf("pmrebs : %x\n", pmrebs); - stdout_registers_pmrebs(pmrebs); + if (nssr != -1) + stdout_ctrl_register_support(bar, NVME_REG_NSSR, human, true); - printf("pmrswtp : %x\n", pmrswtp); - stdout_registers_pmrswtp(pmrswtp); + if (crto != -1) + stdout_ctrl_register_support(bar, NVME_REG_CRTO, human, true); - printf("pmrmscl : %#x\n", pmrmscl); - stdout_registers_pmrmscl(pmrmscl); + if (fabrics) + return; - printf("pmrmscu : %#x\n", pmrmscu); - stdout_registers_pmrmscu(pmrmscu); - } - } else { - 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 (crto != 0xffffffff) - printf("crto : %x\n", crto); - 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); - printf("bpinfo : %x\n", bpinfo); - printf("bprsel : %x\n", bprsel); - printf("bpmbl : %"PRIx64"\n", bpmbl); - printf("cmbmsc : %"PRIx64"\n", cmbmsc); - printf("cmbsts : %x\n", cmbsts); - printf("pmrcap : %x\n", pmrcap); - printf("pmrctl : %x\n", pmrctl); - printf("pmrsts : %x\n", pmrsts); - printf("pmrebs : %x\n", pmrebs); - printf("pmrswtp : %x\n", pmrswtp); - printf("pmrmscl : %#x\n", pmrmscl); - printf("pmrmscu : %#x\n", pmrmscu); - } - } + stdout_ctrl_register_support(bar, NVME_REG_INTMS, human, true); + stdout_ctrl_register_support(bar, NVME_REG_INTMC, human, true); + stdout_ctrl_register_support(bar, NVME_REG_AQA, human, true); + stdout_ctrl_register_support(bar, NVME_REG_ASQ, human, true); + stdout_ctrl_register_support(bar, NVME_REG_ACQ, human, true); + stdout_ctrl_register_support(bar, NVME_REG_CMBLOC, human, + stdout_registers_cmbloc_support(cmbsz)); + stdout_ctrl_register_support(bar, NVME_REG_CMBSZ, human, true); + stdout_ctrl_register_support(bar, NVME_REG_BPINFO, human, true); + stdout_ctrl_register_support(bar, NVME_REG_BPRSEL, human, true); + stdout_ctrl_register_support(bar, NVME_REG_BPMBL, human, true); + stdout_ctrl_register_support(bar, NVME_REG_CMBMSC, human, true); + stdout_ctrl_register_support(bar, NVME_REG_CMBSTS, human, true); + stdout_ctrl_register_support(bar, NVME_REG_PMRCAP, human, true); + stdout_ctrl_register_support(bar, NVME_REG_PMRCTL, human, true); + stdout_ctrl_register_support(bar, NVME_REG_PMRSTS, human, + stdout_registers_pmrctl_ready(pmrctl)); + stdout_ctrl_register_support(bar, NVME_REG_PMREBS, human, true); + stdout_ctrl_register_support(bar, NVME_REG_PMRSWTP, human, true); + stdout_ctrl_register_support(bar, NVME_REG_PMRMSCL, human, true); + stdout_ctrl_register_support(bar, NVME_REG_PMRMSCU, human, true); } static void stdout_single_property(int offset, uint64_t value64) @@ -1592,44 +1646,33 @@ static void stdout_single_property(int offset, uint64_t value64) if (!human) { if (nvme_is_64bit_reg(offset)) - printf("property: 0x%02x (%s), value: %"PRIx64"\n", + printf("property: 0x%04x (%s), value: %"PRIx64"\n", offset, nvme_register_to_string(offset), value64); else - printf("property: 0x%02x (%s), value: %x\n", offset, + printf("property: 0x%04x (%s), value: %x\n", offset, nvme_register_to_string(offset), value32); return; } - switch (offset) { - case NVME_REG_CAP: - printf("cap : %"PRIx64"\n", value64); - stdout_registers_cap((struct nvme_bar_cap *)&value64); - break; - case NVME_REG_VS: - printf("version : %x\n", value32); - stdout_registers_version(value32); - break; - case NVME_REG_CC: - printf("cc : %x\n", value32); - stdout_registers_cc(value32); - break; - case NVME_REG_CSTS: - printf("csts : %x\n", value32); - stdout_registers_csts(value32); - break; - case NVME_REG_NSSR: - printf("nssr : %x\n", value32); - printf("\tNVM Subsystem Reset Control (NSSRC): %u\n\n", value32); - break; - case NVME_REG_CRTO: - printf("crto : %x\n", value32); - stdout_registers_crto(value32); - break; - default: - printf("unknown property: 0x%02x (%s), value: %"PRIx64"\n", - offset, nvme_register_to_string(offset), value64); - break; + if (nvme_is_fabrics_reg(offset)) { + printf("%s : ", nvme_register_symbol_to_string(offset)); + switch (offset) { + case NVME_REG_CAP: + printf("%"PRIx64"\n", value64); + break; + case NVME_REG_VS: + case NVME_REG_CC: + case NVME_REG_CSTS: + case NVME_REG_NSSR: + case NVME_REG_CRTO: + printf("%x\n", value32); + break; + default: + break; + } } + + stdout_ctrl_register_human(offset, value64, NULL); } static void stdout_status(int status) @@ -1707,32 +1750,29 @@ static void stdout_id_ctrl_oaes(__le32 ctrl_oaes) __u32 nace = (oaes & 0x100) >> 8; __u32 rsvd3 = oaes & 0xFF; - printf(" [31:31] : %#x\tDiscovery Log Change Notice %sSupported\n", - disc, disc ? "" : "Not "); + printf(" [31:31] : %#x\tDiscovery Log Change Notice %sSupported\n", disc, + disc ? "" : "Not "); if (rsvd0) printf(" [30:28] : %#x\tReserved\n", rsvd0); - printf(" [27:27] : %#x\tZone Descriptor Changed Notices %sSupported\n", - zicn, zicn ? "" : "Not "); + printf(" [27:27] : %#x\tZone Descriptor Changed Notices %sSupported\n", zicn, + zicn ? "" : "Not "); if (rsvd1) printf(" [26:16] : %#x\tReserved\n", rsvd1); - printf(" [15:15] : %#x\tNormal NSS Shutdown Event %sSupported\n", - normal_shn, normal_shn ? "" : "Not "); - printf(" [14:14] : %#x\tEndurance Group Event Aggregate Log Page"\ - " Change Notice %sSupported\n", - egealpcn, egealpcn ? "" : "Not "); - printf(" [13:13] : %#x\tLBA Status Information Notices %sSupported\n", - lbasin, lbasin ? "" : "Not "); - printf(" [12:12] : %#x\tPredictable Latency Event Aggregate Log Change"\ - " Notices %sSupported\n", - plealcn, plealcn ? "" : "Not "); - printf(" [11:11] : %#x\tAsymmetric Namespace Access Change Notices"\ - " %sSupported\n", anacn, anacn ? "" : "Not "); + printf(" [15:15] : %#x\tNormal NSS Shutdown Event %sSupported\n", normal_shn, + normal_shn ? "" : "Not "); + printf(" [14:14] : %#x\tEndurance Group Event Aggregate Log Page Change Notice %s%s", + egealpcn, egealpcn ? "" : "Not ", "Supported\n"); + printf(" [13:13] : %#x\tLBA Status Information Notices %sSupported\n", lbasin, + lbasin ? "" : "Not "); + printf(" [12:12] : %#x\tPredictable Latency Event Aggregate Log Change Notices %s%s", + plealcn, plealcn ? "" : "Not ", "Supported\n"); + printf(" [11:11] : %#x\tAsymmetric Namespace Access Change Notices %sSupported\n", anacn, + anacn ? "" : "Not "); if (rsvd2) printf(" [10:10] : %#x\tReserved\n", rsvd2); - printf(" [9:9] : %#x\tFirmware Activation Notices %sSupported\n", - fan, fan ? "" : "Not "); - printf(" [8:8] : %#x\tNamespace Attribute Changed Event %sSupported\n", - nace, nace ? "" : "Not "); + printf(" [9:9] : %#x\tFirmware Activation Notices %sSupported\n", fan, fan ? "" : "Not "); + printf(" [8:8] : %#x\tNamespace Attribute Changed Event %sSupported\n", nace, + nace ? "" : "Not "); if (rsvd3) printf(" [7:0] : %#x\tReserved\n", rsvd3); printf("\n"); @@ -1807,7 +1847,7 @@ static void stdout_id_ctrl_cntrltype(__u8 cntrltype) __u8 rsvd = (cntrltype & 0xFC) >> 2; __u8 cntrl = cntrltype & 0x3; - static const char *type[] = { + static const char * const type[] = { "Controller type not reported", "I/O Controller", "Discovery Controller", @@ -1840,7 +1880,7 @@ static void stdout_id_ctrl_vwci(__u8 vwci) printf(" [7:7] : %#x\tVPD Write Cycles Remaining field is %svalid.\n", vwcrv, vwcrv ? "" : "Not "); - printf(" [6:0] : %#x\tVPD Write Cycles Remaining \n", vwcr); + printf(" [6:0] : %#x\tVPD Write Cycles Remaining\n", vwcr); printf("\n"); } @@ -1853,12 +1893,11 @@ static void stdout_id_ctrl_mec(__u8 mec) if (rsvd) printf(" [7:2] : %#x\tReserved\n", rsvd); - printf(" [1:1] : %#x\tNVM subsystem %scontains a Management Endpoint"\ - " on a PCIe port\n", pcieme, pcieme ? "" : "Not "); - printf(" [0:0] : %#x\tNVM subsystem %scontains a Management Endpoint"\ - " on an SMBus/I2C port\n", smbusme, smbusme ? "" : "Not "); + printf(" [1:1] : %#x\tNVM subsystem %scontains a Management Endpoint on a PCIe port\n", + pcieme, pcieme ? "" : "Not "); + printf(" [0:0] : %#x\tNVM subsystem %scontains a Management Endpoint%s", smbusme, + smbusme ? "" : "Not ", " on an SMBus/I2C port\n"); printf("\n"); - } static void stdout_id_ctrl_oacs(__le16 ctrl_oacs) @@ -1937,20 +1976,17 @@ static void stdout_id_ctrl_lpa(__u8 lpa) if (rsvd) printf(" [7:7] : %#x\tReserved\n", rsvd); - printf(" [6:6] : %#x\tTelemetry Log Data Area 4 %sSupported\n", - tel, tel ? "" : "Not "); - printf(" [5:5] : %#x\tLID 0x0, Scope of each command in LID 0x5, "\ - "0x12, 0x13 %sSupported\n", lid_sup, lid_sup ? "" : "Not "); - printf(" [4:4] : %#x\tPersistent Event log %sSupported\n", - persevnt, persevnt ? "" : "Not "); - printf(" [3:3] : %#x\tTelemetry host/controller initiated log page %sSupported\n", - telem, telem ? "" : "Not "); - printf(" [2:2] : %#x\tExtended data for Get Log Page %sSupported\n", - ed, ed ? "" : "Not "); - printf(" [1:1] : %#x\tCommand Effects Log Page %sSupported\n", - celp, celp ? "" : "Not "); - printf(" [0:0] : %#x\tSMART/Health Log Page per NS %sSupported\n", - smlp, smlp ? "" : "Not "); + printf(" [6:6] : %#x\tTelemetry Log Data Area 4 %sSupported\n", tel, tel ? "" : "Not "); + printf(" [5:5] : %#x\tLID 0x0, Scope of each command in LID 0x5, %s%s%s", lid_sup, + "0x12, 0x13 ", lid_sup ? "" : "Not ", "Supported\n"); + printf(" [4:4] : %#x\tPersistent Event log %sSupported\n", persevnt, + persevnt ? "" : "Not "); + printf(" [3:3] : %#x\tTelemetry host/controller initiated log page %sSupported\n", telem, + telem ? "" : "Not "); + printf(" [2:2] : %#x\tExtended data for Get Log Page %sSupported\n", ed, ed ? "" : "Not "); + printf(" [1:1] : %#x\tCommand Effects Log Page %sSupported\n", celp, celp ? "" : "Not "); + printf(" [0:0] : %#x\tSMART/Health Log Page per NS %sSupported\n", smlp, + smlp ? "" : "Not "); printf("\n"); } @@ -1972,6 +2008,7 @@ static void stdout_id_ctrl_avscc(__u8 avscc) { __u8 rsvd = (avscc & 0xFE) >> 1; __u8 fmt = avscc & 0x1; + if (rsvd) printf(" [7:1] : %#x\tReserved\n", rsvd); printf(" [0:0] : %#x\tAdmin Vendor Specific Commands uses %s Format\n", @@ -1983,6 +2020,7 @@ static void stdout_id_ctrl_apsta(__u8 apsta) { __u8 rsvd = (apsta & 0xFE) >> 1; __u8 apst = apsta & 0x1; + if (rsvd) printf(" [7:1] : %#x\tReserved\n", rsvd); printf(" [0:0] : %#x\tAutonomous Power State Transitions %sSupported\n", @@ -2071,7 +2109,7 @@ static void stdout_id_ctrl_sanicap(__le32 ctrl_sanicap) __u32 ndi = (sanicap & 0x20000000) >> 29; __u32 nodmmas = (sanicap & 0xC0000000) >> 30; - static const char *modifies_media[] = { + static const char * const modifies_media[] = { "Additional media modification after sanitize operation completes successfully is not defined", "Media is not additionally modified after sanitize operation completes successfully", "Media is additionally modified after sanitize operation completes successfully", @@ -2126,6 +2164,7 @@ static void stdout_id_ctrl_sqes(__u8 sqes) { __u8 msqes = (sqes & 0xF0) >> 4; __u8 rsqes = sqes & 0xF; + printf(" [7:4] : %#x\tMax SQ Entry Size (%d)\n", msqes, 1 << msqes); printf(" [3:0] : %#x\tMin SQ Entry Size (%d)\n", rsqes, 1 << rsqes); printf("\n"); @@ -2135,6 +2174,7 @@ static void stdout_id_ctrl_cqes(__u8 cqes) { __u8 mcqes = (cqes & 0xF0) >> 4; __u8 rcqes = cqes & 0xF; + printf(" [7:4] : %#x\tMax CQ Entry Size (%d)\n", mcqes, 1 << mcqes); printf(" [3:0] : %#x\tMin CQ Entry Size (%d)\n", rcqes, 1 << rcqes); printf("\n"); @@ -2203,6 +2243,7 @@ static void stdout_id_ctrl_fna(__u8 fna) __u8 cese = (fna & 0x4) >> 2; __u8 cens = (fna & 0x2) >> 1; __u8 fmns = fna & 0x1; + if (rsvd) printf(" [7:4] : %#x\tReserved\n", rsvd); printf(" [3:3] : %#x\tFormat NVM Broadcast NSID (FFFFFFFFh) %sSupported\n", @@ -2222,7 +2263,7 @@ static void stdout_id_ctrl_vwc(__u8 vwc) __u8 flush = (vwc & 0x6) >> 1; __u8 vwcp = vwc & 0x1; - static const char *flush_behavior[] = { + static const char * const flush_behavior[] = { "Support for the NSID field set to FFFFFFFFh is not indicated", "Reserved", "The Flush command does not support NSID set to FFFFFFFFh", @@ -2232,8 +2273,7 @@ static void stdout_id_ctrl_vwc(__u8 vwc) if (rsvd) printf(" [7:3] : %#x\tReserved\n", rsvd); printf(" [2:1] : %#x\t%s\n", flush, flush_behavior[flush]); - printf(" [0:0] : %#x\tVolatile Write Cache %sPresent\n", - vwcp, vwcp ? "" : "Not "); + printf(" [0:0] : %#x\tVolatile Write Cache %sPresent\n", vwcp, vwcp ? "" : "Not "); printf("\n"); } @@ -2241,6 +2281,7 @@ static void stdout_id_ctrl_icsvscc(__u8 icsvscc) { __u8 rsvd = (icsvscc & 0xFE) >> 1; __u8 fmt = icsvscc & 0x1; + if (rsvd) printf(" [7:1] : %#x\tReserved\n", rsvd); printf(" [0:0] : %#x\tNVM Vendor Specific Commands uses %s Format\n", @@ -2273,6 +2314,7 @@ static void stdout_id_ctrl_ocfs(__le16 ctrl_ocfs) __u16 rsvd = ocfs >> 4; __u8 copy_fmt_supported; int copy_fmt; + if (rsvd) printf(" [15:4] : %#x\tReserved\n", rsvd); for (copy_fmt = 3; copy_fmt >= 0; copy_fmt--) { @@ -2307,9 +2349,8 @@ static void stdout_id_ctrl_sgls(__le32 ctrl_sgls) printf(" [20:20]: %#x\tAddress Offsets %sSupported\n", aofdsl, aofdsl ? "" : "Not "); if (sglsp || (!sglsp && mpcsd)) - printf(" [19:19]: %#x\tMetadata Pointer Containing " - "SGL Descriptor is %sSupported\n", - mpcsd, mpcsd ? "" : "Not "); + printf(" [19:19]: %#x\tMetadata Pointer Containing SGL Descriptor is %s%s", + mpcsd, mpcsd ? "" : "Not ", "Supported\n"); if (sglsp || (!sglsp && sglltb)) printf(" [18:18]: %#x\tSGL Length Larger than Buffer %sSupported\n", sglltb, sglltb ? "" : "Not "); @@ -2328,11 +2369,11 @@ static void stdout_id_ctrl_sgls(__le32 ctrl_sgls) if (sglsp == 0x3) printf(" [1:0] : %#x\tReserved\n", sglsp); else if (sglsp == 0x2) - printf(" [1:0] : %#x\tScatter-Gather Lists Supported." - " Dword alignment required.\n", sglsp); + printf(" [1:0] : %#x\tScatter-Gather Lists Supported.%s", + sglsp, " Dword alignment required.\n"); else if (sglsp == 0x1) - printf(" [1:0] : %#x\tScatter-Gather Lists Supported." - " No Dword alignment required.\n", sglsp); + printf(" [1:0] : %#x\tScatter-Gather Lists Supported.%s", + sglsp, " No Dword alignment required.\n"); else printf(" [1:0] : %#x\tScatter-Gather Lists Not Supported\n", sglsp); printf("\n"); @@ -2342,6 +2383,7 @@ static void stdout_id_ctrl_fcatt(__u8 fcatt) { __u8 rsvd = (fcatt & 0xFE) >> 1; __u8 scm = fcatt & 0x1; + if (rsvd) printf(" [7:1] : %#x\tReserved\n", rsvd); printf(" [0:0] : %#x\t%s Controller Model\n", @@ -2353,6 +2395,7 @@ static void stdout_id_ctrl_ofcs(__le16 ofcs) { __u16 rsvd = (ofcs & 0xfffe) >> 1; __u8 disconn = ofcs & 0x1; + if (rsvd) printf(" [15:1] : %#x\tReserved\n", rsvd); printf(" [0:0] : %#x\tDisconnect command %s Supported\n", @@ -2369,6 +2412,7 @@ static void stdout_id_ns_nsfeat(__u8 nsfeat) __u8 dulbe = (nsfeat & 0x4) >> 2; __u8 na = (nsfeat & 0x2) >> 1; __u8 thin = nsfeat & 0x1; + if (rsvd) printf(" [7:5] : %#x\tReserved\n", rsvd); printf(" [4:4] : %#x\tNPWG, NPWA, NPDG, NPDA, and NOWS are %sSupported\n", @@ -2407,6 +2451,7 @@ static void stdout_id_ns_mc(__u8 mc) __u8 rsvd = (mc & 0xFC) >> 2; __u8 mdp = (mc & 0x2) >> 1; __u8 extdlba = mc & 0x1; + if (rsvd) printf(" [7:2] : %#x\tReserved\n", rsvd); printf(" [1:1] : %#x\tMetadata Pointer %sSupported\n", @@ -2424,6 +2469,7 @@ static void stdout_id_ns_dpc(__u8 dpc) __u8 pit3 = (dpc & 0x4) >> 2; __u8 pit2 = (dpc & 0x2) >> 1; __u8 pit1 = dpc & 0x1; + if (rsvd) printf(" [7:5] : %#x\tReserved\n", rsvd); printf(" [4:4] : %#x\tProtection Information Transferred as Last Bytes of Metadata %sSupported\n", @@ -2444,6 +2490,7 @@ static void stdout_id_ns_dps(__u8 dps) __u8 rsvd = (dps & 0xF0) >> 4; __u8 pif8 = (dps & 0x8) >> 3; __u8 pit = dps & 0x7; + if (rsvd) printf(" [7:4] : %#x\tReserved\n", rsvd); printf(" [3:3] : %#x\tProtection Information is Transferred as %s Bytes of Metadata\n", @@ -2460,6 +2507,7 @@ static void stdout_id_ns_nmic(__u8 nmic) { __u8 rsvd = (nmic & 0xFE) >> 1; __u8 mp = nmic & 0x1; + if (rsvd) printf(" [7:1] : %#x\tReserved\n", rsvd); printf(" [0:0] : %#x\tNamespace Multipath %sCapable\n", @@ -2501,6 +2549,7 @@ static void stdout_id_ns_fpi(__u8 fpi) { __u8 fpis = (fpi & 0x80) >> 7; __u8 fpii = fpi & 0x7F; + printf(" [7:7] : %#x\tFormat Progress Indicator %sSupported\n", fpis, fpis ? "" : "Not "); if (fpis || (!fpis && fpii)) @@ -2513,6 +2562,7 @@ static void stdout_id_ns_nsattr(__u8 nsattr) { __u8 rsvd = (nsattr & 0xFE) >> 1; __u8 write_protected = nsattr & 0x1; + if (rsvd) printf(" [7:1] : %#x\tReserved\n", rsvd); printf(" [0:0] : %#x\tNamespace %sWrite Protected\n", @@ -2526,6 +2576,7 @@ static void stdout_id_ns_dlfeat(__u8 dlfeat) __u8 guard = (dlfeat & 0x10) >> 4; __u8 dwz = (dlfeat & 0x8) >> 3; __u8 val = dlfeat & 0x7; + if (rsvd) printf(" [7:5] : %#x\tReserved\n", rsvd); printf(" [4:4] : %#x\tGuard Field of Deallocated Logical Blocks is set to %s\n", @@ -2629,19 +2680,18 @@ static void stdout_id_ns(struct nvme_id_ns *ns, unsigned int nsid, nvme_id_ns_flbas_to_lbaf_inuse(ns->flbas, &flbas); for (i = 0; i <= ns->nlbaf + ns->nulbaf; i++) { - if (human) - printf("LBA Format %2d : Metadata Size: %-3d bytes - " - "Data Size: %-2d bytes - Relative Performance: %#x %s %s\n", - i, le16_to_cpu(ns->lbaf[i].ms), - 1 << ns->lbaf[i].ds, ns->lbaf[i].rp, - ns->lbaf[i].rp == 3 ? "Degraded" : - ns->lbaf[i].rp == 2 ? "Good" : - ns->lbaf[i].rp == 1 ? "Better" : "Best", - i == flbas ? in_use : ""); - else + if (human) { + printf("LBA Format %2d : Metadata Size: %-3d bytes - ", i, + le16_to_cpu(ns->lbaf[i].ms)); + printf("Data Size: %-2d bytes - Relative Performance: %#x %s %s\n", + 1 << ns->lbaf[i].ds, ns->lbaf[i].rp, + ns->lbaf[i].rp == 3 ? "Degraded" : ns->lbaf[i].rp == 2 ? "Good" : + ns->lbaf[i].rp == 1 ? "Better" : "Best", i == flbas ? in_use : ""); + } else { printf("lbaf %2d : ms:%-3d lbads:%-2d rp:%#x %s\n", i, - le16_to_cpu(ns->lbaf[i].ms), ns->lbaf[i].ds, - ns->lbaf[i].rp, i == flbas ? in_use : ""); + le16_to_cpu(ns->lbaf[i].ms), ns->lbaf[i].ds, + ns->lbaf[i].rp, i == flbas ? in_use : ""); + } } if (vs && !cap_only) { @@ -2657,6 +2707,7 @@ static void stdout_cmd_set_independent_id_ns_nsfeat(__u8 nsfeat) __u8 rmedia = (nsfeat & 0x10) >> 4; __u8 uidreuse = (nsfeat & 0x8) >> 3; __u8 rsvd0 = (nsfeat & 0x7); + if (rsvd6) printf(" [7:6] : %#x\tReserved\n", rsvd6); printf(" [5:5] : %#x\tVolatile Write Cache is %sPresent\n", @@ -2674,6 +2725,7 @@ static void stdout_cmd_set_independent_id_ns_nstat(__u8 nstat) { __u8 rsvd1 = (nstat & 0xfe) >> 1; __u8 nrdy = nstat & 0x1; + if (rsvd1) printf(" [7:1] : %#x\tReserved\n", rsvd1); printf(" [0:0] : %#x\tName space is %sready\n", @@ -3077,16 +3129,15 @@ static void stdout_nvm_id_ns(struct nvme_nvm_id_ns *nvm_ns, unsigned int nsid, elbaf = le32_to_cpu(nvm_ns->elbaf[i]); pif = (elbaf >> 7) & 0x3; sts = elbaf & 0x7f; - if (verbose) - printf("Extended LBA Format %2d : Protection Information Format: " - "%s(%d) - Storage Tag Size (MSB): %-2d %s\n", - i, pif == 3 ? "Reserved" : - pif == 2 ? "64b Guard" : - pif == 1 ? "32b Guard" : "16b Guard", - pif, sts, i == (ns->flbas & 0xf) ? in_use : ""); - else + if (verbose) { + printf("Extended LBA Format %2d : Protection Information Format: ", i); + printf("%s(%d) - Storage Tag Size (MSB): %-2d %s\n", pif == 3 ? "Reserved" : + pif == 2 ? "64b Guard" : pif == 1 ? "32b Guard" : "16b Guard", + pif, sts, i == (ns->flbas & 0xf) ? in_use : ""); + } else { printf("elbaf %2d : pif:%d sts:%-2d %s\n", i, - pif, sts, i == (ns->flbas & 0xf) ? in_use : ""); + pif, sts, i == (ns->flbas & 0xf) ? in_use : ""); + } } } @@ -3102,6 +3153,7 @@ static void show_nvme_id_ns_zoned_zoc(__le16 ns_zoc) __u8 rsvd = (zoc & 0xfffc) >> 2; __u8 ze = (zoc & 0x2) >> 1; __u8 vzc = zoc & 0x1; + if (rsvd) printf(" [15:2] : %#x\tReserved\n", rsvd); printf(" [1:1] : %#x\t Zone Active Excursions: %s\n", @@ -3130,6 +3182,7 @@ static void stdout_zns_id_ns_recommended_limit(__le32 ns_rl, int human, const char *target_limit) { unsigned int recommended_limit = le32_to_cpu(ns_rl); + if (!recommended_limit && human) printf("%s : Not Reported\n", target_limit); else @@ -3173,21 +3226,19 @@ static void stdout_zns_id_ns(struct nvme_zns_id_ns *ns, } if (human) { - if (ns->mar == 0xffffffff) { + if (ns->mar == 0xffffffff) printf("mar : No Active Resource Limit\n"); - } else { + else printf("mar : %u\tActive Resources\n", le32_to_cpu(ns->mar) + 1); - } } else { printf("mar : %#x\n", le32_to_cpu(ns->mar)); } if (human) { - if (ns->mor == 0xffffffff) { + if (ns->mor == 0xffffffff) printf("mor : No Open Resource Limit\n"); - } else { + else printf("mor : %u\tOpen Resources\n", le32_to_cpu(ns->mor) + 1); - } } else { printf("mor : %#x\n", le32_to_cpu(ns->mor)); } @@ -3211,16 +3262,16 @@ static void stdout_zns_id_ns(struct nvme_zns_id_ns *ns, printf("zrwacap : %u\n", ns->zrwacap); } - for (i = 0; i <= id_ns->nlbaf; i++){ + for (i = 0; i <= id_ns->nlbaf; i++) { if (human) - printf("LBA Format Extension %2d : Zone Size: 0x%"PRIx64" LBAs - " - "Zone Descriptor Extension Size: %-1d bytes%s\n", - i, le64_to_cpu(ns->lbafe[i].zsze), ns->lbafe[i].zdes << 6, - i == lbaf ? " (in use)" : ""); + printf("LBA Format Extension %2d : %s0x%"PRIx64" LBAs - %s%-1d%s%s", + i, "Zone Size: ", le64_to_cpu(ns->lbafe[i].zsze), + "Zone Descriptor Extension Size: ", ns->lbafe[i].zdes << 6, " bytes", + i == lbaf ? " (in use)\n" : "\n"); else printf("lbafe %2d: zsze:0x%"PRIx64" zdes:%u%s\n", i, - (uint64_t)le64_to_cpu(ns->lbafe[i].zsze), - ns->lbafe[i].zdes, i == lbaf ? " (in use)" : ""); + (uint64_t)le64_to_cpu(ns->lbafe[i].zsze), + ns->lbafe[i].zdes, i == lbaf ? " (in use)" : ""); } if (vs) { @@ -3264,20 +3315,18 @@ static void stdout_zns_changed(struct nvme_zns_changed_zone_log *log) static void stdout_zns_report_zone_attributes(__u8 za, __u8 zai) { - const char *const recommended_limit[4] = {"","1","2","3"}; + const char *const recommended_limit[4] = {"", "1", "2", "3"}; + printf("Attrs: Zone Descriptor Extension is %sVaild\n", - (za & NVME_ZNS_ZA_ZDEV)? "" : "Not "); - if(za & NVME_ZNS_ZA_RZR) { + za & NVME_ZNS_ZA_ZDEV ? "" : "Not "); + if (za & NVME_ZNS_ZA_RZR) printf(" Reset Zone Recommended with Reset Recommended Limit%s\n", - recommended_limit[(zai&0xd)>>2]); - } - if (za & NVME_ZNS_ZA_FZR) { + recommended_limit[(zai&0xd)>>2]); + if (za & NVME_ZNS_ZA_FZR) printf(" Finish Zone Recommended with Finish Recommended Limit%s\n", - recommended_limit[zai&0x3]); - } - if (za & NVME_ZNS_ZA_ZFC) { + recommended_limit[zai&0x3]); + if (za & NVME_ZNS_ZA_ZFC) printf(" Zone Finished by Controller\n"); - } } static void stdout_zns_report_zones(void *report, __u32 descs, @@ -3295,7 +3344,7 @@ static void stdout_zns_report_zones(void *report, __u32 descs, for (i = 0; i < descs; i++) { desc = (struct nvme_zns_desc *) (report + sizeof(*r) + i * (sizeof(*desc) + ext_size)); - if(verbose) { + if (verbose) { printf("SLBA: %#-10"PRIx64" WP: %#-10"PRIx64" Cap: %#-10"PRIx64" State: %-12s Type: %-14s\n", (uint64_t)le64_to_cpu(desc->zslba), (uint64_t)le64_to_cpu(desc->wp), (uint64_t)le64_to_cpu(desc->zcap), nvme_zone_state_to_string(desc->zs >> 4), @@ -3512,9 +3561,8 @@ static void stdout_endurance_group_list(struct nvme_id_endurance_group_list *end __u16 num = le16_to_cpu(endgrp_list->num); printf("num of endurance group ids: %u\n", num); - for (i = 0; i < min(num, 2047); i++) { + for (i = 0; i < min(num, 2047); i++) printf("[%4u]:%#x\n", i, le16_to_cpu(endgrp_list->identifier[i])); - } } static void stdout_id_iocs(struct nvme_id_iocs *iocs) @@ -3538,7 +3586,7 @@ static void stdout_error_log(struct nvme_error_log_page *err_log, int entries, for (i = 0; i < entries; i++) { __u16 status = le16_to_cpu(err_log[i].status_field) >> 0x1; - printf(" Entry[%2d] \n", i); + printf(" Entry[%2d]\n", i); printf(".................\n"); printf("error_count : %"PRIu64"\n", le64_to_cpu(err_log[i].error_count)); @@ -3683,7 +3731,7 @@ static void stdout_effects_log_human(FILE *stream, __u32 effect) fprintf(stream, " Reserved CSE\n"); } -static void stdout_effects_entry(FILE* stream, int admin, int index, +static void stdout_effects_entry(FILE *stream, int admin, int index, __le32 entry, unsigned int human) { __u32 effect; @@ -3704,7 +3752,7 @@ static void stdout_effects_entry(FILE* stream, int admin, int index, static void stdout_effects_log_segment(int admin, int a, int b, struct nvme_cmd_effects_log *effects, - char* header, int human) + char *header, int human) { FILE *stream; char *stream_location; @@ -3717,13 +3765,10 @@ static void stdout_effects_log_segment(int admin, int a, int b, } for (int i = a; i < b; i++) { - if (admin) { + if (admin) stdout_effects_entry(stream, admin, i, effects->acs[i], human); - } - else { - stdout_effects_entry(stream, admin, i, - effects->iocs[i], human); - } + else + stdout_effects_entry(stream, admin, i, effects->iocs[i], human); } fclose(stream); @@ -3788,7 +3833,7 @@ static void stdout_support_log_human(__u32 support, __u8 lid) static void stdout_supported_log(struct nvme_supported_log_pages *support_log, const char *devname) { - int lid, human = stdout_print_ops.flags& VERBOSE; + int lid, human = stdout_print_ops.flags & VERBOSE; __u32 support = 0; printf("Support Log Pages Details for %s:\n", devname); @@ -3957,11 +4002,9 @@ static void stdout_self_test_result(struct nvme_st_result *res) "Operation was aborted by a Controller Level Reset", "Operation was aborted due to a removal of a namespace from the namespace inventory", "Operation was aborted due to the processing of a Format NVM command", - "A fatal error or unknown test error occurred while the controller was executing the"\ - " device self-test operation and the operation did not complete", + "A fatal error or unknown test error occurred while the controller was executing the device self-test operation and the operation did not complete", "Operation completed with a segment that failed and the segment that failed is not known", - "Operation completed with one or more failed segments and the first segment that failed "\ - "is indicated in the SegmentNumber field", + "Operation completed with one or more failed segments and the first segment that failed is indicated in the SegmentNumber field", "Operation was aborted for unknown reason", "Operation was aborted due to a sanitize operation", "Reserved", @@ -4062,14 +4105,15 @@ static void stdout_sanitize_log_sstat(__u16 status) printf("\t [8]\t"); if (status & NVME_SANITIZE_SSTAT_GLOBAL_DATA_ERASED) - str = "Global Data Erased set: no NS LB in the NVM subsystem "\ - "has been written to and no PMR in the NVM subsystem "\ - "has been enabled"; + str = "Global Data Erased set: no NS LB in the NVM subsystem "; else - str = "Global Data Erased cleared: a NS LB in the NVM "\ - "subsystem has been written to or a PMR in the NVM "\ - "subsystem has been enabled"; - printf("%s\n", str); + str = "Global Data Erased cleared: a NS LB in the NVM "; + printf("%s%s%s\n", str, status & NVME_SANITIZE_SSTAT_GLOBAL_DATA_ERASED ? + "has been written to and no PMR in the NVM subsystem " : + "subsystem has been written to or a PMR in the NVM ", + status & NVME_SANITIZE_SSTAT_GLOBAL_DATA_ERASED ? + "has been enabled" : + "subsystem has been enabled"); } static void stdout_estimate_sanitize_time(const char *text, uint32_t value) @@ -4151,12 +4195,12 @@ static void stdout_auto_pst(struct nvme_feat_auto_pst *apst) int i; __u64 value; - printf( "\tAuto PST Entries"); + printf("\tAuto PST Entries"); printf("\t.................\n"); for (i = 0; i < ARRAY_SIZE(apst->apst_entry); i++) { value = le64_to_cpu(apst->apst_entry[i]); - printf("\tEntry[%2d] \n", i); + printf("\tEntry[%2d]\n", i); printf("\t.................\n"); printf("\tIdle Time Prior to Transition (ITPT): %u ms\n", (__u32)NVME_GET(value, APST_ENTRY_ITPT)); @@ -4175,18 +4219,18 @@ static void stdout_timestamp(struct nvme_timestamp *ts) tm = localtime(×tamp); printf("\tThe timestamp is : %'"PRIu64" (%s)\n", - int48_to_long(ts->timestamp), - strftime(buffer, sizeof(buffer), "%c %Z", tm) ? buffer : "-"); - printf("\t%s\n", (ts->attr & 2) ? - "The Timestamp field was initialized with a "\ - "Timestamp value using a Set Features command." : - "The Timestamp field was initialized "\ - "to ‘0’ by a Controller Level Reset."); - printf("\t%s\n", (ts->attr & 1) ? - "The controller may have stopped counting during vendor specific "\ - "intervals after the Timestamp value was initialized" : - "The controller counted time in milliseconds "\ - "continuously since the Timestamp value was initialized."); + int48_to_long(ts->timestamp), + strftime(buffer, sizeof(buffer), "%c %Z", tm) ? buffer : "-"); + printf("\t%s%s\n", ts->attr & 2 ? + "The Timestamp field was initialized with a " : + "The Timestamp field was initialized ", + ts->attr & 2 ? "Timestamp value using a Set Features command." : + "to ‘0’ by a Controller Level Reset."); + printf("\t%s%s\n", ts->attr & 1 ? + "The controller may have stopped counting during vendor specific " : + "The controller counted time in milliseconds ", + ts->attr & 1 ? "intervals after the Timestamp value was initialized" : + "continuously since the Timestamp value was initialized."); } static void stdout_host_mem_buffer(struct nvme_host_mem_buf_attrs *hmb) @@ -4211,21 +4255,21 @@ static void stdout_directive_show_fields(__u8 dtype, __u8 doper, case NVME_DIRECTIVE_DTYPE_IDENTIFY: switch (doper) { case NVME_DIRECTIVE_RECEIVE_IDENTIFY_DOPER_PARAM: - printf("\tDirective support \n"); + printf("\tDirective support\n"); printf("\t\tIdentify Directive : %s\n", (*field & 0x1) ? "supported" : "not supported"); printf("\t\tStream Directive : %s\n", (*field & 0x2) ? "supported" : "not supported"); printf("\t\tData Placement Directive : %s\n", (*field & 0x4) ? "supported" : "not supported"); - printf("\tDirective enabled \n"); + printf("\tDirective enabled\n"); printf("\t\tIdentify Directive : %s\n", (*(field + 32) & 0x1) ? "enabled" : "disabled"); printf("\t\tStream Directive : %s\n", (*(field + 32) & 0x2) ? "enabled" : "disabled"); printf("\t\tData Placement Directive : %s\n", (*(field + 32) & 0x4) ? "enabled" : "disabled"); - printf("\tDirective Persistent Across Controller Level Resets \n"); + printf("\tDirective Persistent Across Controller Level Resets\n"); printf("\t\tIdentify Directive : %s\n", (*(field + 64) & 0x1) ? "enabled" : "disabled"); printf("\t\tStream Directive : %s\n", @@ -4313,25 +4357,26 @@ void stdout_d(unsigned char *buf, int len, int width, int group) for (i = 0; i < len; i++) { if (!(i % width)) - printf( "\n%04x:", offset); + printf("\n%04x:", offset); if (i % group) - printf( "%02x", buf[i]); + printf("%02x", buf[i]); else - printf( " %02x", buf[i]); + printf(" %02x", buf[i]); ascii[i % width] = (buf[i] >= '!' && buf[i] <= '~') ? buf[i] : '.'; if (!((i + 1) % width)) { - printf( " \"%.*s\"", width, ascii); + printf(" \"%.*s\"", width, ascii); offset += width; memset(ascii, 0, sizeof(ascii)); } } if (strlen(ascii)) { - unsigned b = width - (i % width); - printf( " %*s \"%.*s\"", 2 * b + b / group + (b % group ? 1 : 0), "", width, ascii); + unsigned int b = width - (i % width); + + printf(" %*s \"%.*s\"", 2 * b + b / group + (b % group ? 1 : 0), "", width, ascii); } - printf( "\n"); + printf("\n"); } static void stdout_plm_config(struct nvme_plm_config *plmcfg) @@ -4589,13 +4634,13 @@ static void stdout_lba_status(struct nvme_lba_status *list, switch (list->cmpc) { case 1: - printf("\tCompleted due to transferring the amount of data"\ + printf("\tCompleted due to transferring the amount of data%s", " specified in the MNDW field\n"); break; case 2: - printf("\tCompleted due to having performed the action\n"\ - "\tspecified in the Action Type field over the\n"\ - "\tnumber of logical blocks specified in the\n"\ + printf("\tCompleted due to having performed the action\n%s%s%s", + "\tspecified in the Action Type field over the\n", + "\tnumber of logical blocks specified in the\n", "\tRange Length field\n"); break; default: @@ -4604,6 +4649,7 @@ static void stdout_lba_status(struct nvme_lba_status *list, for (idx = 0; idx < list->nlsd; idx++) { struct nvme_lba_status_desc *e = &list->descs[idx]; + printf("{ DSLBA: 0x%016"PRIu64", NLB: 0x%08x, Status: 0x%02x }\n", le64_to_cpu(e->dslba), le32_to_cpu(e->nlb), e->status); @@ -4635,8 +4681,8 @@ static void stdout_generic_full_path(nvme_ns_t n, char *path, size_t len) int instance; struct stat st; - sscanf(nvme_ns_get_name(n), "nvme%dn%d", &instance, &head_instance); - snprintf(path, len, "/dev/ng%dn%d", instance, head_instance); + if (sscanf(nvme_ns_get_name(n), "nvme%dn%d", &instance, &head_instance) == 2) + snprintf(path, len, "/dev/ng%dn%d", instance, head_instance); if (stat(path, &st) == 0) return; @@ -4717,8 +4763,8 @@ static void stdout_ns_details(nvme_ns_t n) const char *u_suffix = suffix_si_get(&nuse); const char *l_suffix = suffix_binary_get(&lba); - sprintf(usage,"%6.2f %2sB / %6.2f %2sB", nuse, u_suffix, nsze, s_suffix); - sprintf(format,"%3.0f %2sB + %2d B", (double)lba, l_suffix, + sprintf(usage, "%6.2f %2sB / %6.2f %2sB", nuse, u_suffix, nsze, s_suffix); + sprintf(format, "%3.0f %2sB + %2d B", (double)lba, l_suffix, nvme_ns_get_meta_size(n)); nvme_dev_full_path(n, devname, sizeof(devname)); @@ -5090,6 +5136,7 @@ static struct print_ops stdout_print_ops = { .phy_rx_eom_log = stdout_phy_rx_eom_log, .ctrl_list = stdout_list_ctrl, .ctrl_registers = stdout_ctrl_registers, + .ctrl_register = stdout_ctrl_register, .directive = stdout_directive_show, .discovery_log = stdout_discovery_log, .effects_log_list = stdout_effects_log_pages, @@ -5130,7 +5177,7 @@ static struct print_ops stdout_print_ops = { .sanitize_log_page = stdout_sanitize_log, .secondary_ctrl_list = stdout_list_secondary_ctrl, .select_result = stdout_select_result, - .self_test_log = stdout_self_test_log, + .self_test_log = stdout_self_test_log, .single_property = stdout_single_property, .smart_log = stdout_smart_log, .supported_cap_config_list_log = stdout_supported_cap_config_log, diff --git a/nvme-print.c b/nvme-print.c index 2c7802be71..47dc67ce25 100644 --- a/nvme-print.c +++ b/nvme-print.c @@ -351,15 +351,69 @@ const char *nvme_register_pmr_hsts_to_string(__u8 hsts) } } +const char *nvme_register_unit_to_string(__u8 unit) +{ + switch (unit) { + case 0: + return "Bytes"; + case 1: + return "One KB"; + case 2: + return "One MB"; + case 3: + return "One GB"; + default: + break; + } + + return "Reserved"; +} + const char *nvme_register_pmr_pmrszu_to_string(__u8 pmrszu) { - switch (pmrszu) { - case 0: return "Bytes"; - case 1: return "One KB"; - case 2: return "One MB"; - case 3: return "One GB"; - default: return "Reserved"; + return nvme_register_unit_to_string(pmrszu); +} + +bool nvme_is_fabrics_reg(int offset) +{ + switch (offset) { + case NVME_REG_CAP: + case NVME_REG_VS: + case NVME_REG_CC: + case NVME_REG_CSTS: + case NVME_REG_NSSR: + case NVME_REG_CRTO: + return true; + default: + break; + } + + return false; +} + +void nvme_show_ctrl_register(void *bar, bool fabrics, int offset, enum nvme_print_flags flags) +{ + uint64_t value; + + if (nvme_is_64bit_reg(offset)) + value = mmio_read64(bar + offset); + else + value = mmio_read32(bar + offset); + + if (!nvme_is_fabrics_reg(offset)) { + if (fabrics) { + printf("register: 0x%04x (%s) not fabrics\n", offset, + nvme_register_to_string(offset)); + return; + } + if (value == -1) { + printf("register: 0x%04x (%s), value: 0x%"PRIx64" not valid\n", offset, + nvme_register_to_string(offset), value); + return; + } } + + nvme_print(ctrl_register, flags, offset, value); } void nvme_show_ctrl_registers(void *bar, bool fabrics, enum nvme_print_flags flags) @@ -761,20 +815,67 @@ const char *nvme_feature_to_string(enum nvme_features_id feature) const char *nvme_register_to_string(int reg) { switch (reg) { - case NVME_REG_CAP: return "Controller Capabilities"; - case NVME_REG_VS: return "Version"; - case NVME_REG_INTMS: return "Interrupt Vector Mask Set"; - case NVME_REG_INTMC: return "Interrupt Vector Mask Clear"; - case NVME_REG_CC: return "Controller Configuration"; - case NVME_REG_CSTS: return "Controller Status"; - case NVME_REG_NSSR: return "NVM Subsystem Reset"; - case NVME_REG_AQA: return "Admin Queue Attributes"; - case NVME_REG_ASQ: return "Admin Submission Queue Base Address"; - case NVME_REG_ACQ: return "Admin Completion Queue Base Address"; - case NVME_REG_CMBLOC: return "Controller Memory Buffer Location"; - case NVME_REG_CMBSZ: return "Controller Memory Buffer Size"; - default: return "Unknown"; + case NVME_REG_CAP: + return "Controller Capabilities"; + case NVME_REG_VS: + return "Version"; + case NVME_REG_INTMS: + return "Interrupt Vector Mask Set"; + case NVME_REG_INTMC: + return "Interrupt Vector Mask Clear"; + case NVME_REG_CC: + return "Controller Configuration"; + case NVME_REG_CSTS: + return "Controller Status"; + case NVME_REG_NSSR: + return "NVM Subsystem Reset"; + case NVME_REG_AQA: + return "Admin Queue Attributes"; + case NVME_REG_ASQ: + return "Admin Submission Queue Base Address"; + case NVME_REG_ACQ: + return "Admin Completion Queue Base Address"; + case NVME_REG_CMBLOC: + return "Controller Memory Buffer Location"; + case NVME_REG_CMBSZ: + return "Controller Memory Buffer Size"; + case NVME_REG_BPINFO: + return "Boot Partition Information"; + case NVME_REG_BPRSEL: + return "Boot Partition Read Select"; + case NVME_REG_BPMBL: + return "Boot Partition Memory Buffer Location"; + case NVME_REG_CMBMSC: + return "Controller Memory Buffer Memory Space Control"; + case NVME_REG_CMBSTS: + return "Controller Memory Buffer Status"; + case NVME_REG_CMBEBS: + return "Controller Memory Buffer Elasticity Buffer Size"; + case NVME_REG_CMBSWTP: + return "Controller Memory Buffer Sustained Write Throughput"; + case NVME_REG_NSSD: + return "NVM Subsystem Shutdown"; + case NVME_REG_CRTO: + return "Controller Ready Timeouts"; + case NVME_REG_PMRCAP: + return "Persistent Memory Region Capabilities"; + case NVME_REG_PMRCTL: + return "Persistent Memory Region Control"; + case NVME_REG_PMRSTS: + return "Persistent Memory Region Status"; + case NVME_REG_PMREBS: + return "Persistent Memory Region Elasticity Buffer Size"; + case NVME_REG_PMRSWTP: + return "Persistent Memory Region Sustained Write Throughput"; + case NVME_REG_PMRMSCL: + return "Persistent Memory Region Memory Space Control Lower"; + case NVME_REG_PMRMSCU: + return "Persistent Memory Region Memory Space Control Upper"; + default: + break; } + + return "Unknown"; } const char *nvme_select_to_string(int sel) @@ -950,6 +1051,72 @@ const char *nvme_host_metadata_type_to_string(enum nvme_features_id fid, } } +const char *nvme_register_symbol_to_string(int offset) +{ + switch (offset) { + case NVME_REG_CAP: + return "cap"; + case NVME_REG_VS: + return "version"; + case NVME_REG_INTMS: + return "intms"; + case NVME_REG_INTMC: + return "intmc"; + case NVME_REG_CC: + return "cc"; + case NVME_REG_CSTS: + return "csts"; + case NVME_REG_NSSR: + return "nssr"; + case NVME_REG_AQA: + return "aqa"; + case NVME_REG_ASQ: + return "asq"; + case NVME_REG_ACQ: + return "acq"; + case NVME_REG_CMBLOC: + return "cmbloc"; + case NVME_REG_CMBSZ: + return "cmbsz"; + case NVME_REG_BPINFO: + return "bpinfo"; + case NVME_REG_BPRSEL: + return "bprsel"; + case NVME_REG_BPMBL: + return "bpmbl"; + case NVME_REG_CMBMSC: + return "cmbmsc"; + case NVME_REG_CMBSTS: + return "cmbsts"; + case NVME_REG_CMBEBS: + return "cmbebs"; + case NVME_REG_CMBSWTP: + return "cmbswtp"; + case NVME_REG_NSSD: + return "nssd"; + case NVME_REG_CRTO: + return "crto"; + case NVME_REG_PMRCAP: + return "pmrcap"; + case NVME_REG_PMRCTL: + return "pmrctl"; + case NVME_REG_PMRSTS: + return "pmrsts"; + case NVME_REG_PMREBS: + return "pmrebs"; + case NVME_REG_PMRSWTP: + return "pmrswtp"; + case NVME_REG_PMRMSCL: + return "pmrmscl"; + case NVME_REG_PMRMSCU: + return "pmrmscu"; + default: + break; + } + + return "unknown"; +} + void nvme_feature_show(enum nvme_features_id fid, int sel, unsigned int result) { nvme_print(show_feature, NORMAL, fid, sel, result); diff --git a/nvme-print.h b/nvme-print.h index 4533474eb3..c503ca798f 100644 --- a/nvme-print.h +++ b/nvme-print.h @@ -26,6 +26,7 @@ struct print_ops { void (*phy_rx_eom_log)(struct nvme_phy_rx_eom_log *log, __u16 controller); void (*ctrl_list)(struct nvme_ctrl_list *ctrl_list); void (*ctrl_registers)(void *bar, bool fabrics); + void (*ctrl_register)(int offset, uint64_t value); void (*directive)(__u8 type, __u8 oper, __u16 spec, __u32 nsid, __u32 result, void *buf, __u32 len); void (*discovery_log)(struct nvmf_discovery_log *log, int numrec); void (*effects_log_list)(struct list_head *list); @@ -205,6 +206,7 @@ void nvme_show_media_unit_stat_log(struct nvme_media_unit_stat_log *mus, void nvme_show_supported_cap_config_log(struct nvme_supported_cap_config_list_log *caplog, enum nvme_print_flags flags); void nvme_show_ctrl_registers(void *bar, bool fabrics, enum nvme_print_flags flags); +void nvme_show_ctrl_register(void *bar, bool fabrics, int offset, enum nvme_print_flags flags); void nvme_show_single_property(int offset, uint64_t prop, enum nvme_print_flags flags); void nvme_show_id_ns_descs(void *data, unsigned nsid, enum nvme_print_flags flags); void nvme_show_lba_status(struct nvme_lba_status *list, unsigned long len, @@ -291,9 +293,11 @@ const char *nvme_log_to_string(__u8 lid); const char *nvme_nss_hw_error_to_string(__u16 error_code); const char *nvme_pel_event_to_string(int type); const char *nvme_register_pmr_hsts_to_string(__u8 hsts); +const char *nvme_register_unit_to_string(__u8 ebszu); const char *nvme_register_pmr_pmrszu_to_string(__u8 pmrszu); const char *nvme_register_szu_to_string(__u8 szu); const char *nvme_register_to_string(int reg); +const char *nvme_register_symbol_to_string(int offset); const char *nvme_resv_notif_to_string(__u8 type); const char *nvme_select_to_string(int sel); const char *nvme_sstat_status_to_string(__u16 status); @@ -310,4 +314,5 @@ void nvme_show_perror(const char *msg); void nvme_show_error_status(int status, const char *msg, ...); void nvme_show_init(void); void nvme_show_finish(void); +bool nvme_is_fabrics_reg(int offset); #endif /* NVME_PRINT_H */ diff --git a/nvme.c b/nvme.c index 64aa556000..a411212993 100644 --- a/nvme.c +++ b/nvme.c @@ -106,6 +106,60 @@ struct passthru_config { bool latency; }; +struct get_reg_config { + int offset; + bool human_readable; + bool cap; + bool vs; + bool intms; + bool intmc; + bool cc; + bool csts; + bool nssr; + bool aqa; + bool asq; + bool acq; + bool cmbloc; + bool cmbsz; + bool bpinfo; + bool bprsel; + bool bpmbl; + bool cmbmsc; + bool cmbsts; + bool cmbebs; + bool cmbswtp; + bool nssd; + bool crto; + bool pmrcap; + bool pmrctl; + bool pmrsts; + bool pmrebs; + bool pmrswtp; + bool pmrmscl; + bool pmrmscu; +}; + +struct set_reg_config { + int offset; + bool mmio32; + __u64 value; + __u32 intms; + __u32 intmc; + __u32 cc; + __u32 csts; + __u32 nssr; + __u32 aqa; + __u64 asq; + __u64 acq; + __u32 bprsel; + __u64 bpmbl; + __u64 cmbmsc; + __u32 nssd; + __u32 pmrctl; + __u32 pmrmscl; + __u32 pmrmscu; +}; + #define NVME_ARGS(n, ...) \ struct argconfig_commandline_options n[] = { \ OPT_FLAG("verbose", 'v', NULL, verbose), \ @@ -114,6 +168,11 @@ struct passthru_config { OPT_END() \ } +#define REG_ARGS(opts, cfg, ...) \ + NVME_ARGS(opts, \ + OPT_UINT("offset", 'O', &cfg.offset, offset), \ + ##__VA_ARGS__) + static const char nvme_version_string[] = NVME_VERSION; static struct plugin builtin = { @@ -184,10 +243,26 @@ static const char *uuid_index_specify = "specify uuid index"; static const char *verbose = "Increase output verbosity"; static const char dash[51] = {[0 ... 49] = '=', '\0'}; static const char space[51] = {[0 ... 49] = ' ', '\0'}; +static const char *offset = "offset of the requested register"; +static const char *intms = "INTMS=0xc register offset"; +static const char *intmc = "INTMC=0x10 register offset"; +static const char *cc = "CC=0x14 register offset"; +static const char *csts = "CSTS=0x1c register offset"; +static const char *nssr = "NSSR=0x20 register offset"; +static const char *aqa = "AQA=0x24 register offset"; +static const char *asq = "ASQ=0x28 register offset"; +static const char *acq = "ACQ=0x30 register offset"; +static const char *bprsel = "BPRSEL=0x44 register offset"; +static const char *bpmbl = "BPMBL=0x48 register offset"; +static const char *cmbmsc = "CMBMSC=0x50 register offset"; +static const char *nssd = "NSSD=0x64 register offset"; +static const char *pmrctl = "PMRCTL=0xe04 register offset"; +static const char *pmrmscl = "PMRMSCL=0xe14 register offset"; +static const char *pmrmscu = "PMRMSCU=0xe18 register offset"; static char *output_format_val = "normal"; -static void *mmap_registers(nvme_root_t r, struct nvme_dev *dev); +static void *mmap_registers(nvme_root_t r, struct nvme_dev *dev, bool writable); const char *nvme_strerror(int errnum) { @@ -469,6 +544,7 @@ static int get_smart_log(int argc, char **argv, struct command *cmd, struct plug "(default) or binary."; _cleanup_free_ struct nvme_smart_log *smart_log = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; const char *namespace = "(optional) desired namespace"; enum nvme_print_flags flags; @@ -531,7 +607,7 @@ static int get_ana_log(int argc, char **argv, struct command *cmd, "decoded format (default), json or binary."; const char *groups = "Return ANA groups only."; - _cleanup_nvme_dev_ struct nvme_dev *dev= NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; _cleanup_free_ struct nvme_id_ctrl *ctrl = NULL; _cleanup_free_ void *ana_log = NULL; size_t ana_log_len; @@ -1011,7 +1087,7 @@ static int get_effects_log(int argc, char **argv, struct command *cmd, struct pl __u64 cap; r = nvme_scan(NULL); - bar = mmap_registers(r, dev); + bar = mmap_registers(r, dev, false); nvme_free_tree(r); if (bar) { @@ -1419,6 +1495,7 @@ static int get_persistent_event_log(int argc, char **argv, _cleanup_free_ struct nvme_persistent_event_log *pevent_collected = NULL; _cleanup_free_ struct nvme_persistent_event_log *pevent = NULL; + _cleanup_huge_ struct nvme_mem_huge mh = { 0, }; _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; @@ -5214,7 +5291,7 @@ static int nvme_get_properties(int fd, void **pbar) return err; } -static void *mmap_registers(nvme_root_t r, struct nvme_dev *dev) +static void *mmap_registers(nvme_root_t r, struct nvme_dev *dev, bool writable) { nvme_ctrl_t c = NULL; nvme_ns_t n = NULL; @@ -5222,6 +5299,10 @@ static void *mmap_registers(nvme_root_t r, struct nvme_dev *dev) char path[512]; void *membase; int fd; + int prot = PROT_READ; + + if (writable) + prot |= PROT_WRITE; c = nvme_scan_ctrl(r, dev->name); if (c) { @@ -5239,7 +5320,7 @@ static void *mmap_registers(nvme_root_t r, struct nvme_dev *dev) nvme_free_ns(n); } - fd = open(path, O_RDONLY); + fd = open(path, writable ? O_RDWR : O_RDONLY); if (fd < 0) { if (map_log_level(0, false) >= LOG_DEBUG) nvme_show_error("%s did not find a pci resource, open failed %s", @@ -5247,7 +5328,7 @@ static void *mmap_registers(nvme_root_t r, struct nvme_dev *dev) return NULL; } - membase = mmap(NULL, getpagesize(), PROT_READ, MAP_SHARED, fd, 0); + membase = mmap(NULL, getpagesize(), prot, MAP_SHARED, fd, 0); if (membase == MAP_FAILED) { if (map_log_level(0, false) >= LOG_DEBUG) { fprintf(stderr, "%s failed to map. ", dev->name); @@ -5299,7 +5380,7 @@ static int show_registers(int argc, char **argv, struct command *cmd, struct plu flags |= VERBOSE; r = nvme_scan(NULL); - bar = mmap_registers(r, dev); + bar = mmap_registers(r, dev, false); if (!bar) { err = nvme_get_properties(dev_fd(dev), &bar); if (err) @@ -5317,6 +5398,629 @@ static int show_registers(int argc, char **argv, struct command *cmd, struct plu return err; } +static int get_register_property(int fd, void **pbar, int offset) +{ + int err; + int size = offset + 1 + (nvme_is_64bit_reg(offset) ? sizeof(uint64_t) : sizeof(uint32_t)); + __u64 value; + void *bar = malloc(size); + struct nvme_get_property_args args = { + .args_size = sizeof(args), + .fd = fd, + .offset = offset, + .value = &value, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + }; + + if (!bar) { + nvme_show_error("malloc: %s", strerror(errno)); + return -1; + } + + memset(bar, 0xff, size); + + err = nvme_get_property(&args); + if (nvme_status_equals(err, NVME_STATUS_TYPE_NVME, NVME_SC_INVALID_FIELD)) { + value = -1; + } else if (err) { + nvme_show_error("get-property: %s", nvme_strerror(errno)); + free(bar); + return err; + } + + if (nvme_is_64bit_reg(offset)) + *(uint64_t *)(bar + offset) = value; + else + *(uint32_t *)(bar + offset) = value; + + *pbar = bar; + + return 0; +} + +static bool get_register_flag(void *bar, bool fabrics, struct get_reg_config *cfg, int offset, + enum nvme_print_flags flags) +{ + bool flag = false; + + if (cfg->offset == offset) + return false; + + switch (offset) { + case NVME_REG_CAP: + if (cfg->cap) + flag = true; + break; + case NVME_REG_VS: + if (cfg->vs) + flag = true; + break; + case NVME_REG_INTMS: + if (cfg->intms) + flag = true; + break; + case NVME_REG_INTMC: + if (cfg->intmc) + flag = true; + break; + case NVME_REG_CC: + if (cfg->cc) + flag = true; + break; + case NVME_REG_CSTS: + if (cfg->csts) + flag = true; + break; + case NVME_REG_NSSR: + if (cfg->nssr) + flag = true; + break; + case NVME_REG_AQA: + if (cfg->aqa) + flag = true; + break; + case NVME_REG_ASQ: + if (cfg->asq) + flag = true; + break; + case NVME_REG_ACQ: + if (cfg->acq) + flag = true; + break; + case NVME_REG_CMBLOC: + if (cfg->cmbloc) + flag = true; + break; + case NVME_REG_CMBSZ: + if (cfg->cmbsz) + flag = true; + break; + case NVME_REG_BPINFO: + if (cfg->bpinfo) + flag = true; + break; + case NVME_REG_BPRSEL: + if (cfg->bprsel) + flag = true; + break; + case NVME_REG_BPMBL: + if (cfg->bpmbl) + flag = true; + break; + case NVME_REG_CMBMSC: + if (cfg->cmbmsc) + flag = true; + break; + case NVME_REG_CMBSTS: + if (cfg->cmbsts) + flag = true; + break; + case NVME_REG_CMBEBS: + if (cfg->cmbebs) + flag = true; + break; + case NVME_REG_CMBSWTP: + if (cfg->cmbswtp) + flag = true; + break; + case NVME_REG_NSSD: + if (cfg->nssd) + flag = true; + break; + case NVME_REG_CRTO: + if (cfg->crto) + flag = true; + break; + case NVME_REG_PMRCAP: + if (cfg->pmrcap) + flag = true; + break; + case NVME_REG_PMRCTL: + if (cfg->pmrctl) + flag = true; + break; + case NVME_REG_PMRSTS: + if (cfg->pmrsts) + flag = true; + break; + case NVME_REG_PMREBS: + if (cfg->pmrebs) + flag = true; + break; + case NVME_REG_PMRSWTP: + if (cfg->pmrswtp) + flag = true; + break; + case NVME_REG_PMRMSCL: + if (cfg->pmrmscl) + flag = true; + break; + case NVME_REG_PMRMSCU: + if (cfg->pmrmscu) + flag = true; + break; + default: + break; + } + + if (flag) + nvme_show_ctrl_register(bar, fabrics, offset, flags); + + return flag; +} + +static bool get_register_offset(void *bar, bool fabrics, struct get_reg_config *cfg, + enum nvme_print_flags flags) +{ + bool flag = cfg->offset >= 0; + + if (flag) + nvme_show_ctrl_register(bar, fabrics, cfg->offset, flags); + + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_CAP, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_VS, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_INTMS, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_INTMC, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_CC, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_CSTS, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_NSSR, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_AQA, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_ASQ, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_ACQ, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_CMBLOC, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_CMBSZ, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_BPINFO, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_BPRSEL, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_BPMBL, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_CMBMSC, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_CMBSTS, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_CMBEBS, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_CMBSWTP, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_NSSD, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_CRTO, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_PMRCAP, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_PMRCTL, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_PMRSTS, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_PMREBS, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_PMRSWTP, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_PMRMSCL, flags) || flag; + flag = get_register_flag(bar, fabrics, cfg, NVME_REG_PMRMSCU, flags) || flag; + + return flag; +} + +static int get_register(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Reads and shows the defined NVMe controller register.\n" + "Register offset must be one of:\n" + "CAP=0x0, VS=0x8, INTMS=0xc, INTMC=0x10, CC=0x14, CSTS=0x1c,\n" + "NSSR=0x20, AQA=0x24, ASQ=0x28, ACQ=0x30, CMBLOC=0x38,\n" + "CMBSZ=0x3c, BPINFO=0x40, BPRSEL=0x44, BPMBL=0x48, CMBMSC=0x50,\n" + "CMBSTS=0x58, CRTO=0x68, PMRCAP=0xe00, PMRCTL=0xe04,\n" + "PMRSTS=0xe08, PMREBS=0xe0c, PMRSWTP=0xe10, PMRMSCL=0xe14, PMRMSCU=0xe18"; + const char *human_readable = "show register in readable format"; + const char *cap = "CAP=0x0 register offset"; + const char *vs = "VS=0x8 register offset"; + const char *cmbloc = "CMBLOC=0x38 register offset"; + const char *cmbsz = "CMBSZ=0x3c register offset"; + const char *bpinfo = "BPINFO=0x40 register offset"; + const char *cmbsts = "CMBSTS=0x58 register offset"; + const char *cmbebs = "CMBEBS=0x5c register offset"; + const char *cmbswtp = "CMBSWTP=0x60 register offset"; + const char *crto = "CRTO=0x68 register offset"; + const char *pmrcap = "PMRCAP=0xe00 register offset"; + const char *pmrsts = "PMRSTS=0xe08 register offset"; + const char *pmrebs = "PMREBS=0xe0c register offset"; + const char *pmrswtp = "PMRSWTP=0xe10 register offset"; + const char *pmrmscl = "PMRMSCL=0xe14 register offset"; + const char *pmrmscu = "PMRMSCU=0xe18 register offset"; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + int err; + enum nvme_print_flags flags; + bool fabrics = false; + + _cleanup_nvme_root_ nvme_root_t r = NULL; + void *bar; + + struct get_reg_config cfg = { + .offset = -1, + }; + + REG_ARGS(opts, cfg, + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable), + OPT_FLAG("cap", 'c', &cfg.cap, cap), + OPT_FLAG("vs", 'V', &cfg.vs, vs), + OPT_FLAG("cmbloc", 'm', &cfg.cmbloc, cmbloc), + OPT_FLAG("cmbsz", 'M', &cfg.cmbsz, cmbsz), + OPT_FLAG("bpinfo", 'b', &cfg.bpinfo, bpinfo), + OPT_FLAG("cmbsts", 'S', &cfg.cmbsts, cmbsts), + OPT_FLAG("cmbebs", 'E', &cfg.cmbebs, cmbebs), + OPT_FLAG("cmbswtp", 'W', &cfg.cmbswtp, cmbswtp), + OPT_FLAG("crto", 'r', &cfg.crto, crto), + OPT_FLAG("pmrcap", 'P', &cfg.pmrcap, pmrcap), + OPT_FLAG("pmrsts", 't', &cfg.pmrsts, pmrsts), + OPT_FLAG("pmrebs", 'e', &cfg.pmrebs, pmrebs), + OPT_FLAG("pmrswtp", 'w', &cfg.pmrswtp, pmrswtp), + OPT_FLAG("intms", 'i', &cfg.intms, intms), + OPT_FLAG("intmc", 'I', &cfg.intmc, intmc), + OPT_FLAG("cc", 'C', &cfg.cc, cc), + OPT_FLAG("csts", 'T', &cfg.csts, csts), + OPT_FLAG("nssr", 'n', &cfg.nssr, nssr), + OPT_FLAG("aqa", 'a', &cfg.aqa, aqa), + OPT_FLAG("asq", 'A', &cfg.asq, asq), + OPT_FLAG("acq", 'q', &cfg.acq, acq), + OPT_FLAG("bprsel", 'B', &cfg.bprsel, bprsel), + OPT_FLAG("bpmbl", 'p', &cfg.bpmbl, bpmbl), + OPT_FLAG("cmbmsc", 's', &cfg.cmbmsc, cmbmsc), + OPT_FLAG("nssd", 'N', &cfg.nssd, nssd), + OPT_FLAG("pmrctl", 'R', &cfg.pmrctl, pmrctl), + OPT_FLAG("pmrmscl", 'l', &cfg.pmrmscl, pmrmscl), + OPT_FLAG("pmrmscu", 'u', &cfg.pmrmscu, pmrmscu)); + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } + + if (cfg.human_readable) + flags |= VERBOSE; + + r = nvme_scan(NULL); + bar = mmap_registers(r, dev, false); + if (!bar) { + err = get_register_property(dev_fd(dev), &bar, NVME_REG_PMRMSCU); + if (err) + return err; + fabrics = true; + } + + if (!get_register_offset(bar, fabrics, &cfg, flags)) { + nvme_show_error("offset required param"); + err = -EINVAL; + } + + if (fabrics) + free(bar); + else + munmap(bar, getpagesize()); + + return err; +} + +static void nvme_set_register(void *bar, int offset, uint64_t value, bool mmio32) +{ + if (nvme_is_64bit_reg(offset)) + mmio_write64(bar + offset, value, mmio32); + else + mmio_write32(bar + offset, value); + + printf("set-register: %02x (%s), value: %"PRIx64"\n", offset, + nvme_register_to_string(offset), value); +} + +static void set_register_value(void *bar, struct argconfig_commandline_options *opts, + struct set_reg_config *cfg, int offset) +{ + switch (offset) { + case NVME_REG_INTMS: + if (argconfig_parse_seen(opts, "intms")) + nvme_set_register(bar, offset, cfg->intms, cfg->mmio32); + break; + case NVME_REG_INTMC: + if (argconfig_parse_seen(opts, "intmc")) + nvme_set_register(bar, offset, cfg->intmc, cfg->mmio32); + break; + case NVME_REG_CC: + if (argconfig_parse_seen(opts, "cc")) + nvme_set_register(bar, offset, cfg->cc, cfg->mmio32); + break; + case NVME_REG_CSTS: + if (argconfig_parse_seen(opts, "csts")) + nvme_set_register(bar, offset, cfg->csts, cfg->mmio32); + break; + case NVME_REG_NSSR: + if (argconfig_parse_seen(opts, "nssr")) + nvme_set_register(bar, offset, cfg->nssr, cfg->mmio32); + break; + case NVME_REG_AQA: + if (argconfig_parse_seen(opts, "aqa")) + nvme_set_register(bar, offset, cfg->aqa, cfg->mmio32); + break; + case NVME_REG_ASQ: + if (argconfig_parse_seen(opts, "asq")) + nvme_set_register(bar, offset, cfg->asq, cfg->mmio32); + break; + case NVME_REG_ACQ: + if (argconfig_parse_seen(opts, "acq")) + nvme_set_register(bar, offset, cfg->acq, cfg->mmio32); + break; + case NVME_REG_BPRSEL: + if (argconfig_parse_seen(opts, "bprsel")) + nvme_set_register(bar, offset, cfg->bprsel, cfg->mmio32); + break; + case NVME_REG_CMBMSC: + if (argconfig_parse_seen(opts, "cmbmsc")) + nvme_set_register(bar, offset, cfg->cmbmsc, cfg->mmio32); + break; + case NVME_REG_NSSD: + if (argconfig_parse_seen(opts, "nssd")) + nvme_set_register(bar, offset, cfg->nssd, cfg->mmio32); + break; + case NVME_REG_PMRCTL: + if (argconfig_parse_seen(opts, "pmrctl")) + nvme_set_register(bar, offset, cfg->pmrctl, cfg->mmio32); + break; + case NVME_REG_PMRMSCL: + if (argconfig_parse_seen(opts, "pmrmscl")) + nvme_set_register(bar, offset, cfg->pmrmscl, cfg->mmio32); + break; + case NVME_REG_PMRMSCU: + if (argconfig_parse_seen(opts, "pmrmscu")) + nvme_set_register(bar, offset, cfg->pmrmscu, cfg->mmio32); + break; + default: + break; + } +} + +static int set_register_check(struct argconfig_commandline_options *opts, + struct set_reg_config *cfg, int offset) +{ + bool flag = false; + + switch (offset) { + case NVME_REG_INTMS: + if (argconfig_parse_seen(opts, "intms")) + flag = true; + break; + case NVME_REG_INTMC: + if (argconfig_parse_seen(opts, "intmc")) + flag = true; + break; + case NVME_REG_CC: + if (argconfig_parse_seen(opts, "cc")) + flag = true; + break; + case NVME_REG_CSTS: + if (argconfig_parse_seen(opts, "csts")) + flag = true; + break; + case NVME_REG_NSSR: + if (argconfig_parse_seen(opts, "nssr")) + flag = true; + break; + case NVME_REG_AQA: + if (argconfig_parse_seen(opts, "aqa")) + flag = true; + break; + case NVME_REG_ASQ: + if (argconfig_parse_seen(opts, "asq")) + flag = true; + break; + case NVME_REG_ACQ: + if (argconfig_parse_seen(opts, "acq")) + flag = true; + break; + case NVME_REG_BPRSEL: + if (argconfig_parse_seen(opts, "bprsel")) + flag = true; + break; + case NVME_REG_CMBMSC: + if (argconfig_parse_seen(opts, "cmbmsc")) + flag = true; + break; + case NVME_REG_NSSD: + if (argconfig_parse_seen(opts, "nssd")) + flag = true; + break; + case NVME_REG_PMRCTL: + if (argconfig_parse_seen(opts, "pmrctl")) + flag = true; + break; + case NVME_REG_PMRMSCL: + if (argconfig_parse_seen(opts, "pmrmscl")) + flag = true; + break; + case NVME_REG_PMRMSCU: + if (argconfig_parse_seen(opts, "pmrmscu")) + flag = true; + break; + default: + break; + } + + if (flag && cfg->offset == offset) { + nvme_show_error("offset duplicated param"); + return -EINVAL; + } + + return 0; +} + +static int set_register_offset_check(struct argconfig_commandline_options *opts, + struct set_reg_config *cfg) +{ + int err; + + if (!argconfig_parse_seen(opts, "value")) { + nvme_show_error("value required param"); + return -EINVAL; + } + + err = set_register_check(opts, cfg, NVME_REG_INTMS); + if (err) + return err; + + err = set_register_check(opts, cfg, NVME_REG_INTMC); + if (err) + return err; + + err = set_register_check(opts, cfg, NVME_REG_CC); + if (err) + return err; + + err = set_register_check(opts, cfg, NVME_REG_CSTS); + if (err) + return err; + + err = set_register_check(opts, cfg, NVME_REG_NSSR); + if (err) + return err; + + err = set_register_check(opts, cfg, NVME_REG_AQA); + if (err) + return err; + + err = set_register_check(opts, cfg, NVME_REG_ASQ); + if (err) + return err; + + err = set_register_check(opts, cfg, NVME_REG_ACQ); + if (err) + return err; + + err = set_register_check(opts, cfg, NVME_REG_BPRSEL); + if (err) + return err; + + err = set_register_check(opts, cfg, NVME_REG_BPMBL); + if (err) + return err; + + err = set_register_check(opts, cfg, NVME_REG_CMBMSC); + if (err) + return err; + + err = set_register_check(opts, cfg, NVME_REG_NSSD); + if (err) + return err; + + err = set_register_check(opts, cfg, NVME_REG_PMRCTL); + if (err) + return err; + + err = set_register_check(opts, cfg, NVME_REG_PMRMSCL); + if (err) + return err; + + err = set_register_check(opts, cfg, NVME_REG_PMRMSCU); + if (err) + return err; + + return 0; +} + +static int set_register_offset(void *bar, struct argconfig_commandline_options *opts, + struct set_reg_config *cfg) +{ + bool set = cfg->offset >= 0; + int err; + + if (set) { + err = set_register_offset_check(opts, cfg); + if (err) + return err; + nvme_set_register(bar, cfg->offset, cfg->value, cfg->mmio32); + } + + set_register_value(bar, opts, cfg, NVME_REG_INTMS); + set_register_value(bar, opts, cfg, NVME_REG_INTMC); + set_register_value(bar, opts, cfg, NVME_REG_CC); + set_register_value(bar, opts, cfg, NVME_REG_CSTS); + set_register_value(bar, opts, cfg, NVME_REG_NSSR); + set_register_value(bar, opts, cfg, NVME_REG_AQA); + set_register_value(bar, opts, cfg, NVME_REG_ASQ); + set_register_value(bar, opts, cfg, NVME_REG_ACQ); + set_register_value(bar, opts, cfg, NVME_REG_BPRSEL); + set_register_value(bar, opts, cfg, NVME_REG_BPMBL); + set_register_value(bar, opts, cfg, NVME_REG_CMBMSC); + set_register_value(bar, opts, cfg, NVME_REG_NSSD); + set_register_value(bar, opts, cfg, NVME_REG_PMRCTL); + set_register_value(bar, opts, cfg, NVME_REG_PMRMSCL); + set_register_value(bar, opts, cfg, NVME_REG_PMRMSCU); + + return 0; +} + +static int set_register(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Writes and shows the defined NVMe controller register"; + const char *value = "the value of the register to be set"; + const char *mmio32 = "Access 64-bit registers as 2 32-bit"; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + int err; + + _cleanup_nvme_root_ nvme_root_t r = NULL; + void *bar; + + struct set_reg_config cfg = { + .offset = -1, + }; + + REG_ARGS(opts, cfg, + OPT_SUFFIX("value", 'V', &cfg.value, value), + OPT_FLAG("mmio32", 'M', &cfg.mmio32, mmio32), + OPT_UINT("intms", 'i', &cfg.intms, intms), + OPT_UINT("intmc", 'I', &cfg.intmc, intmc), + OPT_UINT("cc", 'C', &cfg.cc, cc), + OPT_UINT("csts", 'T', &cfg.csts, csts), + OPT_UINT("nssr", 'n', &cfg.nssr, nssr), + OPT_UINT("aqa", 'a', &cfg.aqa, aqa), + OPT_SUFFIX("asq", 'A', &cfg.asq, asq), + OPT_SUFFIX("acq", 'q', &cfg.acq, acq), + OPT_UINT("bprsel", 'B', &cfg.bprsel, bprsel), + OPT_SUFFIX("bpmbl", 'p', &cfg.bpmbl, bpmbl), + OPT_SUFFIX("cmbmsc", 's', &cfg.cmbmsc, cmbmsc), + OPT_UINT("nssd", 'N', &cfg.nssd, nssd), + OPT_UINT("pmrctl", 'R', &cfg.pmrctl, pmrctl), + OPT_UINT("pmrmscl", 'l', &cfg.pmrmscl, pmrmscl), + OPT_UINT("pmrmscu", 'u', &cfg.pmrmscu, pmrmscu)); + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + r = nvme_scan(NULL); + bar = mmap_registers(r, dev, true); + if (!bar) { + nvme_show_error("Failed to map"); + return -EINVAL; + } + + err = set_register_offset(bar, opts, &cfg); + + munmap(bar, getpagesize()); + + return err; +} + static int get_property(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Reads and shows the defined NVMe controller property\n" diff --git a/nvme.h b/nvme.h index 3915698599..366a3de976 100644 --- a/nvme.h +++ b/nvme.h @@ -106,6 +106,10 @@ static inline DEFINE_CLEANUP_FUNC( cleanup_nvme_dev, struct nvme_dev *, dev_close) #define _cleanup_nvme_dev_ __cleanup__(cleanup_nvme_dev) +static inline DEFINE_CLEANUP_FUNC( + cleanup_nvme_root, nvme_root_t, nvme_free_tree) +#define _cleanup_nvme_root_ __cleanup__(cleanup_nvme_root) + extern const char *output_format; int validate_output_format(const char *format, enum nvme_print_flags *flags); diff --git a/subprojects/libnvme.wrap b/subprojects/libnvme.wrap index 7aa3c43009..411c95d971 100644 --- a/subprojects/libnvme.wrap +++ b/subprojects/libnvme.wrap @@ -1,6 +1,6 @@ [wrap-git] url = https://github.com/linux-nvme/libnvme.git -revision = b5122474cc0f545e7a8868f9c0177a41428acb2b +revision = 24a5580e13ff3aed1e4a872bd7cb329a1bb9273a [provide] libnvme = libnvme_dep