Merging upstream version 2.12.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
078c0dbcc0
commit
635faa7346
571 changed files with 10718 additions and 2738 deletions
|
@ -10,15 +10,59 @@
|
|||
#include "nvme.h"
|
||||
#include "libnvme.h"
|
||||
#include "plugin.h"
|
||||
#include "nvme-print.h"
|
||||
|
||||
#define CREATE_CMD
|
||||
#include "amzn-nvme.h"
|
||||
|
||||
#define AMZN_NVME_STATS_LOGPAGE_ID 0xD0
|
||||
#define AMZN_NVME_STATS_MAGIC 0x3C23B510
|
||||
|
||||
#define array_add_obj json_array_add_value_object
|
||||
#define obj_add_array json_object_add_value_array
|
||||
#define obj_add_obj json_object_add_value_object
|
||||
#define obj_add_uint json_object_add_value_uint
|
||||
#define obj_add_uint64 json_object_add_value_uint64
|
||||
|
||||
struct nvme_vu_id_ctrl_field {
|
||||
__u8 bdev[32];
|
||||
__u8 reserved0[992];
|
||||
};
|
||||
|
||||
struct amzn_latency_histogram_bin {
|
||||
__u64 lower;
|
||||
__u64 upper;
|
||||
__u32 count;
|
||||
__u32 reserved;
|
||||
} __packed;
|
||||
|
||||
struct amzn_latency_histogram {
|
||||
__u64 num_bins;
|
||||
struct amzn_latency_histogram_bin bins[64];
|
||||
} __packed;
|
||||
|
||||
struct amzn_latency_log_page {
|
||||
__u32 magic;
|
||||
__u32 reserved0;
|
||||
__u64 total_read_ops;
|
||||
__u64 total_write_ops;
|
||||
__u64 total_read_bytes;
|
||||
__u64 total_write_bytes;
|
||||
__u64 total_read_time;
|
||||
__u64 total_write_time;
|
||||
__u64 ebs_volume_performance_exceeded_iops;
|
||||
__u64 ebs_volume_performance_exceeded_tp;
|
||||
__u64 ec2_instance_ebs_performance_exceeded_iops;
|
||||
__u64 ec2_instance_ebs_performance_exceeded_tp;
|
||||
__u64 volume_queue_length;
|
||||
__u8 reserved1[416];
|
||||
|
||||
struct amzn_latency_histogram read_io_latency_histogram;
|
||||
struct amzn_latency_histogram write_io_latency_histogram;
|
||||
|
||||
__u8 reserved2[496];
|
||||
} __packed;
|
||||
|
||||
static void json_amzn_id_ctrl(struct nvme_vu_id_ctrl_field *id,
|
||||
char *bdev,
|
||||
struct json_object *root)
|
||||
|
@ -52,3 +96,180 @@ static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *pl
|
|||
{
|
||||
return __id_ctrl(argc, argv, cmd, plugin, amzn_id_ctrl);
|
||||
}
|
||||
|
||||
static void amzn_print_latency_histogram(struct amzn_latency_histogram *hist)
|
||||
{
|
||||
printf("=================================\n");
|
||||
printf("Lower Upper IO Count\n");
|
||||
printf("=================================\n");
|
||||
|
||||
for (int b = 0; b < hist->num_bins && b < 64; b++) {
|
||||
struct amzn_latency_histogram_bin *bin = &hist->bins[b];
|
||||
|
||||
printf("[%-8"PRIu64" - %-8"PRIu64"] => %-8u\n",
|
||||
(uint64_t)bin->lower, (uint64_t)bin->upper, bin->count);
|
||||
}
|
||||
|
||||
printf("=================================\n\n");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_JSONC
|
||||
static void amzn_json_add_histogram(struct json_object *root,
|
||||
struct amzn_latency_histogram *hist)
|
||||
{
|
||||
struct json_object *bins = json_create_array();
|
||||
|
||||
obj_add_uint64(root, "num_bins", hist->num_bins);
|
||||
obj_add_array(root, "bins", bins);
|
||||
|
||||
for (int b = 0; b < hist->num_bins && b < 64; b++) {
|
||||
struct amzn_latency_histogram_bin *bin = &hist->bins[b];
|
||||
struct json_object *json_bin = json_create_object();
|
||||
|
||||
obj_add_uint64(json_bin, "lower", bin->lower);
|
||||
obj_add_uint64(json_bin, "upper", bin->upper);
|
||||
obj_add_uint(json_bin, "count", bin->count);
|
||||
|
||||
array_add_obj(bins, json_bin);
|
||||
}
|
||||
}
|
||||
|
||||
static void amzn_print_json_stats(struct amzn_latency_log_page *log)
|
||||
{
|
||||
struct json_object *root = json_create_object();
|
||||
struct json_object *r_hist = json_create_object();
|
||||
struct json_object *w_hist = json_create_object();
|
||||
|
||||
obj_add_uint64(root, "total_read_ops", log->total_read_ops);
|
||||
obj_add_uint64(root, "total_write_ops", log->total_write_ops);
|
||||
obj_add_uint64(root, "total_read_bytes", log->total_read_bytes);
|
||||
obj_add_uint64(root, "total_write_bytes", log->total_write_bytes);
|
||||
obj_add_uint64(root, "total_read_time", log->total_read_time);
|
||||
obj_add_uint64(root, "total_write_time", log->total_write_time);
|
||||
obj_add_uint64(root, "ebs_volume_performance_exceeded_iops",
|
||||
log->ebs_volume_performance_exceeded_iops);
|
||||
obj_add_uint64(root, "ebs_volume_performance_exceeded_tp",
|
||||
log->ebs_volume_performance_exceeded_tp);
|
||||
obj_add_uint64(root,
|
||||
"ec2_instance_ebs_performance_exceeded_iops",
|
||||
log->ec2_instance_ebs_performance_exceeded_iops);
|
||||
obj_add_uint64(root, "ec2_instance_ebs_performance_exceeded_tp",
|
||||
log->ec2_instance_ebs_performance_exceeded_tp);
|
||||
obj_add_uint64(root, "volume_queue_length", log->volume_queue_length);
|
||||
|
||||
amzn_json_add_histogram(r_hist, &log->read_io_latency_histogram);
|
||||
obj_add_obj(root, "read_io_latency_histogram", r_hist);
|
||||
amzn_json_add_histogram(w_hist, &log->write_io_latency_histogram);
|
||||
obj_add_obj(root, "write_io_latency_histogram", w_hist);
|
||||
|
||||
json_print_object(root, NULL);
|
||||
printf("\n");
|
||||
|
||||
json_free_object(root);
|
||||
}
|
||||
#else /* CONFIG_JSONC */
|
||||
#define amzn_print_json_stats(log)
|
||||
#endif /* CONFIG_JSONC */
|
||||
|
||||
static void amzn_print_normal_stats(struct amzn_latency_log_page *log)
|
||||
{
|
||||
printf("Total Ops:\n");
|
||||
printf(" Read: %"PRIu64"\n", (uint64_t)log->total_read_ops);
|
||||
printf(" Write: %"PRIu64"\n", (uint64_t)log->total_write_ops);
|
||||
printf("Total Bytes:\n");
|
||||
printf(" Read: %"PRIu64"\n", (uint64_t)log->total_read_bytes);
|
||||
printf(" Write: %"PRIu64"\n", (uint64_t)log->total_write_bytes);
|
||||
printf("Total Time (us):\n");
|
||||
printf(" Read: %"PRIu64"\n", (uint64_t)log->total_read_time);
|
||||
printf(" Write: %"PRIu64"\n\n", (uint64_t)log->total_write_time);
|
||||
|
||||
printf("EBS Volume Performance Exceeded (us):\n");
|
||||
printf(" IOPS: %"PRIu64"\n", (uint64_t)log->ebs_volume_performance_exceeded_iops);
|
||||
printf(" Throughput: %"PRIu64"\n\n",
|
||||
(uint64_t)log->ebs_volume_performance_exceeded_tp);
|
||||
printf("EC2 Instance EBS Performance Exceeded (us):\n");
|
||||
printf(" IOPS: %"PRIu64"\n",
|
||||
(uint64_t)log->ec2_instance_ebs_performance_exceeded_iops);
|
||||
printf(" Throughput: %"PRIu64"\n\n",
|
||||
(uint64_t)log->ec2_instance_ebs_performance_exceeded_tp);
|
||||
|
||||
printf("Queue Length (point in time): %"PRIu64"\n\n",
|
||||
(uint64_t)log->volume_queue_length);
|
||||
|
||||
printf("Read IO Latency Histogram\n");
|
||||
amzn_print_latency_histogram(&log->read_io_latency_histogram);
|
||||
|
||||
printf("Write IO Latency Histogram\n");
|
||||
amzn_print_latency_histogram(&log->write_io_latency_histogram);
|
||||
}
|
||||
|
||||
static int get_stats(int argc, char **argv, struct command *cmd,
|
||||
struct plugin *plugin)
|
||||
{
|
||||
const char *desc = "display command latency statistics";
|
||||
struct nvme_dev *dev;
|
||||
struct amzn_latency_log_page log = { 0 };
|
||||
int rc;
|
||||
nvme_print_flags_t flags;
|
||||
int err;
|
||||
|
||||
struct config {
|
||||
char *output_format;
|
||||
};
|
||||
|
||||
struct config cfg = {
|
||||
.output_format = "normal",
|
||||
};
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
OPT_FMT("output-format", 'o', &cfg.output_format,
|
||||
"Output Format: normal|json"),
|
||||
OPT_END()};
|
||||
|
||||
rc = parse_and_open(&dev, argc, argv, desc, opts);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
struct nvme_get_log_args args = {
|
||||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.lid = AMZN_NVME_STATS_LOGPAGE_ID,
|
||||
.nsid = 1,
|
||||
.lpo = 0,
|
||||
.lsp = NVME_LOG_LSP_NONE,
|
||||
.lsi = 0,
|
||||
.rae = false,
|
||||
.uuidx = 0,
|
||||
.csi = NVME_CSI_NVM,
|
||||
.ot = false,
|
||||
.len = sizeof(log),
|
||||
.log = &log,
|
||||
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
|
||||
.result = NULL,
|
||||
};
|
||||
|
||||
rc = nvme_get_log(&args);
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "[ERROR] %s: Failed to get log page, rc = %d",
|
||||
__func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (log.magic != AMZN_NVME_STATS_MAGIC) {
|
||||
fprintf(stderr, "[ERROR] %s: Not an EBS device", __func__);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
err = validate_output_format(cfg.output_format, &flags);
|
||||
if (err < 0) {
|
||||
nvme_show_error("Invalid output format");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (flags & JSON)
|
||||
amzn_print_json_stats(&log);
|
||||
else
|
||||
amzn_print_normal_stats(&log);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
PLUGIN(NAME("amzn", "Amazon vendor specific extensions", NVME_VERSION),
|
||||
COMMAND_LIST(
|
||||
ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl)
|
||||
ENTRY("stats", "Get EBS volume stats", get_stats)
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -505,7 +505,9 @@ static int dapustor_additional_smart_log(int argc, char **argv, struct command *
|
|||
const char *desc = "Get DapuStor vendor specific additional smart log, and show it.";
|
||||
const char *namespace = "(optional) desired namespace";
|
||||
const char *raw = "Dump output in binary format";
|
||||
#ifdef CONFIG_JSONC
|
||||
const char *json = "Dump output in json format";
|
||||
#endif /* CONFIG_JSONC */
|
||||
|
||||
struct nvme_additional_smart_log smart_log;
|
||||
struct nvme_extended_additional_smart_log ext_smart_log;
|
||||
|
@ -526,7 +528,7 @@ static int dapustor_additional_smart_log(int argc, char **argv, struct command *
|
|||
OPT_ARGS(opts) = {
|
||||
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace),
|
||||
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
|
||||
OPT_FLAG("json", 'j', &cfg.json, json),
|
||||
OPT_FLAG_JSON("json", 'j', &cfg.json, json),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
|
|
|
@ -215,6 +215,12 @@ static int fdp_stats(int argc, char **argv, struct command *cmd, struct plugin *
|
|||
if (cfg.raw_binary)
|
||||
flags = BINARY;
|
||||
|
||||
if (!cfg.egid) {
|
||||
fprintf(stderr, "endurance group identifier required\n");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(&stats, 0x0, sizeof(stats));
|
||||
|
||||
err = nvme_get_log_fdp_stats(dev->direct.fd, cfg.egid, 0, sizeof(stats), &stats);
|
||||
|
@ -276,6 +282,12 @@ static int fdp_events(int argc, char **argv, struct command *cmd, struct plugin
|
|||
if (cfg.raw_binary)
|
||||
flags = BINARY;
|
||||
|
||||
if (!cfg.egid) {
|
||||
fprintf(stderr, "endurance group identifier required\n");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(&events, 0x0, sizeof(events));
|
||||
|
||||
err = nvme_get_log_fdp_events(dev->direct.fd, cfg.egid,
|
||||
|
@ -539,3 +551,99 @@ out:
|
|||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int fdp_feature(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
||||
{
|
||||
const char *desc = "Show, enable or disable FDP configuration";
|
||||
const char *enable_conf_idx = "FDP configuration index to enable";
|
||||
const char *endurance_group = "Endurance group ID";
|
||||
const char *disable = "Disable current FDP configuration";
|
||||
|
||||
_cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
|
||||
int err = -1;
|
||||
__u32 result;
|
||||
bool enabling_conf_idx = false;
|
||||
struct nvme_set_features_args setf_args = {
|
||||
.args_size = sizeof(setf_args),
|
||||
.fd = -1,
|
||||
.fid = NVME_FEAT_FID_FDP,
|
||||
.save = 1,
|
||||
.nsid = NVME_NSID_ALL,
|
||||
.data_len = 0,
|
||||
.data = NULL,
|
||||
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
|
||||
};
|
||||
|
||||
struct config {
|
||||
bool disable;
|
||||
__u8 fdpcidx;
|
||||
__u16 endgid;
|
||||
};
|
||||
|
||||
struct config cfg = {
|
||||
.disable = false,
|
||||
.fdpcidx = 0,
|
||||
.endgid = 0,
|
||||
};
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
OPT_SHRT("endgrp-id", 'e', &cfg.endgid, endurance_group),
|
||||
OPT_BYTE("enable-conf-idx", 'c', &cfg.fdpcidx, enable_conf_idx),
|
||||
OPT_FLAG("disable", 'd', &cfg.disable, disable),
|
||||
OPT_INCR("verbose", 'v', &nvme_cfg.verbose, verbose),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
err = parse_and_open(&dev, argc, argv, desc, opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
enabling_conf_idx = argconfig_parse_seen(opts, "enable-conf-idx");
|
||||
if (enabling_conf_idx && cfg.disable) {
|
||||
nvme_show_error("Cannot enable and disable at the same time");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!enabling_conf_idx && !cfg.disable) {
|
||||
struct nvme_get_features_args getf_args = {
|
||||
.args_size = sizeof(getf_args),
|
||||
.fd = dev_fd(dev),
|
||||
.fid = NVME_FEAT_FID_FDP,
|
||||
.nsid = NVME_NSID_ALL,
|
||||
.sel = NVME_GET_FEATURES_SEL_CURRENT,
|
||||
.cdw11 = cfg.endgid,
|
||||
.uuidx = 0,
|
||||
.data_len = 0,
|
||||
.data = NULL,
|
||||
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
|
||||
.result = &result,
|
||||
};
|
||||
|
||||
nvme_show_result("Endurance Group : %d", cfg.endgid);
|
||||
|
||||
err = nvme_get_features(&getf_args);
|
||||
if (err) {
|
||||
nvme_show_status(err);
|
||||
return err;
|
||||
}
|
||||
|
||||
nvme_show_result("Flexible Direct Placement Enable (FDPE) : %s",
|
||||
(result & 0x1) ? "Yes" : "No");
|
||||
nvme_show_result("Flexible Direct Placement Configuration Index : %u",
|
||||
(result >> 8) & 0xf);
|
||||
return err;
|
||||
}
|
||||
|
||||
setf_args.fd = dev_fd(dev);
|
||||
setf_args.cdw11 = cfg.endgid;
|
||||
setf_args.cdw12 = cfg.fdpcidx << 8 | (!cfg.disable);
|
||||
|
||||
err = nvme_set_features(&setf_args);
|
||||
if (err) {
|
||||
nvme_show_status(err);
|
||||
return err;
|
||||
}
|
||||
nvme_show_result("Success %s Endurance Group: %d, FDP configuration index: %d",
|
||||
(cfg.disable) ? "disabling" : "enabling", cfg.endgid, cfg.fdpcidx);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,8 @@ PLUGIN(NAME("fdp", "Manage Flexible Data Placement enabled devices", NVME_VERSIO
|
|||
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)
|
||||
ENTRY("set-events", "Enable or disable events", fdp_set_events)
|
||||
ENTRY("feature", "Show, enable or disable FDP configuration", fdp_feature)
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -117,6 +117,7 @@ static int huawei_get_nvme_info(int fd, struct huawei_list_item *item, const cha
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_JSONC
|
||||
static void format(char *formatter, size_t fmt_sz, char *tofmt, size_t tofmtsz)
|
||||
{
|
||||
fmt_sz = snprintf(formatter, fmt_sz, "%-*.*s", (int)tofmtsz, (int)tofmtsz, tofmt);
|
||||
|
@ -177,6 +178,7 @@ static void huawei_json_print_list_items(struct huawei_list_item *list_items,
|
|||
printf("\n");
|
||||
json_free_object(root);
|
||||
}
|
||||
#endif /* CONFIG_JSONC */
|
||||
|
||||
static void huawei_print_list_head(struct huawei_list_element_len element_len)
|
||||
{
|
||||
|
@ -351,9 +353,11 @@ static int huawei_list(int argc, char **argv, struct command *command,
|
|||
}
|
||||
|
||||
if (huawei_num > 0) {
|
||||
#ifdef CONFIG_JSONC
|
||||
if (fmt == JSON)
|
||||
huawei_json_print_list_items(list_items, huawei_num);
|
||||
else
|
||||
#endif /* CONFIG_JSONC */
|
||||
huawei_print_list_items(list_items, huawei_num);
|
||||
}
|
||||
out_free_list_items:
|
||||
|
|
|
@ -336,7 +336,9 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
|
|||
"Get Intel vendor specific additional smart log (optionally, for the specified namespace), and show it.";
|
||||
const char *namespace = "(optional) desired namespace";
|
||||
const char *raw = "Dump output in binary format";
|
||||
#ifdef CONFIG_JSONC
|
||||
const char *json = "Dump output in json format";
|
||||
#endif /* CONFIG_JSONC */
|
||||
|
||||
struct nvme_additional_smart_log smart_log;
|
||||
struct nvme_dev *dev;
|
||||
|
@ -355,7 +357,7 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
|
|||
OPT_ARGS(opts) = {
|
||||
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace),
|
||||
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
|
||||
OPT_FLAG("json", 'j', &cfg.json, json),
|
||||
OPT_FLAG_JSON("json", 'j', &cfg.json, json),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
|
@ -1032,7 +1034,9 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct
|
|||
|
||||
const char *desc = "Get Intel Latency Statistics log and show it.";
|
||||
const char *raw = "Dump output in binary format";
|
||||
#ifdef CONFIG_JSONC
|
||||
const char *json = "Dump output in json format";
|
||||
#endif /* CONFIG_JSONC */
|
||||
const char *write = "Get write statistics (read default)";
|
||||
|
||||
struct config {
|
||||
|
@ -1047,7 +1051,7 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct
|
|||
OPT_ARGS(opts) = {
|
||||
OPT_FLAG("write", 'w', &cfg.write, write),
|
||||
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
|
||||
OPT_FLAG("json", 'j', &cfg.json, json),
|
||||
OPT_FLAG_JSON("json", 'j', &cfg.json, json),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
|
|
669
plugins/lm/lm-nvme.c
Normal file
669
plugins/lm/lm-nvme.c
Normal file
|
@ -0,0 +1,669 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2024 Samsung Electronics Co., LTD.
|
||||
*
|
||||
* Authors: Nate Thornton <n.thornton@samsung.com>
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/fs.h>
|
||||
#include <inttypes.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "nvme.h"
|
||||
#include "nvme-print.h"
|
||||
#include "libnvme.h"
|
||||
#include "plugin.h"
|
||||
#include "linux/types.h"
|
||||
#include "nvme-wrap.h"
|
||||
#include "util/cleanup.h"
|
||||
|
||||
#define CREATE_CMD
|
||||
#include "lm-nvme.h"
|
||||
|
||||
#include "lm-print.h"
|
||||
|
||||
static inline const char *arg_str(const char * const *strings, size_t array_size, size_t idx)
|
||||
{
|
||||
if (idx < array_size && strings[idx])
|
||||
return strings[idx];
|
||||
return "unrecognized";
|
||||
}
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
#define ARGSTR(s, i) arg_str(s, ARRAY_SIZE(s), i)
|
||||
|
||||
static int lm_create_cdq(int argc, char **argv, struct command *command, struct plugin *plugin)
|
||||
{
|
||||
const char *desc = "Create Controller Data Queue for controller of specific type and size";
|
||||
const char *sz = "CDQ Size (in dwords)";
|
||||
const char *cntlid = "Controller ID";
|
||||
const char *qt = "Queue Type (default: 0 = User Data Migration Queue)";
|
||||
const char *consent = "I consent this will not work and understand a CDQ cannot be mapped "
|
||||
"to user space. If I proceed with the creation of a CDQ, the device "
|
||||
"will write to invalid memory, inevitably leading to MMU faults or "
|
||||
"worse.";
|
||||
|
||||
_cleanup_huge_ struct nvme_mem_huge mh = { 0, };
|
||||
_cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
|
||||
struct lba_migration_queue_entry_type_0 *queue = NULL;
|
||||
int err = -1;
|
||||
|
||||
struct config {
|
||||
__u32 sz;
|
||||
__u16 cntlid;
|
||||
__u8 qt;
|
||||
bool consent;
|
||||
char *file;
|
||||
};
|
||||
|
||||
struct config cfg = {
|
||||
.sz = 0,
|
||||
.cntlid = 0,
|
||||
.qt = 0,
|
||||
.consent = false,
|
||||
.file = NULL,
|
||||
};
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
OPT_UINT("size", 's', &cfg.sz, sz),
|
||||
OPT_SHRT("cntlid", 'c', &cfg.cntlid, cntlid),
|
||||
OPT_BYTE("queue-type", 'q', &cfg.qt, qt),
|
||||
OPT_FLAG("consent", 0, &cfg.consent, consent),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
err = parse_and_open(&dev, argc, argv, desc, opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!consent) {
|
||||
nvme_show_error("ERROR: consent required");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// Not that it really matters, but we setup memory as if the CDQ can be held
|
||||
// in user space regardless.
|
||||
queue = nvme_alloc_huge(cfg.sz << 2, &mh);
|
||||
if (!queue) {
|
||||
nvme_show_error("ERROR: nvme_alloc of size %dB failed %s", cfg.sz << 2,
|
||||
strerror(errno));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
struct nvme_lm_cdq_args args = {
|
||||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.sel = NVME_LM_SEL_CREATE_CDQ,
|
||||
.mos = NVME_SET(cfg.qt, LM_QT),
|
||||
.cntlid = cfg.cntlid,
|
||||
.sz = cfg.sz,
|
||||
.data = queue
|
||||
};
|
||||
|
||||
err = nvme_lm_cdq(&args);
|
||||
if (err < 0)
|
||||
nvme_show_error("ERROR: nvme_lm_cdq() failed: %s", nvme_strerror(errno));
|
||||
else if (err)
|
||||
nvme_show_status(err);
|
||||
else
|
||||
printf("Create CDQ Successful: CDQID=0x%04x\n", args.cdqid);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int lm_delete_cdq(int argc, char **argv, struct command *command, struct plugin *plugin)
|
||||
{
|
||||
const char *desc = "Delete Controller Data Queue";
|
||||
const char *cdqid = "Controller Data Queue ID";
|
||||
|
||||
_cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
|
||||
int err = -1;
|
||||
|
||||
struct config {
|
||||
__u16 cdqid;
|
||||
};
|
||||
|
||||
struct config cfg = {
|
||||
.cdqid = 0
|
||||
};
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
OPT_SHRT("cdqid", 'C', &cfg.cdqid, cdqid),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
err = parse_and_open(&dev, argc, argv, desc, opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
struct nvme_lm_cdq_args args = {
|
||||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.sel = NVME_LM_SEL_DELETE_CDQ,
|
||||
.cdqid = cfg.cdqid,
|
||||
};
|
||||
|
||||
err = nvme_lm_cdq(&args);
|
||||
if (err < 0)
|
||||
nvme_show_error("ERROR: nvme_lm_cdq() failed: %s", nvme_strerror(errno));
|
||||
else if (err > 0)
|
||||
nvme_show_status(err);
|
||||
else
|
||||
printf("Delete CDQ Successful: CDQID=0x%04x\n", cfg.cdqid);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const char * const lm_track_send_select_argstr[] = {
|
||||
[NVME_LM_SEL_LOG_USER_DATA_CHANGES] = "Log User Data Changes",
|
||||
[NVME_LM_SEL_TRACK_MEMORY_CHANGES] = "Track Memory Changes"
|
||||
};
|
||||
|
||||
static int lm_track_send(int argc, char **argv, struct command *command, struct plugin *plugin)
|
||||
{
|
||||
const char *desc = "Track Send command used to manage the tracking of information by a "
|
||||
"controller";
|
||||
const char *sel = "Type of management operation to perform\n"
|
||||
" 0h = Log User Data Changes\n"
|
||||
" 1h = Track Memory Changes";
|
||||
const char *mos = "Management operation specific";
|
||||
const char *cdqid = "Controller Data Queue ID";
|
||||
const char *start = "Equivalent to start tracking with defaults";
|
||||
const char *stop = "Equivalent to stop tracking with defaults";
|
||||
|
||||
|
||||
_cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
|
||||
int err = -1;
|
||||
|
||||
struct config {
|
||||
__s8 sel;
|
||||
__u8 mos;
|
||||
__u16 cdqid;
|
||||
bool start;
|
||||
bool stop;
|
||||
};
|
||||
|
||||
struct config cfg = {
|
||||
.sel = -1,
|
||||
.mos = 0,
|
||||
.cdqid = 0,
|
||||
.start = false,
|
||||
.stop = false,
|
||||
};
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
OPT_BYTE("sel", 's', &cfg.sel, sel),
|
||||
OPT_BYTE("mos", 'm', &cfg.mos, mos),
|
||||
OPT_SHRT("cdqid", 'C', &cfg.cdqid, cdqid),
|
||||
OPT_FLAG("start", 0, &cfg.start, start),
|
||||
OPT_FLAG("stop", 0, &cfg.stop, stop),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
err = parse_and_open(&dev, argc, argv, desc, opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (cfg.sel == -1) {
|
||||
nvme_show_error("Select field required");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (cfg.sel != NVME_LM_SEL_LOG_USER_DATA_CHANGES) {
|
||||
nvme_show_error("Unsupported select option %d (%s)", cfg.sel,
|
||||
ARGSTR(lm_track_send_select_argstr, cfg.sel));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (cfg.start && cfg.stop) {
|
||||
nvme_show_error("Must select one of start & stop, not both");
|
||||
return -EINVAL;
|
||||
} else if (cfg.sel == NVME_LM_SEL_LOG_USER_DATA_CHANGES) {
|
||||
if (cfg.start)
|
||||
cfg.mos = NVME_SET(NVME_LM_LACT_START_LOGGING, LM_LACT);
|
||||
else if (cfg.stop)
|
||||
cfg.mos = NVME_SET(NVME_LM_LACT_STOP_LOGGING, LM_LACT);
|
||||
}
|
||||
|
||||
struct nvme_lm_track_send_args args = {
|
||||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.cdqid = cfg.cdqid,
|
||||
.sel = cfg.sel,
|
||||
.mos = cfg.mos,
|
||||
};
|
||||
|
||||
err = nvme_lm_track_send(&args);
|
||||
if (err < 0)
|
||||
nvme_show_error("ERROR: nvme_lm_track_send() failed %s", strerror(errno));
|
||||
else if (err)
|
||||
nvme_show_status(err);
|
||||
else
|
||||
printf("Track Send (%s) Successful\n",
|
||||
ARGSTR(lm_track_send_select_argstr, cfg.sel));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const char * const lm_migration_send_select_argstr[] = {
|
||||
[NVME_LM_SEL_SUSPEND] = "Suspend",
|
||||
[NVME_LM_SEL_RESUME] = "Resume",
|
||||
[NVME_LM_SEL_SET_CONTROLLER_STATE] = "Set Controller State"
|
||||
};
|
||||
|
||||
static int lm_migration_send(int argc, char **argv, struct command *command, struct plugin *plugin)
|
||||
{
|
||||
const char *desc = "Migration Send command is used to manage the migration of a controller";
|
||||
const char *sel = "Select (SEL) the type of management operation to perform "
|
||||
"(CDW10[07:00])\n"
|
||||
" 0h = Suspend\n"
|
||||
" 1h = Resume\n"
|
||||
" 2h = Set Controller State";
|
||||
const char *cntlid = "Controller Identifier (CDW11[15:00])";
|
||||
const char *stype = "Type of suspend (STYPE) (CDW11[23:16]\n"
|
||||
" 0h = Suspend Notification\n"
|
||||
" 1h = Suspend";
|
||||
const char *dudmq = "Delete user data migration queue (DUDMQ) as part of suspend operation "
|
||||
"(CDW11[31])";
|
||||
const char *seqind = "Sequence Indicator (CDW11[17:16])\n"
|
||||
" 0h = Not first not last\n"
|
||||
" 1h = First in two or more\n"
|
||||
" 2h = Last in two or more\n"
|
||||
" 3h = Entire state info";
|
||||
const char *csuuidi = "Controller State UUID Index (CSUUIDI) (CDW11[31:24])";
|
||||
const char *csvi = "Controller State Version Index (CSVI) (CDW11[23:16])";
|
||||
const char *uidx = "UUID Index (UIDX) (CDW14[16:00])";
|
||||
const char *offset = "Controller State Offset";
|
||||
const char *numd = "Number of Dwords (NUMD)";
|
||||
const char *input = "Controller State Data input file";
|
||||
|
||||
_cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
|
||||
_cleanup_file_ FILE *file = NULL;
|
||||
_cleanup_huge_ struct nvme_mem_huge mh = { 0, };
|
||||
void *data = NULL;
|
||||
int err = -1;
|
||||
|
||||
struct config {
|
||||
__s8 sel;
|
||||
__u16 cntlid;
|
||||
__u8 stype;
|
||||
__u8 seqind;
|
||||
__u8 csuuidi;
|
||||
__u8 csvi;
|
||||
__u8 uidx;
|
||||
__u64 offset;
|
||||
__u32 numd;
|
||||
char *input;
|
||||
bool dudmq;
|
||||
};
|
||||
|
||||
struct config cfg = {
|
||||
.sel = -1,
|
||||
.cntlid = 0,
|
||||
.stype = 0,
|
||||
.seqind = 0,
|
||||
.csuuidi = 0,
|
||||
.csvi = 0,
|
||||
.uidx = 0,
|
||||
.offset = 0,
|
||||
.numd = 0,
|
||||
.input = NULL,
|
||||
.dudmq = false
|
||||
};
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
OPT_BYTE("sel", 's', &cfg.sel, sel),
|
||||
OPT_SHRT("cntlid", 'c', &cfg.cntlid, cntlid),
|
||||
OPT_BYTE("stype", 't', &cfg.stype, stype),
|
||||
OPT_FLAG("dudmq", 'd', &cfg.dudmq, dudmq),
|
||||
OPT_BYTE("seq-ind", 'S', &cfg.seqind, seqind),
|
||||
OPT_BYTE("csuuidi", 'U', &cfg.csuuidi, csuuidi),
|
||||
OPT_BYTE("csvi", 'V', &cfg.csvi, csvi),
|
||||
OPT_BYTE("uidx", 'u', &cfg.uidx, uidx),
|
||||
OPT_LONG("offset", 'o', &cfg.offset, offset),
|
||||
OPT_UINT("numd", 'n', &cfg.numd, numd),
|
||||
OPT_FILE("input-file", 'f', &cfg.input, input),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
err = parse_and_open(&dev, argc, argv, desc, opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (cfg.sel == -1) {
|
||||
nvme_show_error("Select field required");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// Sanity check input parameters
|
||||
if (cfg.sel == NVME_LM_SEL_SUSPEND || cfg.sel == NVME_LM_SEL_RESUME) {
|
||||
if (cfg.csuuidi != 0 || cfg.csvi != 0) {
|
||||
nvme_show_error("Unexpected fields for %s",
|
||||
ARGSTR(lm_migration_send_select_argstr, cfg.sel));
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (cfg.sel == NVME_LM_SEL_SET_CONTROLLER_STATE) {
|
||||
if (cfg.dudmq || cfg.stype != 0) {
|
||||
nvme_show_error("Unexpected fields for %s",
|
||||
ARGSTR(lm_migration_send_select_argstr, cfg.sel));
|
||||
return -EINVAL;
|
||||
} else if (!strlen(cfg.input)) {
|
||||
nvme_show_error("Expected file for %s",
|
||||
ARGSTR(lm_migration_send_select_argstr, cfg.sel));
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.input && strlen(cfg.input)) {
|
||||
file = fopen(cfg.input, "r");
|
||||
if (file == NULL) {
|
||||
nvme_show_perror(cfg.input);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
data = nvme_alloc_huge(cfg.numd << 2, &mh);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
size_t n_data = fread(data, 1, cfg.numd << 2, file);
|
||||
|
||||
fclose(file);
|
||||
|
||||
if (n_data != (size_t)(cfg.numd << 2)) {
|
||||
nvme_show_error("failed to read controller state data %s", strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
struct nvme_lm_migration_send_args args = {
|
||||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.sel = cfg.sel,
|
||||
.mos = NVME_SET(cfg.seqind, LM_MIGRATION_SEND_MOS),
|
||||
.cntlid = cfg.cntlid,
|
||||
.csuuidi = cfg.csuuidi,
|
||||
.uidx = cfg.uidx,
|
||||
.stype = cfg.stype,
|
||||
.offset = cfg.offset,
|
||||
.dudmq = cfg.dudmq,
|
||||
.numd = cfg.numd,
|
||||
.data = data,
|
||||
};
|
||||
|
||||
err = nvme_lm_migration_send(&args);
|
||||
if (err < 0)
|
||||
nvme_show_error("ERROR: nvme_lm_migration_send() failed %s", strerror(errno));
|
||||
else if (err > 0)
|
||||
nvme_show_status(err);
|
||||
else
|
||||
printf("Migration Send (%s) Successful\n",
|
||||
ARGSTR(lm_migration_send_select_argstr, cfg.sel));
|
||||
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int lm_migration_recv(int argc, char **argv, struct command *command, struct plugin *plugin)
|
||||
{
|
||||
const char *desc = "Migration Receive command is used to obtain information used to manage "
|
||||
" a migratable controller";
|
||||
const char *sel = "Select (SEL) the type of management operation to perform "
|
||||
"(CDW10[07:00])\n"
|
||||
" 0h = Get Controller State";
|
||||
const char *cntlid = "Controller Identifier (CDW10[31:16])";
|
||||
const char *csuuidi = "Controller State UUID Index (CSUUIDI) (CDW11[23:16])";
|
||||
const char *csvi = "Controller State Version Index (CSVI) (CDW11[7:0])";
|
||||
const char *uidx = "UUID Index (UIDX) (CDW14[16:00])";
|
||||
const char *offset = "Controller State Offset";
|
||||
const char *numd = "Number of Dwords (NUMD)";
|
||||
const char *output = "Controller State Data output file";
|
||||
const char *human_readable_info = "show info in readable format";
|
||||
|
||||
_cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
|
||||
_cleanup_file_ FILE *fd = NULL;
|
||||
_cleanup_huge_ struct nvme_mem_huge mh = { 0, };
|
||||
nvme_print_flags_t flags;
|
||||
void *data = NULL;
|
||||
int err = -1;
|
||||
|
||||
struct config {
|
||||
__u8 sel;
|
||||
__u16 cntlid;
|
||||
__u8 csuuidi;
|
||||
__u8 csvi;
|
||||
__u8 uidx;
|
||||
__u64 offset;
|
||||
__u32 numd;
|
||||
char *output;
|
||||
char *output_format;
|
||||
bool human_readable;
|
||||
};
|
||||
|
||||
struct config cfg = {
|
||||
.sel = -1,
|
||||
.cntlid = 0,
|
||||
.csuuidi = 0,
|
||||
.csvi = 0,
|
||||
.uidx = 0,
|
||||
.offset = 0,
|
||||
.numd = 0,
|
||||
.output = NULL,
|
||||
.output_format = "normal",
|
||||
.human_readable = false
|
||||
};
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
OPT_BYTE("sel", 's', &cfg.sel, sel),
|
||||
OPT_SHRT("cntlid", 'c', &cfg.cntlid, cntlid),
|
||||
OPT_BYTE("csuuidi", 'U', &cfg.csuuidi, csuuidi),
|
||||
OPT_BYTE("csvi", 'V', &cfg.csvi, csvi),
|
||||
OPT_BYTE("uidx", 'u', &cfg.uidx, uidx),
|
||||
OPT_LONG("offset", 'o', &cfg.offset, offset),
|
||||
OPT_UINT("numd", 'n', &cfg.numd, numd),
|
||||
OPT_FILE("output-file", 'f', &cfg.output, output),
|
||||
OPT_FMT("output-format", 0, &cfg.output_format, output_format),
|
||||
OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_info),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
err = parse_and_open(&dev, argc, argv, desc, opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = validate_output_format(cfg.output_format, &flags);
|
||||
if (err < 0) {
|
||||
nvme_show_error("Invalid output format");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (cfg.output_format && cfg.offset != 0 && !(flags & BINARY)) {
|
||||
nvme_show_error("cannot parse non-zero offset");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (cfg.human_readable)
|
||||
flags |= VERBOSE;
|
||||
|
||||
if (cfg.output && strlen(cfg.output)) {
|
||||
fd = fopen(cfg.output, "w");
|
||||
if (fd < 0) {
|
||||
nvme_show_perror(cfg.output);
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
data = nvme_alloc_huge((cfg.numd + 1) << 2, &mh);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
__u32 result = 0;
|
||||
struct nvme_lm_migration_recv_args args = {
|
||||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.sel = cfg.sel,
|
||||
.mos = NVME_SET(cfg.csvi, LM_GET_CONTROLLER_STATE_CSVI),
|
||||
.uidx = cfg.uidx,
|
||||
.csuuidi = cfg.csuuidi,
|
||||
.offset = cfg.offset,
|
||||
.cntlid = cfg.cntlid,
|
||||
.data = data,
|
||||
.result = &result,
|
||||
};
|
||||
|
||||
err = nvme_lm_migration_recv(&args);
|
||||
if (err < 0)
|
||||
nvme_show_error("ERROR: nvme_lm_migration_recv() failed %s", strerror(errno));
|
||||
else if (err)
|
||||
nvme_show_status(err);
|
||||
else if (cfg.sel == NVME_LM_SEL_GET_CONTROLLER_STATE) {
|
||||
if (flags == NORMAL)
|
||||
printf("CDW0: 0x%x: Controller %sSuspended\n", result,
|
||||
(result & NVME_LM_GET_CONTROLLER_STATE_CSUP) ? "" : "NOT ");
|
||||
|
||||
if (cfg.output && strlen(cfg.output)) {
|
||||
if (fwrite(data, 1, cfg.numd << 2, fd) != (cfg.numd << 2)) {
|
||||
nvme_show_error("ERROR: %s: failed to write buffer to output file",
|
||||
strerror(errno));
|
||||
err = -errno;
|
||||
}
|
||||
} else {
|
||||
lm_show_controller_state_data((struct nvme_lm_controller_state_data *)data,
|
||||
(cfg.numd + 1) << 2, cfg.offset, flags);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum lm_controller_data_queue_feature_id {
|
||||
lm_cdq_feature_id = 0x21
|
||||
};
|
||||
|
||||
static int lm_set_cdq(int argc, char **argv, struct command *command, struct plugin *plugin)
|
||||
{
|
||||
const char *desc = "This Feature allows a host to update the status of the head pointer "
|
||||
"of a CDQ and specify the configuration of a CDQ Tail event.";
|
||||
const char *cdqid = "Controller Data Queue ID";
|
||||
const char *hp = "The slot of the head pointer for the specified CDQ";
|
||||
const char *tpt = "If specified, the slot that causes the controller "
|
||||
" to issue a CDQ Tail Pointer event";
|
||||
|
||||
_cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
|
||||
int err = -1;
|
||||
|
||||
struct config {
|
||||
__u16 cdqid;
|
||||
__u32 hp;
|
||||
__s32 tpt;
|
||||
};
|
||||
|
||||
struct config cfg = {
|
||||
.cdqid = 0,
|
||||
.hp = 0,
|
||||
.tpt = -1,
|
||||
};
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
OPT_SHRT("cdqid", 'C', &cfg.cdqid, cdqid),
|
||||
OPT_UINT("hp", 'H', &cfg.hp, hp),
|
||||
OPT_UINT("tpt", 'T', &cfg.tpt, tpt),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
err = parse_and_open(&dev, argc, argv, desc, opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
struct nvme_set_features_args args = {
|
||||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.fid = lm_cdq_feature_id,
|
||||
.cdw11 = cfg.cdqid |
|
||||
((cfg.tpt >= 0) ? NVME_SET(1, LM_CTRL_DATA_QUEUE_ETPT) : 0),
|
||||
.cdw12 = cfg.hp,
|
||||
.cdw13 = cfg.tpt
|
||||
};
|
||||
|
||||
err = nvme_set_features(&args);
|
||||
if (err < 0)
|
||||
nvme_show_error("ERROR: nvme_set_features() failed %s", nvme_strerror(errno));
|
||||
else if (err)
|
||||
nvme_show_status(err);
|
||||
else
|
||||
printf("Success. Head Pointer: %d\n", cfg.hp);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int lm_get_cdq(int argc, char **argv, struct command *command, struct plugin *plugin)
|
||||
{
|
||||
const char *desc = "This Feature allows a host to retrieve the status of the head pointer "
|
||||
"of a CDQ and specify the configuration of a CDQ Tail event.";
|
||||
const char *cdqid = "Controller Data Queue ID";
|
||||
|
||||
_cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
|
||||
nvme_print_flags_t flags;
|
||||
int err = -1;
|
||||
|
||||
struct config {
|
||||
__u16 cdqid;
|
||||
char *output_format;
|
||||
};
|
||||
|
||||
struct config cfg = {
|
||||
.cdqid = 0,
|
||||
.output_format = "normal",
|
||||
};
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
OPT_SHRT("cdqid", 'C', &cfg.cdqid, cdqid),
|
||||
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
err = parse_and_open(&dev, argc, argv, desc, opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = validate_output_format(cfg.output_format, &flags);
|
||||
if (err < 0) {
|
||||
nvme_show_error("Invalid output format");
|
||||
return err;
|
||||
}
|
||||
|
||||
struct nvme_lm_ctrl_data_queue_fid_data data;
|
||||
|
||||
struct nvme_get_features_args args = {
|
||||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.fid = lm_cdq_feature_id,
|
||||
.cdw11 = cfg.cdqid,
|
||||
.data = &data,
|
||||
.data_len = sizeof(data)
|
||||
};
|
||||
|
||||
err = nvme_get_features(&args);
|
||||
if (err < 0)
|
||||
nvme_show_error("ERROR: nvme_get_features() failed %s", nvme_strerror(errno));
|
||||
else if (err)
|
||||
nvme_show_status(err);
|
||||
else
|
||||
lm_show_controller_data_queue(&data, flags);
|
||||
|
||||
return err;
|
||||
}
|
30
plugins/lm/lm-nvme.h
Normal file
30
plugins/lm/lm-nvme.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2024 Samsung Electronics Co., LTD.
|
||||
*
|
||||
* Authors: Nate Thornton <n.thornton@samsung.com>
|
||||
*/
|
||||
|
||||
#undef CMD_INC_FILE
|
||||
#define CMD_INC_FILE plugins/lm/lm-nvme
|
||||
|
||||
#if !defined(LIVE_MIGRATION_NVME) || defined(CMD_HEADER_MULTI_READ)
|
||||
#define LIVE_MIGRATION_NVME
|
||||
|
||||
#include "cmd.h"
|
||||
|
||||
PLUGIN(NAME("lm", "Live Migration NVMe extensions", NVME_VERSION),
|
||||
COMMAND_LIST(
|
||||
ENTRY("create-cdq", "Create Controller Data Queue", lm_create_cdq)
|
||||
ENTRY("delete-cdq", "Delete Controller Data Queue", lm_delete_cdq)
|
||||
ENTRY("track-send", "Track Send Command", lm_track_send)
|
||||
ENTRY("migration-send", "Migration Send", lm_migration_send)
|
||||
ENTRY("migration-recv", "Migration Receive", lm_migration_recv)
|
||||
ENTRY("set-cdq", "Set Feature - Controller Data Queue (FID 21h)", lm_set_cdq)
|
||||
ENTRY("get-cdq", "Get Feature - Controller Data Queue (FID 21h)", lm_get_cdq)
|
||||
)
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
#include "define_cmd.h"
|
25
plugins/lm/lm-print-binary.c
Normal file
25
plugins/lm/lm-print-binary.c
Normal file
|
@ -0,0 +1,25 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "lm-print.h"
|
||||
|
||||
static void binary_controller_state_data(struct nvme_lm_controller_state_data *data, size_t len,
|
||||
__u32 offset)
|
||||
{
|
||||
d_raw((unsigned char *)data, len);
|
||||
}
|
||||
|
||||
static void binary_controller_data_queue(struct nvme_lm_ctrl_data_queue_fid_data *data)
|
||||
{
|
||||
d_raw((unsigned char *)data, sizeof(*data));
|
||||
}
|
||||
|
||||
static struct lm_print_ops binary_print_ops = {
|
||||
.controller_state_data = binary_controller_state_data,
|
||||
.controller_data_queue = binary_controller_data_queue,
|
||||
};
|
||||
|
||||
struct lm_print_ops *lm_get_binary_print_ops(nvme_print_flags_t flags)
|
||||
{
|
||||
binary_print_ops.flags = flags;
|
||||
return &binary_print_ops;
|
||||
}
|
109
plugins/lm/lm-print-json.c
Normal file
109
plugins/lm/lm-print-json.c
Normal file
|
@ -0,0 +1,109 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "lm-print.h"
|
||||
#include "common.h"
|
||||
|
||||
static void json_controller_state_data(struct nvme_lm_controller_state_data *data, size_t len,
|
||||
__u32 offset)
|
||||
{
|
||||
if (offset) {
|
||||
fprintf(stderr, "cannot understand non-zero offset\n");
|
||||
return;
|
||||
}
|
||||
|
||||
struct json_object *root = json_create_object();
|
||||
struct json_object *nvmecs = json_create_object();
|
||||
struct json_object *iosqs = json_create_array();
|
||||
struct json_object *iocqs = json_create_array();
|
||||
|
||||
json_object_add_value_uint(root, "version",
|
||||
le16_to_cpu(data->hdr.ver));
|
||||
json_object_add_value_uint(root, "controller state attributes",
|
||||
data->hdr.csattr);
|
||||
json_object_add_value_uint128(root, "nvme controller state size",
|
||||
le128_to_cpu(data->hdr.nvmecss));
|
||||
json_object_add_value_uint128(root, "vendor specific size",
|
||||
le128_to_cpu(data->hdr.vss));
|
||||
|
||||
json_object_add_value_object(root, "nvme controller state", nvmecs);
|
||||
|
||||
json_object_add_value_uint(nvmecs, "version",
|
||||
le16_to_cpu(data->data.hdr.ver));
|
||||
json_object_add_value_uint(nvmecs, "number of io submission queues",
|
||||
le16_to_cpu(data->data.hdr.niosq));
|
||||
json_object_add_value_uint(nvmecs, "number of io completion queues",
|
||||
le16_to_cpu(data->data.hdr.niocq));
|
||||
|
||||
json_object_add_value_array(nvmecs, "io submission queue list", iosqs);
|
||||
|
||||
for (int i = 0; i < data->data.hdr.niosq; i++) {
|
||||
struct nvme_lm_io_submission_queue_data *sq = &data->data.sqs[i];
|
||||
struct json_object *sq_obj = json_create_object();
|
||||
|
||||
json_object_add_value_uint64(sq_obj, "io submission prp entry 1",
|
||||
le64_to_cpu(sq->iosqprp1));
|
||||
json_object_add_value_uint(sq_obj, "io submission queue size",
|
||||
le16_to_cpu(sq->iosqqsize));
|
||||
json_object_add_value_uint(sq_obj, "io submission queue identifier",
|
||||
le16_to_cpu(sq->iosqqid));
|
||||
json_object_add_value_uint(sq_obj, "io completion queue identifier",
|
||||
le16_to_cpu(sq->iosqcqid));
|
||||
json_object_add_value_uint(sq_obj, "io submission queue attributes",
|
||||
le16_to_cpu(sq->iosqa));
|
||||
json_object_add_value_uint(sq_obj, "io submission queue head pointer",
|
||||
le16_to_cpu(sq->iosqhp));
|
||||
json_object_add_value_uint(sq_obj, "io submission queue tail pointer",
|
||||
le16_to_cpu(sq->iosqtp));
|
||||
|
||||
json_array_add_value_object(iosqs, sq_obj);
|
||||
}
|
||||
|
||||
json_object_add_value_array(nvmecs, "io completion queue list", iocqs);
|
||||
|
||||
for (int i = 0; i < data->data.hdr.niocq; i++) {
|
||||
struct nvme_lm_io_completion_queue_data *cq = &data->data.cqs[i];
|
||||
struct json_object *cq_obj = json_create_object();
|
||||
|
||||
json_object_add_value_uint64(cq_obj, "io completion prp entry 1",
|
||||
le64_to_cpu(cq->iocqprp1));
|
||||
json_object_add_value_uint(cq_obj, "io completion queue size",
|
||||
le16_to_cpu(cq->iocqqsize));
|
||||
json_object_add_value_uint(cq_obj, "io completion queue identifier",
|
||||
le16_to_cpu(cq->iocqqid));
|
||||
json_object_add_value_uint(cq_obj, "io completion queue head pointer",
|
||||
le16_to_cpu(cq->iocqhp));
|
||||
json_object_add_value_uint(cq_obj, "io completion queue tail pointer",
|
||||
le16_to_cpu(cq->iocqtp));
|
||||
json_object_add_value_uint(cq_obj, "io completion queue attributes",
|
||||
le32_to_cpu(cq->iocqa));
|
||||
|
||||
json_array_add_value_object(iocqs, cq_obj);
|
||||
}
|
||||
|
||||
json_print_object(root, NULL);
|
||||
printf("\n");
|
||||
json_free_object(root);
|
||||
}
|
||||
|
||||
static void json_controller_data_queue(struct nvme_lm_ctrl_data_queue_fid_data *data)
|
||||
{
|
||||
struct json_object *root = json_create_object();
|
||||
|
||||
json_object_add_value_uint(root, "head_pointer", le32_to_cpu(data->hp));
|
||||
json_object_add_value_uint(root, "tail_pointer_trigger", le32_to_cpu(data->tpt));
|
||||
|
||||
json_print_object(root, NULL);
|
||||
printf("\n");
|
||||
json_free_object(root);
|
||||
}
|
||||
|
||||
static struct lm_print_ops json_print_ops = {
|
||||
.controller_state_data = json_controller_state_data,
|
||||
.controller_data_queue = json_controller_data_queue
|
||||
};
|
||||
|
||||
struct lm_print_ops *lm_get_json_print_ops(nvme_print_flags_t flags)
|
||||
{
|
||||
json_print_ops.flags = flags;
|
||||
return &json_print_ops;
|
||||
}
|
145
plugins/lm/lm-print-stdout.c
Normal file
145
plugins/lm/lm-print-stdout.c
Normal file
|
@ -0,0 +1,145 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "lm-print.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "util/types.h"
|
||||
|
||||
static struct lm_print_ops stdout_print_ops;
|
||||
|
||||
static void stdout_controller_state_data(struct nvme_lm_controller_state_data *data, size_t len,
|
||||
__u32 offset)
|
||||
{
|
||||
if (offset) {
|
||||
fprintf(stderr, "cannot understand non-zero offset\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int human = stdout_print_ops.flags & VERBOSE;
|
||||
|
||||
if (sizeof(struct nvme_lm_controller_state_data_header) <= len) {
|
||||
printf("Header:\n");
|
||||
printf("%-45s: 0x%x\n", "Version (VER)", data->hdr.ver);
|
||||
printf("%-45s: 0x%x\n", "Controller State Attributes (CSATTR)", data->hdr.csattr);
|
||||
if (human)
|
||||
printf(" [0:0] : 0x%x Controller %sSuspended\n",
|
||||
data->hdr.csattr & 1, data->hdr.csattr & 1 ? "" : "NOT ");
|
||||
printf("%-45s: %s\n", "NVMe Controller State Size (NVMECSS)",
|
||||
uint128_t_to_string(le128_to_cpu(data->hdr.nvmecss)));
|
||||
printf("%-45s: %s\n", "Vendor Specific Size (VSS)",
|
||||
uint128_t_to_string(le128_to_cpu(data->hdr.vss)));
|
||||
|
||||
len -= sizeof(struct nvme_lm_controller_state_data_header);
|
||||
} else {
|
||||
fprintf(stderr, "WARNING: Header truncated\n");
|
||||
len = 0;
|
||||
}
|
||||
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
if (sizeof(struct nvme_lm_nvme_controller_state_data_header) <= len) {
|
||||
int niosq = data->data.hdr.niosq;
|
||||
int niocq = data->data.hdr.niocq;
|
||||
|
||||
printf("\nNVMe Controller State Data Structure:\n");
|
||||
printf("%-45s: 0x%x\n", "Version (VER)",
|
||||
le16_to_cpu(data->data.hdr.ver));
|
||||
printf("%-45s: %d\n", "Number of I/O Submission Queues (NIOSQ)",
|
||||
le16_to_cpu(niosq));
|
||||
printf("%-45s: %d\n", "Number of I/O Completion Queues (NIOCQ)",
|
||||
le16_to_cpu(niocq));
|
||||
|
||||
len -= sizeof(struct nvme_lm_nvme_controller_state_data_header);
|
||||
|
||||
if (len < niosq * sizeof(struct nvme_lm_io_submission_queue_data)) {
|
||||
fprintf(stderr, "WARNING: I/O Submission Queues truncated\n");
|
||||
niosq = len / sizeof(struct nvme_lm_io_submission_queue_data);
|
||||
}
|
||||
|
||||
for (int i = 0; i < niosq; ++i) {
|
||||
struct nvme_lm_io_submission_queue_data *sq = &(data->data.sqs[i]);
|
||||
__u16 iosqa = le16_to_cpu(sq->iosqa);
|
||||
|
||||
printf("\nNVMe I/O Submission Queue Data [%d]:\n", i);
|
||||
printf("%-45s: 0x%"PRIu64"\n", "PRP Entry 1 (IOSQPRP1)",
|
||||
le64_to_cpu(sq->iosqprp1));
|
||||
printf("%-45s: 0x%x\n", "Queue Size (IOSQQSIZE)",
|
||||
le16_to_cpu(sq->iosqqsize));
|
||||
printf("%-45s: 0x%x\n", "Identifier (IOSQQID)",
|
||||
le16_to_cpu(sq->iosqqid));
|
||||
printf("%-45s: 0x%x\n", "Completion Queue Identifier (IOSQCQID)",
|
||||
le16_to_cpu(sq->iosqcqid));
|
||||
printf("%-45s: 0x%x\n", "Attributes (IOSQA)", iosqa);
|
||||
if (human) {
|
||||
printf(" [2:1] : 0x%x Queue Priority (IOSQQPRIO)\n",
|
||||
NVME_GET(iosqa, LM_IOSQPRIO));
|
||||
printf(" [0:0] : 0x%x Queue %sPhysically Contiguous (IOSQPC)\n",
|
||||
NVME_GET(iosqa, LM_IOSQPC),
|
||||
NVME_GET(iosqa, LM_IOSQPC) ? "" : "NOT ");
|
||||
}
|
||||
printf("%-45s: 0x%x\n", "I/O Submission Queue Head Pointer (IOSQHP)",
|
||||
le16_to_cpu(sq->iosqhp));
|
||||
printf("%-45s: 0x%x\n", "I/O Submission Queue Tail Pointer (IOSQTP)",
|
||||
le16_to_cpu(sq->iosqtp));
|
||||
}
|
||||
|
||||
len -= niosq * sizeof(struct nvme_lm_io_submission_queue_data);
|
||||
|
||||
if (len < niocq * sizeof(struct nvme_lm_io_completion_queue_data)) {
|
||||
fprintf(stderr, "WARNING: I/O Completion Queues truncated\n");
|
||||
niocq = len / sizeof(struct nvme_lm_io_completion_queue_data);
|
||||
}
|
||||
|
||||
for (int i = 0; i < niocq; ++i) {
|
||||
struct nvme_lm_io_completion_queue_data *cq = &data->data.cqs[niosq + i];
|
||||
__u32 iocqa = le32_to_cpu(cq->iocqa);
|
||||
|
||||
printf("\nNVMe I/O Completion Queue Data [%d]:\n", i);
|
||||
printf("%-45s: 0x%"PRIu64"\n", "I/O Completion PRP Entry 1 (IOCQPRP1)",
|
||||
le64_to_cpu(cq->iocqprp1));
|
||||
printf("%-45s: 0x%x\n", "I/O Completion Queue Size (IOCQQSIZE)",
|
||||
le16_to_cpu(cq->iocqqsize));
|
||||
printf("%-45s: 0x%x\n", "I/O Completion Queue Identifier (IOCQQID)",
|
||||
le16_to_cpu(cq->iocqqid));
|
||||
printf("%-45s: 0x%x\n", "I/O Completion Queue Head Pointer (IOSQHP)",
|
||||
le16_to_cpu(cq->iocqhp));
|
||||
printf("%-45s: 0x%x\n", "I/O Completion Queue Tail Pointer (IOSQTP)",
|
||||
le16_to_cpu(cq->iocqtp));
|
||||
printf("%-45s: 0x%x\n", "I/O Completion Queue Attributes (IOCQA)", iocqa);
|
||||
if (human) {
|
||||
printf(" [31:16] : 0x%x I/O Completion Queue Interrupt Vector "
|
||||
"(IOCQIV)\n",
|
||||
NVME_GET(iocqa, LM_IOCQIEN));
|
||||
printf(" [2:2] : 0x%x Slot 0 Phase Tag (S0PT)\n",
|
||||
NVME_GET(iocqa, LM_S0PT));
|
||||
printf(" [1:1] : 0x%x Interrupts %sEnabled (IOCQIEN)\n",
|
||||
NVME_GET(iocqa, LM_IOCQIEN),
|
||||
NVME_GET(iocqa, LM_IOCQIEN) ? "" : "NOT ");
|
||||
printf(" [0:0] : 0x%x Queue %sPhysically Contiguous (IOCQPC)\n",
|
||||
NVME_GET(iocqa, LM_IOCQPC),
|
||||
NVME_GET(iocqa, LM_IOCQPC) ? "" : "NOT ");
|
||||
}
|
||||
}
|
||||
} else
|
||||
fprintf(stderr, "WARNING: NVMe Controller State Data Structure truncated\n");
|
||||
}
|
||||
|
||||
static void stdout_show_controller_data_queue(struct nvme_lm_ctrl_data_queue_fid_data *data)
|
||||
{
|
||||
printf("Head Pointer: 0x%x\n", le32_to_cpu(data->hp));
|
||||
printf("Tail Pointer Trigger: 0x%x\n", le32_to_cpu(data->tpt));
|
||||
}
|
||||
|
||||
static struct lm_print_ops stdout_print_ops = {
|
||||
.controller_state_data = stdout_controller_state_data,
|
||||
.controller_data_queue = stdout_show_controller_data_queue
|
||||
};
|
||||
|
||||
struct lm_print_ops *lm_get_stdout_print_ops(nvme_print_flags_t flags)
|
||||
{
|
||||
stdout_print_ops.flags = flags;
|
||||
return &stdout_print_ops;
|
||||
}
|
38
plugins/lm/lm-print.c
Normal file
38
plugins/lm/lm-print.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "lm-print.h"
|
||||
|
||||
#define lm_print(name, flags, ...) \
|
||||
do { \
|
||||
struct lm_print_ops *ops = lm_print_ops(flags); \
|
||||
if (ops && ops->name) \
|
||||
ops->name(__VA_ARGS__); \
|
||||
else \
|
||||
fprintf(stderr, "unhandled output format\n"); \
|
||||
} while (false)
|
||||
|
||||
static struct lm_print_ops *lm_print_ops(nvme_print_flags_t flags)
|
||||
{
|
||||
struct lm_print_ops *ops = NULL;
|
||||
|
||||
if (flags & JSON || nvme_is_output_format_json())
|
||||
ops = lm_get_json_print_ops(flags);
|
||||
else if (flags & BINARY)
|
||||
ops = lm_get_binary_print_ops(flags);
|
||||
else
|
||||
ops = lm_get_stdout_print_ops(flags);
|
||||
|
||||
return ops;
|
||||
}
|
||||
|
||||
void lm_show_controller_state_data(struct nvme_lm_controller_state_data *data, size_t len,
|
||||
__u32 offset, nvme_print_flags_t flags)
|
||||
{
|
||||
lm_print(controller_state_data, flags, data, len, offset);
|
||||
}
|
||||
|
||||
void lm_show_controller_data_queue(struct nvme_lm_ctrl_data_queue_fid_data *data,
|
||||
nvme_print_flags_t flags)
|
||||
{
|
||||
lm_print(controller_data_queue, flags, data);
|
||||
}
|
31
plugins/lm/lm-print.h
Normal file
31
plugins/lm/lm-print.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
#ifndef LM_PRINT_H
|
||||
#define LM_PRINT_H
|
||||
|
||||
#include "nvme.h"
|
||||
#include "libnvme.h"
|
||||
|
||||
struct lm_print_ops {
|
||||
void (*controller_state_data)(struct nvme_lm_controller_state_data *data, size_t len,
|
||||
__u32 offset);
|
||||
void (*controller_data_queue)(struct nvme_lm_ctrl_data_queue_fid_data *data);
|
||||
nvme_print_flags_t flags;
|
||||
};
|
||||
|
||||
struct lm_print_ops *lm_get_stdout_print_ops(nvme_print_flags_t flags);
|
||||
struct lm_print_ops *lm_get_binary_print_ops(nvme_print_flags_t flags);
|
||||
|
||||
#ifdef CONFIG_JSONC
|
||||
struct lm_print_ops *lm_get_json_print_ops(nvme_print_flags_t flags);
|
||||
#else
|
||||
static inline struct lm_print_ops *lm_get_json_print_ops(nvme_print_flags_t flags)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
void lm_show_controller_state_data(struct nvme_lm_controller_state_data *data, size_t len,
|
||||
__u32 offset, nvme_print_flags_t flags);
|
||||
void lm_show_controller_data_queue(struct nvme_lm_ctrl_data_queue_fid_data *data,
|
||||
nvme_print_flags_t flags);
|
||||
#endif /* LM_PRINT_H */
|
12
plugins/lm/meson.build
Normal file
12
plugins/lm/meson.build
Normal file
|
@ -0,0 +1,12 @@
|
|||
sources += [
|
||||
'plugins/lm/lm-nvme.c',
|
||||
'plugins/lm/lm-print.c',
|
||||
'plugins/lm/lm-print-stdout.c',
|
||||
'plugins/lm/lm-print-binary.c',
|
||||
]
|
||||
|
||||
if json_c_dep.found()
|
||||
sources += [
|
||||
'plugins/lm/lm-print-json.c',
|
||||
]
|
||||
endif
|
|
@ -2,37 +2,42 @@
|
|||
|
||||
if json_c_dep.found()
|
||||
sources += [
|
||||
'plugins/amzn/amzn-nvme.c',
|
||||
'plugins/dapustor/dapustor-nvme.c',
|
||||
'plugins/dell/dell-nvme.c',
|
||||
'plugins/dera/dera-nvme.c',
|
||||
'plugins/fdp/fdp.c',
|
||||
'plugins/huawei/huawei-nvme.c',
|
||||
'plugins/innogrit/innogrit-nvme.c',
|
||||
'plugins/inspur/inspur-nvme.c',
|
||||
'plugins/intel/intel-nvme.c',
|
||||
'plugins/memblaze/memblaze-nvme.c',
|
||||
'plugins/micron/micron-nvme.c',
|
||||
'plugins/nbft/nbft-plugin.c',
|
||||
'plugins/netapp/netapp-nvme.c',
|
||||
'plugins/nvidia/nvidia-nvme.c',
|
||||
'plugins/scaleflux/sfx-nvme.c',
|
||||
'plugins/seagate/seagate-nvme.c',
|
||||
'plugins/shannon/shannon-nvme.c',
|
||||
'plugins/solidigm/solidigm-nvme.c',
|
||||
'plugins/toshiba/toshiba-nvme.c',
|
||||
'plugins/transcend/transcend-nvme.c',
|
||||
'plugins/virtium/virtium-nvme.c',
|
||||
'plugins/wdc/wdc-nvme.c',
|
||||
'plugins/wdc/wdc-utils.c',
|
||||
'plugins/ymtc/ymtc-nvme.c',
|
||||
'plugins/zns/zns.c',
|
||||
'plugins/ssstc/ssstc-nvme.c',
|
||||
]
|
||||
subdir('solidigm')
|
||||
if conf.get('HAVE_SED_OPAL') != 0
|
||||
subdir('sed')
|
||||
endif
|
||||
endif
|
||||
|
||||
sources += [
|
||||
'plugins/amzn/amzn-nvme.c',
|
||||
'plugins/dapustor/dapustor-nvme.c',
|
||||
'plugins/dell/dell-nvme.c',
|
||||
'plugins/dera/dera-nvme.c',
|
||||
'plugins/fdp/fdp.c',
|
||||
'plugins/huawei/huawei-nvme.c',
|
||||
'plugins/innogrit/innogrit-nvme.c',
|
||||
'plugins/inspur/inspur-nvme.c',
|
||||
'plugins/intel/intel-nvme.c',
|
||||
'plugins/memblaze/memblaze-nvme.c',
|
||||
'plugins/micron/micron-nvme.c',
|
||||
'plugins/nbft/nbft-plugin.c',
|
||||
'plugins/netapp/netapp-nvme.c',
|
||||
'plugins/nvidia/nvidia-nvme.c',
|
||||
'plugins/scaleflux/sfx-nvme.c',
|
||||
'plugins/seagate/seagate-nvme.c',
|
||||
'plugins/shannon/shannon-nvme.c',
|
||||
'plugins/ssstc/ssstc-nvme.c',
|
||||
'plugins/toshiba/toshiba-nvme.c',
|
||||
'plugins/transcend/transcend-nvme.c',
|
||||
'plugins/virtium/virtium-nvme.c',
|
||||
'plugins/wdc/wdc-nvme.c',
|
||||
'plugins/wdc/wdc-utils.c',
|
||||
'plugins/ymtc/ymtc-nvme.c',
|
||||
'plugins/zns/zns.c',
|
||||
]
|
||||
|
||||
subdir('ocp')
|
||||
subdir('lm')
|
||||
|
||||
if conf.get('HAVE_SED_OPAL') != 0
|
||||
subdir('sed')
|
||||
endif
|
||||
|
|
|
@ -737,10 +737,12 @@ static int micron_temp_stats(int argc, char **argv, struct command *cmd,
|
|||
struct format cfg = {
|
||||
.fmt = "normal",
|
||||
};
|
||||
|
||||
bool is_json = false;
|
||||
struct json_object *root;
|
||||
struct json_object *logPages;
|
||||
struct nvme_dev *dev;
|
||||
nvme_print_flags_t flags;
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
OPT_FMT("format", 'f', &cfg.fmt, fmt),
|
||||
|
@ -753,7 +755,13 @@ static int micron_temp_stats(int argc, char **argv, struct command *cmd,
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (!strcmp(cfg.fmt, "json"))
|
||||
err = validate_output_format(nvme_cfg.output_format, &flags);
|
||||
if (err < 0) {
|
||||
nvme_show_error("Invalid output format");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (flags & JSON)
|
||||
is_json = true;
|
||||
|
||||
err = nvme_get_log_smart(dev_fd(dev), 0xffffffff, false, &smart_log);
|
||||
|
@ -764,6 +772,7 @@ static int micron_temp_stats(int argc, char **argv, struct command *cmd,
|
|||
tempSensors[i] = le16_to_cpu(smart_log.temp_sensor[i]);
|
||||
tempSensors[i] = tempSensors[i] ? tempSensors[i] - 273 : 0;
|
||||
}
|
||||
|
||||
if (is_json) {
|
||||
struct json_object *stats = json_create_object();
|
||||
char tempstr[64] = { 0 };
|
||||
|
@ -840,6 +849,7 @@ static int micron_pcie_stats(int argc, char **argv,
|
|||
__u16 ecrc_error;
|
||||
__u16 unsupported_request_error;
|
||||
} pcie_error_counters = { 0 };
|
||||
nvme_print_flags_t flags;
|
||||
|
||||
struct {
|
||||
char *err;
|
||||
|
@ -905,7 +915,13 @@ static int micron_pcie_stats(int argc, char **argv,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (!strcmp(cfg.fmt, "normal"))
|
||||
err = validate_output_format(cfg.fmt, &flags);
|
||||
if (err < 0) {
|
||||
nvme_show_error("Invalid output format");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (flags & NORMAL)
|
||||
is_json = false;
|
||||
|
||||
if (eModel == M5407) {
|
||||
|
@ -1546,12 +1562,20 @@ static int micron_smart_ext_log(int argc, char **argv,
|
|||
OPT_FMT("format", 'f', &cfg.fmt, fmt),
|
||||
OPT_END()
|
||||
};
|
||||
nvme_print_flags_t flags;
|
||||
|
||||
err = parse_and_open(&dev, argc, argv, desc, opts);
|
||||
if (err) {
|
||||
printf("\nDevice not found\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = validate_output_format(nvme_cfg.output_format, &flags);
|
||||
if (err < 0) {
|
||||
nvme_show_error("Invalid output format");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!strcmp(cfg.fmt, "normal"))
|
||||
is_json = false;
|
||||
|
||||
|
@ -1956,6 +1980,7 @@ static int micron_drive_info(int argc, char **argv, struct command *cmd,
|
|||
char *fmt;
|
||||
};
|
||||
int err = 0;
|
||||
nvme_print_flags_t flags;
|
||||
|
||||
const char *fmt = "output format normal";
|
||||
struct format cfg = {
|
||||
|
@ -1972,11 +1997,17 @@ static int micron_drive_info(int argc, char **argv, struct command *cmd,
|
|||
return err;
|
||||
|
||||
if (model == UNKNOWN_MODEL) {
|
||||
fprintf(stderr, "ERROR : Unsupported drive for vs-drive-info cmd");
|
||||
fprintf(stderr, "ERROR : Unsupported drive for vs-drive-info cmd\n");
|
||||
dev_close(dev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = validate_output_format(cfg.fmt, &flags);
|
||||
if (err < 0) {
|
||||
nvme_show_error("Invalid output format");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!strcmp(cfg.fmt, "json"))
|
||||
is_json = true;
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ static char *mac_addr_to_string(unsigned char mac_addr[6])
|
|||
return mac_string;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_JSONC
|
||||
static json_object *hfi_to_json(struct nbft_info_hfi *hfi)
|
||||
{
|
||||
struct json_object *hfi_json;
|
||||
|
@ -348,6 +349,9 @@ fail:
|
|||
json_free_object(nbft_json_array);
|
||||
return -ENOMEM;
|
||||
}
|
||||
#else /* CONFIG_JSONC */
|
||||
#define json_show_nbfts(nbft_list, show_subsys, show_hfi, show_discovery) -EINVAL
|
||||
#endif /* CONFIG_JSONC */
|
||||
|
||||
static void print_nbft_hfi_info(struct nbft_info *nbft)
|
||||
{
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "nvme.h"
|
||||
|
@ -118,6 +119,43 @@ static void netapp_get_ns_size(char *size, unsigned long long *lba,
|
|||
sprintf(size, "%.2f%sB", nsze, s_suffix);
|
||||
}
|
||||
|
||||
static void netapp_get_ns_attrs(char *size, char *used, char *blk_size,
|
||||
char *version, unsigned long long *lba,
|
||||
struct nvme_id_ctrl *ctrl, struct nvme_id_ns *ns)
|
||||
{
|
||||
__u8 lba_index;
|
||||
|
||||
nvme_id_ns_flbas_to_lbaf_inuse(ns->flbas, &lba_index);
|
||||
*lba = 1ULL << ns->lbaf[lba_index].ds;
|
||||
|
||||
/* get the namespace size */
|
||||
double nsze = le64_to_cpu(ns->nsze) * (*lba);
|
||||
const char *s_suffix = suffix_si_get(&nsze);
|
||||
|
||||
sprintf(size, "%.2f%sB", nsze, s_suffix);
|
||||
|
||||
/* get the namespace utilization */
|
||||
double nuse = le64_to_cpu(ns->nuse) * (*lba);
|
||||
const char *u_suffix = suffix_si_get(&nuse);
|
||||
|
||||
sprintf(used, "%.2f%sB", nuse, u_suffix);
|
||||
|
||||
/* get the namespace block size */
|
||||
long long addr = 1LL << ns->lbaf[lba_index].ds;
|
||||
const char *l_suffix = suffix_binary_get(&addr);
|
||||
|
||||
sprintf(blk_size, "%u%sB", (unsigned int)addr, l_suffix);
|
||||
|
||||
/* get the firmware version */
|
||||
int i, max = sizeof(ctrl->fr);
|
||||
|
||||
memcpy(version, ctrl->fr, max);
|
||||
version[max] = '\0';
|
||||
/* strip trailing whitespaces */
|
||||
for (i = max - 1; i >= 0 && version[i] == ' '; i--)
|
||||
version[i] = '\0';
|
||||
}
|
||||
|
||||
static void ontap_labels_to_str(char *dst, char *src, int count)
|
||||
{
|
||||
int i;
|
||||
|
@ -212,10 +250,11 @@ static void netapp_get_ontap_labels(char *vsname, char *nspath,
|
|||
|
||||
static void netapp_smdevice_json(struct json_object *devices, char *devname,
|
||||
char *arrayname, char *volname, int nsid, char *nguid,
|
||||
char *ctrl, char *astate, char *size, long long lba,
|
||||
long long nsze)
|
||||
char *ctrl, char *astate, char *version, unsigned long long lba,
|
||||
unsigned long long nsze, unsigned long long nuse)
|
||||
{
|
||||
struct json_object *device_attrs;
|
||||
unsigned long long ns_size = nsze * lba;
|
||||
|
||||
device_attrs = json_create_object();
|
||||
json_object_add_value_string(device_attrs, "Device", devname);
|
||||
|
@ -225,18 +264,21 @@ static void netapp_smdevice_json(struct json_object *devices, char *devname,
|
|||
json_object_add_value_string(device_attrs, "Volume_ID", nguid);
|
||||
json_object_add_value_string(device_attrs, "Controller", ctrl);
|
||||
json_object_add_value_string(device_attrs, "Access_State", astate);
|
||||
json_object_add_value_string(device_attrs, "Size", size);
|
||||
json_object_add_value_int(device_attrs, "LBA_Data_Size", lba);
|
||||
json_object_add_value_int(device_attrs, "Namespace_Size", nsze);
|
||||
json_object_add_value_uint64(device_attrs, "LBA_Size", lba);
|
||||
json_object_add_value_uint64(device_attrs, "Namespace_Size", ns_size);
|
||||
json_object_add_value_string(device_attrs, "Version", version);
|
||||
|
||||
json_array_add_value_object(devices, device_attrs);
|
||||
}
|
||||
|
||||
static void netapp_ontapdevice_json(struct json_object *devices, char *devname,
|
||||
char *vsname, char *nspath, int nsid, char *uuid,
|
||||
char *size, long long lba, long long nsze)
|
||||
unsigned long long lba, char *version,
|
||||
unsigned long long nsze, unsigned long long nuse)
|
||||
{
|
||||
struct json_object *device_attrs;
|
||||
unsigned long long ns_size = nsze * lba;
|
||||
unsigned long long used_size = nuse * lba;
|
||||
|
||||
device_attrs = json_create_object();
|
||||
json_object_add_value_string(device_attrs, "Device", devname);
|
||||
|
@ -244,13 +286,93 @@ static void netapp_ontapdevice_json(struct json_object *devices, char *devname,
|
|||
json_object_add_value_string(device_attrs, "Namespace_Path", nspath);
|
||||
json_object_add_value_int(device_attrs, "NSID", nsid);
|
||||
json_object_add_value_string(device_attrs, "UUID", uuid);
|
||||
json_object_add_value_string(device_attrs, "Size", size);
|
||||
json_object_add_value_int(device_attrs, "LBA_Data_Size", lba);
|
||||
json_object_add_value_int(device_attrs, "Namespace_Size", nsze);
|
||||
json_object_add_value_uint64(device_attrs, "LBA_Size", lba);
|
||||
json_object_add_value_uint64(device_attrs, "Namespace_Size", ns_size);
|
||||
json_object_add_value_uint64(device_attrs, "UsedBytes", used_size);
|
||||
json_object_add_value_string(device_attrs, "Version", version);
|
||||
|
||||
json_array_add_value_object(devices, device_attrs);
|
||||
}
|
||||
|
||||
static void netapp_smdevices_print_verbose(struct smdevice_info *devices,
|
||||
int count, int format, const char *devname)
|
||||
{
|
||||
int i, slta;
|
||||
char array_label[ARRAY_LABEL_LEN / 2 + 1];
|
||||
char volume_label[VOLUME_LABEL_LEN / 2 + 1];
|
||||
char nguid_str[33];
|
||||
unsigned long long lba;
|
||||
char size[128], used[128];
|
||||
char blk_size[128], version[9];
|
||||
|
||||
char *formatstr = NULL;
|
||||
char basestr[] =
|
||||
"%s, Array Name %s, Volume Name %s, NSID %d, Volume ID %s, "
|
||||
"Controller %c, Access State %s, Size %s, Format %s, Version %s\n";
|
||||
char columnstr[] =
|
||||
"%-16s %-30s %-30s %4d %32s %c %-12s %-9s %-9s %-9s\n";
|
||||
|
||||
if (format == NNORMAL)
|
||||
formatstr = basestr;
|
||||
else if (format == NCOLUMN) {
|
||||
/* print column headers and change the output string */
|
||||
printf("%-16s %-30s %-30s %-4s %-32s %-4s %-12s %-9s %-9s %-9s\n",
|
||||
"Device", "Array Name", "Volume Name", "NSID",
|
||||
"Volume ID", "Ctrl", "Access State", " Size",
|
||||
"Format", "Version");
|
||||
printf("%-16s %-30s %-30s %-4s %-32s %-4s %-12s %-9s %-9s %-9s\n",
|
||||
"----------------", "------------------------------",
|
||||
"------------------------------", "----",
|
||||
"--------------------------------", "----",
|
||||
"------------", "---------",
|
||||
"---------", "---------");
|
||||
formatstr = columnstr;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (devname && !strcmp(devname, basename(devices[i].dev))) {
|
||||
/* found the device, fetch info for that alone */
|
||||
netapp_get_ns_attrs(size, used, blk_size, version,
|
||||
&lba, &devices[i].ctrl, &devices[i].ns);
|
||||
netapp_convert_string(array_label,
|
||||
(char *)&devices[i].ctrl.vs[20],
|
||||
ARRAY_LABEL_LEN / 2);
|
||||
slta = devices[i].ctrl.vs[0] & 0x1;
|
||||
netapp_convert_string(volume_label,
|
||||
(char *)devices[i].ns.vs,
|
||||
VOLUME_LABEL_LEN / 2);
|
||||
netapp_nguid_to_str(nguid_str, devices[i].ns.nguid);
|
||||
|
||||
printf(formatstr, devices[i].dev, array_label,
|
||||
volume_label, devices[i].nsid,
|
||||
nguid_str,
|
||||
slta ? 'A' : 'B', "unknown", size,
|
||||
blk_size, version);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
/* fetch info and print for all devices */
|
||||
netapp_get_ns_attrs(size, used, blk_size, version,
|
||||
&lba, &devices[i].ctrl, &devices[i].ns);
|
||||
netapp_convert_string(array_label,
|
||||
(char *)&devices[i].ctrl.vs[20],
|
||||
ARRAY_LABEL_LEN / 2);
|
||||
slta = devices[i].ctrl.vs[0] & 0x1;
|
||||
netapp_convert_string(volume_label,
|
||||
(char *)devices[i].ns.vs,
|
||||
VOLUME_LABEL_LEN / 2);
|
||||
netapp_nguid_to_str(nguid_str, devices[i].ns.nguid);
|
||||
|
||||
printf(formatstr, devices[i].dev, array_label,
|
||||
volume_label, devices[i].nsid,
|
||||
nguid_str,
|
||||
slta ? 'A' : 'B', "unknown", size,
|
||||
blk_size, version);
|
||||
}
|
||||
}
|
||||
|
||||
static void netapp_smdevices_print_regular(struct smdevice_info *devices,
|
||||
int count, int format, const char *devname)
|
||||
{
|
||||
|
@ -258,7 +380,8 @@ static void netapp_smdevices_print_regular(struct smdevice_info *devices,
|
|||
char array_label[ARRAY_LABEL_LEN / 2 + 1];
|
||||
char volume_label[VOLUME_LABEL_LEN / 2 + 1];
|
||||
char nguid_str[33];
|
||||
__u8 lba_index;
|
||||
unsigned long long lba;
|
||||
char size[128];
|
||||
|
||||
char *formatstr = NULL;
|
||||
char basestr[] =
|
||||
|
@ -268,7 +391,7 @@ static void netapp_smdevices_print_regular(struct smdevice_info *devices,
|
|||
if (format == NNORMAL)
|
||||
formatstr = basestr;
|
||||
else if (format == NCOLUMN) {
|
||||
/* change output string and print column headers */
|
||||
/* print column headers and change the output string */
|
||||
printf("%-16s %-30s %-30s %-4s %-32s %-4s %-12s %-9s\n",
|
||||
"Device", "Array Name", "Volume Name", "NSID",
|
||||
"Volume ID", "Ctrl", "Access State", " Size");
|
||||
|
@ -283,15 +406,7 @@ static void netapp_smdevices_print_regular(struct smdevice_info *devices,
|
|||
for (i = 0; i < count; i++) {
|
||||
if (devname && !strcmp(devname, basename(devices[i].dev))) {
|
||||
/* found the device, fetch info for that alone */
|
||||
nvme_id_ns_flbas_to_lbaf_inuse(devices[i].ns.flbas,
|
||||
&lba_index);
|
||||
unsigned long long lba = 1ULL <<
|
||||
devices[i].ns.lbaf[lba_index].ds;
|
||||
double nsze = le64_to_cpu(devices[i].ns.nsze) * lba;
|
||||
const char *s_suffix = suffix_si_get(&nsze);
|
||||
char size[128];
|
||||
|
||||
sprintf(size, "%.2f%sB", nsze, s_suffix);
|
||||
netapp_get_ns_size(size, &lba, &devices[i].ns);
|
||||
netapp_convert_string(array_label,
|
||||
(char *)&devices[i].ctrl.vs[20],
|
||||
ARRAY_LABEL_LEN / 2);
|
||||
|
@ -311,14 +426,7 @@ static void netapp_smdevices_print_regular(struct smdevice_info *devices,
|
|||
|
||||
for (i = 0; i < count; i++) {
|
||||
/* fetch info for all devices */
|
||||
nvme_id_ns_flbas_to_lbaf_inuse(devices[i].ns.flbas, &lba_index);
|
||||
unsigned long long lba = 1ULL <<
|
||||
devices[i].ns.lbaf[lba_index].ds;
|
||||
double nsze = le64_to_cpu(devices[i].ns.nsze) * lba;
|
||||
const char *s_suffix = suffix_si_get(&nsze);
|
||||
char size[128];
|
||||
|
||||
sprintf(size, "%.2f%sB", nsze, s_suffix);
|
||||
netapp_get_ns_size(size, &lba, &devices[i].ns);
|
||||
netapp_convert_string(array_label,
|
||||
(char *)&devices[i].ctrl.vs[20],
|
||||
ARRAY_LABEL_LEN / 2);
|
||||
|
@ -342,7 +450,9 @@ static void netapp_smdevices_print_json(struct smdevice_info *devices,
|
|||
char array_label[ARRAY_LABEL_LEN / 2 + 1];
|
||||
char volume_label[VOLUME_LABEL_LEN / 2 + 1];
|
||||
char nguid_str[33];
|
||||
__u8 lba_index;
|
||||
unsigned long long lba;
|
||||
char size[128], used[128];
|
||||
char blk_size[128], version[9];
|
||||
|
||||
/* prepare for the json output */
|
||||
root = json_create_object();
|
||||
|
@ -351,15 +461,8 @@ static void netapp_smdevices_print_json(struct smdevice_info *devices,
|
|||
for (i = 0; i < count; i++) {
|
||||
if (devname && !strcmp(devname, basename(devices[i].dev))) {
|
||||
/* found the device, fetch info for that alone */
|
||||
nvme_id_ns_flbas_to_lbaf_inuse(devices[i].ns.flbas,
|
||||
&lba_index);
|
||||
unsigned long long lba = 1ULL <<
|
||||
devices[i].ns.lbaf[lba_index].ds;
|
||||
double nsze = le64_to_cpu(devices[i].ns.nsze) * lba;
|
||||
const char *s_suffix = suffix_si_get(&nsze);
|
||||
char size[128];
|
||||
|
||||
sprintf(size, "%.2f%sB", nsze, s_suffix);
|
||||
netapp_get_ns_attrs(size, used, blk_size, version,
|
||||
&lba, &devices[i].ctrl, &devices[i].ns);
|
||||
netapp_convert_string(array_label,
|
||||
(char *)&devices[i].ctrl.vs[20],
|
||||
ARRAY_LABEL_LEN / 2);
|
||||
|
@ -371,22 +474,18 @@ static void netapp_smdevices_print_json(struct smdevice_info *devices,
|
|||
netapp_smdevice_json(json_devices, devices[i].dev,
|
||||
array_label, volume_label,
|
||||
devices[i].nsid, nguid_str,
|
||||
slta ? "A" : "B", "unknown", size, lba,
|
||||
le64_to_cpu(devices[i].ns.nsze));
|
||||
slta ? "A" : "B", "unknown",
|
||||
version, lba,
|
||||
le64_to_cpu(devices[i].ns.nsze),
|
||||
le64_to_cpu(devices[i].ns.nuse));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
/* fetch info for all devices */
|
||||
nvme_id_ns_flbas_to_lbaf_inuse(devices[i].ns.flbas, &lba_index);
|
||||
unsigned long long lba = 1ULL <<
|
||||
devices[i].ns.lbaf[lba_index].ds;
|
||||
double nsze = le64_to_cpu(devices[i].ns.nsze) * lba;
|
||||
const char *s_suffix = suffix_si_get(&nsze);
|
||||
char size[128];
|
||||
|
||||
sprintf(size, "%.2f%sB", nsze, s_suffix);
|
||||
netapp_get_ns_attrs(size, used, blk_size, version,
|
||||
&lba, &devices[i].ctrl, &devices[i].ns);
|
||||
netapp_convert_string(array_label,
|
||||
(char *)&devices[i].ctrl.vs[20],
|
||||
ARRAY_LABEL_LEN / 2);
|
||||
|
@ -398,7 +497,9 @@ static void netapp_smdevices_print_json(struct smdevice_info *devices,
|
|||
netapp_smdevice_json(json_devices, devices[i].dev,
|
||||
array_label, volume_label, devices[i].nsid,
|
||||
nguid_str, slta ? "A" : "B", "unknown",
|
||||
size, lba, le64_to_cpu(devices[i].ns.nsze));
|
||||
version, lba,
|
||||
le64_to_cpu(devices[i].ns.nsze),
|
||||
le64_to_cpu(devices[i].ns.nuse));
|
||||
}
|
||||
|
||||
out:
|
||||
|
@ -409,6 +510,67 @@ out:
|
|||
json_free_object(root);
|
||||
}
|
||||
|
||||
static void netapp_ontapdevices_print_verbose(struct ontapdevice_info *devices,
|
||||
int count, int format, const char *devname)
|
||||
{
|
||||
char vsname[ONTAP_LABEL_LEN] = " ";
|
||||
char nspath[ONTAP_NS_PATHLEN] = " ";
|
||||
unsigned long long lba;
|
||||
char size[128], used[128];
|
||||
char blk_size[128], version[9];
|
||||
char uuid_str[37] = " ";
|
||||
int i;
|
||||
|
||||
char *formatstr = NULL;
|
||||
char basestr[] =
|
||||
"%s, Vserver %s, Namespace Path %s, NSID %d, UUID %s, "
|
||||
"Size %s, Used %s, Format %s, Version %s\n";
|
||||
char columnstr[] = "%-16s %-25s %-50s %-4d %-38s %-9s %-9s %-9s %-9s\n";
|
||||
|
||||
if (format == NNORMAL)
|
||||
formatstr = basestr;
|
||||
else if (format == NCOLUMN) {
|
||||
printf("%-16s %-25s %-50s %-4s %-38s %-9s %-9s %-9s %-9s\n",
|
||||
"Device", "Vserver", "Namespace Path",
|
||||
"NSID", "UUID", "Size", "Used",
|
||||
"Format", "Version");
|
||||
printf("%-16s %-25s %-50s %-4s %-38s %-9s %-9s %-9s %-9s\n",
|
||||
"----------------", "-------------------------",
|
||||
"--------------------------------------------------",
|
||||
"----", "--------------------------------------",
|
||||
"---------", "---------", "---------", "---------");
|
||||
formatstr = columnstr;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (devname && !strcmp(devname, basename(devices[i].dev))) {
|
||||
/* found the device, fetch and print for that alone */
|
||||
netapp_get_ns_attrs(size, used, blk_size, version,
|
||||
&lba, &devices[i].ctrl, &devices[i].ns);
|
||||
nvme_uuid_to_string(devices[i].uuid, uuid_str);
|
||||
netapp_get_ontap_labels(vsname, nspath,
|
||||
devices[i].log_data);
|
||||
|
||||
printf(formatstr, devices[i].dev, vsname, nspath,
|
||||
devices[i].nsid, uuid_str, size, used,
|
||||
blk_size, version);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
/* fetch info and print for all devices */
|
||||
netapp_get_ns_attrs(size, used, blk_size, version,
|
||||
&lba, &devices[i].ctrl, &devices[i].ns);
|
||||
nvme_uuid_to_string(devices[i].uuid, uuid_str);
|
||||
netapp_get_ontap_labels(vsname, nspath, devices[i].log_data);
|
||||
|
||||
printf(formatstr, devices[i].dev, vsname, nspath,
|
||||
devices[i].nsid, uuid_str, size, used,
|
||||
blk_size, version);
|
||||
}
|
||||
}
|
||||
|
||||
static void netapp_ontapdevices_print_regular(struct ontapdevice_info *devices,
|
||||
int count, int format, const char *devname)
|
||||
{
|
||||
|
@ -471,7 +633,8 @@ static void netapp_ontapdevices_print_json(struct ontapdevice_info *devices,
|
|||
char vsname[ONTAP_LABEL_LEN] = " ";
|
||||
char nspath[ONTAP_NS_PATHLEN] = " ";
|
||||
unsigned long long lba;
|
||||
char size[128];
|
||||
char size[128], used[128];
|
||||
char blk_size[128], version[9];
|
||||
char uuid_str[37] = " ";
|
||||
int i;
|
||||
|
||||
|
@ -482,28 +645,33 @@ static void netapp_ontapdevices_print_json(struct ontapdevice_info *devices,
|
|||
for (i = 0; i < count; i++) {
|
||||
if (devname && !strcmp(devname, basename(devices[i].dev))) {
|
||||
/* found the device, fetch info for that alone */
|
||||
netapp_get_ns_size(size, &lba, &devices[i].ns);
|
||||
netapp_get_ns_attrs(size, used, blk_size, version,
|
||||
&lba, &devices[i].ctrl, &devices[i].ns);
|
||||
nvme_uuid_to_string(devices[i].uuid, uuid_str);
|
||||
netapp_get_ontap_labels(vsname, nspath, devices[i].log_data);
|
||||
netapp_get_ontap_labels(vsname, nspath,
|
||||
devices[i].log_data);
|
||||
|
||||
netapp_ontapdevice_json(json_devices, devices[i].dev,
|
||||
vsname, nspath, devices[i].nsid,
|
||||
uuid_str, size, lba,
|
||||
le64_to_cpu(devices[i].ns.nsze));
|
||||
uuid_str, lba, version,
|
||||
le64_to_cpu(devices[i].ns.nsze),
|
||||
le64_to_cpu(devices[i].ns.nuse));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
/* fetch info for all devices */
|
||||
netapp_get_ns_size(size, &lba, &devices[i].ns);
|
||||
netapp_get_ns_attrs(size, used, blk_size, version,
|
||||
&lba, &devices[i].ctrl, &devices[i].ns);
|
||||
nvme_uuid_to_string(devices[i].uuid, uuid_str);
|
||||
netapp_get_ontap_labels(vsname, nspath, devices[i].log_data);
|
||||
|
||||
netapp_ontapdevice_json(json_devices, devices[i].dev,
|
||||
vsname, nspath, devices[i].nsid,
|
||||
uuid_str, size, lba,
|
||||
le64_to_cpu(devices[i].ns.nsze));
|
||||
uuid_str, lba, version,
|
||||
le64_to_cpu(devices[i].ns.nsze),
|
||||
le64_to_cpu(devices[i].ns.nuse));
|
||||
}
|
||||
|
||||
out:
|
||||
|
@ -663,8 +831,10 @@ static int netapp_output_format(char *format)
|
|||
return -EINVAL;
|
||||
if (!strcmp(format, "normal"))
|
||||
return NNORMAL;
|
||||
#ifdef CONFIG_JSONC
|
||||
if (!strcmp(format, "json"))
|
||||
return NJSON;
|
||||
#endif /* CONFIG_JSONC */
|
||||
if (!strcmp(format, "column"))
|
||||
return NCOLUMN;
|
||||
return -EINVAL;
|
||||
|
@ -684,6 +854,7 @@ static int netapp_smdevices(int argc, char **argv, struct command *command,
|
|||
int num_smdevices = 0;
|
||||
|
||||
struct config {
|
||||
bool verbose;
|
||||
char *output_format;
|
||||
};
|
||||
|
||||
|
@ -692,6 +863,7 @@ static int netapp_smdevices(int argc, char **argv, struct command *command,
|
|||
};
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
OPT_FLAG("verbose", 'v', &cfg.verbose, "Increase output verbosity"),
|
||||
OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json|column"),
|
||||
OPT_END()
|
||||
};
|
||||
|
@ -708,7 +880,7 @@ static int netapp_smdevices(int argc, char **argv, struct command *command,
|
|||
|
||||
num = scandir(dev_path, &devices, netapp_nvme_filter, alphasort);
|
||||
if (num <= 0) {
|
||||
fprintf(stderr, "No NVMe devices detected.\n");
|
||||
fprintf(stderr, "No smdevices detected\n");
|
||||
return num;
|
||||
}
|
||||
|
||||
|
@ -726,7 +898,7 @@ static int netapp_smdevices(int argc, char **argv, struct command *command,
|
|||
|
||||
smdevices = calloc(num, sizeof(*smdevices));
|
||||
if (!smdevices) {
|
||||
fprintf(stderr, "Unable to allocate memory for devices.\n");
|
||||
fprintf(stderr, "Unable to allocate memory for devices\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -746,9 +918,14 @@ static int netapp_smdevices(int argc, char **argv, struct command *command,
|
|||
}
|
||||
|
||||
if (num_smdevices) {
|
||||
if (fmt == NNORMAL || fmt == NCOLUMN)
|
||||
netapp_smdevices_print_regular(smdevices,
|
||||
num_smdevices, fmt, devname);
|
||||
if (fmt == NNORMAL || fmt == NCOLUMN) {
|
||||
if (argconfig_parse_seen(opts, "verbose"))
|
||||
netapp_smdevices_print_verbose(smdevices,
|
||||
num_smdevices, fmt, devname);
|
||||
else
|
||||
netapp_smdevices_print_regular(smdevices,
|
||||
num_smdevices, fmt, devname);
|
||||
}
|
||||
else if (fmt == NJSON)
|
||||
netapp_smdevices_print_json(smdevices,
|
||||
num_smdevices, devname);
|
||||
|
@ -775,6 +952,7 @@ static int netapp_ontapdevices(int argc, char **argv, struct command *command,
|
|||
int num_ontapdevices = 0;
|
||||
|
||||
struct config {
|
||||
bool verbose;
|
||||
char *output_format;
|
||||
};
|
||||
|
||||
|
@ -783,6 +961,7 @@ static int netapp_ontapdevices(int argc, char **argv, struct command *command,
|
|||
};
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
OPT_FLAG("verbose", 'v', &cfg.verbose, "Increase output verbosity"),
|
||||
OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json|column"),
|
||||
OPT_END()
|
||||
};
|
||||
|
@ -811,13 +990,13 @@ static int netapp_ontapdevices(int argc, char **argv, struct command *command,
|
|||
|
||||
num = scandir(dev_path, &devices, netapp_nvme_filter, alphasort);
|
||||
if (num <= 0) {
|
||||
fprintf(stderr, "No NVMe devices detected.\n");
|
||||
fprintf(stderr, "No ontapdevices detected\n");
|
||||
return num;
|
||||
}
|
||||
|
||||
ontapdevices = calloc(num, sizeof(*ontapdevices));
|
||||
if (!ontapdevices) {
|
||||
fprintf(stderr, "Unable to allocate memory for devices.\n");
|
||||
fprintf(stderr, "Unable to allocate memory for devices\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -838,9 +1017,14 @@ static int netapp_ontapdevices(int argc, char **argv, struct command *command,
|
|||
}
|
||||
|
||||
if (num_ontapdevices) {
|
||||
if (fmt == NNORMAL || fmt == NCOLUMN)
|
||||
netapp_ontapdevices_print_regular(ontapdevices,
|
||||
num_ontapdevices, fmt, devname);
|
||||
if (fmt == NNORMAL || fmt == NCOLUMN) {
|
||||
if (argconfig_parse_seen(opts, "verbose"))
|
||||
netapp_ontapdevices_print_verbose(ontapdevices,
|
||||
num_ontapdevices, fmt, devname);
|
||||
else
|
||||
netapp_ontapdevices_print_regular(ontapdevices,
|
||||
num_ontapdevices, fmt, devname);
|
||||
}
|
||||
else if (fmt == NJSON)
|
||||
netapp_ontapdevices_print_json(ontapdevices,
|
||||
num_ontapdevices, devname);
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include "util/types.h"
|
||||
#include "ocp-nvme.h"
|
||||
#include "ocp-utils.h"
|
||||
#include "nvme-print.h"
|
||||
|
||||
static const __u8 OCP_FID_CLEAR_FW_ACTIVATION_HISTORY = 0xC1;
|
||||
static const __u8 OCP_FID_CLEAR_PCIE_CORRECTABLE_ERROR_COUNTERS = 0xC3;
|
||||
|
||||
static int ocp_clear_feature(int argc, char **argv, const char *desc, const __u8 fid)
|
||||
{
|
||||
__u32 result = 0;
|
||||
|
@ -80,14 +79,13 @@ int ocp_clear_fw_update_history(int argc, char **argv, struct command *cmd, stru
|
|||
{
|
||||
const char *desc = "OCP Clear Firmware Update History";
|
||||
|
||||
return ocp_clear_feature(argc, argv, desc, OCP_FID_CLEAR_FW_ACTIVATION_HISTORY);
|
||||
return ocp_clear_feature(argc, argv, desc, OCP_FID_CFUH);
|
||||
}
|
||||
|
||||
int ocp_clear_pcie_correctable_errors(int argc, char **argv, struct command *cmd,
|
||||
struct plugin *plugin)
|
||||
struct plugin *plugin)
|
||||
{
|
||||
const char *desc = "OCP Clear PCIe Correctable Error Counters";
|
||||
|
||||
return ocp_clear_feature(argc, argv, desc,
|
||||
OCP_FID_CLEAR_PCIE_CORRECTABLE_ERROR_COUNTERS);
|
||||
return ocp_clear_feature(argc, argv, desc, OCP_FID_CPCIE);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "common.h"
|
||||
#include "nvme-print.h"
|
||||
|
||||
#include "ocp-nvme.h"
|
||||
#include "ocp-utils.h"
|
||||
#include "ocp-print.h"
|
||||
|
||||
|
@ -26,7 +27,6 @@ static const unsigned char ocp_fw_activation_history_guid[GUID_LEN] = {
|
|||
int ocp_fw_activation_history_log(int argc, char **argv, struct command *cmd,
|
||||
struct plugin *plugin)
|
||||
{
|
||||
const __u8 log_id = 0xC2;
|
||||
const char *description = "Retrieves the OCP firmware activation history log.";
|
||||
|
||||
char *format = "normal";
|
||||
|
@ -59,7 +59,7 @@ int ocp_fw_activation_history_log(int argc, char **argv, struct command *cmd,
|
|||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
|
||||
.lid = log_id,
|
||||
.lid = (enum nvme_cmd_get_log_lid)OCP_LID_FAHL_OBSOLETE,
|
||||
.len = sizeof(fw_history),
|
||||
.nsid = NVME_NSID_ALL,
|
||||
.csi = NVME_CSI_NVM,
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
*
|
||||
* Authors: karl.dedow@solidigm.com
|
||||
*/
|
||||
#include <libnvme.h>
|
||||
#include "common.h"
|
||||
#include "linux/types.h"
|
||||
|
||||
|
@ -18,7 +19,7 @@ struct __packed fw_activation_history_entry {
|
|||
__u8 entry_length;
|
||||
__le16 reserved1;
|
||||
__le16 activation_count;
|
||||
__le64 timestamp;
|
||||
struct nvme_timestamp ts;
|
||||
__le64 reserved2;
|
||||
__le64 power_cycle_count;
|
||||
char previous_fw[8];
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "nvme-print.h"
|
||||
#include "ocp-hardware-component-log.h"
|
||||
#include "ocp-print.h"
|
||||
#include "ocp-utils.h"
|
||||
|
||||
//#define HWCOMP_DUMMY
|
||||
|
||||
|
@ -154,6 +155,8 @@ const char *hwcomp_id_to_string(__u32 id)
|
|||
return "Country of Origin";
|
||||
case HWCOMP_ID_HW_REV:
|
||||
return "Global Device Hardware Revision";
|
||||
case HWCOMP_ID_BORN_ON_DATE:
|
||||
return "Born on Date";
|
||||
case HWCOMP_ID_VENDOR ... HWCOMP_ID_MAX:
|
||||
return "Vendor Unique Component";
|
||||
case HWCOMP_ID_RSVD:
|
||||
|
@ -168,39 +171,59 @@ static int get_hwcomp_log_data(struct nvme_dev *dev, struct hwcomp_log *log)
|
|||
{
|
||||
int ret = 0;
|
||||
size_t desc_offset = offsetof(struct hwcomp_log, desc);
|
||||
long double log_bytes;
|
||||
nvme_uint128_t log_size;
|
||||
|
||||
struct nvme_get_log_args args = {
|
||||
.lpo = desc_offset,
|
||||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
|
||||
.lid = LID_HWCOMP,
|
||||
.lid = (enum nvme_cmd_get_log_lid)OCP_LID_HWCOMP,
|
||||
.nsid = NVME_NSID_ALL,
|
||||
.log = log,
|
||||
.len = desc_offset,
|
||||
};
|
||||
|
||||
ocp_get_uuid_index(dev, &args.uuidx);
|
||||
|
||||
#ifdef HWCOMP_DUMMY
|
||||
memcpy(log, hwcomp_dummy, desc_offset);
|
||||
#else /* HWCOMP_DUMMY */
|
||||
ret = nvme_get_log_simple(dev_fd(dev), LID_HWCOMP, desc_offset, log);
|
||||
ret = nvme_get_log_page(dev_fd(dev), NVME_LOG_PAGE_PDU_SIZE, &args);
|
||||
if (ret) {
|
||||
print_info_error("error: ocp: failed to get log simple (hwcomp: %02X, ret: %d)\n",
|
||||
LID_HWCOMP, ret);
|
||||
print_info_error("error: ocp: failed to get hwcomp log size (ret: %d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
#endif /* HWCOMP_DUMMY */
|
||||
|
||||
print_info("id: %02Xh\n", LID_HWCOMP);
|
||||
log_size = le128_to_cpu(log->size);
|
||||
|
||||
print_info("id: %02Xh\n", OCP_LID_HWCOMP);
|
||||
print_info("version: %04Xh\n", log->ver);
|
||||
print_info_array("guid", log->guid, ARRAY_SIZE(log->guid));
|
||||
print_info("size: %s\n", uint128_t_to_string(le128_to_cpu(log->size)));
|
||||
print_info("size: %s\n", uint128_t_to_string(log_size));
|
||||
|
||||
log_bytes = uint128_t_to_double(log_size);
|
||||
if (log->ver == 1)
|
||||
log_bytes *= sizeof(__le32);
|
||||
|
||||
if (log_bytes <= desc_offset) {
|
||||
print_info_error("error: ocp: invalid hwcomp log size bytes: %.0Lf\n", log_bytes);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
args.len = log_bytes - desc_offset;
|
||||
|
||||
print_info("args.len: %u\n", args.len);
|
||||
|
||||
args.len = uint128_t_to_double(le128_to_cpu(log->size)) * sizeof(__le32);
|
||||
log->desc = calloc(1, args.len);
|
||||
if (!log->desc) {
|
||||
fprintf(stderr, "error: ocp: calloc: %s\n", strerror(errno));
|
||||
return -1;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
args.log = log->desc,
|
||||
args.lpo = desc_offset,
|
||||
|
||||
#ifdef HWCOMP_DUMMY
|
||||
memcpy(log->desc, &hwcomp_dummy[desc_offset], args.len);
|
||||
|
@ -208,7 +231,8 @@ static int get_hwcomp_log_data(struct nvme_dev *dev, struct hwcomp_log *log)
|
|||
ret = nvme_get_log_page(dev_fd(dev), NVME_LOG_PAGE_PDU_SIZE, &args);
|
||||
if (ret) {
|
||||
print_info_error("error: ocp: failed to get log page (hwcomp: %02X, ret: %d)\n",
|
||||
LID_HWCOMP, ret);
|
||||
OCP_LID_HWCOMP, ret);
|
||||
free(log->desc);
|
||||
return ret;
|
||||
}
|
||||
#endif /* HWCOMP_DUMMY */
|
||||
|
@ -218,12 +242,10 @@ static int get_hwcomp_log_data(struct nvme_dev *dev, struct hwcomp_log *log)
|
|||
|
||||
static int get_hwcomp_log(struct nvme_dev *dev, __u32 id, bool list)
|
||||
{
|
||||
_cleanup_free_ __u8 *desc = NULL;
|
||||
|
||||
int ret;
|
||||
nvme_print_flags_t fmt;
|
||||
struct hwcomp_log log = {
|
||||
.desc = (struct hwcomp_desc *)desc,
|
||||
.desc = NULL,
|
||||
};
|
||||
|
||||
ret = validate_output_format(nvme_cfg.output_format, &fmt);
|
||||
|
@ -235,12 +257,14 @@ static int get_hwcomp_log(struct nvme_dev *dev, __u32 id, bool list)
|
|||
ret = get_hwcomp_log_data(dev, &log);
|
||||
if (ret) {
|
||||
print_info_error("error: ocp: failed get hwcomp log: %02X data, ret: %d\n",
|
||||
LID_HWCOMP, ret);
|
||||
OCP_LID_HWCOMP, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ocp_show_hwcomp_log(&log, id, list, fmt);
|
||||
|
||||
free(log.desc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -268,6 +292,7 @@ int ocp_hwcomp_log(int argc, char **argv, struct command *cmd, struct plugin *pl
|
|||
VAL_LONG("sn", HWCOMP_ID_SN),
|
||||
VAL_LONG("country", HWCOMP_ID_COUNTRY),
|
||||
VAL_LONG("hw-rev", HWCOMP_ID_HW_REV),
|
||||
VAL_LONG("born-on-date", HWCOMP_ID_BORN_ON_DATE),
|
||||
VAL_LONG("vendor", HWCOMP_ID_VENDOR),
|
||||
VAL_END()
|
||||
};
|
||||
|
@ -281,8 +306,8 @@ int ocp_hwcomp_log(int argc, char **argv, struct command *cmd, struct plugin *pl
|
|||
|
||||
ret = get_hwcomp_log(dev, cfg.id, cfg.list);
|
||||
if (ret)
|
||||
fprintf(stderr, "error: ocp: failed to get hwcomp log: %02X, ret: %d\n", LID_HWCOMP,
|
||||
ret);
|
||||
fprintf(stderr, "error: ocp: failed to get hwcomp log: %02X, ret: %d\n",
|
||||
OCP_LID_HWCOMP, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#ifndef OCP_HARDWARE_COMPONENT_LOG_H
|
||||
#define OCP_HARDWARE_COMPONENT_LOG_H
|
||||
|
||||
#define LID_HWCOMP 0xc6
|
||||
#define HWCOMP_RSVD2_LEN 14
|
||||
#define HWCOMP_SIZE_LEN 16
|
||||
#define HWCOMP_RSVD48_LEN 16
|
||||
|
@ -54,6 +53,7 @@ enum hwcomp_id {
|
|||
HWCOMP_ID_SN,
|
||||
HWCOMP_ID_COUNTRY,
|
||||
HWCOMP_ID_HW_REV,
|
||||
HWCOMP_ID_BORN_ON_DATE,
|
||||
HWCOMP_ID_VENDOR = 0x8000,
|
||||
HWCOMP_ID_MAX = 0xffff,
|
||||
};
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "ocp-telemetry-decode.h"
|
||||
#include "ocp-hardware-component-log.h"
|
||||
#include "ocp-print.h"
|
||||
#include "ocp-types.h"
|
||||
|
||||
#define CREATE_CMD
|
||||
#include "ocp-nvme.h"
|
||||
|
@ -44,8 +45,6 @@
|
|||
/// Latency Monitor Log
|
||||
|
||||
#define C3_LATENCY_MON_LOG_BUF_LEN 0x200
|
||||
#define C3_LATENCY_MON_OPCODE 0xC3
|
||||
#define NVME_FEAT_OCP_LATENCY_MONITOR 0xC5
|
||||
|
||||
static __u8 lat_mon_guid[GUID_LEN] = {
|
||||
0x92, 0x7a, 0xc0, 0x8c,
|
||||
|
@ -104,6 +103,17 @@ enum erri_type {
|
|||
ERRI_TYPE_HW_MALFUNCTION,
|
||||
ERRI_TYPE_NO_MORE_NAND_SPARES,
|
||||
ERRI_TYPE_INCOMPLETE_SHUTDOWN,
|
||||
ERRI_TYPE_METADATA_CORRUPTION,
|
||||
ERRI_TYPE_CRITICAL_GC,
|
||||
ERRI_TYPE_LATENCY_SPIKE,
|
||||
ERRI_TYPE_IO_CMD_FAILURE,
|
||||
ERRI_TYPE_IO_CMD_TIMEOUT,
|
||||
ERRI_TYPE_ADMIN_CMD_FAILURE,
|
||||
ERRI_TYPE_ADMIN_CMD_TIMEOUT,
|
||||
ERRI_TYPE_THERMAL_THROTTLE_ENGAGED,
|
||||
ERRI_TYPE_THERMAL_THROTTLE_DISENGAGED,
|
||||
ERRI_TYPE_CRITICAL_TEMPERATURE_EVENT,
|
||||
ERRI_TYPE_DIE_OFFLINE,
|
||||
};
|
||||
|
||||
const char *erri_type_to_string(__le16 type)
|
||||
|
@ -131,6 +141,28 @@ const char *erri_type_to_string(__le16 type)
|
|||
return "no more NAND spares available";
|
||||
case ERRI_TYPE_INCOMPLETE_SHUTDOWN:
|
||||
return "incomplete shutdown";
|
||||
case ERRI_TYPE_METADATA_CORRUPTION:
|
||||
return "Metadata Corruption";
|
||||
case ERRI_TYPE_CRITICAL_GC:
|
||||
return "Critical Garbage Collection";
|
||||
case ERRI_TYPE_LATENCY_SPIKE:
|
||||
return "Latency Spike";
|
||||
case ERRI_TYPE_IO_CMD_FAILURE:
|
||||
return "I/O command failure";
|
||||
case ERRI_TYPE_IO_CMD_TIMEOUT:
|
||||
return "I/O command timeout";
|
||||
case ERRI_TYPE_ADMIN_CMD_FAILURE:
|
||||
return "Admin command failure";
|
||||
case ERRI_TYPE_ADMIN_CMD_TIMEOUT:
|
||||
return "Admin command timeout";
|
||||
case ERRI_TYPE_THERMAL_THROTTLE_ENGAGED:
|
||||
return "Thermal Throttle Engaged";
|
||||
case ERRI_TYPE_THERMAL_THROTTLE_DISENGAGED:
|
||||
return "Thermal Throttle Disengaged";
|
||||
case ERRI_TYPE_CRITICAL_TEMPERATURE_EVENT:
|
||||
return "Critical Temperature Event";
|
||||
case ERRI_TYPE_DIE_OFFLINE:
|
||||
return "Die Offline";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -161,6 +193,8 @@ const char *data = "Error injection data structure entries";
|
|||
const char *number = "Number of valid error injection data entries";
|
||||
static const char *type = "Error injection type";
|
||||
static const char *nrtdp = "Number of reads to trigger device panic";
|
||||
static const char *save = "Specifies that the controller shall save the attribute";
|
||||
static const char *enable_ieee1667_silo = "enable IEEE1667 silo";
|
||||
|
||||
static int get_c3_log_page(struct nvme_dev *dev, char *format)
|
||||
{
|
||||
|
@ -183,8 +217,7 @@ static int get_c3_log_page(struct nvme_dev *dev, char *format)
|
|||
}
|
||||
memset(data, 0, sizeof(__u8) * C3_LATENCY_MON_LOG_BUF_LEN);
|
||||
|
||||
ret = nvme_get_log_simple(dev_fd(dev), C3_LATENCY_MON_OPCODE,
|
||||
C3_LATENCY_MON_LOG_BUF_LEN, data);
|
||||
ret = ocp_get_log_simple(dev, OCP_LID_LMLOG, C3_LATENCY_MON_LOG_BUF_LEN, data);
|
||||
|
||||
if (strcmp(format, "json"))
|
||||
fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret, false), ret);
|
||||
|
@ -305,7 +338,7 @@ int ocp_set_latency_monitor_feature(int argc, char **argv, struct command *cmd,
|
|||
.active_latency_minimum_window = 0xA,
|
||||
.debug_log_trigger_enable = 0,
|
||||
.discard_debug_log = 0,
|
||||
.latency_monitor_feature_enable = 0x7,
|
||||
.latency_monitor_feature_enable = 0x1,
|
||||
};
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
|
@ -356,7 +389,7 @@ int ocp_set_latency_monitor_feature(int argc, char **argv, struct command *cmd,
|
|||
struct nvme_set_features_args args = {
|
||||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.fid = NVME_FEAT_OCP_LATENCY_MONITOR,
|
||||
.fid = OCP_FID_LM,
|
||||
.nsid = 0,
|
||||
.cdw12 = 0,
|
||||
.save = 1,
|
||||
|
@ -370,7 +403,7 @@ int ocp_set_latency_monitor_feature(int argc, char **argv, struct command *cmd,
|
|||
if (err < 0) {
|
||||
perror("set-feature");
|
||||
} else if (!err) {
|
||||
printf("NVME_FEAT_OCP_LATENCY_MONITOR: 0x%02x\n", NVME_FEAT_OCP_LATENCY_MONITOR);
|
||||
printf("NVME_FEAT_OCP_LATENCY_MONITOR: 0x%02x\n", OCP_FID_LM);
|
||||
printf("active bucket timer threshold: 0x%x\n",
|
||||
le16_to_cpu(buf.active_bucket_timer_threshold));
|
||||
printf("active threshold a: 0x%x\n", buf.active_threshold_a);
|
||||
|
@ -511,10 +544,8 @@ static int eol_plp_failure_mode(int argc, char **argv, struct command *cmd,
|
|||
const char *desc = "Define EOL or PLP circuitry failure mode.\n"
|
||||
"No argument prints current mode.";
|
||||
const char *mode = "[0-3]: default/rom/wtm/normal";
|
||||
const char *save = "Specifies that the controller shall save the attribute";
|
||||
const char *sel = "[0-3]: current/default/saved/supported";
|
||||
const __u32 nsid = 0;
|
||||
const __u8 fid = 0xc2;
|
||||
const __u8 fid = OCP_FID_ROWTM;
|
||||
struct nvme_dev *dev;
|
||||
int err;
|
||||
|
||||
|
@ -1252,8 +1283,7 @@ static int get_c9_log_page_data(struct nvme_dev *dev, int print_data, int save_b
|
|||
}
|
||||
memset(header_data, 0, sizeof(__u8) * C9_TELEMETRY_STR_LOG_LEN);
|
||||
|
||||
ret = nvme_get_log_simple(dev_fd(dev), C9_TELEMETRY_STRING_LOG_ENABLE_OPCODE,
|
||||
C9_TELEMETRY_STR_LOG_LEN, header_data);
|
||||
ret = ocp_get_log_simple(dev, OCP_LID_TELSLG, C9_TELEMETRY_STR_LOG_LEN, header_data);
|
||||
|
||||
if (!ret) {
|
||||
log_data = (struct telemetry_str_log_format *)header_data;
|
||||
|
@ -1295,8 +1325,7 @@ static int get_c9_log_page_data(struct nvme_dev *dev, int print_data, int save_b
|
|||
}
|
||||
memset(pC9_string_buffer, 0, sizeof(__u8) * total_log_page_sz);
|
||||
|
||||
ret = nvme_get_log_simple(dev_fd(dev), C9_TELEMETRY_STRING_LOG_ENABLE_OPCODE,
|
||||
total_log_page_sz, pC9_string_buffer);
|
||||
ret = ocp_get_log_simple(dev, OCP_LID_TELSLG, total_log_page_sz, pC9_string_buffer);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR : OCP : Unable to read C9 data.\n");
|
||||
}
|
||||
|
@ -1385,7 +1414,7 @@ static int ocp_telemetry_log(int argc, char **argv, struct command *cmd, struct
|
|||
const char *output_format = "output format normal|json";
|
||||
const char *data_area = "Telemetry Data Area; 1 or 2;\n"
|
||||
"e.g. '-a 1 for Data Area 1.'\n'-a 2 for Data Areas 1 and 2.';\n";
|
||||
const char *telemetry_type = "Telemetry Type; 'host' or 'controller'";
|
||||
const char *telemetry_type = "Telemetry Type; 'host', 'host0', 'host1' or 'controller'";
|
||||
|
||||
struct nvme_dev *dev;
|
||||
int err = 0;
|
||||
|
@ -1453,7 +1482,8 @@ static int ocp_telemetry_log(int argc, char **argv, struct command *cmd, struct
|
|||
else if (!strcmp(opt.telemetry_type, "controller"))
|
||||
tele_type = TELEMETRY_TYPE_CONTROLLER;
|
||||
else {
|
||||
nvme_show_error("telemetry-type should be host or controller.\n");
|
||||
nvme_show_error(
|
||||
"telemetry-type should be host, host0, host1 or controller.\n");
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
|
@ -1504,60 +1534,6 @@ static int ocp_telemetry_log(int argc, char **argv, struct command *cmd, struct
|
|||
nvme_show_result("Status:(%x)\n", err);
|
||||
}
|
||||
break;
|
||||
case TELEMETRY_TYPE_NONE:
|
||||
printf("\n-------------------------------------------------------------\n");
|
||||
/* Host 0 (lsp == 0) must be executed before Host 1 (lsp == 1). */
|
||||
printf("\nExtracting Telemetry Host 0 Dump (Data Area 1)...\n");
|
||||
|
||||
err = get_telemetry_dump(dev, opt.output_file, sn,
|
||||
TELEMETRY_TYPE_HOST_0, 1, true);
|
||||
if (err)
|
||||
fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false),
|
||||
err);
|
||||
|
||||
printf("\n-------------------------------------------------------------\n");
|
||||
|
||||
printf("\nExtracting Telemetry Host 0 Dump (Data Area 3)...\n");
|
||||
|
||||
err = get_telemetry_dump(dev, opt.output_file, sn,
|
||||
TELEMETRY_TYPE_HOST_0, 3, false);
|
||||
if (err)
|
||||
fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false),
|
||||
err);
|
||||
|
||||
printf("\n-------------------------------------------------------------\n");
|
||||
|
||||
printf("\nExtracting Telemetry Host 1 Dump (Data Area 1)...\n");
|
||||
|
||||
err = get_telemetry_dump(dev, opt.output_file, sn,
|
||||
TELEMETRY_TYPE_HOST_1, 1, true);
|
||||
if (err)
|
||||
fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false),
|
||||
err);
|
||||
|
||||
printf("\n-------------------------------------------------------------\n");
|
||||
|
||||
printf("\nExtracting Telemetry Host 1 Dump (Data Area 3)...\n");
|
||||
|
||||
err = get_telemetry_dump(dev, opt.output_file, sn,
|
||||
TELEMETRY_TYPE_HOST_1, 3, false);
|
||||
if (err)
|
||||
fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false),
|
||||
err);
|
||||
|
||||
printf("\n-------------------------------------------------------------\n");
|
||||
|
||||
printf("\nExtracting Telemetry Controller Dump (Data Area 3)...\n");
|
||||
|
||||
if (is_support_telemetry_controller == true) {
|
||||
err = get_telemetry_dump(dev, opt.output_file, sn,
|
||||
TELEMETRY_TYPE_CONTROLLER, 3, true);
|
||||
if (err)
|
||||
fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err);
|
||||
}
|
||||
|
||||
printf("\n-------------------------------------------------------------\n");
|
||||
break;
|
||||
case TELEMETRY_TYPE_HOST_0:
|
||||
case TELEMETRY_TYPE_HOST_1:
|
||||
default:
|
||||
|
@ -1585,7 +1561,6 @@ out:
|
|||
|
||||
/* C5 Unsupported Requirement Log Page */
|
||||
#define C5_UNSUPPORTED_REQS_LEN 4096
|
||||
#define C5_UNSUPPORTED_REQS_OPCODE 0xC5
|
||||
|
||||
static __u8 unsupported_req_guid[GUID_LEN] = {
|
||||
0x2F, 0x72, 0x9C, 0x0E,
|
||||
|
@ -1620,8 +1595,7 @@ static int get_c5_log_page(struct nvme_dev *dev, char *format)
|
|||
}
|
||||
memset(data, 0, sizeof(__u8) * C5_UNSUPPORTED_REQS_LEN);
|
||||
|
||||
ret = nvme_get_log_simple(dev_fd(dev), C5_UNSUPPORTED_REQS_OPCODE,
|
||||
C5_UNSUPPORTED_REQS_LEN, data);
|
||||
ret = ocp_get_log_simple(dev, OCP_LID_URLP, C5_UNSUPPORTED_REQS_LEN, data);
|
||||
if (!ret) {
|
||||
log_data = (struct unsupported_requirement_log *)data;
|
||||
|
||||
|
@ -1693,7 +1667,6 @@ static int ocp_unsupported_requirements_log(int argc, char **argv, struct comman
|
|||
/// Error Recovery Log Page(0xC1)
|
||||
|
||||
#define C1_ERROR_RECOVERY_LOG_BUF_LEN 0x200
|
||||
#define C1_ERROR_RECOVERY_OPCODE 0xC1
|
||||
|
||||
static __u8 error_recovery_guid[GUID_LEN] = {
|
||||
0x44, 0xd9, 0x31, 0x21,
|
||||
|
@ -1726,7 +1699,7 @@ static int get_c1_log_page(struct nvme_dev *dev, char *format)
|
|||
}
|
||||
memset(data, 0, sizeof(__u8) * C1_ERROR_RECOVERY_LOG_BUF_LEN);
|
||||
|
||||
ret = nvme_get_log_simple(dev_fd(dev), C1_ERROR_RECOVERY_OPCODE, C1_ERROR_RECOVERY_LOG_BUF_LEN, data);
|
||||
ret = ocp_get_log_simple(dev, OCP_LID_EREC, C1_ERROR_RECOVERY_LOG_BUF_LEN, data);
|
||||
|
||||
if (!ret) {
|
||||
log_data = (struct ocp_error_recovery_log_page *)data;
|
||||
|
@ -1797,7 +1770,6 @@ static int ocp_error_recovery_log(int argc, char **argv, struct command *cmd, st
|
|||
/// Device Capabilities (Log Identifier C4h) Requirements
|
||||
|
||||
#define C4_DEV_CAP_REQ_LEN 0x1000
|
||||
#define C4_DEV_CAP_REQ_OPCODE 0xC4
|
||||
static __u8 dev_cap_req_guid[GUID_LEN] = {
|
||||
0x97, 0x42, 0x05, 0x0d,
|
||||
0xd1, 0xe1, 0xc9, 0x98,
|
||||
|
@ -1829,7 +1801,7 @@ static int get_c4_log_page(struct nvme_dev *dev, char *format)
|
|||
}
|
||||
memset(data, 0, sizeof(__u8) * C4_DEV_CAP_REQ_LEN);
|
||||
|
||||
ret = nvme_get_log_simple(dev_fd(dev), C4_DEV_CAP_REQ_OPCODE, C4_DEV_CAP_REQ_LEN, data);
|
||||
ret = ocp_get_log_simple(dev, OCP_LID_DCLP, C4_DEV_CAP_REQ_LEN, data);
|
||||
|
||||
if (!ret) {
|
||||
log_data = (struct ocp_device_capabilities_log_page *)data;
|
||||
|
@ -1915,7 +1887,7 @@ static int ocp_set_telemetry_profile(struct nvme_dev *dev, __u8 tps)
|
|||
struct nvme_set_features_args args = {
|
||||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.fid = 0xC8,
|
||||
.fid = OCP_FID_TEL_CFG,
|
||||
.nsid = 0xFFFFFFFF,
|
||||
.cdw11 = tps,
|
||||
.cdw12 = 0,
|
||||
|
@ -2038,7 +2010,6 @@ static int set_dssd_power_state_feature(int argc, char **argv, struct command *c
|
|||
const char *power_state = "DSSD Power State to set in watts";
|
||||
const char *save = "Specifies that the controller shall save the attribute";
|
||||
const __u32 nsid = 0;
|
||||
const __u8 fid = 0xC7;
|
||||
struct nvme_dev *dev;
|
||||
int err;
|
||||
|
||||
|
@ -2065,9 +2036,8 @@ static int set_dssd_power_state_feature(int argc, char **argv, struct command *c
|
|||
return err;
|
||||
|
||||
if (argconfig_parse_seen(opts, "power-state"))
|
||||
err = set_dssd_power_state(dev, nsid, fid, cfg.power_state,
|
||||
cfg.save,
|
||||
!argconfig_parse_seen(opts, "no-uuid"));
|
||||
err = set_dssd_power_state(dev, nsid, OCP_FID_DSSDPS, cfg.power_state, cfg.save,
|
||||
!argconfig_parse_seen(opts, "no-uuid"));
|
||||
|
||||
dev_close(dev);
|
||||
|
||||
|
@ -2130,7 +2100,7 @@ static int get_dssd_power_state_feature(int argc, char **argv, struct command *c
|
|||
const char *all = "Print out all 3 values at once - Current, Default, and Saved";
|
||||
const char *sel = "[0-3]: current/default/saved/supported/";
|
||||
const __u32 nsid = 0;
|
||||
const __u8 fid = 0xC7;
|
||||
const __u8 fid = OCP_FID_DSSDPS;
|
||||
struct nvme_dev *dev;
|
||||
int i, err;
|
||||
|
||||
|
@ -2188,7 +2158,6 @@ static int set_plp_health_check_interval(int argc, char **argv, struct command *
|
|||
const char *plp_health_interval = "[31:16]:PLP Health Check Interval";
|
||||
const char *save = "Specifies that the controller shall save the attribute";
|
||||
const __u32 nsid = 0;
|
||||
const __u8 fid = 0xc6;
|
||||
struct nvme_dev *dev;
|
||||
int err;
|
||||
__u32 result;
|
||||
|
@ -2230,7 +2199,7 @@ static int set_plp_health_check_interval(int argc, char **argv, struct command *
|
|||
struct nvme_set_features_args args = {
|
||||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.fid = fid,
|
||||
.fid = OCP_FID_PLPI,
|
||||
.nsid = nsid,
|
||||
.cdw11 = cfg.plp_health_interval << 16,
|
||||
.cdw12 = 0,
|
||||
|
@ -2262,7 +2231,6 @@ static int get_plp_health_check_interval(int argc, char **argv, struct command *
|
|||
{
|
||||
|
||||
const char *desc = "Define Issue Get Feature command (FID : 0xC6) PLP Health Check Interval";
|
||||
const char *sel = "[0-3,8]: current/default/saved/supported/changed";
|
||||
const __u32 nsid = 0;
|
||||
const __u8 fid = 0xc6;
|
||||
struct nvme_dev *dev;
|
||||
|
@ -2290,7 +2258,7 @@ static int get_plp_health_check_interval(int argc, char **argv, struct command *
|
|||
struct nvme_get_features_args args = {
|
||||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.fid = fid,
|
||||
.fid = OCP_FID_PLPI,
|
||||
.nsid = nsid,
|
||||
.sel = cfg.sel,
|
||||
.cdw11 = 0,
|
||||
|
@ -2328,7 +2296,6 @@ static int set_dssd_async_event_config(int argc, char **argv, struct command *cm
|
|||
const char *epn = "[0]:Enable Panic Notices";
|
||||
const char *save = "Specifies that the controller shall save the attribute";
|
||||
const __u32 nsid = 0;
|
||||
const __u8 fid = 0xc9;
|
||||
struct nvme_dev *dev;
|
||||
int err;
|
||||
__u32 result;
|
||||
|
@ -2364,7 +2331,7 @@ static int set_dssd_async_event_config(int argc, char **argv, struct command *cm
|
|||
struct nvme_set_features_args args = {
|
||||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.fid = fid,
|
||||
.fid = OCP_FID_DAEC,
|
||||
.nsid = nsid,
|
||||
.cdw11 = cfg.epn ? 1 : 0,
|
||||
.cdw12 = 0,
|
||||
|
@ -2398,7 +2365,7 @@ static int get_dssd_async_event_config(int argc, char **argv, struct command *cm
|
|||
const char *desc = "Issue Get Feature command (FID : 0xC9) DSSD Async Event Config";
|
||||
const char *sel = "[0-3]: current/default/saved/supported";
|
||||
const __u32 nsid = 0;
|
||||
const __u8 fid = 0xc9;
|
||||
const __u8 fid = OCP_FID_DAEC;
|
||||
struct nvme_dev *dev;
|
||||
__u32 result;
|
||||
int err;
|
||||
|
@ -2469,7 +2436,11 @@ static int get_c9_log_page(struct nvme_dev *dev, char *format)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = get_c9_log_page_data(dev, 1, 0);
|
||||
if (fmt == BINARY)
|
||||
ret = get_c9_log_page_data(dev, 0, 1);
|
||||
else
|
||||
ret = get_c9_log_page_data(dev, 0, 0);
|
||||
|
||||
if (!ret) {
|
||||
ocp_c9_log(log_data, pC9_string_buffer, total_log_page_sz, fmt);
|
||||
} else {
|
||||
|
@ -2496,7 +2467,8 @@ static int ocp_telemetry_str_log_format(int argc, char **argv, struct command *c
|
|||
};
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
OPT_FMT("output-format", 'o', &cfg.output_format, "output Format: normal|json"),
|
||||
OPT_FMT("output-format", 'o', &cfg.output_format,
|
||||
"output Format:normal|json|binary"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
|
@ -2521,7 +2493,6 @@ static int ocp_telemetry_str_log_format(int argc, char **argv, struct command *c
|
|||
|
||||
/* C7 TCG Configuration Log Page */
|
||||
#define C7_TCG_CONFIGURATION_LEN 512
|
||||
#define C7_TCG_CONFIGURATION_OPCODE 0xC7
|
||||
|
||||
static __u8 tcg_configuration_guid[GUID_LEN] = {
|
||||
0x06, 0x40, 0x24, 0xBD,
|
||||
|
@ -2556,8 +2527,7 @@ static int get_c7_log_page(struct nvme_dev *dev, char *format)
|
|||
}
|
||||
memset(data, 0, sizeof(__u8) * C7_TCG_CONFIGURATION_LEN);
|
||||
|
||||
ret = nvme_get_log_simple(dev_fd(dev), C7_TCG_CONFIGURATION_OPCODE,
|
||||
C7_TCG_CONFIGURATION_LEN, data);
|
||||
ret = ocp_get_log_simple(dev, OCP_LID_TCGL, C7_TCG_CONFIGURATION_LEN, data);
|
||||
if (!ret) {
|
||||
log_data = (struct tcg_configuration_log *)data;
|
||||
|
||||
|
@ -2657,7 +2627,7 @@ static int error_injection_get(struct nvme_dev *dev, const __u8 sel, bool uuid)
|
|||
struct erri_get_cq_entry cq_entry;
|
||||
int err;
|
||||
int i;
|
||||
const __u8 fid = 0xc0;
|
||||
const __u8 fid = OCP_FID_ERRI;
|
||||
|
||||
_cleanup_free_ struct erri_entry *entry = NULL;
|
||||
|
||||
|
@ -2738,7 +2708,7 @@ static int error_injection_set(struct nvme_dev *dev, struct erri_config *cfg, bo
|
|||
struct nvme_set_features_args args = {
|
||||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.fid = 0xc0,
|
||||
.fid = OCP_FID_ERRI,
|
||||
.cdw11 = cfg->number,
|
||||
.data_len = cfg->number * sizeof(struct erri_entry),
|
||||
.timeout = nvme_cfg.timeout,
|
||||
|
@ -2830,7 +2800,7 @@ static int enable_ieee1667_silo_get(struct nvme_dev *dev, const __u8 sel, bool u
|
|||
{
|
||||
struct ieee1667_get_cq_entry cq_entry;
|
||||
int err;
|
||||
const __u8 fid = 0xc4;
|
||||
const __u8 fid = OCP_FID_1667;
|
||||
|
||||
struct nvme_get_features_args args = {
|
||||
.result = (__u32 *)&cq_entry,
|
||||
|
@ -2890,6 +2860,70 @@ static int get_enable_ieee1667_silo(int argc, char **argv, struct command *cmd,
|
|||
return enable_ieee1667_silo_get(dev, cfg.sel, !argconfig_parse_seen(opts, "no-uuid"));
|
||||
}
|
||||
|
||||
static int enable_ieee1667_silo_set(struct nvme_dev *dev,
|
||||
struct argconfig_commandline_options *opts)
|
||||
{
|
||||
struct ieee1667_get_cq_entry cq_entry;
|
||||
int err;
|
||||
const __u8 fid = OCP_FID_1667;
|
||||
bool enable = argconfig_parse_seen(opts, "enable");
|
||||
|
||||
struct nvme_set_features_args args = {
|
||||
.result = (__u32 *)&cq_entry,
|
||||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
|
||||
.cdw11 = OCP_SET(enable, ENABLE_IEEE1667_SILO),
|
||||
.save = argconfig_parse_seen(opts, "save"),
|
||||
.fid = fid,
|
||||
};
|
||||
|
||||
if (!argconfig_parse_seen(opts, "no-uuid")) {
|
||||
/* OCP 2.0 requires UUID index support */
|
||||
err = ocp_get_uuid_index(dev, &args.uuidx);
|
||||
if (err || !args.uuidx) {
|
||||
nvme_show_error("ERROR: No OCP UUID index found");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = nvme_cli_set_features(dev, &args);
|
||||
if (err > 0) {
|
||||
nvme_show_status(err);
|
||||
} else if (err < 0) {
|
||||
nvme_show_perror(enable_ieee1667_silo);
|
||||
fprintf(stderr, "Command failed while parsing.\n");
|
||||
} else {
|
||||
enable = OCP_GET(args.cdw11, ENABLE_IEEE1667_SILO);
|
||||
nvme_show_result("Successfully set enable (feature: 0x%02x): %d (%s: %s).", fid,
|
||||
enable, args.save ? "Save" : "Not save",
|
||||
enable ? "Enabled" : "Disabled");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int set_enable_ieee1667_silo(int argc, char **argv, struct command *cmd,
|
||||
struct plugin *plugin)
|
||||
{
|
||||
int err;
|
||||
|
||||
_cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
OPT_FLAG("enable", 'e', NULL, no_uuid),
|
||||
OPT_FLAG("save", 's', NULL, save),
|
||||
OPT_FLAG("no-uuid", 'n', NULL, no_uuid),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
err = parse_and_open(&dev, argc, argv, enable_ieee1667_silo, opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return enable_ieee1667_silo_set(dev, opts);
|
||||
}
|
||||
|
||||
static int hwcomp_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
||||
{
|
||||
return ocp_hwcomp_log(argc, argv, cmd, plugin);
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#if !defined(OCP_NVME) || defined(CMD_HEADER_MULTI_READ)
|
||||
#define OCP_NVME
|
||||
|
||||
#define OCP_PLUGIN_VERSION "2.9.2"
|
||||
#define OCP_PLUGIN_VERSION "2.11.0"
|
||||
#include "cmd.h"
|
||||
|
||||
PLUGIN(NAME("ocp", "OCP cloud SSD extensions", OCP_PLUGIN_VERSION),
|
||||
|
@ -40,6 +40,7 @@ PLUGIN(NAME("ocp", "OCP cloud SSD extensions", OCP_PLUGIN_VERSION),
|
|||
ENTRY("set-error-injection", "Inject error conditions", set_error_injection)
|
||||
ENTRY("get-enable-ieee1667-silo", "return set of enable IEEE1667 silo",
|
||||
get_enable_ieee1667_silo)
|
||||
ENTRY("set-enable-ieee1667-silo", "enable IEEE1667 silo", set_enable_ieee1667_silo)
|
||||
ENTRY("hardware-component-log", "retrieve hardware component log", hwcomp_log)
|
||||
)
|
||||
);
|
||||
|
@ -50,6 +51,8 @@ PLUGIN(NAME("ocp", "OCP cloud SSD extensions", OCP_PLUGIN_VERSION),
|
|||
|
||||
#ifndef OCP_NVME_H
|
||||
#define OCP_NVME_H
|
||||
#include "common.h"
|
||||
|
||||
struct __packed ssd_latency_monitor_log {
|
||||
__u8 feature_status; /* 0x00 */
|
||||
__u8 rsvd1; /* 0x01 */
|
||||
|
@ -73,8 +76,9 @@ struct __packed ssd_latency_monitor_log {
|
|||
__le64 static_latency_timestamp[4][3]; /* 0x130 - 0x18F */
|
||||
__le16 static_measured_latency[4][3]; /* 0x190 - 0x1A7 */
|
||||
__le16 static_latency_stamp_units; /* 0x1A8 */
|
||||
__u8 rsvd4[0x16]; /* 0x1AA */
|
||||
__u8 rsvd4[0x0A]; /* 0x1AA */
|
||||
|
||||
__u8 latency_monitor_debug_log_size[0x0C]; /* 0x1B4 */
|
||||
__le16 debug_log_trigger_enable; /* 0x1C0 */
|
||||
__le16 debug_log_measured_latency; /* 0x1C2 */
|
||||
__le64 debug_log_latency_stamp; /* 0x1C4 */
|
||||
|
@ -195,7 +199,7 @@ struct __packed ocp_device_capabilities_log_page {
|
|||
/*
|
||||
* struct tcg_configuration_log - TCG Configuration Log Page Structure
|
||||
* @state: state
|
||||
* @rsvd1: Reserved1
|
||||
* @rsvd1: Reserved
|
||||
* @locking_sp_act_count: Locking SP Activation Count
|
||||
* @type_rev_count: Tper Revert Count
|
||||
* @locking_sp_rev_count: Locking SP Revert Count.
|
||||
|
@ -207,13 +211,14 @@ struct __packed ocp_device_capabilities_log_page {
|
|||
* @no_of_write_lock_locking_obj: Number of Write Locked Locking Objects
|
||||
* @no_of_read_unlock_locking_obj: Number of Read Unlocked Locking Objects
|
||||
* @no_of_read_unlock_locking_obj: Number of Write Unlocked Locking Objects
|
||||
* @rsvd2: Reserved2
|
||||
* @rsvd15: Reserved
|
||||
* @sid_auth_try_count: SID Authentication Try Count
|
||||
* @sid_auth_try_limit: SID Authentication Try Limit
|
||||
* @pro_tcg_rc: Programmatic TCG Reset Count
|
||||
* @pro_rlc: Programmatic Reset Lock Count
|
||||
* @tcg_ec: TCG Error Count
|
||||
* @rsvd3: Reserved3
|
||||
* @no_of_ns_prov_locking_obj_ext: Number of Namespace Provisioned Locking Objects Extended
|
||||
* @rsvd38: Reserved
|
||||
* @log_page_version: Log Page Version
|
||||
*/
|
||||
struct __packed tcg_configuration_log {
|
||||
|
@ -230,15 +235,43 @@ struct __packed tcg_configuration_log {
|
|||
__u8 no_of_write_lock_locking_obj;
|
||||
__u8 no_of_read_unlock_locking_obj;
|
||||
__u8 no_of_write_unlock_locking_obj;
|
||||
__u8 rsvd2;
|
||||
__u8 rsvd15;
|
||||
__le32 sid_auth_try_count;
|
||||
__le32 sid_auth_try_limit;
|
||||
__le32 pro_tcg_rc;
|
||||
__le32 pro_rlc;
|
||||
__le32 tcg_ec;
|
||||
__u8 rsvd3[458];
|
||||
__le16 no_of_ns_prov_locking_obj_ext;
|
||||
__u8 rsvd38[456];
|
||||
__le16 log_page_version;
|
||||
__u8 log_page_guid[GUID_LEN];
|
||||
|
||||
};
|
||||
|
||||
enum ocp_dssd_log_id {
|
||||
OCP_LID_SMART = 0xc0, /* SMART / Helth Information Extended */
|
||||
OCP_LID_EREC, /* Error Recovery */
|
||||
OCP_LID_FAHL_OBSOLETE, /* Firmware Activation History (Obsolete) */
|
||||
OCP_LID_LMLOG, /* Latency Monitor */
|
||||
OCP_LID_DCLP, /* Device Capabilities */
|
||||
OCP_LID_URLP, /* Unsupported Requirements */
|
||||
OCP_LID_HWCOMP, /* Hardware Component */
|
||||
OCP_LID_TCGL, /* TCG Configuration */
|
||||
OCP_LID_RESERVED, /* Reserved for future use */
|
||||
OCP_LID_TELSLG, /* Telemetry String */
|
||||
OCP_LID_LMLOG_DEBUG, /* Latency Monitor Debug Telemetry */
|
||||
};
|
||||
|
||||
enum ocp_dssd_feature_id {
|
||||
OCP_FID_ERRI = 0xc0, /* Error Injection */
|
||||
OCP_FID_CFUH, /* Clear Firmware Update History (Obsolete) */
|
||||
OCP_FID_ROWTM, /* EOL/PLP Failure Mode */
|
||||
OCP_FID_CPCIE, /* Clear PCIe Correctable Error Counters */
|
||||
OCP_FID_1667, /* Enable IEEE1667 Silo */
|
||||
OCP_FID_LM, /* Latency Monitor */
|
||||
OCP_FID_PLPI, /* PLP Health Check Interval */
|
||||
OCP_FID_DSSDPS, /* DSSD Power State */
|
||||
OCP_FID_TEL_CFG, /* Telemetry Profile */
|
||||
OCP_FID_DAEC, /* DSSD Asynchronous Event Configuration */
|
||||
};
|
||||
#endif /* OCP_NVME_H */
|
||||
|
|
|
@ -7,9 +7,12 @@
|
|||
|
||||
static void binary_hwcomp_log(struct hwcomp_log *log, __u32 id, bool list)
|
||||
{
|
||||
long double desc_len = uint128_t_to_double(le128_to_cpu(log->size)) * sizeof(__le32);
|
||||
long double log_bytes = uint128_t_to_double(le128_to_cpu(log->size));
|
||||
|
||||
d_raw((unsigned char *)log, offsetof(struct hwcomp_log, desc) + desc_len);
|
||||
if (log->ver == 1)
|
||||
log_bytes *= sizeof(__le32);
|
||||
|
||||
d_raw((unsigned char *)log, log_bytes);
|
||||
}
|
||||
|
||||
static void binary_c5_log(struct nvme_dev *dev, struct unsupported_requirement_log *log_data)
|
||||
|
|
|
@ -11,15 +11,16 @@
|
|||
|
||||
static void print_hwcomp_desc_json(struct hwcomp_desc_entry *e, struct json_object *r)
|
||||
{
|
||||
obj_add_str(r, "Description", hwcomp_id_to_string(le32_to_cpu(e->desc->id)));
|
||||
obj_add_nprix64(r, "Date/Lot Size", e->date_lot_size);
|
||||
obj_add_nprix64(r, "Additional Information Size", e->add_info_size);
|
||||
obj_add_uint_0nx(r, "Identifier", le32_to_cpu(e->desc->id), 8);
|
||||
obj_add_0nprix64(r, "Manufacture", le64_to_cpu(e->desc->mfg), 16);
|
||||
obj_add_0nprix64(r, "Revision", le64_to_cpu(e->desc->rev), 16);
|
||||
obj_add_0nprix64(r, "Manufacture Code", le64_to_cpu(e->desc->mfg_code), 16);
|
||||
obj_add_byte_array(r, "Date/Lot Code", e->date_lot_code, e->date_lot_size);
|
||||
obj_add_byte_array(r, "Additional Information", e->add_info, e->add_info_size);
|
||||
json_object_add_value_string(r, "Description",
|
||||
hwcomp_id_to_string(le32_to_cpu(e->desc->id)));
|
||||
json_object_add_nprix64(r, "Date/Lot Size", e->date_lot_size);
|
||||
json_object_add_nprix64(r, "Additional Information Size", e->add_info_size);
|
||||
json_object_add_uint_0nx(r, "Identifier", le32_to_cpu(e->desc->id), 8);
|
||||
json_object_add_0nprix64(r, "Manufacture", le64_to_cpu(e->desc->mfg), 16);
|
||||
json_object_add_0nprix64(r, "Revision", le64_to_cpu(e->desc->rev), 16);
|
||||
json_object_add_0nprix64(r, "Manufacture Code", le64_to_cpu(e->desc->mfg_code), 16);
|
||||
json_object_add_byte_array(r, "Date/Lot Code", e->date_lot_code, e->date_lot_size);
|
||||
json_object_add_byte_array(r, "Additional Information", e->add_info, e->add_info_size);
|
||||
}
|
||||
|
||||
static void print_hwcomp_desc_list_json(struct json_object *r, struct hwcomp_desc_entry *e,
|
||||
|
@ -31,7 +32,8 @@ static void print_hwcomp_desc_list_json(struct json_object *r, struct hwcomp_des
|
|||
return;
|
||||
|
||||
if (list) {
|
||||
obj_add_str(r, k, hwcomp_id_to_string(le32_to_cpu(e->desc->id)));
|
||||
json_object_add_value_string(r, k,
|
||||
hwcomp_id_to_string(le32_to_cpu(e->desc->id)));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -63,17 +65,19 @@ static void print_hwcomp_descs_json(struct hwcomp_desc *desc, long double log_si
|
|||
|
||||
static void json_hwcomp_log(struct hwcomp_log *log, __u32 id, bool list)
|
||||
{
|
||||
long double log_bytes = uint128_t_to_double(le128_to_cpu(log->size));
|
||||
struct json_object *r = json_create_object();
|
||||
|
||||
long double log_size = uint128_t_to_double(le128_to_cpu(log->size)) * sizeof(__le32);
|
||||
if (log->ver == 1)
|
||||
log_bytes *= sizeof(__le32);
|
||||
|
||||
obj_add_uint_02x(r, "Log Identifier", LID_HWCOMP);
|
||||
obj_add_uint_0x(r, "Log Page Version", le16_to_cpu(log->ver));
|
||||
obj_add_byte_array(r, "Reserved2", log->rsvd2, ARRAY_SIZE(log->rsvd2));
|
||||
obj_add_byte_array(r, "Log page GUID", log->guid, ARRAY_SIZE(log->guid));
|
||||
obj_add_nprix64(r, "Hardware Component Log Size", (unsigned long long)log_size);
|
||||
obj_add_byte_array(r, "Reserved48", log->rsvd48, ARRAY_SIZE(log->rsvd48));
|
||||
print_hwcomp_descs_json(log->desc, log_size, id, list,
|
||||
json_object_add_uint_02x(r, "Log Identifier", OCP_LID_HWCOMP);
|
||||
json_object_add_uint_0x(r, "Log Page Version", le16_to_cpu(log->ver));
|
||||
json_object_add_byte_array(r, "Reserved2", log->rsvd2, ARRAY_SIZE(log->rsvd2));
|
||||
json_object_add_byte_array(r, "Log page GUID", log->guid, ARRAY_SIZE(log->guid));
|
||||
json_object_add_nprix64(r, "Hardware Component Log Size", (unsigned long long)log_bytes);
|
||||
json_object_add_byte_array(r, "Reserved48", log->rsvd48, ARRAY_SIZE(log->rsvd48));
|
||||
print_hwcomp_descs_json(log->desc, log_bytes - offsetof(struct hwcomp_log, desc), id, list,
|
||||
obj_create_array_obj(r, "Component Descriptions"));
|
||||
|
||||
json_print(r);
|
||||
|
@ -97,7 +101,7 @@ static void json_fw_activation_history(const struct fw_activation_history *fw_hi
|
|||
json_object_add_value_uint(entry_obj, "activation count",
|
||||
le16_to_cpu(entry->activation_count));
|
||||
json_object_add_value_uint64(entry_obj, "timestamp",
|
||||
(0x0000FFFFFFFFFFFF & le64_to_cpu(entry->timestamp)));
|
||||
int48_to_long(entry->ts.timestamp));
|
||||
json_object_add_value_uint(entry_obj, "power cycle count",
|
||||
le64_to_cpu(entry->power_cycle_count));
|
||||
|
||||
|
@ -134,85 +138,88 @@ static void json_fw_activation_history(const struct fw_activation_history *fw_hi
|
|||
printf("\n");
|
||||
}
|
||||
|
||||
static void json_smart_extended_log(void *data)
|
||||
static void json_smart_extended_log_v1(struct ocp_smart_extended_log *log)
|
||||
{
|
||||
struct json_object *root;
|
||||
struct json_object *pmuw;
|
||||
struct json_object *pmur;
|
||||
uint16_t smart_log_ver = 0;
|
||||
__u8 *log_data = data;
|
||||
uint16_t dssd_version = 0;
|
||||
int i = 0;
|
||||
char guid[40];
|
||||
char ascii_arr[65];
|
||||
char *ascii = ascii_arr;
|
||||
|
||||
root = json_create_object();
|
||||
pmuw = json_create_object();
|
||||
pmur = json_create_object();
|
||||
|
||||
json_object_add_value_uint64(pmuw, "hi",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW + 8] & 0xFFFFFFFFFFFFFFFF));
|
||||
le64_to_cpu(*(uint64_t *)&log->physical_media_units_written[8]));
|
||||
json_object_add_value_uint64(pmuw, "lo",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW] & 0xFFFFFFFFFFFFFFFF));
|
||||
le64_to_cpu(*(uint64_t *)&log->physical_media_units_written));
|
||||
json_object_add_value_object(root, "Physical media units written", pmuw);
|
||||
json_object_add_value_uint64(pmur, "hi",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR + 8] & 0xFFFFFFFFFFFFFFFF));
|
||||
le64_to_cpu(*(uint64_t *)&log->physical_media_units_read[8]));
|
||||
json_object_add_value_uint64(pmur, "lo",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR] & 0xFFFFFFFFFFFFFFFF));
|
||||
le64_to_cpu(*(uint64_t *)&log->physical_media_units_read));
|
||||
json_object_add_value_object(root, "Physical media units read", pmur);
|
||||
json_object_add_value_uint64(root, "Bad user nand blocks - Raw",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BUNBR] & 0x0000FFFFFFFFFFFF));
|
||||
int48_to_long(log->bad_user_nand_blocks_raw));
|
||||
json_object_add_value_uint(root, "Bad user nand blocks - Normalized",
|
||||
(uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BUNBN]));
|
||||
le16_to_cpu(log->bad_user_nand_blocks_normalized));
|
||||
json_object_add_value_uint64(root, "Bad system nand blocks - Raw",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BSNBR] & 0x0000FFFFFFFFFFFF));
|
||||
int48_to_long(log->bad_system_nand_blocks_raw));
|
||||
json_object_add_value_uint(root, "Bad system nand blocks - Normalized",
|
||||
(uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BSNBN]));
|
||||
le16_to_cpu(log->bad_system_nand_blocks_normalized));
|
||||
json_object_add_value_uint64(root, "XOR recovery count",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_XRC]));
|
||||
le64_to_cpu(log->xor_recovery_count));
|
||||
json_object_add_value_uint64(root, "Uncorrectable read error count",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UREC]));
|
||||
le64_to_cpu(log->uncorrectable_read_err_count));
|
||||
json_object_add_value_uint64(root, "Soft ecc error count",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SEEC]));
|
||||
le64_to_cpu(log->soft_ecc_err_count));
|
||||
json_object_add_value_uint(root, "End to end detected errors",
|
||||
(uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EEDC]));
|
||||
le32_to_cpu(log->end_to_end_detected_err));
|
||||
json_object_add_value_uint(root, "End to end corrected errors",
|
||||
(uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EECE]));
|
||||
le32_to_cpu(log->end_to_end_corrected_err));
|
||||
json_object_add_value_uint(root, "System data percent used",
|
||||
(__u8)log_data[SCAO_SDPU]);
|
||||
log->system_data_used_percent);
|
||||
json_object_add_value_uint64(root, "Refresh counts",
|
||||
(uint64_t)(le64_to_cpu(*(uint64_t *)&log_data[SCAO_RFSC]) & 0x00FFFFFFFFFFFFFF));
|
||||
int56_to_long(log->refresh_counts));
|
||||
json_object_add_value_uint(root, "Max User data erase counts",
|
||||
(uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MXUDEC]));
|
||||
le32_to_cpu(log->user_data_erase_count_max));
|
||||
json_object_add_value_uint(root, "Min User data erase counts",
|
||||
(uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MNUDEC]));
|
||||
le32_to_cpu(log->user_data_erase_count_min));
|
||||
json_object_add_value_uint(root, "Number of Thermal throttling events",
|
||||
(__u8)log_data[SCAO_NTTE]);
|
||||
log->thermal_throttling_event_count);
|
||||
json_object_add_value_uint(root, "Current throttling status",
|
||||
(__u8)log_data[SCAO_CTS]);
|
||||
log->thermal_throttling_current_status);
|
||||
json_object_add_value_uint64(root, "PCIe correctable error count",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PCEC]));
|
||||
le64_to_cpu(log->pcie_correctable_err_count));
|
||||
json_object_add_value_uint(root, "Incomplete shutdowns",
|
||||
(uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_ICS]));
|
||||
le32_to_cpu(log->incomplete_shoutdowns));
|
||||
json_object_add_value_uint(root, "Percent free blocks",
|
||||
(__u8)log_data[SCAO_PFB]);
|
||||
log->percent_free_blocks);
|
||||
json_object_add_value_uint(root, "Capacitor health",
|
||||
(uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_CPH]));
|
||||
le16_to_cpu(log->capacitor_health));
|
||||
json_object_add_value_uint64(root, "Unaligned I/O",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UIO]));
|
||||
le64_to_cpu(log->unaligned_io));
|
||||
json_object_add_value_uint64(root, "Security Version Number",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN]));
|
||||
le64_to_cpu(log->security_version));
|
||||
json_object_add_value_uint64(root, "NUSE - Namespace utilization",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE]));
|
||||
le64_to_cpu(log->total_nuse));
|
||||
json_object_add_value_uint128(root, "PLP start count",
|
||||
le128_to_cpu(&log_data[SCAO_PSC]));
|
||||
le128_to_cpu(log->plp_start_count));
|
||||
json_object_add_value_uint128(root, "Endurance estimate",
|
||||
le128_to_cpu(&log_data[SCAO_EEST]));
|
||||
smart_log_ver = (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_LPV]);
|
||||
le128_to_cpu(log->endurance_estimate));
|
||||
smart_log_ver = le16_to_cpu(log->log_page_version);
|
||||
|
||||
json_object_add_value_uint(root, "Log page version", smart_log_ver);
|
||||
|
||||
memset((void *)guid, 0, 40);
|
||||
sprintf((char *)guid, "0x%"PRIx64"%"PRIx64"",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]),
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG]));
|
||||
le64_to_cpu(*(uint64_t *)&log->log_page_guid[8]),
|
||||
le64_to_cpu(*(uint64_t *)&log->log_page_guid));
|
||||
json_object_add_value_string(root, "Log page GUID", guid);
|
||||
|
||||
switch (smart_log_ver) {
|
||||
|
@ -221,31 +228,251 @@ static void json_smart_extended_log(void *data)
|
|||
default:
|
||||
case 4:
|
||||
json_object_add_value_uint(root, "NVMe Command Set Errata Version",
|
||||
(__u8)log_data[SCAO_NCSEV]);
|
||||
log->nvme_cmdset_errata_version);
|
||||
json_object_add_value_uint(root, "Lowest Permitted Firmware Revision",
|
||||
le64_to_cpu(*(uint64_t *)&log_data[SCAO_PSCC]));
|
||||
le64_to_cpu(log->lowest_permitted_fw_rev));
|
||||
json_object_add_value_uint(root, "NVMe Over Pcie Errata Version",
|
||||
log->nvme_over_pcie_errate_version);
|
||||
json_object_add_value_uint(root, "NVMe Mi Errata Version",
|
||||
log->nvme_mi_errata_version);
|
||||
json_object_add_value_uint(root, "Total media dies",
|
||||
le16_to_cpu(log->total_media_dies));
|
||||
json_object_add_value_uint(root, "Total die failure tolerance",
|
||||
le16_to_cpu(log->total_die_failure_tolerance));
|
||||
json_object_add_value_uint(root, "Media dies offline",
|
||||
le16_to_cpu(log->media_dies_offline));
|
||||
json_object_add_value_uint(root, "Max temperature recorded",
|
||||
log->max_temperature_recorded);
|
||||
json_object_add_value_uint64(root, "Nand avg erase count",
|
||||
le64_to_cpu(log->nand_avg_erase_count));
|
||||
json_object_add_value_uint(root, "Command timeouts",
|
||||
le32_to_cpu(log->command_timeouts));
|
||||
json_object_add_value_uint(root, "Sys area program fail count raw",
|
||||
le32_to_cpu(log->sys_area_program_fail_count_raw));
|
||||
json_object_add_value_uint(root, "Sys area program fail count noralized",
|
||||
log->sys_area_program_fail_count_normalized);
|
||||
json_object_add_value_uint(root, "Sys area uncorrectable read count raw",
|
||||
le32_to_cpu(log->sys_area_uncorr_read_count_raw));
|
||||
json_object_add_value_uint(root, "Sys area uncorrectable read count noralized",
|
||||
log->sys_area_uncorr_read_count_normalized);
|
||||
json_object_add_value_uint(root, "Sys area erase fail count raw",
|
||||
le32_to_cpu(log->sys_area_erase_fail_count_raw));
|
||||
json_object_add_value_uint(root, "Sys area erase fail count noralized",
|
||||
log->sys_area_erase_fail_count_normalized);
|
||||
json_object_add_value_uint(root, "Max peak power capability",
|
||||
le16_to_cpu(log->max_peak_power_capability));
|
||||
json_object_add_value_uint(root, "Current max avg power",
|
||||
le16_to_cpu(log->current_max_avg_power));
|
||||
json_object_add_value_uint64(root, "Lifetime power consumed",
|
||||
int48_to_long(log->lifetime_power_consumed));
|
||||
memset((void *)ascii, 0, 65);
|
||||
for (i = 0; i < 8; i++)
|
||||
ascii += sprintf(ascii, "%c", log->dssd_firmware_revision[i]);
|
||||
json_object_add_value_string(root, "Dssd firmware revision", ascii_arr);
|
||||
json_object_add_value_string(root, "Dssd firmware build UUID",
|
||||
util_uuid_to_string(log->dssd_firmware_build_uuid));
|
||||
ascii = ascii_arr;
|
||||
memset((void *)ascii, 0, 65);
|
||||
for (i = 0; i < 64; i++)
|
||||
ascii += sprintf(ascii, "%c", log->dssd_firmware_build_label[i]);
|
||||
json_object_add_value_string(root, "Dssd firmware build label", ascii_arr);
|
||||
fallthrough;
|
||||
case 2 ... 3:
|
||||
json_object_add_value_uint(root, "Errata Version Field",
|
||||
(__u8)log_data[SCAO_EVF]);
|
||||
log->dssd_errata_version);
|
||||
memcpy(&dssd_version, log->dssd_point_version, sizeof(dssd_version));
|
||||
json_object_add_value_uint(root, "Point Version Field",
|
||||
le16_to_cpu(*(uint16_t *)&log_data[SCAO_PVF]));
|
||||
le16_to_cpu(dssd_version));
|
||||
memcpy(&dssd_version, log->dssd_minor_version, sizeof(dssd_version));
|
||||
json_object_add_value_uint(root, "Minor Version Field",
|
||||
le16_to_cpu(*(uint16_t *)&log_data[SCAO_MIVF]));
|
||||
le16_to_cpu(dssd_version));
|
||||
json_object_add_value_uint(root, "Major Version Field",
|
||||
(__u8)log_data[SCAO_MAVF]);
|
||||
log->dssd_major_version);
|
||||
json_object_add_value_uint(root, "NVMe Base Errata Version",
|
||||
(__u8)log_data[SCAO_NBEV]);
|
||||
log->nvme_base_errata_version);
|
||||
json_object_add_value_uint(root, "PCIe Link Retraining Count",
|
||||
le64_to_cpu(*(uint64_t *)&log_data[SCAO_PLRC]));
|
||||
le64_to_cpu(log->pcie_link_retaining_count));
|
||||
json_object_add_value_uint(root, "Power State Change Count",
|
||||
le64_to_cpu(*(uint64_t *)&log_data[SCAO_PSCC]));
|
||||
le64_to_cpu(log->power_state_change_count));
|
||||
}
|
||||
json_print_object(root, NULL);
|
||||
printf("\n");
|
||||
json_free_object(root);
|
||||
}
|
||||
|
||||
static void json_smart_extended_log_v2(struct ocp_smart_extended_log *log)
|
||||
{
|
||||
struct json_object *root;
|
||||
struct json_object *pmuw;
|
||||
struct json_object *pmur;
|
||||
int i = 0;
|
||||
uint16_t smart_log_ver = 0;
|
||||
uint16_t dssd_version = 0;
|
||||
char guid[40];
|
||||
char ascii_arr[65];
|
||||
char *ascii = ascii_arr;
|
||||
|
||||
root = json_create_object();
|
||||
pmuw = json_create_object();
|
||||
pmur = json_create_object();
|
||||
|
||||
json_object_add_value_uint64(pmuw, "hi",
|
||||
le64_to_cpu(*(uint64_t *)&log->physical_media_units_written[8]));
|
||||
json_object_add_value_uint64(pmuw, "lo",
|
||||
le64_to_cpu(*(uint64_t *)&log->physical_media_units_written));
|
||||
json_object_add_value_object(root, "physical_media_units_written", pmuw);
|
||||
json_object_add_value_uint64(pmur, "hi",
|
||||
le64_to_cpu(*(uint64_t *)&log->physical_media_units_read[8]));
|
||||
json_object_add_value_uint64(pmur, "lo",
|
||||
le64_to_cpu(*(uint64_t *)&log->physical_media_units_read));
|
||||
json_object_add_value_object(root, "physical_media_units_read", pmur);
|
||||
json_object_add_value_uint64(root, "bad_user_nand_blocks_raw",
|
||||
int48_to_long(log->bad_user_nand_blocks_raw));
|
||||
json_object_add_value_uint(root, "bad_user_nand_blocks_normalized",
|
||||
le16_to_cpu(log->bad_user_nand_blocks_normalized));
|
||||
json_object_add_value_uint64(root, "bad_system_nand_blocks_raw",
|
||||
int48_to_long(log->bad_system_nand_blocks_raw));
|
||||
json_object_add_value_uint(root, "bad_system_nand_blocks_normalized",
|
||||
le16_to_cpu(log->bad_system_nand_blocks_normalized));
|
||||
json_object_add_value_uint64(root, "xor_recovery_count",
|
||||
le64_to_cpu(log->xor_recovery_count));
|
||||
json_object_add_value_uint64(root, "uncorrectable_read_errors",
|
||||
le64_to_cpu(log->uncorrectable_read_err_count));
|
||||
json_object_add_value_uint64(root, "soft_ecc_error_count",
|
||||
le64_to_cpu(log->soft_ecc_err_count));
|
||||
json_object_add_value_uint(root, "end_to_end_detected_errors",
|
||||
le32_to_cpu(log->end_to_end_detected_err));
|
||||
json_object_add_value_uint(root, "end_to_end_corrected_errors",
|
||||
le32_to_cpu(log->end_to_end_corrected_err));
|
||||
json_object_add_value_uint(root, "system_data_percent_used",
|
||||
log->system_data_used_percent);
|
||||
json_object_add_value_uint64(root, "refresh_count",
|
||||
int56_to_long(log->refresh_counts));
|
||||
json_object_add_value_uint(root, "max_user_data_erase_count",
|
||||
le32_to_cpu(log->user_data_erase_count_max));
|
||||
json_object_add_value_uint(root, "min_user_data_erase_count",
|
||||
le32_to_cpu(log->user_data_erase_count_min));
|
||||
json_object_add_value_uint(root, "thermal_throttling_events",
|
||||
log->thermal_throttling_event_count);
|
||||
json_object_add_value_uint(root, "current_throttling_status",
|
||||
log->thermal_throttling_current_status);
|
||||
json_object_add_value_uint64(root, "pcie_correctable_errors",
|
||||
le64_to_cpu(log->pcie_correctable_err_count));
|
||||
json_object_add_value_uint(root, "incomplete_shutdowns",
|
||||
le32_to_cpu(log->incomplete_shoutdowns));
|
||||
json_object_add_value_uint(root, "percent_free_blocks",
|
||||
log->percent_free_blocks);
|
||||
json_object_add_value_uint(root, "capacitor_health",
|
||||
le16_to_cpu(log->capacitor_health));
|
||||
json_object_add_value_uint64(root, "unaligned_io",
|
||||
le64_to_cpu(log->unaligned_io));
|
||||
json_object_add_value_uint64(root, "security_version_number",
|
||||
le64_to_cpu(log->security_version));
|
||||
json_object_add_value_uint64(root, "nuse_namespace_utilization",
|
||||
le64_to_cpu(log->total_nuse));
|
||||
json_object_add_value_uint128(root, "plp_start_count",
|
||||
le128_to_cpu(log->plp_start_count));
|
||||
json_object_add_value_uint128(root, "endurance_estimate",
|
||||
le128_to_cpu(log->endurance_estimate));
|
||||
smart_log_ver = le16_to_cpu(log->log_page_version);
|
||||
|
||||
json_object_add_value_uint(root, "log_page_version", smart_log_ver);
|
||||
|
||||
memset((void *)guid, 0, 40);
|
||||
sprintf((char *)guid, "0x%"PRIx64"%"PRIx64"",
|
||||
le64_to_cpu(*(uint64_t *)&log->log_page_guid[8]),
|
||||
le64_to_cpu(*(uint64_t *)&log->log_page_guid));
|
||||
json_object_add_value_string(root, "log_page_guid", guid);
|
||||
|
||||
switch (smart_log_ver) {
|
||||
case 0 ... 1:
|
||||
break;
|
||||
default:
|
||||
case 4:
|
||||
json_object_add_value_uint(root, "nvme_command_set_errata_version",
|
||||
log->nvme_cmdset_errata_version);
|
||||
json_object_add_value_uint(root, "lowest_permitted_firmware_revision",
|
||||
le64_to_cpu(log->lowest_permitted_fw_rev));
|
||||
json_object_add_value_uint(root, "nvme_over_pcie_errata_version",
|
||||
log->nvme_over_pcie_errate_version);
|
||||
json_object_add_value_uint(root, "nvme_mi_errata_version",
|
||||
log->nvme_mi_errata_version);
|
||||
json_object_add_value_uint(root, "total_media_dies",
|
||||
le16_to_cpu(log->total_media_dies));
|
||||
json_object_add_value_uint(root, "total_die_failure_tolerance",
|
||||
le16_to_cpu(log->total_die_failure_tolerance));
|
||||
json_object_add_value_uint(root, "media_dies_offline",
|
||||
le16_to_cpu(log->media_dies_offline));
|
||||
json_object_add_value_uint(root, "max_temperature_recorded",
|
||||
log->max_temperature_recorded);
|
||||
json_object_add_value_uint64(root, "nand_avg_erase_count",
|
||||
le64_to_cpu(log->nand_avg_erase_count));
|
||||
json_object_add_value_uint(root, "command_timeouts",
|
||||
le32_to_cpu(log->command_timeouts));
|
||||
json_object_add_value_uint(root, "sys_area_program_fail_count_raw",
|
||||
le32_to_cpu(log->sys_area_program_fail_count_raw));
|
||||
json_object_add_value_uint(root, "sys_area_program_fail_count_noralized",
|
||||
log->sys_area_program_fail_count_normalized);
|
||||
json_object_add_value_uint(root, "sys_area_uncorrectable_read_count_raw",
|
||||
le32_to_cpu(log->sys_area_uncorr_read_count_raw));
|
||||
json_object_add_value_uint(root, "sys_area_uncorrectable_read_count_noralized",
|
||||
log->sys_area_uncorr_read_count_normalized);
|
||||
json_object_add_value_uint(root, "sys_area_erase_fail_count_raw",
|
||||
le32_to_cpu(log->sys_area_erase_fail_count_raw));
|
||||
json_object_add_value_uint(root, "sys_area_erase_fail_count_noralized",
|
||||
log->sys_area_erase_fail_count_normalized);
|
||||
json_object_add_value_uint(root, "max_peak_power_capability",
|
||||
le16_to_cpu(log->max_peak_power_capability));
|
||||
json_object_add_value_uint(root, "current_max_avg_power",
|
||||
le16_to_cpu(log->current_max_avg_power));
|
||||
json_object_add_value_uint64(root, "lifetime_power_consumed",
|
||||
int48_to_long(log->lifetime_power_consumed));
|
||||
memset((void *)ascii, 0, 65);
|
||||
for (i = 0; i < 8; i++)
|
||||
ascii += sprintf(ascii, "%c", log->dssd_firmware_revision[i]);
|
||||
json_object_add_value_string(root, "dssd_firmware_revision", ascii_arr);
|
||||
json_object_add_value_string(root, "dssd_firmware_build_uuid",
|
||||
util_uuid_to_string(log->dssd_firmware_build_uuid));
|
||||
ascii = ascii_arr;
|
||||
memset((void *)ascii, 0, 65);
|
||||
for (i = 0; i < 64; i++)
|
||||
ascii += sprintf(ascii, "%c", log->dssd_firmware_build_label[i]);
|
||||
json_object_add_value_string(root, "dssd_firmware_build_label", ascii_arr);
|
||||
fallthrough;
|
||||
case 2 ... 3:
|
||||
json_object_add_value_uint(root, "errata_version_field",
|
||||
log->dssd_errata_version);
|
||||
memcpy(&dssd_version, log->dssd_point_version, sizeof(dssd_version));
|
||||
json_object_add_value_uint(root, "point_version_field",
|
||||
le16_to_cpu(dssd_version));
|
||||
memcpy(&dssd_version, log->dssd_minor_version, sizeof(dssd_version));
|
||||
json_object_add_value_uint(root, "minor_version_field",
|
||||
le16_to_cpu(dssd_version));
|
||||
json_object_add_value_uint(root, "major_version_field",
|
||||
log->dssd_major_version);
|
||||
json_object_add_value_uint(root, "nvme_base_errata_version",
|
||||
log->nvme_base_errata_version);
|
||||
json_object_add_value_uint(root, "pcie_link_retraining_count",
|
||||
le64_to_cpu(log->pcie_link_retaining_count));
|
||||
json_object_add_value_uint(root, "power_state_change_count",
|
||||
le64_to_cpu(log->power_state_change_count));
|
||||
}
|
||||
json_print_object(root, NULL);
|
||||
printf("\n");
|
||||
json_free_object(root);
|
||||
}
|
||||
|
||||
static void json_smart_extended_log(struct ocp_smart_extended_log *log, unsigned int version)
|
||||
{
|
||||
switch (version) {
|
||||
default:
|
||||
case 1:
|
||||
json_smart_extended_log_v1(log);
|
||||
break;
|
||||
case 2:
|
||||
json_smart_extended_log_v2(log);
|
||||
}
|
||||
}
|
||||
static void json_telemetry_log(struct ocp_telemetry_parse_options *options)
|
||||
{
|
||||
print_ocp_telemetry_json(options);
|
||||
|
@ -258,6 +485,7 @@ static void json_c3_log(struct nvme_dev *dev, struct ssd_latency_monitor_log *lo
|
|||
char buf[128];
|
||||
int i, j;
|
||||
char *operation[3] = {"Trim", "Write", "Read"};
|
||||
__u16 log_page_version = le16_to_cpu(log_data->log_page_version);
|
||||
|
||||
root = json_create_object();
|
||||
|
||||
|
@ -374,6 +602,21 @@ static void json_c3_log(struct nvme_dev *dev, struct ssd_latency_monitor_log *lo
|
|||
|
||||
json_object_add_value_uint(root, "Static Latency Stamp Units",
|
||||
le16_to_cpu(log_data->static_latency_stamp_units));
|
||||
|
||||
if (log_page_version >= 0x4) {
|
||||
strcpy(buf, "0x");
|
||||
for (i = ARRAY_SIZE(log_data->latency_monitor_debug_log_size) - 1;
|
||||
i > 0 && (log_data->latency_monitor_debug_log_size[i] == 0); i--)
|
||||
;
|
||||
while (i >= 0) {
|
||||
char hex_string[3];
|
||||
|
||||
sprintf(hex_string, "%02x", log_data->latency_monitor_debug_log_size[i--]);
|
||||
strcat(buf, hex_string);
|
||||
}
|
||||
json_object_add_value_string(root, "Debug Telemetry Log Size", buf);
|
||||
}
|
||||
|
||||
json_object_add_value_uint(root, "Debug Log Trigger Enable",
|
||||
le16_to_cpu(log_data->debug_log_trigger_enable));
|
||||
json_object_add_value_uint(root, "Debug Log Measured Latency",
|
||||
|
@ -390,8 +633,7 @@ static void json_c3_log(struct nvme_dev *dev, struct ssd_latency_monitor_log *lo
|
|||
le16_to_cpu(log_data->debug_log_counter_trigger));
|
||||
json_object_add_value_uint(root, "Debug Log Stamp Units",
|
||||
le16_to_cpu(log_data->debug_log_stamp_units));
|
||||
json_object_add_value_uint(root, "Log Page Version",
|
||||
le16_to_cpu(log_data->log_page_version));
|
||||
json_object_add_value_uint(root, "Log Page Version", log_page_version);
|
||||
|
||||
char guid[(GUID_LEN * 2) + 1];
|
||||
char *ptr = &guid[0];
|
||||
|
@ -552,7 +794,7 @@ static void json_c9_log(struct telemetry_str_log_format *log_data, __u8 *log_dat
|
|||
json_object_add_value_int(root, "Log Page Version",
|
||||
le16_to_cpu(log_data->log_page_version));
|
||||
|
||||
memset((__u8 *)res, 0, 15);
|
||||
memset((__u8 *)res, 0, 48);
|
||||
for (j = 0; j < 15; j++)
|
||||
res += sprintf(res, "%d", log_data->reserved1[j]);
|
||||
json_object_add_value_string(root, "Reserved", res_arr);
|
||||
|
@ -564,7 +806,8 @@ static void json_c9_log(struct telemetry_str_log_format *log_data, __u8 *log_dat
|
|||
|
||||
json_object_add_value_int(root, "Telemetry String Log Size", le64_to_cpu(log_data->sls));
|
||||
|
||||
memset((__u8 *)res, 0, 24);
|
||||
res = res_arr;
|
||||
memset((__u8 *)res, 0, 48);
|
||||
for (j = 0; j < 24; j++)
|
||||
res += sprintf(res, "%d", log_data->reserved2[j]);
|
||||
json_object_add_value_string(root, "Reserved", res_arr);
|
||||
|
@ -587,81 +830,97 @@ static void json_c9_log(struct telemetry_str_log_format *log_data, __u8 *log_dat
|
|||
fifo += sprintf(fifo, "%c", log_data->fifo1[j]);
|
||||
json_object_add_value_string(root, "FIFO 1 ASCII String", fifo_arr);
|
||||
|
||||
fifo = fifo_arr;
|
||||
memset((void *)fifo, 0, 16);
|
||||
for (j = 0; j < 16; j++)
|
||||
fifo += sprintf(fifo, "%c", log_data->fifo2[j]);
|
||||
json_object_add_value_string(root, "FIFO 2 ASCII String", fifo_arr);
|
||||
|
||||
fifo = fifo_arr;
|
||||
memset((void *)fifo, 0, 16);
|
||||
for (j = 0; j < 16; j++)
|
||||
fifo += sprintf(fifo, "%c", log_data->fifo3[j]);
|
||||
json_object_add_value_string(root, "FIFO 3 ASCII String", fifo_arr);
|
||||
|
||||
fifo = fifo_arr;
|
||||
memset((void *)fifo, 0, 16);
|
||||
for (j = 0; j < 16; j++)
|
||||
fifo += sprintf(fifo, "%c", log_data->fifo4[j]);
|
||||
json_object_add_value_string(root, "FIFO 4 ASCII String", fifo_arr);
|
||||
|
||||
fifo = fifo_arr;
|
||||
memset((void *)fifo, 0, 16);
|
||||
for (j = 0; j < 16; j++)
|
||||
fifo += sprintf(fifo, "%c", log_data->fifo5[j]);
|
||||
json_object_add_value_string(root, "FIFO 5 ASCII String", fifo_arr);
|
||||
|
||||
fifo = fifo_arr;
|
||||
memset((void *)fifo, 0, 16);
|
||||
for (j = 0; j < 16; j++)
|
||||
fifo += sprintf(fifo, "%c", log_data->fifo6[j]);
|
||||
json_object_add_value_string(root, "FIFO 6 ASCII String", fifo_arr);
|
||||
|
||||
fifo = fifo_arr;
|
||||
memset((void *)fifo, 0, 16);
|
||||
for (j = 0; j < 16; j++)
|
||||
fifo += sprintf(fifo, "%c", log_data->fifo7[j]);
|
||||
json_object_add_value_string(root, "FIFO 7 ASCII String", fifo_arr);
|
||||
|
||||
fifo = fifo_arr;
|
||||
memset((void *)fifo, 0, 16);
|
||||
for (j = 0; j < 16; j++)
|
||||
fifo += sprintf(fifo, "%c", log_data->fifo8[j]);
|
||||
json_object_add_value_string(root, "FIFO 8 ASCII String", fifo_arr);
|
||||
|
||||
fifo = fifo_arr;
|
||||
memset((void *)fifo, 0, 16);
|
||||
for (j = 0; j < 16; j++)
|
||||
fifo += sprintf(fifo, "%c", log_data->fifo9[j]);
|
||||
json_object_add_value_string(root, "FIFO 9 ASCII String", fifo_arr);
|
||||
|
||||
fifo = fifo_arr;
|
||||
memset((void *)fifo, 0, 16);
|
||||
for (j = 0; j < 16; j++)
|
||||
fifo += sprintf(fifo, "%c", log_data->fifo10[j]);
|
||||
json_object_add_value_string(root, "FIFO 10 ASCII String", fifo_arr);
|
||||
|
||||
fifo = fifo_arr;
|
||||
memset((void *)fifo, 0, 16);
|
||||
for (j = 0; j < 16; j++)
|
||||
fifo += sprintf(fifo, "%c", log_data->fifo11[j]);
|
||||
json_object_add_value_string(root, "FIFO 11 ASCII String", fifo_arr);
|
||||
|
||||
fifo = fifo_arr;
|
||||
memset((void *)fifo, 0, 16);
|
||||
for (j = 0; j < 16; j++)
|
||||
fifo += sprintf(fifo, "%c", log_data->fifo12[j]);
|
||||
json_object_add_value_string(root, "FIFO 12 ASCII String", fifo_arr);
|
||||
|
||||
fifo = fifo_arr;
|
||||
memset((void *)fifo, 0, 16);
|
||||
for (j = 0; j < 16; j++)
|
||||
fifo += sprintf(fifo, "%c", log_data->fifo13[j]);
|
||||
json_object_add_value_string(root, "FIFO 13 ASCII String", fifo_arr);
|
||||
|
||||
fifo = fifo_arr;
|
||||
memset((void *)fifo, 0, 16);
|
||||
for (j = 0; j < 16; j++)
|
||||
fifo += sprintf(fifo, "%c", log_data->fifo14[j]);
|
||||
json_object_add_value_string(root, "FIFO 14 ASCII String", fifo_arr);
|
||||
|
||||
fifo = fifo_arr;
|
||||
memset((void *)fifo, 0, 16);
|
||||
for (j = 0; j < 16; j++)
|
||||
fifo += sprintf(fifo, "%c", log_data->fifo15[j]);
|
||||
json_object_add_value_string(root, "FIFO 15 ASCII String", fifo_arr);
|
||||
|
||||
fifo = fifo_arr;
|
||||
memset((void *)fifo, 0, 16);
|
||||
for (j = 0; j < 16; j++)
|
||||
fifo += sprintf(fifo, "%c", log_data->fifo16[j]);
|
||||
json_object_add_value_string(root, "FIFO 16 ASCII String", fifo_arr);
|
||||
|
||||
res = res_arr;
|
||||
memset((__u8 *)res, 0, 48);
|
||||
for (j = 0; j < 48; j++)
|
||||
res += sprintf(res, "%d", log_data->reserved3[j]);
|
||||
|
@ -772,6 +1031,7 @@ static void json_c7_log(struct nvme_dev *dev, struct tcg_configuration_log *log_
|
|||
char *guid = guid_buf;
|
||||
char res_arr[458];
|
||||
char *res = res_arr;
|
||||
__u16 log_page_version = le16_to_cpu(log_data->log_page_version);
|
||||
|
||||
root = json_create_object();
|
||||
|
||||
|
@ -800,7 +1060,7 @@ static void json_c7_log(struct nvme_dev *dev, struct tcg_configuration_log *log_
|
|||
log_data->no_of_read_unlock_locking_obj);
|
||||
json_object_add_value_int(root, "Number of Write Unlocked Locking Objects",
|
||||
log_data->no_of_write_unlock_locking_obj);
|
||||
json_object_add_value_int(root, "Reserved2", log_data->rsvd2);
|
||||
json_object_add_value_int(root, "Reserved2", log_data->rsvd15);
|
||||
|
||||
json_object_add_value_int(root, "SID Authentication Try Count",
|
||||
le32_to_cpu(log_data->sid_auth_try_count));
|
||||
|
@ -813,12 +1073,20 @@ static void json_c7_log(struct nvme_dev *dev, struct tcg_configuration_log *log_
|
|||
json_object_add_value_int(root, "TCG Error Count", le32_to_cpu(log_data->tcg_ec));
|
||||
|
||||
memset((__u8 *)res, 0, 458);
|
||||
for (j = 0; j < 458; j++)
|
||||
res += sprintf(res, "%d", log_data->rsvd3[j]);
|
||||
if (log_page_version == 1) {
|
||||
res += sprintf(res, "%d%d", *(__u8 *)&log_data->no_of_ns_prov_locking_obj_ext,
|
||||
*((__u8 *)&log_data->no_of_ns_prov_locking_obj_ext + 1));
|
||||
} else {
|
||||
json_object_add_value_int(root,
|
||||
"Number of Namespace Provisioned Locking Objects Extended",
|
||||
log_data->no_of_ns_prov_locking_obj_ext);
|
||||
}
|
||||
|
||||
for (j = 0; j < 456; j++)
|
||||
res += sprintf(res, "%d", log_data->rsvd38[j]);
|
||||
json_object_add_value_string(root, "Reserved3", res_arr);
|
||||
|
||||
json_object_add_value_int(root, "Log Page Version",
|
||||
le16_to_cpu(log_data->log_page_version));
|
||||
json_object_add_value_int(root, "Log Page Version", log_page_version);
|
||||
|
||||
memset((void *)guid, 0, GUID_LEN);
|
||||
for (j = GUID_LEN - 1; j >= 0; j--)
|
||||
|
|
|
@ -30,18 +30,21 @@ static void stdout_hwcomp_log(struct hwcomp_log *log, __u32 id, bool list)
|
|||
{
|
||||
size_t date_lot_code_offset = sizeof(struct hwcomp_desc);
|
||||
int num = 1;
|
||||
long double log_bytes = uint128_t_to_double(le128_to_cpu(log->size));
|
||||
struct hwcomp_desc_entry e = { log->desc };
|
||||
|
||||
long double log_size = uint128_t_to_double(le128_to_cpu(log->size)) * sizeof(__le32);
|
||||
if (log->ver == 1)
|
||||
log_bytes *= sizeof(__le32);
|
||||
|
||||
printf("Log Identifier: 0x%02xh\n", LID_HWCOMP);
|
||||
printf("Log Identifier: 0x%02xh\n", OCP_LID_HWCOMP);
|
||||
printf("Log Page Version: 0x%x\n", le16_to_cpu(log->ver));
|
||||
print_array("Reserved2", log->rsvd2, ARRAY_SIZE(log->rsvd2));
|
||||
print_array("Log page GUID", log->guid, ARRAY_SIZE(log->guid));
|
||||
printf("Hardware Component Log Size: 0x%"PRIx64"\n", (uint64_t)log_size);
|
||||
printf("Hardware Component Log Size: 0x%"PRIx64"\n", (uint64_t)log_bytes);
|
||||
print_array("Reserved48", log->rsvd48, ARRAY_SIZE(log->rsvd48));
|
||||
printf("Component Descriptions\n");
|
||||
while (log_size > 0) {
|
||||
log_bytes -= offsetof(struct hwcomp_log, desc);
|
||||
while (log_bytes > 0) {
|
||||
e.date_lot_size = le64_to_cpu(e.desc->date_lot_size) * sizeof(__le32);
|
||||
e.date_lot_code = e.date_lot_size ? (__u8 *)e.desc + date_lot_code_offset : NULL;
|
||||
e.add_info_size = le64_to_cpu(e.desc->add_info_size) * sizeof(__le32);
|
||||
|
@ -51,7 +54,7 @@ static void stdout_hwcomp_log(struct hwcomp_log *log, __u32 id, bool list)
|
|||
print_hwcomp_desc(&e, list, num++);
|
||||
e.desc_size = date_lot_code_offset + e.date_lot_size + e.add_info_size;
|
||||
e.desc = (struct hwcomp_desc *)((__u8 *)e.desc + e.desc_size);
|
||||
log_size -= e.desc_size;
|
||||
log_bytes -= e.desc_size;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,8 +75,7 @@ static void stdout_fw_activation_history(const struct fw_activation_history *fw_
|
|||
printf(" %-22s%d\n", "entry length:", entry->entry_length);
|
||||
printf(" %-22s%d\n", "activation count:",
|
||||
le16_to_cpu(entry->activation_count));
|
||||
printf(" %-22s%"PRIu64"\n", "timestamp:",
|
||||
(0x0000FFFFFFFFFFFF & le64_to_cpu(entry->timestamp)));
|
||||
printf(" %-22s%"PRIu64"\n", "timestamp:", int48_to_long(entry->ts.timestamp));
|
||||
printf(" %-22s%"PRIu64"\n", "power cycle count:",
|
||||
le64_to_cpu(entry->power_cycle_count));
|
||||
printf(" %-22s%.*s\n", "previous firmware:", (int)sizeof(entry->previous_fw),
|
||||
|
@ -95,101 +97,144 @@ static void stdout_fw_activation_history(const struct fw_activation_history *fw_
|
|||
printf("\n");
|
||||
}
|
||||
|
||||
static void stdout_smart_extended_log(void *data)
|
||||
static void stdout_smart_extended_log(struct ocp_smart_extended_log *log, unsigned int version)
|
||||
{
|
||||
uint16_t smart_log_ver = 0;
|
||||
__u8 *log_data = data;
|
||||
uint16_t dssd_version = 0;
|
||||
int i = 0;
|
||||
|
||||
printf("SMART Cloud Attributes :-\n");
|
||||
|
||||
printf(" Physical media units written - %"PRIu64" %"PRIu64"\n",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW + 8] & 0xFFFFFFFFFFFFFFFF),
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW] & 0xFFFFFFFFFFFFFFFF));
|
||||
le64_to_cpu(*(uint64_t *)&log->physical_media_units_written[8]),
|
||||
le64_to_cpu(*(uint64_t *)&log->physical_media_units_written));
|
||||
printf(" Physical media units read - %"PRIu64" %"PRIu64"\n",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR + 8] & 0xFFFFFFFFFFFFFFFF),
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR] & 0xFFFFFFFFFFFFFFFF));
|
||||
le64_to_cpu(*(uint64_t *)&log->physical_media_units_read[8]),
|
||||
le64_to_cpu(*(uint64_t *)&log->physical_media_units_read));
|
||||
printf(" Bad user nand blocks - Raw %"PRIu64"\n",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BUNBR] & 0x0000FFFFFFFFFFFF));
|
||||
int48_to_long(log->bad_user_nand_blocks_raw));
|
||||
printf(" Bad user nand blocks - Normalized %d\n",
|
||||
(uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BUNBN]));
|
||||
le16_to_cpu(log->bad_user_nand_blocks_normalized));
|
||||
printf(" Bad system nand blocks - Raw %"PRIu64"\n",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BSNBR] & 0x0000FFFFFFFFFFFF));
|
||||
int48_to_long(log->bad_system_nand_blocks_raw));
|
||||
printf(" Bad system nand blocks - Normalized %d\n",
|
||||
(uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BSNBN]));
|
||||
le16_to_cpu(log->bad_system_nand_blocks_normalized));
|
||||
printf(" XOR recovery count %"PRIu64"\n",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_XRC]));
|
||||
le64_to_cpu(log->xor_recovery_count));
|
||||
printf(" Uncorrectable read error count %"PRIu64"\n",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UREC]));
|
||||
le64_to_cpu(log->uncorrectable_read_err_count));
|
||||
printf(" Soft ecc error count %"PRIu64"\n",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SEEC]));
|
||||
le64_to_cpu(log->soft_ecc_err_count));
|
||||
printf(" End to end detected errors %"PRIu32"\n",
|
||||
(uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EEDC]));
|
||||
le32_to_cpu(log->end_to_end_detected_err));
|
||||
printf(" End to end corrected errors %"PRIu32"\n",
|
||||
(uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EECE]));
|
||||
le32_to_cpu(log->end_to_end_corrected_err));
|
||||
printf(" System data percent used %d\n",
|
||||
(__u8)log_data[SCAO_SDPU]);
|
||||
log->system_data_used_percent);
|
||||
printf(" Refresh counts %"PRIu64"\n",
|
||||
(uint64_t)(le64_to_cpu(*(uint64_t *)&log_data[SCAO_RFSC]) & 0x00FFFFFFFFFFFFFF));
|
||||
int56_to_long(log->refresh_counts));
|
||||
printf(" Max User data erase counts %"PRIu32"\n",
|
||||
(uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MXUDEC]));
|
||||
le32_to_cpu(log->user_data_erase_count_max));
|
||||
printf(" Min User data erase counts %"PRIu32"\n",
|
||||
(uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MNUDEC]));
|
||||
le32_to_cpu(log->user_data_erase_count_min));
|
||||
printf(" Number of Thermal throttling events %d\n",
|
||||
(__u8)log_data[SCAO_NTTE]);
|
||||
log->thermal_throttling_event_count);
|
||||
printf(" Current throttling status 0x%x\n",
|
||||
(__u8)log_data[SCAO_CTS]);
|
||||
log->thermal_throttling_current_status);
|
||||
printf(" PCIe correctable error count %"PRIu64"\n",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PCEC]));
|
||||
le64_to_cpu(log->pcie_correctable_err_count));
|
||||
printf(" Incomplete shutdowns %"PRIu32"\n",
|
||||
(uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_ICS]));
|
||||
le32_to_cpu(log->incomplete_shoutdowns));
|
||||
printf(" Percent free blocks %d\n",
|
||||
(__u8)log_data[SCAO_PFB]);
|
||||
log->percent_free_blocks);
|
||||
printf(" Capacitor health %"PRIu16"\n",
|
||||
(uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_CPH]));
|
||||
printf(" NVMe base errata version %c\n",
|
||||
(uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_CPH]));
|
||||
printf(" NVMe command set errata version %c\n",
|
||||
(uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_CPH]));
|
||||
le16_to_cpu(log->capacitor_health));
|
||||
printf(" Unaligned I/O %"PRIu64"\n",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UIO]));
|
||||
le64_to_cpu(log->unaligned_io));
|
||||
printf(" Security Version Number %"PRIu64"\n",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN]));
|
||||
le64_to_cpu(log->security_version));
|
||||
printf(" NUSE - Namespace utilization %"PRIu64"\n",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE]));
|
||||
le64_to_cpu(log->total_nuse));
|
||||
printf(" PLP start count %s\n",
|
||||
uint128_t_to_string(le128_to_cpu(&log_data[SCAO_PSC])));
|
||||
uint128_t_to_string(le128_to_cpu(log->plp_start_count)));
|
||||
printf(" Endurance estimate %s\n",
|
||||
uint128_t_to_string(le128_to_cpu(&log_data[SCAO_EEST])));
|
||||
smart_log_ver = (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_LPV]);
|
||||
uint128_t_to_string(le128_to_cpu(log->endurance_estimate)));
|
||||
smart_log_ver = le16_to_cpu(log->log_page_version);
|
||||
printf(" Log page version %"PRIu16"\n", smart_log_ver);
|
||||
printf(" Log page GUID 0x");
|
||||
printf("%"PRIx64"%"PRIx64"\n", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]),
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG]));
|
||||
printf("%"PRIx64"%"PRIx64"\n", le64_to_cpu(*(uint64_t *)&log->log_page_guid[8]),
|
||||
le64_to_cpu(*(uint64_t *)&log->log_page_guid));
|
||||
switch (smart_log_ver) {
|
||||
case 0 ... 1:
|
||||
break;
|
||||
default:
|
||||
case 4:
|
||||
printf(" NVMe Command Set Errata Version %d\n",
|
||||
(__u8)log_data[SCAO_NCSEV]);
|
||||
log->nvme_cmdset_errata_version);
|
||||
printf(" Lowest Permitted Firmware Revision %"PRIu64"\n",
|
||||
le64_to_cpu(*(uint64_t *)&log_data[SCAO_PSCC]));
|
||||
le64_to_cpu(log->lowest_permitted_fw_rev));
|
||||
printf(" NVMe Over Pcie Errata Version %d\n",
|
||||
log->nvme_over_pcie_errate_version);
|
||||
printf(" NVMe Mi Errata Version %d\n",
|
||||
log->nvme_mi_errata_version);
|
||||
printf(" Total media dies %"PRIu16"\n",
|
||||
le16_to_cpu(log->total_media_dies));
|
||||
printf(" Total die failure tolerance %"PRIu16"\n",
|
||||
le16_to_cpu(log->total_die_failure_tolerance));
|
||||
printf(" Media dies offline %"PRIu16"\n",
|
||||
le16_to_cpu(log->media_dies_offline));
|
||||
printf(" Max temperature recorded %d\n",
|
||||
log->max_temperature_recorded);
|
||||
printf(" Nand avg erase count %"PRIu64"\n",
|
||||
le64_to_cpu(log->nand_avg_erase_count));
|
||||
printf(" Command timeouts %"PRIu32"\n",
|
||||
le32_to_cpu(log->command_timeouts));
|
||||
printf(" Sys area program fail count raw %"PRIu32"\n",
|
||||
le32_to_cpu(log->sys_area_program_fail_count_raw));
|
||||
printf(" Sys area program fail count noralized %d\n",
|
||||
le32_to_cpu(log->sys_area_program_fail_count_normalized));
|
||||
printf(" Sys area uncorrectable read count raw %"PRIu32"\n",
|
||||
le32_to_cpu(log->sys_area_uncorr_read_count_raw));
|
||||
printf(" Sys area uncorrectable read count noralized %d\n",
|
||||
le32_to_cpu(log->sys_area_uncorr_read_count_normalized));
|
||||
printf(" Sys area erase fail count raw %"PRIu32"\n",
|
||||
le32_to_cpu(log->sys_area_erase_fail_count_raw));
|
||||
printf(" Sys area erase fail count noralized %d\n",
|
||||
le32_to_cpu(log->sys_area_erase_fail_count_normalized));
|
||||
printf(" Max peak power capability %"PRIu16"\n",
|
||||
le16_to_cpu(log->max_peak_power_capability));
|
||||
printf(" Current max avg power %"PRIu16"\n",
|
||||
le16_to_cpu(log->current_max_avg_power));
|
||||
printf(" Lifetime power consumed %"PRIu64"\n",
|
||||
int48_to_long(log->lifetime_power_consumed));
|
||||
printf(" Dssd firmware revision ");
|
||||
for (i = 0; i < sizeof(log->dssd_firmware_revision); i++)
|
||||
printf("%c", log->dssd_firmware_revision[i]);
|
||||
printf("\n");
|
||||
printf(" Dssd firmware build UUID %s\n",
|
||||
util_uuid_to_string(log->dssd_firmware_build_uuid));
|
||||
printf(" Dssd firmware build label ");
|
||||
for (i = 0; i < sizeof(log->dssd_firmware_build_label); i++)
|
||||
printf("%c", log->dssd_firmware_build_label[i]);
|
||||
printf("\n");
|
||||
fallthrough;
|
||||
case 2 ... 3:
|
||||
printf(" Errata Version Field %d\n",
|
||||
(__u8)log_data[SCAO_EVF]);
|
||||
log->dssd_errata_version);
|
||||
memcpy(&dssd_version, log->dssd_point_version, sizeof(dssd_version));
|
||||
printf(" Point Version Field %"PRIu16"\n",
|
||||
le16_to_cpu(*(uint16_t *)&log_data[SCAO_PVF]));
|
||||
le16_to_cpu(dssd_version));
|
||||
memcpy(&dssd_version, log->dssd_minor_version, sizeof(dssd_version));
|
||||
printf(" Minor Version Field %"PRIu16"\n",
|
||||
le16_to_cpu(*(uint16_t *)&log_data[SCAO_MIVF]));
|
||||
le16_to_cpu(dssd_version));
|
||||
printf(" Major Version Field %d\n",
|
||||
(__u8)log_data[SCAO_MAVF]);
|
||||
log->dssd_major_version);
|
||||
printf(" NVMe Base Errata Version %d\n",
|
||||
(__u8)log_data[SCAO_NBEV]);
|
||||
log->nvme_base_errata_version);
|
||||
printf(" PCIe Link Retraining Count %"PRIu64"\n",
|
||||
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PLRC]));
|
||||
le64_to_cpu(log->pcie_link_retaining_count));
|
||||
printf(" Power State Change Count %"PRIu64"\n",
|
||||
le64_to_cpu(*(uint64_t *)&log_data[SCAO_PSCC]));
|
||||
le64_to_cpu(log->power_state_change_count));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
@ -205,6 +250,7 @@ static void stdout_c3_log(struct nvme_dev *dev, struct ssd_latency_monitor_log *
|
|||
{
|
||||
char ts_buf[128];
|
||||
int i, j;
|
||||
__u16 log_page_version = le16_to_cpu(log_data->log_page_version);
|
||||
|
||||
printf("-Latency Monitor/C3 Log Page Data-\n");
|
||||
printf(" Controller : %s\n", dev->name);
|
||||
|
@ -237,6 +283,17 @@ static void stdout_c3_log(struct nvme_dev *dev, struct ssd_latency_monitor_log *
|
|||
le16_to_cpu(log_data->active_latency_stamp_units));
|
||||
printf(" Static Latency Stamp Units %d\n",
|
||||
le16_to_cpu(log_data->static_latency_stamp_units));
|
||||
|
||||
if (log_page_version >= 0x4) {
|
||||
printf(" Debug Telemetry Log Size 0x");
|
||||
for (i = ARRAY_SIZE(log_data->latency_monitor_debug_log_size) - 1;
|
||||
i > 0 && (log_data->latency_monitor_debug_log_size[i] == 0); i--)
|
||||
;
|
||||
while (i >= 0)
|
||||
printf("%02x", log_data->latency_monitor_debug_log_size[i--]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
printf(" Debug Log Trigger Enable %d\n",
|
||||
le16_to_cpu(log_data->debug_log_trigger_enable));
|
||||
printf(" Debug Log Measured Latency %d\n",
|
||||
|
@ -253,8 +310,7 @@ static void stdout_c3_log(struct nvme_dev *dev, struct ssd_latency_monitor_log *
|
|||
le16_to_cpu(log_data->debug_log_counter_trigger));
|
||||
printf(" Debug Log Stamp Units %d\n",
|
||||
le16_to_cpu(log_data->debug_log_stamp_units));
|
||||
printf(" Log Page Version %d\n",
|
||||
le16_to_cpu(log_data->log_page_version));
|
||||
printf(" Log Page Version %d\n", log_page_version);
|
||||
|
||||
char guid[(GUID_LEN * 2) + 1];
|
||||
char *ptr = &guid[0];
|
||||
|
@ -632,59 +688,67 @@ static void stdout_c9_log(struct telemetry_str_log_format *log_data, __u8 *log_d
|
|||
static void stdout_c7_log(struct nvme_dev *dev, struct tcg_configuration_log *log_data)
|
||||
{
|
||||
int j;
|
||||
__u16 log_page_version = le16_to_cpu(log_data->log_page_version);
|
||||
|
||||
printf("TCG Configuration C7 Log Page Data-\n");
|
||||
|
||||
printf(" State : 0x%x\n",
|
||||
log_data->state);
|
||||
printf(" Reserved1 : 0x");
|
||||
printf(" State : 0x%x\n",
|
||||
log_data->state);
|
||||
printf(" Reserved1 : ");
|
||||
for (j = 0; j < 3; j++)
|
||||
printf("%d", log_data->rsvd1[j]);
|
||||
printf("\n");
|
||||
printf(" Locking SP Activation Count : 0x%x\n",
|
||||
printf(" Locking SP Activation Count : 0x%x\n",
|
||||
log_data->locking_sp_act_count);
|
||||
printf(" Tper Revert Count : 0x%x\n",
|
||||
printf(" Tper Revert Count : 0x%x\n",
|
||||
log_data->type_rev_count);
|
||||
printf(" Locking SP Revert Count : 0x%x\n",
|
||||
printf(" Locking SP Revert Count : 0x%x\n",
|
||||
log_data->locking_sp_rev_count);
|
||||
printf(" Number of Locking Objects : 0x%x\n",
|
||||
printf(" Number of Locking Objects : 0x%x\n",
|
||||
log_data->no_of_locking_obj);
|
||||
printf(" Number of Single User Mode Locking Objects : 0x%x\n",
|
||||
printf(" Number of Single User Mode Locking Objects : 0x%x\n",
|
||||
log_data->no_of_single_um_locking_obj);
|
||||
printf(" Number of Range Provisioned Locking Objects : 0x%x\n",
|
||||
printf(" Number of Range Provisioned Locking Objects : 0x%x\n",
|
||||
log_data->no_of_range_prov_locking_obj);
|
||||
printf(" Number of Namespace Provisioned Locking Objects : 0x%x\n",
|
||||
printf(" Number of Namespace Provisioned Locking Objects : 0x%x\n",
|
||||
log_data->no_of_ns_prov_locking_obj);
|
||||
printf(" Number of Read Locked Locking Objects : 0x%x\n",
|
||||
printf(" Number of Read Locked Locking Objects : 0x%x\n",
|
||||
log_data->no_of_read_lock_locking_obj);
|
||||
printf(" Number of Write Locked Locking Objects : 0x%x\n",
|
||||
printf(" Number of Write Locked Locking Objects : 0x%x\n",
|
||||
log_data->no_of_write_lock_locking_obj);
|
||||
printf(" Number of Read Unlocked Locking Objects : 0x%x\n",
|
||||
printf(" Number of Read Unlocked Locking Objects : 0x%x\n",
|
||||
log_data->no_of_read_unlock_locking_obj);
|
||||
printf(" Number of Write Unlocked Locking Objects : 0x%x\n",
|
||||
printf(" Number of Write Unlocked Locking Objects : 0x%x\n",
|
||||
log_data->no_of_write_unlock_locking_obj);
|
||||
printf(" Reserved2 : 0x%x\n",
|
||||
log_data->rsvd2);
|
||||
|
||||
printf(" SID Authentication Try Count : 0x%x\n",
|
||||
printf(" Reserved2 : %x\n",
|
||||
log_data->rsvd15);
|
||||
printf(" SID Authentication Try Count : 0x%x\n",
|
||||
le32_to_cpu(log_data->sid_auth_try_count));
|
||||
printf(" SID Authentication Try Limit : 0x%x\n",
|
||||
printf(" SID Authentication Try Limit : 0x%x\n",
|
||||
le32_to_cpu(log_data->sid_auth_try_limit));
|
||||
printf(" Programmatic TCG Reset Count : 0x%x\n",
|
||||
printf(" Programmatic TCG Reset Count : 0x%x\n",
|
||||
le32_to_cpu(log_data->pro_tcg_rc));
|
||||
printf(" Programmatic Reset Lock Count : 0x%x\n",
|
||||
printf(" Programmatic Reset Lock Count : 0x%x\n",
|
||||
le32_to_cpu(log_data->pro_rlc));
|
||||
printf(" TCG Error Count : 0x%x\n",
|
||||
printf(" TCG Error Count : 0x%x\n",
|
||||
le32_to_cpu(log_data->tcg_ec));
|
||||
|
||||
printf(" Reserved3 : 0x");
|
||||
for (j = 0; j < 458; j++)
|
||||
printf("%d", log_data->rsvd3[j]);
|
||||
if (log_page_version == 1) {
|
||||
printf(" Reserved3 : %d%d",
|
||||
*(__u8 *)&log_data->no_of_ns_prov_locking_obj_ext,
|
||||
*((__u8 *)&log_data->no_of_ns_prov_locking_obj_ext + 1));
|
||||
} else {
|
||||
printf(" Number of Namespace Provisioned Locking Objects Extended : 0x%x\n",
|
||||
le16_to_cpu(log_data->no_of_ns_prov_locking_obj_ext));
|
||||
printf(" Reserved3 : ");
|
||||
}
|
||||
for (j = 0; j < 456; j++)
|
||||
printf("%d", log_data->rsvd38[j]);
|
||||
printf("\n");
|
||||
|
||||
printf(" Log Page Version : 0x%x\n",
|
||||
le16_to_cpu(log_data->log_page_version));
|
||||
printf(" Log page GUID : 0x");
|
||||
printf(" Log Page Version : 0x%x\n",
|
||||
log_page_version);
|
||||
printf(" Log page GUID : 0x");
|
||||
for (j = GUID_LEN - 1; j >= 0; j--)
|
||||
printf("%02x", log_data->log_page_guid[j]);
|
||||
printf("\n");
|
||||
|
|
|
@ -36,9 +36,10 @@ void ocp_fw_act_history(const struct fw_activation_history *fw_history, nvme_pri
|
|||
ocp_print(fw_act_history, flags, fw_history);
|
||||
}
|
||||
|
||||
void ocp_smart_extended_log(void *data, nvme_print_flags_t flags)
|
||||
void ocp_smart_extended_log(struct ocp_smart_extended_log *log, unsigned int version,
|
||||
nvme_print_flags_t flags)
|
||||
{
|
||||
ocp_print(smart_extended_log, flags, data);
|
||||
ocp_print(smart_extended_log, flags, log, version);
|
||||
}
|
||||
|
||||
void ocp_show_telemetry_log(struct ocp_telemetry_parse_options *options, nvme_print_flags_t flags)
|
||||
|
|
|
@ -4,13 +4,14 @@
|
|||
|
||||
#include "ocp-hardware-component-log.h"
|
||||
#include "ocp-fw-activation-history.h"
|
||||
#include "ocp-smart-extended-log.h"
|
||||
#include "ocp-telemetry-decode.h"
|
||||
#include "ocp-nvme.h"
|
||||
|
||||
struct ocp_print_ops {
|
||||
void (*hwcomp_log)(struct hwcomp_log *log, __u32 id, bool list);
|
||||
void (*fw_act_history)(const struct fw_activation_history *fw_history);
|
||||
void (*smart_extended_log)(void *data);
|
||||
void (*smart_extended_log)(struct ocp_smart_extended_log *log, unsigned int version);
|
||||
void (*telemetry_log)(struct ocp_telemetry_parse_options *options);
|
||||
void (*c3_log)(struct nvme_dev *dev, struct ssd_latency_monitor_log *log_data);
|
||||
void (*c5_log)(struct nvme_dev *dev, struct unsupported_requirement_log *log_data);
|
||||
|
@ -36,7 +37,8 @@ static inline struct ocp_print_ops *ocp_get_json_print_ops(nvme_print_flags_t fl
|
|||
|
||||
void ocp_show_hwcomp_log(struct hwcomp_log *log, __u32 id, bool list, nvme_print_flags_t flags);
|
||||
void ocp_fw_act_history(const struct fw_activation_history *fw_history, nvme_print_flags_t flags);
|
||||
void ocp_smart_extended_log(void *data, nvme_print_flags_t flags);
|
||||
void ocp_smart_extended_log(struct ocp_smart_extended_log *log, unsigned int version,
|
||||
nvme_print_flags_t flags);
|
||||
void ocp_show_telemetry_log(struct ocp_telemetry_parse_options *options, nvme_print_flags_t flags);
|
||||
void ocp_c3_log(struct nvme_dev *dev, struct ssd_latency_monitor_log *log_data,
|
||||
nvme_print_flags_t flags);
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
#include "common.h"
|
||||
#include "nvme-print.h"
|
||||
#include "ocp-print.h"
|
||||
#include "ocp-utils.h"
|
||||
|
||||
/* C0 SCAO Log Page */
|
||||
#define C0_SMART_CLOUD_ATTR_LEN 0x200
|
||||
#define C0_SMART_CLOUD_ATTR_OPCODE 0xC0
|
||||
|
||||
static __u8 scao_guid[GUID_LEN] = {
|
||||
0xC5, 0xAF, 0x10, 0x28,
|
||||
|
@ -26,12 +26,21 @@ static __u8 scao_guid[GUID_LEN] = {
|
|||
0xC9, 0x14, 0xD5, 0xAF
|
||||
};
|
||||
|
||||
static int get_c0_log_page(int fd, char *format)
|
||||
static int get_c0_log_page(struct nvme_dev *dev, char *format,
|
||||
unsigned int format_version)
|
||||
{
|
||||
nvme_print_flags_t fmt;
|
||||
__u8 *data;
|
||||
struct ocp_smart_extended_log *data;
|
||||
int i;
|
||||
int ret;
|
||||
int fd = dev_fd(dev);
|
||||
struct nvme_get_log_args args = {
|
||||
.args_size = sizeof(args),
|
||||
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
|
||||
.lid = (enum nvme_cmd_get_log_lid)OCP_LID_SMART,
|
||||
.nsid = NVME_NSID_ALL,
|
||||
.len = C0_SMART_CLOUD_ATTR_LEN,
|
||||
};
|
||||
|
||||
ret = validate_output_format(format, &fmt);
|
||||
if (ret < 0) {
|
||||
|
@ -46,8 +55,9 @@ static int get_c0_log_page(int fd, char *format)
|
|||
}
|
||||
memset(data, 0, sizeof(__u8) * C0_SMART_CLOUD_ATTR_LEN);
|
||||
|
||||
ret = nvme_get_log_simple(fd, C0_SMART_CLOUD_ATTR_OPCODE,
|
||||
C0_SMART_CLOUD_ATTR_LEN, data);
|
||||
args.log = data;
|
||||
ocp_get_uuid_index(dev, &args.uuidx);
|
||||
ret = nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args);
|
||||
|
||||
if (strcmp(format, "json"))
|
||||
fprintf(stderr, "NVMe Status:%s(%x)\n",
|
||||
|
@ -57,7 +67,7 @@ static int get_c0_log_page(int fd, char *format)
|
|||
/* check log page guid */
|
||||
/* Verify GUID matches */
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (scao_guid[i] != data[SCAO_LPG + i]) {
|
||||
if (scao_guid[i] != data->log_page_guid[i]) {
|
||||
int j;
|
||||
|
||||
fprintf(stderr, "ERROR : OCP : Unknown GUID in C0 Log Page data\n");
|
||||
|
@ -67,7 +77,7 @@ static int get_c0_log_page(int fd, char *format)
|
|||
|
||||
fprintf(stderr, "\nERROR : OCP : Actual GUID: 0x");
|
||||
for (j = 0; j < 16; j++)
|
||||
fprintf(stderr, "%x", data[SCAO_LPG + j]);
|
||||
fprintf(stderr, "%x", data->log_page_guid[j]);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
ret = -1;
|
||||
|
@ -76,7 +86,7 @@ static int get_c0_log_page(int fd, char *format)
|
|||
}
|
||||
|
||||
/* print the data */
|
||||
ocp_smart_extended_log(data, fmt);
|
||||
ocp_smart_extended_log(data, format_version, fmt);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR : OCP : Unable to read C0 data from buffer\n");
|
||||
}
|
||||
|
@ -95,14 +105,17 @@ int ocp_smart_add_log(int argc, char **argv, struct command *cmd,
|
|||
|
||||
struct config {
|
||||
char *output_format;
|
||||
unsigned int output_format_version;
|
||||
};
|
||||
|
||||
struct config cfg = {
|
||||
.output_format = "normal",
|
||||
.output_format_version = 1,
|
||||
};
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
OPT_FMT("output-format", 'o', &cfg.output_format, "output Format: normal|json"),
|
||||
OPT_UINT("output-format-version", 0, &cfg.output_format_version, "output Format version: 1|2"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
|
@ -110,7 +123,8 @@ int ocp_smart_add_log(int argc, char **argv, struct command *cmd,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = get_c0_log_page(dev_fd(dev), cfg.output_format);
|
||||
ret = get_c0_log_page(dev, cfg.output_format,
|
||||
cfg.output_format_version);
|
||||
if (ret)
|
||||
fprintf(stderr, "ERROR : OCP : Failure reading the C0 Log Page, ret = %d\n",
|
||||
ret);
|
||||
|
|
|
@ -6,50 +6,149 @@
|
|||
* Venkat Ramesh <venkatraghavan@fb.com>
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "linux/types.h"
|
||||
|
||||
#ifndef OCP_SMART_EXTENDED_LOG_H
|
||||
#define OCP_SMART_EXTENDED_LOG_H
|
||||
|
||||
struct command;
|
||||
struct plugin;
|
||||
|
||||
enum {
|
||||
SCAO_PMUW = 0, /* Physical media units written */
|
||||
SCAO_PMUR = 16, /* Physical media units read */
|
||||
SCAO_BUNBR = 32, /* Bad user nand blocks raw */
|
||||
SCAO_BUNBN = 38, /* Bad user nand blocks normalized */
|
||||
SCAO_BSNBR = 40, /* Bad system nand blocks raw */
|
||||
SCAO_BSNBN = 46, /* Bad system nand blocks normalized */
|
||||
SCAO_XRC = 48, /* XOR recovery count */
|
||||
SCAO_UREC = 56, /* Uncorrectable read error count */
|
||||
SCAO_SEEC = 64, /* Soft ecc error count */
|
||||
SCAO_EEDC = 72, /* End to end detected errors */
|
||||
SCAO_EECE = 76, /* End to end corrected errors */
|
||||
SCAO_SDPU = 80, /* System data percent used */
|
||||
SCAO_RFSC = 81, /* Refresh counts */
|
||||
SCAO_MXUDEC = 88, /* Max User data erase counts */
|
||||
SCAO_MNUDEC = 92, /* Min User data erase counts */
|
||||
SCAO_NTTE = 96, /* Number of Thermal throttling events */
|
||||
SCAO_CTS = 97, /* Current throttling status */
|
||||
SCAO_EVF = 98, /* Errata Version Field */
|
||||
SCAO_PVF = 99, /* Point Version Field */
|
||||
SCAO_MIVF = 101, /* Minor Version Field */
|
||||
SCAO_MAVF = 103, /* Major Version Field */
|
||||
SCAO_PCEC = 104, /* PCIe correctable error count */
|
||||
SCAO_ICS = 112, /* Incomplete shutdowns */
|
||||
SCAO_PFB = 120, /* Percent free blocks */
|
||||
SCAO_CPH = 128, /* Capacitor health */
|
||||
SCAO_NBEV = 130, /* NVMe Base Errata Version */
|
||||
SCAO_NCSEV = 131, /* NVMe Command Set Errata Version */
|
||||
SCAO_UIO = 136, /* Unaligned I/O */
|
||||
SCAO_SVN = 144, /* Security Version Number */
|
||||
SCAO_NUSE = 152, /* NUSE - Namespace utilization */
|
||||
SCAO_PSC = 160, /* PLP start count */
|
||||
SCAO_EEST = 176, /* Endurance estimate */
|
||||
SCAO_PLRC = 192, /* PCIe Link Retraining Count */
|
||||
SCAO_PSCC = 200, /* Power State Change Count */
|
||||
SCAO_LPFR = 208, /* Lowest Permitted Firmware Revision */
|
||||
SCAO_LPV = 494, /* Log page version */
|
||||
SCAO_LPG = 496, /* Log page GUID */
|
||||
/**
|
||||
* struct ocp_smart_extended_log - SMART / Health Information Extended
|
||||
* @physical_media_units_written: Physical Media Units Written
|
||||
* @physical_media_units_read: Physical Media Units Read
|
||||
* @bad_user_nand_blocks_raw: Bad User NAND Blocks raw
|
||||
* @bad_user_nand_blocks_normalized: Bad User NAND Blocks normalized
|
||||
* @bad_system_nand_blocks_raw: Bad System NAND Blocks raw
|
||||
* @bad_system_nand_blocks_normalized: Bad System NAND Blocks normalized
|
||||
* @xor_recovery_count: XOR Recovery Count
|
||||
* @uncorrectable_read_err_count: Uncorrectable Read Error Count
|
||||
* @soft_ecc_err_count: Soft ECC Error Count
|
||||
* @end_to_end_detected_err: End to End detected errors
|
||||
* @end_to_end_corrected_err: End to End corrected errors
|
||||
* @system_data_used_percent: System data percent used
|
||||
* @refresh_counts: Refresh Counts
|
||||
* @user_data_erase_count_max: Max User data erase counts
|
||||
* @user_data_erase_count_min: Min User data erase counts
|
||||
* @thermal_throttling_event_count: Number of Thermal throttling events
|
||||
* @dssd_errata_version: DSSD Errata Version
|
||||
* @dssd_point_version: DSSD Point Version
|
||||
* @dssd_minor_version: DSSD Minor Version
|
||||
* @dssd_major_version: DSSD Major Version
|
||||
* @pcie_correctable_err_count: PCIe Correctable Error Count
|
||||
* @incomplete_shoutdowns: Incomplete Shutdowns
|
||||
* @rsvd116: Reserved
|
||||
* @percent_free_blocks: Percent free blocks
|
||||
* @rsvd121: Reserved
|
||||
* @capacitor_health: Capacitor health
|
||||
* @nvme_base_errata_version: NVM Express Base Errata Version
|
||||
* @nvme_cmdset_errata_version: NVMe Command Set Errata Version
|
||||
* @rsvd132: Reserved
|
||||
* @nvme_over_pcie_errate_version: NVMe Over Pcie Errata Version
|
||||
* @nvme_mi_errata_version: NVMe MI Errata Version
|
||||
* @unaligned_io: Unaligned I/O
|
||||
* @security_version: Security Version Number
|
||||
* @total_nuse: Total NUSE - Namespace utilization
|
||||
* @plp_start_count: PLP start count
|
||||
* @endurance_estimate: Endurance Estimate
|
||||
* @pcie_link_retaining_count: PCIe Link Retraining Count
|
||||
* @power_state_change_count: Power State Change Count
|
||||
* @lowest_permitted_fw_rev: Lowest Permitted Firmware Revision -------------
|
||||
* @rsvd216: Reserved
|
||||
* @total_media_dies: Total media dies
|
||||
* @total_die_failure_tolerance: Total die failure tolerance
|
||||
* @media_dies_offline: Media dies offline
|
||||
* @max_temperature_recorded: Max temperature recorded
|
||||
* @rsvd223: Reserved
|
||||
* @nand_avg_erase_count: Nand avg erase count
|
||||
* @command_timeouts: Command timeouts
|
||||
* @sys_area_program_fail_count_raw: Sys area program fail count raw
|
||||
* @sys_area_program_fail_count_normalized: Sys area program fail count noralized
|
||||
* @revd241: Reserved
|
||||
* @sys_area_uncorr_read_count_raw: Sys area uncorrectable read count raw
|
||||
* @sys_area_uncorr_read_count_normalized: Sys area uncorrectable read count noralized
|
||||
* @revd249: Reserved
|
||||
* @sys_area_erase_fail_count_raw: Sys area erase fail count raw
|
||||
* @sys_area_erase_fail_count_normalized: Sys area erase fail count noralized
|
||||
* @revd257: Reserved
|
||||
* @max_peak_power_capability: Max peak power capability
|
||||
* @current_max_avg_power: Current max avg power
|
||||
* @lifetime_power_consumed: Lifetime power consumed
|
||||
* @dssd_firmware_revision: Dssd firmware revision
|
||||
* @dssd_firmware_build_uuid: Dssd firmware build UUID
|
||||
* @dssd_firmware_build_label: Dssd firmware build label
|
||||
* @revd358: Reserved
|
||||
* @log_page_version: Log page version
|
||||
* @log_page_guid: Log page GUID
|
||||
*/
|
||||
struct ocp_smart_extended_log {
|
||||
__u8 physical_media_units_written[16]; /* [15:0] */
|
||||
__u8 physical_media_units_read[16]; /* [31:16] */
|
||||
__u8 bad_user_nand_blocks_raw[6]; /* [37:32] */
|
||||
__le16 bad_user_nand_blocks_normalized; /* [39:38] */
|
||||
__u8 bad_system_nand_blocks_raw[6]; /* [45:40] */
|
||||
__le16 bad_system_nand_blocks_normalized; /* [47:46] */
|
||||
__le64 xor_recovery_count; /* [55:48] */
|
||||
__le64 uncorrectable_read_err_count; /* [63:56] */
|
||||
__le64 soft_ecc_err_count; /* [71:64] */
|
||||
__le32 end_to_end_detected_err; /* [75:72] */
|
||||
__le32 end_to_end_corrected_err; /* [79:76] */
|
||||
__u8 system_data_used_percent; /* [80] */
|
||||
__u8 refresh_counts[7]; /* [87:81] */
|
||||
__le32 user_data_erase_count_max; /* [91:88] */
|
||||
__le32 user_data_erase_count_min; /* [95:92] */
|
||||
__u8 thermal_throttling_event_count; /* [96] */
|
||||
__u8 thermal_throttling_current_status; /* [97] */
|
||||
__u8 dssd_errata_version; /* [98] */
|
||||
__u8 dssd_point_version[2]; /* [100:99] */
|
||||
__u8 dssd_minor_version[2]; /* [102:101] */
|
||||
__u8 dssd_major_version; /* [103] */
|
||||
__le64 pcie_correctable_err_count; /* [111:104] */
|
||||
__le32 incomplete_shoutdowns; /* [115:112] */
|
||||
__u8 rsvd116[4]; /* [119:116] */
|
||||
__u8 percent_free_blocks; /* [120] */
|
||||
__u8 rsvd121[7]; /* [127:121] */
|
||||
__le16 capacitor_health; /* [129:128] */
|
||||
__u8 nvme_base_errata_version; /* [130] */
|
||||
__u8 nvme_cmdset_errata_version; /* [131] */
|
||||
__u8 nvme_over_pcie_errate_version; /* [132] */
|
||||
__u8 nvme_mi_errata_version; /* [133] */
|
||||
__u8 rsvd134[2]; /* [135:134] */
|
||||
__le64 unaligned_io; /* [143:136] */
|
||||
__le64 security_version; /* [151:144] */
|
||||
__le64 total_nuse; /* [159:152] */
|
||||
__u8 plp_start_count[16]; /* [175:160] */
|
||||
__u8 endurance_estimate[16]; /* [191:176] */
|
||||
__le64 pcie_link_retaining_count; /* [199:192] */
|
||||
__le64 power_state_change_count; /* [207:200] */
|
||||
__le64 lowest_permitted_fw_rev; /* [215:208] */
|
||||
__le16 total_media_dies; /* [217:216] */
|
||||
__le16 total_die_failure_tolerance; /* [219:218] */
|
||||
__le16 media_dies_offline; /* [221:220] */
|
||||
__u8 max_temperature_recorded; /* [222] */
|
||||
__u8 rsvd223; /* [223] */
|
||||
__le64 nand_avg_erase_count; /* [231:224] */
|
||||
__le32 command_timeouts; /* [235:232] */
|
||||
__le32 sys_area_program_fail_count_raw; /* [239:236] */
|
||||
__u8 sys_area_program_fail_count_normalized; /* [240] */
|
||||
__u8 rsvd241[3]; /* [243:241] */
|
||||
__le32 sys_area_uncorr_read_count_raw; /* [247:244] */
|
||||
__u8 sys_area_uncorr_read_count_normalized; /* [248] */
|
||||
__u8 rsvd249[3]; /* [251:249] */
|
||||
__le32 sys_area_erase_fail_count_raw; /* [255:252] */
|
||||
__u8 sys_area_erase_fail_count_normalized; /* [256] */
|
||||
__u8 rsvd257[3]; /* [259:257] */
|
||||
__le16 max_peak_power_capability; /* [261:260] */
|
||||
__le16 current_max_avg_power; /* [263:262] */
|
||||
__u8 lifetime_power_consumed[6]; /* [269:264] */
|
||||
__u8 dssd_firmware_revision[8]; /* [277:270] */
|
||||
__u8 dssd_firmware_build_uuid[16]; /* [293:278] */
|
||||
__u8 dssd_firmware_build_label[64]; /* [375:294] */
|
||||
__u8 rsvd358[136]; /* [493:358] */
|
||||
__le16 log_page_version; /* [495:494] */
|
||||
__u8 log_page_guid[16]; /* [511:496] */
|
||||
};
|
||||
|
||||
int ocp_smart_add_log(int argc, char **argv, struct command *cmd,
|
||||
|
|
|
@ -39,6 +39,7 @@ void print_stats_desc(struct telemetry_stats_desc *stat_desc)
|
|||
printf("Statistics info : 0x%x\n", stat_desc->info);
|
||||
printf("NS info : 0x%x\n", stat_desc->ns_info);
|
||||
printf("Statistic Data Size : 0x%x\n", le16_to_cpu(stat_data_sz));
|
||||
printf("Namespace ID[15:0] : 0x%x\n", stat_desc->nsid);
|
||||
|
||||
if (stat_data_sz > 0) {
|
||||
printf("%s : 0x",
|
||||
|
@ -109,13 +110,18 @@ void print_telemetry_fifo_event(__u8 class_type,
|
|||
if ((id == ADMIN_QUEUE_NONZERO_STATUS) ||
|
||||
(id == IO_QUEUE_NONZERO_STATUS)) {
|
||||
printf(" Cmd Op Code : 0x%02x\n", data[0]);
|
||||
__u16 status = *(__u16 *)&data[1];
|
||||
__u16 cmd_id = *(__u16 *)&data[3];
|
||||
__u16 sq_id = *(__u16 *)&data[5];
|
||||
__u16 status;
|
||||
__u16 cmd_id;
|
||||
__u16 sq_id;
|
||||
|
||||
memcpy(&status, &data[1], sizeof(status));
|
||||
memcpy(&cmd_id, &data[3], sizeof(cmd_id));
|
||||
memcpy(&sq_id, &data[5], sizeof(sq_id));
|
||||
|
||||
printf(" Status Code : 0x%04x\n", le16_to_cpu(status));
|
||||
printf(" Cmd ID : 0x%04x\n", le16_to_cpu(cmd_id));
|
||||
printf(" SQ ID : 0x%04x\n", le16_to_cpu(sq_id));
|
||||
printf(" LID,FID,Other Cmd Reserved : 0x%02x\n", data[7]);
|
||||
} else if (id == CC_REGISTER_CHANGED) {
|
||||
__u32 cc_reg_data = *(__u32 *)data;
|
||||
|
||||
|
@ -126,6 +132,20 @@ void print_telemetry_fifo_event(__u8 class_type,
|
|||
|
||||
printf(" CSTS Reg Data : 0x%08x\n",
|
||||
le32_to_cpu(csts_reg_data));
|
||||
} else if (id == OOB_COMMAND) {
|
||||
printf(" Cmd Op Code : 0x%02x\n", data[0]);
|
||||
__u16 status;
|
||||
memcpy(&status, &data[1], sizeof(status));
|
||||
|
||||
printf(" Admin Cmd Status : 0x%04x\n", le16_to_cpu(status));
|
||||
printf(" NVMe MI SC : 0x%02x\n", data[3]);
|
||||
printf(" Byte1 Req Msg : 0x%02x\n", data[4]);
|
||||
printf(" Byte2 Req Msg : 0x%02x\n", data[5]);
|
||||
} else if (id == OOB_AER_EVENT_MSG_TRANS) {
|
||||
__u64 aem = *(__u64 *)data;
|
||||
|
||||
printf(" AEM : 0x%016"PRIx64"\n",
|
||||
le64_to_cpu(aem));
|
||||
}
|
||||
if (size > 8)
|
||||
print_vu_event_data((size-8), (__u8 *)&data[8]);
|
||||
|
@ -168,7 +188,7 @@ void print_telemetry_fifo_event(__u8 class_type,
|
|||
|
||||
case TELEMETRY_MEDIA_WEAR_CLASS:
|
||||
printf(" Event ID : 0x%04x %s\n",
|
||||
id, telemetry_media_debug_event_id_to_string(id));
|
||||
id, telemetry_media_wear_event_id_to_string(id));
|
||||
__u32 host_tb_written = *(__u32 *)&data[0];
|
||||
__u32 media_tb_written = *(__u32 *)&data[4];
|
||||
__u32 media_tb_erased = *(__u32 *)&data[8];
|
||||
|
@ -190,6 +210,16 @@ void print_telemetry_fifo_event(__u8 class_type,
|
|||
print_stats_desc((struct telemetry_stats_desc *)data);
|
||||
break;
|
||||
|
||||
case TELEMETRY_VIRTUAL_FIFO_EVENT_CLASS:
|
||||
printf(" Event ID : 0x%04x %s\n",
|
||||
id, telemetry_virtual_fifo_event_id_to_string(id));
|
||||
|
||||
__u16 vu_event_id = *(__u16 *)data;
|
||||
|
||||
printf(" VU Virtual FIFO Event ID : 0x%02x\n", le16_to_cpu(vu_event_id));
|
||||
printf("\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
/*
|
||||
* printf("Unknown Event Class Type\n");
|
||||
|
@ -489,9 +519,9 @@ int get_telemetry_das_offset_and_size(
|
|||
return 0;
|
||||
}
|
||||
|
||||
int get_static_id_ascii_string(int identifier, char *description)
|
||||
int get_statistic_id_ascii_string(int identifier, char *description)
|
||||
{
|
||||
if (pstring_buffer == NULL)
|
||||
if (!pstring_buffer || !description)
|
||||
return -1;
|
||||
|
||||
struct nvme_ocp_telemetry_string_header *pocp_ts_header =
|
||||
|
@ -522,16 +552,17 @@ int get_static_id_ascii_string(int identifier, char *description)
|
|||
memcpy(description, pdescription,
|
||||
peach_statistic_entry->ascii_id_length + 1);
|
||||
|
||||
// If ASCII string isn't found, see in our internal Map
|
||||
// for 2.5 Spec defined strings (id < 0x1D).
|
||||
if ((description == NULL) && (identifier < 0x1D))
|
||||
memcpy(description,
|
||||
statistic_identifiers_map[identifier].description,
|
||||
peach_statistic_entry->ascii_id_length + 1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// If ASCII string isn't found, see in our internal Map
|
||||
// for 2.5 Spec defined strings
|
||||
if (identifier <= 0x1D) {
|
||||
strcpy(description, statistic_identifiers_map[identifier].description);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -629,10 +660,10 @@ int parse_ocp_telemetry_string_log(int event_fifo_num, int identifier, int debug
|
|||
}
|
||||
|
||||
if (string_table == STATISTICS_IDENTIFIER_STRING)
|
||||
get_static_id_ascii_string(identifier, description);
|
||||
else if (string_table == EVENT_STRING)
|
||||
get_statistic_id_ascii_string(identifier, description);
|
||||
else if (string_table == EVENT_STRING && debug_event_class < 0x80)
|
||||
get_event_id_ascii_string(identifier, debug_event_class, description);
|
||||
else if (string_table == VU_EVENT_STRING)
|
||||
else if (string_table == VU_EVENT_STRING || debug_event_class >= 0x80)
|
||||
get_vu_event_id_ascii_string(identifier, debug_event_class, description);
|
||||
|
||||
return 0;
|
||||
|
@ -1204,10 +1235,15 @@ int parse_statistic(struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_e
|
|||
struct json_object *pstats_array, FILE *fp)
|
||||
{
|
||||
if (pstatistic_entry == NULL) {
|
||||
nvme_show_error("Input buffer was NULL");
|
||||
nvme_show_error("Statistics Input buffer was NULL");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pstatistic_entry->statistic_id == STATISTICS_RESERVED_ID)
|
||||
/* End of statistics entries, return -1 to stop processing the buffer */
|
||||
return -1;
|
||||
|
||||
|
||||
unsigned int data_size = pstatistic_entry->statistic_data_size * SIZE_OF_DWORD;
|
||||
__u8 *pdata = (__u8 *)pstatistic_entry +
|
||||
sizeof(struct nvme_ocp_telemetry_statistic_descriptor);
|
||||
|
@ -1236,8 +1272,33 @@ int parse_statistic(struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_e
|
|||
pstatistic_entry->statistic_data_size);
|
||||
json_add_formatted_u32_str(pstatistics_object, STR_RESERVED,
|
||||
pstatistic_entry->reserved);
|
||||
json_add_formatted_var_size_str(pstatistics_object, STR_STATISTICS_SPECIFIC_DATA,
|
||||
pdata, data_size);
|
||||
if (pstatistic_entry->statistic_id == MAX_DIE_BAD_BLOCK_ID) {
|
||||
json_add_formatted_u32_str(pstatistics_object,
|
||||
STR_STATISTICS_WORST_DIE_PERCENT,
|
||||
pdata[0]);
|
||||
json_add_formatted_u32_str(pstatistics_object,
|
||||
STR_STATISTICS_WORST_DIE_RAW,
|
||||
*(__u16 *)&pdata[2]);
|
||||
} else if (pstatistic_entry->statistic_id == MAX_NAND_CHANNEL_BAD_BLOCK_ID) {
|
||||
json_add_formatted_u32_str(pstatistics_object,
|
||||
STR_STATISTICS_WORST_NAND_CHANNEL_PERCENT,
|
||||
pdata[0]);
|
||||
json_add_formatted_u32_str(pstatistics_object,
|
||||
STR_STATISTICS_WORST_NAND_CHANNEL_RAW,
|
||||
*(__u16 *)&pdata[2]);
|
||||
} else if (pstatistic_entry->statistic_id == MIN_NAND_CHANNEL_BAD_BLOCK_ID) {
|
||||
json_add_formatted_u32_str(pstatistics_object,
|
||||
STR_STATISTICS_BEST_NAND_CHANNEL_PERCENT,
|
||||
pdata[0]);
|
||||
json_add_formatted_u32_str(pstatistics_object,
|
||||
STR_STATISTICS_BEST_NAND_CHANNEL_RAW,
|
||||
*(__u16 *)&pdata[2]);
|
||||
} else {
|
||||
json_add_formatted_var_size_str(pstatistics_object,
|
||||
STR_STATISTICS_SPECIFIC_DATA,
|
||||
pdata,
|
||||
data_size);
|
||||
}
|
||||
|
||||
if (pstatistics_object != NULL)
|
||||
json_array_add_value_object(pstats_array, pstatistics_object);
|
||||
|
@ -1257,8 +1318,33 @@ int parse_statistic(struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_e
|
|||
fprintf(fp, "%s: 0x%x\n", STR_STATISTICS_DATA_SIZE,
|
||||
pstatistic_entry->statistic_data_size);
|
||||
fprintf(fp, "%s: 0x%x\n", STR_RESERVED, pstatistic_entry->reserved);
|
||||
print_formatted_var_size_str(STR_STATISTICS_SPECIFIC_DATA, pdata,
|
||||
data_size, fp);
|
||||
if (pstatistic_entry->statistic_id == MAX_DIE_BAD_BLOCK_ID) {
|
||||
fprintf(fp, "%s: 0x%02x\n", STR_STATISTICS_WORST_DIE_PERCENT,
|
||||
pdata[0]);
|
||||
fprintf(fp, "%s: 0x%04x\n", STR_STATISTICS_WORST_DIE_RAW,
|
||||
*(__u16 *)&pdata[2]);
|
||||
} else if (pstatistic_entry->statistic_id ==
|
||||
MAX_NAND_CHANNEL_BAD_BLOCK_ID) {
|
||||
fprintf(fp, "%s: 0x%02x\n",
|
||||
STR_STATISTICS_WORST_NAND_CHANNEL_PERCENT,
|
||||
pdata[0]);
|
||||
fprintf(fp, "%s: 0x%04x\n",
|
||||
STR_STATISTICS_WORST_NAND_CHANNEL_RAW,
|
||||
*(__u16 *)&pdata[2]);
|
||||
} else if (pstatistic_entry->statistic_id ==
|
||||
MIN_NAND_CHANNEL_BAD_BLOCK_ID) {
|
||||
fprintf(fp, "%s: 0x%02x\n",
|
||||
STR_STATISTICS_BEST_NAND_CHANNEL_PERCENT,
|
||||
pdata[0]);
|
||||
fprintf(fp, "%s: 0x%04x\n",
|
||||
STR_STATISTICS_BEST_NAND_CHANNEL_RAW,
|
||||
*(__u16 *)&pdata[2]);
|
||||
} else {
|
||||
print_formatted_var_size_str(STR_STATISTICS_SPECIFIC_DATA,
|
||||
pdata,
|
||||
data_size,
|
||||
fp);
|
||||
}
|
||||
fprintf(fp, STR_LINE2);
|
||||
} else {
|
||||
printf("%s: 0x%x\n", STR_STATISTICS_IDENTIFIER,
|
||||
|
@ -1275,8 +1361,33 @@ int parse_statistic(struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_e
|
|||
printf("%s: 0x%x\n", STR_STATISTICS_DATA_SIZE,
|
||||
pstatistic_entry->statistic_data_size);
|
||||
printf("%s: 0x%x\n", STR_RESERVED, pstatistic_entry->reserved);
|
||||
print_formatted_var_size_str(STR_STATISTICS_SPECIFIC_DATA, pdata,
|
||||
data_size, fp);
|
||||
if (pstatistic_entry->statistic_id == MAX_DIE_BAD_BLOCK_ID) {
|
||||
printf("%s: 0x%02x\n", STR_STATISTICS_WORST_DIE_PERCENT,
|
||||
pdata[0]);
|
||||
printf("%s: 0x%04x\n", STR_STATISTICS_WORST_DIE_RAW,
|
||||
*(__u16 *)&pdata[2]);
|
||||
} else if (pstatistic_entry->statistic_id ==
|
||||
MAX_NAND_CHANNEL_BAD_BLOCK_ID) {
|
||||
printf("%s: 0x%02x\n",
|
||||
STR_STATISTICS_WORST_NAND_CHANNEL_PERCENT,
|
||||
pdata[0]);
|
||||
printf("%s: 0x%04x\n",
|
||||
STR_STATISTICS_WORST_NAND_CHANNEL_RAW,
|
||||
*(__u16 *)&pdata[2]);
|
||||
} else if (pstatistic_entry->statistic_id ==
|
||||
MIN_NAND_CHANNEL_BAD_BLOCK_ID) {
|
||||
printf("%s: 0x%02x\n",
|
||||
STR_STATISTICS_BEST_NAND_CHANNEL_PERCENT,
|
||||
pdata[0]);
|
||||
printf("%s: 0x%04x\n",
|
||||
STR_STATISTICS_BEST_NAND_CHANNEL_RAW,
|
||||
*(__u16 *)&pdata[2]);
|
||||
} else {
|
||||
print_formatted_var_size_str(STR_STATISTICS_SPECIFIC_DATA,
|
||||
pdata,
|
||||
data_size,
|
||||
fp);
|
||||
}
|
||||
printf(STR_LINE2);
|
||||
}
|
||||
}
|
||||
|
@ -1297,6 +1408,7 @@ int parse_statistics(struct json_object *root, struct nvme_ocp_telemetry_offsets
|
|||
__u32 stats_da_1_start_dw = 0, stats_da_1_size_dw = 0;
|
||||
__u32 stats_da_2_start_dw = 0, stats_da_2_size_dw = 0;
|
||||
__u8 *pstats_offset = NULL;
|
||||
int parse_rc = 0;
|
||||
|
||||
if (poffsets->data_area == 1) {
|
||||
__u32 stats_da_1_start = *(__u32 *)(pda1_ocp_header_offset +
|
||||
|
@ -1336,7 +1448,11 @@ int parse_statistics(struct json_object *root, struct nvme_ocp_telemetry_offsets
|
|||
(struct nvme_ocp_telemetry_statistic_descriptor *)
|
||||
(pstats_offset + offset_to_move);
|
||||
|
||||
parse_statistic(pstatistic_entry, pstats_array, fp);
|
||||
parse_rc = parse_statistic(pstatistic_entry, pstats_array, fp);
|
||||
if (parse_rc < 0)
|
||||
/* end of stats entries or null pointer, so break */
|
||||
break;
|
||||
|
||||
offset_to_move += (pstatistic_entry->statistic_data_size * SIZE_OF_DWORD +
|
||||
stat_des_size);
|
||||
}
|
||||
|
|
|
@ -48,6 +48,83 @@ enum TELEMETRY_STATISTIC_ID {
|
|||
TELEMETRY_STAT_ID_MAXDBB = 0x1B, /* Max Die Bad Block */
|
||||
TELEMETRY_STAT_ID_MAXCBB = 0x1C, /* Max NAND Channel Bad Block */
|
||||
TELEMETRY_STAT_ID_MINCBB = 0x1D, /* Min NAND Channel Bad Block */
|
||||
TELEMETRY_STAT_ID_PMUW = 0x1E, /* Physical Media Units Written */
|
||||
TELEMETRY_STAT_ID_PMUR = 0x1F, /* Physical Media Units Read */
|
||||
TELEMETRY_STAT_ID_BUNB = 0x20, /* Bad User NAND Blocks */
|
||||
TELEMETRY_STAT_ID_BSNB = 0x21, /* Bad System NAND Blocks */
|
||||
TELEMETRY_STAT_ID_XORRC = 0x22, /* XOR Recovery Count */
|
||||
TELEMETRY_STAT_ID_UNREC = 0x23, /* Uncorrectable Read Error Count */
|
||||
TELEMETRY_STAT_ID_SECCEC = 0x24, /* Soft ECC Error Count */
|
||||
TELEMETRY_STAT_ID_ETOECC = 0x25, /* End To End Correction Counts */
|
||||
TELEMETRY_STAT_ID_SDU = 0x26, /* System Data % Used */
|
||||
TELEMETRY_STAT_ID_RC = 0x27, /* Refresh Count */
|
||||
TELEMETRY_STAT_ID_UDEC = 0x28, /* User Data Erase Counts */
|
||||
TELEMETRY_STAT_ID_TTSC = 0x29, /* Thremal Throttling Status and Count */
|
||||
TELEMETRY_STAT_ID_DSSDSV = 0x2A, /* DSSD Specification Version */
|
||||
TELEMETRY_STAT_ID_PCIECEC = 0x2B, /* PCIe Correctable Error Count */
|
||||
TELEMETRY_STAT_ID_IS = 0x2C, /* Incomplete Shutdown */
|
||||
TELEMETRY_STAT_ID_FB = 0x2D, /* % Free Block */
|
||||
TELEMETRY_STAT_ID_CH = 0x2E, /* Capacitor Health */
|
||||
TELEMETRY_STAT_ID_NVMEBEV = 0x2F, /* NVM Express Base Errata Version */
|
||||
TELEMETRY_STAT_ID_NVMCSEV = 0x30, /* NVM Command Set Errata Version */
|
||||
TELEMETRY_STAT_ID_NVMEMIEV = 0x31, /* NVM Exp Mgmt Interface Err Version */
|
||||
TELEMETRY_STAT_ID_UIO = 0x32, /* Unaligned IO */
|
||||
TELEMETRY_STAT_ID_SVN = 0x33, /* Security Version Number */
|
||||
TELEMETRY_STAT_ID_TNUSE = 0x34, /* Total NUSE */
|
||||
TELEMETRY_STAT_ID_PLPSC = 0x35, /* PLP Start Count */
|
||||
TELEMETRY_STAT_ID_EE = 0x36, /* Endurance Estimate */
|
||||
TELEMETRY_STAT_ID_PCIELRC = 0x37, /* PCIe Link Retraining Count */
|
||||
TELEMETRY_STAT_ID_PSCC = 0x38, /* Power State Change Count */
|
||||
TELEMETRY_STAT_ID_LPFR = 0x39, /* Lowest Permitted Firmware Revision */
|
||||
TELEMETRY_STAT_ID_LPV = 0x3A, /* Log Page Version */
|
||||
TELEMETRY_STAT_ID_MDO = 0x3B, /* Media Dies Offline */
|
||||
TELEMETRY_STAT_ID_MTR = 0x3C, /* Max Temperature Recorded */
|
||||
TELEMETRY_STAT_ID_NAEC = 0x3D, /* Nand Avg Erase Count */
|
||||
TELEMETRY_STAT_ID_CT = 0x3E, /* Command Timeout */
|
||||
TELEMETRY_STAT_ID_SAPFC = 0x3F, /* System Area Program Fail Count */
|
||||
TELEMETRY_STAT_ID_SARFC = 0x40, /* System Area Read Fail Count */
|
||||
TELEMETRY_STAT_ID_SAEFC = 0x41, /* System Area Erase Fail Count */
|
||||
TELEMETRY_STAT_ID_MPPC = 0x42, /* Max Peak Power Capability */
|
||||
TELEMETRY_STAT_ID_CMAP = 0x43, /* Current Max Average Power */
|
||||
TELEMETRY_STAT_ID_LPC = 0x44, /* Lifetime Power Consumed */
|
||||
TELEMETRY_STAT_ID_PAC = 0x45, /* Panic Asset Count */
|
||||
TELEMETRY_STAT_ID_DBT = 0x46, /* Device Busy Time */
|
||||
TELEMETRY_STAT_ID_CW = 0x47, /* Critical Warning */
|
||||
TELEMETRY_STAT_ID_COMTEMP = 0x48, /* Composite Temperature */
|
||||
TELEMETRY_STAT_ID_AS = 0x49, /* Available Spare */
|
||||
TELEMETRY_STAT_ID_AST = 0x4A, /* Available Spare Threshold */
|
||||
TELEMETRY_STAT_ID_PU = 0x4B, /* Percentage Used */
|
||||
TELEMETRY_STAT_ID_EGCWS = 0x4C, /* Endurance Gp CW Summary */
|
||||
TELEMETRY_STAT_ID_DUR = 0x4D, /* Data Units Read */
|
||||
TELEMETRY_STAT_ID_DUW = 0x4E, /* Data Units Written */
|
||||
TELEMETRY_STAT_ID_HRC = 0x4F, /* Host Read Commands */
|
||||
TELEMETRY_STAT_ID_HWC = 0x50, /* Host Write Commands */
|
||||
TELEMETRY_STAT_ID_CBT = 0x51, /* Controller Busy Time */
|
||||
TELEMETRY_STAT_ID_PC = 0x52, /* Power Cycles */
|
||||
TELEMETRY_STAT_ID_POH = 0x53, /* Power On Hours */
|
||||
TELEMETRY_STAT_ID_US = 0x54, /* Unsafe Shutdowns */
|
||||
TELEMETRY_STAT_ID_MDIE = 0x55, /* Media and Data Integrity Er */
|
||||
TELEMETRY_STAT_ID_NEILE = 0x56, /* No of Error Info Entries */
|
||||
TELEMETRY_STAT_ID_WCTT = 0x57, /* Warning Composite Temp Time */
|
||||
TELEMETRY_STAT_ID_CCTT = 0x58, /* Critical Comp Temp Time */
|
||||
TELEMETRY_STAT_ID_TS1 = 0x59, /* Temperature Sensor 1 */
|
||||
TELEMETRY_STAT_ID_TS2 = 0x5A, /* Temperature Sensor 2 */
|
||||
TELEMETRY_STAT_ID_TS3 = 0x5B, /* Temperature Sensor 3 */
|
||||
TELEMETRY_STAT_ID_TS4 = 0x5C, /* Temperature Sensor 4 */
|
||||
TELEMETRY_STAT_ID_TS5 = 0x5D, /* Temperature Sensor 5 */
|
||||
TELEMETRY_STAT_ID_TS6 = 0x5E, /* Temperature Sensor 6 */
|
||||
TELEMETRY_STAT_ID_TS7 = 0x5F, /* Temperature Sensor 7 */
|
||||
TELEMETRY_STAT_ID_TS8 = 0x60, /* Temperature Sensor 8 */
|
||||
TELEMETRY_STAT_ID_TMT1TC = 0x61, /* Thermal Mgmt Temp1 TC */
|
||||
TELEMETRY_STAT_ID_TMT2TC = 0x62, /* Thermal Mgmt Temp2 TC */
|
||||
TELEMETRY_STAT_ID_TTTMT1 = 0x63, /* Total Time TMT1 */
|
||||
TELEMETRY_STAT_ID_TTTMT2 = 0x64, /* Total Time TMT2 */
|
||||
TELEMETRY_STAT_ID_EEE = 0x65, /* Endurance Estimate */
|
||||
TELEMETRY_STAT_ID_EDUR = 0x66, /* Endurance Data Units Read */
|
||||
TELEMETRY_STAT_ID_EDUW = 0x67, /* Endurance Data Units Written */
|
||||
TELEMETRY_STAT_ID_EMUW = 0x68, /* Endurance Media Units Written */
|
||||
TELEMETRY_STAT_ID_ENEILE = 0x69, /* Endurance No Of Err Info Log Entries */
|
||||
|
||||
};
|
||||
|
||||
static const char * const telemetry_stat_id_str[] = {
|
||||
|
@ -80,50 +157,128 @@ static const char * const telemetry_stat_id_str[] = {
|
|||
[TELEMETRY_STAT_ID_MAXDBB] = "Max Die Bad Block",
|
||||
[TELEMETRY_STAT_ID_MAXCBB] = "Max NAND Channel Bad Block",
|
||||
[TELEMETRY_STAT_ID_MINCBB] = "Min NAND Channel Bad Block",
|
||||
[TELEMETRY_STAT_ID_PMUW] = "Physical Media Units Written",
|
||||
[TELEMETRY_STAT_ID_PMUR] = "Physical Media Units Read",
|
||||
[TELEMETRY_STAT_ID_BUNB] = "Bad User NAND Blocks",
|
||||
[TELEMETRY_STAT_ID_BSNB] = "Bad System NAND Blocks",
|
||||
[TELEMETRY_STAT_ID_XORRC] = "XOR Recovery Count",
|
||||
[TELEMETRY_STAT_ID_UNREC] = "Uncorrectable Read Error Count",
|
||||
[TELEMETRY_STAT_ID_SECCEC] = "Soft ECC Error Count",
|
||||
[TELEMETRY_STAT_ID_ETOECC] = "End To End Correction Counts",
|
||||
[TELEMETRY_STAT_ID_SDU] = "System Data Used",
|
||||
[TELEMETRY_STAT_ID_RC] = "Refresh Count",
|
||||
[TELEMETRY_STAT_ID_UDEC] = "User Data Erase Counts",
|
||||
[TELEMETRY_STAT_ID_TTSC] = "Thremal Throttling Status and Count",
|
||||
[TELEMETRY_STAT_ID_DSSDSV] = "DSSD Specification Version",
|
||||
[TELEMETRY_STAT_ID_PCIECEC] = "PCIe Correctable Error Count",
|
||||
[TELEMETRY_STAT_ID_IS] = "Incomplete Shutdown",
|
||||
[TELEMETRY_STAT_ID_FB] = "Free Block",
|
||||
[TELEMETRY_STAT_ID_CH] = "Capacitor Health",
|
||||
[TELEMETRY_STAT_ID_NVMEBEV] = "NVM Express Base Errata Version",
|
||||
[TELEMETRY_STAT_ID_NVMCSEV] = "NVM Command Set Errata Version",
|
||||
[TELEMETRY_STAT_ID_NVMEMIEV] = "NVM Express Management Interface Errata Version",
|
||||
[TELEMETRY_STAT_ID_UIO] = "Unaligned IO",
|
||||
[TELEMETRY_STAT_ID_SVN] = "Security Version Number",
|
||||
[TELEMETRY_STAT_ID_TNUSE] = "Total NUSE",
|
||||
[TELEMETRY_STAT_ID_PLPSC] = "PLP Start Count",
|
||||
[TELEMETRY_STAT_ID_EE] = "Endurance Estimate",
|
||||
[TELEMETRY_STAT_ID_PCIELRC] = "PCIe Link Retraining Count",
|
||||
[TELEMETRY_STAT_ID_PSCC] = "Power State Change Count",
|
||||
[TELEMETRY_STAT_ID_LPFR] = "Lowest Permitted Firmware Revision",
|
||||
[TELEMETRY_STAT_ID_LPV] = "Log Page Version",
|
||||
[TELEMETRY_STAT_ID_MDO] = "Media Dies Offline",
|
||||
[TELEMETRY_STAT_ID_MTR] = "Max Temperature Recorded",
|
||||
[TELEMETRY_STAT_ID_NAEC] = "Nand Avg Erase Count",
|
||||
[TELEMETRY_STAT_ID_CT] = "Command Timeout",
|
||||
[TELEMETRY_STAT_ID_SAPFC] = "System Area Program Fail Count",
|
||||
[TELEMETRY_STAT_ID_SARFC] = "System Area Read Fail Count",
|
||||
[TELEMETRY_STAT_ID_SAEFC] = "System Area Erase Fail Count",
|
||||
[TELEMETRY_STAT_ID_MPPC] = "Max Peak Power Capability",
|
||||
[TELEMETRY_STAT_ID_CMAP] = "Current Max Average Power",
|
||||
[TELEMETRY_STAT_ID_LPC] = "Lifetime Power Consumed",
|
||||
[TELEMETRY_STAT_ID_PAC] = "Panic Asset Count",
|
||||
[TELEMETRY_STAT_ID_DBT] = "Device Busy Time",
|
||||
[TELEMETRY_STAT_ID_CW] = "Critical Warning",
|
||||
[TELEMETRY_STAT_ID_COMTEMP] = "Composite Temperature",
|
||||
[TELEMETRY_STAT_ID_AS] = "Available Spare",
|
||||
[TELEMETRY_STAT_ID_AST] = "Available Spare Threshold",
|
||||
[TELEMETRY_STAT_ID_PU] = "Percentage Used",
|
||||
[TELEMETRY_STAT_ID_EGCWS] = "Endurance Gp CW Summary",
|
||||
[TELEMETRY_STAT_ID_DUR] = "Data Units Read",
|
||||
[TELEMETRY_STAT_ID_DUW] = "Data Units Written",
|
||||
[TELEMETRY_STAT_ID_HRC] = "Host Read Commands",
|
||||
[TELEMETRY_STAT_ID_HWC] = "Host Write Commands",
|
||||
[TELEMETRY_STAT_ID_CBT] = "Controller Busy Time",
|
||||
[TELEMETRY_STAT_ID_PC] = "Power Cycles",
|
||||
[TELEMETRY_STAT_ID_POH] = "Power On Hours",
|
||||
[TELEMETRY_STAT_ID_US] = "Unsafe Shutdowns",
|
||||
[TELEMETRY_STAT_ID_MDIE] = "Media and Data Integrity Er",
|
||||
[TELEMETRY_STAT_ID_NEILE] = "No of Error Info Entries",
|
||||
[TELEMETRY_STAT_ID_WCTT] = "Warning Composite Temp Time",
|
||||
[TELEMETRY_STAT_ID_CCTT] = "Critical Comp Temp Time",
|
||||
[TELEMETRY_STAT_ID_TS1] = "Temperature Sensor 1",
|
||||
[TELEMETRY_STAT_ID_TS2] = "Temperature Sensor 2",
|
||||
[TELEMETRY_STAT_ID_TS3] = "Temperature Sensor 3",
|
||||
[TELEMETRY_STAT_ID_TS4] = "Temperature Sensor 4",
|
||||
[TELEMETRY_STAT_ID_TS5] = "Temperature Sensor 5",
|
||||
[TELEMETRY_STAT_ID_TS6] = "Temperature Sensor 6",
|
||||
[TELEMETRY_STAT_ID_TS7] = "Temperature Sensor 7",
|
||||
[TELEMETRY_STAT_ID_TS8] = "Temperature Sensor 8",
|
||||
[TELEMETRY_STAT_ID_TMT1TC] = "Thermal Mgmt Temp1 TC",
|
||||
[TELEMETRY_STAT_ID_TMT2TC] = "Thermal Mgmt Temp2 TC",
|
||||
[TELEMETRY_STAT_ID_TTTMT1] = "Total Time TMT1",
|
||||
[TELEMETRY_STAT_ID_TTTMT2] = "Total Time TMT2",
|
||||
[TELEMETRY_STAT_ID_EEE] = "Endurance Estimate",
|
||||
[TELEMETRY_STAT_ID_EDUR] = "Endurance Data Units Read",
|
||||
[TELEMETRY_STAT_ID_EDUW] = "Endurance Data Units Written",
|
||||
[TELEMETRY_STAT_ID_EMUW] = "Endurance Media Units Written",
|
||||
[TELEMETRY_STAT_ID_ENEILE] = "Endurance No Of Err Info Log Entries",
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* Telemetry FIFO Event Class ID's and Strings
|
||||
*****************************************************************************/
|
||||
enum TELEMETRY_EVENT_CLASS_TYPE {
|
||||
TELEMETRY_TIMESTAMP_CLASS = 0x1,
|
||||
TELEMETRY_PCIE_CLASS = 0x2,
|
||||
TELEMETRY_NVME_CLASS = 0x3,
|
||||
TELEMETRY_RESET_CLASS = 0x4,
|
||||
TELEMETRY_BOOT_SEQ_CLASS = 0x5,
|
||||
TELEMETRY_FW_ASSERT_CLASS = 0x6,
|
||||
TELEMETRY_TEMPERATURE_CLASS = 0x7,
|
||||
TELEMETRY_MEDIA_DBG_CLASS = 0x8,
|
||||
TELEMETRY_MEDIA_WEAR_CLASS = 0x9,
|
||||
TELEMETRY_STAT_SNAPSHOT_CLASS = 0xA,
|
||||
TELEMETRY_TIMESTAMP_CLASS = 0x1,
|
||||
TELEMETRY_PCIE_CLASS = 0x2,
|
||||
TELEMETRY_NVME_CLASS = 0x3,
|
||||
TELEMETRY_RESET_CLASS = 0x4,
|
||||
TELEMETRY_BOOT_SEQ_CLASS = 0x5,
|
||||
TELEMETRY_FW_ASSERT_CLASS = 0x6,
|
||||
TELEMETRY_TEMPERATURE_CLASS = 0x7,
|
||||
TELEMETRY_MEDIA_DBG_CLASS = 0x8,
|
||||
TELEMETRY_MEDIA_WEAR_CLASS = 0x9,
|
||||
TELEMETRY_STAT_SNAPSHOT_CLASS = 0xA,
|
||||
TELEMETRY_VIRTUAL_FIFO_EVENT_CLASS = 0xB,
|
||||
};
|
||||
|
||||
static const char * const telemetry_event_class_str[] = {
|
||||
[TELEMETRY_TIMESTAMP_CLASS] = "Timestamp Class",
|
||||
[TELEMETRY_PCIE_CLASS] = "PCIe Class",
|
||||
[TELEMETRY_NVME_CLASS] = "NVMe Class",
|
||||
[TELEMETRY_RESET_CLASS] = "Reset Class",
|
||||
[TELEMETRY_BOOT_SEQ_CLASS] = "Boot Sequence Class",
|
||||
[TELEMETRY_FW_ASSERT_CLASS] = "FW Assert Class",
|
||||
[TELEMETRY_TEMPERATURE_CLASS] = "Temperature Class",
|
||||
[TELEMETRY_MEDIA_DBG_CLASS] = "Media Debug Class",
|
||||
[TELEMETRY_MEDIA_WEAR_CLASS] = "Media Wear Class",
|
||||
[TELEMETRY_STAT_SNAPSHOT_CLASS] = "Statistic Snapshot Class",
|
||||
[TELEMETRY_TIMESTAMP_CLASS] = "Timestamp Class",
|
||||
[TELEMETRY_PCIE_CLASS] = "PCIe Class",
|
||||
[TELEMETRY_NVME_CLASS] = "NVMe Class",
|
||||
[TELEMETRY_RESET_CLASS] = "Reset Class",
|
||||
[TELEMETRY_BOOT_SEQ_CLASS] = "Boot Sequence Class",
|
||||
[TELEMETRY_FW_ASSERT_CLASS] = "FW Assert Class",
|
||||
[TELEMETRY_TEMPERATURE_CLASS] = "Temperature Class",
|
||||
[TELEMETRY_MEDIA_DBG_CLASS] = "Media Debug Class",
|
||||
[TELEMETRY_MEDIA_WEAR_CLASS] = "Media Wear Class",
|
||||
[TELEMETRY_STAT_SNAPSHOT_CLASS] = "Statistic Snapshot Class",
|
||||
[TELEMETRY_VIRTUAL_FIFO_EVENT_CLASS] = "Virtual FIFO Event Class",
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* Telemetry Timestamp Class (01h) Event ID's and Strings
|
||||
*****************************************************************************/
|
||||
enum TELEMETRY_TIMESTAMP_EVENT_ID {
|
||||
TIMESTAMP_HOST_CMD_ISSUED = 0x0000,
|
||||
TIMESTAMP_SNAPSHOT = 0x0001,
|
||||
TIMESTAMP_POWER_ON_HOURS = 0x0002,
|
||||
TIMESTAMP_FEATURE_HOST_ISSUED = 0x0000,
|
||||
TIMESTAMP_FW_INTIATED_SNAPSHOT = 0x0001,
|
||||
TIMESTAMP_OBSOLETE = 0x0002,
|
||||
};
|
||||
|
||||
static const char * const telemetry_timestamp_event_id_str[] = {
|
||||
[TIMESTAMP_HOST_CMD_ISSUED] = "Timestamp Host Cmd Issued",
|
||||
[TIMESTAMP_SNAPSHOT] = "Timestamp Snapshot",
|
||||
[TIMESTAMP_POWER_ON_HOURS] = "Timestamp Power on Hours",
|
||||
[TIMESTAMP_FEATURE_HOST_ISSUED] = "Host Issued Timestamp Set Feature Cmd",
|
||||
[TIMESTAMP_FW_INTIATED_SNAPSHOT] = "Fw Initiated Timestamp Snapshot",
|
||||
[TIMESTAMP_OBSOLETE] = "TimeStamp Obsolete",
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
|
@ -217,6 +372,8 @@ enum TELEMETRY_NVME_EVENT_ID {
|
|||
CC_REGISTER_CHANGED = 0x000B,
|
||||
CSTS_REGISTER_CHANGED = 0x000C,
|
||||
DELETE_IO_QUEUE_PROCESSED = 0x000D,
|
||||
OOB_COMMAND = 0x000E,
|
||||
OOB_AER_EVENT_MSG_TRANS = 0x000F
|
||||
};
|
||||
|
||||
static const char * const telemetry_nvme_event_id_str[] = {
|
||||
|
@ -226,14 +383,16 @@ static const char * const telemetry_nvme_event_id_str[] = {
|
|||
[CSTS_RDY_1_TO_0] = "CSTS.RDY Transitions from 1 to 0",
|
||||
[NVME_EVENT_ID_RESERVED] = "Reserved NVMe Event ID",
|
||||
[CREATE_IO_QUEUE_PROCESSED] = "Create IO SQ or CQ Command Processed",
|
||||
[ADMIN_QUEUE_CMD_PROCESSED] = "Other Admin Queue Command Processed",
|
||||
[ADMIN_QUEUE_CMD_PROCESSED] = "Inb-Admin Que Cmd Proc other than Cr IO SQ/CQ",
|
||||
[ADMIN_QUEUE_NONZERO_STATUS] = "Admin Command Returned Non-zero Status",
|
||||
[IO_QUEUE_NONZERO_STATUS] = "IO Command Returned Non-zero Status",
|
||||
[CSTS_CFS_0_TO_1] = "CSTS.CFS Transitions from 0 to 1",
|
||||
[ADMIN_QUEUE_BASE_WRITTEN] = "Admin SQ or CQ Base Address Written",
|
||||
[CC_REGISTER_CHANGED] = "CC Register Changed",
|
||||
[CSTS_REGISTER_CHANGED] = "CTS Register Changed",
|
||||
[CSTS_REGISTER_CHANGED] = "CSTS Register Changed",
|
||||
[DELETE_IO_QUEUE_PROCESSED] = "Delete IO SQ or CQ Command Processed",
|
||||
[OOB_COMMAND] = "Out of Band Command Process",
|
||||
[OOB_AER_EVENT_MSG_TRANS] = "Out of Band AER Event Msg Transition"
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
|
@ -292,7 +451,7 @@ static const char * const telemetry_fw_assert_event_id_str[] = {
|
|||
[ASSERT_BACKGROUND_CODE] = "Assert in Background Services Code",
|
||||
[FTL_REBUILD_FAILED] = "FTL Rebuild Failed",
|
||||
[FTL_DATA_MISMATCH] = "FTL Data Mismatch",
|
||||
[ASSERT_OTHER_CODE] = "FTL Other Code",
|
||||
[ASSERT_OTHER_CODE] = "Assert in Other Code",
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
|
@ -342,6 +501,19 @@ static const char * const telemetry_media_wear_event_id_str[] = {
|
|||
[MEDIA_WEAR] = "Media Wear",
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* Telemetry Virtual FIFO (0Bh) Event ID's and Strings
|
||||
*****************************************************************************/
|
||||
enum TELEMETRY_VIRTUAL_FIFO_EVENT_ID {
|
||||
VIRTUAL_FIFO_START = 0x0000,
|
||||
VIRTUAL_FIFO_END = 0x0002,
|
||||
};
|
||||
|
||||
static const char * const telemetry_virtual_fifo_event_id_str[] = {
|
||||
[VIRTUAL_FIFO_START] = "Virtual FIFO Start",
|
||||
[VIRTUAL_FIFO_END] = "Virtual FIFO End",
|
||||
};
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Telemetry Data Structures
|
||||
|
@ -353,7 +525,6 @@ static const char * const telemetry_media_wear_event_id_str[] = {
|
|||
#define FILE_NAME_SIZE 2048
|
||||
|
||||
enum TELEMETRY_TYPE {
|
||||
TELEMETRY_TYPE_NONE = 0,
|
||||
TELEMETRY_TYPE_HOST = 7,
|
||||
TELEMETRY_TYPE_CONTROLLER = 8,
|
||||
TELEMETRY_TYPE_HOST_0 = 9,
|
||||
|
@ -381,7 +552,7 @@ struct telemetry_stats_desc {
|
|||
__u8 info;
|
||||
__u8 ns_info;
|
||||
__le16 size;
|
||||
__le16 rsvd1;
|
||||
__le16 nsid;
|
||||
__u8 data[];
|
||||
};
|
||||
|
||||
|
@ -438,7 +609,6 @@ struct telemetry_data_area_1 {
|
|||
#define DEFAULT_OUTPUT_FORMAT_JSON "json"
|
||||
|
||||
/* C9 Telemetry String Log Format Log Page */
|
||||
#define C9_TELEMETRY_STRING_LOG_ENABLE_OPCODE 0xC9
|
||||
#define C9_TELEMETRY_STR_LOG_LEN 432
|
||||
#define C9_TELEMETRY_STR_LOG_SIST_OFST 431
|
||||
|
||||
|
@ -460,6 +630,12 @@ struct telemetry_data_area_1 {
|
|||
#define STR_STATISTICS_DATA_SIZE "Statistic Data Size"
|
||||
#define STR_RESERVED "Reserved"
|
||||
#define STR_STATISTICS_SPECIFIC_DATA "Statistic Specific Data"
|
||||
#define STR_STATISTICS_WORST_DIE_PERCENT "Worst die % of bad blocks"
|
||||
#define STR_STATISTICS_WORST_DIE_RAW "Worst die raw number of bad blocks"
|
||||
#define STR_STATISTICS_WORST_NAND_CHANNEL_PERCENT "Worst NAND channel % of bad blocks"
|
||||
#define STR_STATISTICS_WORST_NAND_CHANNEL_RAW "Worst NAND channel number of bad blocks"
|
||||
#define STR_STATISTICS_BEST_NAND_CHANNEL_PERCENT "Best NAND channel % of bad blocks"
|
||||
#define STR_STATISTICS_BEST_NAND_CHANNEL_RAW "Best NAND channel number of bad blocks"
|
||||
#define STR_CLASS_SPECIFIC_DATA "Class Specific Data"
|
||||
#define STR_DBG_EVENT_CLASS_TYPE "Debug Event Class type"
|
||||
#define STR_EVENT_IDENTIFIER "Event Identifier"
|
||||
|
@ -497,6 +673,47 @@ enum ocp_telemetry_string_tables {
|
|||
VU_EVENT_STRING
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ocp_telemetry_statistics_identifiers - OCP Statistics Identifiers
|
||||
*/
|
||||
enum ocp_telemetry_statistic_identifiers {
|
||||
STATISTICS_RESERVED_ID = 0x00,
|
||||
OUTSTANDING_ADMIN_CMDS_ID = 0x01,
|
||||
HOST_WRTIE_BANDWIDTH_ID = 0x02,
|
||||
GW_WRITE_BANDWITH_ID = 0x03,
|
||||
ACTIVE_NAMESPACES_ID = 0x04,
|
||||
INTERNAL_WRITE_WORKLOAD_ID = 0x05,
|
||||
INTERNAL_READ_WORKLOAD_ID = 0x06,
|
||||
INTERNAL_WRITE_QUEUE_DEPTH_ID = 0x07,
|
||||
INTERNAL_READ_QUEUE_DEPTH_ID = 0x08,
|
||||
PENDING_TRIM_LBA_COUNT_ID = 0x09,
|
||||
HOST_TRIM_LBA_REQUEST_COUNT_ID = 0x0A,
|
||||
CURRENT_NVME_POWER_STATE_ID = 0x0B,
|
||||
CURRENT_DSSD_POWER_STATE_ID = 0x0C,
|
||||
PROGRAM_FAIL_COUNT_ID = 0x0D,
|
||||
ERASE_FAIL_COUNT_ID = 0x0E,
|
||||
READ_DISTURB_WRITES_ID = 0x0F,
|
||||
|
||||
RETENTION_WRITES_ID = 0x10,
|
||||
WEAR_LEVELING_WRITES_ID = 0x11,
|
||||
READ_RECOVERY_WRITES_ID = 0x12,
|
||||
GC_WRITES_ID = 0x13,
|
||||
SRAM_CORRECTABLE_COUNT_ID = 0x14,
|
||||
DRAM_CORRECTABLE_COUNT_ID = 0x15,
|
||||
SRAM_UNCORRECTABLE_COUNT_ID = 0x16,
|
||||
DRAM_UNCORRECTABLE_COUNT_ID = 0x17,
|
||||
DATA_INTEGRITY_ERROR_COUNT_ID = 0x18,
|
||||
READ_RETRY_ERROR_COUNT_ID = 0x19,
|
||||
PERST_EVENTS_COUNT_ID = 0x1A,
|
||||
MAX_DIE_BAD_BLOCK_ID = 0x1B,
|
||||
MAX_NAND_CHANNEL_BAD_BLOCK_ID = 0x1C,
|
||||
MIN_NAND_CHANNEL_BAD_BLOCK_ID = 0x1D,
|
||||
|
||||
//RESERVED = 7FFFh-1Eh,
|
||||
//VENDOR_UNIQUE_CLASS_TYPE = FFFFh-8000h,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* enum ocp_telemetry_debug_event_class_types - OCP Debug Event Class types
|
||||
* @RESERVED_CLASS_TYPE: Reserved class
|
||||
|
@ -1018,6 +1235,10 @@ static inline const char *telemetry_media_wear_event_id_to_string(int event_id)
|
|||
{
|
||||
return ARGSTR(telemetry_media_wear_event_id_str, event_id);
|
||||
}
|
||||
static inline const char *telemetry_virtual_fifo_event_id_to_string(int event_id)
|
||||
{
|
||||
return ARGSTR(telemetry_virtual_fifo_event_id_str, event_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief parse the ocp telemetry host or controller log binary file
|
||||
|
@ -1129,7 +1350,7 @@ int print_ocp_telemetry_json(struct ocp_telemetry_parse_options *options);
|
|||
*
|
||||
* @return 0 success
|
||||
*/
|
||||
int get_static_id_ascii_string(int identifier, char *description);
|
||||
int get_statistic_id_ascii_string(int identifier, char *description);
|
||||
|
||||
/**
|
||||
* @brief gets event id ascii string
|
||||
|
|
13
plugins/ocp/ocp-types.h
Normal file
13
plugins/ocp/ocp-types.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
#ifndef OCP_TYPES_H
|
||||
#define OCP_TYPES_H
|
||||
|
||||
#define OCP_GET(value, name) NVME_GET(value, OCP_##name)
|
||||
#define OCP_SET(value, name) NVME_SET(value, OCP_##name)
|
||||
|
||||
enum nvme_ocp_enable_ieee1667_silo {
|
||||
NVME_OCP_ENABLE_IEEE1667_SILO_SHIFT = 31,
|
||||
NVME_OCP_ENABLE_IEEE1667_SILO_MASK = 1,
|
||||
};
|
||||
|
||||
#endif /* OCP_TYPES_H */
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "util/types.h"
|
||||
#include "ocp-nvme.h"
|
||||
#include "ocp-utils.h"
|
||||
|
||||
const unsigned char ocp_uuid[NVME_UUID_LEN] = {
|
||||
|
@ -37,3 +39,23 @@ int ocp_get_uuid_index(struct nvme_dev *dev, __u8 *index)
|
|||
|
||||
return ocp_find_uuid_index(&uuid_list, index);
|
||||
}
|
||||
|
||||
int ocp_get_log_simple(struct nvme_dev *dev, enum ocp_dssd_log_id lid, __u32 len, void *log)
|
||||
{
|
||||
int fd = dev_fd(dev);
|
||||
struct nvme_get_log_args args = {
|
||||
.log = log,
|
||||
.args_size = sizeof(args),
|
||||
.fd = fd,
|
||||
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
|
||||
.lid = (enum nvme_cmd_get_log_lid)lid,
|
||||
.len = len,
|
||||
.nsid = NVME_NSID_ALL,
|
||||
.lsi = NVME_LOG_LSI_NONE,
|
||||
.lsp = NVME_LOG_LSP_NONE,
|
||||
};
|
||||
|
||||
ocp_get_uuid_index(dev, &args.uuidx);
|
||||
|
||||
return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
*
|
||||
* Author: leonardo.da.cunha@solidigm.com
|
||||
*/
|
||||
|
||||
#include "nvme.h"
|
||||
|
||||
/*
|
||||
|
@ -30,3 +29,5 @@ int ocp_get_uuid_index(struct nvme_dev *dev, __u8 *index);
|
|||
* Return: Zero if nvme device has UUID list log page, Negative POSIX error code otherwise.
|
||||
*/
|
||||
int ocp_find_uuid_index(struct nvme_id_uuid_list *uuid_list, __u8 *index);
|
||||
|
||||
int ocp_get_log_simple(struct nvme_dev *dev, enum ocp_dssd_log_id lid, __u32 len, void *log);
|
||||
|
|
|
@ -22,9 +22,11 @@
|
|||
#include "nvme-wrap.h"
|
||||
#include "nvme-print.h"
|
||||
#include "util/cleanup.h"
|
||||
#include "util/types.h"
|
||||
|
||||
#define CREATE_CMD
|
||||
#include "sfx-nvme.h"
|
||||
#include "sfx-types.h"
|
||||
|
||||
#define SFX_PAGE_SHIFT 12
|
||||
#define SECTOR_SHIFT 9
|
||||
|
@ -32,8 +34,10 @@
|
|||
#define SFX_GET_FREESPACE _IOWR('N', 0x240, struct sfx_freespace_ctx)
|
||||
#define NVME_IOCTL_CLR_CARD _IO('N', 0x47)
|
||||
|
||||
//See IDEMA LBA1-03
|
||||
#define IDEMA_CAP(exp_GB) (((__u64)exp_GB - 50ULL) * 1953504ULL + 97696368ULL)
|
||||
#define IDEMA_CAP2GB(exp_sector) (((__u64)exp_sector - 97696368ULL) / 1953504ULL + 50ULL)
|
||||
#define IDEMA_CAP2GB(exp_sector) (((__u64)exp_sector - 97696368ULL) / 1953504ULL + 50ULL)
|
||||
#define IDEMA_CAP2GB_LDS(exp_sector) (((__u64)exp_sector - 12212046ULL) / 244188ULL + 50ULL)
|
||||
|
||||
#define VANDA_MAJOR_IDX 0
|
||||
#define VANDA_MINOR_IDX 0
|
||||
|
@ -41,93 +45,7 @@
|
|||
#define MYRTLE_MAJOR_IDX 4
|
||||
#define MYRTLE_MINOR_IDX 1
|
||||
|
||||
enum {
|
||||
SFX_LOG_LATENCY_READ_STATS = 0xc1,
|
||||
SFX_LOG_SMART = 0xc2,
|
||||
SFX_LOG_LATENCY_WRITE_STATS = 0xc3,
|
||||
SFX_LOG_QUAL = 0xc4,
|
||||
SFX_LOG_MISMATCHLBA = 0xc5,
|
||||
SFX_LOG_MEDIA = 0xc6,
|
||||
SFX_LOG_BBT = 0xc7,
|
||||
SFX_LOG_IDENTIFY = 0xcc,
|
||||
SFX_FEAT_ATOMIC = 0x01,
|
||||
SFX_FEAT_UP_P_CAP = 0xac,
|
||||
SFX_FEAT_CLR_CARD = 0xdc,
|
||||
};
|
||||
|
||||
enum sfx_nvme_admin_opcode {
|
||||
nvme_admin_query_cap_info = 0xd3,
|
||||
nvme_admin_change_cap = 0xd4,
|
||||
nvme_admin_sfx_set_features = 0xd5,
|
||||
nvme_admin_sfx_get_features = 0xd6,
|
||||
};
|
||||
|
||||
struct sfx_freespace_ctx {
|
||||
__u64 free_space;
|
||||
__u64 phy_cap; /* physical capacity, in unit of sector */
|
||||
__u64 phy_space; /* physical space considering OP, in unit of sector */
|
||||
__u64 user_space; /* user required space, in unit of sector*/
|
||||
__u64 hw_used; /* hw space used in 4K */
|
||||
__u64 app_written; /* app data written in 4K */
|
||||
__u64 out_of_space;
|
||||
__u64 map_unit;
|
||||
__u64 max_user_space;
|
||||
__u64 extendible_user_cap_lba_count;
|
||||
__u64 friendly_change_cap_support;
|
||||
};
|
||||
|
||||
struct nvme_capacity_info {
|
||||
__u64 lba_sec_sz;
|
||||
__u64 phy_sec_sz;
|
||||
__u64 used_space;
|
||||
__u64 free_space;
|
||||
};
|
||||
|
||||
struct __packed nvme_additional_smart_log_item {
|
||||
__u8 key;
|
||||
__u8 _kp[2];
|
||||
__u8 norm;
|
||||
__u8 _np;
|
||||
union __packed {
|
||||
__u8 raw[6];
|
||||
struct __packed wear_level {
|
||||
__le16 min;
|
||||
__le16 max;
|
||||
__le16 avg;
|
||||
} wear_level;
|
||||
struct __packed thermal_throttle {
|
||||
__u8 pct;
|
||||
__u32 count;
|
||||
} thermal_throttle;
|
||||
};
|
||||
__u8 _rp;
|
||||
};
|
||||
|
||||
struct nvme_additional_smart_log {
|
||||
struct nvme_additional_smart_log_item program_fail_cnt;
|
||||
struct nvme_additional_smart_log_item erase_fail_cnt;
|
||||
struct nvme_additional_smart_log_item wear_leveling_cnt;
|
||||
struct nvme_additional_smart_log_item e2e_err_cnt;
|
||||
struct nvme_additional_smart_log_item crc_err_cnt;
|
||||
struct nvme_additional_smart_log_item timed_workload_media_wear;
|
||||
struct nvme_additional_smart_log_item timed_workload_host_reads;
|
||||
struct nvme_additional_smart_log_item timed_workload_timer;
|
||||
struct nvme_additional_smart_log_item thermal_throttle_status;
|
||||
struct nvme_additional_smart_log_item retry_buffer_overflow_cnt;
|
||||
struct nvme_additional_smart_log_item pll_lock_loss_cnt;
|
||||
struct nvme_additional_smart_log_item nand_bytes_written;
|
||||
struct nvme_additional_smart_log_item host_bytes_written;
|
||||
struct nvme_additional_smart_log_item raid_recover_cnt; /* errors which can be recovered by RAID */
|
||||
struct nvme_additional_smart_log_item prog_timeout_cnt;
|
||||
struct nvme_additional_smart_log_item erase_timeout_cnt;
|
||||
struct nvme_additional_smart_log_item read_timeout_cnt;
|
||||
struct nvme_additional_smart_log_item read_ecc_cnt; /* retry cnt */
|
||||
struct nvme_additional_smart_log_item non_media_crc_err_cnt;
|
||||
struct nvme_additional_smart_log_item compression_path_err_cnt;
|
||||
struct nvme_additional_smart_log_item out_of_space_flag;
|
||||
struct nvme_additional_smart_log_item physical_usage_ratio;
|
||||
struct nvme_additional_smart_log_item grown_bb; /* grown bad block */
|
||||
};
|
||||
|
||||
int nvme_query_cap(int fd, __u32 nsid, __u32 data_len, void *data)
|
||||
{
|
||||
|
@ -183,13 +101,14 @@ int nvme_sfx_get_features(int fd, __u32 nsid, __u32 fid, __u32 *result)
|
|||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_JSONC
|
||||
static void show_sfx_smart_log_jsn(struct nvme_additional_smart_log *smart,
|
||||
unsigned int nsid, const char *devname)
|
||||
{
|
||||
struct json_object *root, *entry_stats, *dev_stats, *multi;
|
||||
|
||||
root = json_create_object();
|
||||
json_object_add_value_string(root, "Intel Smart log", devname);
|
||||
json_object_add_value_string(root, "ScaleFlux Smart log", devname);
|
||||
|
||||
dev_stats = json_create_object();
|
||||
|
||||
|
@ -318,9 +237,12 @@ static void show_sfx_smart_log_jsn(struct nvme_additional_smart_log *smart,
|
|||
json_object_add_value_object(root, "Device stats", dev_stats);
|
||||
|
||||
json_print_object(root, NULL);
|
||||
printf("/n");
|
||||
printf("\n");
|
||||
json_free_object(root);
|
||||
}
|
||||
#else /* CONFIG_JSONC */
|
||||
#define show_sfx_smart_log_jsn(smart, nsid, devname)
|
||||
#endif /* CONFIG_JSONC */
|
||||
|
||||
static void show_sfx_smart_log(struct nvme_additional_smart_log *smart,
|
||||
unsigned int nsid, const char *devname)
|
||||
|
@ -410,7 +332,9 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
|
|||
"Get ScaleFlux vendor specific additional smart log (optionally, for the specified namespace), and show it.";
|
||||
const char *namespace = "(optional) desired namespace";
|
||||
const char *raw = "dump output in binary format";
|
||||
#ifdef CONFIG_JSONC
|
||||
const char *json = "Dump output in json format";
|
||||
#endif /* CONFIG_JSONC */
|
||||
struct nvme_dev *dev;
|
||||
struct config {
|
||||
__u32 namespace_id;
|
||||
|
@ -420,17 +344,16 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
|
|||
int err;
|
||||
|
||||
struct config cfg = {
|
||||
.namespace_id = 0xffffffff,
|
||||
.namespace_id = NVME_NSID_ALL,
|
||||
};
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace),
|
||||
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
|
||||
OPT_FLAG("json", 'j', &cfg.json, json),
|
||||
OPT_FLAG_JSON("json", 'j', &cfg.json, json),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
|
||||
err = parse_and_open(&dev, argc, argv, desc, opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -453,56 +376,6 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
|
|||
return err;
|
||||
}
|
||||
|
||||
struct __packed sfx_lat_stats_vanda {
|
||||
__u16 maj;
|
||||
__u16 min;
|
||||
__u32 bucket_1[32]; /* 0~1ms, step 32us */
|
||||
__u32 bucket_2[31]; /* 1~32ms, step 1ms */
|
||||
__u32 bucket_3[31]; /* 32ms~1s, step 32ms */
|
||||
__u32 bucket_4[1]; /* 1s~2s, specifically 1024ms~2047ms */
|
||||
__u32 bucket_5[1]; /* 2s~4s, specifically 2048ms~4095ms */
|
||||
__u32 bucket_6[1]; /* 4s+, specifically 4096ms+ */
|
||||
};
|
||||
|
||||
struct __packed sfx_lat_stats_myrtle {
|
||||
__u16 maj;
|
||||
__u16 min;
|
||||
__u32 bucket_1[64]; /* 0us~63us, step 1us */
|
||||
__u32 bucket_2[64]; /* 63us~127us, step 1us */
|
||||
__u32 bucket_3[64]; /* 127us~255us, step 2us */
|
||||
__u32 bucket_4[64]; /* 255us~510us, step 4us */
|
||||
__u32 bucket_5[64]; /* 510us~1.02ms step 8us */
|
||||
__u32 bucket_6[64]; /* 1.02ms~2.04ms step 16us */
|
||||
__u32 bucket_7[64]; /* 2.04ms~4.08ms step 32us */
|
||||
__u32 bucket_8[64]; /* 4.08ms~8.16ms step 64us */
|
||||
__u32 bucket_9[64]; /* 8.16ms~16.32ms step 128us */
|
||||
__u32 bucket_10[64]; /* 16.32ms~32.64ms step 256us */
|
||||
__u32 bucket_11[64]; /* 32.64ms~65.28ms step 512us */
|
||||
__u32 bucket_12[64]; /* 65.28ms~130.56ms step 1.024ms */
|
||||
__u32 bucket_13[64]; /* 130.56ms~261.12ms step 2.048ms */
|
||||
__u32 bucket_14[64]; /* 261.12ms~522.24ms step 4.096ms */
|
||||
__u32 bucket_15[64]; /* 522.24ms~1.04s step 8.192ms */
|
||||
__u32 bucket_16[64]; /* 1.04s~2.09s step 16.384ms */
|
||||
__u32 bucket_17[64]; /* 2.09s~4.18s step 32.768ms */
|
||||
__u32 bucket_18[64]; /* 4.18s~8.36s step 65.536ms */
|
||||
__u32 bucket_19[64]; /* 8.36s~ step 131.072ms */
|
||||
__u64 average; /* average latency statistics */
|
||||
};
|
||||
|
||||
|
||||
struct __packed sfx_lat_status_ver {
|
||||
__u16 maj;
|
||||
__u16 min;
|
||||
};
|
||||
|
||||
struct sfx_lat_stats {
|
||||
union {
|
||||
struct sfx_lat_status_ver ver;
|
||||
struct sfx_lat_stats_vanda vanda;
|
||||
struct sfx_lat_stats_myrtle myrtle;
|
||||
};
|
||||
};
|
||||
|
||||
static void show_lat_stats_vanda(struct sfx_lat_stats_vanda *stats, int write)
|
||||
{
|
||||
int i;
|
||||
|
@ -713,7 +586,7 @@ static int get_bb_table(int fd, __u32 nsid, unsigned char *buf, __u64 size)
|
|||
/**
|
||||
* @brief display bb table
|
||||
*
|
||||
* @param bd_table buffer that contain bb table dumped from drvier
|
||||
* @param bd_table buffer that contain bb table dumped from driver
|
||||
* @param table_size buffer size (BYTES), should at least has 8 bytes for mf_bb_count and grown_bb_count
|
||||
*/
|
||||
static void bd_table_show(unsigned char *bd_table, __u64 table_size)
|
||||
|
@ -796,7 +669,7 @@ static int sfx_get_bad_block(int argc, char **argv, struct command *cmd, struct
|
|||
return -1;
|
||||
}
|
||||
|
||||
err = get_bb_table(dev_fd(dev), 0xffffffff, data_buf, buf_size);
|
||||
err = get_bb_table(dev_fd(dev), NVME_NSID_ALL, data_buf, buf_size);
|
||||
if (err < 0) {
|
||||
perror("get-bad-block");
|
||||
} else if (err) {
|
||||
|
@ -847,7 +720,7 @@ static int query_cap_info(int argc, char **argv, struct command *cmd, struct plu
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
if (nvme_query_cap(dev_fd(dev), 0xffffffff, sizeof(ctx), &ctx)) {
|
||||
if (nvme_query_cap(dev_fd(dev), NVME_NSID_ALL, sizeof(ctx), &ctx)) {
|
||||
perror("sfx-query-cap");
|
||||
err = -1;
|
||||
}
|
||||
|
@ -868,22 +741,22 @@ static int change_sanity_check(int fd, __u64 trg_in_4k, int *shrink)
|
|||
struct sysinfo s_info;
|
||||
__u64 mem_need = 0;
|
||||
__u64 cur_in_4k = 0;
|
||||
__u64 provisoned_cap_4k = 0;
|
||||
__u64 provisioned_cap_4k = 0;
|
||||
int extend = 0;
|
||||
|
||||
if (nvme_query_cap(fd, 0xffffffff, sizeof(freespace_ctx), &freespace_ctx))
|
||||
if (nvme_query_cap(fd, NVME_NSID_ALL, sizeof(freespace_ctx), &freespace_ctx))
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* capacity illegal check
|
||||
*/
|
||||
provisoned_cap_4k = freespace_ctx.phy_space >>
|
||||
provisioned_cap_4k = freespace_ctx.phy_space >>
|
||||
(SFX_PAGE_SHIFT - SECTOR_SHIFT);
|
||||
if (trg_in_4k < provisoned_cap_4k ||
|
||||
trg_in_4k > ((__u64)provisoned_cap_4k * 4)) {
|
||||
if (trg_in_4k < provisioned_cap_4k ||
|
||||
trg_in_4k > ((__u64)provisioned_cap_4k * 4)) {
|
||||
fprintf(stderr,
|
||||
"WARNING: Only support 1.0~4.0 x provisioned capacity!\n");
|
||||
if (trg_in_4k < provisoned_cap_4k)
|
||||
if (trg_in_4k < provisioned_cap_4k)
|
||||
fprintf(stderr,
|
||||
"WARNING: The target capacity is less than 1.0 x provisioned capacity!\n");
|
||||
else
|
||||
|
@ -891,7 +764,7 @@ static int change_sanity_check(int fd, __u64 trg_in_4k, int *shrink)
|
|||
"WARNING: The target capacity is larger than 4.0 x provisioned capacity!\n");
|
||||
return -1;
|
||||
}
|
||||
if (trg_in_4k > ((__u64)provisoned_cap_4k*4)) {
|
||||
if (trg_in_4k > ((__u64)provisioned_cap_4k*4)) {
|
||||
fprintf(stderr, "WARNING: the target capacity is too large\n");
|
||||
return -1;
|
||||
}
|
||||
|
@ -997,7 +870,7 @@ static int change_cap(int argc, char **argv, struct command *cmd, struct plugin
|
|||
return 0;
|
||||
}
|
||||
|
||||
err = nvme_change_cap(dev_fd(dev), 0xffffffff, cap_in_4k);
|
||||
err = nvme_change_cap(dev_fd(dev), NVME_NSID_ALL, cap_in_4k);
|
||||
if (err < 0) {
|
||||
perror("sfx-change-cap");
|
||||
} else if (err) {
|
||||
|
@ -1112,7 +985,7 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl
|
|||
}
|
||||
|
||||
if (cfg.feature_id == SFX_FEAT_ATOMIC && cfg.value) {
|
||||
if (cfg.namespace_id != 0xffffffff) {
|
||||
if (cfg.namespace_id != NVME_NSID_ALL) {
|
||||
err = nvme_identify_ns(dev_fd(dev), cfg.namespace_id,
|
||||
&ns);
|
||||
if (err) {
|
||||
|
@ -1506,7 +1379,7 @@ static int sfx_dump_evtlog(int argc, char **argv, struct command *cmd, struct pl
|
|||
};
|
||||
struct config cfg = {
|
||||
.file = NULL,
|
||||
.namespace_id = 0xffffffff,
|
||||
.namespace_id = NVME_NSID_ALL,
|
||||
.storage_medium = 0,
|
||||
.parse = false,
|
||||
.output = NULL,
|
||||
|
@ -1634,7 +1507,7 @@ static int sfx_expand_cap(int argc, char **argv, struct command *cmd, struct plu
|
|||
__u32 units;
|
||||
};
|
||||
struct config cfg = {
|
||||
.namespace_id = 0xffffffff,
|
||||
.namespace_id = NVME_NSID_ALL,
|
||||
.lbaf = 0,
|
||||
.units = 0,
|
||||
};
|
||||
|
@ -1652,7 +1525,7 @@ static int sfx_expand_cap(int argc, char **argv, struct command *cmd, struct plu
|
|||
if (err)
|
||||
goto ret;
|
||||
|
||||
if (cfg.namespace_id == 0xffffffff) {
|
||||
if (cfg.namespace_id == NVME_NSID_ALL) {
|
||||
if (S_ISCHR(dev->direct.stat.st_mode)) {
|
||||
fprintf(stderr, "namespace_id or blk device required\n");
|
||||
err = EINVAL;
|
||||
|
@ -1685,3 +1558,528 @@ close_dev:
|
|||
ret:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int sfx_status(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
||||
{
|
||||
const char *desc = "Get ScaleFlux specific status information and print it";
|
||||
const char *json_desc = "Print output in JSON format, otherwise human readable";
|
||||
struct nvme_dev *dev;
|
||||
struct nvme_id_ctrl id_ctrl = { 0 };
|
||||
struct extended_health_info_myrtle sfx_smart = { 0 };
|
||||
struct nvme_smart_log smart_log = { 0 };
|
||||
struct nvme_additional_smart_log additional_smart_log = { 0 };
|
||||
struct sfx_freespace_ctx sfx_freespace = { 0 };
|
||||
struct nvme_get_features_args get_feat_args = { 0 };
|
||||
unsigned int get_feat_result, pcie_correctable, pcie_fatal, pcie_nonfatal;
|
||||
unsigned long long capacity;
|
||||
bool capacity_valid = false;
|
||||
int err, fd, len, sector_size;
|
||||
char pci_vid[7], pci_did[7], pci_ssvid[7], link_speed[20], link_width[5], link_string[40];
|
||||
char path[512], numa_node[5], vendor[10], form_factor[15], temperature[10], io_speed[15];
|
||||
char chr_dev[8], serial_number[21], model_number[41], firmware_revision[9], pcie_status[9];
|
||||
struct json_object *root, *dev_stats, *link_stats, *crit_stats;
|
||||
double write_amp;
|
||||
|
||||
struct config {
|
||||
bool json;
|
||||
};
|
||||
struct config cfg = {
|
||||
.json = false
|
||||
};
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
OPT_FLAG("json-print", 'j', &cfg.json, json_desc),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
err = parse_and_open(&dev, argc, argv, desc, opts);
|
||||
|
||||
if (err)
|
||||
goto ret;
|
||||
|
||||
//Calculate formatted capacity, not concerned with errors, we may have a char device
|
||||
memset(&path, 0, 512);
|
||||
snprintf(path, 512, "/dev/%s", dev->name);
|
||||
fd = open(path, O_RDONLY | O_NONBLOCK);
|
||||
if (fd >= 0) {
|
||||
err = ioctl(fd, BLKSSZGET, §or_size);
|
||||
if (!err)
|
||||
err = ioctl(fd, BLKGETSIZE64, &capacity);
|
||||
capacity_valid = (!err);
|
||||
}
|
||||
|
||||
if (capacity_valid && sector_size == 512)
|
||||
capacity = IDEMA_CAP2GB(capacity/sector_size);
|
||||
else if (capacity_valid && sector_size == 4096)
|
||||
capacity = IDEMA_CAP2GB_LDS(capacity/sector_size);
|
||||
else
|
||||
capacity = capacity / (1000 * 1000 * 1000); //B --> GB
|
||||
|
||||
memset(&chr_dev, 0, 8);
|
||||
strcpy(chr_dev, dev->name);
|
||||
for (len = 2; len < 8; len++) {
|
||||
if (chr_dev[len] == 'n')
|
||||
chr_dev[len] = '\0';
|
||||
}
|
||||
|
||||
// Populate PCIe VID/DID/SS_VID, link speed/width, and NUMA node from /sys/
|
||||
snprintf(path, 512, "/sys/class/nvme/%s/device/vendor", chr_dev);
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("Could not open PCIe VID in /sys/");
|
||||
err = errno;
|
||||
goto close_dev;
|
||||
}
|
||||
memset(&pci_vid, 0, 7);
|
||||
len = read(fd, pci_vid, 6);
|
||||
if (len < 1) {
|
||||
perror("Could not read PCIe VID in /sys/");
|
||||
close(fd);
|
||||
err = errno;
|
||||
goto close_dev;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
snprintf(path, 512, "/sys/class/nvme/%s/device/device", chr_dev);
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("Could not open PCIe DID in /sys/");
|
||||
err = errno;
|
||||
goto close_dev;
|
||||
}
|
||||
memset(&pci_did, 0, 7);
|
||||
len = read(fd, pci_did, 6);
|
||||
if (len < 1) {
|
||||
perror("Could not read PCIe DID in /sys/");
|
||||
close(fd);
|
||||
err = errno;
|
||||
goto close_dev;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
if (strncmp("0xcc53", pci_vid, 6) == 0)
|
||||
strncpy(vendor, "ScaleFlux", 10);
|
||||
else if (strncmp("0x1dfd", pci_vid, 6) == 0)
|
||||
strncpy(vendor, "DIGISTOR", 10);
|
||||
else {
|
||||
fprintf(stderr, "Please use on a ScaleFlux device\n");
|
||||
err = -1;
|
||||
goto close_dev;
|
||||
}
|
||||
|
||||
snprintf(path, 512, "/sys/class/nvme/%s/device/subsystem_vendor", chr_dev);
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("Could not open PCIe Subsystem Vendor ID in /sys/");
|
||||
err = errno;
|
||||
goto close_dev;
|
||||
}
|
||||
memset(&pci_ssvid, 0, 7);
|
||||
len = read(fd, pci_ssvid, 6);
|
||||
if (len < 1) {
|
||||
perror("could not read PCIe Subsystem Vendor ID in /sys/");
|
||||
close(fd);
|
||||
err = errno;
|
||||
goto close_dev;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
snprintf(path, 512, "/sys/class/nvme/%s/device/current_link_speed", chr_dev);
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("Could not open link speed in /sys/");
|
||||
err = errno;
|
||||
goto close_dev;
|
||||
}
|
||||
memset(&link_speed, 0, 20);
|
||||
len = read(fd, link_speed, 20);
|
||||
if (len < 1) {
|
||||
perror("Could not read link speed in /sys/");
|
||||
close(fd);
|
||||
err = errno;
|
||||
goto close_dev;
|
||||
}
|
||||
close(fd);
|
||||
// Ending string before "PCIe" and newline
|
||||
for (len = 0; (len+2) < 20 && link_speed[len+2] != '\0'; ++len) {
|
||||
if (link_speed[len] == '/' && link_speed[len+1] == 's')
|
||||
link_speed[len+2] = '\0';
|
||||
}
|
||||
|
||||
snprintf(path, 512, "/sys/class/nvme/%s/device/current_link_width", chr_dev);
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("Could not open link width in /sys/");
|
||||
err = errno;
|
||||
goto close_dev;
|
||||
}
|
||||
memset(&link_width, 0, 5);
|
||||
len = read(fd, link_width, 5);
|
||||
if (len < 1) {
|
||||
perror("Could not read link width in /sys/");
|
||||
close(fd);
|
||||
err = errno;
|
||||
goto close_dev;
|
||||
}
|
||||
close(fd);
|
||||
// Ending string before newline
|
||||
for (len = 0; (len) < 5 ; ++len) {
|
||||
if (link_width[len] == '\n')
|
||||
link_width[len] = '\0';
|
||||
}
|
||||
|
||||
snprintf(link_string, 40, "Speed %s, Width x%s", link_speed, link_width);
|
||||
|
||||
snprintf(path, 512, "/sys/class/nvme/%s/device/numa_node", chr_dev);
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("Could not open NUMA node in /sys/");
|
||||
err = errno;
|
||||
goto close_dev;
|
||||
}
|
||||
memset(&numa_node, 0, 5);
|
||||
len = read(fd, numa_node, 5);
|
||||
if (len < 1) {
|
||||
perror("Could not read NUMA node in /sys/");
|
||||
close(fd);
|
||||
err = errno;
|
||||
goto close_dev;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
for (len = 0; len < 5; ++len) {
|
||||
if (numa_node[len] == '\n')
|
||||
numa_node[len] = '\0';
|
||||
}
|
||||
|
||||
//Populate PCIe AER errors from /sys/
|
||||
snprintf(path, 512, "/sys/class/nvme/%s/device/aer_dev_correctable", chr_dev);
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("Could not open PCIe AER Correctable errors in /sys/");
|
||||
err = errno;
|
||||
goto close_dev;
|
||||
}
|
||||
len = read(fd, path, 512);
|
||||
if (len < 1) {
|
||||
perror("Could not read PCIe AER Correctable errors in /sys/");
|
||||
close(fd);
|
||||
err = errno;
|
||||
goto close_dev;
|
||||
}
|
||||
close(fd);
|
||||
len = sscanf(path, "%*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d TOTAL_ERR_COR %d", &pcie_correctable);
|
||||
len = 1;
|
||||
if (len < 1 || len == EOF) {
|
||||
perror("Could not parse PCIe AER Correctable errors in /sys/");
|
||||
err = -1;
|
||||
goto close_dev;
|
||||
}
|
||||
|
||||
snprintf(path, 512, "/sys/class/nvme/%s/device/aer_dev_nonfatal", chr_dev);
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("Could not open PCIe AER Non-Fatal errors in /sys/");
|
||||
err = errno;
|
||||
goto close_dev;
|
||||
}
|
||||
|
||||
len = read(fd, path, 512);
|
||||
if (len < 1) {
|
||||
perror("Could not read PCIe AER Non-Fatal errors in /sys/");
|
||||
err = errno;
|
||||
goto close_dev;
|
||||
}
|
||||
close(fd);
|
||||
len = sscanf(path, "%*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d TOTAL_ERR_NONFATAL %d", &pcie_nonfatal);
|
||||
if (len < 1) {
|
||||
perror("Could not parse PCIe AER Non-Fatal errors in /sys/");
|
||||
err = -1;
|
||||
goto close_dev;
|
||||
}
|
||||
|
||||
snprintf(path, 512, "/sys/class/nvme/%s/device/aer_dev_fatal", chr_dev);
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("Could not open PCIe AER Fatal errors in /sys/");
|
||||
err = errno;
|
||||
goto close_dev;
|
||||
}
|
||||
|
||||
len = read(fd, path, 512);
|
||||
if (len < 1) {
|
||||
perror("Could not read PCIe AER Fatal errors in /sys/");
|
||||
close(fd);
|
||||
err = errno;
|
||||
goto close_dev;
|
||||
}
|
||||
close(fd);
|
||||
len = sscanf(path, "%*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d TOTAL_ERR_FATAL %d", &pcie_fatal);
|
||||
if (len < 1) {
|
||||
perror("Could not parse PCIe AER Fatal errors in /sys/");
|
||||
close(fd);
|
||||
err = -1;
|
||||
goto close_dev;
|
||||
}
|
||||
|
||||
snprintf(pcie_status, 9, "%s", (pcie_fatal != 0 || pcie_nonfatal != 0 || pcie_correctable != 0) ? "Warning":"Good");
|
||||
|
||||
//Populate id-ctrl
|
||||
err = nvme_identify_ctrl(dev_fd(dev), &id_ctrl);
|
||||
if (err) {
|
||||
fprintf(stderr, "Unable to read nvme_identify_ctrl() error code:%x\n", err);
|
||||
goto close_dev;
|
||||
}
|
||||
//Re-format specific fields so they can be safely treated as strings later
|
||||
serial_number[20] = '\0';
|
||||
memcpy(serial_number, id_ctrl.sn, 20);
|
||||
model_number[40] = '\0';
|
||||
memcpy(model_number, id_ctrl.mn, 40);
|
||||
firmware_revision[8] = '\0';
|
||||
memcpy(firmware_revision, id_ctrl.fr, 8);
|
||||
|
||||
//Populate SMART log (0x02)
|
||||
err = nvme_cli_get_log_smart(dev, NVME_NSID_ALL, false, &smart_log);
|
||||
if (err < 0) {
|
||||
perror("Could not read SMART log (0x02)");
|
||||
err = errno;
|
||||
goto close_dev;
|
||||
} else if (err > 0) {
|
||||
nvme_show_status(err);
|
||||
goto close_dev;
|
||||
}
|
||||
|
||||
snprintf(temperature, 10, "%li", kelvin_to_celsius(smart_log.temperature[1]<<8 | smart_log.temperature[0]));
|
||||
|
||||
//Populate SFX Extended Health log (0xC2) or if PCIe DID ==0x20 (Quince) use 0xD2
|
||||
if (strncmp("0x0020", pci_did, 6) == 0)
|
||||
err = nvme_get_log_simple(dev_fd(dev), SFX_LOG_EXTENDED_HEALTH_ALT, sizeof(sfx_smart), (void *)&sfx_smart);
|
||||
else
|
||||
err = nvme_get_log_simple(dev_fd(dev), SFX_LOG_EXTENDED_HEALTH, sizeof(sfx_smart), (void *)&sfx_smart);
|
||||
if (err < 0) {
|
||||
perror("Could not read ScaleFlux SMART log");
|
||||
err = errno;
|
||||
goto close_dev;
|
||||
} else if (err > 0) {
|
||||
nvme_show_status(err);
|
||||
goto close_dev;
|
||||
}
|
||||
|
||||
//Make sure the OPN can be printed safely
|
||||
sfx_smart.opn[10] = '\0';
|
||||
|
||||
switch (sfx_smart.opn[3]) {
|
||||
case 'P':
|
||||
snprintf(form_factor, 15, "%s", "AIC");
|
||||
break;
|
||||
case 'U':
|
||||
snprintf(form_factor, 15, "%s", (sfx_smart.opn[4] == '8')?"U.3":"U.2");
|
||||
break;
|
||||
case 'E':
|
||||
snprintf(form_factor, 15, "%s", "E1.S");
|
||||
break;
|
||||
default:
|
||||
snprintf(form_factor, 15, "%s", "Incorrect OPN");
|
||||
}
|
||||
|
||||
//Populate Additional SMART log (0xCA)
|
||||
err = nvme_get_nsid_log(dev_fd(dev), false, 0xca, NVME_NSID_ALL, sizeof(struct nvme_additional_smart_log), (void *)&additional_smart_log);
|
||||
if (err < 0) {
|
||||
perror("Could not read ScaleFlux SMART log");
|
||||
err = errno;
|
||||
goto close_dev;
|
||||
} else if (err > 0) {
|
||||
nvme_show_status(err);
|
||||
goto close_dev;
|
||||
}
|
||||
|
||||
//OK with the '-nan' if host_bytes_written is zero
|
||||
write_amp = int48_to_long(additional_smart_log.nand_bytes_written.raw)/(1.0 * int48_to_long(additional_smart_log.host_bytes_written.raw));
|
||||
|
||||
//Get SFX freespace information
|
||||
err = nvme_query_cap(dev_fd(dev), NVME_NSID_ALL, sizeof(sfx_freespace), &sfx_freespace);
|
||||
if (err < 0) {
|
||||
perror("Could not query freespace information (0xD6)");
|
||||
err = errno;
|
||||
goto close_dev;
|
||||
} else if (err > 0) {
|
||||
nvme_show_status(err);
|
||||
goto close_dev;
|
||||
}
|
||||
|
||||
//Parse IO Speed information
|
||||
memset(&io_speed, 0, 15);
|
||||
switch (sfx_smart.io_speed) {
|
||||
case '1':
|
||||
if (strncmp("0x0020", pci_did, 6))
|
||||
strncpy(io_speed, "2.5MB/s", 15);
|
||||
else
|
||||
strncpy(io_speed, "10MB/s", 15);
|
||||
break;
|
||||
case '2':
|
||||
if (strncmp("0x0020", pci_did, 6))
|
||||
strncpy(io_speed, "128KB/s", 15);
|
||||
else
|
||||
strncpy(io_speed, "512KB/s", 15);
|
||||
break;
|
||||
case '3':
|
||||
strncpy(io_speed, "Write Reject", 15);
|
||||
break;
|
||||
default:
|
||||
strncpy(io_speed, "Normal", 15);
|
||||
}
|
||||
|
||||
if (sfx_smart.comp_ratio < 100)
|
||||
sfx_smart.comp_ratio = 100;
|
||||
else if (sfx_smart.comp_ratio > 800)
|
||||
sfx_smart.comp_ratio = 800;
|
||||
|
||||
//Get status of atomic write feature
|
||||
get_feat_args.args_size = sizeof(get_feat_args);
|
||||
get_feat_args.fid = 0x0A;
|
||||
get_feat_args.timeout = NVME_DEFAULT_IOCTL_TIMEOUT;
|
||||
get_feat_args.result = &get_feat_result;
|
||||
err = nvme_cli_get_features(dev, &get_feat_args);
|
||||
if (err < 0) {
|
||||
perror("Could not get feature (0x0A)");
|
||||
err = errno;
|
||||
goto close_dev;
|
||||
} else if (err > 0) {
|
||||
nvme_show_status(err);
|
||||
goto close_dev;
|
||||
}
|
||||
|
||||
if (cfg.json) {
|
||||
root = json_create_object();
|
||||
json_object_add_value_string(root, "ScaleFlux Status", dev->name);
|
||||
|
||||
dev_stats = json_create_object();
|
||||
link_stats = json_create_object();
|
||||
crit_stats = json_create_object();
|
||||
|
||||
json_object_add_value_string(dev_stats, "PCIe Vendor ID", pci_vid);
|
||||
json_object_add_value_string(dev_stats, "PCIe Subsystem Vendor ID", pci_ssvid);
|
||||
json_object_add_value_string(dev_stats, "Manufacturer", vendor);
|
||||
json_object_add_value_string(dev_stats, "Model", model_number);
|
||||
json_object_add_value_string(dev_stats, "Serial Number", serial_number);
|
||||
json_object_add_value_string(dev_stats, "OPN", (char *)sfx_smart.opn);
|
||||
json_object_add_value_string(dev_stats, "Drive Type", form_factor);
|
||||
json_object_add_value_string(dev_stats, "Firmware Revision", firmware_revision);
|
||||
json_object_add_value_string(dev_stats, "Temperature [C]", temperature);
|
||||
json_object_add_value_uint(dev_stats, "Power Consumption [mW]", sfx_smart.power_mw_consumption);
|
||||
json_object_add_value_uint(dev_stats, "Atomic Write Mode", (get_feat_result));
|
||||
json_object_add_value_int(dev_stats, "Percentage Used", smart_log.percent_used);
|
||||
json_object_add_value_string(dev_stats, "Data Read", uint128_t_to_si_string(le128_to_cpu(smart_log.data_units_read), 1000 * 512));
|
||||
json_object_add_value_string(dev_stats, "Data Written", uint128_t_to_si_string(le128_to_cpu(smart_log.data_units_written), 1000 * 512));
|
||||
json_object_add_value_int(dev_stats, "Correctable Error Count", sfx_smart.pcie_rx_correct_errs);
|
||||
json_object_add_value_int(dev_stats, "Uncorrectable Error Count", sfx_smart.pcie_rx_uncorrect_errs);
|
||||
json_object_add_value_string(link_stats, "PCIe Link Width", link_width);
|
||||
json_object_add_value_string(link_stats, "PCIe Link Speed", link_speed);
|
||||
json_object_add_value_int(link_stats, "PCIe Link Fatal Errors", pcie_fatal);
|
||||
json_object_add_value_int(link_stats, "PCIe Link Non-Fatal Errors", pcie_nonfatal);
|
||||
json_object_add_value_int(link_stats, "PCIe Link Correctable Errors", pcie_correctable);
|
||||
json_object_add_value_string(link_stats, "PCIe Device Status", pcie_status);
|
||||
json_object_add_value_object(dev_stats, "PCIe Link Status", link_stats);
|
||||
if (sfx_smart.friendly_changecap_support) {
|
||||
json_object_add_value_int(dev_stats, "Current Formatted Capacity [GB]", sfx_smart.cur_formatted_capability);
|
||||
json_object_add_value_int(dev_stats, "Max Formatted Capacity [GB]", sfx_smart.max_formatted_capability);
|
||||
json_object_add_value_int(dev_stats, "Extendible Capacity LBA count", sfx_smart.extendible_cap_lbacount);
|
||||
} else if (capacity_valid)
|
||||
json_object_add_value_int(dev_stats, "Formatted Capacity [GB]", capacity);
|
||||
|
||||
json_object_add_value_int(dev_stats, "Provisioned Capacity [GB]", IDEMA_CAP2GB(sfx_smart.total_physical_capability));
|
||||
json_object_add_value_int(dev_stats, "Compression Ratio", sfx_smart.comp_ratio);
|
||||
json_object_add_value_int(dev_stats, "Physical Used Ratio", sfx_smart.physical_usage_ratio);
|
||||
json_object_add_value_int(dev_stats, "Free Physical Space [GB]", IDEMA_CAP2GB(sfx_smart.free_physical_capability));
|
||||
json_object_add_value_int(dev_stats, "Firmware RSA Verification", (sfx_smart.otp_rsa_en));
|
||||
json_object_add_value_string(dev_stats, "IO Speed", io_speed);
|
||||
json_object_add_value_string(dev_stats, "NUMA Node", numa_node);
|
||||
json_object_add_value_int(dev_stats, "Indirection Unit [kiB]", (4*sfx_freespace.map_unit));
|
||||
json_object_add_value_double(dev_stats, "Lifetime WAF", write_amp);
|
||||
|
||||
json_object_add_value_int(crit_stats, "Thermal Throttling On", (sfx_smart.temp_throttle_info));
|
||||
json_object_add_value_int(crit_stats, "Backup Capacitor Status Bad", (smart_log.critical_warning & 0x10));
|
||||
json_object_add_value_int(crit_stats, "Bad block exceeds threshold", (smart_log.critical_warning & 0x01));
|
||||
json_object_add_value_int(crit_stats, "Media Error", (smart_log.critical_warning & 0x04));
|
||||
json_object_add_value_int(crit_stats, "Read only mode", (smart_log.critical_warning & 0x08));
|
||||
json_object_add_value_int(crit_stats, "Power Failure Data Loss", (sfx_smart.sfx_critical_warning & SFX_CRIT_PWR_FAIL_DATA_LOSS));
|
||||
json_object_add_value_int(crit_stats, "Exceed physical capacity limitation", (sfx_smart.sfx_critical_warning & SFX_CRIT_OVER_CAP));
|
||||
json_object_add_value_int(crit_stats, "Read/Write lock mode", (sfx_smart.sfx_critical_warning & SFX_CRIT_RW_LOCK));
|
||||
|
||||
json_object_add_value_object(dev_stats, "Critical Warning(s)", crit_stats);
|
||||
|
||||
json_object_add_value_object(root, "Device stats", dev_stats);
|
||||
|
||||
json_print_object(root, NULL);
|
||||
printf("\n");
|
||||
json_free_object(root);
|
||||
|
||||
} else {
|
||||
// Re-using path variable to hold critical warning text
|
||||
// order is to match sfx-status, done here to include color
|
||||
memset(path, 0, 512);
|
||||
len = snprintf(path, 512, FMT_RED "\n%s%s%s%s%s%s%s%s" FMT_RESET, \
|
||||
(sfx_smart.temp_throttle_info) ? "\tThermal Throttling On\n" : "", \
|
||||
(smart_log.critical_warning & 0x10) ? "\tBackup Capacitor Status Bad\n" : "", \
|
||||
(smart_log.critical_warning & 0x01) ? "\tBad block exceeds threshold\n" : "", \
|
||||
(smart_log.critical_warning & 0x04) ? "\tMedia Error\n" : "", \
|
||||
(smart_log.critical_warning & 0x08) ? "\tRead only mode\n" : "", \
|
||||
(sfx_smart.sfx_critical_warning & SFX_CRIT_PWR_FAIL_DATA_LOSS) ? "\tPower Failure Data Loss\n" : "", \
|
||||
(sfx_smart.sfx_critical_warning & SFX_CRIT_OVER_CAP) ? "\tExceed physical capacity limitation\n" : "", \
|
||||
(sfx_smart.sfx_critical_warning & SFX_CRIT_RW_LOCK) ? "\tRead/Write lock mode\n" : "" \
|
||||
);
|
||||
if (len < 11)
|
||||
strcpy(path, "None");
|
||||
|
||||
printf("%-35s%s%s\n", "ScaleFlux Drive:", "/dev/", dev->name);
|
||||
printf("%-35s%s\n", "PCIe Vendor ID:", pci_vid);
|
||||
printf("%-35s%s\n", "PCIe Subsystem Vendor ID:", pci_ssvid);
|
||||
printf("%-35s%s\n", "Manufacturer:", vendor);
|
||||
printf("%-35s%.*s\n", "Model:", 40, model_number);
|
||||
printf("%-35s%.*s\n", "Serial Number:", 20, serial_number);
|
||||
printf("%-35s%.*s\n", "OPN:", 32, sfx_smart.opn);
|
||||
printf("%-35s%s\n", "Drive Type:", form_factor);
|
||||
printf("%-35s%.*s\n", "Firmware Revision:", 8, firmware_revision);
|
||||
printf("%-35s%s C\n", "Temperature:", temperature);
|
||||
printf("%-35s%i mW\n", "Power Consumption:", sfx_smart.power_mw_consumption);
|
||||
printf("%-35s%s\n", "Atomic Write mode:", (get_feat_result)?"Off":"On");
|
||||
printf("%-35s%u%%\n", "Percentage Used:", smart_log.percent_used);
|
||||
printf("%-35s%s\n", "Host Data Read:", uint128_t_to_si_string( le128_to_cpu( \
|
||||
smart_log.data_units_read), 1000 * 512));
|
||||
printf("%-35s%s\n", "Host Data Written:", uint128_t_to_si_string(le128_to_cpu( \
|
||||
smart_log.data_units_written), 1000 * 512));
|
||||
write_amp = int48_to_long(additional_smart_log.nand_bytes_written.raw)/(1.0 * int48_to_long(additional_smart_log.host_bytes_written.raw));
|
||||
printf("%-35s%i\n", "Correctable Error Cnt:", sfx_smart.pcie_rx_correct_errs);
|
||||
printf("%-35s%i\n", "Uncorrectable Error Cnt:", sfx_smart.pcie_rx_uncorrect_errs);
|
||||
printf("%-35s%s\n", "PCIe Link Status:", link_string);
|
||||
printf("%-35s%s\n", "PCIe Device Status:", pcie_status);
|
||||
if (sfx_smart.friendly_changecap_support) {
|
||||
printf("%-35s%"PRIu64" GB\n", "Current Formatted Capacity:",
|
||||
(uint64_t)sfx_smart.cur_formatted_capability);
|
||||
printf("%-35s%"PRIu64" GB\n", "Max Formatted Capacity:",
|
||||
(uint64_t)sfx_smart.max_formatted_capability);
|
||||
printf("%-35s%"PRIu64"\n", "Extendible Capacity LBA count:",
|
||||
(uint64_t)sfx_smart.extendible_cap_lbacount);
|
||||
} else if (capacity_valid) {
|
||||
printf("%-35s%"PRIu64" GB\n", "Formatted Capacity:", (uint64_t)capacity);
|
||||
}
|
||||
printf("%-35s%"PRIu64" GB\n", "Provisioned Capacity:",
|
||||
(uint64_t)IDEMA_CAP2GB(sfx_smart.total_physical_capability));
|
||||
printf("%-35s%u%%\n", "Compression Ratio:", sfx_smart.comp_ratio);
|
||||
printf("%-35s%u%%\n", "Physical Used Ratio:", sfx_smart.physical_usage_ratio);
|
||||
printf("%-35s%"PRIu64" GB\n", "Free Physical Space:",
|
||||
(uint64_t)IDEMA_CAP2GB(sfx_smart.free_physical_capability));
|
||||
printf("%-35s%s\n", "Firmware Verification:", (sfx_smart.otp_rsa_en) ? "On":"Off");
|
||||
printf("%-35s%s\n", "IO Speed:", io_speed);
|
||||
printf("%-35s%s\n", "NUMA Node:", numa_node);
|
||||
printf("%-35s%"PRIu64"K\n", "Indirection Unit:",
|
||||
(uint64_t)(4*sfx_freespace.map_unit));
|
||||
printf("%-35s%.2f\n", "Lifetime WAF:", write_amp);
|
||||
printf("%-35s%s\n", "Critical Warning(s):", path);
|
||||
}
|
||||
|
||||
close_dev:
|
||||
dev_close(dev);
|
||||
ret:
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ PLUGIN(NAME("sfx", "ScaleFlux vendor specific extensions", NVME_VERSION),
|
|||
ENTRY("get-feature", "Get a feature", sfx_get_feature)
|
||||
ENTRY("dump-evtlog", "dump evtlog into file and parse warning & error log", sfx_dump_evtlog)
|
||||
ENTRY("expand-cap", "expand the last namespace capacity lossless", sfx_expand_cap)
|
||||
ENTRY("status", "Retrieve the ScaleFlux status output, show it", sfx_status)
|
||||
)
|
||||
);
|
||||
|
||||
|
|
189
plugins/scaleflux/sfx-types.h
Normal file
189
plugins/scaleflux/sfx-types.h
Normal file
|
@ -0,0 +1,189 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#define FMT_RED "\x1b[31m"
|
||||
#define FMT_GREEN "\x1b[32m"
|
||||
#define FMT_YELLOW "\x1b[33m"
|
||||
#define FMT_BLUE "\x1b[34m"
|
||||
#define FMT_RESET "\x1b[0m"
|
||||
|
||||
|
||||
enum {
|
||||
SFX_LOG_LATENCY_READ_STATS = 0xc1,
|
||||
SFX_LOG_EXTENDED_HEALTH = 0xc2,
|
||||
SFX_LOG_LATENCY_WRITE_STATS = 0xc3,
|
||||
SFX_LOG_QUAL = 0xc4,
|
||||
SFX_LOG_MISMATCHLBA = 0xc5,
|
||||
SFX_LOG_MEDIA = 0xc6,
|
||||
SFX_LOG_BBT = 0xc7,
|
||||
SFX_LOG_IDENTIFY = 0xcc,
|
||||
SFX_FEAT_ATOMIC = 0x01,
|
||||
SFX_FEAT_UP_P_CAP = 0xac,
|
||||
SFX_LOG_EXTENDED_HEALTH_ALT = 0xd2,
|
||||
SFX_FEAT_CLR_CARD = 0xdc,
|
||||
};
|
||||
|
||||
enum {
|
||||
SFX_CRIT_PWR_FAIL_DATA_LOSS = 0x01,
|
||||
SFX_CRIT_OVER_CAP = 0x02,
|
||||
SFX_CRIT_RW_LOCK = 0x04,
|
||||
};
|
||||
|
||||
enum sfx_nvme_admin_opcode {
|
||||
nvme_admin_query_cap_info = 0xd3,
|
||||
nvme_admin_change_cap = 0xd4,
|
||||
nvme_admin_sfx_set_features = 0xd5,
|
||||
nvme_admin_sfx_get_features = 0xd6,
|
||||
};
|
||||
|
||||
struct sfx_freespace_ctx {
|
||||
__u64 free_space;
|
||||
__u64 phy_cap; /* physical capacity, in unit of sector */
|
||||
__u64 phy_space; /* physical space considering OP, in unit of sector */
|
||||
__u64 user_space; /* user required space, in unit of sector*/
|
||||
__u64 hw_used; /* hw space used in 4K */
|
||||
__u64 app_written; /* app data written in 4K */
|
||||
__u64 out_of_space;
|
||||
__u64 map_unit;
|
||||
__u64 max_user_space;
|
||||
__u64 extendible_user_cap_lba_count;
|
||||
__u64 friendly_change_cap_support;
|
||||
};
|
||||
|
||||
struct nvme_capacity_info {
|
||||
__u64 lba_sec_sz;
|
||||
__u64 phy_sec_sz;
|
||||
__u64 used_space;
|
||||
__u64 free_space;
|
||||
};
|
||||
|
||||
struct __packed nvme_additional_smart_log_item {
|
||||
__u8 key;
|
||||
__u8 _kp[2];
|
||||
__u8 norm;
|
||||
__u8 _np;
|
||||
union __packed {
|
||||
__u8 raw[6];
|
||||
struct __packed wear_level {
|
||||
__le16 min;
|
||||
__le16 max;
|
||||
__le16 avg;
|
||||
} wear_level;
|
||||
struct __packed thermal_throttle {
|
||||
__u8 pct;
|
||||
__u32 count;
|
||||
} thermal_throttle;
|
||||
};
|
||||
__u8 _rp;
|
||||
};
|
||||
|
||||
struct __packed sfx_lat_stats_vanda {
|
||||
__u16 maj;
|
||||
__u16 min;
|
||||
__u32 bucket_1[32]; /* 0~1ms, step 32us */
|
||||
__u32 bucket_2[31]; /* 1~32ms, step 1ms */
|
||||
__u32 bucket_3[31]; /* 32ms~1s, step 32ms */
|
||||
__u32 bucket_4[1]; /* 1s~2s, specifically 1024ms~2047ms */
|
||||
__u32 bucket_5[1]; /* 2s~4s, specifically 2048ms~4095ms */
|
||||
__u32 bucket_6[1]; /* 4s+, specifically 4096ms+ */
|
||||
};
|
||||
|
||||
struct __packed sfx_lat_stats_myrtle {
|
||||
__u16 maj;
|
||||
__u16 min;
|
||||
__u32 bucket_1[64]; /* 0us~63us, step 1us */
|
||||
__u32 bucket_2[64]; /* 63us~127us, step 1us */
|
||||
__u32 bucket_3[64]; /* 127us~255us, step 2us */
|
||||
__u32 bucket_4[64]; /* 255us~510us, step 4us */
|
||||
__u32 bucket_5[64]; /* 510us~1.02ms step 8us */
|
||||
__u32 bucket_6[64]; /* 1.02ms~2.04ms step 16us */
|
||||
__u32 bucket_7[64]; /* 2.04ms~4.08ms step 32us */
|
||||
__u32 bucket_8[64]; /* 4.08ms~8.16ms step 64us */
|
||||
__u32 bucket_9[64]; /* 8.16ms~16.32ms step 128us */
|
||||
__u32 bucket_10[64]; /* 16.32ms~32.64ms step 256us */
|
||||
__u32 bucket_11[64]; /* 32.64ms~65.28ms step 512us */
|
||||
__u32 bucket_12[64]; /* 65.28ms~130.56ms step 1.024ms */
|
||||
__u32 bucket_13[64]; /* 130.56ms~261.12ms step 2.048ms */
|
||||
__u32 bucket_14[64]; /* 261.12ms~522.24ms step 4.096ms */
|
||||
__u32 bucket_15[64]; /* 522.24ms~1.04s step 8.192ms */
|
||||
__u32 bucket_16[64]; /* 1.04s~2.09s step 16.384ms */
|
||||
__u32 bucket_17[64]; /* 2.09s~4.18s step 32.768ms */
|
||||
__u32 bucket_18[64]; /* 4.18s~8.36s step 65.536ms */
|
||||
__u32 bucket_19[64]; /* 8.36s~ step 131.072ms */
|
||||
__u64 average; /* average latency statistics */
|
||||
};
|
||||
|
||||
|
||||
struct __packed sfx_lat_status_ver {
|
||||
__u16 maj;
|
||||
__u16 min;
|
||||
};
|
||||
|
||||
struct sfx_lat_stats {
|
||||
union {
|
||||
struct sfx_lat_status_ver ver;
|
||||
struct sfx_lat_stats_vanda vanda;
|
||||
struct sfx_lat_stats_myrtle myrtle;
|
||||
};
|
||||
};
|
||||
|
||||
struct nvme_additional_smart_log {
|
||||
struct nvme_additional_smart_log_item program_fail_cnt;
|
||||
struct nvme_additional_smart_log_item erase_fail_cnt;
|
||||
struct nvme_additional_smart_log_item wear_leveling_cnt;
|
||||
struct nvme_additional_smart_log_item e2e_err_cnt;
|
||||
struct nvme_additional_smart_log_item crc_err_cnt;
|
||||
struct nvme_additional_smart_log_item timed_workload_media_wear;
|
||||
struct nvme_additional_smart_log_item timed_workload_host_reads;
|
||||
struct nvme_additional_smart_log_item timed_workload_timer;
|
||||
struct nvme_additional_smart_log_item thermal_throttle_status;
|
||||
struct nvme_additional_smart_log_item retry_buffer_overflow_cnt;
|
||||
struct nvme_additional_smart_log_item pll_lock_loss_cnt;
|
||||
struct nvme_additional_smart_log_item nand_bytes_written;
|
||||
struct nvme_additional_smart_log_item host_bytes_written;
|
||||
struct nvme_additional_smart_log_item raid_recover_cnt;
|
||||
/* errors which can be recovered by RAID */
|
||||
struct nvme_additional_smart_log_item prog_timeout_cnt;
|
||||
struct nvme_additional_smart_log_item erase_timeout_cnt;
|
||||
struct nvme_additional_smart_log_item read_timeout_cnt;
|
||||
struct nvme_additional_smart_log_item read_ecc_cnt; /* retry cnt */
|
||||
struct nvme_additional_smart_log_item non_media_crc_err_cnt;
|
||||
struct nvme_additional_smart_log_item compression_path_err_cnt;
|
||||
struct nvme_additional_smart_log_item out_of_space_flag;
|
||||
struct nvme_additional_smart_log_item physical_usage_ratio;
|
||||
struct nvme_additional_smart_log_item grown_bb; /* grown bad block */
|
||||
};
|
||||
|
||||
|
||||
struct __packed extended_health_info_myrtle {
|
||||
__u32 soft_read_recoverable_errs;
|
||||
__u32 flash_die_raid_recoverable_errs;
|
||||
__u32 pcie_rx_correct_errs;
|
||||
__u32 pcie_rx_uncorrect_errs;
|
||||
__u32 data_read_from_flash;
|
||||
__u32 data_write_to_flash;
|
||||
__u32 temp_throttle_info;// bit0: 0--> normal, 1 --> throttled
|
||||
// bit 31:1 --> throttle events count, resets on power cycle
|
||||
__u32 power_consumption;
|
||||
__u32 pf_bbd_read_cnt;
|
||||
__u32 sfx_critical_warning;
|
||||
__u32 raid_recovery_total_count;
|
||||
__u32 rsvd;
|
||||
__u8 opn[32];
|
||||
__u64 total_physical_capability;
|
||||
__u64 free_physical_capability;
|
||||
__u32 physical_usage_ratio;
|
||||
__u32 comp_ratio;
|
||||
__u32 otp_rsa_en;
|
||||
__u32 power_mw_consumption;
|
||||
__u32 io_speed;
|
||||
__u64 max_formatted_capability;
|
||||
__u32 map_unit;
|
||||
__u64 extendible_cap_lbacount;
|
||||
__u32 friendly_changecap_support;
|
||||
__u32 rvd1;
|
||||
__u64 cur_formatted_capability;
|
||||
};
|
||||
|
||||
|
|
@ -1078,6 +1078,7 @@ static int temp_stats(int argc, char **argv, struct command *cmd, struct plugin
|
|||
int index;
|
||||
const char *desc = "Retrieve Seagate Temperature Stats information for the given device ";
|
||||
const char *output_format = "output in binary format";
|
||||
nvme_print_flags_t flags;
|
||||
unsigned int temperature = 0, PcbTemp = 0, SocTemp = 0, scCurrentTemp = 0, scMaxTemp = 0;
|
||||
unsigned long long maxTemperature = 0, MaxSocTemp = 0;
|
||||
struct nvme_dev *dev;
|
||||
|
@ -1100,7 +1101,13 @@ static int temp_stats(int argc, char **argv, struct command *cmd, struct plugin
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (strcmp(cfg.output_format, "json"))
|
||||
err = validate_output_format(cfg.output_format, &flags);
|
||||
if (err < 0) {
|
||||
nvme_show_error("Invalid output format");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (flags & NORMAL)
|
||||
printf("Seagate Temperature Stats Information :\n");
|
||||
/*STEP-1 : Get Current Temperature from SMART */
|
||||
err = nvme_get_log_smart(dev_fd(dev), 0xffffffff, false, &smart_log);
|
||||
|
@ -1111,7 +1118,7 @@ static int temp_stats(int argc, char **argv, struct command *cmd, struct plugin
|
|||
PcbTemp = PcbTemp ? PcbTemp - 273 : 0;
|
||||
SocTemp = le16_to_cpu(smart_log.temp_sensor[1]);
|
||||
SocTemp = SocTemp ? SocTemp - 273 : 0;
|
||||
if (strcmp(cfg.output_format, "json")) {
|
||||
if (flags & NORMAL) {
|
||||
printf("%-20s : %u C\n", "Current Temperature", temperature);
|
||||
printf("%-20s : %u C\n", "Current PCB Temperature", PcbTemp);
|
||||
printf("%-20s : %u C\n", "Current SOC Temperature", SocTemp);
|
||||
|
@ -1126,14 +1133,14 @@ static int temp_stats(int argc, char **argv, struct command *cmd, struct plugin
|
|||
if (ExtdSMARTInfo.vendorData[index].AttributeNumber == VS_ATTR_ID_MAX_LIFE_TEMPERATURE) {
|
||||
maxTemperature = smart_attribute_vs(ExtdSMARTInfo.Version, ExtdSMARTInfo.vendorData[index]);
|
||||
maxTemperature = maxTemperature ? maxTemperature - 273 : 0;
|
||||
if (strcmp(cfg.output_format, "json"))
|
||||
if (flags & NORMAL)
|
||||
printf("%-20s : %d C\n", "Highest Temperature", (unsigned int)maxTemperature);
|
||||
}
|
||||
|
||||
if (ExtdSMARTInfo.vendorData[index].AttributeNumber == VS_ATTR_ID_MAX_SOC_LIFE_TEMPERATURE) {
|
||||
MaxSocTemp = smart_attribute_vs(ExtdSMARTInfo.Version, ExtdSMARTInfo.vendorData[index]);
|
||||
MaxSocTemp = MaxSocTemp ? MaxSocTemp - 273 : 0;
|
||||
if (strcmp(cfg.output_format, "json"))
|
||||
if (flags & NORMAL)
|
||||
printf("%-20s : %d C\n", "Max SOC Temperature", (unsigned int)MaxSocTemp);
|
||||
}
|
||||
}
|
||||
|
@ -1155,7 +1162,7 @@ static int temp_stats(int argc, char **argv, struct command *cmd, struct plugin
|
|||
printf("%-20s : %d C\n", "Super-cap Max Temperature", scMaxTemp);
|
||||
}
|
||||
|
||||
if (!strcmp(cfg.output_format, "json"))
|
||||
if (flags & JSON)
|
||||
json_temp_stats(temperature, PcbTemp, SocTemp, maxTemperature, MaxSocTemp, cf_err, scCurrentTemp, scMaxTemp);
|
||||
|
||||
dev_close(dev);
|
||||
|
@ -1248,6 +1255,7 @@ static int vs_pcie_error_log(int argc, char **argv, struct command *cmd, struct
|
|||
const char *desc = "Retrieve Seagate PCIe error counters for the given device ";
|
||||
const char *output_format = "output in binary format";
|
||||
int err;
|
||||
nvme_print_flags_t flags;
|
||||
struct config {
|
||||
char *output_format;
|
||||
};
|
||||
|
@ -1267,13 +1275,19 @@ static int vs_pcie_error_log(int argc, char **argv, struct command *cmd, struct
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (strcmp(cfg.output_format, "json"))
|
||||
err = validate_output_format(cfg.output_format, &flags);
|
||||
if (err < 0) {
|
||||
nvme_show_error("Invalid output format");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (flags & NORMAL)
|
||||
printf("Seagate PCIe error counters Information :\n");
|
||||
|
||||
err = nvme_get_log_simple(dev_fd(dev), 0xCB,
|
||||
sizeof(pcieErrorLog), &pcieErrorLog);
|
||||
if (!err) {
|
||||
if (strcmp(cfg.output_format, "json"))
|
||||
if (flags & NORMAL)
|
||||
print_vs_pcie_error_log(pcieErrorLog);
|
||||
else
|
||||
json_vs_pcie_error_log(pcieErrorLog);
|
||||
|
@ -1386,6 +1400,7 @@ static int stx_vs_fw_activate_history(int argc, char **argv, struct command *cmd
|
|||
const char *desc = "Retrieve FW Activate History for Seagate device ";
|
||||
const char *output_format = "output in binary format";
|
||||
int err;
|
||||
nvme_print_flags_t flags;
|
||||
struct config {
|
||||
char *output_format;
|
||||
};
|
||||
|
@ -1405,16 +1420,21 @@ static int stx_vs_fw_activate_history(int argc, char **argv, struct command *cmd
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (strcmp(cfg.output_format, "json"))
|
||||
err = validate_output_format(cfg.output_format, &flags);
|
||||
if (err < 0) {
|
||||
nvme_show_error("Invalid output format");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (flags & NORMAL)
|
||||
printf("Seagate FW Activation History Information :\n");
|
||||
|
||||
err = nvme_get_log_simple(dev_fd(dev), 0xC2, sizeof(fwActivHis), &fwActivHis);
|
||||
if (!err) {
|
||||
if (strcmp(cfg.output_format, "json"))
|
||||
if (flags & NORMAL)
|
||||
print_stx_vs_fw_activate_history(fwActivHis);
|
||||
else
|
||||
json_stx_vs_fw_activate_history(fwActivHis);
|
||||
|
||||
} else if (err > 0) {
|
||||
nvme_show_status(err);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,12 @@ OPT_ARGS(no_opts) = {
|
|||
OPT_END()
|
||||
};
|
||||
|
||||
OPT_ARGS(init_opts) = {
|
||||
OPT_FLAG("read-only", 'r', &sedopal_lock_ro,
|
||||
"Set locking range to read-only"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
OPT_ARGS(key_opts) = {
|
||||
OPT_FLAG("ask-key", 'k', &sedopal_ask_key,
|
||||
"prompt for SED authentication key"),
|
||||
|
@ -36,6 +42,21 @@ OPT_ARGS(revert_opts) = {
|
|||
OPT_END()
|
||||
};
|
||||
|
||||
OPT_ARGS(lock_opts) = {
|
||||
OPT_FLAG("read-only", 'r', &sedopal_lock_ro,
|
||||
"Set locking range to read-only"),
|
||||
OPT_FLAG("ask-key", 'k', &sedopal_ask_key,
|
||||
"prompt for SED authentication key"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
OPT_ARGS(discovery_opts) = {
|
||||
OPT_FLAG("verbose", 'v', &sedopal_discovery_verbose,
|
||||
"Print extended discovery information"),
|
||||
OPT_FLAG("udev", 'u', &sedopal_discovery_udev,
|
||||
"Print locking information in form suitable for udev rules"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
/*
|
||||
* Open the NVMe device specified on the command line. It must be the
|
||||
|
@ -67,7 +88,7 @@ static int sed_opal_discover(int argc, char **argv, struct command *cmd,
|
|||
const char *desc = "Query SED device and display locking features";
|
||||
struct nvme_dev *dev;
|
||||
|
||||
err = sed_opal_open_device(&dev, argc, argv, desc, no_opts);
|
||||
err = sed_opal_open_device(&dev, argc, argv, desc, discovery_opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -84,12 +105,12 @@ static int sed_opal_initialize(int argc, char **argv, struct command *cmd,
|
|||
const char *desc = "Initialize a SED device for locking";
|
||||
struct nvme_dev *dev;
|
||||
|
||||
err = sed_opal_open_device(&dev, argc, argv, desc, no_opts);
|
||||
err = sed_opal_open_device(&dev, argc, argv, desc, init_opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = sedopal_cmd_initialize(dev->direct.fd);
|
||||
if (err != 0)
|
||||
if ((err != 0) && (err != -EOPNOTSUPP))
|
||||
fprintf(stderr, "initialize: SED error - %s\n",
|
||||
sedopal_error_to_text(err));
|
||||
|
||||
|
@ -109,7 +130,7 @@ static int sed_opal_revert(int argc, char **argv, struct command *cmd,
|
|||
return err;
|
||||
|
||||
err = sedopal_cmd_revert(dev->direct.fd);
|
||||
if (err != 0)
|
||||
if ((err != 0) && (err != -EOPNOTSUPP))
|
||||
fprintf(stderr, "revert: SED error - %s\n",
|
||||
sedopal_error_to_text(err));
|
||||
|
||||
|
@ -124,12 +145,12 @@ static int sed_opal_lock(int argc, char **argv, struct command *cmd,
|
|||
const char *desc = "Lock a SED device";
|
||||
struct nvme_dev *dev;
|
||||
|
||||
err = sed_opal_open_device(&dev, argc, argv, desc, key_opts);
|
||||
err = sed_opal_open_device(&dev, argc, argv, desc, lock_opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = sedopal_cmd_lock(dev->direct.fd);
|
||||
if (err != 0)
|
||||
if ((err != 0) && (err != -EOPNOTSUPP))
|
||||
fprintf(stderr, "lock: SED error - %s\n",
|
||||
sedopal_error_to_text(err));
|
||||
|
||||
|
@ -144,12 +165,12 @@ static int sed_opal_unlock(int argc, char **argv, struct command *cmd,
|
|||
const char *desc = "Unlock a SED device";
|
||||
struct nvme_dev *dev;
|
||||
|
||||
err = sed_opal_open_device(&dev, argc, argv, desc, key_opts);
|
||||
err = sed_opal_open_device(&dev, argc, argv, desc, lock_opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = sedopal_cmd_unlock(dev->direct.fd);
|
||||
if (err != 0)
|
||||
if ((err != 0) && (err != -EOPNOTSUPP))
|
||||
fprintf(stderr, "unlock: SED error - %s\n",
|
||||
sedopal_error_to_text(err));
|
||||
|
||||
|
|
|
@ -34,6 +34,46 @@ bool sedopal_destructive_revert;
|
|||
*/
|
||||
bool sedopal_psid_revert;
|
||||
|
||||
/*
|
||||
* Lock read-only
|
||||
*/
|
||||
bool sedopal_lock_ro;
|
||||
|
||||
/*
|
||||
* Verbose discovery
|
||||
*/
|
||||
bool sedopal_discovery_verbose;
|
||||
|
||||
/*
|
||||
* discovery with udev output
|
||||
*/
|
||||
bool sedopal_discovery_udev;
|
||||
|
||||
/*
|
||||
* level 0 discovery buffer
|
||||
*/
|
||||
char level0_discovery_buf[4096];
|
||||
|
||||
struct sedopal_feature_parser {
|
||||
uint32_t features;
|
||||
void *tper_desc;
|
||||
void *locking_desc;
|
||||
void *geometry_reporting_desc;
|
||||
void *opalv1_desc;
|
||||
void *single_user_mode_desc;
|
||||
void *datastore_desc;
|
||||
void *opalv2_desc;
|
||||
void *opalite_desc;
|
||||
void *pyrite_v1_desc;
|
||||
void *pyrite_v2_desc;
|
||||
void *ruby_desc;
|
||||
void *locking_lba_desc;
|
||||
void *block_sid_auth_desc;
|
||||
void *config_ns_desc;
|
||||
void *data_removal_desc;
|
||||
void *ns_geometry_desc;
|
||||
};
|
||||
|
||||
/*
|
||||
* Map method status codes to error text
|
||||
*/
|
||||
|
@ -170,6 +210,15 @@ int sedopal_cmd_initialize(int fd)
|
|||
struct opal_lr_act lr_act = {};
|
||||
struct opal_user_lr_setup lr_setup = {};
|
||||
struct opal_new_pw new_pw = {};
|
||||
uint8_t locking_state;
|
||||
|
||||
locking_state = sedopal_locking_state(fd);
|
||||
|
||||
if (locking_state & OPAL_FEATURE_LOCKING_ENABLED) {
|
||||
fprintf(stderr,
|
||||
"Error: cannot initialize an initialized drive\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
sedopal_ask_key = true;
|
||||
sedopal_ask_new_key = true;
|
||||
|
@ -206,7 +255,8 @@ int sedopal_cmd_initialize(int fd)
|
|||
lr_setup.range_start = 0;
|
||||
lr_setup.range_length = 0;
|
||||
lr_setup.RLE = true;
|
||||
lr_setup.WLE = true;
|
||||
if (!sedopal_lock_ro)
|
||||
lr_setup.WLE = true;
|
||||
|
||||
lr_setup.session.opal_key = key;
|
||||
lr_setup.session.sum = 0;
|
||||
|
@ -242,8 +292,12 @@ int sedopal_cmd_initialize(int fd)
|
|||
*/
|
||||
int sedopal_cmd_lock(int fd)
|
||||
{
|
||||
int lock_state = OPAL_LK;
|
||||
|
||||
return sedopal_lock_unlock(fd, OPAL_LK);
|
||||
if (sedopal_lock_ro)
|
||||
lock_state = OPAL_RO;
|
||||
|
||||
return sedopal_lock_unlock(fd, lock_state);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -252,8 +306,12 @@ int sedopal_cmd_lock(int fd)
|
|||
int sedopal_cmd_unlock(int fd)
|
||||
{
|
||||
int rc;
|
||||
int lock_state = OPAL_RW;
|
||||
|
||||
rc = sedopal_lock_unlock(fd, OPAL_RW);
|
||||
if (sedopal_lock_ro)
|
||||
lock_state = OPAL_RO;
|
||||
|
||||
rc = sedopal_lock_unlock(fd, lock_state);
|
||||
|
||||
/*
|
||||
* If the unlock was successful, force a re-read of the
|
||||
|
@ -275,6 +333,15 @@ int sedopal_lock_unlock(int fd, int lock_state)
|
|||
{
|
||||
int rc;
|
||||
struct opal_lock_unlock opal_lu = {};
|
||||
uint8_t locking_state;
|
||||
|
||||
locking_state = sedopal_locking_state(fd);
|
||||
|
||||
if (!(locking_state & OPAL_FEATURE_LOCKING_ENABLED)) {
|
||||
fprintf(stderr,
|
||||
"Error: cannot lock/unlock an uninitialized drive\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
rc = sedopal_set_key(&opal_lu.session.opal_key);
|
||||
if (rc != 0)
|
||||
|
@ -389,6 +456,21 @@ int sedopal_cmd_revert(int fd)
|
|||
} else {
|
||||
#ifdef IOC_OPAL_REVERT_LSP
|
||||
struct opal_revert_lsp revert_lsp;
|
||||
uint8_t locking_state;
|
||||
|
||||
locking_state = sedopal_locking_state(fd);
|
||||
|
||||
if (!(locking_state & OPAL_FEATURE_LOCKING_ENABLED)) {
|
||||
fprintf(stderr,
|
||||
"Error: can't revert an uninitialized drive\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (locking_state & OPAL_FEATURE_LOCKED) {
|
||||
fprintf(stderr,
|
||||
"Error: cannot revert drive while locked\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
rc = sedopal_set_key(&revert_lsp.key);
|
||||
if (rc != 0)
|
||||
|
@ -470,36 +552,462 @@ int sedopal_cmd_password(int fd)
|
|||
/*
|
||||
* Print the state of locking features.
|
||||
*/
|
||||
void sedopal_print_locking_features(uint8_t features)
|
||||
void sedopal_print_locking_features(void *data)
|
||||
{
|
||||
printf("Locking Features:\n");
|
||||
printf("\tLocking Supported: %s\n",
|
||||
(features & OPAL_FEATURE_LOCKING_SUPPORTED) ? "Yes" : "No");
|
||||
printf("\tLocking Feature Enabled: %s\n",
|
||||
(features & OPAL_FEATURE_LOCKING_ENABLED) ? "Yes" : "No");
|
||||
printf("\tLocked: %s\n",
|
||||
(features & OPAL_FEATURE_LOCKED) ? "Yes" : "No");
|
||||
struct locking_desc *ld = (struct locking_desc *)data;
|
||||
uint8_t features = ld->features;
|
||||
|
||||
if (!sedopal_discovery_udev) {
|
||||
printf("Locking Features:\n");
|
||||
printf("\tLocking Supported : %s\n",
|
||||
(features & OPAL_FEATURE_LOCKING_SUPPORTED) ?
|
||||
"yes" : "no");
|
||||
printf("\tLocking Feature Enabled : %s\n",
|
||||
(features & OPAL_FEATURE_LOCKING_ENABLED) ?
|
||||
"yes" : "no");
|
||||
printf("\tLocked : %s\n",
|
||||
(features & OPAL_FEATURE_LOCKED) ? "yes" : "no");
|
||||
printf("\tMedia Encryption : %s\n",
|
||||
(features & OPAL_FEATURE_MEDIA_ENCRYPT) ? "yes" : "no");
|
||||
printf("\tMBR Enabled : %s\n",
|
||||
(features & OPAL_FEATURE_MBR_ENABLED) ? "yes" : "no");
|
||||
printf("\tMBR Done : %s\n",
|
||||
(features & OPAL_FEATURE_MBR_DONE) ? "yes" : "no");
|
||||
} else {
|
||||
printf("DEV_SED_LOCKED=%s\n",
|
||||
(features & OPAL_FEATURE_LOCKING_ENABLED) ?
|
||||
"ENABLED" : "DISABLED");
|
||||
printf("DEV_SED_LOCKING=%s\n",
|
||||
(features & OPAL_FEATURE_LOCKING_ENABLED) ?
|
||||
"ENABLED" : "DISABLED");
|
||||
printf("DEV_SED_LOCKING_SUPP=%s\n",
|
||||
(features & OPAL_FEATURE_LOCKING_SUPPORTED) ?
|
||||
"ENABLED" : "DISABLED");
|
||||
printf("DEV_SED_LOCKING_LOCKED=%s\n",
|
||||
(features & OPAL_FEATURE_LOCKED) ?
|
||||
"ENABLED" : "DISABLED");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Query a drive to determine if it's SED Opal capable and
|
||||
* it's current locking status.
|
||||
* Print the TPer feature.
|
||||
*/
|
||||
int sedopal_cmd_discover(int fd)
|
||||
void sedopal_print_tper(void *data)
|
||||
{
|
||||
struct tper_desc *td = (struct tper_desc *)data;
|
||||
|
||||
printf("\nSED TPER:\n");
|
||||
printf("\tSync Supported : %s\n",
|
||||
(td->feature & TPER_FEATURE_SYNC) ? "yes" : "no");
|
||||
printf("\tAsync Supported : %s\n",
|
||||
(td->feature & TPER_FEATURE_ASYNC) ? "yes" : "no");
|
||||
printf("\tACK/NAK Supported : %s\n",
|
||||
(td->feature & TPER_FEATURE_ACKNAK) ? "yes" : "no");
|
||||
printf("\tBuffer Management Supported : %s\n",
|
||||
(td->feature & TPER_FEATURE_BUF_MGMT) ? "yes" : "no");
|
||||
printf("\tStreaming Supported : %s\n",
|
||||
(td->feature & TPER_FEATURE_STREAMING) ? "yes" : "no");
|
||||
printf("\tComID Management Supported : %s\n",
|
||||
(td->feature & TPER_FEATURE_COMID_MGMT) ? "yes" : "no");
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the Geometry feature.
|
||||
*/
|
||||
void sedopal_print_geometry(void *data)
|
||||
{
|
||||
struct geometry_reporting_desc *gd;
|
||||
|
||||
gd = (struct geometry_reporting_desc *)data;
|
||||
|
||||
printf("\nSED Geometry:\n");
|
||||
printf("\tAlignment Required : %s\n",
|
||||
(gd->align & GEOMETRY_ALIGNMENT_REQUIRED) ? "yes" : "no");
|
||||
printf("\tLogical Block Size : %u\n",
|
||||
be32toh(gd->logical_block_size));
|
||||
printf("\tAlignment Granularity : %llx\n",
|
||||
(unsigned long long)(be64toh(gd->alignment_granularity)));
|
||||
printf("\tLowest Aligned LBA : %llx\n",
|
||||
(unsigned long long)(be64toh(gd->lowest_aligned_lba)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the opal v1 feature.
|
||||
*/
|
||||
void sedopal_print_opal_v1(void *data)
|
||||
{
|
||||
struct opalv1_desc *v1d = (struct opalv1_desc *)data;
|
||||
|
||||
printf("\nSED OPAL V1.0:\n");
|
||||
printf("\tBase Comid : %d\n",
|
||||
be16toh(v1d->base_comid));
|
||||
printf("\tNumber of Comids : %d\n",
|
||||
be16toh(v1d->num_comids));
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the opal v2 feature.
|
||||
*/
|
||||
void sedopal_print_opal_v2(void *data)
|
||||
{
|
||||
struct opalv2_desc *v2d = (struct opalv2_desc *)data;
|
||||
|
||||
printf("\nSED OPAL V2.0:\n");
|
||||
printf("\tRange Crossing : %d\n",
|
||||
!(v2d->flags & OPAL_V2_RANGE_CROSSING));
|
||||
printf("\tBase Comid : %d\n",
|
||||
be16toh(v2d->base_comid));
|
||||
printf("\tNumber of Comids : %d\n",
|
||||
be16toh(v2d->num_comids));
|
||||
printf("\tNumber of Admin Authorities : %d\n",
|
||||
be16toh(v2d->num_locking_sp_admin_auth));
|
||||
printf("\tNumber of User Authorities : %d\n",
|
||||
be16toh(v2d->num_locking_sp_user_auth));
|
||||
printf("\tInit pin : %d\n",
|
||||
v2d->initial_cpin_sid_ind);
|
||||
printf("\tRevert pin : %d\n",
|
||||
v2d->initial_cpin_sid_revert);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the ruby feature.
|
||||
*/
|
||||
void sedopal_print_ruby(void *data)
|
||||
{
|
||||
struct ruby_desc *rd = (struct ruby_desc *)data;
|
||||
|
||||
printf("\nRuby:\n");
|
||||
printf("\tRange Crossing : %d\n",
|
||||
!(rd->flags & RUBY_RANGE_CROSSING));
|
||||
printf("\tBase Comid : %d\n",
|
||||
be16toh(rd->base_comid));
|
||||
printf("\tNumber of Comids : %d\n",
|
||||
be16toh(rd->num_comids));
|
||||
printf("\tNumber of Admin Authorities : %d\n",
|
||||
be16toh(rd->num_locking_sp_admin_auth));
|
||||
printf("\tNumber of User Authorities : %d\n",
|
||||
be16toh(rd->num_locking_sp_user_auth));
|
||||
printf("\tInit pin : %d\n",
|
||||
rd->initial_cpin_sid_ind);
|
||||
printf("\tRevert pin : %d\n",
|
||||
rd->initial_cpin_sid_revert);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the opalite feature.
|
||||
*/
|
||||
void sedopal_print_opalite(void *data)
|
||||
{
|
||||
struct opalite_desc *old = (struct opalite_desc *)data;
|
||||
|
||||
printf("\nSED Opalite:\n");
|
||||
printf("\tBase Comid : %d\n",
|
||||
be16toh(old->base_comid));
|
||||
printf("\tNumber of Comids : %d\n",
|
||||
be16toh(old->num_comids));
|
||||
printf("\tInit pin : %d\n",
|
||||
old->initial_cpin_sid_ind);
|
||||
printf("\tRevert pin : %d\n",
|
||||
old->initial_cpin_sid_revert);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the pyrite v1 feature.
|
||||
*/
|
||||
void sedopal_print_pyrite_v1(void *data)
|
||||
{
|
||||
struct pyrite_v1_desc *p1d = (struct pyrite_v1_desc *)data;
|
||||
|
||||
printf("\nPyrite V1:\n");
|
||||
printf("\tBase Comid : %d\n",
|
||||
be16toh(p1d->base_comid));
|
||||
printf("\tNumber of Comids : %d\n",
|
||||
be16toh(p1d->num_comids));
|
||||
printf("\tInit pin : %d\n",
|
||||
p1d->initial_cpin_sid_ind);
|
||||
printf("\tRevert pin : %d\n",
|
||||
p1d->initial_cpin_sid_revert);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the pyrite v2 feature.
|
||||
*/
|
||||
void sedopal_print_pyrite_v2(void *data)
|
||||
{
|
||||
struct pyrite_v2_desc *p2d = (struct pyrite_v2_desc *)data;
|
||||
|
||||
printf("\nPyrite V2:\n");
|
||||
printf("\tBase Comid : %d\n",
|
||||
be16toh(p2d->base_comid));
|
||||
printf("\tNumber of Comids : %d\n",
|
||||
be16toh(p2d->num_comids));
|
||||
printf("\tInit pin : %d\n",
|
||||
p2d->initial_cpin_sid_ind);
|
||||
printf("\tRevert pin : %d\n",
|
||||
p2d->initial_cpin_sid_revert);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the single user mode feature.
|
||||
*/
|
||||
void sedopal_print_sum(void *data)
|
||||
{
|
||||
struct single_user_mode_desc *sumd;
|
||||
|
||||
sumd = (struct single_user_mode_desc *)data;
|
||||
|
||||
printf("\nSingle User Mode (SUM):\n");
|
||||
printf("\tNumber of Locking Objects : %u\n",
|
||||
be32toh(sumd->num_locking_objects));
|
||||
printf("\tAny Locking Objects in SUM? : %s\n",
|
||||
(sumd->flags & SUM_FEATURE_ANY) ? "yes" : "no");
|
||||
printf("\tAll Locking Objects in SUM? : %s\n",
|
||||
(sumd->flags & SUM_FEATURE_ALL) ? "yes" : "no");
|
||||
printf("\tUser Authority of Objects : %s\n",
|
||||
(sumd->flags & SUM_FEATURE_POLICY) ? "yes" : "no");
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the data store table feature.
|
||||
*/
|
||||
void sedopal_print_datastore(void *data)
|
||||
{
|
||||
struct datastore_desc *dsd = (struct datastore_desc *)data;
|
||||
|
||||
printf("\nData Store Table:\n");
|
||||
printf("\tNumber of Tables Supported : %u\n",
|
||||
be16toh(dsd->max_tables));
|
||||
printf("\tMax Size of Tables : %u\n",
|
||||
be32toh(dsd->max_table_size));
|
||||
printf("\tTable Size Alignment : %u\n",
|
||||
be32toh(dsd->table_alignment));
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the block SID authentication feature.
|
||||
*/
|
||||
void sedopal_print_sid_auth(void *data)
|
||||
{
|
||||
struct block_sid_auth_desc *sid_auth_d;
|
||||
|
||||
sid_auth_d = (struct block_sid_auth_desc *)data;
|
||||
|
||||
printf("\nSED Block SID Authentication:\n");
|
||||
printf("\tSID value equal MSID : %s\n",
|
||||
(sid_auth_d->states & BLOCK_SID_VALUE_STATE) ? "yes" : "no");
|
||||
printf("\tSID auth blocked : %s\n",
|
||||
(sid_auth_d->states & BLOCK_SID_BLOCKED_STATE) ? "yes" : "no");
|
||||
printf("\tHW reset selected : %s\n",
|
||||
(sid_auth_d->hw_reset & BLOCK_SID_HW_RESET) ? "yes" : "no");
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the Locking LBA Ranges Control feature
|
||||
*/
|
||||
void sedopal_print_locking_lba(void *data)
|
||||
{
|
||||
/*
|
||||
* There currently isn't any definition of the level 0 content
|
||||
* of this feature, so defer any printing.
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the configurable namespace locking feature.
|
||||
*/
|
||||
void sedopal_print_config_ns(void *data)
|
||||
{
|
||||
struct config_ns_desc *nsd = (struct config_ns_desc *)data;
|
||||
|
||||
printf("\nSED Configurable Namespace Locking:\n");
|
||||
printf("\tNon-global Locking Support : %s\n",
|
||||
(nsd->flags & CONFIG_NS_RANGE_C) ? "yes" : "no");
|
||||
printf("\tNon-global Lock objects exist : %s\n",
|
||||
(nsd->flags & CONFIG_NS_RANGE_P) ? "yes" : "no");
|
||||
printf("\tMaximum Key Count : %d\n",
|
||||
be32toh(nsd->max_key_count));
|
||||
printf("\tUnused Key Count : %d\n",
|
||||
be32toh(nsd->unused_key_count));
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the data removal mechanism feature.
|
||||
*/
|
||||
void sedopal_print_data_removal(void *data)
|
||||
{
|
||||
struct data_removal_desc *drd = (struct data_removal_desc *)data;
|
||||
|
||||
printf("\nSED Data Removal Mechanism:\n");
|
||||
printf("\tRemoval Operation Processing : %s\n",
|
||||
(drd->flags & DATA_REMOVAL_OPER_PROCESSING) ? "yes" : "no");
|
||||
printf("\tRemoval Operation Interrupted : %s\n",
|
||||
(drd->flags & DATA_REMOVAL_OPER_INTERRUPTED) ? "yes" : "no");
|
||||
printf("\tData Removal Mechanism : %x\n",
|
||||
drd->removal_mechanism);
|
||||
printf("\tData Removal Format : %x\n",
|
||||
drd->format);
|
||||
printf("\tData Removal Time (Bit 0) : %x\n",
|
||||
be16toh(drd->time_mechanism_bit0));
|
||||
printf("\tData Removal Time (Bit 1) : %x\n",
|
||||
be16toh(drd->time_mechanism_bit1));
|
||||
printf("\tData Removal Time (Bit 2) : %x\n",
|
||||
be16toh(drd->time_mechanism_bit2));
|
||||
printf("\tData Removal Time (Bit 5) : %x\n",
|
||||
be16toh(drd->time_mechanism_bit5));
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the namespace geometry feature.
|
||||
*/
|
||||
void sedopal_print_ns_geometry(void *data)
|
||||
{
|
||||
struct ns_geometry_desc *nsgd = (struct ns_geometry_desc *)data;
|
||||
|
||||
printf("\nSED Namespace Geometry:\n");
|
||||
printf("\tAlignment Required : %s\n",
|
||||
(nsgd->align & NS_GEOMETRY_ALIGNMENT_REQUIRED) ? "yes" : "no");
|
||||
printf("\tLogical Block Size : %x\n",
|
||||
be32toh(nsgd->logical_block_size));
|
||||
printf("\tAlignment Granularity : %llx\n",
|
||||
(unsigned long long)(be64toh(nsgd->alignment_granularity)));
|
||||
printf("\tLowest Aligned LBA : %llx\n",
|
||||
(unsigned long long)(be64toh(nsgd->lowest_aligned_lba)));
|
||||
}
|
||||
|
||||
void sedopal_parse_features(struct level_0_discovery_features *feat,
|
||||
struct sedopal_feature_parser *sfp)
|
||||
{
|
||||
uint16_t code = be16toh(feat->code);
|
||||
|
||||
switch (code) {
|
||||
case OPAL_FEATURE_CODE_LOCKING:
|
||||
sfp->features |= OPAL_FEATURE_LOCKING;
|
||||
sfp->locking_desc = (void *)(feat + 1);
|
||||
break;
|
||||
case OPAL_FEATURE_CODE_OPALV1:
|
||||
sfp->features |= OPAL_FEATURE_OPALV1;
|
||||
sfp->opalv1_desc = (void *)(feat + 1);
|
||||
break;
|
||||
case OPAL_FEATURE_CODE_OPALV2:
|
||||
sfp->features |= OPAL_FEATURE_OPALV2;
|
||||
sfp->opalv2_desc = (void *)(feat + 1);
|
||||
break;
|
||||
case OPAL_FEATURE_CODE_TPER:
|
||||
sfp->features |= OPAL_FEATURE_TPER;
|
||||
sfp->tper_desc = (void *)(feat + 1);
|
||||
break;
|
||||
case OPAL_FEATURE_CODE_GEOMETRY:
|
||||
sfp->features |= OPAL_FEATURE_GEOMETRY;
|
||||
sfp->geometry_reporting_desc = (void *)(feat + 1);
|
||||
break;
|
||||
case OPAL_FEATURE_CODE_SINGLE_USER_MODE:
|
||||
sfp->features |= OPAL_FEATURE_SINGLE_USER_MODE;
|
||||
sfp->single_user_mode_desc = (void *)(feat + 1);
|
||||
break;
|
||||
case OPAL_FEATURE_CODE_DATA_STORE:
|
||||
sfp->features |= OPAL_FEATURE_DATA_STORE;
|
||||
sfp->datastore_desc = (void *)(feat + 1);
|
||||
break;
|
||||
case OPAL_FEATURE_CODE_OPALITE:
|
||||
sfp->features |= OPAL_FEATURE_OPALITE;
|
||||
sfp->opalite_desc = (void *)(feat + 1);
|
||||
break;
|
||||
case OPAL_FEATURE_CODE_PYRITE_V1:
|
||||
sfp->features |= OPAL_FEATURE_PYRITE_V1;
|
||||
sfp->pyrite_v1_desc = (void *)(feat + 1);
|
||||
break;
|
||||
case OPAL_FEATURE_CODE_PYRITE_V2:
|
||||
sfp->features |= OPAL_FEATURE_PYRITE_V2;
|
||||
sfp->pyrite_v2_desc = (void *)(feat + 1);
|
||||
break;
|
||||
case OPAL_FEATURE_CODE_RUBY:
|
||||
sfp->features |= OPAL_FEATURE_RUBY;
|
||||
sfp->ruby_desc = (void *)(feat + 1);
|
||||
break;
|
||||
case OPAL_FEATURE_CODE_LOCKING_LBA:
|
||||
sfp->features |= OPAL_FEATURE_LOCKING_LBA;
|
||||
sfp->locking_lba_desc = (void *)(feat + 1);
|
||||
break;
|
||||
case OPAL_FEATURE_CODE_BLOCK_SID_AUTH:
|
||||
sfp->features |= OPAL_FEATURE_BLOCK_SID_AUTH;
|
||||
sfp->block_sid_auth_desc = (void *)(feat + 1);
|
||||
break;
|
||||
case OPAL_FEATURE_CODE_CONFIG_NS_LOCKING:
|
||||
sfp->features |= OPAL_FEATURE_CONFIG_NS_LOCKING;
|
||||
sfp->config_ns_desc = (void *)(feat + 1);
|
||||
break;
|
||||
case OPAL_FEATURE_CODE_DATA_REMOVAL:
|
||||
sfp->features |= OPAL_FEATURE_DATA_REMOVAL;
|
||||
sfp->data_removal_desc = (void *)(feat + 1);
|
||||
break;
|
||||
case OPAL_FEATURE_CODE_NS_GEOMETRY:
|
||||
sfp->features |= OPAL_FEATURE_NS_GEOMETRY;
|
||||
sfp->ns_geometry_desc = (void *)(feat + 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void sedopal_print_features(struct sedopal_feature_parser *sfp)
|
||||
{
|
||||
if (sfp->features & OPAL_FEATURE_OPALV1)
|
||||
sedopal_print_opal_v1(sfp->opalv1_desc);
|
||||
|
||||
if (sfp->features & OPAL_FEATURE_OPALV2)
|
||||
sedopal_print_opal_v2(sfp->opalv2_desc);
|
||||
|
||||
if (sfp->features & OPAL_FEATURE_TPER)
|
||||
sedopal_print_tper(sfp->tper_desc);
|
||||
|
||||
if (sfp->features & OPAL_FEATURE_GEOMETRY)
|
||||
sedopal_print_geometry(sfp->geometry_reporting_desc);
|
||||
|
||||
if (sfp->features & OPAL_FEATURE_OPALITE)
|
||||
sedopal_print_opalite(sfp->opalite_desc);
|
||||
|
||||
if (sfp->features & OPAL_FEATURE_SINGLE_USER_MODE)
|
||||
sedopal_print_sum(sfp->single_user_mode_desc);
|
||||
|
||||
if (sfp->features & OPAL_FEATURE_DATA_STORE)
|
||||
sedopal_print_datastore(sfp->datastore_desc);
|
||||
|
||||
if (sfp->features & OPAL_FEATURE_BLOCK_SID_AUTH)
|
||||
sedopal_print_sid_auth(sfp->block_sid_auth_desc);
|
||||
|
||||
if (sfp->features & OPAL_FEATURE_RUBY)
|
||||
sedopal_print_ruby(sfp->ruby_desc);
|
||||
|
||||
if (sfp->features & OPAL_FEATURE_PYRITE_V1)
|
||||
sedopal_print_pyrite_v1(sfp->pyrite_v1_desc);
|
||||
|
||||
if (sfp->features & OPAL_FEATURE_PYRITE_V2)
|
||||
sedopal_print_pyrite_v2(sfp->pyrite_v2_desc);
|
||||
|
||||
if (sfp->features & OPAL_FEATURE_LOCKING_LBA)
|
||||
sedopal_print_locking_lba(sfp->locking_lba_desc);
|
||||
|
||||
if (sfp->features & OPAL_FEATURE_CONFIG_NS_LOCKING)
|
||||
sedopal_print_config_ns(sfp->config_ns_desc);
|
||||
|
||||
if (sfp->features & OPAL_FEATURE_NS_GEOMETRY)
|
||||
sedopal_print_ns_geometry(sfp->ns_geometry_desc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Query a drive to retrieve it's level 0 features.
|
||||
*/
|
||||
int sedopal_discover_device(int fd, struct level_0_discovery_features **feat,
|
||||
struct level_0_discovery_features **feat_end)
|
||||
{
|
||||
#ifdef IOC_OPAL_DISCOVERY
|
||||
int rc, feat_length;
|
||||
bool sedopal_locking_supported = false;
|
||||
int rc;
|
||||
struct opal_discovery discover;
|
||||
struct level_0_discovery_header *dh;
|
||||
struct level_0_discovery_features *feat;
|
||||
struct level_0_discovery_features *feat_end;
|
||||
uint16_t code;
|
||||
uint8_t locking_flags = 0;
|
||||
char buf[4096];
|
||||
|
||||
discover.data = (__u64)buf;
|
||||
discover.size = sizeof(buf);
|
||||
discover.data = (uintptr_t)level0_discovery_buf;
|
||||
discover.size = sizeof(level0_discovery_buf);
|
||||
|
||||
rc = ioctl(fd, IOC_OPAL_DISCOVERY, &discover);
|
||||
if (rc < 0) {
|
||||
|
@ -513,41 +1021,89 @@ int sedopal_cmd_discover(int fd)
|
|||
*
|
||||
* TCG Opal Specification v2.0.2 section 3.1.1
|
||||
*/
|
||||
dh = (struct level_0_discovery_header *)buf;
|
||||
feat = (struct level_0_discovery_features *)(dh + 1);
|
||||
feat_end = (struct level_0_discovery_features *)
|
||||
(buf + be32toh(dh->parameter_length));
|
||||
dh = (struct level_0_discovery_header *)level0_discovery_buf;
|
||||
*feat = (struct level_0_discovery_features *)(dh + 1);
|
||||
*feat_end = (struct level_0_discovery_features *)
|
||||
(level0_discovery_buf + be32toh(dh->parameter_length));
|
||||
|
||||
/*
|
||||
* iterate through all the features that were returned
|
||||
*/
|
||||
while (feat < feat_end) {
|
||||
code = be16toh(feat->code);
|
||||
feat_length = feat->length + 4 /* hdr */;
|
||||
switch (code) {
|
||||
case OPAL_FEATURE_CODE_LOCKING:
|
||||
locking_flags = feat->feature;
|
||||
break;
|
||||
case OPAL_FEATURE_CODE_OPALV2:
|
||||
sedopal_locking_supported = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
feat = (struct level_0_discovery_features *)((char *)feat + feat_length);
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
if (!sedopal_locking_supported) {
|
||||
fprintf(stderr, "Error: device does not support SED Opal\n");
|
||||
rc = -1;
|
||||
} else
|
||||
sedopal_print_locking_features(locking_flags);
|
||||
|
||||
return rc;
|
||||
return 0
|
||||
;
|
||||
#else /* IOC_OPAL_DISCOVERY */
|
||||
fprintf(stderr, "ERROR : NVMe device discovery is not supported\n");
|
||||
return -EOPNOTSUPP;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Query a drive to determine if it's SED Opal capable and
|
||||
* it's current locking status.
|
||||
*/
|
||||
int sedopal_cmd_discover(int fd)
|
||||
{
|
||||
int rc, feat_length;
|
||||
struct level_0_discovery_features *feat;
|
||||
struct level_0_discovery_features *feat_end;
|
||||
struct sedopal_feature_parser sfp = {};
|
||||
|
||||
rc = sedopal_discover_device(fd, &feat, &feat_end);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* iterate through all the features that were returned
|
||||
*/
|
||||
while (feat < feat_end) {
|
||||
sedopal_parse_features(feat, &sfp);
|
||||
feat_length = feat->length + 4 /* hdr */;
|
||||
feat = (struct level_0_discovery_features *)
|
||||
((char *)feat + feat_length);
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
if (!(sfp.features & OPAL_SED_LOCKING_SUPPORT)) {
|
||||
fprintf(stderr, "Error: device does not support SED Opal\n");
|
||||
rc = -1;
|
||||
} else
|
||||
sedopal_print_locking_features(sfp.locking_desc);
|
||||
|
||||
if (!sedopal_discovery_verbose)
|
||||
return rc;
|
||||
|
||||
sedopal_print_features(&sfp);
|
||||
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Query a drive to determine its locking state
|
||||
*/
|
||||
int sedopal_locking_state(int fd)
|
||||
{
|
||||
int rc, feat_length;
|
||||
struct level_0_discovery_features *feat;
|
||||
struct level_0_discovery_features *feat_end;
|
||||
|
||||
rc = sedopal_discover_device(fd, &feat, &feat_end);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* iterate through all the features that were returned
|
||||
*/
|
||||
while (feat < feat_end) {
|
||||
uint16_t code = be16toh(feat->code);
|
||||
|
||||
if (code == OPAL_FEATURE_CODE_LOCKING) {
|
||||
struct locking_desc *ld = (struct locking_desc *) (feat + 1);
|
||||
|
||||
return ld->features;
|
||||
}
|
||||
|
||||
feat_length = feat->length + 4 /* hdr */;
|
||||
feat = (struct level_0_discovery_features *)
|
||||
((char *)feat + feat_length);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,9 @@ extern bool sedopal_ask_key;
|
|||
extern bool sedopal_ask_new_key;
|
||||
extern bool sedopal_destructive_revert;
|
||||
extern bool sedopal_psid_revert;
|
||||
extern bool sedopal_lock_ro;
|
||||
extern bool sedopal_discovery_verbose;
|
||||
extern bool sedopal_discovery_udev;
|
||||
|
||||
/*
|
||||
* Sub-commands supported by the sedopal command
|
||||
|
@ -51,5 +54,6 @@ int sedopal_cmd_discover(int fd);
|
|||
int sedopal_open_nvme_device(char *device);
|
||||
int sedopal_lock_unlock(int fd, int lock_state);
|
||||
const char *sedopal_error_to_text(int code);
|
||||
int sedopal_locking_state(int fd);
|
||||
|
||||
#endif /* _SED_OPAL_CMD_H */
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#ifndef _SED_OPAL_SPEC_H
|
||||
#define _SED_OPAL_SPEC_H
|
||||
|
||||
#include <common.h>
|
||||
|
||||
/*
|
||||
* TCP Storage Architecture Core Specification Version 2.01
|
||||
* section 5.1.5 Method Status Codes
|
||||
|
@ -31,6 +33,31 @@ enum sed_status_codes {
|
|||
SED_STATUS_NO_METHOD_STATUS = 0x89,
|
||||
};
|
||||
|
||||
/*
|
||||
* level 0 feature flags
|
||||
*/
|
||||
#define OPAL_FEATURE_TPER 0x0001
|
||||
#define OPAL_FEATURE_LOCKING 0x0002
|
||||
#define OPAL_FEATURE_GEOMETRY 0x0004
|
||||
#define OPAL_FEATURE_OPALV1 0x0008
|
||||
#define OPAL_FEATURE_SINGLE_USER_MODE 0x0010
|
||||
#define OPAL_FEATURE_DATA_STORE 0x0020
|
||||
#define OPAL_FEATURE_OPALV2 0x0040
|
||||
#define OPAL_FEATURE_OPALITE 0x0080
|
||||
#define OPAL_FEATURE_PYRITE_V1 0x0100
|
||||
#define OPAL_FEATURE_PYRITE_V2 0x0200
|
||||
#define OPAL_FEATURE_RUBY 0x0400
|
||||
#define OPAL_FEATURE_LOCKING_LBA 0x0800
|
||||
#define OPAL_FEATURE_BLOCK_SID_AUTH 0x1000
|
||||
#define OPAL_FEATURE_CONFIG_NS_LOCKING 0x2000
|
||||
#define OPAL_FEATURE_DATA_REMOVAL 0x4000
|
||||
#define OPAL_FEATURE_NS_GEOMETRY 0x8000
|
||||
|
||||
#define OPAL_SED_LOCKING_SUPPORT \
|
||||
(OPAL_FEATURE_OPALV1 | OPAL_FEATURE_OPALV2 | \
|
||||
OPAL_FEATURE_RUBY | OPAL_FEATURE_PYRITE_V1 | \
|
||||
OPAL_FEATURE_PYRITE_V2 | OPAL_FEATURE_LOCKING)
|
||||
|
||||
/*
|
||||
* Definitions from TCG Opal Specification v2.0.2
|
||||
*/
|
||||
|
@ -38,34 +65,304 @@ enum sed_status_codes {
|
|||
/*
|
||||
* level 0 feature codes - section 3.1.1
|
||||
*/
|
||||
#define OPAL_FEATURE_CODE_LOCKING 0x0002
|
||||
#define OPAL_FEATURE_CODE_OPALV2 0x0203
|
||||
#define OPAL_FEATURE_CODE_TPER 0x0001
|
||||
#define OPAL_FEATURE_CODE_LOCKING 0x0002
|
||||
#define OPAL_FEATURE_CODE_GEOMETRY 0x0003
|
||||
|
||||
#define OPAL_FEATURE_CODE_OPALV1 0x0200
|
||||
#define OPAL_FEATURE_CODE_SINGLE_USER_MODE 0x0201
|
||||
#define OPAL_FEATURE_CODE_DATA_STORE 0x0202
|
||||
#define OPAL_FEATURE_CODE_OPALV2 0x0203
|
||||
|
||||
#define OPAL_FEATURE_CODE_OPALITE 0x0301
|
||||
#define OPAL_FEATURE_CODE_PYRITE_V1 0x0302
|
||||
#define OPAL_FEATURE_CODE_PYRITE_V2 0x0303
|
||||
#define OPAL_FEATURE_CODE_RUBY 0x0304
|
||||
|
||||
#define OPAL_FEATURE_CODE_LOCKING_LBA 0x0401
|
||||
#define OPAL_FEATURE_CODE_BLOCK_SID_AUTH 0x0402
|
||||
#define OPAL_FEATURE_CODE_CONFIG_NS_LOCKING 0x0403
|
||||
#define OPAL_FEATURE_CODE_DATA_REMOVAL 0x0404
|
||||
#define OPAL_FEATURE_CODE_NS_GEOMETRY 0x0405
|
||||
|
||||
/* locking features */
|
||||
#define OPAL_FEATURE_LOCKING_SUPPORTED 0x01
|
||||
#define OPAL_FEATURE_LOCKING_ENABLED 0x02
|
||||
#define OPAL_FEATURE_LOCKED 0x04
|
||||
|
||||
#define OPAL_FEATURE_MEDIA_ENCRYPT 0x08
|
||||
#define OPAL_FEATURE_MBR_ENABLED 0x10
|
||||
#define OPAL_FEATURE_MBR_DONE 0x20
|
||||
|
||||
/*
|
||||
* discovery header as specified in section 3.1.1.1
|
||||
* discovery header as specified in section 3.1.1
|
||||
*/
|
||||
struct level_0_discovery_header {
|
||||
uint32_t parameter_length;
|
||||
uint32_t revision;
|
||||
uint64_t reserved;
|
||||
__be32 parameter_length;
|
||||
__be32 revision;
|
||||
__be64 reserved;
|
||||
uint8_t vendor_specific[32];
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* level 0 features as specified in section 3.1.1.3
|
||||
*/
|
||||
struct level_0_discovery_features {
|
||||
uint16_t code;
|
||||
__be16 code;
|
||||
uint8_t version;
|
||||
uint8_t length;
|
||||
uint8_t feature;
|
||||
uint8_t reserved[11];
|
||||
};
|
||||
} __packed;
|
||||
|
||||
#define TPER_FEATURE_SYNC 0x0001
|
||||
#define TPER_FEATURE_ASYNC 0x0002
|
||||
#define TPER_FEATURE_ACKNAK 0x0004
|
||||
#define TPER_FEATURE_BUF_MGMT 0x0008
|
||||
#define TPER_FEATURE_STREAMING 0x0010
|
||||
#define TPER_FEATURE_COMID_MGMT 0x0040
|
||||
|
||||
/*
|
||||
* 3.1.1.2
|
||||
*
|
||||
* feature code 0x0001
|
||||
*/
|
||||
struct tper_desc {
|
||||
uint8_t feature;
|
||||
uint8_t reserved[11];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* 3.1.1.3
|
||||
*
|
||||
* feature code 0x0002
|
||||
*/
|
||||
struct locking_desc {
|
||||
uint8_t features;
|
||||
uint8_t reserved[11];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* 3.1.1.4
|
||||
*
|
||||
* feature code 0x0003
|
||||
*/
|
||||
#define GEOMETRY_ALIGNMENT_REQUIRED 0x01
|
||||
|
||||
struct geometry_reporting_desc {
|
||||
uint8_t align;
|
||||
uint8_t reserved[7];
|
||||
__be32 logical_block_size;
|
||||
__be64 alignment_granularity;
|
||||
__be64 lowest_aligned_lba;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* 3.1.1.5
|
||||
*
|
||||
* feature code 0x0203
|
||||
*/
|
||||
#define OPAL_V2_RANGE_CROSSING 0x01
|
||||
|
||||
struct opalv2_desc {
|
||||
__be16 base_comid;
|
||||
__be16 num_comids;
|
||||
uint8_t flags;
|
||||
__be16 num_locking_sp_admin_auth;
|
||||
__be16 num_locking_sp_user_auth;
|
||||
uint8_t initial_cpin_sid_ind;
|
||||
uint8_t initial_cpin_sid_revert;
|
||||
uint8_t reserved_future[5];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* 3.1.1.5
|
||||
*
|
||||
* feature code 0x0200
|
||||
*/
|
||||
struct opalv1_desc {
|
||||
__be16 base_comid;
|
||||
__be16 num_comids;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* TCG Opal SSC Feature Set v1.00 : Single User Mode
|
||||
* section 4.2.1
|
||||
*
|
||||
* feature code 0x0201
|
||||
*/
|
||||
#define SUM_FEATURE_ANY 0x0001
|
||||
#define SUM_FEATURE_ALL 0x0002
|
||||
#define SUM_FEATURE_POLICY 0x0004
|
||||
|
||||
struct single_user_mode_desc {
|
||||
__be32 num_locking_objects;
|
||||
uint8_t flags;
|
||||
uint8_t reserved[7];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* TCG Opal SSC Feature Set v1.00 : Additional DataStore Tables
|
||||
* section 4.2.1
|
||||
*
|
||||
* feature code 0x0202
|
||||
*/
|
||||
struct datastore_desc {
|
||||
__be16 reserved;
|
||||
__be16 max_tables;
|
||||
__be32 max_table_size;
|
||||
__be32 table_alignment;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* TCG Storage Security Subsystem Class: Opalite
|
||||
* section 3.1.1.4
|
||||
*
|
||||
* feature code 0x0301
|
||||
*/
|
||||
struct opalite_desc {
|
||||
__be16 base_comid;
|
||||
__be16 num_comids;
|
||||
uint8_t reserved[5];
|
||||
uint8_t initial_cpin_sid_ind;
|
||||
uint8_t initial_cpin_sid_revert;
|
||||
uint8_t reserved_future[5];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* TCG Storage Security Subsystem Class: Pyrite version 1
|
||||
* section 3.1.1.4
|
||||
*
|
||||
* feature code 0x0302
|
||||
*/
|
||||
struct pyrite_v1_desc {
|
||||
__be16 base_comid;
|
||||
__be16 num_comids;
|
||||
uint8_t reserved[5];
|
||||
uint8_t initial_cpin_sid_ind;
|
||||
uint8_t initial_cpin_sid_revert;
|
||||
uint8_t reserved_future[5];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* TCG Storage Security Subsystem Class: Pyrite version 2
|
||||
* section 3.1.1.4
|
||||
*
|
||||
* feature code 0x0303
|
||||
*/
|
||||
struct pyrite_v2_desc {
|
||||
__be16 base_comid;
|
||||
__be16 num_comids;
|
||||
uint8_t reserved[5];
|
||||
uint8_t initial_cpin_sid_ind;
|
||||
uint8_t initial_cpin_sid_revert;
|
||||
uint8_t reserved_future[5];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* TCG Ruby SSC Feature Set v1.00
|
||||
* section 3.1.1.5
|
||||
*
|
||||
* feature code 0x0304
|
||||
*/
|
||||
#define RUBY_RANGE_CROSSING 0x01
|
||||
|
||||
struct ruby_desc {
|
||||
__be16 base_comid;
|
||||
__be16 num_comids;
|
||||
uint8_t flags;
|
||||
__be16 num_locking_sp_admin_auth;
|
||||
__be16 num_locking_sp_user_auth;
|
||||
uint8_t initial_cpin_sid_ind;
|
||||
uint8_t initial_cpin_sid_revert;
|
||||
uint8_t reserved_future[5];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* TCG Storage Enterprise SSC Feature Set Locking LBA Ranges Control
|
||||
* section 4.1.1
|
||||
*
|
||||
* feature code 0x0401
|
||||
*/
|
||||
struct locking_lba_desc {
|
||||
uint8_t reserved;
|
||||
uint8_t reserved_range_control[11];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* TCG Storage Feature Set: Block SID Authentication
|
||||
* section 4.1.1
|
||||
*
|
||||
* feature code 0x0402
|
||||
*/
|
||||
#define BLOCK_SID_VALUE_STATE 0x0001
|
||||
#define BLOCK_SID_BLOCKED_STATE 0x0002
|
||||
#define BLOCK_SID_HW_RESET 0x0001
|
||||
|
||||
struct block_sid_auth_desc {
|
||||
uint8_t states;
|
||||
uint8_t hw_reset;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* TCG Storage Opal SSC Feature Set: Configurable Namespace Locking
|
||||
* section 4.2.1
|
||||
*
|
||||
* feature code 0x0403
|
||||
*/
|
||||
#define CONFIG_NS_RANGE_C 0x0080
|
||||
#define CONFIG_NS_RANGE_P 0x0040
|
||||
|
||||
struct config_ns_desc {
|
||||
uint8_t flags;
|
||||
uint8_t reserved[3];
|
||||
__be32 max_key_count;
|
||||
__be32 unused_key_count;
|
||||
__be32 max_ranges_per_ns;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* TCG Storage Security Subsystem Class: Opal version 2.02
|
||||
* section 3.1.1.6
|
||||
*
|
||||
* feature code 0x0404
|
||||
*/
|
||||
#define DATA_REMOVAL_OPER_PROCESSING 0x01
|
||||
#define DATA_REMOVAL_OPER_INTERRUPTED 0x02
|
||||
#define DATA_REMOVAL_TIME_BIT0 0x01
|
||||
#define DATA_REMOVAL_TIME_BIT1 0x02
|
||||
#define DATA_REMOVAL_TIME_BIT2 0x04
|
||||
#define DATA_REMOVAL_TIME_BIT5 0x20
|
||||
|
||||
#define DATA_REMOVAL_MECHANISM_OVERWRITE 0x01
|
||||
#define DATA_REMOVAL_MECHANISM_BLOCK_ERASE 0x02
|
||||
#define DATA_REMOVAL_MECHANISM_CRYPTO_ERASE 0x04
|
||||
#define DATA_REMOVAL_MECHANISM_VENDOR_ERASE 0x10
|
||||
|
||||
struct data_removal_desc {
|
||||
uint8_t reserved;
|
||||
uint8_t flags;
|
||||
uint8_t removal_mechanism;
|
||||
uint8_t format;
|
||||
__be16 time_mechanism_bit0;
|
||||
__be16 time_mechanism_bit1;
|
||||
__be16 time_mechanism_bit2;
|
||||
uint8_t reserved_mech[4];
|
||||
__be16 time_mechanism_bit5;
|
||||
uint8_t future_reserved[16];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* TCG Storage Opal SSC Feature Set: Configurable Namespace Locking
|
||||
* section 4.2.1
|
||||
*
|
||||
* feature code 0x0405
|
||||
*/
|
||||
#define NS_GEOMETRY_ALIGNMENT_REQUIRED 0x01
|
||||
|
||||
struct ns_geometry_desc {
|
||||
uint8_t align;
|
||||
uint8_t reserved[7];
|
||||
__be32 logical_block_size;
|
||||
__be64 alignment_granularity;
|
||||
__be64 lowest_aligned_lba;
|
||||
} __packed;
|
||||
|
||||
#endif /* _SED_OPAL_SPEC_H */
|
||||
|
|
|
@ -233,7 +233,7 @@ static int ilog_dump_assert_logs(struct ilog *ilog)
|
|||
{
|
||||
__u8 buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
|
||||
__u8 head_buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
|
||||
char file_path[PATH_MAX] = {0};
|
||||
_cleanup_free_ char *file_path = NULL;
|
||||
char file_name[] = "AssertLog.bin";
|
||||
struct assert_dump_header *ad = (struct assert_dump_header *) head_buf;
|
||||
struct nvme_passthru_cmd cmd = {
|
||||
|
@ -249,8 +249,10 @@ static int ilog_dump_assert_logs(struct ilog *ilog)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
snprintf(file_path, sizeof(file_path), "%.*s/%s",
|
||||
(int) (sizeof(file_path) - sizeof(file_name) - 1), ilog->cfg->out_dir, file_name);
|
||||
if (asprintf(&file_path, "%.*s/%s",
|
||||
(int) (sizeof(file_path) - sizeof(file_name) - 1),
|
||||
ilog->cfg->out_dir, file_name) < 0)
|
||||
return -errno;
|
||||
output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, LOG_FILE_PERMISSION);
|
||||
if (output < 0)
|
||||
return -errno;
|
||||
|
@ -289,7 +291,7 @@ static int ilog_dump_event_logs(struct ilog *ilog)
|
|||
{
|
||||
__u8 buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
|
||||
__u8 head_buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
|
||||
char file_path[PATH_MAX] = {0};
|
||||
_cleanup_free_ char *file_path = NULL;
|
||||
struct event_dump_header *ehdr = (struct event_dump_header *) head_buf;
|
||||
struct nvme_passthru_cmd cmd = {
|
||||
.opcode = 0xd2,
|
||||
|
@ -304,7 +306,8 @@ static int ilog_dump_event_logs(struct ilog *ilog)
|
|||
err = read_header(&cmd, dev_fd(ilog->dev));
|
||||
if (err)
|
||||
return err;
|
||||
snprintf(file_path, sizeof(file_path) - 1, "%s/EventLog.bin", ilog->cfg->out_dir);
|
||||
if (asprintf(&file_path, "%s/EventLog.bin", ilog->cfg->out_dir))
|
||||
return -errno;
|
||||
output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, LOG_FILE_PERMISSION);
|
||||
if (output < 0)
|
||||
return -errno;
|
||||
|
@ -363,7 +366,7 @@ static int ilog_dump_nlogs(struct ilog *ilog, int core)
|
|||
int err = 0;
|
||||
__u32 count, core_num;
|
||||
__u8 buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
|
||||
char file_path[PATH_MAX] = {0};
|
||||
_cleanup_free_ char *file_path = NULL;
|
||||
struct nlog_dump_header_common *nlog_header = (struct nlog_dump_header_common *)buf;
|
||||
struct nvme_passthru_cmd cmd = {
|
||||
.opcode = 0xd2,
|
||||
|
@ -400,11 +403,12 @@ static int ilog_dump_nlogs(struct ilog *ilog, int core)
|
|||
count = nlog_header->totalnlogs;
|
||||
core_num = core < 0 ? nlog_header->corecount : 0;
|
||||
if (!header_size) {
|
||||
snprintf(file_path, sizeof(file_path) - 1, "%s/NLog.bin",
|
||||
ilog->cfg->out_dir);
|
||||
output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
LOG_FILE_PERMISSION);
|
||||
if (output < 0)
|
||||
if (asprintf(&file_path, "%s/NLog.bin", ilog->cfg->out_dir) >= 0) {
|
||||
output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
LOG_FILE_PERMISSION);
|
||||
if (output < 0)
|
||||
return -errno;
|
||||
} else
|
||||
return -errno;
|
||||
header_size = get_nlog_header_size(nlog_header);
|
||||
is_open = true;
|
||||
|
@ -416,7 +420,7 @@ static int ilog_dump_nlogs(struct ilog *ilog, int core)
|
|||
print_nlog_header(buf);
|
||||
cmd.cdw13 = 0x400;
|
||||
err = cmd_dump_repeat(&cmd, nlog_header->nlogbytesize / 4,
|
||||
output, dev_fd(ilog->dev), true);
|
||||
output, dev_fd(ilog->dev), true);
|
||||
if (err)
|
||||
break;
|
||||
} while (++log_select.selectNlog < count);
|
||||
|
@ -432,16 +436,19 @@ static int ilog_dump_nlogs(struct ilog *ilog, int core)
|
|||
|
||||
int ensure_dir(const char *parent_dir_name, const char *name)
|
||||
{
|
||||
char file_path[PATH_MAX] = {0};
|
||||
_cleanup_free_ char *file_path = NULL;
|
||||
struct stat sb;
|
||||
|
||||
snprintf(file_path, sizeof(file_path) - 1, "%s/%s", parent_dir_name, name);
|
||||
if (asprintf(&file_path, "%s/%s", parent_dir_name, name) < 0)
|
||||
return -errno;
|
||||
|
||||
if (!(stat(file_path, &sb) == 0 && S_ISDIR(sb.st_mode))) {
|
||||
if (mkdir(file_path, 777) != 0) {
|
||||
perror(file_path);
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -456,13 +463,14 @@ static int log_save(struct log *log, const char *parent_dir_name, const char *su
|
|||
const char *file_name, __u8 *buffer, size_t buf_size)
|
||||
{
|
||||
_cleanup_fd_ int output = -1;
|
||||
char file_path[PATH_MAX] = {0};
|
||||
_cleanup_free_ char *file_path = NULL;
|
||||
size_t bytes_remaining = 0;
|
||||
|
||||
ensure_dir(parent_dir_name, subdir_name);
|
||||
|
||||
snprintf(file_path, sizeof(file_path) - 1, "%s/%s/%s", parent_dir_name, subdir_name,
|
||||
file_name);
|
||||
if (asprintf(&file_path, "%s/%s/%s", parent_dir_name, subdir_name, file_name) < 0)
|
||||
return -errno;
|
||||
|
||||
output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, LOG_FILE_PERMISSION);
|
||||
if (output < 0)
|
||||
return -errno;
|
||||
|
@ -486,15 +494,15 @@ static int ilog_dump_identify_page(struct ilog *ilog, struct log *cns, __u32 nsi
|
|||
{
|
||||
__u8 data[NVME_IDENTIFY_DATA_SIZE];
|
||||
__u8 *buff = cns->buffer ? cns->buffer : data;
|
||||
char filename[sizeof(
|
||||
"cntid_XXXXX_cns_XXX_nsid_XXXXXXXXXX_nvmsetid_XXXXX_csi_XXX.bin")] = {0};
|
||||
_cleanup_free_ char *filename = NULL;
|
||||
int err = nvme_identify_cns_nsid(dev_fd(ilog->dev), cns->id, nsid, buff);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
snprintf(filename, sizeof(filename) - 1, "cntid_0_cns_%d_nsid_%d_nvmsetid_0_csi_0.bin",
|
||||
cns->id, nsid);
|
||||
if (asprintf(&filename, "cntid_0_cns_%d_nsid_%d_nvmsetid_0_csi_0.bin", cns->id, nsid) < 0)
|
||||
return -errno;
|
||||
|
||||
return log_save(cns, ilog->cfg->out_dir, "identify", filename, buff, sizeof(data));
|
||||
}
|
||||
|
||||
|
@ -646,9 +654,9 @@ static int ilog_dump_identify_pages(struct ilog *ilog)
|
|||
static int ilog_dump_log_page(struct ilog *ilog, struct log *lp, __u32 nsid)
|
||||
{
|
||||
__u8 *buff = lp->buffer;
|
||||
char filename[sizeof("lid_0xXX_lsp_0xXX_lsi_0xXXXX.bin")] = {0};
|
||||
int err;
|
||||
_cleanup_free_ char *filename = NULL;
|
||||
|
||||
int err;
|
||||
if (!lp->buffer_size)
|
||||
return -EINVAL;
|
||||
if (!buff) {
|
||||
|
@ -660,8 +668,9 @@ static int ilog_dump_log_page(struct ilog *ilog, struct log *lp, __u32 nsid)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
snprintf(filename, sizeof(filename), "lid_0x%02x_lsp_0x00_lsi_0x0000.bin",
|
||||
lp->id);
|
||||
if (asprintf(&filename, "lid_0x%02x_lsp_0x00_lsi_0x0000.bin", lp->id) < 0)
|
||||
return -errno;
|
||||
|
||||
return log_save(lp, ilog->cfg->out_dir, "log_pages", filename, buff, lp->buffer_size);
|
||||
}
|
||||
|
||||
|
@ -813,10 +822,11 @@ int solidigm_get_internal_log(int argc, char **argv, struct command *command,
|
|||
{
|
||||
char sn_prefix[sizeof(((struct nvme_id_ctrl *)0)->sn)+1];
|
||||
char date_str[sizeof("-YYYYMMDDHHMMSS")];
|
||||
char full_folder[PATH_MAX] = {0};
|
||||
char unique_folder[sizeof(sn_prefix)+sizeof(date_str)-1] = {0};
|
||||
_cleanup_free_ char *full_folder = NULL;
|
||||
_cleanup_free_ char *unique_folder = NULL;
|
||||
_cleanup_free_ char *zip_name = NULL;
|
||||
|
||||
char *initial_folder;
|
||||
char zip_name[PATH_MAX] = {0};
|
||||
char *output_path;
|
||||
struct ilog ilog = {0};
|
||||
int err;
|
||||
|
@ -885,12 +895,16 @@ int solidigm_get_internal_log(int argc, char **argv, struct command *command,
|
|||
|
||||
current_time = time(NULL);
|
||||
strftime(date_str, sizeof(date_str), "-%Y%m%d%H%M%S", localtime(¤t_time));
|
||||
snprintf(unique_folder, sizeof(unique_folder), "%s%s", sn_prefix, date_str);
|
||||
snprintf(full_folder, sizeof(full_folder) - 1, "%s/%s", cfg.out_dir, unique_folder);
|
||||
if (asprintf(&unique_folder, "%s%s", sn_prefix, date_str) < 0)
|
||||
return -errno;
|
||||
if (asprintf(&full_folder, "%s/%s", cfg.out_dir, unique_folder) < 0)
|
||||
return -errno;
|
||||
|
||||
if (mkdir(full_folder, 0755) != 0) {
|
||||
perror("mkdir");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
cfg.out_dir = full_folder;
|
||||
output_path = full_folder;
|
||||
|
||||
|
@ -946,10 +960,12 @@ int solidigm_get_internal_log(int argc, char **argv, struct command *command,
|
|||
|
||||
if (ilog.count > 0) {
|
||||
int ret_cmd;
|
||||
char *cmd;
|
||||
_cleanup_free_ char *cmd = NULL;
|
||||
char *quiet = cfg.verbose ? "" : " -q";
|
||||
|
||||
snprintf(zip_name, sizeof(zip_name) - 1, "%s.zip", unique_folder);
|
||||
if (asprintf(&zip_name, "%s.zip", unique_folder) < 0)
|
||||
return -errno;
|
||||
|
||||
if (asprintf(&cmd, "cd \"%s\" && zip -MM -r \"../%s\" ./* %s", cfg.out_dir,
|
||||
zip_name, quiet) < 0) {
|
||||
err = errno;
|
||||
|
@ -962,7 +978,6 @@ int solidigm_get_internal_log(int argc, char **argv, struct command *command,
|
|||
perror(cmd);
|
||||
else {
|
||||
output_path = zip_name;
|
||||
free(cmd);
|
||||
if (asprintf(&cmd, "rm -rf %s", cfg.out_dir) < 0) {
|
||||
err = errno;
|
||||
perror("Can't allocate string for cleanup");
|
||||
|
@ -971,7 +986,6 @@ int solidigm_get_internal_log(int argc, char **argv, struct command *command,
|
|||
if (system(cmd) != 0)
|
||||
perror("Failed removing logs folder");
|
||||
}
|
||||
free(cmd);
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "common.h"
|
||||
#include "nvme-print.h"
|
||||
|
||||
#include "plugins/ocp/ocp-nvme.h"
|
||||
#include "plugins/ocp/ocp-utils.h"
|
||||
#include "solidigm-util.h"
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
#include "cmd.h"
|
||||
|
||||
#define SOLIDIGM_PLUGIN_VERSION "1.8"
|
||||
#define SOLIDIGM_PLUGIN_VERSION "1.9"
|
||||
|
||||
PLUGIN(NAME("solidigm", "Solidigm vendor specific extensions", SOLIDIGM_PLUGIN_VERSION),
|
||||
COMMAND_LIST(
|
||||
|
|
|
@ -61,7 +61,7 @@ const char *solidigm_config_get_nlog_obj_name(const struct json_object *config,
|
|||
if (!json_object_object_get_ex(nlog_names, hex_header, &obj_name))
|
||||
return NULL;
|
||||
name = json_object_get_string(obj_name);
|
||||
if (strncmp(NLOG_OBJ_PREFIX, name, strlen(NLOG_OBJ_PREFIX)))
|
||||
if ((!name) || (strncmp(NLOG_OBJ_PREFIX, name, strlen(NLOG_OBJ_PREFIX))))
|
||||
return NULL;
|
||||
|
||||
return &name[strlen(OBJ_NAME_PREFIX)];
|
||||
|
|
|
@ -383,7 +383,9 @@ int ssstc_get_add_smart_log(int argc, char **argv, struct command *cmd, struct p
|
|||
"(optionally, for the specified namespace), and show it.";
|
||||
const char *namespace = "(optional) desired namespace";
|
||||
const char *raw = "Dump output in binary format";
|
||||
#ifdef CONFIG_JSONC
|
||||
const char *json = "Dump output in json format";
|
||||
#endif /* CONFIG_JSONC */
|
||||
|
||||
struct nvme_additional_smart_log smart_log_add;
|
||||
struct nvme_dev *dev;
|
||||
|
@ -402,7 +404,7 @@ int ssstc_get_add_smart_log(int argc, char **argv, struct command *cmd, struct p
|
|||
OPT_ARGS(opts) = {
|
||||
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace),
|
||||
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
|
||||
OPT_FLAG("json", 'j', &cfg.json, json),
|
||||
OPT_FLAG_JSON("json", 'j', &cfg.json, json),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
|
|
|
@ -127,8 +127,10 @@ static void vt_convert_smart_data_to_human_readable_format(struct vtview_smart_l
|
|||
|
||||
capacity = le64_to_cpu(smart->raw_ns.nsze) * lba;
|
||||
|
||||
snprintf(tempbuff, sizeof(tempbuff), "log;%s;%lu;%s;%s;%-.*s;", smart->raw_ctrl.sn, smart->time_stamp, smart->path,
|
||||
smart->raw_ctrl.mn, (int)sizeof(smart->raw_ctrl.fr), smart->raw_ctrl.fr);
|
||||
snprintf(tempbuff, sizeof(tempbuff), "log;%s;%llu;%s;%s;%-.*s;", smart->raw_ctrl.sn,
|
||||
(unsigned long long)smart->time_stamp, smart->path,
|
||||
smart->raw_ctrl.mn, (int)sizeof(smart->raw_ctrl.fr),
|
||||
smart->raw_ctrl.fr);
|
||||
strcpy(text, tempbuff);
|
||||
snprintf(tempbuff, sizeof(tempbuff), "Capacity;%lf;", capacity / 1000000000);
|
||||
strcat(text, tempbuff);
|
||||
|
|
|
@ -1882,7 +1882,6 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev)
|
|||
case WDC_NVME_SN861_DEV_ID:
|
||||
case WDC_NVME_SN861_DEV_ID_1:
|
||||
case WDC_NVME_SN861_DEV_ID_2:
|
||||
case WDC_NVME_SNTMP_DEV_ID:
|
||||
capabilities |= (WDC_DRIVE_CAP_C0_LOG_PAGE |
|
||||
WDC_DRIVE_CAP_C3_LOG_PAGE |
|
||||
WDC_DRIVE_CAP_CA_LOG_PAGE |
|
||||
|
@ -1899,6 +1898,23 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev)
|
|||
WDC_DRIVE_CAP_SET_LATENCY_MONITOR);
|
||||
break;
|
||||
|
||||
case WDC_NVME_SNTMP_DEV_ID:
|
||||
capabilities |= (WDC_DRIVE_CAP_C0_LOG_PAGE |
|
||||
WDC_DRIVE_CAP_C3_LOG_PAGE |
|
||||
WDC_DRIVE_CAP_CA_LOG_PAGE |
|
||||
WDC_DRIVE_CAP_OCP_C4_LOG_PAGE |
|
||||
WDC_DRIVE_CAP_OCP_C5_LOG_PAGE |
|
||||
WDC_DRIVE_CAP_DUI |
|
||||
WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2 |
|
||||
WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE |
|
||||
WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY |
|
||||
WDC_DRIVE_CAP_INFO |
|
||||
WDC_DRIVE_CAP_CLOUD_SSD_VERSION |
|
||||
WDC_DRIVE_CAP_LOG_PAGE_DIR |
|
||||
WDC_DRIVE_CAP_DRIVE_STATUS |
|
||||
WDC_DRIVE_CAP_SET_LATENCY_MONITOR);
|
||||
break;
|
||||
|
||||
default:
|
||||
capabilities = 0;
|
||||
}
|
||||
|
@ -2165,6 +2181,163 @@ static int wdc_create_log_file(char *file, __u8 *drive_log_data,
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool wdc_validate_dev_mng_log(void *data)
|
||||
{
|
||||
__u32 remaining_len = 0;
|
||||
__u32 log_length = 0;
|
||||
__u32 log_entry_size = 0;
|
||||
__u32 log_entry_id = 0;
|
||||
__u32 offset = 0;
|
||||
bool valid_log = false;
|
||||
struct wdc_c2_log_subpage_header *p_next_log_entry = NULL;
|
||||
struct wdc_c2_log_page_header *hdr_ptr = (struct wdc_c2_log_page_header *)data;
|
||||
|
||||
log_length = le32_to_cpu(hdr_ptr->length);
|
||||
/* Ensure log data is large enough for common header */
|
||||
if (log_length < sizeof(struct wdc_c2_log_page_header)) {
|
||||
fprintf(stderr,
|
||||
"ERROR: %s: log smaller than header. log_len: 0x%x HdrSize: %"PRIxPTR"\n",
|
||||
__func__, log_length, sizeof(struct wdc_c2_log_page_header));
|
||||
return valid_log;
|
||||
}
|
||||
|
||||
/* Get pointer to first log Entry */
|
||||
offset = sizeof(struct wdc_c2_log_page_header);
|
||||
p_next_log_entry = (struct wdc_c2_log_subpage_header *)(((__u8 *)data) + offset);
|
||||
remaining_len = log_length - offset;
|
||||
|
||||
/* Proceed only if there is at least enough data to read an entry header */
|
||||
while (remaining_len >= sizeof(struct wdc_c2_log_subpage_header)) {
|
||||
/* Get size of the next entry */
|
||||
log_entry_size = le32_to_cpu(p_next_log_entry->length);
|
||||
log_entry_id = le32_to_cpu(p_next_log_entry->entry_id);
|
||||
/*
|
||||
* If log entry size is 0 or the log entry goes past the end
|
||||
* of the data, we must be at the end of the data
|
||||
*/
|
||||
if (!log_entry_size || log_entry_size > remaining_len) {
|
||||
fprintf(stderr, "ERROR: WDC: %s: Detected unaligned end of the data. ",
|
||||
__func__);
|
||||
fprintf(stderr, "Data Offset: 0x%x Entry Size: 0x%x, ",
|
||||
offset, log_entry_size);
|
||||
fprintf(stderr, "Remaining Log Length: 0x%x Entry Id: 0x%x\n",
|
||||
remaining_len, log_entry_id);
|
||||
|
||||
/* Force the loop to end */
|
||||
remaining_len = 0;
|
||||
} else if (!log_entry_id || log_entry_id > 200) {
|
||||
/* Invalid entry - fail the search */
|
||||
fprintf(stderr, "ERROR: WDC: %s: Invalid entry found at offset: 0x%x ",
|
||||
__func__, offset);
|
||||
fprintf(stderr, "Entry Size: 0x%x, Remaining Log Length: 0x%x ",
|
||||
log_entry_size, remaining_len);
|
||||
fprintf(stderr, "Entry Id: 0x%x\n", log_entry_id);
|
||||
|
||||
/* Force the loop to end */
|
||||
remaining_len = 0;
|
||||
valid_log = false;
|
||||
} else {
|
||||
/* A valid log has at least one entry and no invalid entries */
|
||||
valid_log = true;
|
||||
remaining_len -= log_entry_size;
|
||||
if (remaining_len > 0) {
|
||||
/* Increment the offset counter */
|
||||
offset += log_entry_size;
|
||||
/* Get the next entry */
|
||||
p_next_log_entry =
|
||||
(struct wdc_c2_log_subpage_header *)(((__u8 *)data) + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return valid_log;
|
||||
}
|
||||
|
||||
bool wdc_parse_dev_mng_log_entry(void *data, __u32 entry_id,
|
||||
struct wdc_c2_log_subpage_header **log_entry)
|
||||
{
|
||||
__u32 remaining_len = 0;
|
||||
__u32 log_length = 0;
|
||||
__u32 log_entry_size = 0;
|
||||
__u32 log_entry_id = 0;
|
||||
__u32 offset = 0;
|
||||
bool found = false;
|
||||
struct wdc_c2_log_subpage_header *p_next_log_entry = NULL;
|
||||
struct wdc_c2_log_page_header *hdr_ptr = (struct wdc_c2_log_page_header *)data;
|
||||
|
||||
log_length = le32_to_cpu(hdr_ptr->length);
|
||||
/* Ensure log data is large enough for common header */
|
||||
if (log_length < sizeof(struct wdc_c2_log_page_header)) {
|
||||
fprintf(stderr,
|
||||
"ERROR: %s: log smaller than header. log_len: 0x%x HdrSize: %"PRIxPTR"\n",
|
||||
__func__, log_length, sizeof(struct wdc_c2_log_page_header));
|
||||
return found;
|
||||
}
|
||||
|
||||
/* Get pointer to first log Entry */
|
||||
offset = sizeof(struct wdc_c2_log_page_header);
|
||||
p_next_log_entry = (struct wdc_c2_log_subpage_header *)(((__u8 *)data) + offset);
|
||||
remaining_len = log_length - offset;
|
||||
|
||||
if (!log_entry) {
|
||||
fprintf(stderr, "ERROR: WDC - %s: No log entry pointer.\n", __func__);
|
||||
return found;
|
||||
}
|
||||
*log_entry = NULL;
|
||||
|
||||
/* Proceed only if there is at least enough data to read an entry header */
|
||||
while (remaining_len >= sizeof(struct wdc_c2_log_subpage_header)) {
|
||||
/* Get size of the next entry */
|
||||
log_entry_size = le32_to_cpu(p_next_log_entry->length);
|
||||
log_entry_id = le32_to_cpu(p_next_log_entry->entry_id);
|
||||
|
||||
/*
|
||||
* If log entry size is 0 or the log entry goes past the end
|
||||
* of the data, we must be at the end of the data
|
||||
*/
|
||||
if (!log_entry_size || log_entry_size > remaining_len) {
|
||||
fprintf(stderr, "ERROR: WDC: %s: Detected unaligned end of the data. ",
|
||||
__func__);
|
||||
fprintf(stderr, "Data Offset: 0x%x Entry Size: 0x%x, ",
|
||||
offset, log_entry_size);
|
||||
fprintf(stderr, "Remaining Log Length: 0x%x Entry Id: 0x%x\n",
|
||||
remaining_len, log_entry_id);
|
||||
|
||||
/* Force the loop to end */
|
||||
remaining_len = 0;
|
||||
} else if (!log_entry_id || log_entry_id > 200) {
|
||||
/* Invalid entry - fail the search */
|
||||
fprintf(stderr, "ERROR: WDC: %s: Invalid entry found at offset: 0x%x ",
|
||||
__func__, offset);
|
||||
fprintf(stderr, "Entry Size: 0x%x, Remaining Log Length: 0x%x ",
|
||||
log_entry_size, remaining_len);
|
||||
fprintf(stderr, "Entry Id: 0x%x\n", log_entry_id);
|
||||
|
||||
/* Force the loop to end */
|
||||
remaining_len = 0;
|
||||
} else {
|
||||
if (log_entry_id == entry_id) {
|
||||
found = true;
|
||||
*log_entry = p_next_log_entry;
|
||||
remaining_len = 0;
|
||||
} else {
|
||||
remaining_len -= log_entry_size;
|
||||
}
|
||||
|
||||
if (remaining_len > 0) {
|
||||
/* Increment the offset counter */
|
||||
offset += log_entry_size;
|
||||
|
||||
/* Get the next entry */
|
||||
p_next_log_entry =
|
||||
(struct wdc_c2_log_subpage_header *)(((__u8 *)data) + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
bool wdc_get_dev_mng_log_entry(__u32 log_length, __u32 entry_id,
|
||||
struct wdc_c2_log_page_header *p_log_hdr,
|
||||
struct wdc_c2_log_subpage_header **p_p_found_log_entry)
|
||||
|
@ -2172,9 +2345,10 @@ bool wdc_get_dev_mng_log_entry(__u32 log_length, __u32 entry_id,
|
|||
__u32 remaining_len = 0;
|
||||
__u32 log_entry_hdr_size = sizeof(struct wdc_c2_log_subpage_header) - 1;
|
||||
__u32 log_entry_size = 0;
|
||||
__u32 log_entry_id = 0;
|
||||
__u32 size = 0;
|
||||
bool valid_log;
|
||||
__u32 current_data_offset = 0;
|
||||
__u32 offset = 0;
|
||||
struct wdc_c2_log_subpage_header *p_next_log_entry = NULL;
|
||||
|
||||
if (!*p_p_found_log_entry) {
|
||||
|
@ -2194,8 +2368,8 @@ bool wdc_get_dev_mng_log_entry(__u32 log_length, __u32 entry_id,
|
|||
|
||||
/* Get pointer to first log Entry */
|
||||
size = sizeof(struct wdc_c2_log_page_header);
|
||||
current_data_offset = size;
|
||||
p_next_log_entry = (struct wdc_c2_log_subpage_header *)((__u8 *)p_log_hdr + current_data_offset);
|
||||
offset = size;
|
||||
p_next_log_entry = (struct wdc_c2_log_subpage_header *)(((__u8 *)p_log_hdr) + offset);
|
||||
remaining_len = log_length - size;
|
||||
valid_log = false;
|
||||
|
||||
|
@ -2209,7 +2383,8 @@ bool wdc_get_dev_mng_log_entry(__u32 log_length, __u32 entry_id,
|
|||
/* Proceed only if there is at least enough data to read an entry header */
|
||||
while (remaining_len >= log_entry_hdr_size) {
|
||||
/* Get size of the next entry */
|
||||
log_entry_size = p_next_log_entry->length;
|
||||
log_entry_size = le32_to_cpu(p_next_log_entry->length);
|
||||
log_entry_id = le32_to_cpu(p_next_log_entry->entry_id);
|
||||
|
||||
/*
|
||||
* If log entry size is 0 or the log entry goes past the end
|
||||
|
@ -2219,19 +2394,19 @@ bool wdc_get_dev_mng_log_entry(__u32 log_length, __u32 entry_id,
|
|||
fprintf(stderr, "ERROR: WDC: %s: Detected unaligned end of the data. ",
|
||||
__func__);
|
||||
fprintf(stderr, "Data Offset: 0x%x Entry Size: 0x%x, ",
|
||||
current_data_offset, log_entry_size);
|
||||
offset, log_entry_size);
|
||||
fprintf(stderr, "Remaining Log Length: 0x%x Entry Id: 0x%x\n",
|
||||
remaining_len, p_next_log_entry->entry_id);
|
||||
remaining_len, log_entry_id);
|
||||
|
||||
/* Force the loop to end */
|
||||
remaining_len = 0;
|
||||
} else if (!p_next_log_entry->entry_id || p_next_log_entry->entry_id > 200) {
|
||||
} else if (!log_entry_id || log_entry_id > 200) {
|
||||
/* Invalid entry - fail the search */
|
||||
fprintf(stderr, "ERROR: WDC: %s: Invalid entry found at offset: 0x%x ",
|
||||
__func__, current_data_offset);
|
||||
__func__, offset);
|
||||
fprintf(stderr, "Entry Size: 0x%x, Remaining Log Length: 0x%x ",
|
||||
log_entry_size, remaining_len);
|
||||
fprintf(stderr, "Entry Id: 0x%x\n", p_next_log_entry->entry_id);
|
||||
fprintf(stderr, "Entry Id: 0x%x\n", log_entry_id);
|
||||
|
||||
/* Force the loop to end */
|
||||
remaining_len = 0;
|
||||
|
@ -2242,7 +2417,7 @@ bool wdc_get_dev_mng_log_entry(__u32 log_length, __u32 entry_id,
|
|||
} else {
|
||||
/* Structure must have at least one valid entry to be considered valid */
|
||||
valid_log = true;
|
||||
if (p_next_log_entry->entry_id == entry_id)
|
||||
if (log_entry_id == entry_id)
|
||||
/* A potential match. */
|
||||
*p_p_found_log_entry = p_next_log_entry;
|
||||
|
||||
|
@ -2250,10 +2425,11 @@ bool wdc_get_dev_mng_log_entry(__u32 log_length, __u32 entry_id,
|
|||
|
||||
if (remaining_len > 0) {
|
||||
/* Increment the offset counter */
|
||||
current_data_offset += log_entry_size;
|
||||
offset += log_entry_size;
|
||||
|
||||
/* Get the next entry */
|
||||
p_next_log_entry = (struct wdc_c2_log_subpage_header *)(((__u8 *)p_log_hdr) + current_data_offset);
|
||||
p_next_log_entry =
|
||||
(struct wdc_c2_log_subpage_header *)(((__u8 *)p_log_hdr) + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2261,6 +2437,109 @@ bool wdc_get_dev_mng_log_entry(__u32 log_length, __u32 entry_id,
|
|||
return valid_log;
|
||||
}
|
||||
|
||||
static bool get_dev_mgmt_log_page_data(struct nvme_dev *dev, void **log_data,
|
||||
__u8 uuid_ix)
|
||||
{
|
||||
void *data;
|
||||
struct wdc_c2_log_page_header *hdr_ptr;
|
||||
__u32 length = 0;
|
||||
int ret = 0;
|
||||
bool valid = false;
|
||||
|
||||
data = (__u8 *)malloc(sizeof(__u8) * WDC_C2_LOG_BUF_LEN);
|
||||
if (!data) {
|
||||
fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(data, 0, sizeof(__u8) * WDC_C2_LOG_BUF_LEN);
|
||||
|
||||
/* get the log page length */
|
||||
struct nvme_get_log_args args_len = {
|
||||
.args_size = sizeof(args_len),
|
||||
.fd = dev_fd(dev),
|
||||
.lid = WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID,
|
||||
.nsid = 0xFFFFFFFF,
|
||||
.lpo = 0,
|
||||
.lsp = NVME_LOG_LSP_NONE,
|
||||
.lsi = 0,
|
||||
.rae = false,
|
||||
.uuidx = uuid_ix,
|
||||
.csi = NVME_CSI_NVM,
|
||||
.ot = false,
|
||||
.len = WDC_C2_LOG_BUF_LEN,
|
||||
.log = data,
|
||||
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
|
||||
.result = NULL,
|
||||
};
|
||||
ret = nvme_get_log(&args_len);
|
||||
if (ret) {
|
||||
fprintf(stderr,
|
||||
"ERROR: WDC: Unable to get 0x%x Log Page with uuid %d, ret = 0x%x\n",
|
||||
WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID, uuid_ix, ret);
|
||||
goto end;
|
||||
}
|
||||
|
||||
hdr_ptr = (struct wdc_c2_log_page_header *)data;
|
||||
length = le32_to_cpu(hdr_ptr->length);
|
||||
|
||||
if (length > WDC_C2_LOG_BUF_LEN) {
|
||||
/* Log page buffer too small for actual data */
|
||||
free(data);
|
||||
data = calloc(length, sizeof(__u8));
|
||||
if (!data) {
|
||||
fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* get the log page data with the increased length */
|
||||
struct nvme_get_log_args args_data = {
|
||||
.args_size = sizeof(args_data),
|
||||
.fd = dev_fd(dev),
|
||||
.lid = WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID,
|
||||
.nsid = 0xFFFFFFFF,
|
||||
.lpo = 0,
|
||||
.lsp = NVME_LOG_LSP_NONE,
|
||||
.lsi = 0,
|
||||
.rae = false,
|
||||
.uuidx = uuid_ix,
|
||||
.csi = NVME_CSI_NVM,
|
||||
.ot = false,
|
||||
.len = length,
|
||||
.log = data,
|
||||
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
|
||||
.result = NULL,
|
||||
};
|
||||
ret = nvme_get_log(&args_data);
|
||||
|
||||
if (ret) {
|
||||
fprintf(stderr,
|
||||
"ERROR: WDC: Unable to read 0x%x Log with uuid %d, ret = 0x%x\n",
|
||||
WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID, uuid_ix, ret);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
valid = wdc_validate_dev_mng_log(data);
|
||||
if (valid) {
|
||||
/* Ensure size of log data matches length in log header */
|
||||
*log_data = calloc(length, sizeof(__u8));
|
||||
if (!*log_data) {
|
||||
fprintf(stderr, "ERROR: WDC: calloc: %s\n", strerror(errno));
|
||||
valid = false;
|
||||
goto end;
|
||||
}
|
||||
memcpy((void *)*log_data, data, length);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: WDC: C2 log page not found with uuid index %d\n",
|
||||
uuid_ix);
|
||||
}
|
||||
|
||||
end:
|
||||
free(data);
|
||||
return valid;
|
||||
}
|
||||
|
||||
static bool get_dev_mgmt_log_page_lid_data(struct nvme_dev *dev,
|
||||
void **cbs_data,
|
||||
__u8 lid,
|
||||
|
@ -2371,6 +2650,78 @@ end:
|
|||
return found;
|
||||
}
|
||||
|
||||
static bool get_dev_mgment_data(nvme_root_t r, struct nvme_dev *dev,
|
||||
void **data)
|
||||
{
|
||||
bool found = false;
|
||||
*data = NULL;
|
||||
__u32 device_id = 0, vendor_id = 0;
|
||||
bool uuid_present = false;
|
||||
int index = 0, uuid_index = 0;
|
||||
struct nvme_id_uuid_list uuid_list;
|
||||
|
||||
/* The wdc_get_pci_ids function could fail when drives are connected
|
||||
* via a PCIe switch. Therefore, the return code is intentionally
|
||||
* being ignored. The device_id and vendor_id variables have been
|
||||
* initialized to 0 so the code can continue on without issue for
|
||||
* both cases: wdc_get_pci_ids successful or failed.
|
||||
*/
|
||||
wdc_get_pci_ids(r, dev, &device_id, &vendor_id);
|
||||
|
||||
typedef struct nvme_id_uuid_list_entry *uuid_list_entry;
|
||||
|
||||
memset(&uuid_list, 0, sizeof(struct nvme_id_uuid_list));
|
||||
if (wdc_CheckUuidListSupport(dev, &uuid_list)) {
|
||||
uuid_list_entry uuid_list_entry_ptr = (uuid_list_entry)&uuid_list.entry[0];
|
||||
|
||||
while (index <= NVME_ID_UUID_LIST_MAX &&
|
||||
!wdc_UuidEqual(uuid_list_entry_ptr, (uuid_list_entry)UUID_END)) {
|
||||
|
||||
if (wdc_UuidEqual(uuid_list_entry_ptr,
|
||||
(uuid_list_entry)WDC_UUID)) {
|
||||
uuid_present = true;
|
||||
break;
|
||||
} else if (wdc_UuidEqual(uuid_list_entry_ptr,
|
||||
(uuid_list_entry)WDC_UUID_SN640_3) &&
|
||||
wdc_is_sn640_3(device_id)) {
|
||||
uuid_present = true;
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
uuid_list_entry_ptr = (uuid_list_entry)&uuid_list.entry[index];
|
||||
}
|
||||
if (uuid_present)
|
||||
uuid_index = index + 1;
|
||||
}
|
||||
|
||||
if (uuid_present) {
|
||||
/* use the uuid index found above */
|
||||
found = get_dev_mgmt_log_page_data(dev, data, uuid_index);
|
||||
} else {
|
||||
if (!uuid_index && needs_c2_log_page_check(device_id)) {
|
||||
/* In certain devices that don't support UUID lists, there are multiple
|
||||
* definitions of the C2 logpage. In those cases, the code
|
||||
* needs to try two UUID indexes and use an identification algorithm
|
||||
* to determine which is returning the correct log page data.
|
||||
*/
|
||||
uuid_index = 1;
|
||||
}
|
||||
|
||||
found = get_dev_mgmt_log_page_data(dev, data, uuid_index);
|
||||
|
||||
if (!found) {
|
||||
/* not found with uuid = 1 try with uuid = 0 */
|
||||
uuid_index = 0;
|
||||
fprintf(stderr, "Not found, requesting log page with uuid_index %d\n",
|
||||
uuid_index);
|
||||
|
||||
found = get_dev_mgmt_log_page_data(dev, data, uuid_index);
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static bool get_dev_mgment_cbs_data(nvme_root_t r, struct nvme_dev *dev,
|
||||
__u8 log_id, void **cbs_data)
|
||||
{
|
||||
|
@ -2485,6 +2836,22 @@ static bool wdc_nvme_check_supported_log_page(nvme_root_t r, struct nvme_dev *de
|
|||
return found;
|
||||
}
|
||||
|
||||
static bool wdc_nvme_parse_dev_status_log_entry(void *log_data, __u32 *ret_data,
|
||||
__u32 entry_id)
|
||||
{
|
||||
struct wdc_c2_log_subpage_header *entry_data = NULL;
|
||||
|
||||
if (wdc_parse_dev_mng_log_entry(log_data, entry_id, &entry_data)) {
|
||||
if (entry_data) {
|
||||
*ret_data = le32_to_cpu(entry_data->data);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
*ret_data = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool wdc_nvme_get_dev_status_log_data(nvme_root_t r, struct nvme_dev *dev, __le32 *ret_data,
|
||||
__u8 log_id)
|
||||
{
|
||||
|
@ -8609,12 +8976,13 @@ static int wdc_drive_status(int argc, char **argv, struct command *command,
|
|||
struct nvme_dev *dev;
|
||||
int ret = 0;
|
||||
nvme_root_t r;
|
||||
__le32 system_eol_state;
|
||||
__le32 user_eol_state;
|
||||
__le32 format_corrupt_reason = cpu_to_le32(0xFFFFFFFF);
|
||||
__le32 eol_status;
|
||||
__le32 assert_status = cpu_to_le32(0xFFFFFFFF);
|
||||
__le32 thermal_status = cpu_to_le32(0xFFFFFFFF);
|
||||
void *dev_mng_log = NULL;
|
||||
__u32 system_eol_state;
|
||||
__u32 user_eol_state;
|
||||
__u32 format_corrupt_reason = 0xFFFFFFFF;
|
||||
__u32 eol_status;
|
||||
__u32 assert_status = 0xFFFFFFFF;
|
||||
__u32 thermal_status = 0xFFFFFFFF;
|
||||
__u64 capabilities = 0;
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
|
@ -8641,35 +9009,41 @@ static int wdc_drive_status(int argc, char **argv, struct command *command,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (!get_dev_mgment_data(r, dev, &dev_mng_log)) {
|
||||
fprintf(stderr, "ERROR: WDC: 0xC2 Log Page not found\n");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Get the assert dump present status */
|
||||
if (!wdc_nvme_get_dev_status_log_data(r, dev, &assert_status,
|
||||
if (!wdc_nvme_parse_dev_status_log_entry(dev_mng_log, &assert_status,
|
||||
WDC_C2_ASSERT_DUMP_PRESENT_ID))
|
||||
fprintf(stderr, "ERROR: WDC: Get Assert Status Failed\n");
|
||||
|
||||
/* Get the thermal throttling status */
|
||||
if (!wdc_nvme_get_dev_status_log_data(r, dev, &thermal_status,
|
||||
if (!wdc_nvme_parse_dev_status_log_entry(dev_mng_log, &thermal_status,
|
||||
WDC_C2_THERMAL_THROTTLE_STATUS_ID))
|
||||
fprintf(stderr, "ERROR: WDC: Get Thermal Throttling Status Failed\n");
|
||||
|
||||
/* Get EOL status */
|
||||
if (!wdc_nvme_get_dev_status_log_data(r, dev, &eol_status,
|
||||
if (!wdc_nvme_parse_dev_status_log_entry(dev_mng_log, &eol_status,
|
||||
WDC_C2_USER_EOL_STATUS_ID)) {
|
||||
fprintf(stderr, "ERROR: WDC: Get User EOL Status Failed\n");
|
||||
eol_status = cpu_to_le32(-1);
|
||||
}
|
||||
|
||||
/* Get Customer EOL state */
|
||||
if (!wdc_nvme_get_dev_status_log_data(r, dev, &user_eol_state,
|
||||
if (!wdc_nvme_parse_dev_status_log_entry(dev_mng_log, &user_eol_state,
|
||||
WDC_C2_USER_EOL_STATE_ID))
|
||||
fprintf(stderr, "ERROR: WDC: Get User EOL State Failed\n");
|
||||
|
||||
/* Get System EOL state*/
|
||||
if (!wdc_nvme_get_dev_status_log_data(r, dev, &system_eol_state,
|
||||
if (!wdc_nvme_parse_dev_status_log_entry(dev_mng_log, &system_eol_state,
|
||||
WDC_C2_SYSTEM_EOL_STATE_ID))
|
||||
fprintf(stderr, "ERROR: WDC: Get System EOL State Failed\n");
|
||||
|
||||
/* Get format corrupt reason*/
|
||||
if (!wdc_nvme_get_dev_status_log_data(r, dev, &format_corrupt_reason,
|
||||
if (!wdc_nvme_parse_dev_status_log_entry(dev_mng_log, &format_corrupt_reason,
|
||||
WDC_C2_FORMAT_CORRUPT_REASON_ID))
|
||||
fprintf(stderr, "ERROR: WDC: Get Format Corrupt Reason Failed\n");
|
||||
|
||||
|
@ -8716,6 +9090,7 @@ static int wdc_drive_status(int argc, char **argv, struct command *command,
|
|||
else
|
||||
printf(" Format Corrupt Reason: Unknown : 0x%08x\n", le32_to_cpu(format_corrupt_reason));
|
||||
|
||||
free(dev_mng_log);
|
||||
out:
|
||||
nvme_free_tree(r);
|
||||
dev_close(dev);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#if !defined(WDC_NVME) || defined(CMD_HEADER_MULTI_READ)
|
||||
#define WDC_NVME
|
||||
|
||||
#define WDC_PLUGIN_VERSION "2.11.1"
|
||||
#define WDC_PLUGIN_VERSION "2.12.0"
|
||||
#include "cmd.h"
|
||||
|
||||
PLUGIN(NAME("wdc", "Western Digital vendor specific extensions", WDC_PLUGIN_VERSION),
|
||||
|
|
|
@ -81,7 +81,7 @@ int wdc_UtilsGetTime(PUtilsTimeInfo timeInfo)
|
|||
timeInfo->second = currTimeInfo.tm_sec;
|
||||
timeInfo->msecs = 0;
|
||||
timeInfo->isDST = currTimeInfo.tm_isdst;
|
||||
#if defined(__GLIBC__) && !defined(__UCLIBC__) && !defined(__MUSL__)
|
||||
#if (defined(__GLIBC__) && !defined(__UCLIBC__) && !defined(__MUSL__)) || defined(__FreeBSD__)
|
||||
timeInfo->zone = -currTimeInfo.tm_gmtoff / 60;
|
||||
#else
|
||||
timeInfo->zone = -1 * (timezone / SECONDS_IN_MIN);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue