Add relevant TP4146 ("Flexible Data Placement") management commands.
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
'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',
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
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)
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;
__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",
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) {
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
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;
}
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);
__u32 namespace_id;
enum nvme_get_features_sel sel;
__u32 cdw11;
+ __u32 cdw12;
__u8 uuid_index;
__u32 data_len;
bool raw_binary;
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;
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;
--- /dev/null
+// 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;
+}
--- /dev/null
+/* 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"
'plugins/ymtc/ymtc-nvme.c',
'plugins/zns/zns.c',
'plugins/inspur/inspur-nvme.c',
+ 'plugins/fdp/fdp.c',
]
subdir('solidigm')
subdir('ocp')