]> www.infradead.org Git - users/sagi/nvme-cli.git/commitdiff
nvme: add flexible data placement management commands
authorKlaus Jensen <k.jensen@samsung.com>
Tue, 13 Dec 2022 20:05:12 +0000 (21:05 +0100)
committerKlaus Jensen <k.jensen@samsung.com>
Thu, 19 Jan 2023 17:45:48 +0000 (18:45 +0100)
Add relevant TP4146 ("Flexible Data Placement") management commands.

Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
14 files changed:
Documentation/meson.build
Documentation/nvme-fdp-configs.txt [new file with mode: 0644]
Documentation/nvme-fdp-events.txt [new file with mode: 0644]
Documentation/nvme-fdp-set-events.txt [new file with mode: 0644]
Documentation/nvme-fdp-stats.txt [new file with mode: 0644]
Documentation/nvme-fdp-status.txt [new file with mode: 0644]
Documentation/nvme-fdp-update.txt [new file with mode: 0644]
Documentation/nvme-fdp-usage.txt [new file with mode: 0644]
nvme-print.c
nvme-print.h
nvme.c
plugins/fdp/fdp.c [new file with mode: 0644]
plugins/fdp/fdp.h [new file with mode: 0644]
plugins/meson.build

index c64891484d9dd7be8b3784150066f9a0eea2dd57..a526b992d6d4a66c622296c4001272c5b709fde6 100644 (file)
@@ -31,6 +31,13 @@ adoc_sources = [
   'nvme-error-log',
   'nvme-fid-support-effects-log',
   'nvme-mi-cmd-support-effects-log',
+  'nvme-fdp-configs',
+  'nvme-fdp-usage',
+  'nvme-fdp-stats',
+  'nvme-fdp-events',
+  'nvme-fdp-status',
+  'nvme-fdp-update',
+  'nvme-fdp-set-events',
   'nvme-flush',
   'nvme-format',
   'nvme-fw-commit',
diff --git a/Documentation/nvme-fdp-configs.txt b/Documentation/nvme-fdp-configs.txt
new file mode 100644 (file)
index 0000000..c4311fb
--- /dev/null
@@ -0,0 +1,42 @@
+nvme-fdp-configs(1)
+===================
+
+NAME
+----
+nvme-fdp-configs - Get Flexible Data Placement Configurations
+
+SYNOPSIS
+--------
+[verse]
+'nvme fdp configs' <device> [--endgrp-id=<NUM> | -e <NUM>]
+                           [--human-readable | -H]
+                           [--raw-binary | -b]
+                           [--output-format=<FMT> | -o <FMT>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, and the endurance group identifier specified, list
+the possible configurations for Flexible Data Placement.
+
+OPTIONS
+-------
+-e <NUM>::
+--endgrp-id=<NUM>::
+       The endurance group identifier to use when requesting the log page.
+
+-H::
+--human-readable::
+       Parse, print and describe individual parts of bitfields.
+
+-b::
+--raw-binary::
+       Print the raw buffer to the standard output stream.
+
+-o <format>::
+--output-format=<format>::
+       Set the reporting format to 'normal', 'json', or 'binary'. Only one
+       output format can be used at a time.
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-fdp-events.txt b/Documentation/nvme-fdp-events.txt
new file mode 100644 (file)
index 0000000..606a163
--- /dev/null
@@ -0,0 +1,42 @@
+nvme-fdp-events(1)
+==================
+
+NAME
+----
+nvme-fdp-events - Get Flexible Data Placement Events
+
+SYNOPSIS
+--------
+[verse]
+'nvme fdp events' <device> [--endgrp-id=<NUM> | -e <NUM>]
+                          [--host-events | -E]
+                          [--raw-binary | -b]
+                          [--output-format=<FMT> | -o <FMT>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, provide information about events affecting Reclaim
+Units and media usage in an Endurance Group.
+
+OPTIONS
+-------
+-e <NUM>::
+--endgrp-id=<NUM>::
+       The endurance group identifier to use when requesting the log page.
+
+-E::
+--host-events::
+       Request the controller to report host events.
+
+-b::
+--raw-binary::
+       Print the raw buffer to the standard output stream.
+
+-o <format>::
+--output-format=<format>::
+       Set the reporting format to 'normal', 'json', or 'binary'. Only one
+       output format can be used at a time.
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-fdp-set-events.txt b/Documentation/nvme-fdp-set-events.txt
new file mode 100644 (file)
index 0000000..b45819b
--- /dev/null
@@ -0,0 +1,39 @@
+nvme-fdp-set-events(1)
+======================
+
+NAME
+----
+nvme-fdp-set-events - Enable or disable FDP events
+
+SYNOPSIS
+--------
+[verse]
+'nvme fdp set-events' <device> [--namespace-id=<NUM> | -n <NUM>]
+                              [--placement-handle=<NUM> | -p <NUM>]
+                              [--enable | -e]
+                              [--event-types=<NUM,> | -t <NUM,>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, enable or disable a list of event types from being
+generated for the Reclaim Unit Handle reference by the specified Placement
+Handle.
+
+OPTIONS
+-------
+-n <NUM>::
+--namespace-id=<NUM>::
+       Namespace identifier.
+
+-b::
+--raw-binary::
+       Print the raw buffer to the standard output stream.
+
+-o <format>::
+--output-format=<format>::
+       Set the reporting format to 'normal', 'json', or 'binary'. Only one
+       output format can be used at a time.
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-fdp-stats.txt b/Documentation/nvme-fdp-stats.txt
new file mode 100644 (file)
index 0000000..7f96065
--- /dev/null
@@ -0,0 +1,37 @@
+nvme-fdp-stats(1)
+=================
+
+NAME
+----
+nvme-fdp-stats - Get Flexible Data Placement Statistics
+
+SYNOPSIS
+--------
+[verse]
+'nvme fdp stats' <device> [--endgrp-id=<NUM> | -e <NUM>]
+                         [--raw-binary | -b]
+                         [--output-format=<FMT> | -o <FMT>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, provide information about the FDP configuration over
+the life of the FDP configuration in an Endurance Group.
+
+OPTIONS
+-------
+-e <NUM>::
+--endgrp-id=<NUM>::
+       The endurance group identifier to use when requesting the log page.
+
+-b::
+--raw-binary::
+       Print the raw buffer to the standard output stream.
+
+-o <format>::
+--output-format=<format>::
+       Set the reporting format to 'normal', 'json', or 'binary'. Only one
+       output format can be used at a time.
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-fdp-status.txt b/Documentation/nvme-fdp-status.txt
new file mode 100644 (file)
index 0000000..263cb4c
--- /dev/null
@@ -0,0 +1,37 @@
+nvme-fdp-status(1)
+==================
+
+NAME
+----
+nvme-fdp-status - Get Reclaim Unit Handle Status
+
+SYNOPSIS
+--------
+[verse]
+'nvme fdp status' <device> [--namespace-id=<NUM> | -n <NUM>]
+                          [--raw-binary | -b]
+                          [--output-format=<FMT> | -o <FMT>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, provide information about Reclaim Unit Handles that
+are accessible by the specified namespace.
+
+OPTIONS
+-------
+-n <NUM>::
+--namespace-id=<NUM>::
+       Namespace identifier.
+
+-b::
+--raw-binary::
+       Print the raw buffer to the standard output stream.
+
+-o <format>::
+--output-format=<format>::
+       Set the reporting format to 'normal', 'json', or 'binary'. Only one
+       output format can be used at a time.
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-fdp-update.txt b/Documentation/nvme-fdp-update.txt
new file mode 100644 (file)
index 0000000..4b70c24
--- /dev/null
@@ -0,0 +1,31 @@
+nvme-fdp-update(1)
+==================
+
+NAME
+----
+nvme-fdp-update - Reclaim Unit Handle Update
+
+SYNOPSIS
+--------
+[verse]
+'nvme fdp update' <device> [--namespace-id=<NUM> | -n <NUM>]
+                          [--pids=<NUM,> | -p <NUM,>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, update the given Placement Identifiers to reference
+a different Reclaim Unit accessible by the specified namespace.
+
+OPTIONS
+-------
+-n <NUM>::
+--namespace-id=<NUM>::
+       Namespace identifier.
+
+-p <NUM,>::
+--pids=<NUM,>::
+       Comma-separated list of placement identifiers to update.
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-fdp-usage.txt b/Documentation/nvme-fdp-usage.txt
new file mode 100644 (file)
index 0000000..ad9d1eb
--- /dev/null
@@ -0,0 +1,38 @@
+nvme-fdp-usage(1)
+=================
+
+NAME
+----
+nvme-fdp-usage - Get Reclaim Unit Handle Usage
+
+SYNOPSIS
+--------
+[verse]
+'nvme fdp usage' <device> [--endgrp-id=<NUM> | -e <NUM>]
+                         [--raw-binary | -b]
+                         [--output-format=<FMT> | -o <FMT>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, provide information about the Reclaim Unit Handles
+associated with the Placement Handles of the namespaces in the specified
+Endurance Group.
+
+OPTIONS
+-------
+-e <NUM>::
+--endgrp-id=<NUM>::
+       The endurance group identifier to use when requesting the log page.
+
+-b::
+--raw-binary::
+       Print the raw buffer to the standard output stream.
+
+-o <format>::
+--output-format=<format>::
+       Set the reporting format to 'normal', 'json', or 'binary'. Only one
+       output format can be used at a time.
+
+NVME
+----
+Part of nvme-cli
index 14a90a316976fdd6ed6e679e5998f72c2b4fa903..55423416d0d7fec3125e5e8e44c5890e85f31685 100644 (file)
@@ -2292,6 +2292,331 @@ static void json_supported_cap_config_log(
        json_free_object(root);
 }
 
+static void json_nvme_fdp_configs(struct nvme_fdp_config_log *log, size_t len)
+{
+       struct json_object *root, *obj_configs;
+       uint16_t n;
+
+       void *p = log->configs;
+
+       root = json_create_object();
+       obj_configs = json_create_array();
+
+       n = le16_to_cpu(log->n);
+
+       json_object_add_value_uint(root, "n", n);
+
+       for (int i = 0; i < n + 1; i++) {
+               struct nvme_fdp_config_desc *config = p;
+
+               struct json_object *obj_config = json_create_object();
+               struct json_object *obj_ruhs = json_create_array();
+
+               json_object_add_value_uint(obj_config, "fdpa", config->fdpa);
+               json_object_add_value_uint(obj_config, "vss", config->vss);
+               json_object_add_value_uint(obj_config, "nrg", le32_to_cpu(config->nrg));
+               json_object_add_value_uint(obj_config, "nruh", le16_to_cpu(config->nruh));
+               json_object_add_value_uint(obj_config, "nnss", le32_to_cpu(config->nnss));
+               json_object_add_value_uint(obj_config, "runs", le64_to_cpu(config->runs));
+               json_object_add_value_uint(obj_config, "erutl", le32_to_cpu(config->erutl));
+
+               for (int j = 0; j < le16_to_cpu(config->nruh); j++) {
+                       struct nvme_fdp_ruh_desc *ruh = &config->ruhs[j];
+
+                       struct json_object *obj_ruh = json_create_object();
+
+                       json_object_add_value_uint(obj_ruh, "ruht", ruh->ruht);
+
+                       json_array_add_value_object(obj_ruhs, obj_ruh);
+               }
+
+               json_array_add_value_object(obj_configs, obj_config);
+
+               p += config->size;
+       }
+
+       json_object_add_value_array(root, "configs", obj_configs);
+
+       json_print_object(root, NULL);
+       printf("\n");
+
+       json_free_object(root);
+}
+
+void nvme_show_fdp_config_fdpa(uint8_t fdpa)
+{
+       __u8 valid = (fdpa >> 7) & 0x1;
+       __u8 rsvd = (fdpa >> 5) >> 0x3;
+       __u8 fdpvwc = (fdpa >> 4) & 0x1;
+       __u8 rgif = fdpa & 0xf;
+
+       printf("  [7:7] : %#x\tFDP Configuration %sValid\n",
+               valid, valid ? "" : "Not ");
+       if (rsvd)
+               printf("  [6:5] : %#x\tReserved\n", rsvd);
+       printf("  [4:4] : %#x\tFDP Volatile Write Cache %sPresent\n",
+               fdpvwc, fdpvwc ? "" : "Not ");
+       printf("  [3:0] : %#x\tReclaim Group Identifier Format\n", rgif);
+}
+
+void nvme_show_fdp_configs(struct nvme_fdp_config_log *log, size_t len,
+               enum nvme_print_flags flags)
+{
+       void *p = log->configs;
+       int human = flags & VERBOSE;
+       uint16_t n;
+
+       if (flags & BINARY)
+               return d_raw((unsigned char *)log, len);
+       if (flags & JSON)
+               return json_nvme_fdp_configs(log, len);
+
+       n = le16_to_cpu(log->n) + 1;
+
+       for (int i = 0; i < n; i++) {
+               struct nvme_fdp_config_desc *config = p;
+
+               printf("FDP Attributes: %#x\n", config->fdpa);
+               if (human)
+                       nvme_show_fdp_config_fdpa(config->fdpa);
+
+               printf("Vendor Specific Size: %u\n", config->vss);
+               printf("Number of Reclaim Groups: %"PRIu32"\n", le32_to_cpu(config->nrg));
+               printf("Number of Reclaim Unit Handles: %"PRIu16"\n", le16_to_cpu(config->nruh));
+               printf("Number of Namespaces Supported: %"PRIu32"\n", le32_to_cpu(config->nnss));
+               printf("Reclaim Unit Nominal Size: %"PRIu64"\n", le64_to_cpu(config->runs));
+               printf("Estimated Reclaim Unit Time Limit: %"PRIu32"\n", le32_to_cpu(config->erutl));
+
+               printf("Reclaim Unit Handle List:\n");
+               for (int j = 0; j < le16_to_cpu(config->nruh); j++) {
+                       struct nvme_fdp_ruh_desc *ruh = &config->ruhs[j];
+
+                       printf("  [%d]: %s\n", j, ruh->ruht == NVME_FDP_RUHT_INITIALLY_ISOLATED ? "Initially Isolated" : "Persistently Isolated");
+               }
+
+               p += config->size;
+       }
+}
+
+static void json_nvme_fdp_usage(struct nvme_fdp_ruhu_log *log, size_t len)
+{
+       struct json_object *root, *obj_ruhus;
+       uint16_t nruh;
+
+       root = json_create_object();
+       obj_ruhus = json_create_array();
+
+       nruh = le16_to_cpu(log->nruh);
+
+       json_object_add_value_uint(root, "nruh", nruh);
+
+       for (int i = 0; i < nruh; i++) {
+               struct nvme_fdp_ruhu_desc *ruhu = &log->ruhus[i];
+
+               struct json_object *obj_ruhu = json_create_object();
+
+               json_object_add_value_uint(obj_ruhu, "ruha", ruhu->ruha);
+
+               json_array_add_value_object(obj_ruhus, obj_ruhu);
+       }
+
+       json_object_add_value_array(root, "ruhus", obj_ruhus);
+
+       json_print_object(root, NULL);
+       printf("\n");
+
+       json_free_object(root);
+}
+
+void nvme_show_fdp_usage(struct nvme_fdp_ruhu_log *log, size_t len,
+               enum nvme_print_flags flags)
+{
+       if (flags & BINARY)
+               return d_raw((unsigned char *)log, len);
+       if (flags & JSON)
+               return json_nvme_fdp_usage(log, len);
+
+       uint16_t nruh = le16_to_cpu(log->nruh);
+
+       for (int i = 0; i < nruh; i++) {
+               struct nvme_fdp_ruhu_desc *ruhu = &log->ruhus[i];
+
+               printf("Reclaim Unit Handle %d Attributes: 0x%"PRIx8" (%s)\n", i, ruhu->ruha,
+                               ruhu->ruha == 0x1 ? "Host Specified" : (
+                                       ruhu->ruha == 0x2 ? "Controller Specified" :
+                                       "Unknown"));
+       }
+}
+
+static void json_nvme_fdp_stats(struct nvme_fdp_stats_log *log)
+{
+       struct json_object *root = json_create_object();
+
+       json_object_add_value_uint128(root, "hbmw", le128_to_cpu(log->hbmw));
+       json_object_add_value_uint128(root, "mbmw", le128_to_cpu(log->mbmw));
+       json_object_add_value_uint128(root, "mbe", le128_to_cpu(log->mbe));
+
+       json_print_object(root, NULL);
+       printf("\n");
+
+       json_free_object(root);
+}
+
+void nvme_show_fdp_stats(struct nvme_fdp_stats_log *log,
+               enum nvme_print_flags flags)
+{
+       if (flags & BINARY)
+               return d_raw((unsigned char*)log, sizeof(*log));
+       if (flags & JSON)
+               return json_nvme_fdp_stats(log);
+
+       printf("Host Bytes with Metadata Written (HBMW): %s\n",
+               uint128_t_to_string(le128_to_cpu(log->hbmw)));
+       printf("Media Bytes with Metadata Written (MBMW): %s\n",
+               uint128_t_to_string(le128_to_cpu(log->mbmw)));
+       printf("Media Bytes Erased (MBE): %s\n",
+               uint128_t_to_string(le128_to_cpu(log->mbe)));
+}
+
+static void json_nvme_fdp_events(struct nvme_fdp_events_log *log)
+{
+       struct json_object *root, *obj_events;
+       uint32_t n;
+
+       root = json_create_object();
+       obj_events = json_create_array();
+
+       n = le32_to_cpu(log->n);
+
+       json_object_add_value_uint(root, "n", n);
+
+       for (unsigned int i = 0; i < n; i++) {
+               struct nvme_fdp_event *event = &log->events[i];
+
+               struct json_object *obj_event = json_create_object();
+
+               json_object_add_value_uint(obj_event, "type", event->type);
+               json_object_add_value_uint(obj_event, "fdpef", event->flags);
+               json_object_add_value_uint(obj_event, "pid", le16_to_cpu(event->pid));
+               json_object_add_value_uint(obj_event, "timestamp", le64_to_cpu(event->timestamp));
+               json_object_add_value_uint(obj_event, "nsid", le32_to_cpu(event->nsid));
+
+               if (event->type == NVME_FDP_EVENT_REALLOC) {
+                       struct nvme_fdp_event_realloc *mr;
+                       mr = (struct nvme_fdp_event_realloc *)&event->type_specific;
+
+                       json_object_add_value_uint(obj_event, "nlbam", le16_to_cpu(mr->nlbam));
+
+                       if (mr->flags & NVME_FDP_EVENT_REALLOC_F_LBAV)
+                               json_object_add_value_uint(obj_event, "lba", le64_to_cpu(mr->lba));
+               }
+
+               json_array_add_value_object(obj_events, obj_event);
+       }
+
+       json_object_add_value_array(root, "events", obj_events);
+
+       json_print_object(root, NULL);
+       printf("\n");
+
+       json_free_object(root);
+}
+
+void nvme_show_fdp_events(struct nvme_fdp_events_log *log,
+               enum nvme_print_flags flags)
+{
+       if (flags & BINARY)
+               return d_raw((unsigned char*)log, sizeof(*log));
+       if (flags & JSON)
+               return json_nvme_fdp_events(log);
+
+       uint32_t n = le32_to_cpu(log->n);
+
+       for (unsigned int i = 0; i < n; i++) {
+               struct nvme_fdp_event *event = &log->events[i];
+
+               printf("Event[%u]\n", i);
+               printf("  Event Type: 0x%"PRIx8"\n", event->type);
+               printf("  FDP Event Flags (FDPEF): 0x%"PRIx8"\n", event->flags);
+               printf("  Placement Identifier (PID): 0x%"PRIx16"\n", le16_to_cpu(event->pid));
+               printf("  Event Timestamp: %"PRIu64"\n", le64_to_cpu(event->timestamp));
+               printf("  Namespace Identifier (NSID): %"PRIu32"\n", le32_to_cpu(event->nsid));
+
+               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) {
+                               printf("  Logical Block Address (LBA): 0x%"PRIx64"\n", le64_to_cpu(mr->lba));
+                       }
+               }
+
+               printf("  Reclaim Group Identifier: %"PRIu16"\n", le16_to_cpu(event->rgid));
+               printf("  Reclaim Unit Handle Identifier %"PRIu8"\n", event->ruhid);
+
+               printf("\n");
+       }
+}
+
+static void json_nvme_fdp_ruh_status(struct nvme_fdp_ruh_status *status, size_t len)
+{
+       struct json_object *root, *obj_ruhss;
+       uint16_t nruhsd;
+
+       root = json_create_object();
+       obj_ruhss = json_create_array();
+
+       nruhsd = le16_to_cpu(status->nruhsd);
+
+       json_object_add_value_uint(root, "nruhsd", nruhsd);
+
+       for (unsigned int i = 0; i < nruhsd; i++) {
+               struct nvme_fdp_ruh_status_desc *ruhs = &status->ruhss[i];
+
+               struct json_object *obj_ruhs = json_create_object();
+
+               json_object_add_value_uint(obj_ruhs, "pid", le16_to_cpu(ruhs->pid));
+               json_object_add_value_uint(obj_ruhs, "ruhid", le16_to_cpu(ruhs->ruhid));
+               json_object_add_value_uint(obj_ruhs, "earutr", le32_to_cpu(ruhs->earutr));
+               json_object_add_value_uint(obj_ruhs, "ruamw", le64_to_cpu(ruhs->ruamw));
+
+               json_array_add_value_object(obj_ruhss, obj_ruhs);
+       }
+
+       json_object_add_value_array(root, "ruhss", obj_ruhss);
+
+       json_print_object(root, NULL);
+       printf("\n");
+
+       json_free_object(root);
+}
+
+void nvme_show_fdp_ruh_status(struct nvme_fdp_ruh_status *status, size_t len,
+               enum nvme_print_flags flags)
+{
+       if (flags & BINARY)
+               return d_raw((unsigned char *)status, len);
+       if (flags & JSON)
+               return json_nvme_fdp_ruh_status(status, len);
+
+       uint16_t nruhsd = le16_to_cpu(status->nruhsd);
+
+       for (unsigned int i = 0; i < nruhsd; i++) {
+               struct nvme_fdp_ruh_status_desc *ruhs = &status->ruhss[i];
+
+               printf("Placement Identifier %"PRIu16"; Reclaim Unit Handle Identifier %"PRIu16"\n",
+                               le16_to_cpu(ruhs->pid), le16_to_cpu(ruhs->ruhid));
+               printf("  Estimated Active Reclaim Unit Time Remaining (EARUTR): %"PRIu32"\n",
+                               le32_to_cpu(ruhs->earutr));
+               printf("  Reclaim Unit Available Media Writes (RUAMW): %"PRIu64"\n",
+                               le64_to_cpu(ruhs->ruamw));
+
+               printf("\n");
+       }
+}
+
 void nvme_show_supported_cap_config_log(
        struct nvme_supported_cap_config_list_log *cap,
        enum nvme_print_flags flags)
@@ -3352,7 +3677,9 @@ static void nvme_show_id_ctrl_oaes(__le32 ctrl_oaes)
 static void nvme_show_id_ctrl_ctratt(__le32 ctrl_ctratt)
 {
        __u32 ctratt = le32_to_cpu(ctrl_ctratt);
-       __u32 rsvd = ctratt >> 16;
+       __u32 rsvd20 = (ctratt >> 20);
+       __u32 fdps = (ctratt >> 19) & 0x1;
+       __u32 rsvd16 = (ctratt >> 16) & 0x7;
        __u32 elbas = (ctratt >> 15) & 0x1;
        __u32 delnvmset = (ctratt >> 14) & 0x1;
        __u32 delegrp = (ctratt >> 13) & 0x1;
@@ -3370,8 +3697,12 @@ static void nvme_show_id_ctrl_ctratt(__le32 ctrl_ctratt)
        __u32 sqa = (ctratt & NVME_CTRL_CTRATT_SQ_ASSOCIATIONS) >> 8;
        __u32 uuidlist = (ctratt & NVME_CTRL_CTRATT_UUID_LIST) >> 9;
 
-       if (rsvd)
-               printf(" [31:16] : %#x\tReserved\n", rsvd);
+       if (rsvd20)
+               printf(" [31:20] : %#x\tReserved\n", rsvd20);
+       printf("  [19:19] : %#x\tFlexible Data Placement %sSupported\n",
+               fdps, fdps ? "" : "Not ");
+       if (rsvd16)
+               printf("  [18:16] : %#x\tReserved\n", rsvd16);
        printf("  [15:15] : %#x\tExtended LBA Formats %sSupported\n",
                elbas, elbas ? "" : "Not ");
        printf("  [14:14] : %#x\tDelete NVM Set %sSupported\n",
@@ -6517,6 +6848,20 @@ void nvme_show_sanitize_log(struct nvme_sanitize_log_page *sanitize,
                le32_to_cpu(sanitize->etcend));
 }
 
+static const char *nvme_fdp_event_to_string(enum nvme_fdp_event_type event)
+{
+       switch (event) {
+       case NVME_FDP_EVENT_RUNFW:      return "Reclaim Unit Not Fully Written";
+       case NVME_FDP_EVENT_RUTLE:      return "Reclaim Unit Active Time Limit Exceeded";
+       case NVME_FDP_EVENT_RESET:      return "Controller Level Reset Modified Reclaim Unit Handles";
+       case NVME_FDP_EVENT_PID:        return "Invalid Placement Identifier";
+       case NVME_FDP_EVENT_REALLOC:    return "Media Reallocated";
+       case NVME_FDP_EVENT_MODIFY:     return "Implicitly Modified Reclaim Unit Handle";
+       }
+
+       return "Unknown";
+}
+
 const char *nvme_feature_to_string(enum nvme_features_id feature)
 {
        switch (feature) {
@@ -6554,6 +6899,8 @@ const char *nvme_feature_to_string(enum nvme_features_id feature)
        case NVME_FEAT_FID_RESV_MASK:   return "Reservation Notification Mask";
        case NVME_FEAT_FID_RESV_PERSIST:return "Reservation Persistence";
        case NVME_FEAT_FID_WRITE_PROTECT:       return "Namespace Write Protect";
+       case NVME_FEAT_FID_FDP:         return "Flexible Direct Placement";
+       case NVME_FEAT_FID_FDP_EVENTS:  return "Flexible Direct Placement Events";
        }
        /*
         * We don't use the "default:" statement to let the compiler warning if
@@ -7119,6 +7466,21 @@ void nvme_feature_show_fields(enum nvme_features_id fid, unsigned int result, un
        case NVME_FEAT_FID_WRITE_PROTECT:
                printf("\tNamespace Write Protect: %s\n", nvme_show_ns_wp_cfg(result));
                break;
+       case NVME_FEAT_FID_FDP:
+               printf("\tFlexible Direct Placement Enable (FDPE)       : %s\n",
+                               (result & 0x1) ? "Yes" : "No");
+               printf("\tFlexible Direct Placement Configuration Index : %u\n",
+                               (result >> 8) & 0xf);
+               break;
+       case NVME_FEAT_FID_FDP_EVENTS:
+               for (unsigned int i = 0; i < result; i++) {
+                       struct nvme_fdp_supported_event_desc *d;
+
+                       d = &((struct nvme_fdp_supported_event_desc *)buf)[i];
+
+                       printf("\t%-53s: %sEnabled\n", nvme_fdp_event_to_string(d->evt),
+                                       d->evta & 0x1 ? "" : "Not ");
+               }
        default:
                break;
        }
index f30f63eb1c86c87f95c1d203f3548430b9765fa3..35a9aa81cc4de15bdc44be39ed118ae660969a62 100644 (file)
@@ -132,6 +132,17 @@ void json_nvme_finish_zone_list(__u64 nr_zones,
        struct json_object *zone_list);
 void nvme_show_list_item(nvme_ns_t n);
 
+void nvme_show_fdp_configs(struct nvme_fdp_config_log *configs, size_t len,
+               enum nvme_print_flags flags);
+void nvme_show_fdp_stats(struct nvme_fdp_stats_log *log,
+               enum nvme_print_flags flags);
+void nvme_show_fdp_events(struct nvme_fdp_events_log *log,
+               enum nvme_print_flags flags);
+void nvme_show_fdp_usage(struct nvme_fdp_ruhu_log *log, size_t len,
+               enum nvme_print_flags flags);
+void nvme_show_fdp_ruh_status(struct nvme_fdp_ruh_status *status, size_t len,
+               enum nvme_print_flags flags);
+
 const char *nvme_cmd_to_string(int admin, __u8 opcode);
 const char *nvme_select_to_string(int sel);
 const char *nvme_feature_to_string(enum nvme_features_id feature);
diff --git a/nvme.c b/nvme.c
index 075a7347c10469ed6c30306c01505b40e7056626..b2cd5da50eaf2b4fa2329657c074f58154b93c43 100644 (file)
--- a/nvme.c
+++ b/nvme.c
@@ -75,6 +75,7 @@ struct feat_cfg {
        __u32 namespace_id;
        enum nvme_get_features_sel sel;
        __u32 cdw11;
+       __u32 cdw12;
        __u8  uuid_index;
        __u32 data_len;
        bool  raw_binary;
@@ -4282,6 +4283,11 @@ static int get_feature_id(struct nvme_dev *dev, struct feat_cfg *cfg,
        if (cfg->feature_id == NVME_FEAT_FID_HOST_ID && (cfg->cdw11 & 0x1))
                cfg->data_len = 16;
 
+       if (cfg->feature_id == NVME_FEAT_FID_FDP_EVENTS) {
+               cfg->data_len = 0xff * sizeof(__u16);
+               cfg->cdw11 |= 0xff << 16;
+       }
+
        if (cfg->sel == 3)
                cfg->data_len = 0;
 
@@ -4413,7 +4419,7 @@ static int get_feature(int argc, char **argv, struct command *cmd,
        const char *raw = "show feature in binary format";
        const char *feature_id = "feature identifier";
        const char *sel = "[0-3,8]: current/default/saved/supported/changed";
-       const char *cdw11 = "dword 11 for interrupt vector config";
+       const char *cdw11 = "feature specific dword 11";
        const char *human_readable = "show feature in readable format";
        struct nvme_dev *dev;
        int err;
diff --git a/plugins/fdp/fdp.c b/plugins/fdp/fdp.c
new file mode 100644 (file)
index 0000000..7802ab5
--- /dev/null
@@ -0,0 +1,537 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <linux/fs.h>
+#include <sys/stat.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "nvme-print.h"
+
+#define CREATE_CMD
+#include "fdp.h"
+
+static int fdp_configs(int argc, char **argv, struct command *cmd,
+               struct plugin *plugin)
+{
+       const char *desc = "Get Flexible Data Placement Configurations";
+       const char *egid = "Endurance group identifier";
+       const char *human_readable = "show log in readable format";
+       const char *raw = "use binary output";
+
+       enum nvme_print_flags flags;
+       struct nvme_dev *dev;
+       struct nvme_fdp_config_log hdr;
+       void *log = NULL;
+       int err;
+
+       struct config {
+               __u16   egid;
+               char    *output_format;
+               bool    human_readable;
+               bool    raw_binary;
+       };
+
+       struct config cfg = {
+               .egid           = 0,
+               .output_format  = "normal",
+               .raw_binary     = false,
+       };
+
+       OPT_ARGS(opts) = {
+               OPT_UINT("endgrp-id",      'e', &cfg.egid,           egid),
+               OPT_FMT("output-format",   'o', &cfg.output_format,  output_format),
+               OPT_FLAG("raw-binary",     'b', &cfg.raw_binary,     raw),
+               OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable),
+               OPT_END()
+       };
+
+       err = parse_and_open(&dev, argc, argv, desc, opts);
+       if (err)
+               return err;
+
+       err = flags = validate_output_format(cfg.output_format);
+       if (flags < 0)
+               goto out;
+
+       if (cfg.raw_binary)
+               flags = BINARY;
+
+       if (cfg.human_readable)
+               flags |= VERBOSE;
+
+       if (!cfg.egid) {
+               fprintf(stderr, "endurance group identifier required\n");
+               err = -EINVAL;
+               goto out;
+       }
+
+       err = nvme_get_log_fdp_configurations(dev->direct.fd, cfg.egid, 0,
+                       sizeof(hdr), &hdr);
+       if (err) {
+               nvme_show_status(errno);
+               goto out;
+       }
+
+       log = malloc(hdr.size);
+       if (!log) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       err = nvme_get_log_fdp_configurations(dev->direct.fd, cfg.egid, 0,
+                       hdr.size, log);
+       if (err) {
+               nvme_show_status(errno);
+               goto out;
+       }
+
+       nvme_show_fdp_configs(log, hdr.size, flags);
+
+out:
+       dev_close(dev);
+       free(log);
+
+       return err;
+}
+
+static int fdp_usage(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       const char *desc = "Get Flexible Data Placement Reclaim Unit Handle Usage";
+       const char *egid = "Endurance group identifier";
+       const char *raw = "use binary output";
+
+       enum nvme_print_flags flags;
+       struct nvme_dev *dev;
+       struct nvme_fdp_ruhu_log hdr;
+       size_t len;
+       void *log = NULL;
+       int err;
+
+       struct config {
+               __u16   egid;
+               char    *output_format;
+               bool    raw_binary;
+       };
+
+       struct config cfg = {
+               .egid      = 0,
+               .output_format  = "normal",
+               .raw_binary     = false,
+       };
+
+       OPT_ARGS(opts) = {
+               OPT_UINT("endgrp-id",    'e', &cfg.egid,          egid),
+               OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+               OPT_FLAG("raw-binary",   'b', &cfg.raw_binary,    raw),
+               OPT_END()
+       };
+
+       err = parse_and_open(&dev, argc, argv, desc, opts);
+       if (err)
+               return err;
+
+       err = flags = validate_output_format(cfg.output_format);
+       if (flags < 0)
+               goto out;
+
+       if (cfg.raw_binary)
+               flags = BINARY;
+
+       err = nvme_get_log_reclaim_unit_handle_usage(dev->direct.fd, cfg.egid,
+                       0, sizeof(hdr), &hdr);
+       if (err) {
+               nvme_show_status(err);
+               goto out;
+       }
+
+       len = sizeof(hdr) + le16_to_cpu(hdr.nruh) * sizeof(struct nvme_fdp_ruhu_desc);
+       log = malloc(len);
+       if (!log) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       err = nvme_get_log_reclaim_unit_handle_usage(dev->direct.fd, cfg.egid,
+                       0, len, log);
+       if (err) {
+               nvme_show_status(err);
+               goto out;
+       }
+
+       nvme_show_fdp_usage(log, len, flags);
+
+out:
+       dev_close(dev);
+       free(log);
+
+       return err;
+}
+
+static int fdp_stats(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       const char *desc = "Get Flexible Data Placement Statistics";
+       const char *egid = "Endurance group identifier";
+       const char *raw = "use binary output";
+
+       enum nvme_print_flags flags;
+       struct nvme_dev *dev;
+       struct nvme_fdp_stats_log stats;
+       int err;
+
+       struct config {
+               __u16   egid;
+               char    *output_format;
+               bool    raw_binary;
+       };
+
+       struct config cfg = {
+               .egid      = 0,
+               .output_format  = "normal",
+               .raw_binary     = false,
+       };
+
+       OPT_ARGS(opts) = {
+               OPT_UINT("endgrp-id",    'e', &cfg.egid,          egid),
+               OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+               OPT_FLAG("raw-binary",   'b', &cfg.raw_binary,    raw),
+               OPT_END()
+       };
+
+       err = parse_and_open(&dev, argc, argv, desc, opts);
+       if (err)
+               return err;
+
+       err = flags = validate_output_format(cfg.output_format);
+       if (flags < 0)
+               goto out;
+
+       if (cfg.raw_binary)
+               flags = BINARY;
+
+       memset(&stats, 0x0, sizeof(stats));
+
+       err = nvme_get_log_fdp_stats(dev->direct.fd, cfg.egid, 0, sizeof(stats), &stats);
+       if (err) {
+               nvme_show_status(err);
+               goto out;
+       }
+
+       nvme_show_fdp_stats(&stats, flags);
+
+out:
+       dev_close(dev);
+
+       return err;
+}
+
+static int fdp_events(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       const char *desc = "Get Flexible Data Placement Events";
+       const char *egid = "Endurance group identifier";
+       const char *host_events = "Get host events";
+       const char *raw = "use binary output";
+
+       enum nvme_print_flags flags;
+       struct nvme_dev *dev;
+       struct nvme_fdp_events_log events;
+       int err;
+
+       struct config {
+               __u16   egid;
+               bool    host_events;
+               char    *output_format;
+               bool    raw_binary;
+       };
+
+       struct config cfg = {
+               .egid      = 0,
+               .host_events = false,
+               .output_format  = "normal",
+               .raw_binary     = false,
+       };
+
+       OPT_ARGS(opts) = {
+               OPT_UINT("endgrp-id",    'e', &cfg.egid,          egid),
+               OPT_FLAG("host-events",  'H', &cfg.host_events,   host_events),
+               OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+               OPT_FLAG("raw-binary",   'b', &cfg.raw_binary,    raw),
+               OPT_END()
+       };
+
+       err = parse_and_open(&dev, argc, argv, desc, opts);
+       if (err)
+               return err;
+
+       err = flags = validate_output_format(cfg.output_format);
+       if (flags < 0)
+               goto out;
+
+       if (cfg.raw_binary)
+               flags = BINARY;
+
+       memset(&events, 0x0, sizeof(events));
+
+       err = nvme_get_log_fdp_events(dev->direct.fd, cfg.egid,
+                       cfg.host_events, 0, sizeof(events), &events);
+       if (err) {
+               nvme_show_status(err);
+               goto out;
+       }
+
+       nvme_show_fdp_events(&events, flags);
+
+out:
+       dev_close(dev);
+
+       return err;
+}
+
+static int fdp_status(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       const char *desc = "Reclaim Unit Handle Status";
+       const char *namespace_id = "Namespace identifier";
+       const char *raw = "use binary output";
+
+       enum nvme_print_flags flags;
+       struct nvme_dev *dev;
+       struct nvme_fdp_ruh_status hdr;
+       size_t len;
+       void *buf = NULL;
+       int err = -1;
+
+       struct config {
+               __u32   namespace_id;
+               char    *output_format;
+               bool    raw_binary;
+       };
+
+       struct config cfg = {
+               .output_format  = "normal",
+               .raw_binary     = false,
+       };
+
+       OPT_ARGS(opts) = {
+               OPT_UINT("namespace-id", 'n', &cfg.namespace_id,  namespace_id),
+               OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+               OPT_FLAG("raw-binary",   'b', &cfg.raw_binary,    raw),
+               OPT_END()
+       };
+
+       err = parse_and_open(&dev, argc, argv, desc, opts);
+       if (err)
+               return err;
+
+       err = flags = validate_output_format(cfg.output_format);
+       if (flags < 0)
+               goto out;
+
+       if (cfg.raw_binary)
+               flags = BINARY;
+
+       if (!cfg.namespace_id) {
+               err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+               if (err < 0) {
+                       perror("get-namespace-id");
+                       goto out;
+               }
+       }
+
+       err = nvme_fdp_reclaim_unit_handle_status(dev_fd(dev),
+                       cfg.namespace_id, sizeof(hdr), &hdr);
+       if (err) {
+               nvme_show_status(err);
+               goto out;
+       }
+
+       len = le16_to_cpu(hdr.nruhsd) * sizeof(struct nvme_fdp_ruh_status_desc);
+       buf = malloc(len);
+       if (!buf) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       err = nvme_fdp_reclaim_unit_handle_status(dev_fd(dev),
+                       cfg.namespace_id, len, buf);
+       if (err) {
+               nvme_show_status(err);
+               goto out;
+       }
+
+       nvme_show_fdp_ruh_status(buf, len, flags);
+
+out:
+       free(buf);
+       dev_close(dev);
+
+       return err;
+}
+
+static int fdp_update(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       const char *desc = "Reclaim Unit Handle Update";
+       const char *namespace_id = "Namespace identifier";
+       const char *_pids = "Comma-separated list of placement identifiers to update";
+
+       struct nvme_dev *dev;
+       unsigned short pids[256];
+       __u16 buf[256];
+       int npids;
+       int err = -1;
+
+       struct config {
+               __u32 namespace_id;
+               char *pids;
+       };
+
+       struct config cfg = {
+               .pids = "",
+       };
+
+       OPT_ARGS(opts) = {
+               OPT_UINT("namespace-id",  'n', &cfg.namespace_id,   namespace_id),
+               OPT_LIST("pids",          'p', &cfg.pids,           _pids),
+               OPT_END()
+       };
+
+       err = parse_and_open(&dev, argc, argv, desc, opts);
+       if (err)
+               return err;
+
+       npids = argconfig_parse_comma_sep_array_short(cfg.pids, pids, ARRAY_SIZE(pids));
+       if (npids < 0) {
+               perror("could not parse pids");
+               err = -EINVAL;
+               goto out;
+       } else if (npids == 0) {
+               fprintf(stderr, "no placement identifiers set\n");
+               err = -EINVAL;
+               goto out;
+       }
+
+       if (!cfg.namespace_id) {
+               err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+               if (err < 0) {
+                       perror("get-namespace-id");
+                       goto out;
+               }
+       }
+
+       for (unsigned int i = 0; i < npids; i++) {
+               buf[i] = cpu_to_le16(pids[i]);
+       }
+
+       err = nvme_fdp_reclaim_unit_handle_update(dev_fd(dev), cfg.namespace_id, npids, buf);
+       if (err) {
+               nvme_show_status(err);
+               goto out;
+       }
+
+       printf("update: Success\n");
+
+out:
+       dev_close(dev);
+
+       return err;
+}
+
+static int fdp_set_events(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       const char *desc = "Enable or disable FDP events";
+       const char *namespace_id = "Namespace identifier";
+       const char *enable = "Enable/disable event";
+       const char *event_types = "Comma-separated list of event types";
+       const char *ph = "Placement Handle";
+
+       struct nvme_dev *dev;
+       int err = -1;
+       unsigned short evts[255];
+       int nev;
+       __u8 buf[255];
+
+       struct config {
+               __u32   namespace_id;
+               __u16   ph;
+               char    *event_types;
+               bool    enable;
+       };
+
+       struct config cfg = {
+               .enable = false,
+       };
+
+       OPT_ARGS(opts) = {
+               OPT_UINT("namespace-id",     'n', &cfg.namespace_id, namespace_id),
+               OPT_SHRT("placement-handle", 'p', &cfg.ph,           ph),
+               OPT_FLAG("enable",           'e', &cfg.enable,       enable),
+               OPT_LIST("event-types",      't', &cfg.event_types,  event_types),
+               OPT_END()
+       };
+
+       err = parse_and_open(&dev, argc, argv, desc, opts);
+       if (err)
+               return err;
+
+       nev = argconfig_parse_comma_sep_array_short(cfg.event_types, evts, ARRAY_SIZE(evts));
+       if (nev < 0) {
+               perror("could not parse event types");
+               err = -EINVAL;
+               goto out;
+       } else if (nev == 0) {
+               fprintf(stderr, "no event types set\n");
+               err = -EINVAL;
+               goto out;
+       } else if (nev > 255) {
+               fprintf(stderr, "too many event types (max 255)\n");
+               err = -EINVAL;
+               goto out;
+       }
+
+       if (!cfg.namespace_id) {
+               err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+               if (err < 0) {
+                       if (errno != ENOTTY) {
+                               fprintf(stderr, "get-namespace-id: %s\n", nvme_strerror(errno));
+                               goto out;
+                       }
+
+                       cfg.namespace_id = NVME_NSID_ALL;
+               }
+       }
+
+       for (unsigned int i = 0; i < nev; i++) {
+               buf[i] = (__u8)evts[i];
+       }
+
+       struct nvme_set_features_args args = {
+               .args_size      = sizeof(args),
+               .fd             = dev_fd(dev),
+               .fid            = NVME_FEAT_FID_FDP_EVENTS,
+               .nsid           = cfg.namespace_id,
+               .cdw11          = (nev << 16) | cfg.ph,
+               .cdw12          = cfg.enable ? 0x1 : 0x0,
+               .data_len       = sizeof(buf),
+               .data           = buf,
+               .timeout        = NVME_DEFAULT_IOCTL_TIMEOUT,
+               .result         = NULL,
+       };
+
+       err = nvme_set_features(&args);
+       if (err) {
+               nvme_show_status(err);
+               goto out;
+       }
+
+       printf("set-events: Success\n");
+
+out:
+       dev_close(dev);
+
+       return err;
+}
diff --git a/plugins/fdp/fdp.h b/plugins/fdp/fdp.h
new file mode 100644 (file)
index 0000000..f162b32
--- /dev/null
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/fdp/fdp
+
+#if !defined(FDP_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define FDP_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("fdp", "Manage Flexible Data Placement enabled devices", NVME_VERSION),
+       COMMAND_LIST(
+               ENTRY("configs", "List configurations", fdp_configs)
+               ENTRY("usage", "Show reclaim unit handle usage", fdp_usage)
+               ENTRY("stats", "Show statistics", fdp_stats)
+               ENTRY("events", "List events affecting reclaim units and media usage", fdp_events)
+               ENTRY("status", "Show reclaim unit handle status", fdp_status)
+               ENTRY("update", "Update a reclaim unit handle", fdp_update)
+               ENTRY("set-events", "Enabled or disable events", fdp_set_events)
+       )
+);
+
+#endif
+
+#include "define_cmd.h"
index 52b7f4aea7b39b69fa6badc2843a09f00c722522..c92b2089b16d0f2db6fc086f781aeacb0610edde 100644 (file)
@@ -23,6 +23,7 @@ sources += [
   'plugins/ymtc/ymtc-nvme.c',
   'plugins/zns/zns.c',
   'plugins/inspur/inspur-nvme.c',
+  'plugins/fdp/fdp.c',
 ]
 subdir('solidigm')
 subdir('ocp')