summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2023-12-24 07:57:54 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2023-12-24 07:57:54 +0000
commit66e4b69042cd3b44acd42f1fad2109180c1bc48b (patch)
tree8bd8e664ae856167566375357963062e8112f181 /plugins
parentReleasing debian version 2.5-1. (diff)
downloadnvme-cli-66e4b69042cd3b44acd42f1fad2109180c1bc48b.tar.xz
nvme-cli-66e4b69042cd3b44acd42f1fad2109180c1bc48b.zip
Merging upstream version 2.7.1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'plugins')
-rw-r--r--plugins/fdp/fdp.c10
-rw-r--r--plugins/huawei/huawei-nvme.c8
-rw-r--r--plugins/intel/intel-nvme.c8
-rw-r--r--plugins/memblaze/memblaze-nvme.c645
-rw-r--r--plugins/memblaze/memblaze-nvme.h3
-rw-r--r--plugins/memblaze/memblaze-utils.h4
-rw-r--r--plugins/micron/micron-nvme.c13
-rw-r--r--plugins/nbft/nbft-plugin.c2
-rw-r--r--plugins/ocp/meson.build2
-rw-r--r--plugins/ocp/ocp-clear-features.c93
-rw-r--r--plugins/ocp/ocp-clear-features.h12
-rw-r--r--plugins/ocp/ocp-clear-fw-update-history.c20
-rw-r--r--plugins/ocp/ocp-clear-fw-update-history.h10
-rw-r--r--plugins/ocp/ocp-fw-activation-history.c12
-rw-r--r--plugins/ocp/ocp-nvme.c1213
-rw-r--r--plugins/ocp/ocp-nvme.h8
-rw-r--r--plugins/ocp/ocp-smart-extended-log.c12
-rw-r--r--plugins/ocp/ocp-utils.c63
-rw-r--r--plugins/ocp/ocp-utils.h4
-rw-r--r--plugins/scaleflux/sfx-nvme.c21
-rw-r--r--plugins/seagate/seagate-nvme.c6
-rw-r--r--plugins/solidigm/meson.build3
-rw-r--r--plugins/solidigm/solidigm-garbage-collection.c6
-rw-r--r--plugins/solidigm/solidigm-get-drive-info.c79
-rw-r--r--plugins/solidigm/solidigm-get-drive-info.h8
-rw-r--r--plugins/solidigm/solidigm-internal-logs.c34
-rw-r--r--plugins/solidigm/solidigm-latency-tracking.c4
-rw-r--r--plugins/solidigm/solidigm-log-page-dir.c46
-rw-r--r--plugins/solidigm/solidigm-nvme.c27
-rw-r--r--plugins/solidigm/solidigm-nvme.h6
-rw-r--r--plugins/solidigm/solidigm-ocp-version.c25
-rw-r--r--plugins/solidigm/solidigm-ocp-version.h8
-rw-r--r--plugins/solidigm/solidigm-smart.c12
-rw-r--r--plugins/solidigm/solidigm-telemetry.c35
-rw-r--r--plugins/solidigm/solidigm-telemetry/config.c2
-rw-r--r--plugins/solidigm/solidigm-telemetry/data-area.c2
-rw-r--r--plugins/solidigm/solidigm-telemetry/nlog.c5
-rw-r--r--plugins/solidigm/solidigm-temp-stats.c108
-rw-r--r--plugins/solidigm/solidigm-temp-stats.h8
-rw-r--r--plugins/solidigm/solidigm-util.h2
-rw-r--r--plugins/wdc/wdc-nvme.c1833
-rw-r--r--plugins/wdc/wdc-nvme.h88
-rw-r--r--plugins/wdc/wdc-utils.c46
-rw-r--r--plugins/wdc/wdc-utils.h4
-rw-r--r--plugins/ymtc/ymtc-nvme.c2
-rw-r--r--plugins/ymtc/ymtc-utils.h2
-rw-r--r--plugins/zns/zns.c67
-rw-r--r--plugins/zns/zns.h2
48 files changed, 3948 insertions, 685 deletions
diff --git a/plugins/fdp/fdp.c b/plugins/fdp/fdp.c
index 8539e18..2a221f8 100644
--- a/plugins/fdp/fdp.c
+++ b/plugins/fdp/fdp.c
@@ -56,7 +56,7 @@ static int fdp_configs(int argc, char **argv, struct command *cmd,
if (err)
return err;
- err = flags = validate_output_format(cfg.output_format);
+ err = validate_output_format(cfg.output_format, &flags);
if (flags < 0)
goto out;
@@ -137,7 +137,7 @@ static int fdp_usage(int argc, char **argv, struct command *cmd, struct plugin *
if (err)
return err;
- err = flags = validate_output_format(cfg.output_format);
+ err = validate_output_format(cfg.output_format, &flags);
if (flags < 0)
goto out;
@@ -208,7 +208,7 @@ static int fdp_stats(int argc, char **argv, struct command *cmd, struct plugin *
if (err)
return err;
- err = flags = validate_output_format(cfg.output_format);
+ err = validate_output_format(cfg.output_format, &flags);
if (flags < 0)
goto out;
@@ -269,7 +269,7 @@ static int fdp_events(int argc, char **argv, struct command *cmd, struct plugin
if (err)
return err;
- err = flags = validate_output_format(cfg.output_format);
+ err = validate_output_format(cfg.output_format, &flags);
if (flags < 0)
goto out;
@@ -328,7 +328,7 @@ static int fdp_status(int argc, char **argv, struct command *cmd, struct plugin
if (err)
return err;
- err = flags = validate_output_format(cfg.output_format);
+ err = validate_output_format(cfg.output_format, &flags);
if (flags < 0)
goto out;
diff --git a/plugins/huawei/huawei-nvme.c b/plugins/huawei/huawei-nvme.c
index 82e190f..0272dea 100644
--- a/plugins/huawei/huawei-nvme.c
+++ b/plugins/huawei/huawei-nvme.c
@@ -296,7 +296,7 @@ static int huawei_list(int argc, char **argv, struct command *command,
struct huawei_list_item *list_items;
unsigned int i, n, ret;
unsigned int huawei_num = 0;
- int fmt;
+ enum nvme_print_flags fmt;
const char *desc = "Retrieve basic information for the given huawei device";
struct config {
char *output_format;
@@ -315,9 +315,9 @@ static int huawei_list(int argc, char **argv, struct command *command,
if (ret)
return ret;
- fmt = validate_output_format(cfg.output_format);
- if (fmt != JSON && fmt != NORMAL)
- return -EINVAL;
+ ret = validate_output_format(cfg.output_format, &fmt);
+ if (ret < 0 || (fmt != JSON && fmt != NORMAL))
+ return ret;
n = scandir("/dev", &devices, nvme_namespace_filter, alphasort);
if (n <= 0)
diff --git a/plugins/intel/intel-nvme.c b/plugins/intel/intel-nvme.c
index e62c85d..378ecc0 100644
--- a/plugins/intel/intel-nvme.c
+++ b/plugins/intel/intel-nvme.c
@@ -1065,7 +1065,7 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct
media_version[1] = (data[3] << 8) | data[2];
if (err)
- goto close_fd;
+ goto close_dev;
if (media_version[0] == 1000) {
__u32 thresholds[OPTANE_V1000_BUCKET_LEN] = {0};
@@ -1086,9 +1086,9 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct
};
err = nvme_get_features(&args);
if (err) {
- fprintf(stderr, "Quering thresholds failed. ");
+ fprintf(stderr, "Querying thresholds failed. ");
nvme_show_status(err);
- goto close_fd;
+ goto close_dev;
}
/* Update bucket thresholds to be printed */
@@ -1124,7 +1124,7 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct
sizeof(stats));
}
-close_fd:
+close_dev:
dev_close(dev);
return err;
}
diff --git a/plugins/memblaze/memblaze-nvme.c b/plugins/memblaze/memblaze-nvme.c
index c0a70ee..b215125 100644
--- a/plugins/memblaze/memblaze-nvme.c
+++ b/plugins/memblaze/memblaze-nvme.c
@@ -646,7 +646,7 @@ static int glp_high_latency_show_bar(FILE *fdi, int print)
}
/*
- * High latency log page definiton
+ * High latency log page definition
* Total 32 bytes
*/
struct log_page_high_latency {
@@ -1197,3 +1197,646 @@ static int mb_set_lat_stats(int argc, char **argv,
dev_close(dev);
return err;
}
+
+// Global definitions
+
+static inline int K2C(int k) // KELVINS_2_CELSIUS
+{
+ return (k - 273);
+};
+
+// Global ID definitions
+
+enum {
+ // feature ids
+ FID_LATENCY_FEATURE = 0xd0,
+
+ // log ids
+ LID_SMART_LOG_ADD = 0xca,
+ LID_LATENCY_STATISTICS = 0xd0,
+ LID_HIGH_LATENCY_LOG = 0xd1,
+ LID_PERFORMANCE_STATISTICS = 0xd2,
+};
+
+// smart-log-add
+
+struct smart_log_add_item {
+ uint32_t index;
+ char *attr;
+};
+
+struct __packed wear_level {
+ __le16 min;
+ __le16 max;
+ __le16 avg;
+};
+
+struct __packed smart_log_add_item_12 {
+ uint8_t id;
+ uint8_t rsvd[2];
+ uint8_t norm;
+ uint8_t rsvd1;
+ union {
+ struct wear_level wear_level; // 0xad
+ struct temp_since_born { // 0xe7
+ __le16 max;
+ __le16 min;
+ __le16 curr;
+ } temp_since_born;
+ struct power_consumption { // 0xe8
+ __le16 max;
+ __le16 min;
+ __le16 curr;
+ } power_consumption;
+ struct temp_since_power_on { // 0xaf
+ __le16 max;
+ __le16 min;
+ __le16 curr;
+ } temp_since_power_on;
+ uint8_t raw[6];
+ };
+ uint8_t rsvd2;
+};
+
+struct __packed smart_log_add_item_10 {
+ uint8_t id;
+ uint8_t norm;
+ union {
+ struct wear_level wear_level; // 0xad
+ uint8_t raw[6];
+ };
+ uint8_t rsvd[2];
+};
+
+struct smart_log_add {
+ union {
+ union {
+ struct smart_log_add_v0 {
+ struct smart_log_add_item_12 program_fail_count;
+ struct smart_log_add_item_12 erase_fail_count;
+ struct smart_log_add_item_12 wear_leveling_count;
+ struct smart_log_add_item_12 end_to_end_error_count;
+ struct smart_log_add_item_12 crc_error_count;
+ struct smart_log_add_item_12 timed_workload_media_wear;
+ struct smart_log_add_item_12 timed_workload_host_reads;
+ struct smart_log_add_item_12 timed_workload_timer;
+ struct smart_log_add_item_12 thermal_throttle_status;
+ struct smart_log_add_item_12 retry_buffer_overflow_counter;
+ struct smart_log_add_item_12 pll_lock_loss_count;
+ struct smart_log_add_item_12 nand_bytes_written;
+ struct smart_log_add_item_12 host_bytes_written;
+ struct smart_log_add_item_12 system_area_life_remaining;
+ struct smart_log_add_item_12 nand_bytes_read;
+ struct smart_log_add_item_12 temperature;
+ struct smart_log_add_item_12 power_consumption;
+ struct smart_log_add_item_12 power_on_temperature;
+ struct smart_log_add_item_12 power_loss_protection;
+ struct smart_log_add_item_12 read_fail_count;
+ struct smart_log_add_item_12 thermal_throttle_time;
+ struct smart_log_add_item_12 flash_error_media_count;
+ } v0;
+
+ struct smart_log_add_item_12 v0_raw[22];
+ };
+
+ union {
+ struct smart_log_add_v2 {
+ struct smart_log_add_item_12 program_fail_count;
+ struct smart_log_add_item_12 erase_fail_count;
+ struct smart_log_add_item_12 wear_leveling_count;
+ struct smart_log_add_item_12 end_to_end_error_count;
+ struct smart_log_add_item_12 crc_error_count;
+ struct smart_log_add_item_12 timed_workload_media_wear;
+ struct smart_log_add_item_12 timed_workload_host_reads;
+ struct smart_log_add_item_12 timed_workload_timer;
+ struct smart_log_add_item_12 thermal_throttle_status;
+ struct smart_log_add_item_12 lifetime_write_amplification;
+ struct smart_log_add_item_12 pll_lock_loss_count;
+ struct smart_log_add_item_12 nand_bytes_written;
+ struct smart_log_add_item_12 host_bytes_written;
+ struct smart_log_add_item_12 system_area_life_remaining;
+ struct smart_log_add_item_12 firmware_update_count;
+ struct smart_log_add_item_12 dram_cecc_count;
+ struct smart_log_add_item_12 dram_uecc_count;
+ struct smart_log_add_item_12 xor_pass_count;
+ struct smart_log_add_item_12 xor_fail_count;
+ struct smart_log_add_item_12 xor_invoked_count;
+ struct smart_log_add_item_12 inflight_read_io_cmd;
+ struct smart_log_add_item_12 flash_error_media_count;
+ struct smart_log_add_item_12 nand_bytes_read;
+ struct smart_log_add_item_12 temp_since_born;
+ struct smart_log_add_item_12 power_consumption;
+ struct smart_log_add_item_12 temp_since_bootup;
+ struct smart_log_add_item_12 thermal_throttle_time;
+ } v2;
+
+ struct smart_log_add_item_12 v2_raw[27];
+ };
+
+ union {
+ struct smart_log_add_v3 {
+ struct smart_log_add_item_10 program_fail_count;
+ struct smart_log_add_item_10 erase_fail_count;
+ struct smart_log_add_item_10 wear_leveling_count;
+ struct smart_log_add_item_10 ext_e2e_err_count;
+ struct smart_log_add_item_10 crc_err_count;
+ struct smart_log_add_item_10 nand_bytes_written;
+ struct smart_log_add_item_10 host_bytes_written;
+ struct smart_log_add_item_10 reallocated_sector_count;
+ struct smart_log_add_item_10 uncorrectable_sector_count;
+ struct smart_log_add_item_10 nand_uecc_detection;
+ struct smart_log_add_item_10 nand_xor_correction;
+ struct smart_log_add_item_10 gc_count;
+ struct smart_log_add_item_10 dram_uecc_detection_count;
+ struct smart_log_add_item_10 sram_uecc_detection_count;
+ struct smart_log_add_item_10 internal_raid_recovery_fail_count;
+ struct smart_log_add_item_10 inflight_cmds;
+ struct smart_log_add_item_10 internal_e2e_err_count;
+ struct smart_log_add_item_10 die_fail_count;
+ struct smart_log_add_item_10 wear_leveling_execution_count;
+ struct smart_log_add_item_10 read_disturb_count;
+ struct smart_log_add_item_10 data_retention_count;
+ struct smart_log_add_item_10 capacitor_health;
+ } v3;
+
+ struct smart_log_add_item_10 v3_raw[24];
+ };
+
+ uint8_t raw[512];
+ };
+};
+
+static void smart_log_add_v0_print(struct smart_log_add_item_12 *item, int item_count)
+{
+ static const struct smart_log_add_item items[0xff] = {
+ [0xab] = {0, "program_fail_count" },
+ [0xac] = {1, "erase_fail_count" },
+ [0xad] = {2, "wear_leveling_count" },
+ [0xb8] = {3, "end_to_end_error_count" },
+ [0xc7] = {4, "crc_error_count" },
+ [0xe2] = {5, "timed_workload_media_wear" },
+ [0xe3] = {6, "timed_workload_host_reads" },
+ [0xe4] = {7, "timed_workload_timer" },
+ [0xea] = {8, "thermal_throttle_status" },
+ [0xf0] = {9, "retry_buffer_overflow_counter"},
+ [0xf3] = {10, "pll_lock_loss_count" },
+ [0xf4] = {11, "nand_bytes_written" },
+ [0xf5] = {12, "host_bytes_written" },
+ [0xf6] = {13, "system_area_life_remaining" },
+ [0xfa] = {14, "nand_bytes_read" },
+ [0xe7] = {15, "temperature" },
+ [0xe8] = {16, "power_consumption" },
+ [0xaf] = {17, "power_on_temperature" },
+ [0xec] = {18, "power_loss_protection" },
+ [0xf2] = {19, "read_fail_count" },
+ [0xeb] = {20, "thermal_throttle_time" },
+ [0xed] = {21, "flash_error_media_count" },
+ };
+
+ for (int i = 0; i < item_count; i++, item++) {
+ if (item->id == 0)
+ continue;
+
+ printf("%#-12" PRIx8 "%-36s%-12d", item->id, items[item->id].attr, item->norm);
+ switch (item->id) {
+ case 0xad:
+ printf("min: %d, max: %d, avg: %d\n",
+ le16_to_cpu(item->wear_level.min),
+ le16_to_cpu(item->wear_level.max),
+ le16_to_cpu(item->wear_level.avg));
+ break;
+ case 0xe7:
+ printf("max: %d °C (%d K), min: %d °C (%d K), curr: %d °C (%d K)\n",
+ K2C(le16_to_cpu(item->temp_since_born.max)),
+ le16_to_cpu(item->temp_since_born.max),
+ K2C(le16_to_cpu(item->temp_since_born.min)),
+ le16_to_cpu(item->temp_since_born.min),
+ K2C(le16_to_cpu(item->temp_since_born.curr)),
+ le16_to_cpu(item->temp_since_born.curr));
+ break;
+ case 0xe8:
+ printf("max: %d, min: %d, curr: %d\n",
+ le16_to_cpu(item->power_consumption.max),
+ le16_to_cpu(item->power_consumption.min),
+ le16_to_cpu(item->power_consumption.curr));
+ break;
+ case 0xaf:
+ printf("max: %d °C (%d K), min: %d °C (%d K), curr: %d °C (%d K)\n",
+ K2C(le16_to_cpu(item->temp_since_power_on.max)),
+ le16_to_cpu(item->temp_since_power_on.max),
+ K2C(le16_to_cpu(item->temp_since_power_on.min)),
+ le16_to_cpu(item->temp_since_power_on.min),
+ K2C(le16_to_cpu(item->temp_since_power_on.curr)),
+ le16_to_cpu(item->temp_since_power_on.curr));
+ break;
+ default:
+ printf("%" PRIu64 "\n", int48_to_long(item->raw));
+ break;
+ }
+ }
+}
+
+static void smart_log_add_v2_print(struct smart_log_add_item_12 *item, int item_count)
+{
+ static const struct smart_log_add_item items[0xff] = {
+ [0xab] = {0, "program_fail_count" },
+ [0xac] = {1, "erase_fail_count" },
+ [0xad] = {2, "wear_leveling_count" },
+ [0xb8] = {3, "end_to_end_error_count" },
+ [0xc7] = {4, "crc_error_count" },
+ [0xe2] = {5, "timed_workload_media_wear" },
+ [0xe3] = {6, "timed_workload_host_reads" },
+ [0xe4] = {7, "timed_workload_timer" },
+ [0xea] = {8, "thermal_throttle_status" },
+ [0xf0] = {9, "lifetime_write_amplification"},
+ [0xf3] = {10, "pll_lock_loss_count" },
+ [0xf4] = {11, "nand_bytes_written" },
+ [0xf5] = {12, "host_bytes_written" },
+ [0xf6] = {13, "system_area_life_remaining" },
+ [0xf9] = {14, "firmware_update_count" },
+ [0xfa] = {15, "dram_cecc_count" },
+ [0xfb] = {16, "dram_uecc_count" },
+ [0xfc] = {17, "xor_pass_count" },
+ [0xfd] = {18, "xor_fail_count" },
+ [0xfe] = {19, "xor_invoked_count" },
+ [0xe5] = {20, "inflight_read_io_cmd" },
+ [0xe6] = {21, "flash_error_media_count" },
+ [0xf8] = {22, "nand_bytes_read" },
+ [0xe7] = {23, "temp_since_born" },
+ [0xe8] = {24, "power_consumption" },
+ [0xaf] = {25, "temp_since_bootup" },
+ [0xeb] = {26, "thermal_throttle_time" },
+ };
+
+ for (int i = 0; i < item_count; i++, item++) {
+ if (item->id == 0)
+ continue;
+
+ printf("%#-12" PRIx8 "%-36s%-12d", item->id, items[item->id].attr, item->norm);
+ switch (item->id) {
+ case 0xad:
+ printf("min: %d, max: %d, avg: %d\n",
+ le16_to_cpu(item->wear_level.min),
+ le16_to_cpu(item->wear_level.max),
+ le16_to_cpu(item->wear_level.avg));
+ break;
+ case 0xe7:
+ printf("max: %d °C (%d K), min: %d °C (%d K), curr: %d °C (%d K)\n",
+ K2C(le16_to_cpu(item->temp_since_born.max)),
+ le16_to_cpu(item->temp_since_born.max),
+ K2C(le16_to_cpu(item->temp_since_born.min)),
+ le16_to_cpu(item->temp_since_born.min),
+ K2C(le16_to_cpu(item->temp_since_born.curr)),
+ le16_to_cpu(item->temp_since_born.curr));
+ break;
+ case 0xe8:
+ printf("max: %d, min: %d, curr: %d\n",
+ le16_to_cpu(item->power_consumption.max),
+ le16_to_cpu(item->power_consumption.min),
+ le16_to_cpu(item->power_consumption.curr));
+ break;
+ case 0xaf:
+ printf("max: %d °C (%d K), min: %d °C (%d K), curr: %d °C (%d K)\n",
+ K2C(le16_to_cpu(item->temp_since_power_on.max)),
+ le16_to_cpu(item->temp_since_power_on.max),
+ K2C(le16_to_cpu(item->temp_since_power_on.min)),
+ le16_to_cpu(item->temp_since_power_on.min),
+ K2C(le16_to_cpu(item->temp_since_power_on.curr)),
+ le16_to_cpu(item->temp_since_power_on.curr));
+ break;
+ default:
+ printf("%" PRIu64 "\n", int48_to_long(item->raw));
+ break;
+ }
+ }
+}
+
+static void smart_log_add_v3_print(struct smart_log_add_item_10 *item, int item_count)
+{
+ static const struct smart_log_add_item items[0xff] = {
+ [0xab] = {0, "program_fail_count" },
+ [0xac] = {1, "erase_fail_count" },
+ [0xad] = {2, "wear_leveling_count" },
+ [0xb8] = {3, "ext_e2e_err_count" },
+ [0xc7] = {4, "crc_err_count" },
+ [0xf4] = {5, "nand_bytes_written" },
+ [0xf5] = {6, "host_bytes_written" },
+ [0xd0] = {7, "reallocated_sector_count" },
+ [0xd1] = {8, "uncorrectable_sector_count" },
+ [0xd2] = {9, "nand_uecc_detection" },
+ [0xd3] = {10, "nand_xor_correction" },
+ [0xd4] = {12, "gc_count" }, // 11 is reserved
+ [0xd5] = {13, "dram_uecc_detection_count" },
+ [0xd6] = {14, "sram_uecc_detection_count" },
+ [0xd7] = {15, "internal_raid_recovery_fail_count"},
+ [0xd8] = {16, "inflight_cmds" },
+ [0xd9] = {17, "internal_e2e_err_count" },
+ [0xda] = {19, "die_fail_count" }, // 18 is reserved
+ [0xdb] = {20, "wear_leveling_execution_count" },
+ [0xdc] = {21, "read_disturb_count" },
+ [0xdd] = {22, "data_retention_count" },
+ [0xde] = {23, "capacitor_health" },
+ };
+
+ for (int i = 0; i < item_count; i++, item++) {
+ if (item->id == 0)
+ continue;
+
+ printf("%#-12" PRIx8 "%-36s%-12d", item->id, items[item->id].attr, item->norm);
+ switch (item->id) {
+ case 0xad:
+ printf("min: %d, max: %d, avg: %d\n",
+ le16_to_cpu(item->wear_level.min),
+ le16_to_cpu(item->wear_level.max),
+ le16_to_cpu(item->wear_level.avg));
+ break;
+ default:
+ printf("%" PRIu64 "\n", int48_to_long(item->raw));
+ break;
+ }
+ }
+}
+
+static void smart_log_add_print(struct smart_log_add *log, const char *devname)
+{
+ uint8_t version = log->raw[511];
+
+ printf("Version: %u\n", version);
+ printf("\n");
+ printf("Additional Smart Log for NVMe device: %s\n", devname);
+ printf("\n");
+
+ printf("%-12s%-36s%-12s%s\n", "Id", "Key", "Normalized", "Raw");
+
+ switch (version) {
+ case 0:
+ return smart_log_add_v0_print(&log->v0_raw[0],
+ sizeof(struct smart_log_add_v0) / sizeof(struct smart_log_add_item_12));
+ case 2:
+ return smart_log_add_v2_print(&log->v2_raw[0],
+ sizeof(struct smart_log_add_v2) / sizeof(struct smart_log_add_item_12));
+ case 3:
+ return smart_log_add_v3_print(&log->v3_raw[0],
+ sizeof(struct smart_log_add_v3) / sizeof(struct smart_log_add_item_10));
+
+ case 1:
+ fprintf(stderr, "Version %d: N/A\n", version);
+ break;
+ default:
+ fprintf(stderr, "Version %d: Not supported yet\n", version);
+ break;
+ }
+}
+
+static int mb_get_smart_log_add(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ int err = 0;
+
+ // Get the configuration
+
+ struct config {
+ bool raw_binary;
+ };
+
+ struct config cfg = {0};
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, "dump the whole log buffer in binary format"),
+ OPT_END()};
+
+ // Open device
+
+ struct nvme_dev *dev = NULL;
+
+ err = parse_and_open(&dev, argc, argv, cmd->help, opts);
+ if (err)
+ return err;
+
+ // Get log
+
+ struct smart_log_add log = {0};
+
+ err = nvme_get_log_simple(dev_fd(dev), LID_SMART_LOG_ADD, sizeof(struct smart_log_add), &log);
+ if (!err) {
+ if (!cfg.raw_binary)
+ smart_log_add_print(&log, dev->name);
+ else
+ d_raw((unsigned char *)&log, sizeof(struct smart_log_add));
+ } else if (err > 0) {
+ nvme_show_status(err);
+ } else {
+ nvme_show_error("%s: %s", cmd->name, nvme_strerror(errno));
+ }
+
+ // Close device
+
+ dev_close(dev);
+ return err;
+}
+
+// performance-monitor
+
+struct latency_stats_bucket {
+ char *start_threshold;
+ char *end_threshold;
+};
+
+struct __packed latency_stats {
+ union {
+ struct latency_stats_v2_0 {
+ uint32_t minor_version;
+ uint32_t major_version;
+ uint32_t bucket_read_data[32];
+ uint32_t rsvd[32];
+ uint32_t bucket_write_data[32];
+ uint32_t rsvd1[32];
+ uint32_t bucket_trim_data[32];
+ uint32_t rsvd2[32];
+ uint8_t rsvd3[248];
+ } v2_0;
+ uint8_t raw[1024];
+ };
+};
+
+struct __packed high_latency_log {
+ union {
+ struct high_latency_log_v1 {
+ uint32_t version;
+ struct high_latency_log_entry {
+ uint64_t timestamp; // ms
+ uint32_t latency;
+ uint32_t qid;
+ uint32_t opcode : 8;
+ uint32_t fuse : 2;
+ uint32_t psdt : 2;
+ uint32_t cid : 16;
+ uint32_t rsvd : 4;
+ uint32_t nsid;
+ uint64_t slba;
+ uint32_t nlb : 16;
+ uint32_t dtype : 8;
+ uint32_t pinfo : 4;
+ uint32_t fua : 1;
+ uint32_t lr : 1;
+ uint32_t rsvd1 : 2;
+ uint8_t rsvd2[28];
+ } entries[1024];
+ } v1;
+ uint8_t raw[4 + 1024 * 64];
+ };
+};
+
+struct __packed performance_stats {
+ union {
+ struct performance_stats_v1 {
+ uint8_t version;
+ uint8_t rsvd[3];
+ struct performance_stats_timestamp {
+ uint8_t timestamp[6];
+ struct performance_stats_entry {
+ uint16_t read_iops; // K IOPS
+ uint16_t read_bandwidth; // MiB
+ uint32_t read_latency; // us
+ uint32_t read_latency_max; // us
+ uint16_t write_iops; // K IOPS
+ uint16_t write_bandwidth; // MiB
+ uint32_t write_latency; // us
+ uint32_t write_latency_max; // us
+ } entries[3600];
+ } timestamps[24];
+ } v1;
+ uint8_t raw[4 + 24 * (6 + 3600 * 24)];
+ };
+};
+
+static int mb_set_latency_feature(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ int err = 0;
+
+ // Get the configuration
+
+ struct config {
+ uint32_t perf_monitor;
+ uint32_t cmd_mask;
+ uint32_t read_threshold;
+ uint32_t write_threshold;
+ uint32_t de_allocate_trim_threshold;
+ };
+
+ struct config cfg = {0};
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("sel-perf-log", 's', &cfg.perf_monitor,
+ "Select features to turn on, default: Disable\n"
+ " bit 0: latency statistics\n"
+ " bit 1: high latency log\n"
+ " bit 2: Performance stat"),
+ OPT_UINT("set-commands-mask", 'm', &cfg.cmd_mask,
+ "Set Enable, default: Disable\n"
+ " bit 0: Read commands\n"
+ " bit 1: high Write commands\n"
+ " bit 2: De-allocate/TRIM (this bit is not worked for Performance stat.)"),
+ OPT_UINT("set-read-threshold", 'r', &cfg.read_threshold,
+ "set read high latency log threshold, it's a 0-based value and unit is 10ms"),
+ OPT_UINT("set-write-threshold", 'w', &cfg.write_threshold,
+ "set write high latency log threshold, it's a 0-based value and unit is 10ms"),
+ OPT_UINT("set-trim-threshold", 't', &cfg.de_allocate_trim_threshold,
+ "set trim high latency log threshold, it's a 0-based value and unit is 10ms"),
+ OPT_END()};
+
+ // Open device
+
+ struct nvme_dev *dev = NULL;
+
+ err = parse_and_open(&dev, argc, argv, cmd->help, opts);
+ if (err)
+ return err;
+
+
+ // Set feature
+
+ uint32_t result = 0;
+
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = FID_LATENCY_FEATURE,
+ .nsid = 0,
+ .cdw11 = 0 | cfg.perf_monitor,
+ .cdw12 = 0 | cfg.cmd_mask,
+ .cdw13 = 0 |
+ (cfg.read_threshold & 0xff) |
+ ((cfg.write_threshold & 0xff) << 8) |
+ ((cfg.de_allocate_trim_threshold & 0xff) << 16),
+ .cdw15 = 0,
+ .save = 0,
+ .uuidx = 0,
+ .data = NULL,
+ .data_len = 0,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ err = nvme_set_features(&args);
+ if (!err)
+ printf("%s have done successfully. result = %#" PRIx32 ".\n", cmd->name, result);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("%s: %s", cmd->name, nvme_strerror(errno));
+
+ // Close device
+
+ dev_close(dev);
+ return err;
+}
+
+static int mb_get_latency_feature(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ int err = 0;
+
+ // Get the configuration
+
+ OPT_ARGS(opts) = {
+ OPT_END()};
+
+ // Open device
+
+ struct nvme_dev *dev = NULL;
+
+ err = parse_and_open(&dev, argc, argv, cmd->help, opts);
+ if (err)
+ return err;
+
+ // Get feature
+
+ uint32_t result = 0;
+
+ err = nvme_get_features_simple(dev_fd(dev), FID_LATENCY_FEATURE, 0, &result);
+ if (!err) {
+ printf("%s have done successfully. result = %#" PRIx32 ".\n", cmd->name, result);
+
+ printf("latency statistics enable status = %d\n", (result & (0x01 << 0)) >> 0);
+ printf("high latency enable status = %d\n", (result & (0x01 << 1)) >> 1);
+ printf("performance stat enable status = %d\n", (result & (0x01 << 2)) >> 2);
+
+ printf("Monitor Read command = %d\n", (result & (0x01 << 4)) >> 4);
+ printf("Monitor Write command = %d\n", (result & (0x01 << 5)) >> 5);
+ printf("Monitor Trim command = %d\n", (result & (0x01 << 6)) >> 6);
+
+ printf("Threshold for Read = %dms\n", (((result & (0xff << 8)) >> 8) + 1) * 10);
+ printf("Threshold for Write = %dms\n", (((result & (0xff << 16)) >> 16) + 1) * 10);
+ printf("Threshold for Trim = %dms\n", (((result & (0xff << 24)) >> 24) + 1) * 10);
+ } else if (err > 0) {
+ nvme_show_status(err);
+ } else {
+ nvme_show_error("%s: %s", cmd->name, nvme_strerror(errno));
+ }
+
+ // Close device
+
+ dev_close(dev);
+ return err;
+}
diff --git a/plugins/memblaze/memblaze-nvme.h b/plugins/memblaze/memblaze-nvme.h
index e214ca6..e25267b 100644
--- a/plugins/memblaze/memblaze-nvme.h
+++ b/plugins/memblaze/memblaze-nvme.h
@@ -18,6 +18,9 @@ PLUGIN(NAME("memblaze", "Memblaze vendor specific extensions", NVME_VERSION),
ENTRY("lat-log", "Set Memblaze High Latency Log", mb_set_high_latency_log)
ENTRY("lat-log-print", "Output Memblaze High Latency Log", mb_high_latency_log_print)
ENTRY("clear-error-log", "Clear error log", memblaze_clear_error_log)
+ ENTRY("smart-log-add-x", "Retrieve Memblaze SMART Log, show it", mb_get_smart_log_add)
+ ENTRY("lat-set-feature-x", "Set Enable/Disable for Latency Monitor feature", mb_set_latency_feature)
+ ENTRY("lat-get-feature-x", "Get Enabled/Disabled of Latency Monitor feature", mb_get_latency_feature)
)
);
diff --git a/plugins/memblaze/memblaze-utils.h b/plugins/memblaze/memblaze-utils.h
index dd89189..8914f95 100644
--- a/plugins/memblaze/memblaze-utils.h
+++ b/plugins/memblaze/memblaze-utils.h
@@ -34,7 +34,7 @@
#define RAISIN_SI_VD_THERMAL_THROTTLE_TIME_ID 0xEB
#define RAISIN_SI_VD_FLASH_MEDIA_ERROR_ID 0xED
-/* Raisin Addtional smart internal ID */
+/* Raisin Additional smart internal ID */
typedef enum
{
/* smart attr following intel */
@@ -154,7 +154,7 @@ struct nvme_p4_smart_log
/**
* change 512 to 4096.
* because micron's getlogpage request,the size of many commands have changed to 4k.
- * request size > user malloc size,casuing parameters that are closed in momery are dirty.
+ * request size > user malloc size,casuing parameters that are closed in memery are dirty.
*/
__u8 resv[SMART_INFO_NEW_SIZE - sizeof(struct nvme_p4_smart_log_item) * NR_SMART_ITEMS];
};
diff --git a/plugins/micron/micron-nvme.c b/plugins/micron/micron-nvme.c
index d6fb601..63a7a79 100644
--- a/plugins/micron/micron-nvme.c
+++ b/plugins/micron/micron-nvme.c
@@ -16,6 +16,7 @@
#include <limits.h>
#include "linux/types.h"
#include "nvme-print.h"
+#include "util/cleanup.h"
#define CREATE_CMD
#include "micron-nvme.h"
@@ -1767,10 +1768,10 @@ static void GetGenericLogs(int fd, const char *dir)
struct nvme_firmware_slot fw_log;
struct nvme_cmd_effects_log effects;
struct nvme_persistent_event_log pevent_log;
+ _cleanup_huge_ struct nvme_mem_huge mh = { 0, };
void *pevent_log_info = NULL;
__u32 log_len = 0;
int err = 0;
- bool huge = false;
/* get self test log */
if (!nvme_get_log_device_self_test(fd, &self_test_log))
@@ -1799,17 +1800,17 @@ static void GetGenericLogs(int fd, const char *dir)
}
log_len = le64_to_cpu(pevent_log.tll);
- pevent_log_info = nvme_alloc(log_len, &huge);
+ pevent_log_info = nvme_alloc_huge(log_len, &mh);
if (!pevent_log_info) {
perror("could not alloc buffer for persistent event log page (ignored)!\n");
return;
}
+
err = nvme_get_log_persistent_event(fd, NVME_PEVENT_LOG_READ,
log_len, pevent_log_info);
if (!err)
WriteData((__u8 *)pevent_log_info, log_len, dir,
"persistent_event_log.bin", "persistent event log");
- nvme_free(pevent_log_info, huge);
}
static void GetNSIDDInfo(int fd, const char *dir, int nsid)
@@ -2221,7 +2222,7 @@ static int display_fw_activate_entry(int entry_count, struct fw_activation_histo
else
sprintf(ptr, "| pass");
- /* replace all null charecters with spaces */
+ /* replace all null characters with spaces */
ptr = formatted_entry;
while (index < entry_size) {
if (ptr[index] == '\0')
@@ -2289,7 +2290,7 @@ static int micron_fw_activation_history(int argc, char **argv, struct command *c
goto out;
}
- /* check if we have atleast one entry to print */
+ /* check if we have at least one entry to print */
struct micron_fw_activation_history_table *table =
(struct micron_fw_activation_history_table *)logC2;
@@ -2696,7 +2697,7 @@ static int micron_ocp_smart_health_logs(int argc, char **argv, struct command *c
/* check for models that support 0xC0 log */
if (eModel != M51CX) {
- printf("Unsupported drive model for vs-smart-add-log commmand\n");
+ printf("Unsupported drive model for vs-smart-add-log command\n");
err = -1;
goto out;
}
diff --git a/plugins/nbft/nbft-plugin.c b/plugins/nbft/nbft-plugin.c
index e8b3fed..2193ffb 100644
--- a/plugins/nbft/nbft-plugin.c
+++ b/plugins/nbft/nbft-plugin.c
@@ -543,7 +543,7 @@ int show_nbft(int argc, char **argv, struct command *cmd, struct plugin *plugin)
if (ret)
return ret;
- ret = flags = validate_output_format(format);
+ ret = validate_output_format(format, &flags);
if (ret < 0)
return ret;
diff --git a/plugins/ocp/meson.build b/plugins/ocp/meson.build
index 405ee51..64447ff 100644
--- a/plugins/ocp/meson.build
+++ b/plugins/ocp/meson.build
@@ -1,7 +1,7 @@
sources += [
'plugins/ocp/ocp-utils.c',
'plugins/ocp/ocp-nvme.c',
- 'plugins/ocp/ocp-clear-fw-update-history.c',
+ 'plugins/ocp/ocp-clear-features.c',
'plugins/ocp/ocp-smart-extended-log.c',
'plugins/ocp/ocp-fw-activation-history.c',
]
diff --git a/plugins/ocp/ocp-clear-features.c b/plugins/ocp/ocp-clear-features.c
new file mode 100644
index 0000000..0f49584
--- /dev/null
+++ b/plugins/ocp/ocp-clear-features.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Authors: haro.panosyan@solidigm.com
+ * leonardo.da.cunha@solidigm.com
+ */
+
+#include <unistd.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;
+ __u32 clear = 1 << 31;
+ struct nvme_dev *dev;
+ int uuid_index = 0;
+ bool uuid = true;
+ int err;
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("no-uuid", 'n', NULL,
+ "Skip UUID index search (UUID index not required for OCP 1.0)"),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (opts[0].seen)
+ uuid = false;
+
+ if (uuid) {
+ /* OCP 2.0 requires UUID index support */
+ err = ocp_get_uuid_index(dev, &uuid_index);
+ if (err || !uuid_index) {
+ fprintf(stderr, "ERROR: No OCP UUID index found\n");
+ goto close_dev;
+ }
+ }
+
+ struct nvme_set_features_args args = {
+ .result = &result,
+ .data = NULL,
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .nsid = 0,
+ .cdw11 = clear,
+ .cdw12 = 0,
+ .cdw13 = 0,
+ .cdw15 = 0,
+ .data_len = 0,
+ .save = 0,
+ .uuidx = uuid_index,
+ .fid = fid,
+ };
+
+ err = nvme_set_features(&args);
+
+ if (err == 0)
+ printf("Success : %s\n", desc);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ printf("Fail : %s\n", desc);
+close_dev:
+ /* Redundant close() to make static code analysis happy */
+ close(dev->direct.fd);
+ dev_close(dev);
+ return err;
+}
+
+int ocp_clear_fw_update_history(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "OCP Clear Firmware Update History";
+
+ return ocp_clear_feature(argc, argv, desc, OCP_FID_CLEAR_FW_ACTIVATION_HISTORY);
+}
+
+int ocp_clear_pcie_correctable_errors(int argc, char **argv, struct command *cmd,
+ 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);
+}
diff --git a/plugins/ocp/ocp-clear-features.h b/plugins/ocp/ocp-clear-features.h
new file mode 100644
index 0000000..99766dd
--- /dev/null
+++ b/plugins/ocp/ocp-clear-features.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Authors: haro.panosyan@solidigm.com
+ * leonardo.da.cunha@solidigm.com
+ */
+
+int ocp_clear_fw_update_history(int argc, char **argv, struct command *cmd, struct plugin *plugin);
+
+int ocp_clear_pcie_correctable_errors(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin);
diff --git a/plugins/ocp/ocp-clear-fw-update-history.c b/plugins/ocp/ocp-clear-fw-update-history.c
deleted file mode 100644
index 6b256b1..0000000
--- a/plugins/ocp/ocp-clear-fw-update-history.c
+++ /dev/null
@@ -1,20 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (c) 2022 Solidigm.
- *
- * Authors: haro.panosyan@solidigm.com
- * leonardo.da.cunha@solidigm.com
- */
-
-#include <unistd.h>
-#include "ocp-utils.h"
-#include "nvme-print.h"
-
-static const __u8 OCP_FID_CLEAR_FW_ACTIVATION_HISTORY = 0xC1;
-
-int ocp_clear_fw_update_history(int argc, char **argv, struct command *cmd, struct plugin *plugin)
-{
- const char *desc = "OCP Clear Firmware Update History";
-
- return ocp_clear_feature(argc, argv, desc, OCP_FID_CLEAR_FW_ACTIVATION_HISTORY);
-}
diff --git a/plugins/ocp/ocp-clear-fw-update-history.h b/plugins/ocp/ocp-clear-fw-update-history.h
deleted file mode 100644
index cd0844c..0000000
--- a/plugins/ocp/ocp-clear-fw-update-history.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (c) 2022 Solidigm.
- *
- * Authors: haro.panosyan@solidigm.com
- * leonardo.da.cunha@solidigm.com
- */
-
-int ocp_clear_fw_update_history(int argc, char **argv,
- struct command *cmd, struct plugin *plugin);
diff --git a/plugins/ocp/ocp-fw-activation-history.c b/plugins/ocp/ocp-fw-activation-history.c
index b067346..ad96c6b 100644
--- a/plugins/ocp/ocp-fw-activation-history.c
+++ b/plugins/ocp/ocp-fw-activation-history.c
@@ -207,16 +207,18 @@ int ocp_fw_activation_history_log(int argc, char **argv, struct command *cmd,
}
if (!err) {
- const enum nvme_print_flags print_flag = validate_output_format(format);
+ enum nvme_print_flags print_flag;
+
+ err = validate_output_format(format, &print_flag);
+ if (err < 0) {
+ fprintf(stderr, "Error: Invalid output format.\n");
+ return err;
+ }
if (print_flag == JSON)
ocp_fw_activation_history_json(&fw_history);
else if (print_flag == NORMAL)
ocp_fw_activation_history_normal(&fw_history);
- else {
- fprintf(stderr, "Error: Invalid output format.\n");
- err = -EINVAL;
- }
}
return err;
diff --git a/plugins/ocp/ocp-nvme.c b/plugins/ocp/ocp-nvme.c
index edf75fc..53ae0f4 100644
--- a/plugins/ocp/ocp-nvme.c
+++ b/plugins/ocp/ocp-nvme.c
@@ -25,7 +25,7 @@
#include "nvme-print.h"
#include "ocp-smart-extended-log.h"
-#include "ocp-clear-fw-update-history.h"
+#include "ocp-clear-features.h"
#include "ocp-fw-activation-history.h"
#define CREATE_CMD
@@ -117,7 +117,6 @@ static int ocp_print_C3_log_normal(struct nvme_dev *dev,
{
char ts_buf[128];
int i, j;
- int pos = 0;
printf("-Latency Monitor/C3 Log Page Data-\n");
printf(" Controller : %s\n", dev->name);
@@ -141,6 +140,8 @@ static int ocp_print_C3_log_normal(struct nvme_dev *dev,
printf(" Active Threshold D %d ms\n",
C3_ACTIVE_THRESHOLD_INCREMENT *
le16_to_cpu(log_data->active_threshold_d+1));
+ printf(" Active Latency Configuration 0x%x \n",
+ le16_to_cpu(log_data->active_latency_config));
printf(" Active Latency Minimum Window %d ms\n",
C3_MINIMUM_WINDOW_INCREMENT *
le16_to_cpu(log_data->active_latency_min_window));
@@ -178,14 +179,6 @@ static int ocp_print_C3_log_normal(struct nvme_dev *dev,
printf(" Read Write Deallocate/Trim\n");
for (i = 0; i < C3_BUCKET_NUM; i++) {
- printf(" Active Latency Mode: Bucket %d %27d %27d %27d\n",
- i,
- log_data->active_latency_config & (1 << pos),
- log_data->active_latency_config & (1 << pos),
- log_data->active_latency_config & (1 << pos));
- }
-
- for (i = 0; i < C3_BUCKET_NUM; i++) {
printf(" Active Bucket Counter: Bucket %d %27d %27d %27d\n",
i,
le32_to_cpu(log_data->active_bucket_counter[i][READ]),
@@ -196,10 +189,10 @@ static int ocp_print_C3_log_normal(struct nvme_dev *dev,
for (i = 0; i < C3_BUCKET_NUM; i++) {
printf(" Active Latency Time Stamp: Bucket %d ", i);
for (j = 2; j >= 0; j--) {
- if (le64_to_cpu(log_data->active_latency_timestamp[i][j]) == -1) {
+ if (le64_to_cpu(log_data->active_latency_timestamp[3-i][j]) == -1) {
printf(" N/A ");
} else {
- convert_ts(le64_to_cpu(log_data->active_latency_timestamp[i][j]), ts_buf);
+ convert_ts(le64_to_cpu(log_data->active_latency_timestamp[3-i][j]), ts_buf);
printf("%s ", ts_buf);
}
}
@@ -209,9 +202,9 @@ static int ocp_print_C3_log_normal(struct nvme_dev *dev,
for (i = 0; i < C3_BUCKET_NUM; i++) {
printf(" Active Measured Latency: Bucket %d %27d ms %27d ms %27d ms\n",
i,
- le16_to_cpu(log_data->active_measured_latency[i][READ-1]),
- le16_to_cpu(log_data->active_measured_latency[i][WRITE-1]),
- le16_to_cpu(log_data->active_measured_latency[i][TRIM-1]));
+ le16_to_cpu(log_data->active_measured_latency[3-i][READ-1]),
+ le16_to_cpu(log_data->active_measured_latency[3-i][WRITE-1]),
+ le16_to_cpu(log_data->active_measured_latency[3-i][TRIM-1]));
}
printf("\n");
@@ -226,10 +219,10 @@ static int ocp_print_C3_log_normal(struct nvme_dev *dev,
for (i = 0; i < C3_BUCKET_NUM; i++) {
printf(" Static Latency Time Stamp: Bucket %d ", i);
for (j = 2; j >= 0; j--) {
- if (le64_to_cpu(log_data->static_latency_timestamp[i][j]) == -1) {
+ if (le64_to_cpu(log_data->static_latency_timestamp[3-i][j]) == -1) {
printf(" N/A ");
} else {
- convert_ts(le64_to_cpu(log_data->static_latency_timestamp[i][j]), ts_buf);
+ convert_ts(le64_to_cpu(log_data->static_latency_timestamp[3-i][j]), ts_buf);
printf("%s ", ts_buf);
}
}
@@ -239,9 +232,9 @@ static int ocp_print_C3_log_normal(struct nvme_dev *dev,
for (i = 0; i < C3_BUCKET_NUM; i++) {
printf(" Static Measured Latency: Bucket %d %27d ms %27d ms %27d ms\n",
i,
- le16_to_cpu(log_data->static_measured_latency[i][READ-1]),
- le16_to_cpu(log_data->static_measured_latency[i][WRITE-1]),
- le16_to_cpu(log_data->static_measured_latency[i][TRIM-1]));
+ le16_to_cpu(log_data->static_measured_latency[3-i][READ-1]),
+ le16_to_cpu(log_data->static_measured_latency[3-i][WRITE-1]),
+ le16_to_cpu(log_data->static_measured_latency[3-i][TRIM-1]));
}
return 0;
@@ -253,7 +246,6 @@ static void ocp_print_C3_log_json(struct ssd_latency_monitor_log *log_data)
char ts_buf[128];
char buf[128];
int i, j;
- int pos = 0;
char *operation[3] = {"Trim", "Write", "Read"};
root = json_create_object();
@@ -278,19 +270,8 @@ static void ocp_print_C3_log_json(struct ssd_latency_monitor_log *log_data)
json_object_add_value_uint(root, "Active Threshold D",
C3_ACTIVE_THRESHOLD_INCREMENT *
le16_to_cpu(log_data->active_threshold_d + 1));
-
- for (i = 0; i < C3_BUCKET_NUM; i++) {
- struct json_object *bucket;
-
- bucket = json_create_object();
- sprintf(buf, "Active Latency Mode: Bucket %d", i);
- for (j = 2; j >= 0; j--) {
- json_object_add_value_uint(bucket, operation[j],
- log_data->active_latency_config & (1 << pos));
- }
- json_object_add_value_object(root, buf, bucket);
- }
-
+ json_object_add_value_uint(root, "Active Latency Configuration",
+ le16_to_cpu(log_data->active_latency_config));
json_object_add_value_uint(root, "Active Latency Minimum Window",
C3_MINIMUM_WINDOW_INCREMENT *
le16_to_cpu(log_data->active_latency_min_window));
@@ -313,10 +294,10 @@ static void ocp_print_C3_log_json(struct ssd_latency_monitor_log *log_data)
bucket = json_create_object();
sprintf(buf, "Active Latency Time Stamp: Bucket %d", i);
for (j = 2; j >= 0; j--) {
- if (le64_to_cpu(log_data->active_latency_timestamp[i][j]) == -1) {
+ if (le64_to_cpu(log_data->active_latency_timestamp[3-i][j]) == -1) {
json_object_add_value_string(bucket, operation[j], "NA");
} else {
- convert_ts(le64_to_cpu(log_data->active_latency_timestamp[i][j]), ts_buf);
+ convert_ts(le64_to_cpu(log_data->active_latency_timestamp[3-i][j]), ts_buf);
json_object_add_value_string(bucket, operation[j], ts_buf);
}
}
@@ -330,7 +311,7 @@ static void ocp_print_C3_log_json(struct ssd_latency_monitor_log *log_data)
sprintf(buf, "Active Measured Latency: Bucket %d", i);
for (j = 2; j >= 0; j--) {
json_object_add_value_uint(bucket, operation[j],
- le16_to_cpu(log_data->active_measured_latency[i][j]));
+ le16_to_cpu(log_data->active_measured_latency[3-i][j]));
}
json_object_add_value_object(root, buf, bucket);
}
@@ -356,10 +337,10 @@ static void ocp_print_C3_log_json(struct ssd_latency_monitor_log *log_data)
bucket = json_create_object();
sprintf(buf, "Static Latency Time Stamp: Bucket %d", i);
for (j = 2; j >= 0; j--) {
- if (le64_to_cpu(log_data->static_latency_timestamp[i][j]) == -1) {
+ if (le64_to_cpu(log_data->static_latency_timestamp[3-i][j]) == -1) {
json_object_add_value_string(bucket, operation[j], "NA");
} else {
- convert_ts(le64_to_cpu(log_data->static_latency_timestamp[i][j]), ts_buf);
+ convert_ts(le64_to_cpu(log_data->static_latency_timestamp[3-i][j]), ts_buf);
json_object_add_value_string(bucket, operation[j], ts_buf);
}
}
@@ -373,7 +354,7 @@ static void ocp_print_C3_log_json(struct ssd_latency_monitor_log *log_data)
sprintf(buf, "Static Measured Latency: Bucket %d", i);
for (j = 2; j >= 0; j--) {
json_object_add_value_uint(bucket, operation[j],
- le16_to_cpu(log_data->static_measured_latency[i][j]));
+ le16_to_cpu(log_data->static_measured_latency[3-i][j]));
}
json_object_add_value_object(root, buf, bucket);
}
@@ -416,15 +397,15 @@ static void ocp_print_C3_log_json(struct ssd_latency_monitor_log *log_data)
static int get_c3_log_page(struct nvme_dev *dev, char *format)
{
struct ssd_latency_monitor_log *log_data;
- int ret = 0;
- int fmt = -1;
+ enum nvme_print_flags fmt;
+ int ret;
__u8 *data;
int i;
- fmt = validate_output_format(format);
- if (fmt < 0) {
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
fprintf(stderr, "ERROR : OCP : invalid output format\n");
- return fmt;
+ return ret;
}
data = malloc(sizeof(__u8) * C3_LATENCY_MON_LOG_BUF_LEN);
@@ -481,6 +462,9 @@ static int get_c3_log_page(struct nvme_dev *dev, char *format)
case JSON:
ocp_print_C3_log_json(log_data);
break;
+ default:
+ fprintf(stderr, "unhandled output format\n");
+
}
} else {
fprintf(stderr,
@@ -707,7 +691,7 @@ static int eol_plp_failure_mode_get(struct nvme_dev *dev, const __u32 nsid,
nvme_select_to_string(sel),
eol_plp_failure_mode_to_string(result));
if (sel == NVME_GET_FEATURES_SEL_SUPPORTED)
- nvme_show_select_result(result);
+ nvme_show_select_result(fid, result);
} else {
nvme_show_error("Could not get feature: %#0*x.", fid ? 4 : 2, fid);
}
@@ -847,6 +831,31 @@ struct telemetry_initiated_log {
__u8 ReasonIdentifier[128];
};
+struct telemetry_data_area_1 {
+ __le16 major_version;
+ __le16 minor_version;
+ __u8 reserved1[4];
+ __le64 timestamp;
+ __u8 log_page_guid[16];
+ __u8 no_of_tps_supp;
+ __u8 tps;
+ __u8 reserved2[6];
+ __le16 sls;
+ __u8 reserved3[8];
+ __le16 fw_revision;
+ __u8 reserved4[32];
+ __le16 da1_stat_start;
+ __le16 da1_stat_size;
+ __le16 da2_stat_start;
+ __le16 da2_stat_size;
+ __u8 reserved5[32];
+ __u8 event_fifo_da[16];
+ __le64 event_fifo_start[16];
+ __le64 event_fifo_size[16];
+ __u8 reserved6[80];
+ __u8 smart_health_info[512];
+ __u8 smart_health_info_extended[512];
+};
static void get_serial_number(struct nvme_id_ctrl *ctrl, char *sn)
{
int i;
@@ -913,6 +922,144 @@ static void print_telemetry_header(struct telemetry_initiated_log *logheader,
printf("===============================================\n\n");
}
}
+static int get_telemetry_data(struct nvme_dev *dev, __u32 ns, __u8 tele_type,
+ __u32 data_len, void *data, __u8 nLSP, __u8 nRAE,
+ __u64 offset)
+{
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_admin_get_log_page,
+ .nsid = ns,
+ .addr = (__u64)(uintptr_t) data,
+ .data_len = data_len,
+ };
+ __u32 numd = (data_len >> 2) - 1;
+ __u16 numdu = numd >> 16;
+ __u16 numdl = numd & 0xffff;
+ cmd.cdw10 = tele_type | (nLSP & 0x0F) << 8 | (nRAE & 0x01) << 15 | (numdl & 0xFFFF) << 16;
+ cmd.cdw11 = numdu;
+ cmd.cdw12 = offset;
+ cmd.cdw13 = 0;
+ cmd.cdw14 = 0;
+ return nvme_submit_admin_passthru(dev_fd(dev), &cmd, NULL);
+}
+static void print_telemetry_data_area_1(struct telemetry_data_area_1 *da1,
+ int tele_type)
+{
+ if (da1) {
+ unsigned int i = 0;
+ if (tele_type == TELEMETRY_TYPE_HOST)
+ printf("============ Telemetry Host Data area 1 ============\n");
+ else
+ printf("========= Telemetry Controller Data area 1 =========\n");
+ printf("Major Version : 0x%x\n", le16_to_cpu(da1->major_version));
+ printf("Minor Version : 0x%x\n", le16_to_cpu(da1->minor_version));
+ for (i = 0; i < 4; i++)
+ printf("reserved1 : 0x%x\n", da1->reserved1[i]);
+ printf("Timestamp : %"PRIu64"\n", le64_to_cpu(da1->timestamp));
+ for (i = 15; i >= 0; i--)
+ printf("%x", da1->log_page_guid[i]);
+ printf("Number Telemetry Profiles Supported : 0x%x\n", da1->no_of_tps_supp);
+ printf("Telemetry Profile Selected (TPS) : 0x%x\n", da1->tps);
+ for (i = 0; i < 6; i++)
+ printf("reserved2 : 0x%x\n", da1->reserved2[i]);
+ printf("Telemetry String Log Size (SLS) : 0x%x\n", le16_to_cpu(da1->sls));
+ for (i = 0; i < 8; i++)
+ printf("reserved3 : 0x%x\n", da1->reserved3[i]);
+ printf("Firmware Revision : 0x%x\n", le16_to_cpu(da1->fw_revision));
+ for (i = 0; i < 32; i++)
+ printf("reserved4 : 0x%x\n", da1->reserved4[i]);
+ printf("Data Area 1 Statistic Start : 0x%x\n", le16_to_cpu(da1->da1_stat_start));
+ printf("Data Area 1 Statistic Size : 0x%x\n", le16_to_cpu(da1->da1_stat_size));
+ printf("Data Area 2 Statistic Start : 0x%x\n", le16_to_cpu(da1->da2_stat_start));
+ printf("Data Area 2 Statistic Size : 0x%x\n", le16_to_cpu(da1->da2_stat_size));
+ for (i = 0; i < 32; i++)
+ printf("reserved5 : 0x%x\n", da1->reserved5[i]);
+ for (i = 0; i < 17; i++){
+ printf("Event FIFO %d Data Area : 0x%x\n", i, da1->event_fifo_da[i]);
+ printf("Event FIFO %d Start : %"PRIu64"\n", i, le64_to_cpu(da1->event_fifo_start[i]));
+ printf("Event FIFO %d Size : %"PRIu64"\n", i, le64_to_cpu(da1->event_fifo_size[i]));
+ }
+ for (i = 0; i < 80; i++)
+ printf("reserved6 : 0x%x\n", da1->reserved6[i]);
+ for (i = 0; i < 512; i++){
+ printf("SMART / Health Information : 0x%x\n", da1->smart_health_info[i]);
+ printf("SMART / Health Information Extended : 0x%x\n", da1->smart_health_info_extended[i]);
+ }
+ printf("===============================================\n\n");
+ }
+}
+static void print_telemetry_da1_stat(__u8 *da1_stat, int tele_type, __u16 buf_size)
+{
+ if (da1_stat) {
+ unsigned int i = 0;
+ if (tele_type == TELEMETRY_TYPE_HOST)
+ printf("============ Telemetry Host Data area 1 Statistics ============\n");
+ else
+ printf("========= Telemetry Controller Data area 1 Statistics =========\n");
+ while((i + 8) < buf_size) {
+ printf("Statistics Identifier : 0x%x\n", (da1_stat[i] | da1_stat[i+1] << 8));
+ printf("Statistics info : 0x%x\n", da1_stat[i+2]);
+ printf("NS info : 0x%x\n", da1_stat[i+3]);
+ printf("Statistic Data Size : 0x%x\n", (da1_stat[i+4] | da1_stat[i+5] << 8));
+ printf("Reserved : 0x%x\n", (da1_stat[i+6] | da1_stat[i+7] << 8));
+ i = 8 + ((da1_stat[i+4] | da1_stat[i+5] << 8) * 4);
+ }
+ printf("===============================================\n\n");
+ }
+}
+static void print_telemetry_da1_fifo(__u8 *da1_fifo, int tele_type, __u16 buf_size)
+{
+ if (da1_fifo) {
+ unsigned int i = 0;
+ if (tele_type == TELEMETRY_TYPE_HOST)
+ printf("============ Telemetry Host Data area 1 FIFO ============\n");
+ else
+ printf("========= Telemetry Controller Data area 1 FIFO =========\n");
+ while((i + 4) < buf_size) {
+ printf("Debug Event Class Type : 0x%x\n", da1_fifo[i]);
+ printf("Event ID : 0x%x\n", (da1_fifo[i+1] | da1_fifo[i+2] << 8));
+ printf("Event Data Size : 0x%x\n", da1_fifo[3]);
+ i = 4 + ((da1_fifo[3]) * 4);
+ }
+ printf("===============================================\n\n");
+ }
+}
+static void print_telemetry_da2_stat(__u8 *da1_stat, int tele_type, __u16 buf_size)
+{
+ if (da1_stat) {
+ unsigned int i = 0;
+ if (tele_type == TELEMETRY_TYPE_HOST)
+ printf("============ Telemetry Host Data area 1 Statistics ============\n");
+ else
+ printf("========= Telemetry Controller Data area 1 Statistics =========\n");
+ while((i + 8) < buf_size) {
+ printf("Statistics Identifier : 0x%x\n", (da1_stat[i] | da1_stat[i+1] << 8));
+ printf("Statistics info : 0x%x\n", da1_stat[i+2]);
+ printf("NS info : 0x%x\n", da1_stat[i+3]);
+ printf("Statistic Data Size : 0x%x\n", (da1_stat[i+4] | da1_stat[i+5] << 8));
+ printf("Reserved : 0x%x\n", (da1_stat[i+6] | da1_stat[i+7] << 8));
+ i = 8 + ((da1_stat[i+4] | da1_stat[i+5] << 8) * 4);
+ }
+ printf("===============================================\n\n");
+ }
+}
+static void print_telemetry_da2_fifo(__u8 *da1_fifo, int tele_type, __u16 buf_size)
+{
+ if (da1_fifo) {
+ unsigned int i = 0;
+ if (tele_type == TELEMETRY_TYPE_HOST)
+ printf("============ Telemetry Host Data area 1 Statistics ============\n");
+ else
+ printf("========= Telemetry Controller Data area 1 Statistics =========\n");
+ while((i + 4) < buf_size) {
+ printf("Debug Event Class Type : 0x%x\n", da1_fifo[i]);
+ printf("Event ID : 0x%x\n", (da1_fifo[i+1] | da1_fifo[i+2] << 8));
+ printf("Event Data Size : 0x%x\n", da1_fifo[3]);
+ i = 4 + ((da1_fifo[3]) * 4);
+ }
+ printf("===============================================\n\n");
+ }
+}
static int extract_dump_get_log(struct nvme_dev *dev, char *featurename, char *filename, char *sn,
int dumpsize, int transfersize, __u32 nsid, __u8 log_id,
@@ -1000,9 +1147,12 @@ static int get_telemetry_dump(struct nvme_dev *dev, char *filename, char *sn,
{
__u32 err = 0, nsid = 0;
__u8 lsp = 0, rae = 0;
+ unsigned int i = 0;
char data[TELEMETRY_TRANSFER_SIZE] = { 0 };
+ char data1[1536] = { 0 };
char *featurename = 0;
struct telemetry_initiated_log *logheader = (struct telemetry_initiated_log *)data;
+ struct telemetry_data_area_1 *da1 = (struct telemetry_data_area_1 *)data1;
__u64 offset = 0, size = 0;
char dumpname[FILE_NAME_SIZE] = { 0 };
@@ -1029,6 +1179,43 @@ static int get_telemetry_dump(struct nvme_dev *dev, char *filename, char *sn,
if (header_print)
print_telemetry_header(logheader, tele_type);
+ err = get_telemetry_data(dev, nsid, tele_type, 1536,
+ (void *)data1, lsp, rae, 512);
+ if (err)
+ return err;
+ print_telemetry_data_area_1(da1, tele_type);
+ char *da1_stat = calloc((da1->da1_stat_size * 4), sizeof(char));
+ err = get_telemetry_data(dev, nsid, tele_type, (da1->da1_stat_size) * 4,
+ (void *)da1_stat, lsp, rae, (da1->da1_stat_start) * 4);
+ if (err)
+ return err;
+ print_telemetry_da1_stat((void *)da1_stat, tele_type, (da1->da1_stat_size) * 4);
+ for (i = 0; i < 17 ; i++){
+ if (da1->event_fifo_da[i] == 1){
+ char *da1_fifo = calloc((da1->event_fifo_size[i]) * 4, sizeof(char));
+ err = get_telemetry_data(dev, nsid, tele_type, (da1->event_fifo_size[i]) * 4,
+ (void *)da1_stat, lsp, rae, (da1->event_fifo_start[i]) * 4);
+ if (err)
+ return err;
+ print_telemetry_da1_fifo((void *)da1_fifo, tele_type, (da1->event_fifo_size[i]) * 4);
+ }
+ }
+ char *da2_stat = calloc((da1->da2_stat_size * 4), sizeof(char));
+ err = get_telemetry_data(dev, nsid, tele_type, (da1->da2_stat_size) * 4,
+ (void *)da2_stat, lsp, rae, (da1->da2_stat_start) * 4);
+ if (err)
+ return err;
+ print_telemetry_da2_stat((void *)da2_stat, tele_type, (da1->da2_stat_size) * 4);
+ for (i = 0; i < 17 ; i++){
+ if (da1->event_fifo_da[i] == 2){
+ char *da1_fifo = calloc((da1->event_fifo_size[i]) * 4, sizeof(char));
+ err = get_telemetry_data(dev, nsid, tele_type, (da1->event_fifo_size[i]) * 4,
+ (void *)da1_stat, lsp, rae, (da1->event_fifo_start[i]) * 4);
+ if (err)
+ return err;
+ print_telemetry_da2_fifo((void *)da1_fifo, tele_type, (da1->event_fifo_size[i]) * 4);
+ }
+ }
switch (data_area) {
case 1:
@@ -1324,17 +1511,17 @@ static void ocp_print_c5_log_binary(struct unsupported_requirement_log *log_data
static int get_c5_log_page(struct nvme_dev *dev, char *format)
{
- int ret = 0;
- int fmt = -1;
+ enum nvme_print_flags fmt;
+ int ret;
__u8 *data;
int i;
struct unsupported_requirement_log *log_data;
int j;
- fmt = validate_output_format(format);
- if (fmt < 0) {
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
fprintf(stderr, "ERROR : OCP : invalid output format\n");
- return fmt;
+ return ret;
}
data = (__u8 *)malloc(sizeof(__u8) * C5_UNSUPPORTED_REQS_LEN);
@@ -1386,6 +1573,8 @@ static int get_c5_log_page(struct nvme_dev *dev, char *format)
case BINARY:
ocp_print_c5_log_binary(log_data);
break;
+ default:
+ break;
}
} else {
fprintf(stderr, "ERROR : OCP : Unable to read C3 data from buffer\n");
@@ -1548,16 +1737,16 @@ static void ocp_print_c1_log_binary(struct ocp_error_recovery_log_page *log_data
static int get_c1_log_page(struct nvme_dev *dev, char *format)
{
- int ret = 0;
- int fmt = -1;
+ struct ocp_error_recovery_log_page *log_data;
+ enum nvme_print_flags fmt;
+ int ret;
__u8 *data;
int i, j;
- struct ocp_error_recovery_log_page *log_data;
- fmt = validate_output_format(format);
- if (fmt < 0) {
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
fprintf(stderr, "ERROR : OCP : invalid output format\n");
- return fmt;
+ return ret;
}
data = (__u8 *)malloc(sizeof(__u8) * C1_ERROR_RECOVERY_LOG_BUF_LEN);
@@ -1609,6 +1798,8 @@ static int get_c1_log_page(struct nvme_dev *dev, char *format)
case BINARY:
ocp_print_c1_log_binary(log_data);
break;
+ default:
+ break;
}
} else {
fprintf(stderr, "ERROR : OCP : Unable to read C1 data from buffer\n");
@@ -1762,16 +1953,16 @@ static void ocp_print_c4_log_binary(struct ocp_device_capabilities_log_page *log
static int get_c4_log_page(struct nvme_dev *dev, char *format)
{
- int ret = 0;
- int fmt = -1;
+ struct ocp_device_capabilities_log_page *log_data;
+ enum nvme_print_flags fmt;
+ int ret;
__u8 *data;
int i, j;
- struct ocp_device_capabilities_log_page *log_data;
- fmt = validate_output_format(format);
- if (fmt < 0) {
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
fprintf(stderr, "ERROR : OCP : invalid output format\n");
- return fmt;
+ return ret;
}
data = (__u8 *)malloc(sizeof(__u8) * C4_DEV_CAP_REQ_LEN);
@@ -1823,6 +2014,8 @@ static int get_c4_log_page(struct nvme_dev *dev, char *format)
case BINARY:
ocp_print_c4_log_binary(log_data);
break;
+ default:
+ break;
}
} else {
fprintf(stderr, "ERROR : OCP : Unable to read C4 data from buffer\n");
@@ -1867,9 +2060,891 @@ static int ocp_device_capabilities_log(int argc, char **argv, struct command *cm
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
-/// Misc
+/// DSSD Power State (Feature Identifier C7h) Set Feature
+
+static int set_dssd_power_state(struct nvme_dev *dev, const __u32 nsid,
+ const __u8 fid, __u8 power_state, bool save,
+ bool uuid)
+{
+ __u32 result;
+ int err;
+ int uuid_index = 0;
+
+ if (uuid) {
+ /* OCP 2.0 requires UUID index support */
+ err = ocp_get_uuid_index(dev, &uuid_index);
+ if (err || !uuid_index) {
+ nvme_show_error("ERROR: No OCP UUID index found");
+ return err;
+ }
+ }
+
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = fid,
+ .nsid = nsid,
+ .cdw11 = power_state,
+ .cdw12 = 0,
+ .save = save,
+ .uuidx = uuid_index,
+ .cdw15 = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ err = nvme_set_features(&args);
+ if (err > 0) {
+ nvme_show_status(err);
+ } else if (err < 0) {
+ nvme_show_perror("Define DSSD Power State");
+ fprintf(stderr, "Command failed while parsing.\n");
+ } else {
+ printf("Successfully set DSSD Power State (feature: 0xC7) to below values\n");
+ printf("DSSD Power State: 0x%x\n", power_state);
+ printf("Save bit Value: 0x%x\n", save);
+ }
+
+ return err;
+}
+
+static int set_dssd_power_state_feature(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Define DSSD Power State (Feature Identifier C7h) Set Feature.";
+ 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;
+
+ struct config {
+ __u8 power_state;
+ bool save;
+ };
+
+ struct config cfg = {
+ .power_state = 0,
+ .save = false,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_BYTE("power-state", 'p', &cfg.power_state, power_state),
+ OPT_FLAG("save", 's', &cfg.save, save),
+ OPT_FLAG("no-uuid", 'n', NULL,
+ "Skip UUID index search (UUID index not required for OCP 1.0)"),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ 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"));
+
+ dev_close(dev);
+
+ return err;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+/// plp_health_check_interval
+
+static int set_plp_health_check_interval(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+
+ const char *desc = "Define Issue Set Feature command (FID : 0xC6) PLP Health Check Interval";
+ 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;
+ int uuid_index = 0;
+
+ struct config {
+ __le16 plp_health_interval;
+ bool save;
+ };
+
+ struct config cfg = {
+ .plp_health_interval = 0,
+ .save = false,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_BYTE("plp_health_interval", 'p', &cfg.plp_health_interval, plp_health_interval),
+ OPT_FLAG("save", 's', &cfg.save, save),
+ OPT_FLAG("no-uuid", 'n', NULL,
+ "Skip UUID index search (UUID index not required for OCP 1.0)"),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+
+ if (!argconfig_parse_seen(opts, "no-uuid")) {
+ /* OCP 2.0 requires UUID index support */
+ err = ocp_get_uuid_index(dev, &uuid_index);
+ if (err || !uuid_index) {
+ printf("ERROR: No OCP UUID index found");
+ return err;
+ }
+ }
+
+
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = fid,
+ .nsid = nsid,
+ .cdw11 = cfg.plp_health_interval << 16,
+ .cdw12 = 0,
+ .save = cfg.save,
+ .uuidx = uuid_index,
+ .cdw15 = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ err = nvme_set_features(&args);
+ if (err > 0) {
+ nvme_show_status(err);
+ } else if (err < 0) {
+ nvme_show_perror("Define PLP Health Check Interval");
+ fprintf(stderr, "Command failed while parsing.\n");
+ } else {
+ printf("Successfully set the PLP Health Check Interval");
+ printf("PLP Health Check Interval: 0x%x\n", cfg.plp_health_interval);
+ printf("Save bit Value: 0x%x\n", cfg.save);
+ }
+ return err;
+}
+
+static int get_plp_health_check_interval(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+
+ 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;
+ __u32 result;
+ int err;
+
+ struct config {
+ __u8 sel;
+ };
+
+ struct config cfg = {
+ .sel = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_BYTE("sel", 'S', &cfg.sel, sel),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+
+ struct nvme_get_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = fid,
+ .nsid = nsid,
+ .sel = cfg.sel,
+ .cdw11 = 0,
+ .uuidx = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ err = nvme_get_features(&args);
+ if (!err) {
+ printf("get-feature:0xC6 %s value: %#08x\n", nvme_select_to_string(cfg.sel), result);
+
+ if (cfg.sel == NVME_GET_FEATURES_SEL_SUPPORTED)
+ nvme_show_select_result(fid, result);
+ } else {
+ nvme_show_error("Could not get feature: 0xC6");
+ }
+
+ return err;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+/// Telemetry String Log Format Log Page (LID : C9h)
+
+/* C9 Telemetry String Log Format Log Page */
+#define C9_GUID_LENGTH 16
+#define C9_TELEMETRY_STRING_LOG_ENABLE_OPCODE 0xC9
+#define C9_TELEMETRY_STR_LOG_LEN 432
+#define C9_TELEMETRY_STR_LOG_SIST_OFST 431
+
+/**
+ * struct telemetry_str_log_format - Telemetry String Log Format
+ * @log_page_version: indicates the version of the mapping this log page uses
+ * Shall be set to 01h.
+ * @reserved1: Reserved.
+ * @log_page_guid: Shall be set to B13A83691A8F408B9EA495940057AA44h.
+ * @sls: Shall be set to the number of DWORDS in the String Log.
+ * @reserved2: reserved.
+ * @sits: shall be set to the number of DWORDS in the Statistics
+ * Identifier String Table
+ * @ests: Shall be set to the number of DWORDS from byte 0 of this
+ * log page to the start of the Event String Table
+ * @estsz: shall be set to the number of DWORDS in the Event String Table
+ * @vu_eve_sts: Shall be set to the number of DWORDS from byte 0 of this
+ * log page to the start of the VU Event String Table
+ * @vu_eve_st_sz: shall be set to the number of DWORDS in the VU Event String Table
+ * @ascts: the number of DWORDS from byte 0 of this log page until the ASCII Table Starts.
+ * @asctsz: the number of DWORDS in the ASCII Table
+ * @fifo1: FIFO 0 ASCII String
+ * @fifo2: FIFO 1 ASCII String
+ * @fifo3: FIFO 2 ASCII String
+ * @fifo4: FIFO 3 ASCII String
+ * @fif05: FIFO 4 ASCII String
+ * @fifo6: FIFO 5 ASCII String
+ * @fifo7: FIFO 6 ASCII String
+ * @fifo8: FIFO 7 ASCII String
+ * @fifo9: FIFO 8 ASCII String
+ * @fifo10: FIFO 9 ASCII String
+ * @fif011: FIFO 10 ASCII String
+ * @fif012: FIFO 11 ASCII String
+ * @fifo13: FIFO 12 ASCII String
+ * @fif014: FIFO 13 ASCII String
+ * @fif015: FIFO 14 ASCII String
+ * @fif016: FIFO 15 ASCII String
+ * @reserved3: reserved
+ */
+struct __attribute__((__packed__)) telemetry_str_log_format {
+ __u8 log_page_version;
+ __u8 reserved1[15];
+ __u8 log_page_guid[C9_GUID_LENGTH];
+ __le64 sls;
+ __u8 reserved2[24];
+ __le64 sits;
+ __le64 sitsz;
+ __le64 ests;
+ __le64 estsz;
+ __le64 vu_eve_sts;
+ __le64 vu_eve_st_sz;
+ __le64 ascts;
+ __le64 asctsz;
+ __u8 fifo1[16];
+ __u8 fifo2[16];
+ __u8 fifo3[16];
+ __u8 fifo4[16];
+ __u8 fifo5[16];
+ __u8 fifo6[16];
+ __u8 fifo7[16];
+ __u8 fifo8[16];
+ __u8 fifo9[16];
+ __u8 fifo10[16];
+ __u8 fifo11[16];
+ __u8 fifo12[16];
+ __u8 fifo13[16];
+ __u8 fifo14[16];
+ __u8 fifo15[16];
+ __u8 fifo16[16];
+ __u8 reserved3[48];
+};
+
+/*
+ * struct statistics_id_str_table_entry - Statistics Identifier String Table Entry
+ * @vs_si: Shall be set the Vendor Unique Statistic Identifier number.
+ * @reserved1: Reserved
+ * @ascii_id_len: Shall be set the number of ASCII Characters that are valid.
+ * @ascii_id_ofst: Shall be set to the offset from DWORD 0/Byte 0 of the Start
+ * of the ASCII Table to the first character of the string for
+ * this Statistic Identifier string..
+ * @reserved2 reserved
+ */
+struct __attribute__((__packed__)) statistics_id_str_table_entry {
+ __le16 vs_si;
+ __u8 reserved1;
+ __u8 ascii_id_len;
+ __le64 ascii_id_ofst;
+ __le32 reserved2;
+};
+
+/*
+ * struct event_id_str_table_entry - Event Identifier String Table Entry
+ * @deb_eve_class: Shall be set the Debug Class.
+ * @ei: Shall be set to the Event Identifier
+ * @ascii_id_len: Shall be set the number of ASCII Characters that are valid.
+ * @ascii_id_ofst: This is the offset from DWORD 0/ Byte 0 of the start of the
+ * ASCII table to the ASCII data for this identifier
+ * @reserved2 reserved
+ */
+struct __attribute__((__packed__)) event_id_str_table_entry {
+ __u8 deb_eve_class;
+ __le16 ei;
+ __u8 ascii_id_len;
+ __le64 ascii_id_ofst;
+ __le32 reserved2;
+};
+
+/*
+ * struct vu_event_id_str_table_entry - VU Event Identifier String Table Entry
+ * @deb_eve_class: Shall be set the Debug Class.
+ * @vu_ei: Shall be set to the VU Event Identifier
+ * @ascii_id_len: Shall be set the number of ASCII Characters that are valid.
+ * @ascii_id_ofst: This is the offset from DWORD 0/ Byte 0 of the start of the
+ * ASCII table to the ASCII data for this identifier
+ * @reserved reserved
+ */
+struct __attribute__((__packed__)) vu_event_id_str_table_entry {
+ __u8 deb_eve_class;
+ __le16 vu_ei;
+ __u8 ascii_id_len;
+ __le64 ascii_id_ofst;
+ __le32 reserved;
+};
+
+/* Function declaration for Telemetry String Log Format (LID:C9h) */
+static int ocp_telemetry_str_log_format(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin);
-static const __u8 OCP_FID_CLEAR_PCIE_CORRECTABLE_ERROR_COUNTERS = 0xC3;
+
+static int ocp_print_C9_log_normal(struct telemetry_str_log_format *log_data,__u8 *log_data_buf)
+{
+ //calculating the index value for array
+ __le64 stat_id_index = (log_data->sitsz * 4) / 16;
+ __le64 eve_id_index = (log_data->estsz * 4) / 16;
+ __le64 vu_eve_index = (log_data->vu_eve_st_sz * 4) / 16;
+ __le64 ascii_table_index = (log_data->asctsz * 4);
+ //Calculating the offset for dynamic fields.
+ __le64 stat_id_str_table_ofst = C9_TELEMETRY_STR_LOG_SIST_OFST + (log_data->sitsz * 4);
+ __le64 event_str_table_ofst = stat_id_str_table_ofst + (log_data->estsz * 4);
+ __le64 vu_event_str_table_ofst = event_str_table_ofst + (log_data->vu_eve_st_sz * 4);
+ __le64 ascii_table_ofst = vu_event_str_table_ofst + (log_data->asctsz * 4);
+ struct statistics_id_str_table_entry stat_id_str_table_arr[stat_id_index];
+ struct event_id_str_table_entry event_id_str_table_arr[eve_id_index];
+ struct vu_event_id_str_table_entry vu_event_id_str_table_arr[vu_eve_index];
+ __u8 ascii_table_info_arr[ascii_table_index];
+ int j;
+
+ printf(" Log Page Version : 0x%x\n", log_data->log_page_version);
+
+ printf(" Reserved : ");
+ for (j = 0; j < 15; j++)
+ printf("%d", log_data->reserved1[j]);
+ printf("\n");
+
+ printf(" Log page GUID : 0x");
+ for (j = C9_GUID_LENGTH - 1; j >= 0; j--)
+ printf("%x", log_data->log_page_guid[j]);
+ printf("\n");
+
+ printf(" Telemetry String Log Size : 0x%lx\n", le64_to_cpu(log_data->sls));
+
+ printf(" Reserved : ");
+ for (j = 0; j < 24; j++)
+ printf("%d", log_data->reserved2[j]);
+ printf("\n");
+
+ printf(" Statistics Identifier String Table Start : 0x%lx\n", le64_to_cpu(log_data->sits));
+ printf(" Statistics Identifier String Table Size : 0x%lx\n", le64_to_cpu(log_data->sitsz));
+ printf(" Event String Table Start : 0x%lx\n", le64_to_cpu(log_data->ests));
+ printf(" Event String Table Size : 0x%lx\n", le64_to_cpu(log_data->estsz));
+ printf(" VU Event String Table Start : 0x%lx\n", le64_to_cpu(log_data->vu_eve_sts));
+ printf(" VU Event String Table Size : 0x%lx\n", le64_to_cpu(log_data->vu_eve_st_sz));
+ printf(" ASCII Table Start : 0x%lx\n", le64_to_cpu(log_data->ascts));
+ printf(" ASCII Table Size : 0x%lx\n", le64_to_cpu(log_data->asctsz));
+
+ printf(" FIFO 1 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo1[j], log_data->fifo1[j]);
+ }
+
+ printf(" FIFO 2 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo2[j], log_data->fifo2[j]);
+ }
+
+ printf(" FIFO 3 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo3[j], log_data->fifo3[j]);
+ }
+
+ printf(" FIFO 4 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+
+ printf(" %d %d %c \n", j, log_data->fifo4[j], log_data->fifo4[j]);
+ }
+
+ printf(" FIFO 5 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo5[j], log_data->fifo5[j]);
+ }
+
+ printf(" FIFO 6 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo6[j], log_data->fifo6[j]);
+ }
+
+ printf(" FIFO 7 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo7[j], log_data->fifo7[j]);
+ }
+
+ printf(" FIFO 8 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf("index value ascii_val");
+ printf(" %d %d %c \n", j, log_data->fifo8[j], log_data->fifo8[j]);
+ }
+
+ printf(" FIFO 9 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo9[j], log_data->fifo9[j]);
+ }
+
+ printf(" FIFO 10 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo10[j], log_data->fifo10[j]);
+ }
+
+ printf(" FIFO 11 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo11[j], log_data->fifo11[j]);
+ }
+
+ printf(" FIFO 12 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo12[j], log_data->fifo12[j]);
+ }
+
+ printf(" FIFO 13 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo13[j], log_data->fifo13[j]);
+ }
+
+ printf(" FIFO 14 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo14[j], log_data->fifo14[j]);
+ }
+
+ printf(" FIFO 15 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo15[j], log_data->fifo16[j]);
+ }
+
+ printf(" FIFO 16 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo16[j], log_data->fifo16[j]);
+ }
+
+ printf(" Reserved : ");
+ for (j = 0; j < 48; j++)
+ printf("%d", log_data->reserved3[j]);
+ printf("\n");
+
+ memcpy(stat_id_str_table_arr, (__u8*)log_data_buf + stat_id_str_table_ofst, (log_data->sitsz * 4));
+ memcpy(event_id_str_table_arr, (__u8*)log_data_buf + event_str_table_ofst, (log_data->estsz * 4));
+ memcpy(vu_event_id_str_table_arr, (__u8*)log_data_buf + vu_event_str_table_ofst, (log_data->vu_eve_st_sz * 4));
+ memcpy(ascii_table_info_arr, (__u8*)log_data_buf + ascii_table_ofst, (log_data->asctsz * 4));
+
+ printf(" Statistics Identifier String Table\n");
+ for (j = 0; j < stat_id_index; j++){
+ printf(" Vendor Specific Statistic Identifier : 0x%x\n",le16_to_cpu(stat_id_str_table_arr[j].vs_si));
+ printf(" Reserved : 0x%d",stat_id_str_table_arr[j].reserved1);
+ printf(" ASCII ID Length : 0x%x\n",stat_id_str_table_arr[j].ascii_id_len);
+ printf(" ASCII ID offset : 0x%lx\n",le64_to_cpu(stat_id_str_table_arr[j].ascii_id_ofst));
+ printf(" Reserved : 0x%d\n",stat_id_str_table_arr[j].reserved2);
+ }
+
+ printf(" Event Identifier String Table Entry\n");
+ for (j = 0; j < eve_id_index; j++){
+ printf(" Debug Event Class : 0x%x\n",event_id_str_table_arr[j].deb_eve_class);
+ printf(" Event Identifier : 0x%x\n",le16_to_cpu(event_id_str_table_arr[j].ei));
+ printf(" ASCII ID Length : 0x%x\n",event_id_str_table_arr[j].ascii_id_len);
+ printf(" ASCII ID offset : 0x%lx\n",le64_to_cpu(event_id_str_table_arr[j].ascii_id_ofst));
+ printf(" Reserved : 0x%d\n",event_id_str_table_arr[j].reserved2);
+
+ }
+
+ printf(" VU Event Identifier String Table Entry\n");
+ for (j = 0; j < vu_eve_index; j++){
+ printf(" Debug Event Class : 0x%x\n",vu_event_id_str_table_arr[j].deb_eve_class);
+ printf(" VU Event Identifier : 0x%x\n",le16_to_cpu(vu_event_id_str_table_arr[j].vu_ei));
+ printf(" ASCII ID Length : 0x%x\n",vu_event_id_str_table_arr[j].ascii_id_len);
+ printf(" ASCII ID offset : 0x%lx\n",le64_to_cpu(vu_event_id_str_table_arr[j].ascii_id_ofst));
+ printf(" Reserved : 0x%d\n",vu_event_id_str_table_arr[j].reserved);
+
+ }
+
+ printf(" ASCII Table\n");
+ printf(" Byte Data_Byte ASCII_Character\n");
+ for (j = 0; j < ascii_table_index; j++){
+ printf(" %lld 0x%x %c \n",ascii_table_ofst+j,ascii_table_info_arr[j],ascii_table_info_arr[j]);
+ }
+ return 0;
+}
+
+static int ocp_print_C9_log_json(struct telemetry_str_log_format *log_data,__u8 *log_data_buf)
+{
+ struct json_object *root = json_create_object();
+ struct json_object *stat_table = json_create_object();
+ struct json_object *eve_table = json_create_object();
+ struct json_object *vu_eve_table = json_create_object();
+ struct json_object *entry = json_create_object();
+ char res_arr[48];
+ char *res = res_arr;
+ char guid_buf[C9_GUID_LENGTH];
+ char *guid = guid_buf;
+ char fifo_arr[16];
+ char *fifo = fifo_arr;
+ //calculating the index value for array
+ __le64 stat_id_index = (log_data->sitsz * 4) / 16;
+ __le64 eve_id_index = (log_data->estsz * 4) / 16;
+ __le64 vu_eve_index = (log_data->vu_eve_st_sz * 4) / 16;
+ __le64 ascii_table_index = (log_data->asctsz * 4);
+ //Calculating the offset for dynamic fields.
+ __le64 stat_id_str_table_ofst = C9_TELEMETRY_STR_LOG_SIST_OFST + (log_data->sitsz * 4);
+ __le64 event_str_table_ofst = stat_id_str_table_ofst + (log_data->estsz * 4);
+ __le64 vu_event_str_table_ofst = event_str_table_ofst + (log_data->vu_eve_st_sz * 4);
+ __le64 ascii_table_ofst = vu_event_str_table_ofst + (log_data->asctsz * 4);
+ struct statistics_id_str_table_entry stat_id_str_table_arr[stat_id_index];
+ struct event_id_str_table_entry event_id_str_table_arr[eve_id_index];
+ struct vu_event_id_str_table_entry vu_event_id_str_table_arr[vu_eve_index];
+ __u8 ascii_table_info_arr[ascii_table_index];
+ char ascii_buf[ascii_table_index];
+ char *ascii = ascii_buf;
+ int j;
+
+ json_object_add_value_int(root, "Log Page Version", le16_to_cpu(log_data->log_page_version));
+
+ memset((__u8 *)res, 0, 15);
+ for (j = 0; j < 15; j++)
+ res += sprintf(res, "%d", log_data->reserved1[j]);
+ json_object_add_value_string(root, "Reserved", res_arr);
+
+ memset((void *)guid, 0, C9_GUID_LENGTH);
+ for (j = C9_GUID_LENGTH - 1; j >= 0; j--)
+ guid += sprintf(guid, "%02x", log_data->log_page_guid[j]);
+ json_object_add_value_string(root, "Log page GUID", guid_buf);
+
+ json_object_add_value_int(root, "Telemetry String Log Size", le64_to_cpu(log_data->sls));
+
+ memset((__u8 *)res, 0, 24);
+ for (j = 0; j < 24; j++)
+ res += sprintf(res, "%d", log_data->reserved2[j]);
+ json_object_add_value_string(root, "Reserved", res_arr);
+
+ json_object_add_value_int(root, "Statistics Identifier String Table Start", le64_to_cpu(log_data->sits));
+ json_object_add_value_int(root, "Event String Table Start", le64_to_cpu(log_data->ests));
+ json_object_add_value_int(root, "Event String Table Size", le64_to_cpu(log_data->estsz));
+ json_object_add_value_int(root, "VU Event String Table Start", le64_to_cpu(log_data->vu_eve_sts));
+ json_object_add_value_int(root, "VU Event String Table Size", le64_to_cpu(log_data->vu_eve_st_sz));
+ json_object_add_value_int(root, "ASCII Table Start", le64_to_cpu(log_data->ascts));
+ json_object_add_value_int(root, "ASCII Table Size", le64_to_cpu(log_data->asctsz));
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo1[j]);
+ json_object_add_value_string(root, "FIFO 1 ASCII String", 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ memset((__u8 *)res, 0, 48);
+ for (j = 0; j < 48; j++)
+ res += sprintf(res, "%d", log_data->reserved3[j]);
+ json_object_add_value_string(root, "Reserved", res_arr);
+
+ memcpy(stat_id_str_table_arr, (__u8*)log_data_buf + stat_id_str_table_ofst, (log_data->sitsz * 4));
+ memcpy(event_id_str_table_arr, (__u8*)log_data_buf + event_str_table_ofst, (log_data->estsz * 4));
+ memcpy(vu_event_id_str_table_arr, (__u8*)log_data_buf + vu_event_str_table_ofst, (log_data->vu_eve_st_sz * 4));
+ memcpy(ascii_table_info_arr, (__u8*)log_data_buf + ascii_table_ofst, (log_data->asctsz * 4));
+
+ for (j = 0; j < stat_id_index; j++){
+ json_object_add_value_int(entry, "Vendor Specific Statistic Identifier", le16_to_cpu(stat_id_str_table_arr[j].vs_si));
+ json_object_add_value_int(entry, "Reserved", le64_to_cpu(stat_id_str_table_arr[j].reserved1));
+ json_object_add_value_int(entry, "ASCII ID Length", le64_to_cpu(stat_id_str_table_arr[j].ascii_id_len));
+ json_object_add_value_int(entry, "ASCII ID offset", le64_to_cpu(stat_id_str_table_arr[j].ascii_id_ofst));
+ json_object_add_value_int(entry, "Reserved", le64_to_cpu(stat_id_str_table_arr[j].reserved2));
+ json_array_add_value_object(stat_table, entry);
+ }
+ json_object_add_value_array(root, "Statistics Identifier String Table", stat_table);
+
+ for (j = 0; j < eve_id_index; j++){
+ json_object_add_value_int(entry, "Debug Event Class", le16_to_cpu(event_id_str_table_arr[j].deb_eve_class));
+ json_object_add_value_int(entry, "Event Identifier", le16_to_cpu(event_id_str_table_arr[j].ei));
+ json_object_add_value_int(entry, "ASCII ID Length", le64_to_cpu(event_id_str_table_arr[j].ascii_id_len));
+ json_object_add_value_int(entry, "ASCII ID offset", le64_to_cpu(event_id_str_table_arr[j].ascii_id_ofst));
+ json_object_add_value_int(entry, "Reserved", le64_to_cpu(event_id_str_table_arr[j].reserved2));
+ json_array_add_value_object(eve_table, entry);
+ }
+ json_object_add_value_array(root, "Event Identifier String Table Entry", eve_table);
+
+ for (j = 0; j < vu_eve_index; j++){
+ json_object_add_value_int(entry, "Debug Event Class", le16_to_cpu(vu_event_id_str_table_arr[j].deb_eve_class));
+ json_object_add_value_int(entry, "VU Event Identifier", le16_to_cpu(vu_event_id_str_table_arr[j].vu_ei));
+ json_object_add_value_int(entry, "ASCII ID Length", le64_to_cpu(vu_event_id_str_table_arr[j].ascii_id_len));
+ json_object_add_value_int(entry, "ASCII ID offset", le64_to_cpu(vu_event_id_str_table_arr[j].ascii_id_ofst));
+ json_object_add_value_int(entry, "Reserved", le64_to_cpu(vu_event_id_str_table_arr[j].reserved));
+ json_array_add_value_object(vu_eve_table, entry);
+ }
+ json_object_add_value_array(root, "VU Event Identifier String Table Entry", vu_eve_table);
+
+ memset((void *)ascii, 0, ascii_table_index);
+ for (j = 0; j < ascii_table_index; j++)
+ ascii += sprintf(ascii, "%c", ascii_table_info_arr[j]);
+ json_object_add_value_string(root, "ASCII Table", ascii_buf);
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+ json_free_object(stat_table);
+ json_free_object(eve_table);
+ json_free_object(vu_eve_table);
+
+ return 0;
+}
+
+static void ocp_print_c9_log_binary(__u8 *log_data_buf,int total_log_page_size)
+{
+ return d_raw((unsigned char *)log_data_buf, total_log_page_size);
+}
+
+static int get_c9_log_page(struct nvme_dev *dev, char *format)
+{
+ int ret = 0;
+ __u8 *header_data;
+ struct telemetry_str_log_format *log_data;
+ enum nvme_print_flags fmt;
+ __u8 *full_log_buf_data = NULL;
+ __le64 stat_id_str_table_ofst = 0;
+ __le64 event_str_table_ofst = 0;
+ __le64 vu_event_str_table_ofst = 0;
+ __le64 ascii_table_ofst = 0;
+ __le64 total_log_page_sz = 0;
+
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR : OCP : invalid output format\n");
+ return ret;
+ }
+
+ header_data = (__u8 *)malloc(sizeof(__u8) * C9_TELEMETRY_STR_LOG_LEN);
+ if (!header_data) {
+ fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno));
+ return -1;
+ }
+ 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);
+
+ if (!ret) {
+ log_data = (struct telemetry_str_log_format *)header_data;
+ printf("Statistics Identifier String Table Size = %lld\n",log_data->sitsz);
+ printf("Event String Table Size = %lld\n",log_data->estsz);
+ printf("VU Event String Table Size = %lld\n",log_data->vu_eve_st_sz);
+ printf("ASCII Table Size = %lld\n",log_data->asctsz);
+
+ //Calculating the offset for dynamic fields.
+ stat_id_str_table_ofst = C9_TELEMETRY_STR_LOG_SIST_OFST + (log_data->sitsz * 4);
+ event_str_table_ofst = stat_id_str_table_ofst + (log_data->estsz * 4);
+ vu_event_str_table_ofst = event_str_table_ofst + (log_data->vu_eve_st_sz * 4);
+ ascii_table_ofst = vu_event_str_table_ofst + (log_data->asctsz * 4);
+ total_log_page_sz = stat_id_str_table_ofst + event_str_table_ofst + vu_event_str_table_ofst + ascii_table_ofst;
+
+ printf("stat_id_str_table_ofst = %lld\n",stat_id_str_table_ofst);
+ printf("event_str_table_ofst = %lld\n",event_str_table_ofst);
+ printf("vu_event_str_table_ofst = %lld\n",vu_event_str_table_ofst);
+ printf("ascii_table_ofst = %lld\n",ascii_table_ofst);
+ printf("total_log_page_sz = %lld\n",total_log_page_sz);
+
+ full_log_buf_data = (__u8 *)malloc(sizeof(__u8) * total_log_page_sz);
+ if (!full_log_buf_data) {
+ fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno));
+ return -1;
+ }
+ memset(full_log_buf_data, 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, full_log_buf_data);
+
+ if (!ret) {
+ switch (fmt) {
+ case NORMAL:
+ ocp_print_C9_log_normal(log_data,full_log_buf_data);
+ break;
+ case JSON:
+ ocp_print_C9_log_json(log_data,full_log_buf_data);
+ break;
+ case BINARY:
+ ocp_print_c9_log_binary(full_log_buf_data,total_log_page_sz);
+ break;
+ default:
+ fprintf(stderr, "unhandled output format\n");
+ break;
+ }
+ } else{
+ fprintf(stderr, "ERROR : OCP : Unable to read C9 data from buffer\n");
+ }
+ } else {
+ fprintf(stderr, "ERROR : OCP : Unable to read C9 data from buffer\n");
+ }
+
+ free(header_data);
+ free(full_log_buf_data);
+
+ return ret;
+}
+
+static int ocp_telemetry_str_log_format(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ struct nvme_dev *dev;
+ int ret = 0;
+ const char *desc = "Retrieve telemetry string log format";
+
+ 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()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ ret = get_c9_log_page(dev, cfg.output_format);
+ if (ret)
+ fprintf(stderr, "ERROR : OCP : Failure reading the C9 Log Page, ret = %d\n", ret);
+
+ dev_close(dev);
+
+ return ret;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+/// Misc
static int clear_fw_update_history(int argc, char **argv,
struct command *cmd, struct plugin *plugin)
@@ -1883,14 +2958,10 @@ static int smart_add_log(int argc, char **argv, struct command *cmd,
return ocp_smart_add_log(argc, argv, cmd, plugin);
}
-static int clear_pcie_corectable_error_counters(int argc, char **argv,
- struct command *cmd,
+static int clear_pcie_correctable_error_counters(int argc, char **argv, struct command *cmd,
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_pcie_correctable_errors(argc, argv, cmd, plugin);
}
static int fw_activation_history_log(int argc, char **argv, struct command *cmd,
diff --git a/plugins/ocp/ocp-nvme.h b/plugins/ocp/ocp-nvme.h
index 74dd0ef..95539b0 100644
--- a/plugins/ocp/ocp-nvme.h
+++ b/plugins/ocp/ocp-nvme.h
@@ -21,11 +21,15 @@ PLUGIN(NAME("ocp", "OCP cloud SSD extensions", NVME_VERSION),
ENTRY("internal-log", "Retrieve and save internal device telemetry log", ocp_telemetry_log)
ENTRY("clear-fw-activate-history", "Clear firmware update history log", clear_fw_update_history)
ENTRY("eol-plp-failure-mode", "Define EOL or PLP circuitry failure mode.", eol_plp_failure_mode)
- ENTRY("clear-pcie-correctable-error-counters", "Clear PCIe correctable error counters", clear_pcie_corectable_error_counters)
- ENTRY("vs-fw-activate-history", "Get firmware activation history log", fw_activation_history_log)
+ ENTRY("clear-pcie-correctable-errors", "Clear PCIe correctable error counters", clear_pcie_correctable_error_counters)
+ ENTRY("fw-activate-history", "Get firmware activation history log", fw_activation_history_log)
ENTRY("unsupported-reqs-log", "Get Unsupported Requirements Log Page", ocp_unsupported_requirements_log)
ENTRY("error-recovery-log", "Retrieve Error Recovery Log Page", ocp_error_recovery_log)
ENTRY("device-capability-log", "Get Device capabilities Requirements Log Page", ocp_device_capabilities_log)
+ ENTRY("set-dssd-power-state-feature", "Get Device capabilities Requirements Log Page", set_dssd_power_state_feature)
+ ENTRY("set-plp-health-check-interval", "Set PLP Health Check Interval", set_plp_health_check_interval)
+ ENTRY("get-plp-health-check-interval", "Get PLP Health Check Interval", get_plp_health_check_interval)
+ ENTRY("telemetry-string-log", "Retrieve Telemetry string Log Page", ocp_telemetry_str_log_format)
)
);
diff --git a/plugins/ocp/ocp-smart-extended-log.c b/plugins/ocp/ocp-smart-extended-log.c
index c989d34..0d8ba81 100644
--- a/plugins/ocp/ocp-smart-extended-log.c
+++ b/plugins/ocp/ocp-smart-extended-log.c
@@ -252,15 +252,15 @@ static void ocp_print_C0_log_json(void *data)
static int get_c0_log_page(int fd, char *format)
{
+ enum nvme_print_flags fmt;
__u8 *data;
int i;
- int ret = 0;
- int fmt = -1;
+ int ret;
- fmt = validate_output_format(format);
- if (fmt < 0) {
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
fprintf(stderr, "ERROR : OCP : invalid output format\n");
- return fmt;
+ return ret;
}
data = malloc(sizeof(__u8) * C0_SMART_CLOUD_ATTR_LEN);
@@ -307,6 +307,8 @@ static int get_c0_log_page(int fd, char *format)
case JSON:
ocp_print_C0_log_json(data);
break;
+ default:
+ break;
}
} else {
fprintf(stderr, "ERROR : OCP : Unable to read C0 data from buffer\n");
diff --git a/plugins/ocp/ocp-utils.c b/plugins/ocp/ocp-utils.c
index a37a58c..1257b30 100644
--- a/plugins/ocp/ocp-utils.c
+++ b/plugins/ocp/ocp-utils.c
@@ -30,66 +30,3 @@ int ocp_get_uuid_index(struct nvme_dev *dev, int *index)
}
return err;
}
-
-int ocp_clear_feature(int argc, char **argv, const char *desc, const __u8 fid)
-{
- __u32 result = 0;
- __u32 clear = 1 << 31;
- struct nvme_dev *dev;
- int uuid_index = 0;
- bool uuid = true;
- int err;
-
- OPT_ARGS(opts) = {
- OPT_FLAG("no-uuid", 'n', NULL,
- "Skip UUID index search (UUID index not required for OCP 1.0)"),
- OPT_END()
- };
-
- err = parse_and_open(&dev, argc, argv, desc, opts);
- if (err)
- return err;
-
- if (opts[0].seen)
- uuid = false;
-
- if (uuid) {
- /* OCP 2.0 requires UUID index support */
- err = ocp_get_uuid_index(dev, &uuid_index);
- if (err || !uuid_index) {
- fprintf(stderr, "ERROR: No OCP UUID index found\n");
- goto close_dev;
- }
- }
-
- struct nvme_set_features_args args = {
- .result = &result,
- .data = NULL,
- .args_size = sizeof(args),
- .fd = dev_fd(dev),
- .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
- .nsid = 0,
- .cdw11 = clear,
- .cdw12 = 0,
- .cdw13 = 0,
- .cdw15 = 0,
- .data_len = 0,
- .save = 0,
- .uuidx = uuid_index,
- .fid = fid,
- };
-
- err = nvme_set_features(&args);
-
- if (err == 0)
- printf("Success : %s\n", desc);
- else if (err > 0)
- nvme_show_status(err);
- else
- printf("Fail : %s\n", desc);
-close_dev:
- /* Redundant close() to make static code analysis happy */
- close(dev->direct.fd);
- dev_close(dev);
- return err;
-}
diff --git a/plugins/ocp/ocp-utils.h b/plugins/ocp/ocp-utils.h
index a962169..d02bea9 100644
--- a/plugins/ocp/ocp-utils.h
+++ b/plugins/ocp/ocp-utils.h
@@ -10,11 +10,9 @@
/**
* ocp_get_uuid_index() - Get OCP UUID index
* @dev: nvme device
- * @index: integer ponter to here to save the index
+ * @index: integer pointer to here to save the index
* @result: The command completion result from CQE dword0
*
* Return: Zero if nvme device has UUID list log page, or result of get uuid list otherwise.
*/
int ocp_get_uuid_index(struct nvme_dev *dev, int *index);
-
-int ocp_clear_feature(int argc, char **argv, const char *desc, const __u8 fid);
diff --git a/plugins/scaleflux/sfx-nvme.c b/plugins/scaleflux/sfx-nvme.c
index 01867c7..f752d5d 100644
--- a/plugins/scaleflux/sfx-nvme.c
+++ b/plugins/scaleflux/sfx-nvme.c
@@ -21,6 +21,7 @@
#include "linux/types.h"
#include "nvme-wrap.h"
#include "nvme-print.h"
+#include "util/cleanup.h"
#define CREATE_CMD
#include "sfx-nvme.h"
@@ -881,7 +882,7 @@ static int change_sanity_check(int fd, __u64 trg_in_4k, int *shrink)
if (trg_in_4k < provisoned_cap_4k ||
trg_in_4k > ((__u64)provisoned_cap_4k * 4)) {
fprintf(stderr,
- "WARNING: Only support 1.0~4.0 x provisoned capacity!\n");
+ "WARNING: Only support 1.0~4.0 x provisioned capacity!\n");
if (trg_in_4k < provisoned_cap_4k)
fprintf(stderr,
"WARNING: The target capacity is less than 1.0 x provisioned capacity!\n");
@@ -924,7 +925,7 @@ static int change_sanity_check(int fd, __u64 trg_in_4k, int *shrink)
*
* @param str, prompt string
*
- * @return 0, cancled; 1 confirmed
+ * @return 0, canceled; 1 confirmed
*/
static int sfx_confirm_change(const char *str)
{
@@ -936,7 +937,7 @@ static int sfx_confirm_change(const char *str)
fprintf(stderr, "Confirm Y/y, Others cancel:\n");
confirm = (unsigned char)fgetc(stdin);
if (confirm != 'y' && confirm != 'Y') {
- fprintf(stderr, "Cancled.\n");
+ fprintf(stderr, "Canceled.\n");
return 0;
}
fprintf(stderr, "Sending operation ...\n");
@@ -1349,12 +1350,12 @@ static int nvme_dump_evtlog(struct nvme_dev *dev, __u32 namespace_id, __u32 stor
{
struct nvme_persistent_event_log *pevent;
void *pevent_log_info;
+ _cleanup_huge_ struct nvme_mem_huge mh = { 0, };
__u8 lsp_base;
__u32 offset = 0;
__u32 length = 0;
__u32 log_len;
__u32 single_len;
- bool huge;
int err = 0;
FILE *fd = NULL;
struct nvme_get_log_args args = {
@@ -1410,7 +1411,7 @@ static int nvme_dump_evtlog(struct nvme_dev *dev, __u32 namespace_id, __u32 stor
if (log_len % 4)
log_len = (log_len / 4 + 1) * 4;
- pevent_log_info = nvme_alloc(single_len, &huge);
+ pevent_log_info = nvme_alloc_huge(single_len, &mh);
if (!pevent_log_info) {
err = -ENOMEM;
goto free_pevent;
@@ -1420,7 +1421,7 @@ static int nvme_dump_evtlog(struct nvme_dev *dev, __u32 namespace_id, __u32 stor
if (!fd) {
fprintf(stderr, "Failed to open %s file to write\n", file);
err = ENOENT;
- goto free;
+ goto free_pevent;
}
args.lsp = lsp_base + NVME_PEVENT_LOG_READ;
@@ -1453,8 +1454,8 @@ static int nvme_dump_evtlog(struct nvme_dev *dev, __u32 namespace_id, __u32 stor
printf("\nDump-evtlog: Success\n");
if (parse) {
- nvme_free(pevent_log_info, huge);
- pevent_log_info = nvme_alloc(log_len, &huge);
+ nvme_free_huge(&mh);
+ pevent_log_info = nvme_alloc_huge(log_len, &mh);
if (!pevent_log_info) {
fprintf(stderr, "Failed to alloc enough memory 0x%x to parse evtlog\n", log_len);
err = -ENOMEM;
@@ -1466,7 +1467,7 @@ static int nvme_dump_evtlog(struct nvme_dev *dev, __u32 namespace_id, __u32 stor
if (!fd) {
fprintf(stderr, "Failed to open %s file to read\n", file);
err = ENOENT;
- goto free;
+ goto free_pevent;
}
if (fread(pevent_log_info, 1, log_len, fd) != log_len) {
fprintf(stderr, "Failed to read evtlog to buffer\n");
@@ -1478,8 +1479,6 @@ static int nvme_dump_evtlog(struct nvme_dev *dev, __u32 namespace_id, __u32 stor
close_fd:
fclose(fd);
-free:
- nvme_free(pevent_log_info, huge);
free_pevent:
free(pevent);
ret:
diff --git a/plugins/seagate/seagate-nvme.c b/plugins/seagate/seagate-nvme.c
index 0f4f59d..887e5bc 100644
--- a/plugins/seagate/seagate-nvme.c
+++ b/plugins/seagate/seagate-nvme.c
@@ -926,7 +926,7 @@ static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugi
/**
* Here we should identify if the drive is a Panthor or Jaguar.
* Here we need to extract the model no from ctrl-id abd use it
- * to deternine drive family.
+ * to determine drive family.
*/
err = nvme_identify_ctrl(dev_fd(dev), &ctrl);
@@ -1299,7 +1299,7 @@ static void print_stx_vs_fw_activate_history(stx_fw_activ_history_log_page fwAct
char buf[80];
if (fwActivHis.numValidFwActHisEnt > 0) {
- printf("\n\nSeagate FW Activation Histry :\n");
+ printf("\n\nSeagate FW Activation History :\n");
printf("%-9s %-21s %-7s %-13s %-9s %-5s %-15s %-9s\n", "Counter ", " Timestamp ", " PCC ", "Previous FW ", "New FW ", "Slot", "Commit Action", "Result");
for (i = 0; i < fwActivHis.numValidFwActHisEnt; i++) {
@@ -1406,7 +1406,7 @@ static int stx_vs_fw_activate_history(int argc, char **argv, struct command *cmd
}
if (strcmp(cfg.output_format, "json"))
- printf("Seagate FW Activation Histry Information :\n");
+ printf("Seagate FW Activation History Information :\n");
err = nvme_get_log_simple(dev_fd(dev), 0xC2, sizeof(fwActivHis), &fwActivHis);
if (!err) {
diff --git a/plugins/solidigm/meson.build b/plugins/solidigm/meson.build
index 84495a1..052afa1 100644
--- a/plugins/solidigm/meson.build
+++ b/plugins/solidigm/meson.build
@@ -8,6 +8,9 @@ sources += [
'plugins/solidigm/solidigm-telemetry.c',
'plugins/solidigm/solidigm-internal-logs.c',
'plugins/solidigm/solidigm-market-log.c',
+ 'plugins/solidigm/solidigm-temp-stats.c',
+ 'plugins/solidigm/solidigm-get-drive-info.c',
+ 'plugins/solidigm/solidigm-ocp-version.c',
]
subdir('solidigm-telemetry')
diff --git a/plugins/solidigm/solidigm-garbage-collection.c b/plugins/solidigm/solidigm-garbage-collection.c
index b26d754..a37e9c5 100644
--- a/plugins/solidigm/solidigm-garbage-collection.c
+++ b/plugins/solidigm/solidigm-garbage-collection.c
@@ -68,6 +68,7 @@ static void vu_gc_log_show(struct garbage_control_collection_log *payload, const
int solidigm_get_garbage_collection_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Get and parse Solidigm vendor specific garbage collection event log.";
+ enum nvme_print_flags flags;
struct nvme_dev *dev;
int err;
__u8 uuid_index;
@@ -89,9 +90,8 @@ int solidigm_get_garbage_collection_log(int argc, char **argv, struct command *c
if (err)
return err;
- enum nvme_print_flags flags = validate_output_format(cfg.output_format);
-
- if (flags == -EINVAL) {
+ err = validate_output_format(cfg.output_format, &flags);
+ if (err) {
fprintf(stderr, "Invalid output format '%s'\n", cfg.output_format);
dev_close(dev);
return -EINVAL;
diff --git a/plugins/solidigm/solidigm-get-drive-info.c b/plugins/solidigm/solidigm-get-drive-info.c
new file mode 100644
index 0000000..21f59bb
--- /dev/null
+++ b/plugins/solidigm/solidigm-get-drive-info.c
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Authors: leonardo.da.cunha@solidigm.com
+ */
+
+#include <errno.h>
+#include "nvme-print.h"
+#include "nvme-wrap.h"
+#include "common.h"
+
+int sldgm_get_drive_info(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ const char *desc = "Get drive HW information";
+ const char *FTL_unit_size_str = "FTL_unit_size";
+ char *output_format = "normal";
+ enum nvme_print_flags flags;
+ nvme_root_t r;
+ nvme_ctrl_t c;
+ nvme_ns_t n;
+ struct nvme_id_ns ns = { 0 };
+ __u8 flbaf_inUse;
+ __u16 lba_size;
+ __u16 ftl_unit_size;
+ int err;
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &output_format, "normal|json"),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format, &flags);
+ if ((err < 0) || !(flags == NORMAL || flags == JSON)) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ r = nvme_scan(NULL);
+ c = nvme_scan_ctrl(r, dev->name);
+ n = c ? nvme_ctrl_first_ns(c) : nvme_scan_namespace(dev->name);
+ if (!n) {
+ nvme_show_error("solidigm-vs-drive-info: drive missing namespace");
+ return -EINVAL;
+ }
+
+ err = nvme_ns_identify(n, &ns);
+ if (err) {
+ nvme_show_error("identify namespace: %s", nvme_strerror(errno));
+ return err;
+ }
+
+ if (!(ns.nsfeat & 0x10)) {
+ nvme_show_error("solidigm-vs-drive-info: performance options not available");
+ return -EINVAL;
+ }
+
+ nvme_id_ns_flbas_to_lbaf_inuse(ns.flbas, &flbaf_inUse);
+ lba_size = 1 << ns.lbaf[flbaf_inUse].ds;
+ ftl_unit_size = (le16_to_cpu(ns.npwg) + 1) * lba_size / 1024;
+
+ if (flags == JSON) {
+ struct json_object *root = json_create_object();
+
+ json_object_add_value_int(root, FTL_unit_size_str, ftl_unit_size);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+ } else {
+ printf("%s: %d\n", FTL_unit_size_str, ftl_unit_size);
+ }
+
+ return err;
+}
diff --git a/plugins/solidigm/solidigm-get-drive-info.h b/plugins/solidigm/solidigm-get-drive-info.h
new file mode 100644
index 0000000..ffc1bd2
--- /dev/null
+++ b/plugins/solidigm/solidigm-get-drive-info.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+int sldgm_get_drive_info(int argc, char **argv, struct command *cmd, struct plugin *plugin);
diff --git a/plugins/solidigm/solidigm-internal-logs.c b/plugins/solidigm/solidigm-internal-logs.c
index 4730443..236652a 100644
--- a/plugins/solidigm/solidigm-internal-logs.c
+++ b/plugins/solidigm/solidigm-internal-logs.c
@@ -19,6 +19,7 @@
#include "libnvme.h"
#include "plugin.h"
#include "nvme-print.h"
+#include "solidigm-util.h"
#define DWORD_SIZE 4
@@ -427,7 +428,8 @@ static int dump_telemetry(struct nvme_dev *dev, struct config cfg, enum telemetr
int err = 0, output;
__u8 *buffer = NULL;
size_t bytes_remaining = 0;
- int data_area = NVME_TELEMETRY_DA_3;
+ enum nvme_telemetry_da da;
+ size_t max_data_tx;
char file_path[PATH_MAX];
char *log_name;
@@ -444,6 +446,12 @@ static int dump_telemetry(struct nvme_dev *dev, struct config cfg, enum telemetr
default:
return -EINVAL;
}
+ err = nvme_get_telemetry_max(dev_fd(dev), &da, &max_data_tx);
+ if (err)
+ return err;
+
+ if (max_data_tx > DRIVER_MAX_TX_256K)
+ max_data_tx = DRIVER_MAX_TX_256K;
sprintf(file_path, "%s_%s.bin", cfg.file_prefix, log_name);
output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
@@ -452,16 +460,16 @@ static int dump_telemetry(struct nvme_dev *dev, struct config cfg, enum telemetr
switch (ttype) {
case HOSTGENNEW:
- err = nvme_get_new_host_telemetry(dev_fd(dev), &log,
- data_area, &log_size);
+ err = nvme_get_telemetry_log(dev_fd(dev), true, false, false, max_data_tx, da,
+ &log, &log_size);
break;
case HOSTGENOLD:
- err = nvme_get_host_telemetry(dev_fd(dev), &log,
- data_area, &log_size);
+ err = nvme_get_telemetry_log(dev_fd(dev), false, false, false, max_data_tx, da,
+ &log, &log_size);
break;
case CONTROLLER:
- err = nvme_get_ctrl_telemetry(dev_fd(dev), true, &log,
- data_area, &log_size);
+ err = nvme_get_telemetry_log(dev_fd(dev), false, true, true, max_data_tx, da, &log,
+ &log_size);
break;
}
@@ -546,42 +554,42 @@ int solidigm_get_internal_log(int argc, char **argv, struct command *command,
if (err == 0)
log_count++;
else if (err < 0)
- perror("Assert log");
+ perror("Error retrieving Assert log");
}
if (all || !strcmp(cfg.type, "EVENT")) {
err = dump_event_logs(dev, cfg);
if (err == 0)
log_count++;
else if (err < 0)
- perror("Eventt log");
+ perror("Error retrieving Event log");
}
if (all || !strcmp(cfg.type, "NLOG")) {
err = dump_nlogs(dev, cfg, -1);
if (err == 0)
log_count++;
else if (err < 0)
- perror("Nlog");
+ perror("Error retrieving Nlog");
}
if (all || !strcmp(cfg.type, "CONTROLLERINITTELEMETRY")) {
err = dump_telemetry(dev, cfg, CONTROLLER);
if (err == 0)
log_count++;
else if (err < 0)
- perror("Telemetry Controller Initated");
+ perror("Error retrieving Telemetry Controller Initiated");
}
if (all || !strcmp(cfg.type, "HOSTINITTELEMETRYNOGEN")) {
err = dump_telemetry(dev, cfg, HOSTGENOLD);
if (err == 0)
log_count++;
else if (err < 0)
- perror("Previously existing Telemetry Host Initated");
+ perror("Error retrieving previously existing Telemetry Host Initiated");
}
if (all || !strcmp(cfg.type, "HOSTINITTELEMETRY")) {
err = dump_telemetry(dev, cfg, HOSTGENNEW);
if (err == 0)
log_count++;
else if (err < 0)
- perror("Telemetry Host Initated");
+ perror("Error retrieving Telemetry Host Initiated");
}
if (log_count == 0) {
diff --git a/plugins/solidigm/solidigm-latency-tracking.c b/plugins/solidigm/solidigm-latency-tracking.c
index 481a831..66f3c56 100644
--- a/plugins/solidigm/solidigm-latency-tracking.c
+++ b/plugins/solidigm/solidigm-latency-tracking.c
@@ -411,8 +411,8 @@ int solidigm_get_latency_tracking_log(int argc, char **argv, struct command *cmd
lt.fd = dev_fd(dev);
- lt.print_flags = validate_output_format(lt.cfg.output_format);
- if (lt.print_flags == -EINVAL) {
+ err = validate_output_format(lt.cfg.output_format, &lt.print_flags);
+ if (err < 0) {
fprintf(stderr, "Invalid output format '%s'\n", lt.cfg.output_format);
dev_close(dev);
return -EINVAL;
diff --git a/plugins/solidigm/solidigm-log-page-dir.c b/plugins/solidigm/solidigm-log-page-dir.c
index 111a433..bf272f8 100644
--- a/plugins/solidigm/solidigm-log-page-dir.c
+++ b/plugins/solidigm/solidigm-log-page-dir.c
@@ -100,38 +100,13 @@ static struct lid_dir *get_standard_lids(struct nvme_supported_log_pages *suppor
static struct lid_dir standard_dir = { 0 };
init_lid_dir(&standard_dir);
- standard_dir.lid[0x00].str = "Supported Log Pages";
- standard_dir.lid[0x01].str = "Error Information";
- standard_dir.lid[0x02].str = "SMART / Health Information";
- standard_dir.lid[0x03].str = "Firmware Slot Information";
- standard_dir.lid[0x04].str = "Changed Namespace List";
- standard_dir.lid[0x05].str = "Commands Supported and Effects";
- standard_dir.lid[0x06].str = "Device Self Test";
- standard_dir.lid[0x07].str = "Telemetry Host-Initiated";
- standard_dir.lid[0x08].str = "Telemetry Controller-Initiated";
- standard_dir.lid[0x09].str = "Endurance Group Information";
- standard_dir.lid[0x0A].str = "Predictable Latency Per NVM Set";
- standard_dir.lid[0x0B].str = "Predictable Latency Event Aggregate";
- standard_dir.lid[0x0C].str = "Asymmetric Namespace Access";
- standard_dir.lid[0x0D].str = "Persistent Event Log";
- standard_dir.lid[0x0E].str = "Predictable Latency Event Aggregate";
- standard_dir.lid[0x0F].str = "Endurance Group Event Aggregate";
- standard_dir.lid[0x10].str = "Media Unit Status";
- standard_dir.lid[0x11].str = "Supported Capacity Configuration List";
- standard_dir.lid[0x12].str = "Feature Identifiers Supported and Effects";
- standard_dir.lid[0x13].str = "NVMe-MI Commands Supported and Effects";
- standard_dir.lid[0x14].str = "Command and Feature lockdown";
- standard_dir.lid[0x15].str = "Boot Partition";
- standard_dir.lid[0x16].str = "Rotational Media Information";
- standard_dir.lid[0x70].str = "Discovery";
- standard_dir.lid[0x80].str = "Reservation Notification";
- standard_dir.lid[0x81].str = "Sanitize Status";
for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) {
if (!supported->lid_support[lid] || lid >= MIN_VENDOR_LID)
continue;
standard_dir.lid[lid].supported = true;
+ standard_dir.lid[lid].str = nvme_log_to_string(lid);
}
return &standard_dir;
@@ -158,6 +133,14 @@ static struct lid_dir *get_solidigm_lids(struct nvme_supported_log_pages *suppor
solidigm_dir.lid[0xC4].str = "Endurance Manager Statistics";
solidigm_dir.lid[0xC5].str = "Temperature Statistics";
solidigm_dir.lid[0xCA].str = "SMART Attributes";
+ solidigm_dir.lid[0xCB].str = "VU NVMe IO Queue Metrics Log Page";
+ solidigm_dir.lid[0xDD].str = "VU Marketing Description Log Page";
+ solidigm_dir.lid[0xEF].str = "Performance Rating and LBA Access Histogram";
+ solidigm_dir.lid[0xF2].str = "Get Power Usage Log Page";
+ solidigm_dir.lid[0xF6].str = "Vt Histo Get Log Page";
+ solidigm_dir.lid[0xF9].str = "Workload Tracker Get Log Page";
+ solidigm_dir.lid[0xFD].str = "Garbage Control Collection Log Page";
+ solidigm_dir.lid[0xFE].str = "Latency Outlier Log Page";
update_vendor_lid_supported(supported, &solidigm_dir);
@@ -281,15 +264,18 @@ int solidigm_get_log_page_directory_log(int argc, char **argv, struct command *c
}
if (!err) {
- const enum nvme_print_flags print_flag = validate_output_format(format);
+ enum nvme_print_flags print_flag;
+
+ err = validate_output_format(format, &print_flag);
+ if (err < 0) {
+ fprintf(stderr, "Error: Invalid output format specified: %s.\n", format);
+ return err;
+ }
if (print_flag == NORMAL) {
supported_log_pages_normal(lid_dirs);
} else if (print_flag == JSON) {
supported_log_pages_json(lid_dirs);
- } else {
- fprintf(stderr, "Error: Invalid output format specified: %s.\n", format);
- err = -EINVAL;
}
}
diff --git a/plugins/solidigm/solidigm-nvme.c b/plugins/solidigm/solidigm-nvme.c
index b0db1ea..3fb86f5 100644
--- a/plugins/solidigm/solidigm-nvme.c
+++ b/plugins/solidigm/solidigm-nvme.c
@@ -18,8 +18,11 @@
#include "solidigm-telemetry.h"
#include "solidigm-log-page-dir.h"
#include "solidigm-market-log.h"
+#include "solidigm-temp-stats.h"
+#include "solidigm-get-drive-info.h"
+#include "solidigm-ocp-version.h"
-#include "plugins/ocp/ocp-clear-fw-update-history.h"
+#include "plugins/ocp/ocp-clear-features.h"
#include "plugins/ocp/ocp-smart-extended-log.h"
#include "plugins/ocp/ocp-fw-activation-history.h"
@@ -59,6 +62,12 @@ static int clear_fw_update_history(int argc, char **argv, struct command *cmd,
return ocp_clear_fw_update_history(argc, argv, cmd, plugin);
}
+static int clear_pcie_correctable_error_counters(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ return ocp_clear_pcie_correctable_errors(argc, argv, cmd, plugin);
+}
+
static int smart_cloud(int argc, char **argv, struct command *cmd,
struct plugin *plugin)
{
@@ -82,3 +91,19 @@ static int get_market_log(int argc, char **argv, struct command *cmd,
{
return sldgm_get_market_log(argc, argv, cmd, plugin);
}
+
+static int get_temp_stats_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ return sldgm_get_temp_stats_log(argc, argv, cmd, plugin);
+}
+
+static int get_drive_info(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ return sldgm_get_drive_info(argc, argv, cmd, plugin);
+}
+
+static int get_cloud_SSDplugin_version(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ return sldgm_ocp_version(argc, argv, cmd, plugin);
+}
diff --git a/plugins/solidigm/solidigm-nvme.h b/plugins/solidigm/solidigm-nvme.h
index 69b63e5..a984a38 100644
--- a/plugins/solidigm/solidigm-nvme.h
+++ b/plugins/solidigm/solidigm-nvme.h
@@ -13,7 +13,7 @@
#include "cmd.h"
-#define SOLIDIGM_PLUGIN_VERSION "0.14"
+#define SOLIDIGM_PLUGIN_VERSION "1.0"
PLUGIN(NAME("solidigm", "Solidigm vendor specific extensions", SOLIDIGM_PLUGIN_VERSION),
COMMAND_LIST(
@@ -25,9 +25,13 @@ PLUGIN(NAME("solidigm", "Solidigm vendor specific extensions", SOLIDIGM_PLUGIN_V
ENTRY("market-log", "Retrieve Market Log", get_market_log)
ENTRY("latency-tracking-log", "Enable/Retrieve Latency tracking Log", get_latency_tracking_log)
ENTRY("parse-telemetry-log", "Parse Telemetry Log binary", get_telemetry_log)
+ ENTRY("clear-pcie-correctable-errors ", "Clear PCIe Correctable Error Counters (redirects to ocp plug-in)", clear_pcie_correctable_error_counters)
ENTRY("clear-fw-activate-history", "Clear firmware update history log (redirects to ocp plug-in)", clear_fw_update_history)
ENTRY("vs-fw-activate-history", "Get firmware activation history log (redirects to ocp plug-in)", fw_activation_history)
ENTRY("log-page-directory", "Retrieve log page directory", get_log_page_directory_log)
+ ENTRY("temp-stats", "Retrieve Temperature Statistics log", get_temp_stats_log)
+ ENTRY("vs-drive-info", "Retrieve drive information", get_drive_info)
+ ENTRY("cloud-SSDplugin-version", "Prints plug-in OCP version", get_cloud_SSDplugin_version)
)
);
diff --git a/plugins/solidigm/solidigm-ocp-version.c b/plugins/solidigm/solidigm-ocp-version.c
new file mode 100644
index 0000000..4048cc1
--- /dev/null
+++ b/plugins/solidigm/solidigm-ocp-version.c
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include <stdio.h>
+#include "nvme.h"
+
+int sldgm_ocp_version(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Prints OCP extensions version of Solidigm plugin";
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ int err = argconfig_parse(argc, argv, desc, opts);
+
+ if (!err)
+ printf("1.0\n");
+
+ return err;
+}
diff --git a/plugins/solidigm/solidigm-ocp-version.h b/plugins/solidigm/solidigm-ocp-version.h
new file mode 100644
index 0000000..d79452c
--- /dev/null
+++ b/plugins/solidigm/solidigm-ocp-version.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+int sldgm_ocp_version(int argc, char **argv, struct command *cmd, struct plugin *plugin);
diff --git a/plugins/solidigm/solidigm-smart.c b/plugins/solidigm/solidigm-smart.c
index e3d468a..62245fa 100644
--- a/plugins/solidigm/solidigm-smart.c
+++ b/plugins/solidigm/solidigm-smart.c
@@ -69,15 +69,17 @@ static char *id_to_name(__u8 id)
case 0xE2:
return "media_wear_percentage";
case 0xE3:
- return "host_reads";
+ return "timed_work_load_host_reads";
case 0xE4:
- return "timed_work_load";
+ return "timed_work_load_timer";
case 0xE5:
return "read_commands_in_flight_counter";
case 0xE6:
return "write_commands_in_flight_counter";
case 0xEA:
return "thermal_throttle_status";
+ case 0xEE:
+ return "re_sku_count";
case 0xF0:
return "retry_buffer_overflow_counter";
case 0xF3:
@@ -220,11 +222,11 @@ int solidigm_get_additional_smart_log(int argc, char **argv, struct command *cmd
if (err)
return err;
- flags = validate_output_format(cfg.output_format);
- if (flags == -EINVAL) {
+ err = validate_output_format(cfg.output_format, &flags);
+ if (err < 0) {
fprintf(stderr, "Invalid output format '%s'\n", cfg.output_format);
dev_close(dev);
- return flags;
+ return err;
}
uuid_index = solidigm_get_vu_uuid_index(dev);
diff --git a/plugins/solidigm/solidigm-telemetry.c b/plugins/solidigm/solidigm-telemetry.c
index 472284a..2bebccc 100644
--- a/plugins/solidigm/solidigm-telemetry.c
+++ b/plugins/solidigm/solidigm-telemetry.c
@@ -22,6 +22,7 @@
#include "solidigm-telemetry/header.h"
#include "solidigm-telemetry/config.h"
#include "solidigm-telemetry/data-area.h"
+#include "solidigm-util.h"
static int read_file2buffer(char *file_name, char **buffer, size_t *length)
{
@@ -71,7 +72,7 @@ int solidigm_get_telemetry_log(int argc, char **argv, struct command *cmd, struc
struct config cfg = {
.host_gen = 1,
.ctrl_init = false,
- .data_area = 3,
+ .data_area = -1,
.cfg_file = NULL,
.is_input_file = false,
};
@@ -90,6 +91,10 @@ int solidigm_get_telemetry_log(int argc, char **argv, struct command *cmd, struc
if (err)
goto ret;
+ /* When not selected on the command line, get minimum data area required */
+ if (cfg.data_area == -1)
+ cfg.data_area = cfg.cfg_file ? 3 : 1;
+
if (cfg.is_input_file) {
if (optind >= argc) {
err = errno = EINVAL;
@@ -138,19 +143,23 @@ int solidigm_get_telemetry_log(int argc, char **argv, struct command *cmd, struc
}
if (!cfg.is_input_file) {
- if (cfg.ctrl_init)
- err = nvme_get_ctrl_telemetry(dev_fd(dev), true,
- &tl.log, cfg.data_area,
- &tl.log_size);
- else if (cfg.host_gen)
- err = nvme_get_new_host_telemetry(dev_fd(dev), &tl.log,
- cfg.data_area,
- &tl.log_size);
- else
- err = nvme_get_host_telemetry(dev_fd(dev), &tl.log,
- cfg.data_area,
- &tl.log_size);
+ size_t max_data_tx;
+
+ err = nvme_get_telemetry_max(dev_fd(dev), NULL, &max_data_tx);
+ if (err < 0) {
+ SOLIDIGM_LOG_WARNING("identify_ctrl: %s",
+ nvme_strerror(errno));
+ goto close_fd;
+ } else if (err > 0) {
+ nvme_show_status(err);
+ SOLIDIGM_LOG_WARNING("Failed to acquire identify ctrl %d!", err);
+ goto close_fd;
+ }
+ if (max_data_tx > DRIVER_MAX_TX_256K)
+ max_data_tx = DRIVER_MAX_TX_256K;
+ err = nvme_get_telemetry_log(dev_fd(dev), cfg.host_gen, cfg.ctrl_init, true,
+ max_data_tx, cfg.data_area, &tl.log, &tl.log_size);
if (err < 0) {
SOLIDIGM_LOG_WARNING("get-telemetry-log: %s",
nvme_strerror(errno));
diff --git a/plugins/solidigm/solidigm-telemetry/config.c b/plugins/solidigm/solidigm-telemetry/config.c
index cc2a8bb..eceeede 100644
--- a/plugins/solidigm/solidigm-telemetry/config.c
+++ b/plugins/solidigm/solidigm-telemetry/config.c
@@ -9,7 +9,7 @@
#include <string.h>
#include "config.h"
-// max 16 bit unsigned integer nummber 65535
+// max 16 bit unsigned integer number 65535
#define MAX_16BIT_NUM_AS_STRING_SIZE 6
#define OBJ_NAME_PREFIX "UID_"
diff --git a/plugins/solidigm/solidigm-telemetry/data-area.c b/plugins/solidigm/solidigm-telemetry/data-area.c
index 0cfa56c..14d612b 100644
--- a/plugins/solidigm/solidigm-telemetry/data-area.c
+++ b/plugins/solidigm/solidigm-telemetry/data-area.c
@@ -57,7 +57,7 @@ static bool telemetry_log_get_value(const struct telemetry_log *tl,
char err_msg[MAX_WARNING_SIZE];
snprintf(err_msg, MAX_WARNING_SIZE,
- "Value crossing 64 bit, byte aligned bounday, not supported. size_bit=%u, offset_bit_from_byte=%u.",
+ "Value crossing 64 bit, byte aligned boundary, not supported. size_bit=%u, offset_bit_from_byte=%u.",
size_bit, offset_bit_from_byte);
*val_obj = json_object_new_string(err_msg);
diff --git a/plugins/solidigm/solidigm-telemetry/nlog.c b/plugins/solidigm/solidigm-telemetry/nlog.c
index 43b8918..926772b 100644
--- a/plugins/solidigm/solidigm-telemetry/nlog.c
+++ b/plugins/solidigm/solidigm-telemetry/nlog.c
@@ -8,15 +8,16 @@
#include "nlog.h"
#include "config.h"
#include <string.h>
-#include <math.h>
#include <stdio.h>
+#include "ccan/ilog/ilog.h"
+
#define LOG_ENTRY_HEADER_SIZE 1
#define LOG_ENTRY_TIMESTAMP_SIZE 2
#define LOG_ENTRY_NUM_ARGS_MAX 8
#define LOG_ENTRY_MAX_SIZE (LOG_ENTRY_HEADER_SIZE + LOG_ENTRY_TIMESTAMP_SIZE + \
LOG_ENTRY_NUM_ARGS_MAX)
-#define NUM_ARGS_MASK ((1 << ((int)log2(LOG_ENTRY_NUM_ARGS_MAX)+1)) - 1)
+#define NUM_ARGS_MASK ((1 << ((int)STATIC_ILOG_32(LOG_ENTRY_NUM_ARGS_MAX))) - 1)
#define MAX_HEADER_MISMATCH_TRACK 10
static int formats_find(struct json_object *formats, uint32_t val, struct json_object **format)
diff --git a/plugins/solidigm/solidigm-temp-stats.c b/plugins/solidigm/solidigm-temp-stats.c
new file mode 100644
index 0000000..85a3c37
--- /dev/null
+++ b/plugins/solidigm/solidigm-temp-stats.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include <errno.h>
+
+#include "common.h"
+#include "nvme-print.h"
+#include "solidigm-util.h"
+
+#define SLDGM_TEMP_STATS_LID 0xC5
+
+struct temp_stats {
+ __le64 curr;
+ __le64 last_overtemp;
+ __le64 life_overtemp;
+ __le64 highest_temp;
+ __le64 lowest_temp;
+ __u8 rsvd[40];
+ __le64 max_operating_temp;
+ __le64 min_operating_temp;
+ __le64 est_offset;
+};
+
+static void show_temp_stats(struct temp_stats *stats)
+{
+ printf("Current temperature : %"PRIu64"\n", le64_to_cpu(stats->curr));
+ printf("Last critical overtemp flag : %"PRIu64"\n", le64_to_cpu(stats->last_overtemp));
+ printf("Life critical overtemp flag : %"PRIu64"\n", le64_to_cpu(stats->life_overtemp));
+ printf("Highest temperature : %"PRIu64"\n", le64_to_cpu(stats->highest_temp));
+ printf("Lowest temperature : %"PRIu64"\n", le64_to_cpu(stats->lowest_temp));
+ printf("Max operating temperature : %"PRIu64"\n", le64_to_cpu(stats->max_operating_temp));
+ printf("Min operating temperature : %"PRIu64"\n", le64_to_cpu(stats->min_operating_temp));
+ printf("Estimated offset : %"PRIu64"\n", le64_to_cpu(stats->est_offset));
+}
+
+int sldgm_get_temp_stats_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ unsigned char buffer[4096] = {0};
+ struct nvme_dev *dev;
+ __u8 uuid_idx;
+ int err;
+
+ const char *desc = "Get/show Temperature Statistics log.";
+ const char *raw = "dump output in binary format";
+ struct config {
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ .raw_binary = false,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ uuid_idx = solidigm_get_vu_uuid_index(dev);
+
+ struct nvme_get_log_args args = {
+ .lpo = 0,
+ .result = NULL,
+ .log = buffer,
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .uuidx = uuid_idx,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .lid = SLDGM_TEMP_STATS_LID,
+ .len = sizeof(buffer),
+ .nsid = NVME_NSID_ALL,
+ .csi = NVME_CSI_NVM,
+ .lsi = NVME_LOG_LSI_NONE,
+ .lsp = NVME_LOG_LSP_NONE,
+ .rae = false,
+ .ot = false,
+ };
+
+ err = nvme_get_log(&args);
+ if (!err) {
+ uint64_t *guid = (uint64_t *)&buffer[4080];
+
+ if (guid[1] == 0xC7BB98B7D0324863 && guid[0] == 0xBB2C23990E9C722F) {
+ fprintf(stderr, "Error: Log page has 'OCP unsupported Requirements' GUID\n");
+ err = -EBADMSG;
+ goto closefd;
+ }
+ if (!cfg.raw_binary)
+ show_temp_stats((struct temp_stats *) buffer);
+ else
+ d_raw(buffer, sizeof(struct temp_stats));
+ } else if (err > 0) {
+ nvme_show_status(err);
+ }
+
+closefd:
+ /* Redundant close() to make static code analysis happy */
+ close(dev->direct.fd);
+ dev_close(dev);
+ return err;
+}
diff --git a/plugins/solidigm/solidigm-temp-stats.h b/plugins/solidigm/solidigm-temp-stats.h
new file mode 100644
index 0000000..58d5a86
--- /dev/null
+++ b/plugins/solidigm/solidigm-temp-stats.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+int sldgm_get_temp_stats_log(int argc, char **argv, struct command *cmd, struct plugin *plugin);
diff --git a/plugins/solidigm/solidigm-util.h b/plugins/solidigm/solidigm-util.h
index 3a18501..fa5032f 100644
--- a/plugins/solidigm/solidigm-util.h
+++ b/plugins/solidigm/solidigm-util.h
@@ -7,4 +7,6 @@
#include "nvme.h"
+#define DRIVER_MAX_TX_256K (256 * 1024)
+
__u8 solidigm_get_vu_uuid_index(struct nvme_dev *dev);
diff --git a/plugins/wdc/wdc-nvme.c b/plugins/wdc/wdc-nvme.c
index ec3f2b0..d663131 100644
--- a/plugins/wdc/wdc-nvme.c
+++ b/plugins/wdc/wdc-nvme.c
@@ -36,6 +36,7 @@
#include "libnvme.h"
#include "plugin.h"
#include "linux/types.h"
+#include "util/cleanup.h"
#include "util/types.h"
#include "nvme-print.h"
@@ -80,12 +81,14 @@
#define WDC_NVME_SN655_DEV_ID 0x2722
#define WDC_NVME_SN860_DEV_ID 0x2730
#define WDC_NVME_SN660_DEV_ID 0x2704
-
-/* This id's are no longer supported, delete ?? */
-#define WDC_NVME_SN550_DEV_ID 0x2708
#define WDC_NVME_SN560_DEV_ID_1 0x2712
#define WDC_NVME_SN560_DEV_ID_2 0x2713
#define WDC_NVME_SN560_DEV_ID_3 0x2714
+#define WDC_NVME_SN861_DEV_ID 0x2750
+#define WDC_NVME_SN861_DEV_ID_1 0x2751
+
+/* This id's are no longer supported, delete ?? */
+#define WDC_NVME_SN550_DEV_ID 0x2708
#define WDC_NVME_SXSLCL_DEV_ID 0x2001
#define WDC_NVME_SN520_DEV_ID 0x5003
@@ -147,6 +150,8 @@
#define WDC_DRIVE_CAP_OCP_C4_LOG_PAGE 0x0000004000000000
#define WDC_DRIVE_CAP_OCP_C5_LOG_PAGE 0x0000008000000000
#define WDC_DRIVE_CAP_DEVICE_WAF 0x0000010000000000
+#define WDC_DRIVE_CAP_SET_LATENCY_MONITOR 0x0000020000000000
+
#define WDC_DRIVE_CAP_SMART_LOG_MASK (WDC_DRIVE_CAP_C0_LOG_PAGE | \
WDC_DRIVE_CAP_C1_LOG_PAGE | \
WDC_DRIVE_CAP_CA_LOG_PAGE | \
@@ -162,6 +167,7 @@
WDC_DRIVE_CAP_DUI | \
WDC_DRIVE_CAP_DUI_DATA | \
WDC_SN730B_CAP_VUC_LOG)
+
/* SN730 Get Log Capabilities */
#define SN730_NVME_GET_LOG_OPCODE 0xc2
#define SN730_GET_FULL_LOG_LENGTH 0x00080009
@@ -301,8 +307,8 @@
#define WDC_NVME_GET_STAT_PERF_INTERVAL_LIFETIME 0x0F
/* C2 Log Page */
-#define WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE 0xC2
-#define WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE_C8 0xC8
+#define WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID 0xC2
+#define WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID_C8 0xC8
#define WDC_C2_LOG_BUF_LEN 0x1000
#define WDC_C2_LOG_PAGES_SUPPORTED_ID 0x08
#define WDC_C2_CUSTOMER_ID_ID 0x15
@@ -367,12 +373,12 @@ static __u8 wdc_lat_mon_guid[WDC_C3_GUID_LENGTH] = {
#define NVME_LOG_PERSISTENT_EVENT 0x0D
#define WDC_LOG_ID_C0 0xC0
#define WDC_LOG_ID_C1 0xC1
-#define WDC_LOG_ID_C2 WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE
+#define WDC_LOG_ID_C2 WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID
#define WDC_LOG_ID_C3 0xC3
#define WDC_LOG_ID_C4 0xC4
#define WDC_LOG_ID_C5 0xC5
#define WDC_LOG_ID_C6 0xC6
-#define WDC_LOG_ID_C8 WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE_C8
+#define WDC_LOG_ID_C8 WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID_C8
#define WDC_LOG_ID_CA WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE
#define WDC_LOG_ID_CB WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID
#define WDC_LOG_ID_D0 WDC_NVME_GET_VU_SMART_LOG_OPCODE
@@ -446,6 +452,12 @@ static __u8 wdc_lat_mon_guid[WDC_C3_GUID_LENGTH] = {
#define WDC_ENC_CRASH_DUMP_ID 0xE4
#define WDC_ENC_LOG_DUMP_ID 0xE2
+/* OCP Log Page Directory Data Structure */
+#define BYTE_TO_BIT(byte) ((byte) * 8)
+
+/* Set latency monitor feature */
+#define NVME_FEAT_OCP_LATENCY_MONITOR 0xC5
+
enum _NVME_FEATURES_SELECT {
FS_CURRENT = 0,
FS_DEFAULT = 1,
@@ -473,6 +485,27 @@ enum NVME_FEATURE_IDENTIFIERS {
FID_RESERVATION_PERSISTENCE = 0x83
};
+/* WDC UUID value */
+const uint8_t WDC_UUID[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0xb9, 0x8c, 0x52, 0x0c, 0x4c,
+ 0x5a, 0x15, 0xab, 0xe6, 0x33, 0x29, 0x9a, 0x70, 0xdf, 0xd0
+};
+
+/* WDC_UUID value for SN640_3 devices */
+const uint8_t WDC_UUID_SN640_3[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22
+};
+
+/* UUID field with value of 0 indicates end of UUID List*/
+const uint8_t UUID_END[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
enum WDC_DRIVE_ESSENTIAL_TYPE {
WDC_DE_TYPE_IDENTIFY = 0x1,
WDC_DE_TYPE_SMARTATTRIBUTEDUMP = 0x2,
@@ -656,6 +689,67 @@ enum {
SCAO_LPG = 496, /* Log page GUID */
};
+struct ocp_bad_nand_block_count {
+ __u64 raw : 48;
+ __u16 normalized : 16;
+};
+
+struct ocp_e2e_correction_count {
+ __u32 detected;
+ __u32 corrected;
+};
+
+struct ocp_user_data_erase_count {
+ __u32 maximum;
+ __u32 minimum;
+};
+
+struct ocp_thermal_status {
+ __u8 num_events;
+ __u8 current_status;
+};
+
+struct __packed ocp_dssd_specific_ver {
+ __u8 errata_ver;
+ __u16 point_ver;
+ __u16 minor_ver;
+ __u8 major_ver;
+};
+
+struct ocp_cloud_smart_log {
+ __u8 physical_media_units_written[16];
+ __u8 physical_media_units_read[16];
+ struct ocp_bad_nand_block_count bad_user_nand_blocks;
+ struct ocp_bad_nand_block_count bad_system_nand_blocks;
+ __u64 xor_recovery_count;
+ __u64 uncorrectable_read_error_count;
+ __u64 soft_ecc_error_count;
+ struct ocp_e2e_correction_count e2e_correction_counts;
+ __u8 system_data_percent_used;
+ __u64 refresh_counts : 56;
+ struct ocp_user_data_erase_count user_data_erase_counts;
+ struct ocp_thermal_status thermal_status;
+ struct ocp_dssd_specific_ver dssd_specific_ver;
+ __u64 pcie_correctable_error_count;
+ __u32 incomplete_shutdowns;
+ __u8 rsvd116[4];
+ __u8 percent_free_blocks;
+ __u8 rsvd121[7];
+ __u16 capacitor_health;
+ __u8 nvme_errata_ver;
+ __u8 rsvd131[5];
+ __u64 unaligned_io;
+ __u64 security_version_number;
+ __u64 total_nuse;
+ __u8 plp_start_count[16];
+ __u8 endurance_estimate[16];
+ __u64 pcie_link_retraining_cnt;
+ __u64 power_state_change_cnt;
+ __u8 rsvd208[286];
+ __u16 log_page_version;
+ __u8 log_page_guid[16];
+};
+
static __u8 scao_guid[WDC_C0_GUID_LENGTH] = {
0xC5, 0xAF, 0x10, 0x28, 0xEA, 0xBF, 0xF2, 0xA4,
0x9C, 0x4F, 0x6F, 0x7C, 0xC9, 0x14, 0xD5, 0xAF
@@ -793,6 +887,46 @@ static struct NVME_VU_DE_LOGPAGE_LIST deVULogPagesList[] = {
{ NVME_DE_LOGPAGE_C0, 0xC0, 512, "0xc0"}
};
+enum {
+ WDC_NVME_ADMIN_VUC_OPCODE_D2 = 0xD2,
+ WDC_VUC_SUBOPCODE_VS_DRIVE_INFO_D2 = 0x0000010A,
+ WDC_VUC_SUBOPCODE_LOG_PAGE_DIR_D2 = 0x00000105,
+};
+
+enum {
+ NVME_LOG_NS_BASE = 0x80,
+ NVME_LOG_VS_BASE = 0xC0,
+};
+
+/*drive_info struct*/
+struct ocp_drive_info {
+ __u32 hw_revision;
+ __u32 ftl_unit_size;
+};
+
+/*get log page directory struct*/
+struct log_page_directory {
+ __u64 supported_lid_bitmap;
+ __u64 rsvd;
+ __u64 supported_ns_lid_bitmap;
+ __u64 supported_vs_lid_bitmap;
+};
+
+/*set latency monitor feature */
+struct __packed feature_latency_monitor {
+ __u16 active_bucket_timer_threshold;
+ __u8 active_threshold_a;
+ __u8 active_threshold_b;
+ __u8 active_threshold_c;
+ __u8 active_threshold_d;
+ __u16 active_latency_config;
+ __u8 active_latency_minimum_window;
+ __u16 debug_log_trigger_enable;
+ __u8 discard_debug_log;
+ __u8 latency_monitor_feature_enable;
+ __u8 reserved[4083];
+};
+
static int wdc_get_serial_name(struct nvme_dev *dev, char *file, size_t len, const char *suffix);
static int wdc_create_log_file(char *file, __u8 *drive_log_data, __u32 drive_log_length);
static int wdc_do_clear_dump(struct nvme_dev *dev, __u8 opcode, __u32 cdw12);
@@ -1228,7 +1362,7 @@ struct __packed wdc_fw_act_history_log_format_c2 {
struct __packed wdc_ocp_C4_dev_cap_log {
__le16 num_pcie_ports; /* 0000 - Number of PCI Express Ports */
__le16 oob_mgmt_support; /* 0002 - OOB Management Interfaces Supported */
- __le16 wrt_zeros_support; /* 0004 - Write Zeros Commmand Support */
+ __le16 wrt_zeros_support; /* 0004 - Write Zeros Command Support */
__le16 sanitize_support; /* 0006 - Sanitize Command Support */
__le16 dsm_support; /* 0008 - Dataset Management Command Support */
__le16 wrt_uncor_support; /* 0010 - Write Uncorrectable Command Support */
@@ -1268,6 +1402,21 @@ static __u8 wdc_ocp_c5_guid[WDC_OCP_C5_GUID_LENGTH] = { 0x2F, 0x72, 0x9C, 0x0
#define WDC_REASON_ID_ENTRY_LEN 128
#define WDC_REASON_ID_PATH_NAME "/usr/local/nvmecli"
+const char *log_page_name[256] = {
+ [NVME_LOG_LID_ERROR] = "Error Information",
+ [NVME_LOG_LID_SMART] = "SMART / Health Information",
+ [NVME_LOG_LID_FW_SLOT] = "Firmware Slot Information",
+ [NVME_LOG_LID_CHANGED_NS] = "Changed Namespace List",
+ [NVME_LOG_LID_CMD_EFFECTS] = "Command Supported and Effects",
+ [NVME_LOG_LID_TELEMETRY_HOST] = "Telemetry Host-Initiated",
+ [NVME_LOG_LID_TELEMETRY_CTRL] = "Telemetry Controller-Initiated",
+ [NVME_LOG_LID_SANITIZE] = "Sanitize Status",
+ [WDC_LOG_ID_C0] = "Extended SMART Information",
+ [WDC_LOG_ID_C2] = "Firmware Activation History",
+ [WDC_LOG_ID_C3] = "Latency Monitor",
+ [WDC_LOG_ID_C4] = "Device Capabilities",
+ [WDC_LOG_ID_C5] = "Unsupported Requirements",
+};
static double safe_div_fp(double numerator, double denominator)
{
@@ -1367,6 +1516,60 @@ static int wdc_get_vendor_id(struct nvme_dev *dev, uint32_t *vendor_id)
return ret;
}
+static bool wdc_is_sn861(__u32 device_id)
+{
+ if ((device_id == WDC_NVME_SN861_DEV_ID) ||
+ (device_id == WDC_NVME_SN861_DEV_ID_1))
+ return true;
+ else
+ return false;
+}
+
+
+static bool wdc_is_sn640(__u32 device_id)
+{
+ if ((device_id == WDC_NVME_SN640_DEV_ID) ||
+ (device_id == WDC_NVME_SN640_DEV_ID_1) ||
+ (device_id == WDC_NVME_SN640_DEV_ID_2))
+ return true;
+ else
+ return false;
+}
+
+static bool wdc_is_sn640_3(__u32 device_id)
+{
+ if (device_id == WDC_NVME_SN640_DEV_ID_3)
+ return true;
+ else
+ return false;
+}
+
+static bool wdc_is_sn650_u2(__u32 device_id)
+{
+ if (device_id == WDC_NVME_SN650_DEV_ID_3)
+ return true;
+ else
+ return false;
+}
+
+static bool wdc_is_sn650_e1l(__u32 device_id)
+{
+ if (device_id == WDC_NVME_SN650_DEV_ID_4)
+ return true;
+ else
+ return false;
+}
+
+static bool needs_c2_log_page_check(__u32 device_id)
+{
+ if ((wdc_is_sn640(device_id)) ||
+ (wdc_is_sn650_u2(device_id)) ||
+ (wdc_is_sn650_e1l(device_id)))
+ return true;
+ else
+ return false;
+}
+
static bool wdc_check_power_of_2(int num)
{
return num && (!(num & (num-1)));
@@ -1548,7 +1751,7 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev)
WDC_DEV_CAP_LOG_ID))
capabilities |= WDC_DRIVE_CAP_OCP_C4_LOG_PAGE;
- /* verify the 0xC5 (OCP Unsupported Requirments) log page is supported */
+ /* verify the 0xC5 (OCP Unsupported Requirements) log page is supported */
if (wdc_nvme_check_supported_log_page(r, dev,
WDC_UNSUPPORTED_REQS_LOG_ID))
capabilities |= WDC_DRIVE_CAP_OCP_C5_LOG_PAGE;
@@ -1637,7 +1840,7 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev)
if (wdc_nvme_check_supported_log_page(r, dev, WDC_DEV_CAP_LOG_ID))
capabilities |= WDC_DRIVE_CAP_OCP_C4_LOG_PAGE;
- /* verify the 0xC5 (OCP Unsupported Requirments) log page is supported */
+ /* verify the 0xC5 (OCP Unsupported Requirements) log page is supported */
if (wdc_nvme_check_supported_log_page(r, dev, WDC_UNSUPPORTED_REQS_LOG_ID))
capabilities |= WDC_DRIVE_CAP_OCP_C5_LOG_PAGE;
@@ -1666,6 +1869,23 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev)
WDC_DRIVE_CAP_CLEAR_PCIE);
break;
+ case WDC_NVME_SN861_DEV_ID:
+ fallthrough;
+ case WDC_NVME_SN861_DEV_ID_1:
+ 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_INTERNAL_LOG |
+ 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_SET_LATENCY_MONITOR);
+ break;
default:
capabilities = 0;
}
@@ -1958,7 +2178,7 @@ bool wdc_get_dev_mng_log_entry(__u32 log_length, __u32 entry_id,
remaining_len = 0;
valid_log = false;
- /* The struture is invalid, so any match that was found is invalid. */
+ /* The structure is invalid, so any match that was found is invalid. */
*p_p_found_log_entry = NULL;
} else {
/* Structure must have at least one valid entry to be considered valid */
@@ -1982,33 +2202,25 @@ bool wdc_get_dev_mng_log_entry(__u32 log_length, __u32 entry_id,
return valid_log;
}
-static bool get_dev_mgment_cbs_data(nvme_root_t r, struct nvme_dev *dev,
- __u8 log_id, void **cbs_data)
+static bool get_dev_mgmt_log_page_lid_data(struct nvme_dev *dev,
+ void **cbs_data,
+ __u8 lid,
+ __u8 log_id,
+ __u8 uuid_ix)
{
- int ret = -1;
void *data;
struct wdc_c2_log_page_header *hdr_ptr;
struct wdc_c2_log_subpage_header *sph;
__u32 length = 0;
+ int ret = 0;
bool found = false;
- __u8 uuid_ix = 1;
- __u8 lid = 0;
- *cbs_data = NULL;
- __u32 device_id, read_vendor_id;
-
- ret = wdc_get_pci_ids(r, dev, &device_id, &read_vendor_id);
- if (device_id == WDC_NVME_ZN350_DEV_ID || device_id == WDC_NVME_ZN350_DEV_ID_1) {
- lid = WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE_C8;
- uuid_ix = 0;
- } else {
- lid = WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE;
- }
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 */
@@ -2031,7 +2243,9 @@ static bool get_dev_mgment_cbs_data(nvme_root_t r, struct nvme_dev *dev,
};
ret = nvme_get_log(&args_len);
if (ret) {
- fprintf(stderr, "ERROR: WDC: Unable to get 0x%x Log Page length, ret = 0x%x\n", lid, ret);
+ fprintf(stderr,
+ "ERROR: WDC: Unable to get 0x%x Log Page length with uuid %d, ret = 0x%x\n",
+ lid, uuid_ix, ret);
goto end;
}
@@ -2044,37 +2258,38 @@ static bool get_dev_mgment_cbs_data(nvme_root_t r, struct nvme_dev *dev,
data = calloc(length, sizeof(__u8));
if (!data) {
fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
- return false;
+ goto end;
}
- }
- /* get the log page data */
- struct nvme_get_log_args args_data = {
- .args_size = sizeof(args_data),
- .fd = dev_fd(dev),
- .lid = lid,
- .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);
+ /* 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 = lid,
+ .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 Page data, ret = 0x%x\n", lid, ret);
- goto end;
+ if (ret) {
+ fprintf(stderr,
+ "ERROR: WDC: Unable to read 0x%x Log Page data with uuid %d, ret = 0x%x\n",
+ lid, uuid_ix, ret);
+ goto end;
+ }
}
/* Check the log data to see if the WD version of log page ID's is found */
-
length = sizeof(struct wdc_c2_log_page_header);
hdr_ptr = (struct wdc_c2_log_page_header *)data;
sph = (struct wdc_c2_log_subpage_header *)(data + length);
@@ -2083,50 +2298,91 @@ static bool get_dev_mgment_cbs_data(nvme_root_t r, struct nvme_dev *dev,
*cbs_data = calloc(le32_to_cpu(sph->length), sizeof(__u8));
if (!*cbs_data) {
fprintf(stderr, "ERROR: WDC: calloc: %s\n", strerror(errno));
+ found = false;
goto end;
}
memcpy((void *)*cbs_data, (void *)&sph->data, le32_to_cpu(sph->length));
} else {
- /* not found with uuid = 1 try with uuid = 0 */
- uuid_ix = 0;
- /* get the log page data */
- struct nvme_get_log_args args = {
- .args_size = sizeof(args),
- .fd = dev_fd(dev),
- .lid = lid,
- .nsid = 0xFFFFFFFF,
- .lpo = 0,
- .lsp = NVME_LOG_LSP_NONE,
- .lsi = 0,
- .rae = false,
- .uuidx = uuid_ix,
- .csi = NVME_CSI_NVM,
- .ot = false,
- .len = le32_to_cpu(hdr_ptr->length),
- .log = data,
- .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
- .result = NULL,
- };
- ret = nvme_get_log(&args);
+ fprintf(stderr, "ERROR: WDC: C2 log id 0x%x not found with uuid index %d\n",
+ log_id, uuid_ix);
+ }
- hdr_ptr = (struct wdc_c2_log_page_header *)data;
- sph = (struct wdc_c2_log_subpage_header *)(data + length);
- found = wdc_get_dev_mng_log_entry(le32_to_cpu(hdr_ptr->length), log_id, hdr_ptr, &sph);
- if (found) {
- *cbs_data = calloc(le32_to_cpu(sph->length), sizeof(__u8));
- if (!*cbs_data) {
- fprintf(stderr, "ERROR: WDC: calloc: %s\n", strerror(errno));
- goto end;
- }
- memcpy((void *)*cbs_data, (void *)&sph->data, le32_to_cpu(sph->length));
+end:
+ free(data);
+ return found;
+}
+
+static bool get_dev_mgment_cbs_data(nvme_root_t r, struct nvme_dev *dev,
+ __u8 log_id, void **cbs_data)
+{
+ int ret = -1;
+ bool found = false;
+ __u8 uuid_ix = 0;
+ __u8 lid = 0;
+ *cbs_data = NULL;
+ __u32 device_id, read_vendor_id;
+ bool uuid_present = false;
+ int index = 0, uuid_index = 0;
+ struct nvme_id_uuid_list uuid_list;
+
+ ret = wdc_get_pci_ids(r, dev, &device_id, &read_vendor_id);
+ if (ret == 0) {
+ if (device_id == WDC_NVME_ZN350_DEV_ID || device_id == WDC_NVME_ZN350_DEV_ID_1) {
+ lid = WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID_C8;
+ uuid_ix = 0;
} else {
- /* WD version not found */
- fprintf(stderr, "ERROR: WDC: Unable to find correct version of page 0x%x, entry id = %d\n", lid, log_id);
+ lid = WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID;
}
+ } else {
+ fprintf(stderr, "ERROR: WDC: get pci ids: %d\n", ret);
+ return false;
+ }
+
+ 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_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_ix = 1;
+ }
+
+ found = get_dev_mgmt_log_page_lid_data(dev, cbs_data, lid, log_id, uuid_ix);
+
+ if (!found) {
+ /* not found with uuid = 1 try with uuid = 0 */
+ uuid_ix = 0;
+ fprintf(stderr, "Not found, requesting log page with uuid_index %d\n", uuid_index);
+
+ found = get_dev_mgmt_log_page_lid_data(dev, cbs_data, lid, log_id, uuid_ix);
}
-end:
- free(data);
return found;
}
@@ -3373,6 +3629,102 @@ free_buf:
return ret;
}
+static int dump_internal_logs(struct nvme_dev *dev, char *dir_name, int verbose)
+{
+ char file_path[128];
+ void *telemetry_log;
+ const size_t bs = 512;
+ struct nvme_telemetry_log *hdr;
+ size_t full_size, offset = bs;
+ int err, output;
+
+ if (verbose)
+ printf("NVMe Telemetry log...\n");
+
+ hdr = malloc(bs);
+ telemetry_log = malloc(bs);
+ if (!hdr || !telemetry_log) {
+ fprintf(stderr, "Failed to allocate %zu bytes for log: %s\n", bs, strerror(errno));
+ err = -ENOMEM;
+ goto free_mem;
+ }
+ memset(hdr, 0, bs);
+
+ sprintf(file_path, "%s/telemetry.bin", dir_name);
+ output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (output < 0) {
+ fprintf(stderr, "Failed to open output file %s: %s!\n", file_path, strerror(errno));
+ err = output;
+ goto free_mem;
+ }
+
+ struct nvme_get_log_args args = {
+ .lpo = 0,
+ .result = NULL,
+ .log = hdr,
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .lid = NVME_LOG_LID_TELEMETRY_HOST,
+ .len = bs,
+ .nsid = NVME_NSID_ALL,
+ .csi = NVME_CSI_NVM,
+ .lsi = NVME_LOG_LSI_NONE,
+ .lsp = NVME_LOG_TELEM_HOST_LSP_CREATE,
+ .uuidx = NVME_UUID_NONE,
+ .rae = true,
+ .ot = false,
+ };
+
+ err = nvme_get_log(&args);
+ if (err < 0)
+ perror("get-telemetry-log");
+ else if (err > 0) {
+ nvme_show_status(err);
+ fprintf(stderr, "Failed to acquire telemetry header %d!\n", err);
+ goto close_output;
+ }
+
+ err = write(output, (void *)hdr, bs);
+ if (err != bs) {
+ fprintf(stderr, "Failed to flush all data to file!\n");
+ goto close_output;
+ }
+
+ full_size = (le16_to_cpu(hdr->dalb3) * bs) + offset;
+
+ while (offset != full_size) {
+ args.log = telemetry_log;
+ args.lpo = offset;
+ args.lsp = NVME_LOG_LSP_NONE;
+ err = nvme_get_log(&args);
+ if (err < 0) {
+ perror("get-telemetry-log");
+ break;
+ } else if (err > 0) {
+ fprintf(stderr, "Failed to acquire full telemetry log!\n");
+ nvme_show_status(err);
+ break;
+ }
+
+ err = write(output, (void *)telemetry_log, bs);
+ if (err != bs) {
+ fprintf(stderr, "Failed to flush all data to file!\n");
+ break;
+ }
+ err = 0;
+ offset += bs;
+ }
+
+close_output:
+ close(output);
+free_mem:
+ free(hdr);
+ free(telemetry_log);
+
+ return err;
+}
+
static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command,
struct plugin *plugin)
{
@@ -3385,6 +3737,7 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command
char *type = "Telemetry type - NONE, HOST, or CONTROLLER. Currently only supported on the SN530, SN640, SN730, SN740, SN810, SN840 and ZN350 devices.";
char *verbose = "Display more debug messages.";
char f[PATH_MAX] = {0};
+ char fb[PATH_MAX/2] = {0};
char fileSuffix[PATH_MAX] = {0};
struct nvme_dev *dev;
nvme_root_t r;
@@ -3393,6 +3746,9 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command
UtilsTimeInfo timeInfo;
__u8 timeStamp[MAX_PATH_LEN];
__u64 capabilities = 0;
+ __u32 device_id, read_vendor_id;
+ char file_path[PATH_MAX/2] = {0};
+ char cmd_buf[PATH_MAX] = {0};
int ret = -1;
struct config {
@@ -3441,72 +3797,149 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command
goto out;
}
- if (cfg.file) {
- int verify_file;
+ ret = wdc_get_pci_ids(r, dev, &device_id, &read_vendor_id);
- /* verify the passed in file name and path is valid before getting the dump data */
- verify_file = open(cfg.file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
- if (verify_file < 0) {
- fprintf(stderr, "ERROR: WDC: open: %s\n", strerror(errno));
- goto out;
+ if (!wdc_is_sn861(device_id)) {
+ if (cfg.file) {
+ int verify_file;
+
+ /* verify file name and path is valid before getting dump data */
+ verify_file = open(cfg.file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (verify_file < 0) {
+ fprintf(stderr, "ERROR: WDC: open: %s\n", strerror(errno));
+ goto out;
+ }
+ close(verify_file);
+ strncpy(f, cfg.file, PATH_MAX - 1);
+ } else {
+ wdc_UtilsGetTime(&timeInfo);
+ memset(timeStamp, 0, sizeof(timeStamp));
+ wdc_UtilsSnprintf((char *)timeStamp, MAX_PATH_LEN,
+ "%02u%02u%02u_%02u%02u%02u", timeInfo.year,
+ timeInfo.month, timeInfo.dayOfMonth,
+ timeInfo.hour, timeInfo.minute,
+ timeInfo.second);
+ snprintf(fileSuffix, PATH_MAX, "_internal_fw_log_%s", (char *)timeStamp);
+
+ ret = wdc_get_serial_name(dev, f, PATH_MAX, fileSuffix);
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC: failed to generate file name\n");
+ goto out;
+ }
}
- close(verify_file);
- strncpy(f, cfg.file, PATH_MAX - 1);
- } else {
- wdc_UtilsGetTime(&timeInfo);
- memset(timeStamp, 0, sizeof(timeStamp));
- wdc_UtilsSnprintf((char *)timeStamp, MAX_PATH_LEN, "%02u%02u%02u_%02u%02u%02u",
- timeInfo.year, timeInfo.month, timeInfo.dayOfMonth,
- timeInfo.hour, timeInfo.minute, timeInfo.second);
- snprintf(fileSuffix, PATH_MAX, "_internal_fw_log_%s", (char *)timeStamp);
- ret = wdc_get_serial_name(dev, f, PATH_MAX, fileSuffix);
- if (ret) {
- fprintf(stderr, "ERROR: WDC: failed to generate file name\n");
- goto out;
+ if (!cfg.file) {
+ if (strlen(f) > PATH_MAX - 5) {
+ fprintf(stderr, "ERROR: WDC: file name overflow\n");
+ ret = -1;
+ goto out;
+ }
+ strcat(f, ".bin");
}
- }
+ fprintf(stderr, "%s: filename = %s\n", __func__, f);
- if (!cfg.file) {
- if (strlen(f) > PATH_MAX - 5) {
- fprintf(stderr, "ERROR: WDC: file name overflow\n");
+ if (cfg.data_area) {
+ if (cfg.data_area > 5 || cfg.data_area < 1) {
+ fprintf(stderr, "ERROR: WDC: Data area must be 1-5\n");
+ ret = -1;
+ goto out;
+ }
+ }
+
+ if (!cfg.type || !strcmp(cfg.type, "NONE") || !strcmp(cfg.type, "none")) {
+ telemetry_type = WDC_TELEMETRY_TYPE_NONE;
+ data_area = 0;
+ } else if (!strcmp(cfg.type, "HOST") || !strcmp(cfg.type, "host")) {
+ telemetry_type = WDC_TELEMETRY_TYPE_HOST;
+ telemetry_data_area = cfg.data_area;
+ } else if (!strcmp(cfg.type, "CONTROLLER") || !strcmp(cfg.type, "controller")) {
+ telemetry_type = WDC_TELEMETRY_TYPE_CONTROLLER;
+ telemetry_data_area = cfg.data_area;
+ } else {
+ fprintf(stderr,
+ "ERROR: WDC: Invalid type - Must be NONE, HOST or CONTROLLER\n");
ret = -1;
goto out;
}
- strcat(f, ".bin");
- }
- fprintf(stderr, "%s: filename = %s\n", __func__, f);
+ } else {
+ if (cfg.file) {
+ strncpy(fb, cfg.file, PATH_MAX/2 - 8);
+ } else {
+ wdc_UtilsGetTime(&timeInfo);
+ memset(timeStamp, 0, sizeof(timeStamp));
+ wdc_UtilsSnprintf((char *)timeStamp, MAX_PATH_LEN,
+ "%02u%02u%02u_%02u%02u%02u", timeInfo.year,
+ timeInfo.month, timeInfo.dayOfMonth,
+ timeInfo.hour, timeInfo.minute,
+ timeInfo.second);
+ snprintf(fileSuffix, PATH_MAX, "_internal_fw_log_%s", (char *)timeStamp);
+
+ ret = wdc_get_serial_name(dev, fb, PATH_MAX/2 - 7, fileSuffix);
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC: failed to generate file name\n");
+ goto out;
+ }
- if (cfg.data_area) {
- if (cfg.data_area > 5 || cfg.data_area < 1) {
- fprintf(stderr, "ERROR: WDC: Data area must be 1-5\n");
+ if (strlen(fb) > PATH_MAX/2 - 7) {
+ fprintf(stderr, "ERROR: WDC: file name overflow\n");
+ ret = -1;
+ goto out;
+ }
+ }
+ fprintf(stderr, "%s: filename = %s.tar.gz\n", __func__, fb);
+
+
+ memset(file_path, 0, sizeof(file_path));
+ if (snprintf(file_path, PATH_MAX/2 - 8, "%s.tar.gz", fb) >= PATH_MAX/2 - 8) {
+ fprintf(stderr, "File path is too long!\n");
ret = -1;
goto out;
}
- }
-
- if (!cfg.type || !strcmp(cfg.type, "NONE") || !strcmp(cfg.type, "none")) {
- telemetry_type = WDC_TELEMETRY_TYPE_NONE;
- data_area = 0;
- } else if (!strcmp(cfg.type, "HOST") || !strcmp(cfg.type, "host")) {
- telemetry_type = WDC_TELEMETRY_TYPE_HOST;
- telemetry_data_area = cfg.data_area;
- } else if (!strcmp(cfg.type, "CONTROLLER") || !strcmp(cfg.type, "controller")) {
- telemetry_type = WDC_TELEMETRY_TYPE_CONTROLLER;
- telemetry_data_area = cfg.data_area;
- } else {
- fprintf(stderr, "ERROR: WDC: Invalid type - Must be NONE, HOST or CONTROLLER\n");
- ret = -1;
- goto out;
+ if (access(file_path, F_OK) != -1) {
+ fprintf(stderr, "Output file already exists!\n");
+ ret = -EEXIST;
+ goto out;
+ }
}
capabilities = wdc_get_drive_capabilities(r, dev);
if ((capabilities & WDC_DRIVE_CAP_INTERNAL_LOG) == WDC_DRIVE_CAP_INTERNAL_LOG) {
- if (!telemetry_data_area)
- telemetry_data_area = 3; /* Set the default DA to 3 if not specified */
+ if (!wdc_is_sn861(device_id)) {
+ /* Set the default DA to 3 if not specified */
+ if (!telemetry_data_area)
+ telemetry_data_area = 3;
+
+ ret = wdc_do_cap_diag(r, dev, f, xfer_size,
+ telemetry_type, telemetry_data_area);
+ } else {
+ if (cfg.verbose)
+ printf("Creating temp directory...\n");
+
+ ret = mkdir(fb, 0666);
+ if (ret) {
+ fprintf(stderr, "Failed to create directory!\n");
+ goto out;
+ }
- ret = wdc_do_cap_diag(r, dev, f, xfer_size,
- telemetry_type, telemetry_data_area);
+ ret = dump_internal_logs(dev, fb, cfg.verbose);
+ if (ret < 0)
+ perror("vs-internal-log");
+
+ if (cfg.verbose)
+ printf("Archiving...\n");
+
+ if (snprintf(cmd_buf, PATH_MAX,
+ "tar --remove-files -czf %s %s",
+ file_path, fb) >= PATH_MAX) {
+ fprintf(stderr, "Command buffer is too long!\n");
+ ret = -1;
+ goto out;
+ }
+
+ ret = system(cmd_buf);
+ if (ret)
+ fprintf(stderr, "Failed to create an archive file!\n");
+ }
goto out;
}
if ((capabilities & WDC_DRIVE_CAP_DUI) == WDC_DRIVE_CAP_DUI) {
@@ -4362,7 +4795,7 @@ static void wdc_print_dev_cap_log_normal(struct wdc_ocp_C4_dev_cap_log *log_data
printf(" Minimum DSSD Power State : 0x%x\n", le16_to_cpu(log_data->min_dssd_ps));
for (j = 0; j < WDC_OCP_C4_NUM_PS_DESCR; j++)
- printf(" DSSD Power State %d Desriptor : 0x%x\n", j, log_data->dssd_ps_descr[j]);
+ printf(" DSSD Power State %d Descriptor : 0x%x\n", j, log_data->dssd_ps_descr[j]);
printf(" Log Page Version : 0x%x\n", le16_to_cpu(log_data->log_page_version));
printf(" Log page GUID : 0x");
@@ -5006,7 +5439,9 @@ static void wdc_get_commit_action_bin(__u8 commit_action_type, char *action_bin)
}
-static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u32 cust_id, __u32 vendor_id)
+static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries,
+ __u32 cust_id, __u32 vendor_id,
+ __u32 device_id)
{
int i, j;
char previous_fw[9];
@@ -5020,7 +5455,9 @@ static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u
if (data[0] == WDC_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID) {
printf(" Firmware Activate History Log\n");
- if (cust_id == WDC_CUSTOMER_ID_0x1005 || vendor_id == WDC_NVME_SNDK_VID) {
+ if (cust_id == WDC_CUSTOMER_ID_0x1005 ||
+ vendor_id == WDC_NVME_SNDK_VID ||
+ wdc_is_sn861(device_id)) {
printf(" Power on Hour Power Cycle Previous New\n");
printf(" Entry hh:mm:ss Count Firmware Firmware Slot Action Result\n");
printf(" ----- ----------------- ----------------- --------- --------- ----- ------ -------\n");
@@ -5079,6 +5516,26 @@ static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u
(int)((timestamp/1000)%60));
printf("%s", time_str);
printf(" ");
+ } else if (wdc_is_sn861(device_id)) {
+ printf(" ");
+ char timestamp[20];
+ __u64 hour;
+ __u8 min;
+ __u8 sec;
+ __u64 timestamp_sec;
+
+ timestamp_sec =
+ le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp)
+ / 1000;
+ hour = timestamp_sec / 3600;
+ min = (timestamp_sec % 3600) / 60;
+ sec = timestamp_sec % 60;
+
+ sprintf(timestamp,
+ "%"PRIu64":%02"PRIu8":%02"PRIu8,
+ (uint64_t)hour, min, sec);
+ printf("%-11s", timestamp);
+ printf(" ");
} else {
printf(" ");
uint64_t timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp));
@@ -5177,7 +5634,9 @@ static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u
}
}
-static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32 cust_id, __u32 vendor_id)
+static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries,
+ __u32 cust_id, __u32 vendor_id,
+ __u32 device_id)
{
struct json_object *root = json_create_object();
int i, j;
@@ -5186,11 +5645,13 @@ static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32
char commit_action_bin[8];
char fail_str[32];
char time_str[11];
+ char ext_time_str[20];
memset((void *)previous_fw, 0, 9);
memset((void *)new_fw, 0, 9);
memset((void *)commit_action_bin, 0, 8);
memset((void *)time_str, 0, 11);
+ memset((void *)ext_time_str, 0, 20);
memset((void *)fail_str, 0, 11);
char *null_fw = "--------";
__u16 oldestEntryIdx = 0, entryIdx = 0;
@@ -5242,6 +5703,17 @@ static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32
sprintf((char *)time_str, "%04d:%02d:%02d", (int)((timestamp/(3600*1000))%24), (int)((timestamp/(1000*60))%60),
(int)((timestamp/1000)%60));
json_object_add_value_string(root, "Power on Hour", time_str);
+ } else if (wdc_is_sn861(device_id)) {
+ __u64 timestamp_sec =
+ le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp)
+ / 1000;
+
+ sprintf((char *)ext_time_str,
+ "%"PRIu64":%02"PRIu8":%02"PRIu8,
+ (uint64_t)(__u64)(timestamp_sec/3600),
+ (__u8)((timestamp_sec%3600)/60),
+ (__u8)(timestamp_sec%60));
+ json_object_add_value_string(root, "Power on Hour", ext_time_str);
} else {
uint64_t timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp));
@@ -6071,7 +6543,7 @@ static void wdc_print_smart_cloud_attr_C0_normal(void *data)
(uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_CPH]));
printf(" Unaligned I/O : %"PRIu64"\n",
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UIO]));
- printf(" Securqity Version Number : %"PRIu64"\n",
+ printf(" Security Version Number : %"PRIu64"\n",
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN]));
printf(" NUSE Namespace utilization : %"PRIu64"\n",
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE]));
@@ -6465,17 +6937,19 @@ static int wdc_get_c0_log_page_sn(nvme_root_t r, struct nvme_dev *dev, int uuid_
static int wdc_get_c0_log_page(nvme_root_t r, struct nvme_dev *dev, char *format, int uuid_index,
__u32 namespace_id)
{
- int ret = 0;
- int fmt = -1;
- __u8 *data;
uint32_t device_id, read_vendor_id;
+ enum nvme_print_flags fmt;
+ int ret;
+ __u8 *data;
+ __u8 log_id;
+ __u32 length;
if (!wdc_check_device(r, dev))
return -1;
- fmt = validate_output_format(format);
- if (fmt < 0) {
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
fprintf(stderr, "ERROR: WDC: invalid output format\n");
- return fmt;
+ return ret;
}
ret = wdc_get_pci_ids(r, dev, &device_id, &read_vendor_id);
@@ -6495,6 +6969,16 @@ static int wdc_get_c0_log_page(nvme_root_t r, struct nvme_dev *dev, char *format
fallthrough;
case WDC_NVME_SN860_DEV_ID:
fallthrough;
+ case WDC_NVME_SN560_DEV_ID_1:
+ fallthrough;
+ case WDC_NVME_SN560_DEV_ID_2:
+ fallthrough;
+ case WDC_NVME_SN560_DEV_ID_3:
+ fallthrough;
+ case WDC_NVME_SN550_DEV_ID:
+ ret = wdc_get_c0_log_page_sn(r, dev, uuid_index, format, namespace_id, fmt);
+ break;
+
case WDC_NVME_SN650_DEV_ID:
fallthrough;
case WDC_NVME_SN650_DEV_ID_1:
@@ -6506,16 +6990,63 @@ static int wdc_get_c0_log_page(nvme_root_t r, struct nvme_dev *dev, char *format
case WDC_NVME_SN650_DEV_ID_4:
fallthrough;
case WDC_NVME_SN655_DEV_ID:
- fallthrough;
- case WDC_NVME_SN560_DEV_ID_1:
- fallthrough;
- case WDC_NVME_SN560_DEV_ID_2:
- fallthrough;
- case WDC_NVME_SN560_DEV_ID_3:
- fallthrough;
- case WDC_NVME_SN550_DEV_ID:
- ret = wdc_get_c0_log_page_sn(r, dev, uuid_index, format, namespace_id, fmt);
+ if (uuid_index == 0) {
+ log_id = WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_ID;
+ length = WDC_NVME_SMART_CLOUD_ATTR_LEN;
+ } else {
+ log_id = WDC_NVME_GET_EOL_STATUS_LOG_OPCODE;
+ length = WDC_NVME_EOL_STATUS_LOG_LEN;
+ }
+
+ data = (__u8 *)malloc(sizeof(__u8) * length);
+ if (!data) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if (namespace_id == NVME_NSID_ALL) {
+ ret = nvme_get_nsid(dev_fd(dev), &namespace_id);
+ if (ret < 0)
+ namespace_id = NVME_NSID_ALL;
+ }
+
+ /* Get the 0xC0 log data */
+ struct nvme_get_log_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .lid = log_id,
+ .nsid = namespace_id,
+ .lpo = 0,
+ .lsp = NVME_LOG_LSP_NONE,
+ .lsi = 0,
+ .rae = false,
+ .uuidx = uuid_index,
+ .csi = NVME_CSI_NVM,
+ .ot = false,
+ .len = length,
+ .log = data,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ ret = nvme_get_log(&args);
+
+ if (strcmp(format, "json"))
+ nvme_show_status(ret);
+
+ if (!ret) {
+ /* parse the data */
+ if (uuid_index == 0)
+ wdc_print_c0_cloud_attr_log(data, fmt);
+ else
+ wdc_print_c0_eol_log(data, fmt);
+ } else {
+ fprintf(stderr, "ERROR: WDC: Unable to read C0 Log Page data ");
+ fprintf(stderr, "with uuid index %d\n", uuid_index);
+ ret = -1;
+ }
+ free(data);
break;
+
case WDC_NVME_ZN350_DEV_ID:
fallthrough;
case WDC_NVME_ZN350_DEV_ID_1:
@@ -6697,7 +7228,9 @@ static int wdc_print_d0_log(struct wdc_ssd_d0_smart_log *perf, int fmt)
return 0;
}
-static int wdc_print_fw_act_history_log(__u8 *data, int num_entries, int fmt, __u32 cust_id, __u32 vendor_id)
+static int wdc_print_fw_act_history_log(__u8 *data, int num_entries, int fmt,
+ __u32 cust_id, __u32 vendor_id,
+ __u32 device_id)
{
if (!data) {
fprintf(stderr, "ERROR: WDC: Invalid buffer to read fw activate history entries\n");
@@ -6706,10 +7239,12 @@ static int wdc_print_fw_act_history_log(__u8 *data, int num_entries, int fmt, __
switch (fmt) {
case NORMAL:
- wdc_print_fw_act_history_log_normal(data, num_entries, cust_id, vendor_id);
+ wdc_print_fw_act_history_log_normal(data, num_entries, cust_id,
+ vendor_id, device_id);
break;
case JSON:
- wdc_print_fw_act_history_log_json(data, num_entries, cust_id, vendor_id);
+ wdc_print_fw_act_history_log_json(data, num_entries, cust_id,
+ vendor_id, device_id);
break;
}
return 0;
@@ -6717,19 +7252,19 @@ static int wdc_print_fw_act_history_log(__u8 *data, int num_entries, int fmt, __
static int wdc_get_ca_log_page(nvme_root_t r, struct nvme_dev *dev, char *format)
{
- int ret = 0;
- int fmt = -1;
- __u8 *data;
- struct wdc_ssd_ca_perf_stats *perf;
uint32_t read_device_id, read_vendor_id;
+ struct wdc_ssd_ca_perf_stats *perf;
+ enum nvme_print_flags fmt;
__u32 cust_id;
+ __u8 *data;
+ int ret;
if (!wdc_check_device(r, dev))
return -1;
- fmt = validate_output_format(format);
- if (fmt < 0) {
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
fprintf(stderr, "ERROR: WDC: invalid output format\n");
- return fmt;
+ return ret;
}
/* verify the 0xCA log page is supported */
@@ -6853,23 +7388,24 @@ static int wdc_get_ca_log_page(nvme_root_t r, struct nvme_dev *dev, char *format
static int wdc_get_c1_log_page(nvme_root_t r, struct nvme_dev *dev,
char *format, uint8_t interval)
{
- int ret = 0;
- int fmt = -1;
+ struct wdc_log_page_subpage_header *sph;
+ struct wdc_ssd_perf_stats *perf;
+ struct wdc_log_page_header *l;
+ enum nvme_print_flags fmt;
+ int total_subpages;
+ int skip_cnt = 4;
__u8 *data;
__u8 *p;
int i;
- int skip_cnt = 4;
- int total_subpages;
- struct wdc_log_page_header *l;
- struct wdc_log_page_subpage_header *sph;
- struct wdc_ssd_perf_stats *perf;
+ int ret;
if (!wdc_check_device(r, dev))
return -1;
- fmt = validate_output_format(format);
- if (fmt < 0) {
+
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
fprintf(stderr, "ERROR: WDC: invalid output format\n");
- return fmt;
+ return ret;
}
if (interval < 1 || interval > 15) {
@@ -6911,18 +7447,19 @@ static int wdc_get_c1_log_page(nvme_root_t r, struct nvme_dev *dev,
static int wdc_get_c3_log_page(nvme_root_t r, struct nvme_dev *dev, char *format)
{
- int ret = 0;
- int fmt = -1;
+ struct wdc_ssd_latency_monitor_log *log_data;
+ enum nvme_print_flags fmt;
__u8 *data;
+ int ret;
int i;
- struct wdc_ssd_latency_monitor_log *log_data;
if (!wdc_check_device(r, dev))
return -1;
- fmt = validate_output_format(format);
- if (fmt < 0) {
+
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
fprintf(stderr, "ERROR: WDC: invalid output format\n");
- return fmt;
+ return ret;
}
data = (__u8 *)malloc(sizeof(__u8) * WDC_LATENCY_MON_LOG_BUF_LEN);
@@ -6982,18 +7519,19 @@ out:
static int wdc_get_ocp_c1_log_page(nvme_root_t r, struct nvme_dev *dev, char *format)
{
- int ret = 0;
- int fmt = -1;
+ struct wdc_ocp_c1_error_recovery_log *log_data;
+ enum nvme_print_flags fmt;
__u8 *data;
+ int ret;
int i;
- struct wdc_ocp_c1_error_recovery_log *log_data;
if (!wdc_check_device(r, dev))
return -1;
- fmt = validate_output_format(format);
- if (fmt < 0) {
+
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
fprintf(stderr, "ERROR: WDC: invalid output format\n");
- return fmt;
+ return ret;
}
data = (__u8 *)malloc(sizeof(__u8) * WDC_ERROR_REC_LOG_BUF_LEN);
@@ -7052,18 +7590,19 @@ out:
static int wdc_get_ocp_c4_log_page(nvme_root_t r, struct nvme_dev *dev, char *format)
{
- int ret = 0;
- int fmt = -1;
+ struct wdc_ocp_C4_dev_cap_log *log_data;
+ enum nvme_print_flags fmt;
__u8 *data;
+ int ret;
int i;
- struct wdc_ocp_C4_dev_cap_log *log_data;
if (!wdc_check_device(r, dev))
return -1;
- fmt = validate_output_format(format);
- if (fmt < 0) {
+
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
fprintf(stderr, "ERROR: WDC: invalid output format\n");
- return fmt;
+ return ret;
}
data = (__u8 *)malloc(sizeof(__u8) * WDC_DEV_CAP_LOG_BUF_LEN);
@@ -7121,18 +7660,19 @@ out:
static int wdc_get_ocp_c5_log_page(nvme_root_t r, struct nvme_dev *dev, char *format)
{
- int ret = 0;
- int fmt = -1;
+ struct wdc_ocp_C5_unsupported_reqs *log_data;
+ enum nvme_print_flags fmt;
+ int ret;
__u8 *data;
int i;
- struct wdc_ocp_C5_unsupported_reqs *log_data;
if (!wdc_check_device(r, dev))
return -1;
- fmt = validate_output_format(format);
- if (fmt < 0) {
+
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
fprintf(stderr, "ERROR: WDC: invalid output format\n");
- return fmt;
+ return ret;
}
data = (__u8 *)malloc(sizeof(__u8) * WDC_UNSUPPORTED_REQS_LOG_BUF_LEN);
@@ -7190,17 +7730,18 @@ out:
static int wdc_get_d0_log_page(nvme_root_t r, struct nvme_dev *dev, char *format)
{
+ struct wdc_ssd_d0_smart_log *perf;
+ enum nvme_print_flags fmt;
int ret = 0;
- int fmt = -1;
__u8 *data;
- struct wdc_ssd_d0_smart_log *perf;
if (!wdc_check_device(r, dev))
return -1;
- fmt = validate_output_format(format);
- if (fmt < 0) {
+
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
fprintf(stderr, "ERROR: WDC: invalid output format\n");
- return fmt;
+ return ret;
}
/* verify the 0xD0 log page is supported */
@@ -7235,6 +7776,235 @@ static int wdc_get_d0_log_page(nvme_root_t r, struct nvme_dev *dev, char *format
return ret;
}
+static long double le_to_float(__u8 *data, int byte_len)
+{
+ long double result = 0;
+ int i;
+
+ for (i = 0; i < byte_len; i++) {
+ result *= 256;
+ result += data[15 - i];
+ }
+
+ return result;
+}
+
+static void stringify_log_page_guid(__u8 *guid, char *buf)
+{
+ char *ptr = buf;
+ int i;
+
+ memset(buf, 0, sizeof(char) * 19);
+
+ ptr += sprintf(ptr, "0x");
+ for (i = 0; i < 16; i++)
+ ptr += sprintf(ptr, "%x", guid[15 - i]);
+}
+
+static const char *const cloud_smart_log_thermal_status[] = {
+ [0x00] = "unthrottled",
+ [0x01] = "first_level",
+ [0x02] = "second_level",
+ [0x03] = "third_level",
+};
+
+static const char *stringify_cloud_smart_log_thermal_status(__u8 status)
+{
+ if (status < ARRAY_SIZE(cloud_smart_log_thermal_status) &&
+ cloud_smart_log_thermal_status[status])
+ return cloud_smart_log_thermal_status[status];
+ return "unrecognized";
+}
+
+static void show_cloud_smart_log_json(struct ocp_cloud_smart_log *log)
+{
+ struct json_object *root;
+ struct json_object *bad_user_nand_blocks;
+ struct json_object *bad_system_nand_blocks;
+ struct json_object *e2e_correction_counts;
+ struct json_object *user_data_erase_counts;
+ struct json_object *thermal_status;
+ struct json_object *dssd_specific_ver;
+ char buf[2 * sizeof(log->log_page_guid) + 3];
+
+ bad_user_nand_blocks = json_create_object();
+ json_object_add_value_uint(bad_user_nand_blocks, "normalized",
+ le16_to_cpu(log->bad_user_nand_blocks.normalized));
+ json_object_add_value_uint(bad_user_nand_blocks, "raw",
+ le64_to_cpu(log->bad_user_nand_blocks.raw));
+
+ bad_system_nand_blocks = json_create_object();
+ json_object_add_value_uint(bad_system_nand_blocks, "normalized",
+ le16_to_cpu(log->bad_system_nand_blocks.normalized));
+ json_object_add_value_uint(bad_system_nand_blocks, "raw",
+ le64_to_cpu(log->bad_system_nand_blocks.raw));
+
+ e2e_correction_counts = json_create_object();
+ json_object_add_value_uint(e2e_correction_counts, "corrected",
+ le32_to_cpu(log->e2e_correction_counts.corrected));
+ json_object_add_value_uint(e2e_correction_counts, "detected",
+ le32_to_cpu(log->e2e_correction_counts.detected));
+
+ user_data_erase_counts = json_create_object();
+ json_object_add_value_uint(user_data_erase_counts, "minimum",
+ le32_to_cpu(log->user_data_erase_counts.minimum));
+ json_object_add_value_uint(user_data_erase_counts, "maximum",
+ le32_to_cpu(log->user_data_erase_counts.maximum));
+
+ thermal_status = json_create_object();
+ json_object_add_value_string(thermal_status, "current_status",
+ stringify_cloud_smart_log_thermal_status(log->thermal_status.current_status));
+ json_object_add_value_uint(thermal_status, "num_events",
+ log->thermal_status.num_events);
+
+ dssd_specific_ver = json_create_object();
+ json_object_add_value_uint(dssd_specific_ver, "major_ver",
+ log->dssd_specific_ver.major_ver);
+ json_object_add_value_uint(dssd_specific_ver, "minor_ver",
+ le16_to_cpu(log->dssd_specific_ver.minor_ver));
+ json_object_add_value_uint(dssd_specific_ver, "point_ver",
+ le16_to_cpu(log->dssd_specific_ver.point_ver));
+ json_object_add_value_uint(dssd_specific_ver, "errata_ver",
+ log->dssd_specific_ver.errata_ver);
+
+ root = json_create_object();
+ json_object_add_value_uint64(root, "physical_media_units_written",
+ le_to_float(log->physical_media_units_written, 16));
+ json_object_add_value_uint64(root, "physical_media_units_read",
+ le_to_float(log->physical_media_units_read, 16));
+ json_object_add_value_object(root, "bad_user_nand_blocks",
+ bad_user_nand_blocks);
+ json_object_add_value_object(root, "bad_system_nand_blocks",
+ bad_system_nand_blocks);
+ json_object_add_value_uint(root, "xor_recovery_count",
+ le64_to_cpu(log->xor_recovery_count));
+ json_object_add_value_uint(root, "uncorrectable_read_error_count",
+ le64_to_cpu(log->uncorrectable_read_error_count));
+ json_object_add_value_uint(root, "soft_ecc_error_count",
+ le64_to_cpu(log->soft_ecc_error_count));
+ json_object_add_value_object(root, "e2e_correction_counts",
+ e2e_correction_counts);
+ json_object_add_value_uint(root, "system_data_percent_used",
+ log->system_data_percent_used);
+ json_object_add_value_uint(root, "refresh_counts",
+ le64_to_cpu(log->refresh_counts));
+ json_object_add_value_object(root, "user_data_erase_counts",
+ user_data_erase_counts);
+ json_object_add_value_object(root, "thermal_status", thermal_status);
+ json_object_add_value_object(root, "dssd_specific_ver",
+ dssd_specific_ver);
+ json_object_add_value_uint(root, "pcie_correctable_error_count",
+ le64_to_cpu(log->pcie_correctable_error_count));
+ json_object_add_value_uint(root, "incomplete_shutdowns",
+ le32_to_cpu(log->incomplete_shutdowns));
+ 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));
+ sprintf(buf, "%c", log->nvme_errata_ver);
+ json_object_add_value_string(root, "nvme_errata_version", buf);
+ json_object_add_value_uint(root, "unaligned_io",
+ le64_to_cpu(log->unaligned_io));
+ json_object_add_value_uint(root, "security_version_number",
+ le64_to_cpu(log->security_version_number));
+ json_object_add_value_uint(root, "total_nuse",
+ le64_to_cpu(log->total_nuse));
+ json_object_add_value_uint64(root, "plp_start_count",
+ le_to_float(log->plp_start_count, 16));
+ json_object_add_value_uint64(root, "endurance_estimate",
+ le_to_float(log->endurance_estimate, 16));
+ json_object_add_value_uint(root, "pcie_link_retraining_count",
+ le64_to_cpu(log->pcie_link_retraining_cnt));
+ json_object_add_value_uint(root, "power_state_change_count",
+ le64_to_cpu(log->power_state_change_cnt));
+ json_object_add_value_uint(root, "log_page_version",
+ le16_to_cpu(log->log_page_version));
+ stringify_log_page_guid(log->log_page_guid, buf);
+ json_object_add_value_string(root, "log_page_guid", buf);
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void show_cloud_smart_log_normal(struct ocp_cloud_smart_log *log, struct nvme_dev *dev)
+{
+ char buf[2 * sizeof(log->log_page_guid) + 3];
+
+ printf("Smart Extended Log for NVME device:%s\n", dev->name);
+ printf("Physical Media Units Written : %'.0Lf\n",
+ le_to_float(log->physical_media_units_written, 16));
+ printf("Physical Media Units Read : %'.0Lf\n",
+ le_to_float(log->physical_media_units_read, 16));
+ printf("Bad User NAND Blocks (Normalized) : %" PRIu16 "%%\n",
+ le16_to_cpu(log->bad_user_nand_blocks.normalized));
+ printf("Bad User NAND Blocks (Raw) : %" PRIu64 "\n",
+ le64_to_cpu(log->bad_user_nand_blocks.raw));
+ printf("Bad System NAND Blocks (Normalized) : %" PRIu16 "%%\n",
+ le16_to_cpu(log->bad_system_nand_blocks.normalized));
+ printf("Bad System NAND Blocks (Raw) : %" PRIu64 "\n",
+ le64_to_cpu(log->bad_system_nand_blocks.raw));
+ printf("XOR Recovery Count : %" PRIu64 "\n",
+ le64_to_cpu(log->xor_recovery_count));
+ printf("Uncorrectable Read Error Count : %" PRIu64 "\n",
+ le64_to_cpu(log->uncorrectable_read_error_count));
+ printf("Soft ECC Error Count : %" PRIu64 "\n",
+ le64_to_cpu(log->soft_ecc_error_count));
+ printf("End to End Correction Counts (Corrected) : %" PRIu32 "\n",
+ le32_to_cpu(log->e2e_correction_counts.corrected));
+ printf("End to End Correction Counts (Detected) : %" PRIu32 "\n",
+ le32_to_cpu(log->e2e_correction_counts.detected));
+ printf("System Data %% Used : %" PRIu8 "%%\n",
+ log->system_data_percent_used);
+ printf("Refresh Counts : %" PRIu64 "\n",
+ le64_to_cpu(log->refresh_counts));
+ printf("User Data Erase Counts (Minimum) : %" PRIu32 "\n",
+ le32_to_cpu(log->user_data_erase_counts.minimum));
+ printf("User Data Erase Counts (Maximum) : %" PRIu32 "\n",
+ le32_to_cpu(log->user_data_erase_counts.maximum));
+ printf("Thermal Throttling Status (Current Status) : %s\n",
+ stringify_cloud_smart_log_thermal_status(log->thermal_status.current_status));
+ printf("Thermal Throttling Status (Number of Events) : %" PRIu8 "\n",
+ log->thermal_status.num_events);
+ printf("NVMe Major Version : %" PRIu8 "\n",
+ log->dssd_specific_ver.major_ver);
+ printf(" Minor Version : %" PRIu16 "\n",
+ le16_to_cpu(log->dssd_specific_ver.minor_ver));
+ printf(" Point Version : %" PRIu16 "\n",
+ le16_to_cpu(log->dssd_specific_ver.point_ver));
+ printf(" Errata Version : %" PRIu8 "\n",
+ log->dssd_specific_ver.errata_ver);
+ printf("PCIe Correctable Error Count : %" PRIu64 "\n",
+ le64_to_cpu(log->pcie_correctable_error_count));
+ printf("Incomplete Shutdowns : %" PRIu32 "\n",
+ le32_to_cpu(log->incomplete_shutdowns));
+ printf("%% Free Blocks : %" PRIu8 "%%\n",
+ log->percent_free_blocks);
+ printf("Capacitor Health : %" PRIu16 "%%\n",
+ le16_to_cpu(log->capacitor_health));
+ printf("NVMe Errata Version : %c\n",
+ log->nvme_errata_ver);
+ printf("Unaligned IO : %" PRIu64 "\n",
+ le64_to_cpu(log->unaligned_io));
+ printf("Security Version Number : %" PRIu64 "\n",
+ le64_to_cpu(log->security_version_number));
+ printf("Total NUSE : %" PRIu64 "\n",
+ le64_to_cpu(log->total_nuse));
+ printf("PLP Start Count : %'.0Lf\n",
+ le_to_float(log->plp_start_count, 16));
+ printf("Endurance Estimate : %'.0Lf\n",
+ le_to_float(log->endurance_estimate, 16));
+ printf("PCIe Link Retraining Count : %" PRIu64 "\n",
+ le64_to_cpu(log->pcie_link_retraining_cnt));
+ printf("Power State Change Count : %" PRIu64 "\n",
+ le64_to_cpu(log->power_state_change_cnt));
+ printf("Log Page Version : %" PRIu16 "\n",
+ le16_to_cpu(log->log_page_version));
+ stringify_log_page_guid(log->log_page_guid, buf);
+ printf("Log Page GUID : %s\n", buf);
+ printf("\n\n");
+}
+
static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command,
struct plugin *plugin)
{
@@ -7243,6 +8013,7 @@ static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command,
const char *log_page_version = "Log Page Version: 0 = vendor, 1 = WDC";
const char *log_page_mask = "Log Page Mask, comma separated list: 0xC0, 0xC1, 0xCA, 0xD0";
const char *namespace_id = "desired namespace id";
+ enum nvme_print_flags fmt;
struct nvme_dev *dev;
nvme_root_t r;
int ret = 0;
@@ -7250,6 +8021,7 @@ static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command,
int page_mask = 0, num, i;
int log_page_list[16];
__u64 capabilities = 0;
+ __u32 device_id, read_vendor_id;
struct config {
uint8_t interval;
@@ -7269,7 +8041,7 @@ static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command,
OPT_ARGS(opts) = {
OPT_UINT("interval", 'i', &cfg.interval, interval),
- OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
OPT_BYTE("log-page-version", 'l', &cfg.log_page_version, log_page_version),
OPT_LIST("log-page-mask", 'p', &cfg.log_page_mask, log_page_mask),
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
@@ -7317,8 +8089,9 @@ static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command,
if (!page_mask)
fprintf(stderr, "ERROR: WDC: Unknown log page mask - %s\n", cfg.log_page_mask);
- capabilities = wdc_get_drive_capabilities(r, dev);
+ ret = wdc_get_pci_ids(r, dev, &device_id, &read_vendor_id);
+ capabilities = wdc_get_drive_capabilities(r, dev);
if (!(capabilities & WDC_DRIVE_CAP_SMART_LOG_MASK)) {
fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
ret = -1;
@@ -7328,13 +8101,56 @@ static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command,
if (((capabilities & WDC_DRIVE_CAP_C0_LOG_PAGE) == WDC_DRIVE_CAP_C0_LOG_PAGE) &&
(page_mask & WDC_C0_PAGE_MASK)) {
/* Get 0xC0 log page if possible. */
- ret = wdc_get_c0_log_page(r, dev, cfg.output_format,
- uuid_index, cfg.namespace_id);
- if (ret)
- fprintf(stderr, "ERROR: WDC: Failure reading the C0 Log Page, ret = %d\n", ret);
+ if (!wdc_is_sn861(device_id)) {
+ ret = wdc_get_c0_log_page(r, dev, cfg.output_format,
+ uuid_index, cfg.namespace_id);
+ if (ret)
+ fprintf(stderr,
+ "ERROR: WDC: Failure reading the C0 Log Page, ret = %d\n",
+ ret);
+ } else {
+ struct ocp_cloud_smart_log log;
+ char buf[2 * sizeof(log.log_page_guid) + 3];
+
+ ret = validate_output_format(output_format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "Invalid output format: %s\n", cfg.output_format);
+ goto out;
+ }
+
+ ret = nvme_get_log_simple(dev_fd(dev),
+ WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_ID,
+ sizeof(log), &log);
+ if (!ret) {
+ char *ptr = buf;
+ int i;
+ __u8 *guid = log.log_page_guid;
+
+ memset(buf, 0, sizeof(char) * 19);
+
+ ptr += sprintf(ptr, "0x");
+ for (i = 0; i < 16; i++)
+ ptr += sprintf(ptr, "%x", guid[15 - i]);
+ if (strcmp(buf, "0xafd514c97c6f4f9ca4f2bfea2810afc5"))
+ fprintf(stderr, "Invalid GUID: %s\n", buf);
+ else {
+ if (fmt == BINARY)
+ d_raw((unsigned char *)&log, sizeof(log));
+ else if (fmt == JSON)
+ show_cloud_smart_log_json(&log);
+ else
+ show_cloud_smart_log_normal(&log, dev);
+ }
+ } else if (ret > 0) {
+ nvme_show_status(ret);
+ } else {
+ perror("vs-smart-add-log");
+ }
+ }
}
if (((capabilities & (WDC_DRIVE_CAP_CA_LOG_PAGE)) == (WDC_DRIVE_CAP_CA_LOG_PAGE)) &&
- (page_mask & WDC_CA_PAGE_MASK)) {
+ (page_mask & WDC_CA_PAGE_MASK) &&
+ (!wdc_is_sn861(device_id))) {
/* Get the CA Log Page */
ret = wdc_get_ca_log_page(r, dev, cfg.output_format);
if (ret)
@@ -7367,10 +8183,11 @@ static int wdc_vs_cloud_log(int argc, char **argv, struct command *command,
{
const char *desc = "Retrieve Cloud Log Smart/Health Information";
const char *namespace_id = "desired namespace id";
+ enum nvme_print_flags fmt;
__u64 capabilities = 0;
struct nvme_dev *dev;
- int ret, fmt = -1;
nvme_root_t r;
+ int ret;
__u8 *data;
struct config {
@@ -7411,14 +8228,13 @@ static int wdc_vs_cloud_log(int argc, char **argv, struct command *command,
nvme_show_status(ret);
if (!ret) {
- fmt = validate_output_format(cfg.output_format);
- if (fmt < 0) {
+ ret = validate_output_format(cfg.output_format, &fmt);
+ if (ret < 0) {
fprintf(stderr, "ERROR: WDC %s: invalid output format\n", __func__);
- ret = fmt;
+ } else {
+ /* parse the data */
+ wdc_print_ext_smart_cloud_log(data, fmt);
}
-
- /* parse the data */
- wdc_print_ext_smart_cloud_log(data, fmt);
} else {
fprintf(stderr, "ERROR: WDC: Unable to read C0 Log Page V1 data\n");
ret = -1;
@@ -7438,9 +8254,10 @@ static int wdc_vs_hw_rev_log(int argc, char **argv, struct command *command,
{
const char *desc = "Retrieve Hardware Revision Log Information";
const char *namespace_id = "desired namespace id";
+ enum nvme_print_flags fmt;
__u64 capabilities = 0;
struct nvme_dev *dev;
- int ret, fmt = -1;
+ int ret;
__u8 *data = NULL;
nvme_root_t r;
@@ -7480,10 +8297,9 @@ static int wdc_vs_hw_rev_log(int argc, char **argv, struct command *command,
nvme_show_status(ret);
if (!ret) {
- fmt = validate_output_format(cfg.output_format);
- if (fmt < 0) {
+ ret = validate_output_format(cfg.output_format, &fmt);
+ if (ret < 0) {
fprintf(stderr, "ERROR: WDC %s: invalid output format\n", __func__);
- ret = fmt;
goto free_buf;
}
@@ -7499,6 +8315,8 @@ static int wdc_vs_hw_rev_log(int argc, char **argv, struct command *command,
case JSON:
wdc_print_hw_rev_log_json(data);
break;
+ default:
+ break;
}
} else {
fprintf(stderr, "ERROR: WDC: Unable to read Hardware Revision Log Page data\n");
@@ -7521,11 +8339,11 @@ static int wdc_vs_device_waf(int argc, char **argv, struct command *command,
const char *desc = "Retrieve Device Write Amplication Factor";
const char *namespace_id = "desired namespace id";
struct nvme_smart_log smart_log;
+ enum nvme_print_flags fmt;
struct nvme_dev *dev;
__u8 *data;
nvme_root_t r;
int ret = 0;
- int fmt = -1;
__u64 capabilities = 0;
struct __packed wdc_nvme_ext_smart_log * ext_smart_log_ptr;
long double data_units_written = 0,
@@ -7601,10 +8419,9 @@ static int wdc_vs_device_waf(int argc, char **argv, struct command *command,
if (strcmp(cfg.output_format, "json"))
nvme_show_status(ret);
- fmt = validate_output_format(cfg.output_format);
- if (fmt < 0) {
+ ret = validate_output_format(cfg.output_format, &fmt);
+ if (ret < 0) {
fprintf(stderr, "ERROR: WDC %s: invalid output format\n", __func__);
- ret = fmt;
goto out;
}
@@ -7936,7 +8753,7 @@ static int wdc_drive_status(int argc, char **argv, struct command *command,
/* verify the 0xC2 Device Manageability log page is supported */
if (wdc_nvme_check_supported_log_page(r, dev,
- WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE) == false) {
+ WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID) == false) {
fprintf(stderr, "ERROR: WDC: 0xC2 Log Page not supported\n");
ret = -1;
goto out;
@@ -8078,18 +8895,18 @@ out:
static int wdc_get_fw_act_history(nvme_root_t r, struct nvme_dev *dev,
char *format)
{
- int ret = 0;
- int fmt = -1;
- __u8 *data;
struct wdc_fw_act_history_log_hdr *fw_act_history_hdr;
+ enum nvme_print_flags fmt;
+ int ret;
+ __u8 *data;
if (!wdc_check_device(r, dev))
return -1;
- fmt = validate_output_format(format);
- if (fmt < 0) {
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
fprintf(stderr, "ERROR: WDC: invalid output format\n");
- return fmt;
+ return ret;
}
/* verify the FW Activate History log page is supported */
@@ -8121,7 +8938,7 @@ static int wdc_get_fw_act_history(nvme_root_t r, struct nvme_dev *dev,
if ((fw_act_history_hdr->num_entries > 0) &&
(fw_act_history_hdr->num_entries <= WDC_MAX_NUM_ACT_HIST_ENTRIES)) {
ret = wdc_print_fw_act_history_log(data, fw_act_history_hdr->num_entries,
- fmt, 0, 0);
+ fmt, 0, 0, 0);
} else if (!fw_act_history_hdr->num_entries) {
fprintf(stderr, "INFO: WDC: No FW Activate History entries found.\n");
ret = 0;
@@ -8159,21 +8976,21 @@ static __u32 wdc_get_fw_cust_id(nvme_root_t r, struct nvme_dev *dev)
static int wdc_get_fw_act_history_C2(nvme_root_t r, struct nvme_dev *dev,
char *format)
{
- int ret = 0;
- int fmt = -1;
- __u8 *data;
- __u32 cust_id;
struct wdc_fw_act_history_log_format_c2 *fw_act_history_log;
__u32 tot_entries = 0, num_entries = 0;
__u32 vendor_id = 0, device_id = 0;
+ __u32 cust_id = 0;
+ enum nvme_print_flags fmt;
+ __u8 *data;
+ int ret;
if (!wdc_check_device(r, dev))
return -1;
- fmt = validate_output_format(format);
- if (fmt < 0) {
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
fprintf(stderr, "ERROR: WDC: invalid output format\n");
- return fmt;
+ return ret;
}
ret = wdc_get_pci_ids(r, dev, &device_id, &vendor_id);
@@ -8200,15 +9017,20 @@ static int wdc_get_fw_act_history_C2(nvme_root_t r, struct nvme_dev *dev,
if (tot_entries > 0) {
/* get the FW customer id */
- cust_id = wdc_get_fw_cust_id(r, dev);
- if (cust_id == WDC_INVALID_CUSTOMER_ID) {
- fprintf(stderr, "%s: ERROR: WDC: invalid customer id\n", __func__);
- ret = -1;
- goto freeData;
+ if (!wdc_is_sn861(device_id)) {
+ cust_id = wdc_get_fw_cust_id(r, dev);
+ if (cust_id == WDC_INVALID_CUSTOMER_ID) {
+ fprintf(stderr,
+ "%s: ERROR: WDC: invalid customer id\n",
+ __func__);
+ ret = -1;
+ goto freeData;
+ }
}
num_entries = (tot_entries < WDC_MAX_NUM_ACT_HIST_ENTRIES) ? tot_entries :
WDC_MAX_NUM_ACT_HIST_ENTRIES;
- ret = wdc_print_fw_act_history_log(data, num_entries, fmt, cust_id, vendor_id);
+ ret = wdc_print_fw_act_history_log(data, num_entries,
+ fmt, cust_id, vendor_id, device_id);
} else {
fprintf(stderr, "INFO: WDC: No FW Activate History entries found.\n");
ret = 0;
@@ -9437,7 +10259,7 @@ static int wdc_reason_identifier(int argc, char **argv,
cfg.log_id != NVME_LOG_LID_TELEMETRY_CTRL) {
fprintf(stderr, "ERROR: WDC: Invalid Log ID. It must be 7 (Host) or 8 (Controller)\n");
ret = -1;
- goto close_fd;
+ goto close_dev;
}
if (cfg.file) {
@@ -9448,7 +10270,7 @@ static int wdc_reason_identifier(int argc, char **argv,
if (verify_file < 0) {
fprintf(stderr, "ERROR: WDC: open: %s\n", strerror(errno));
ret = -1;
- goto close_fd;
+ goto close_dev;
}
close(verify_file);
strncpy(f, cfg.file, PATH_MAX - 1);
@@ -9466,12 +10288,12 @@ static int wdc_reason_identifier(int argc, char **argv,
if (wdc_get_serial_name(dev, f, PATH_MAX, fileSuffix) == -1) {
fprintf(stderr, "ERROR: WDC: failed to generate file name\n");
ret = -1;
- goto close_fd;
+ goto close_dev;
}
if (strlen(f) > PATH_MAX - 5) {
fprintf(stderr, "ERROR: WDC: file name overflow\n");
ret = -1;
- goto close_fd;
+ goto close_dev;
}
strcat(f, ".bin");
}
@@ -9488,7 +10310,7 @@ static int wdc_reason_identifier(int argc, char **argv,
nvme_show_status(ret);
-close_fd:
+close_dev:
dev_close(dev);
nvme_free_tree(r);
return ret;
@@ -9570,10 +10392,104 @@ static const char *nvme_log_id_to_string(__u8 log_id)
}
}
+static void __json_log_page_directory(struct log_page_directory *directory)
+{
+ __u32 bitmap_idx;
+ __u8 log_id;
+ struct json_object *root;
+ struct json_object *entries;
+
+ root = json_create_object();
+
+ entries = json_create_array();
+ json_object_add_value_array(root, "Entries", entries);
+
+ for (bitmap_idx = 0; bitmap_idx < BYTE_TO_BIT(sizeof(__u64)); bitmap_idx++) {
+ log_id = bitmap_idx;
+ if (!log_page_name[log_id])
+ continue;
+ if (directory->supported_lid_bitmap & (1ULL << bitmap_idx)) {
+ struct json_object *json_entry = json_create_object();
+
+ json_object_add_value_uint(json_entry, "Log ID", log_id);
+ json_object_add_value_string(json_entry, "Log Page Name",
+ log_page_name[log_id]);
+
+ json_array_add_value_object(entries, json_entry);
+ }
+ }
+
+ for (bitmap_idx = 0; bitmap_idx < BYTE_TO_BIT(sizeof(__u64)); bitmap_idx++) {
+ log_id = NVME_LOG_NS_BASE + bitmap_idx;
+ if (!log_page_name[log_id])
+ continue;
+ if (directory->supported_ns_lid_bitmap & (1ULL << bitmap_idx)) {
+ struct json_object *json_entry = json_create_object();
+
+ json_object_add_value_uint(json_entry, "Log ID", log_id);
+ json_object_add_value_string(json_entry, "Log Page Name",
+ log_page_name[log_id]);
+
+ json_array_add_value_object(entries, json_entry);
+ }
+ }
+
+ for (bitmap_idx = 0; bitmap_idx < BYTE_TO_BIT(sizeof(__u64)); bitmap_idx++) {
+ log_id = NVME_LOG_VS_BASE + bitmap_idx;
+ if (!log_page_name[log_id])
+ continue;
+ if (directory->supported_vs_lid_bitmap & (1ULL << bitmap_idx)) {
+ struct json_object *json_entry = json_create_object();
+
+ json_object_add_value_uint(json_entry, "Log ID", log_id);
+ json_object_add_value_string(json_entry, "Log Page Name",
+ log_page_name[log_id]);
+
+ json_array_add_value_object(entries, json_entry);
+ }
+ }
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+
+static void __show_log_page_directory(struct log_page_directory *directory)
+{
+ __u32 bitmap_idx;
+ __u8 log_id;
+
+ for (bitmap_idx = 0; bitmap_idx < BYTE_TO_BIT(sizeof(__u64)); bitmap_idx++) {
+ if (directory->supported_lid_bitmap & (1ULL << bitmap_idx)) {
+ log_id = bitmap_idx;
+ if (log_page_name[log_id])
+ printf("0x%02X: %s\n", log_id, log_page_name[log_id]);
+ }
+ }
+
+ for (bitmap_idx = 0; bitmap_idx < BYTE_TO_BIT(sizeof(__u64)); bitmap_idx++) {
+ if (directory->supported_ns_lid_bitmap & (1ULL << bitmap_idx)) {
+ log_id = NVME_LOG_NS_BASE + bitmap_idx;
+ if (log_page_name[log_id])
+ printf("0x%02X: %s\n", log_id, log_page_name[log_id]);
+ }
+ }
+
+ for (bitmap_idx = 0; bitmap_idx < BYTE_TO_BIT(sizeof(__u64)); bitmap_idx++) {
+ if (directory->supported_vs_lid_bitmap & (1ULL << bitmap_idx)) {
+ log_id = NVME_LOG_VS_BASE + bitmap_idx;
+ if (log_page_name[log_id])
+ printf("0x%02X: %s\n", log_id, log_page_name[log_id]);
+ }
+ }
+}
+
static int wdc_log_page_directory(int argc, char **argv, struct command *command,
struct plugin *plugin)
{
const char *desc = "Retrieve Log Page Directory.";
+ enum nvme_print_flags fmt;
struct nvme_dev *dev;
int ret = 0;
nvme_root_t r;
@@ -9582,6 +10498,8 @@ static int wdc_log_page_directory(int argc, char **argv, struct command *command
int i;
__u8 log_id = 0;
__u32 device_id, read_vendor_id;
+ bool uuid_supported = false;
+ struct nvme_id_uuid_list uuid_list;
struct config {
char *output_format;
@@ -9600,13 +10518,12 @@ static int wdc_log_page_directory(int argc, char **argv, struct command *command
if (ret)
return ret;
- ret = validate_output_format(cfg.output_format);
+ ret = validate_output_format(cfg.output_format, &fmt);
if (ret < 0) {
fprintf(stderr, "%s: ERROR: WDC: invalid output format\n", __func__);
dev_close(dev);
return ret;
}
- ret = 0;
r = nvme_scan(NULL);
capabilities = wdc_get_drive_capabilities(r, dev);
@@ -9615,54 +10532,110 @@ static int wdc_log_page_directory(int argc, char **argv, struct command *command
fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
ret = -1;
} else {
- ret = wdc_get_pci_ids(r, dev, &device_id, &read_vendor_id);
- log_id = (device_id == WDC_NVME_ZN350_DEV_ID || device_id == WDC_NVME_ZN350_DEV_ID_1) ?
- WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE_C8 : WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE;
- /* verify the 0xC2 Device Manageability log page is supported */
- if (wdc_nvme_check_supported_log_page(r, dev, log_id) == false) {
- fprintf(stderr, "%s: ERROR: WDC: 0x%x Log Page not supported\n", __func__, log_id);
- ret = -1;
- goto out;
- }
- if (get_dev_mgment_cbs_data(r, dev, WDC_C2_LOG_PAGES_SUPPORTED_ID, (void *)&cbs_data)) {
- if (cbs_data) {
- printf("Log Page Directory\n");
- /* print the supported pages */
- if (!strcmp(cfg.output_format, "normal")) {
- for (i = 0; i < le32_to_cpu(cbs_data->length); i++)
- printf("0x%x - %s\n", cbs_data->data[i],
- nvme_log_id_to_string(cbs_data->data[i]));
- } else if (!strcmp(cfg.output_format, "binary")) {
- d((__u8 *)cbs_data->data, le32_to_cpu(cbs_data->length), 16,
- 1);
- } else if (!strcmp(cfg.output_format, "json")) {
- struct json_object *root = json_create_object();
-
- for (i = 0; i < le32_to_cpu(cbs_data->length); i++)
- json_object_add_value_int(root,
- nvme_log_id_to_string(cbs_data->data[i]),
- cbs_data->data[i]);
+ memset(&uuid_list, 0, sizeof(struct nvme_id_uuid_list));
+ if (wdc_CheckUuidListSupport(dev, &uuid_list))
+ uuid_supported = true;
- json_print_object(root, NULL);
- printf("\n");
- json_free_object(root);
- } else {
- fprintf(stderr,
- "%s: ERROR: WDC: Invalid format, format = %s\n",
- __func__, cfg.output_format);
+ if (uuid_supported)
+ fprintf(stderr, "WDC: UUID lists supported\n");
+ else
+ fprintf(stderr, "WDC: UUID lists NOT supported\n");
+
+
+ ret = wdc_get_pci_ids(r, dev, &device_id, &read_vendor_id);
+ log_id = (device_id == WDC_NVME_ZN350_DEV_ID ||
+ device_id == WDC_NVME_ZN350_DEV_ID_1) ?
+ WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID_C8 :
+ WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID;
+
+ if (!wdc_is_sn861(device_id)) {
+ /* verify the 0xC2 Device Manageability log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev, log_id) == false) {
+ fprintf(stderr,
+ "%s: ERROR: WDC: 0x%x Log Page not supported\n",
+ __func__, log_id);
+ ret = -1;
+ goto out;
+ }
+
+ if (!get_dev_mgment_cbs_data(r, dev,
+ WDC_C2_LOG_PAGES_SUPPORTED_ID,
+ (void *)&cbs_data)) {
+ fprintf(stderr,
+ "%s: ERROR: WDC: 0xC2 Log Page entry ID 0x%x not found\n",
+ __func__, WDC_C2_LOG_PAGES_SUPPORTED_ID);
+ ret = -1;
+ goto out;
+ }
+ if (!cbs_data) {
+ fprintf(stderr, "%s: ERROR: WDC: NULL_data ptr\n", __func__);
+ ret = -1;
+ goto out;
+ }
+ printf("Log Page Directory\n");
+ /* print the supported pages */
+ if (!strcmp(cfg.output_format, "normal")) {
+ for (i = 0; i < le32_to_cpu(cbs_data->length); i++)
+ printf("0x%x - %s\n", cbs_data->data[i],
+ nvme_log_id_to_string(cbs_data->data[i]));
+ } else if (!strcmp(cfg.output_format, "binary")) {
+ d((__u8 *)cbs_data->data,
+ le32_to_cpu(cbs_data->length), 16, 1);
+ } else if (!strcmp(cfg.output_format, "json")) {
+ struct json_object *root = json_create_object();
+
+ for (i = 0; i < le32_to_cpu(cbs_data->length); i++) {
+ json_object_add_value_int(root,
+ nvme_log_id_to_string(cbs_data->data[i]),
+ cbs_data->data[i]);
}
- free(cbs_data);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
} else {
- fprintf(stderr, "%s: ERROR: WDC: NULL_data ptr\n", __func__);
+ fprintf(stderr,
+ "%s: ERROR: WDC: Invalid format, format = %s\n",
+ __func__, cfg.output_format);
}
+
+ free(cbs_data);
} else {
- fprintf(stderr, "%s: ERROR: WDC: 0xC2 Log Page entry ID 0x%x not found\n",
- __func__, WDC_C2_LOG_PAGES_SUPPORTED_ID);
- }
+ struct log_page_directory *dir;
+ void *data = NULL;
+ __u32 result;
+
+ if (posix_memalign(&data, getpagesize(), 512)) {
+ fprintf(stderr,
+ "can not allocate log page directory payload\n");
+ ret = ENOMEM;
+ goto out;
+ }
+ dir = (struct log_page_directory *)data;
+ ret = nvme_admin_passthru(dev_fd(dev), WDC_NVME_ADMIN_VUC_OPCODE_D2, 0, 0,
+ 0, 0, 0, 8,
+ 0, WDC_VUC_SUBOPCODE_LOG_PAGE_DIR_D2, 0, 0, 0,
+ 32, data, 0, NULL,
+ 0, &result);
+ if (!ret) {
+ switch (fmt) {
+ case BINARY:
+ d_raw((unsigned char *)data, 32);
+ break;
+ case JSON:
+ __json_log_page_directory(dir);
+ break;
+ default:
+ __show_log_page_directory(dir);
+ }
+ } else {
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(ret, false), ret);
+ }
+ }
}
out:
@@ -10176,22 +11149,21 @@ static void wdc_print_pcie_stats_json(struct wdc_vs_pcie_stats *pcie_stats)
static int wdc_do_vs_nand_stats_sn810_2(struct nvme_dev *dev, char *format)
{
- int ret;
- int fmt = -1;
+ enum nvme_print_flags fmt;
uint8_t *data = NULL;
+ int ret;
data = NULL;
ret = nvme_get_ext_smart_cloud_log(dev_fd(dev), &data, 0,
NVME_NSID_ALL);
if (ret) {
- fprintf(stderr, "ERROR: WDC: %s : Failed to retreive NAND stats\n", __func__);
+ fprintf(stderr, "ERROR: WDC: %s : Failed to retrieve NAND stats\n", __func__);
goto out;
} else {
- fmt = validate_output_format(format);
- if (fmt < 0) {
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
fprintf(stderr, "ERROR: WDC: %s : invalid output format\n", __func__);
- ret = fmt;
goto out;
}
@@ -10203,6 +11175,8 @@ static int wdc_do_vs_nand_stats_sn810_2(struct nvme_dev *dev, char *format)
case JSON:
wdc_print_ext_smart_cloud_log_json(data, WDC_SCA_V1_NAND_STATS);
break;
+ default:
+ break;
}
}
@@ -10214,10 +11188,10 @@ out:
static int wdc_do_vs_nand_stats(struct nvme_dev *dev, char *format)
{
- int ret;
- int fmt = -1;
+ enum nvme_print_flags fmt;
uint8_t *output = NULL;
__u16 version = 0;
+ int ret;
output = (uint8_t *)calloc(WDC_NVME_NAND_STATS_SIZE, sizeof(uint8_t));
if (!output) {
@@ -10229,13 +11203,12 @@ static int wdc_do_vs_nand_stats(struct nvme_dev *dev, char *format)
ret = nvme_get_log_simple(dev_fd(dev), WDC_NVME_NAND_STATS_LOG_ID,
WDC_NVME_NAND_STATS_SIZE, (void *)output);
if (ret) {
- fprintf(stderr, "ERROR: WDC: %s : Failed to retreive NAND stats\n", __func__);
+ fprintf(stderr, "ERROR: WDC: %s : Failed to retrieve NAND stats\n", __func__);
goto out;
} else {
- fmt = validate_output_format(format);
- if (fmt < 0) {
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
fprintf(stderr, "ERROR: WDC: invalid output format\n");
- ret = fmt;
goto out;
}
@@ -10249,6 +11222,8 @@ static int wdc_do_vs_nand_stats(struct nvme_dev *dev, char *format)
case JSON:
wdc_print_nand_stats_json(version, output);
break;
+ default:
+ break;
}
}
@@ -10337,14 +11312,14 @@ static int wdc_vs_pcie_stats(int argc, char **argv, struct command *command,
struct plugin *plugin)
{
const char *desc = "Retrieve PCIE statistics.";
+ enum nvme_print_flags fmt;
struct nvme_dev *dev;
- int ret = 0;
nvme_root_t r;
+ int ret;
__u64 capabilities = 0;
- int fmt = -1;
+ _cleanup_huge_ struct nvme_mem_huge mh = { 0, };
struct wdc_vs_pcie_stats *pcieStatsPtr = NULL;
int pcie_stats_size = sizeof(struct wdc_vs_pcie_stats);
- bool huge;
struct config {
char *output_format;
@@ -10363,16 +11338,14 @@ static int wdc_vs_pcie_stats(int argc, char **argv, struct command *command,
if (ret)
return ret;
-
r = nvme_scan(NULL);
- fmt = validate_output_format(cfg.output_format);
- if (fmt < 0) {
+ ret = validate_output_format(cfg.output_format, &fmt);
+ if (ret < 0) {
fprintf(stderr, "ERROR: WDC: invalid output format\n");
- ret = fmt;
goto out;
}
- pcieStatsPtr = nvme_alloc(pcie_stats_size, &huge);
+ pcieStatsPtr = nvme_alloc_huge(pcie_stats_size, &mh);
if (!pcieStatsPtr) {
fprintf(stderr, "ERROR: WDC: PCIE Stats alloc: %s\n", strerror(errno));
ret = -1;
@@ -10399,12 +11372,11 @@ static int wdc_vs_pcie_stats(int argc, char **argv, struct command *command,
case JSON:
wdc_print_pcie_stats_json(pcieStatsPtr);
break;
+ default:
+ break;
}
}
}
-
- nvme_free(pcieStatsPtr, huge);
-
out:
nvme_free_tree(r);
dev_close(dev);
@@ -10415,6 +11387,7 @@ static int wdc_vs_drive_info(int argc, char **argv,
struct command *command, struct plugin *plugin)
{
const char *desc = "Send a vs-drive-info command.";
+ enum nvme_print_flags fmt;
nvme_root_t r;
uint64_t capabilities = 0;
struct nvme_dev *dev;
@@ -10428,12 +11401,14 @@ static int wdc_vs_drive_info(int argc, char **argv,
__u8 *data = NULL;
__u32 ftl_unit_size = 0, tcg_dev_ownership = 0;
__u16 boot_spec_major = 0, boot_spec_minor = 0;
- int fmt = -1;
struct json_object *root = NULL;
char formatter[41] = { 0 };
char rev_str[16] = { 0 };
uint32_t read_device_id = -1, read_vendor_id = -1;
struct __packed wdc_nvme_ext_smart_log * ext_smart_log_ptr = NULL;
+ struct ocp_drive_info info;
+ __u32 data_len = 0;
+ unsigned int num_dwords = 0;
struct config {
char *output_format;
@@ -10452,11 +11427,11 @@ static int wdc_vs_drive_info(int argc, char **argv,
if (ret)
return ret;
- fmt = validate_output_format(cfg.output_format);
- if (fmt < 0) {
+ ret = validate_output_format(cfg.output_format, &fmt);
+ if (ret < 0) {
fprintf(stderr, "ERROR: WDC %s invalid output format\n", __func__);
dev_close(dev);
- return fmt;
+ return ret;
}
/* get the id ctrl data used to fill in drive info below */
@@ -10502,13 +11477,13 @@ static int wdc_vs_drive_info(int argc, char **argv,
rev = (double)(cpu_to_le32(result) & 0x0000ffff);
if (fmt == NORMAL) {
- printf("Drive HW Revison: %4.1f\n", (.1 * rev));
+ printf("Drive HW Revision: %4.1f\n", (.1 * rev));
printf("FTL Unit Size: 0x%x KB\n", size);
printf("Customer SN: %-.*s\n", (int)sizeof(ctrl.sn), &ctrl.sn[0]);
} else if (fmt == JSON) {
root = json_create_object();
sprintf(rev_str, "%4.1f", (.1 * rev));
- json_object_add_value_string(root, "Drive HW Revison", rev_str);
+ json_object_add_value_string(root, "Drive HW Revision", rev_str);
json_object_add_value_int(root, "FTL Unit Size", le16_to_cpu(size));
wdc_StrFormat(formatter, sizeof(formatter), &ctrl.sn[0], sizeof(ctrl.sn));
@@ -10611,6 +11586,52 @@ static int wdc_vs_drive_info(int argc, char **argv,
}
break;
+ case WDC_NVME_SN861_DEV_ID:
+ fallthrough;
+ case WDC_NVME_SN861_DEV_ID_1:
+ data_len = sizeof(info);
+ num_dwords = data_len / 4;
+ if (data_len % 4 != 0)
+ num_dwords += 1;
+
+ ret = nvme_admin_passthru(dev_fd(dev),
+ WDC_NVME_ADMIN_VUC_OPCODE_D2,
+ 0, 0, 0, 0, 0, num_dwords, 0,
+ WDC_VUC_SUBOPCODE_VS_DRIVE_INFO_D2,
+ 0, 0, 0, data_len, &info, 0,
+ NULL, 0, NULL);
+
+ if (!ret) {
+ __u16 hw_rev_major, hw_rev_minor;
+
+ hw_rev_major = le32_to_cpu(info.hw_revision) / 10;
+ hw_rev_minor = le32_to_cpu(info.hw_revision) % 10;
+ if (fmt == NORMAL) {
+ printf("HW Revision : %" PRIu32 ".%" PRIu32 "\n",
+ hw_rev_major, hw_rev_minor);
+ printf("FTL Unit Size : %" PRIu32 "\n",
+ le32_to_cpu(info.ftl_unit_size));
+ } else if (fmt == JSON) {
+ char buf[20];
+
+ root = json_create_object();
+
+ memset((void *)buf, 0, 20);
+ sprintf(buf, "%" PRIu32 ".%" PRIu32,
+ hw_rev_major, hw_rev_minor);
+
+ json_object_add_value_string(root,
+ "hw_revision", buf);
+ json_object_add_value_uint(root,
+ "ftl_unit_size",
+ le32_to_cpu(info.ftl_unit_size));
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+ }
+ }
+ break;
default:
fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
ret = -1;
@@ -10634,12 +11655,13 @@ static int wdc_vs_temperature_stats(int argc, char **argv,
const char *desc = "Send a vs-temperature-stats command.";
struct nvme_smart_log smart_log;
struct nvme_id_ctrl id_ctrl;
+ enum nvme_print_flags fmt;
struct nvme_dev *dev;
nvme_root_t r;
uint64_t capabilities = 0;
__u32 hctm_tmt;
int temperature, temp_tmt1, temp_tmt2;
- int ret, fmt = -1;
+ int ret;
struct config {
char *output_format;
@@ -10659,10 +11681,9 @@ static int wdc_vs_temperature_stats(int argc, char **argv,
return ret;
r = nvme_scan(NULL);
- fmt = validate_output_format(cfg.output_format);
- if (fmt < 0) {
+ ret = validate_output_format(cfg.output_format, &fmt);
+ if (ret < 0) {
fprintf(stderr, "ERROR: WDC: invalid output format\n");
- ret = fmt;
goto out;
}
@@ -10844,6 +11865,8 @@ static int wdc_capabilities(int argc, char **argv, struct command *command, stru
capabilities & WDC_DRIVE_CAP_HW_REV_LOG_PAGE ? "Supported" : "Not Supported");
printf("vs-device_waf : %s\n",
capabilities & WDC_DRIVE_CAP_DEVICE_WAF ? "Supported" : "Not Supported");
+ printf("set-latency-monitor-feature : %s\n",
+ capabilities & WDC_DRIVE_CAP_SET_LATENCY_MONITOR ? "Supported" : "Not Supported");
printf("capabilities : Supported\n");
nvme_free_tree(r);
dev_close(dev);
@@ -11214,3 +12237,159 @@ static int wdc_enc_get_nic_log(struct nvme_dev *dev, __u8 log_id, __u32 xfer_siz
free(dump_data);
return ret;
}
+
+//------------------------------------------------------------------------------------
+// Description: set latency monitor feature
+//
+int wdc_set_latency_monitor_feature(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Set Latency Monitor feature.";
+
+ uint64_t capabilities = 0;
+ struct nvme_dev *dev;
+ nvme_root_t r;
+ int ret;
+ __u32 result;
+ struct feature_latency_monitor buf = {0,};
+
+ const char *active_bucket_timer_threshold =
+ "This is the value that loads the Active Bucket Timer Threshold.";
+ const char *active_threshold_a =
+ "This is the value that loads into the Active Threshold A.";
+ const char *active_threshold_b =
+ "This is the value that loads into the Active Threshold B.";
+ const char *active_threshold_c =
+ "This is the value that loads into the Active Threshold C.";
+ const char *active_threshold_d =
+ "This is the value that loads into the Active Threshold D.";
+ const char *active_latency_config =
+ "This is the value that loads into the Active Latency Configuration.";
+ const char *active_latency_minimum_window =
+ "This is the value that loads into the Active Latency Minimum Window.";
+ const char *debug_log_trigger_enable =
+ "This is the value that loads into the Debug Log Trigger Enable.";
+ const char *discard_debug_log = "Discard Debug Log.";
+ const char *latency_monitor_feature_enable = "Latency Monitor Feature Enable.";
+
+ struct config {
+ __u16 active_bucket_timer_threshold;
+ __u8 active_threshold_a;
+ __u8 active_threshold_b;
+ __u8 active_threshold_c;
+ __u8 active_threshold_d;
+ __u16 active_latency_config;
+ __u8 active_latency_minimum_window;
+ __u16 debug_log_trigger_enable;
+ __u8 discard_debug_log;
+ __u8 latency_monitor_feature_enable;
+ };
+
+ struct config cfg = {
+ .active_bucket_timer_threshold = 0x7E0,
+ .active_threshold_a = 0x5,
+ .active_threshold_b = 0x13,
+ .active_threshold_c = 0x1E,
+ .active_threshold_d = 0x2E,
+ .active_latency_config = 0xFFF,
+ .active_latency_minimum_window = 0xA,
+ .debug_log_trigger_enable = 0,
+ .discard_debug_log = 0,
+ .latency_monitor_feature_enable = 0x7,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("active_bucket_timer_threshold", 't',
+ &cfg.active_bucket_timer_threshold,
+ active_bucket_timer_threshold),
+ OPT_UINT("active_threshold_a", 'a', &cfg.active_threshold_a,
+ active_threshold_a),
+ OPT_UINT("active_threshold_b", 'b', &cfg.active_threshold_b,
+ active_threshold_b),
+ OPT_UINT("active_threshold_c", 'c', &cfg.active_threshold_c,
+ active_threshold_c),
+ OPT_UINT("active_threshold_d", 'd', &cfg.active_threshold_d,
+ active_threshold_d),
+ OPT_UINT("active_latency_config", 'f',
+ &cfg.active_latency_config, active_latency_config),
+ OPT_UINT("active_latency_minimum_window", 'w',
+ &cfg.active_latency_minimum_window,
+ active_latency_minimum_window),
+ OPT_UINT("debug_log_trigger_enable", 'r',
+ &cfg.debug_log_trigger_enable, debug_log_trigger_enable),
+ OPT_UINT("discard_debug_log", 'l', &cfg.discard_debug_log,
+ discard_debug_log),
+ OPT_UINT("latency_monitor_feature_enable", 'e',
+ &cfg.latency_monitor_feature_enable,
+ latency_monitor_feature_enable),
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+
+ if (ret < 0)
+ return ret;
+
+ /* get capabilities */
+ r = nvme_scan(NULL);
+ wdc_check_device(r, dev);
+ capabilities = wdc_get_drive_capabilities(r, dev);
+
+ if (!(capabilities & WDC_DRIVE_CAP_SET_LATENCY_MONITOR)) {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ return -1;
+ }
+
+ memset(&buf, 0, sizeof(struct feature_latency_monitor));
+
+ buf.active_bucket_timer_threshold = cfg.active_bucket_timer_threshold;
+ buf.active_threshold_a = cfg.active_threshold_a;
+ buf.active_threshold_b = cfg.active_threshold_b;
+ buf.active_threshold_c = cfg.active_threshold_c;
+ buf.active_threshold_d = cfg.active_threshold_d;
+ buf.active_latency_config = cfg.active_latency_config;
+ buf.active_latency_minimum_window = cfg.active_latency_minimum_window;
+ buf.debug_log_trigger_enable = cfg.debug_log_trigger_enable;
+ buf.discard_debug_log = cfg.discard_debug_log;
+ buf.latency_monitor_feature_enable = cfg.latency_monitor_feature_enable;
+
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = NVME_FEAT_OCP_LATENCY_MONITOR,
+ .nsid = 0,
+ .cdw12 = 0,
+ .save = 1,
+ .data_len = sizeof(struct feature_latency_monitor),
+ .data = (void *)&buf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ ret = nvme_set_features(&args);
+
+ if (ret < 0) {
+ perror("set-feature");
+ } else if (!ret) {
+ printf("NVME_FEAT_OCP_LATENCY_MONITOR: 0x%02x\n",
+ NVME_FEAT_OCP_LATENCY_MONITOR);
+ printf("active bucket timer threshold: 0x%x\n",
+ buf.active_bucket_timer_threshold);
+ printf("active threshold a: 0x%x\n", buf.active_threshold_a);
+ printf("active threshold b: 0x%x\n", buf.active_threshold_b);
+ printf("active threshold c: 0x%x\n", buf.active_threshold_c);
+ printf("active threshold d: 0x%x\n", buf.active_threshold_d);
+ printf("active latency config: 0x%x\n", buf.active_latency_config);
+ printf("active latency minimum window: 0x%x\n",
+ buf.active_latency_minimum_window);
+ printf("debug log trigger enable: 0x%x\n",
+ buf.debug_log_trigger_enable);
+ printf("discard debug log: 0x%x\n", buf.discard_debug_log);
+ printf("latency monitor feature enable: 0x%x\n",
+ buf.latency_monitor_feature_enable);
+ } else if (ret > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(ret, false), ret);
+
+ return ret;
+}
diff --git a/plugins/wdc/wdc-nvme.h b/plugins/wdc/wdc-nvme.h
index cdd9615..f3f28a7 100644
--- a/plugins/wdc/wdc-nvme.h
+++ b/plugins/wdc/wdc-nvme.h
@@ -5,7 +5,7 @@
#if !defined(WDC_NVME) || defined(CMD_HEADER_MULTI_READ)
#define WDC_NVME
-#define WDC_PLUGIN_VERSION "2.3.1"
+#define WDC_PLUGIN_VERSION "2.3.5"
#include "cmd.h"
PLUGIN(NAME("wdc", "Western Digital vendor specific extensions", WDC_PLUGIN_VERSION),
@@ -17,34 +17,72 @@ PLUGIN(NAME("wdc", "Western Digital vendor specific extensions", WDC_PLUGIN_VERS
ENTRY("id-ctrl", "WDC identify controller", wdc_id_ctrl)
ENTRY("purge", "WDC Purge", wdc_purge)
ENTRY("purge-monitor", "WDC Purge Monitor", wdc_purge_monitor)
- ENTRY("vs-internal-log", "WDC Internal Firmware Log", wdc_vs_internal_fw_log)
+ ENTRY("vs-internal-log", "WDC Internal Firmware Log",
+ wdc_vs_internal_fw_log)
ENTRY("vs-nand-stats", "WDC NAND Statistics", wdc_vs_nand_stats)
- ENTRY("vs-smart-add-log", "WDC Additional Smart Log", wdc_vs_smart_add_log)
- ENTRY("clear-pcie-correctable-errors", "WDC Clear PCIe Correctable Error Count", wdc_clear_pcie_correctable_errors)
- ENTRY("drive-essentials", "WDC Drive Essentials", wdc_drive_essentials)
- ENTRY("get-drive-status", "WDC Get Drive Status", wdc_drive_status)
- ENTRY("clear-assert-dump", "WDC Clear Assert Dump", wdc_clear_assert_dump)
+ ENTRY("vs-smart-add-log", "WDC Additional Smart Log",
+ wdc_vs_smart_add_log)
+ ENTRY("clear-pcie-correctable-errors",
+ "WDC Clear PCIe Correctable Error Count",
+ wdc_clear_pcie_correctable_errors)
+ ENTRY("drive-essentials", "WDC Drive Essentials",
+ wdc_drive_essentials)
+ ENTRY("get-drive-status", "WDC Get Drive Status",
+ wdc_drive_status)
+ ENTRY("clear-assert-dump", "WDC Clear Assert Dump",
+ wdc_clear_assert_dump)
ENTRY("drive-resize", "WDC Drive Resize", wdc_drive_resize)
- ENTRY("vs-fw-activate-history", "WDC Get FW Activate History", wdc_vs_fw_activate_history)
- ENTRY("clear-fw-activate-history", "WDC Clear FW Activate History", wdc_clear_fw_activate_history)
+ ENTRY("vs-fw-activate-history", "WDC Get FW Activate History",
+ wdc_vs_fw_activate_history)
+ ENTRY("clear-fw-activate-history",
+ "WDC Clear FW Activate History",
+ wdc_clear_fw_activate_history)
ENTRY("enc-get-log", "WDC Get Enclosure Log", wdc_enc_get_log)
- ENTRY("vs-telemetry-controller-option", "WDC Enable/Disable Controller Initiated Telemetry Log", wdc_vs_telemetry_controller_option)
- ENTRY("vs-error-reason-identifier", "WDC Telemetry Reason Identifier", wdc_reason_identifier)
- ENTRY("log-page-directory", "WDC Get Log Page Directory", wdc_log_page_directory)
- ENTRY("namespace-resize", "WDC NamespaceDrive Resize", wdc_namespace_resize)
+ ENTRY("vs-telemetry-controller-option",
+ "WDC Enable/Disable Controller Initiated Telemetry Log",
+ wdc_vs_telemetry_controller_option)
+ ENTRY("vs-error-reason-identifier",
+ "WDC Telemetry Reason Identifier",
+ wdc_reason_identifier)
+ ENTRY("log-page-directory", "WDC Get Log Page Directory",
+ wdc_log_page_directory)
+ ENTRY("namespace-resize", "WDC NamespaceDrive Resize",
+ wdc_namespace_resize)
ENTRY("vs-drive-info", "WDC Get Drive Info", wdc_vs_drive_info)
- ENTRY("vs-temperature-stats", "WDC Get Temperature Stats", wdc_vs_temperature_stats)
- ENTRY("capabilities", "WDC Device Capabilities", wdc_capabilities)
- ENTRY("cloud-SSD-plugin-version", "WDC Cloud SSD Plugin Version", wdc_cloud_ssd_plugin_version)
- ENTRY("vs-pcie-stats", "WDC VS PCIE Statistics", wdc_vs_pcie_stats)
- ENTRY("get-latency-monitor-log", "WDC Get Latency Monitor Log Page", wdc_get_latency_monitor_log)
- ENTRY("get-error-recovery-log", "WDC Get Error Recovery Log Page", wdc_get_error_recovery_log)
- ENTRY("get-dev-capabilities-log", "WDC Get Device Capabilities Log Page", wdc_get_dev_capabilities_log)
- ENTRY("get-unsupported-reqs-log", "WDC Get Unsupported Requirements Log Page", wdc_get_unsupported_reqs_log)
- ENTRY("cloud-boot-SSD-version", "WDC Get the Cloud Boot SSD Version", wdc_cloud_boot_SSD_version)
- ENTRY("vs-cloud-log", "WDC Get the Cloud Log Page", wdc_vs_cloud_log)
- ENTRY("vs-hw-rev-log", "WDC Get the Hardware Revision Log Page", wdc_vs_hw_rev_log)
- ENTRY("vs-device-waf", "WDC Calculate Device Write Amplication Factor", wdc_vs_device_waf)
+ ENTRY("vs-temperature-stats", "WDC Get Temperature Stats",
+ wdc_vs_temperature_stats)
+ ENTRY("capabilities", "WDC Device Capabilities",
+ wdc_capabilities)
+ ENTRY("cloud-SSD-plugin-version",
+ "WDC Cloud SSD Plugin Version",
+ wdc_cloud_ssd_plugin_version)
+ ENTRY("vs-pcie-stats", "WDC VS PCIE Statistics",
+ wdc_vs_pcie_stats)
+ ENTRY("get-latency-monitor-log",
+ "WDC Get Latency Monitor Log Page",
+ wdc_get_latency_monitor_log)
+ ENTRY("get-error-recovery-log",
+ "WDC Get Error Recovery Log Page",
+ wdc_get_error_recovery_log)
+ ENTRY("get-dev-capabilities-log",
+ "WDC Get Device Capabilities Log Page",
+ wdc_get_dev_capabilities_log)
+ ENTRY("get-unsupported-reqs-log",
+ "WDC Get Unsupported Requirements Log Page",
+ wdc_get_unsupported_reqs_log)
+ ENTRY("cloud-boot-SSD-version",
+ "WDC Get the Cloud Boot SSD Version",
+ wdc_cloud_boot_SSD_version)
+ ENTRY("vs-cloud-log", "WDC Get the Cloud Log Page",
+ wdc_vs_cloud_log)
+ ENTRY("vs-hw-rev-log", "WDC Get the Hardware Revision Log Page",
+ wdc_vs_hw_rev_log)
+ ENTRY("vs-device-waf",
+ "WDC Calculate Device Write Amplication Factor",
+ wdc_vs_device_waf)
+ ENTRY("set-latency-monitor-feature",
+ "WDC set Latency Monitor feature",
+ wdc_set_latency_monitor_feature)
)
);
diff --git a/plugins/wdc/wdc-utils.c b/plugins/wdc/wdc-utils.c
index 3b60772..be2ef06 100644
--- a/plugins/wdc/wdc-utils.c
+++ b/plugins/wdc/wdc-utils.c
@@ -24,6 +24,9 @@
#include <string.h>
#include <unistd.h>
#include <time.h>
+#include "nvme.h"
+#include "libnvme.h"
+#include "nvme-print.h"
#include "wdc-utils.h"
int wdc_UtilsSnprintf(char *buffer, unsigned int sizeOfBuffer, const char *format, ...)
@@ -133,8 +136,8 @@ end:
/**
* Compares the strings ignoring their cases.
*
- * @param pcSrc Points to a null terminated string for comapring.
- * @param pcDst Points to a null terminated string for comapring.
+ * @param pcSrc Points to a null terminated string for comparing.
+ * @param pcDst Points to a null terminated string for comparing.
*
* @returns zero if the string matches or
* 1 if the pcSrc string is lexically higher than pcDst or
@@ -162,3 +165,42 @@ void wdc_StrFormat(char *formatter, size_t fmt_sz, char *tofmt, size_t tofmtsz)
}
}
+bool wdc_CheckUuidListSupport(struct nvme_dev *dev, struct nvme_id_uuid_list *uuid_list)
+{
+ int err;
+ struct nvme_id_ctrl ctrl;
+
+ memset(&ctrl, 0, sizeof(struct nvme_id_ctrl));
+ err = nvme_identify_ctrl(dev_fd(dev), &ctrl);
+ if (err) {
+ fprintf(stderr, "ERROR: WDC: nvme_identify_ctrl() failed 0x%x\n", err);
+ return false;
+ }
+
+ if ((ctrl.ctratt & NVME_CTRL_CTRATT_UUID_LIST) == NVME_CTRL_CTRATT_UUID_LIST) {
+ err = nvme_identify_uuid(dev_fd(dev), uuid_list);
+ if (!err)
+ return true;
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("identify UUID list: %s", nvme_strerror(errno));
+ }
+
+ return false;
+}
+
+bool wdc_UuidEqual(struct nvme_id_uuid_list_entry *entry1, struct nvme_id_uuid_list_entry *entry2)
+{
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ if (entry1->uuid[i] != entry2->uuid[i])
+ break;
+ }
+
+ if (i == 16)
+ return true;
+ else
+ return false;
+}
diff --git a/plugins/wdc/wdc-utils.h b/plugins/wdc/wdc-utils.h
index 83b208e..3fc47ca 100644
--- a/plugins/wdc/wdc-utils.h
+++ b/plugins/wdc/wdc-utils.h
@@ -31,6 +31,7 @@
#include <sys/time.h>
#include <sys/stat.h>
+#include <stdbool.h>
#include <string.h>
#include <unistd.h>
@@ -76,4 +77,5 @@ int wdc_UtilsStrCompare(char *pcSrc, char *pcDst);
int wdc_UtilsCreateDir(char *path);
int wdc_WriteToFile(char *fileName, char *buffer, unsigned int bufferLen);
void wdc_StrFormat(char *formatter, size_t fmt_sz, char *tofmt, size_t tofmtsz);
-
+bool wdc_CheckUuidListSupport(struct nvme_dev *dev, struct nvme_id_uuid_list *uuid_list);
+bool wdc_UuidEqual(struct nvme_id_uuid_list_entry *entry1, struct nvme_id_uuid_list_entry *entry2);
diff --git a/plugins/ymtc/ymtc-nvme.c b/plugins/ymtc/ymtc-nvme.c
index 1f99a64..5568c80 100644
--- a/plugins/ymtc/ymtc-nvme.c
+++ b/plugins/ymtc/ymtc-nvme.c
@@ -54,7 +54,7 @@ static int show_ymtc_smart_log(struct nvme_dev *dev, __u32 nsid,
/* Table Title */
printf("Additional Smart Log for NVME device:%s namespace-id:%x\n",
dev->name, nsid);
- /* Clumn Name*/
+ /* Column Name*/
printf("key normalized raw\n");
/* 00 SI_VD_PROGRAM_FAIL */
get_ymtc_smart_info(smart, SI_VD_PROGRAM_FAIL, nm, raw);
diff --git a/plugins/ymtc/ymtc-utils.h b/plugins/ymtc/ymtc-utils.h
index 39f79cb..e9a3572 100644
--- a/plugins/ymtc/ymtc-utils.h
+++ b/plugins/ymtc/ymtc-utils.h
@@ -34,7 +34,7 @@ typedef unsigned char u8;
#define SI_VD_THERMAL_THROTTLE_TIME_ID 0xEB
#define SI_VD_FLASH_MEDIA_ERROR_ID 0xED
-/* Addtional smart internal ID */
+/* Additional smart internal ID */
typedef enum
{
/* smart attr following intel */
diff --git a/plugins/zns/zns.c b/plugins/zns/zns.c
index 5b9d013..a7a3766 100644
--- a/plugins/zns/zns.c
+++ b/plugins/zns/zns.c
@@ -12,6 +12,7 @@
#include "nvme.h"
#include "libnvme.h"
#include "nvme-print.h"
+#include "util/cleanup.h"
#define CREATE_CMD
#include "zns.h"
@@ -135,9 +136,9 @@ static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *pl
if (err)
return errno;
- err = flags = validate_output_format(cfg.output_format);
- if (flags < 0)
- goto close_fd;
+ err = validate_output_format(cfg.output_format, &flags);
+ if (err < 0)
+ goto close_dev;
err = nvme_zns_identify_ctrl(dev_fd(dev), &ctrl);
if (!err)
@@ -146,7 +147,7 @@ static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *pl
nvme_show_status(err);
else
perror("zns identify controller");
-close_fd:
+close_dev:
dev_close(dev);
return err;
}
@@ -188,9 +189,9 @@ static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plug
if (err)
return errno;
- flags = validate_output_format(cfg.output_format);
- if (flags < 0)
- goto close_fd;
+ err = validate_output_format(cfg.output_format, &flags);
+ if (err < 0)
+ goto close_dev;
if (cfg.vendor_specific)
flags |= VS;
if (cfg.human_readable)
@@ -200,14 +201,14 @@ static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plug
err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
if (err < 0) {
perror("get-namespace-id");
- goto close_fd;
+ goto close_dev;
}
}
err = nvme_identify_ns(dev_fd(dev), cfg.namespace_id, &id_ns);
if (err) {
nvme_show_status(err);
- goto close_fd;
+ goto close_dev;
}
err = nvme_zns_identify_ns(dev_fd(dev), cfg.namespace_id, &ns);
@@ -217,7 +218,7 @@ static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plug
nvme_show_status(err);
else
perror("zns identify namespace");
-close_fd:
+close_dev:
dev_close(dev);
return err;
}
@@ -560,7 +561,7 @@ static int set_zone_desc(int argc, char **argv, struct command *cmd, struct plug
const char *desc = "Set Zone Descriptor Extension\n";
const char *zslba = "starting LBA of the zone for this command";
const char *zrwaa = "Allocate Zone Random Write Area to zone";
- const char *data = "optional file for zone extention data (default stdin)";
+ const char *data = "optional file for zone extension data (default stdin)";
const char *timeout = "timeout value, in milliseconds";
int ffd = STDIN_FILENO, err;
@@ -603,7 +604,7 @@ static int set_zone_desc(int argc, char **argv, struct command *cmd, struct plug
if (!data_len || data_len < 0) {
fprintf(stderr,
- "zone format does not provide descriptor extention\n");
+ "zone format does not provide descriptor extension\n");
errno = EINVAL;
err = -1;
goto close_dev;
@@ -765,8 +766,8 @@ static int zone_mgmt_recv(int argc, char **argv, struct command *cmd, struct plu
if (err)
return errno;
- flags = validate_output_format(cfg.output_format);
- if (flags < 0)
+ err = validate_output_format(cfg.output_format, &flags);
+ if (err < 0)
goto close_dev;
if (!cfg.namespace_id) {
@@ -833,20 +834,20 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi
int zdes = 0, err = -1;
struct nvme_dev *dev;
__u32 report_size;
- bool huge = false;
struct nvme_zone_report *report, *buff;
+ _cleanup_huge_ struct nvme_mem_huge mh = { 0, };
unsigned int nr_zones_chunks = 1024, /* 1024 entries * 64 bytes per entry = 64k byte transfer */
nr_zones_retrieved = 0,
nr_zones,
- offset,
log_len;
+ __u64 offset;
int total_nr_zones = 0;
struct nvme_zns_id_ns id_zns;
struct nvme_id_ns id_ns;
uint8_t lbaf;
__le64 zsze;
- struct json_object *zone_list = 0;
+ struct json_object *zone_list = NULL;
struct config {
char *output_format;
@@ -880,8 +881,8 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi
if (err)
return errno;
- flags = validate_output_format(cfg.output_format);
- if (flags < 0)
+ err = validate_output_format(cfg.output_format, &flags);
+ if (err < 0)
goto close_dev;
if (cfg.verbose)
flags |= VERBOSE;
@@ -949,7 +950,7 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi
log_len = sizeof(struct nvme_zone_report) + ((sizeof(struct nvme_zns_desc) * nr_zones_chunks) + (nr_zones_chunks * zdes));
report_size = log_len;
- report = nvme_alloc(report_size, &huge);
+ report = nvme_alloc_huge(report_size, &mh);
if (!report) {
perror("alloc");
err = -ENOMEM;
@@ -957,10 +958,8 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi
}
offset = cfg.zslba;
- if (flags & JSON)
- zone_list = json_create_array();
- else
- printf("nr_zones: %"PRIu64"\n", (uint64_t)le64_to_cpu(total_nr_zones));
+
+ nvme_zns_start_zone_list(total_nr_zones, &zone_list, flags);
while (nr_zones_retrieved < nr_zones) {
if (nr_zones_retrieved >= nr_zones)
@@ -989,15 +988,7 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi
offset = le64_to_cpu(report->entries[nr_zones_chunks-1].zslba) + zsze;
}
- if (flags & JSON) {
- struct print_ops *ops;
-
- ops = nvme_get_json_print_ops(flags);
- if (ops)
- ops->zns_finish_zone_list(total_nr_zones, zone_list);
- }
-
- nvme_free(report, huge);
+ nvme_zns_finish_zone_list(total_nr_zones, zone_list, flags);
free_buff:
free(buff);
@@ -1256,15 +1247,15 @@ static int changed_zone_list(int argc, char **argv, struct command *cmd, struct
if (err)
return errno;
- flags = validate_output_format(cfg.output_format);
- if (flags < 0)
- goto close_fd;
+ err = validate_output_format(cfg.output_format, &flags);
+ if (err < 0)
+ goto close_dev;
if (!cfg.namespace_id) {
err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
if (err < 0) {
perror("get-namespace-id");
- goto close_fd;
+ goto close_dev;
}
}
@@ -1277,7 +1268,7 @@ static int changed_zone_list(int argc, char **argv, struct command *cmd, struct
else
perror("zns changed-zone-list");
-close_fd:
+close_dev:
dev_close(dev);
return err;
}
diff --git a/plugins/zns/zns.h b/plugins/zns/zns.h
index 77bfdd6..43c4ecd 100644
--- a/plugins/zns/zns.h
+++ b/plugins/zns/zns.h
@@ -15,7 +15,7 @@ PLUGIN(NAME("zns", "Zoned Namespace Command Set", NVME_VERSION),
ENTRY("report-zones", "Report zones associated to a Zoned Namespace", report_zones)
ENTRY("reset-zone", "Reset one or more zones", reset_zone)
ENTRY("close-zone", "Close one or more zones", close_zone)
- ENTRY("finish-zone", "Finishe one or more zones", finish_zone)
+ ENTRY("finish-zone", "Finish one or more zones", finish_zone)
ENTRY("open-zone", "Open one or more zones", open_zone)
ENTRY("offline-zone", "Offline one or more zones", offline_zone)
ENTRY("set-zone-desc", "Attach zone descriptor extension data to a zone", set_zone_desc)