1
0
Fork 0

Merging upstream version 1.14.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-16 11:31:10 +01:00
parent 868b5312e8
commit d6fd2fdea9
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
305 changed files with 20664 additions and 6099 deletions

59
plugins/amzn/amzn-nvme.c Normal file
View file

@ -0,0 +1,59 @@
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>
#include "linux/nvme_ioctl.h"
#include "common.h"
#include "nvme.h"
#include "nvme-print.h"
#include "nvme-ioctl.h"
#include "plugin.h"
#include "argconfig.h"
#include "suffix.h"
#define CREATE_CMD
#include "amzn-nvme.h"
struct nvme_vu_id_ctrl_field {
__u8 bdev[32];
__u8 reserved0[992];
};
static void json_amzn_id_ctrl(struct nvme_vu_id_ctrl_field *id,
char *bdev,
struct json_object *root)
{
json_object_add_value_string(root, "bdev", bdev);
}
static void amzn_id_ctrl(__u8 *vs, struct json_object *root)
{
struct nvme_vu_id_ctrl_field* id = (struct nvme_vu_id_ctrl_field *)vs;
char bdev[32] = { 0 };
int len = 0;
while (len < 31) {
if (id->bdev[++len] == ' ') {
break;
}
}
snprintf(bdev, len+1, "%s", id->bdev);
if (root) {
json_amzn_id_ctrl(id, bdev, root);
return;
}
printf("bdev : %s\n", bdev);
}
static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
return __id_ctrl(argc, argv, cmd, plugin, amzn_id_ctrl);
}

17
plugins/amzn/amzn-nvme.h Normal file
View file

@ -0,0 +1,17 @@
#undef CMD_INC_FILE
#define CMD_INC_FILE plugins/amzn/amzn-nvme
#if !defined(AMZN_NVME) || defined(CMD_HEADER_MULTI_READ)
#define AMZN_NVME
#include "cmd.h"
PLUGIN(NAME("amzn", "Amazon vendor specific extensions"),
COMMAND_LIST(
ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl)
)
);
#endif
#include "define_cmd.h"

View file

@ -131,7 +131,8 @@ static int get_status(int argc, char **argv, struct command *cmd, struct plugin
if (fd < 0)
return fd;
err = nvme_get_log(fd, 0xffffffff, 0xc0, false, sizeof(log), &log);
err = nvme_get_log(fd, 0xffffffff, 0xc0, false, NVME_NO_LOG_LSP,
sizeof(log), &log);
if (err) {
goto exit;
}

View file

@ -32,7 +32,6 @@
#include "nvme-print.h"
#include "nvme-ioctl.h"
#include "plugin.h"
#include "json.h"
#include "argconfig.h"
#include "suffix.h"
@ -143,7 +142,7 @@ static void huawei_json_print_list_items(struct huawei_list_item *list_items,
unsigned len)
{
struct json_object *root;
struct json_array *devices;
struct json_object *devices;
struct json_object *device_attrs;
char formatter[128] = { 0 };
int index, i = 0;

View file

@ -11,7 +11,6 @@
#include "nvme.h"
#include "nvme-print.h"
#include "nvme-ioctl.h"
#include "json.h"
#include "plugin.h"
#include "argconfig.h"
@ -54,6 +53,13 @@ struct nvme_additional_smart_log {
struct nvme_additional_smart_log_item pll_lock_loss_cnt;
struct nvme_additional_smart_log_item nand_bytes_written;
struct nvme_additional_smart_log_item host_bytes_written;
struct nvme_additional_smart_log_item host_ctx_wear_used;
struct nvme_additional_smart_log_item perf_stat_indicator;
struct nvme_additional_smart_log_item re_alloc_sectr_cnt;
struct nvme_additional_smart_log_item soft_ecc_err_rate;
struct nvme_additional_smart_log_item unexp_power_loss;
struct nvme_additional_smart_log_item media_bytes_read;
struct nvme_additional_smart_log_item avail_fw_downgrades;
};
struct nvme_vu_id_ctrl_field { /* CDR MR5 */
@ -218,60 +224,118 @@ static void show_intel_smart_log_jsn(struct nvme_additional_smart_log *smart,
json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->host_bytes_written.raw));
json_object_add_value_object(dev_stats, "host_bytes_written", entry_stats);
entry_stats = json_create_object();
json_object_add_value_int(entry_stats, "normalized", smart->host_ctx_wear_used.norm);
json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->host_ctx_wear_used.raw));
json_object_add_value_object(dev_stats, "host_ctx_wear_used", entry_stats);
entry_stats = json_create_object();
json_object_add_value_int(entry_stats, "normalized", smart->perf_stat_indicator.norm);
json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->perf_stat_indicator.raw));
json_object_add_value_object(dev_stats, "perf_stat_indicator", entry_stats);
entry_stats = json_create_object();
json_object_add_value_int(entry_stats, "normalized", smart->re_alloc_sectr_cnt.norm);
json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->re_alloc_sectr_cnt.raw));
json_object_add_value_object(dev_stats, "re_alloc_sectr_cnt", entry_stats);
entry_stats = json_create_object();
json_object_add_value_int(entry_stats, "normalized", smart->soft_ecc_err_rate.norm);
json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->soft_ecc_err_rate.raw));
json_object_add_value_object(dev_stats, "soft_ecc_err_rate", entry_stats);
entry_stats = json_create_object();
json_object_add_value_int(entry_stats, "normalized", smart->unexp_power_loss.norm);
json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->unexp_power_loss.raw));
json_object_add_value_object(dev_stats, "unexp_power_loss", entry_stats);
entry_stats = json_create_object();
json_object_add_value_int(entry_stats, "normalized", smart->media_bytes_read.norm);
json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->media_bytes_read.raw));
json_object_add_value_object(dev_stats, "media_bytes_read", entry_stats);
entry_stats = json_create_object();
json_object_add_value_int(entry_stats, "normalized", smart->avail_fw_downgrades.norm);
json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->avail_fw_downgrades.raw));
json_object_add_value_object(dev_stats, "avail_fw_downgrades", entry_stats);
json_object_add_value_object(root, "Device stats", dev_stats);
json_print_object(root, NULL);
json_free_object(root);
}
static char *id_to_key(__u8 id)
{
switch (id) {
case 0xAB:
return "program_fail_count";
case 0xAC:
return "erase_fail_count";
case 0xAD:
return "wear_leveling_count";
case 0xB8:
return "e2e_error_detect_count";
case 0xC7:
return "crc_error_count";
case 0xE2:
return "media_wear_percentage";
case 0xE3:
return "host_reads";
case 0xE4:
return "timed_work_load";
case 0xEA:
return "thermal_throttle_status";
case 0xF0:
return "retry_buff_overflow_count";
case 0xF3:
return "pll_lock_loss_counter";
case 0xF4:
return "nand_bytes_written";
case 0xF5:
return "host_bytes_written";
case 0xF6:
return "host_context_wear_used";
case 0xF7:
return "performance_status_indicator";
case 0xF8:
return "media_bytes_read";
case 0xF9:
return "available_fw_downgrades";
case 0x05:
return "re-allocated_sector_count";
case 0x0D:
return "soft_ecc_error_rate";
case 0xAE:
return "unexpected_power_loss";
default:
return "Invalid ID";
}
}
static void print_intel_smart_log_items(struct nvme_additional_smart_log_item *item)
{
if (!item->key)
return;
printf("%#x %-45s %3d %"PRIu64"\n",
item->key, id_to_key(item->key),
item->norm, int48_to_long(item->raw));
}
static void show_intel_smart_log(struct nvme_additional_smart_log *smart,
unsigned int nsid, const char *devname)
{
struct nvme_additional_smart_log_item *iter = &smart->program_fail_cnt;
int num_items = sizeof(struct nvme_additional_smart_log) /
sizeof(struct nvme_additional_smart_log_item);
printf("Additional Smart Log for NVME device:%s namespace-id:%x\n",
devname, nsid);
printf("key normalized raw\n");
printf("program_fail_count : %3d%% %"PRIu64"\n",
smart->program_fail_cnt.norm,
int48_to_long(smart->program_fail_cnt.raw));
printf("erase_fail_count : %3d%% %"PRIu64"\n",
smart->erase_fail_cnt.norm,
int48_to_long(smart->erase_fail_cnt.raw));
printf("wear_leveling : %3d%% min: %u, max: %u, avg: %u\n",
smart->wear_leveling_cnt.norm,
le16_to_cpu(smart->wear_leveling_cnt.wear_level.min),
le16_to_cpu(smart->wear_leveling_cnt.wear_level.max),
le16_to_cpu(smart->wear_leveling_cnt.wear_level.avg));
printf("end_to_end_error_detection_count: %3d%% %"PRIu64"\n",
smart->e2e_err_cnt.norm,
int48_to_long(smart->e2e_err_cnt.raw));
printf("crc_error_count : %3d%% %"PRIu64"\n",
smart->crc_err_cnt.norm,
int48_to_long(smart->crc_err_cnt.raw));
printf("timed_workload_media_wear : %3d%% %.3f%%\n",
smart->timed_workload_media_wear.norm,
((float)int48_to_long(smart->timed_workload_media_wear.raw)) / 1024);
printf("timed_workload_host_reads : %3d%% %"PRIu64"%%\n",
smart->timed_workload_host_reads.norm,
int48_to_long(smart->timed_workload_host_reads.raw));
printf("timed_workload_timer : %3d%% %"PRIu64" min\n",
smart->timed_workload_timer.norm,
int48_to_long(smart->timed_workload_timer.raw));
printf("thermal_throttle_status : %3d%% %u%%, cnt: %u\n",
smart->thermal_throttle_status.norm,
smart->thermal_throttle_status.thermal_throttle.pct,
smart->thermal_throttle_status.thermal_throttle.count);
printf("retry_buffer_overflow_count : %3d%% %"PRIu64"\n",
smart->retry_buffer_overflow_cnt.norm,
int48_to_long(smart->retry_buffer_overflow_cnt.raw));
printf("pll_lock_loss_count : %3d%% %"PRIu64"\n",
smart->pll_lock_loss_cnt.norm,
int48_to_long(smart->pll_lock_loss_cnt.raw));
printf("nand_bytes_written : %3d%% sectors: %"PRIu64"\n",
smart->nand_bytes_written.norm,
int48_to_long(smart->nand_bytes_written.raw));
printf("host_bytes_written : %3d%% sectors: %"PRIu64"\n",
smart->host_bytes_written.norm,
int48_to_long(smart->host_bytes_written.raw));
printf("ID KEY Normalized Raw\n");
for (int i = 0; i < num_items; i++, iter++)
print_intel_smart_log_items(iter);
}
static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
@ -307,7 +371,7 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
return fd;
err = nvme_get_log(fd, cfg.namespace_id, 0xca, false,
sizeof(smart_log), &smart_log);
NVME_NO_LOG_LSP, sizeof(smart_log), &smart_log);
if (!err) {
if (cfg.json)
show_intel_smart_log_jsn(&smart_log, cfg.namespace_id, devicename);
@ -347,7 +411,7 @@ static int get_market_log(int argc, char **argv, struct command *cmd, struct plu
return fd;
err = nvme_get_log(fd, NVME_NSID_ALL, 0xdd, false,
sizeof(log), log);
NVME_NO_LOG_LSP, sizeof(log), log);
if (!err) {
if (!cfg.raw_binary)
printf("Intel Marketing Name Log:\n%s\n", log);
@ -409,7 +473,7 @@ static int get_temp_stats_log(int argc, char **argv, struct command *cmd, struct
return fd;
err = nvme_get_log(fd, NVME_NSID_ALL, 0xc5, false,
sizeof(stats), &stats);
NVME_NO_LOG_LSP, sizeof(stats), &stats);
if (!err) {
if (!cfg.raw_binary)
show_temp_stats(&stats);
@ -427,6 +491,28 @@ struct intel_lat_stats {
__u32 data[1216];
};
struct __attribute__((__packed__)) optane_lat_stats {
__u16 maj;
__u16 min;
__u64 data[9];
};
#define MEDIA_MAJOR_IDX 0
#define MEDIA_MINOR_IDX 1
#define MEDIA_MAX_LEN 2
#define OPTANE_V1000_BUCKET_LEN 8
static struct intel_lat_stats stats;
static struct optane_lat_stats v1000_stats;
struct v1000_thresholds {
__u32 read[OPTANE_V1000_BUCKET_LEN];
__u32 write[OPTANE_V1000_BUCKET_LEN];
};
static struct v1000_thresholds v1000_bucket;
static __u16 media_version[MEDIA_MAX_LEN] = {0};
enum FormatUnit {
US,
MS,
@ -536,6 +622,28 @@ static void show_lat_stats_bucket(struct intel_lat_stats *stats,
printf("%-*d\n", COL_WIDTH, stats->data[i]);
}
static void show_optane_lat_stats_bucket(struct optane_lat_stats *stats,
__u32 lower_us, enum inf_bound_type start_type,
__u32 upper_us, enum inf_bound_type end_type, int i)
{
enum FormatUnit fu = S;
char buffer[BUFSIZE];
init_buffer(buffer, BUFSIZE);
printf("%-*d", COL_WIDTH, i);
fu = get_seconds_magnitude(lower_us);
set_unit_string(buffer, lower_us, fu, start_type);
printf("%-*s", COL_WIDTH, buffer);
fu = get_seconds_magnitude(upper_us);
set_unit_string(buffer, upper_us, fu, end_type);
printf("%-*s", COL_WIDTH, buffer);
printf("%-*lu\n", COL_WIDTH, (long unsigned int)stats->data[i]);
}
static void show_lat_stats_linear(struct intel_lat_stats *stats,
__u32 start_offset, __u32 end_offset, __u32 bytes_per,
__u32 us_step, bool nonzero_print)
@ -622,6 +730,31 @@ static void json_add_bucket(struct intel_lat_stats *stats,
json_object_add_value_int(bucket, "value", val);
}
static void json_add_bucket_optane(struct json_object *bucket_list, __u32 id,
__u32 lower_us, enum inf_bound_type start_type,
__u32 upper_us, enum inf_bound_type end_type, __u32 val)
{
char buffer[BUFSIZE];
struct json_object *bucket = json_create_object();
init_buffer(buffer, BUFSIZE);
json_object_add_value_object(bucket_list,
"bucket", bucket);
json_object_add_value_int(bucket, "id", id);
set_unit_string(buffer, lower_us,
get_seconds_magnitude(lower_us), start_type);
json_object_add_value_string(bucket, "start", buffer);
set_unit_string(buffer, upper_us,
get_seconds_magnitude(upper_us), end_type);
json_object_add_value_string(bucket, "end", buffer);
json_object_add_value_uint(bucket, "value", val);
}
static void json_lat_stats_linear(struct intel_lat_stats *stats,
struct json_object *bucket_list, __u32 start_offset,
__u32 end_offset, __u32 bytes_per,
@ -714,32 +847,121 @@ static void show_lat_stats_4_0(struct intel_lat_stats *stats)
}
}
static void json_lat_stats(struct intel_lat_stats *stats, int write)
static void jason_lat_stats_v1000_0(struct optane_lat_stats *stats, int write)
{
switch (stats->maj) {
int i;
struct json_object *root = json_create_object();
struct json_object *bucket_list = json_create_object();
lat_stats_make_json_root(root, bucket_list, write);
if (write) {
for (i = 0; i < OPTANE_V1000_BUCKET_LEN - 1; i++)
json_add_bucket_optane(bucket_list, i,
v1000_bucket.write[i], NOINF,
v1000_bucket.write[i + 1] - 1,
NOINF,
stats->data[i]);
json_add_bucket_optane(bucket_list,
OPTANE_V1000_BUCKET_LEN - 1,
v1000_bucket.write[i],
NOINF,
v1000_bucket.write[i],
POSINF, stats->data[i]);
} else {
for (i = 0; i < OPTANE_V1000_BUCKET_LEN - 1; i++)
json_add_bucket_optane(bucket_list, i,
v1000_bucket.read[i], NOINF,
v1000_bucket.read[i + 1] - 1,
NOINF,
stats->data[i]);
json_add_bucket_optane(bucket_list,
OPTANE_V1000_BUCKET_LEN - 1,
v1000_bucket.read[i],
NOINF,
v1000_bucket.read[i],
POSINF, stats->data[i]);
}
struct json_object *subroot = json_create_object();
json_object_add_value_object(root, "Average latency since last reset", subroot);
json_object_add_value_uint(subroot, "value in us", stats->data[8]);
json_print_object(root, NULL);
json_free_object(root);
}
static void show_lat_stats_v1000_0(struct optane_lat_stats *stats, int write)
{
int i;
if (write) {
for (i = 0; i < OPTANE_V1000_BUCKET_LEN - 1; i++)
show_optane_lat_stats_bucket(stats,
v1000_bucket.write[i],
NOINF,
v1000_bucket.write[i + 1] -1,
NOINF, i);
show_optane_lat_stats_bucket(stats, v1000_bucket.write[i],
NOINF, v1000_bucket.write[i],
POSINF, i);
} else {
for (i = 0; i < OPTANE_V1000_BUCKET_LEN - 1; i++)
show_optane_lat_stats_bucket(stats,
v1000_bucket.read[i],
NOINF,
v1000_bucket.read[i + 1] -1,
NOINF, i);
show_optane_lat_stats_bucket(stats, v1000_bucket.read[i],
NOINF, v1000_bucket.read[i],
POSINF, i);
}
printf("Average latency since last reset: %lu us\n", (long unsigned int)stats->data[8]);
}
static void json_lat_stats(int write)
{
switch (media_version[MEDIA_MAJOR_IDX]) {
case 3:
json_lat_stats_3_0(stats, write);
json_lat_stats_3_0(&stats, write);
break;
case 4:
switch (stats->min) {
switch (media_version[MEDIA_MINOR_IDX]) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
json_lat_stats_4_0(stats, write);
json_lat_stats_4_0(&stats, write);
break;
default:
printf(("Unsupported minor revision (%u.%u)\n"
"Defaulting to format for rev4.0"),
stats->maj, stats->min);
printf("Unsupported minor revision (%u.%u)\n",
stats.maj, stats.min);
break;
}
break;
case 1000:
switch (media_version[MEDIA_MINOR_IDX]) {
case 0:
jason_lat_stats_v1000_0(&v1000_stats, write);
break;
default:
printf("Unsupported minor revision (%u.%u)\n",
stats.maj, stats.min);
break;
}
break;
default:
printf("Unsupported revision (%u.%u)\n",
stats->maj, stats->min);
stats.maj, stats.min);
break;
}
printf("\n");
@ -752,69 +974,79 @@ static void print_dash_separator(int count)
putchar('\n');
}
static void show_lat_stats(struct intel_lat_stats *stats, int write)
static void show_lat_stats(int write)
{
static const int separator_length = 50;
printf("Intel IO %s Command Latency Statistics\n",
write ? "Write" : "Read");
printf("Major Revision : %u\nMinor Revision : %u\n",
stats->maj, stats->min);
media_version[MEDIA_MAJOR_IDX], media_version[MEDIA_MINOR_IDX]);
print_dash_separator(separator_length);
printf("%-12s%-12s%-12s%-20s\n", "Bucket", "Start", "End", "Value");
print_dash_separator(separator_length);
switch (stats->maj) {
switch (media_version[MEDIA_MAJOR_IDX]) {
case 3:
show_lat_stats_3_0(stats);
show_lat_stats_3_0(&stats);
break;
case 4:
switch (stats->min) {
switch (media_version[MEDIA_MINOR_IDX]) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
show_lat_stats_4_0(stats);
show_lat_stats_4_0(&stats);
break;
default:
printf(("Unsupported minor revision (%u.%u)\n"
"Defaulting to format for rev4.0"),
stats->maj, stats->min);
printf("Unsupported minor revision (%u.%u)\n",
stats.maj, stats.min);
break;
}
break;
case 1000:
switch (media_version[MEDIA_MINOR_IDX]) {
case 0:
show_lat_stats_v1000_0(&v1000_stats, write);
break;
default:
printf("Unsupported minor revision (%u.%u)\n",
stats.maj, stats.min);
break;
}
break;
default:
printf("Unsupported revision (%u.%u)\n",
stats->maj, stats->min);
stats.maj, stats.min);
break;
}
}
static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
struct intel_lat_stats stats;
enum nvme_print_flags flags;
int err, fd;
const char *desc = "Get Intel Latency Statistics log and show it.";
const char *raw = "dump output in binary format";
const char *raw = "Dump output in binary format";
const char *json= "Dump output in json format";
const char *write = "Get write statistics (read default)";
struct config {
char *output_format;
int raw_binary;
int json;
int write;
};
struct config cfg = {
.output_format = "normal",
};
OPT_ARGS(opts) = {
OPT_FLAG("write", 'w', &cfg.write, write),
OPT_FMT("output-format", 'o', &cfg.output_format, "Output format: normal|json|binary"),
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
OPT_FLAG("write", 'w', &cfg.write, write),
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
OPT_FLAG("json", 'j', &cfg.json, json),
OPT_END()
};
@ -822,26 +1054,54 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct
if (fd < 0)
return fd;
err = flags = validate_output_format(cfg.output_format);
if (flags < 0)
/* Query maj and minor version first */
err = nvme_get_log(fd, NVME_NSID_ALL, cfg.write ? 0xc2 : 0xc1,
false, NVME_NO_LOG_LSP, sizeof(media_version),
media_version);
if (err)
goto close_fd;
if (cfg.raw_binary)
flags = BINARY;
if (media_version[0] == 1000) {
__u32 thresholds[OPTANE_V1000_BUCKET_LEN] = {0};
__u32 result;
err = nvme_get_feature(fd, 0, 0xf7, 0, cfg.write ? 0x1 : 0x0,
sizeof(thresholds), thresholds, &result);
if (err) {
fprintf(stderr, "Quering thresholds failed. NVMe Status:%s(%x)\n",
nvme_status_to_string(err), err);
goto close_fd;
}
/* Update bucket thresholds to be printed */
if (cfg.write) {
for (int i = 0; i < OPTANE_V1000_BUCKET_LEN; i++)
v1000_bucket.write[i] = thresholds[i];
} else {
for (int i = 0; i < OPTANE_V1000_BUCKET_LEN; i++)
v1000_bucket.read[i] = thresholds[i];
}
err = nvme_get_log(fd, NVME_NSID_ALL, cfg.write ? 0xc2 : 0xc1,
false, NVME_NO_LOG_LSP, sizeof(v1000_stats),
&v1000_stats);
} else {
err = nvme_get_log(fd, NVME_NSID_ALL, cfg.write ? 0xc2 : 0xc1,
false, NVME_NO_LOG_LSP, sizeof(stats),
&stats);
}
err = nvme_get_log(fd, NVME_NSID_ALL, cfg.write ? 0xc2 : 0xc1,
false, sizeof(stats), &stats);
if (!err) {
if (flags & JSON)
json_lat_stats(&stats, cfg.write);
else if (flags & BINARY)
d_raw((unsigned char *)&stats, sizeof(stats));
if (cfg.json)
json_lat_stats(cfg.write);
else if (!cfg.raw_binary)
show_lat_stats(cfg.write);
else
show_lat_stats(&stats, cfg.write);
d_raw((unsigned char *)&stats, sizeof(stats));
} else if (err > 0)
fprintf(stderr, "NVMe Status:%s(%x)\n",
nvme_status_to_string(err), err);
close_fd:
close(fd);
return err;
@ -1314,3 +1574,84 @@ static int enable_lat_stats_tracking(int argc, char **argv,
}
return fd;
}
static int set_lat_stats_thresholds(int argc, char **argv,
struct command *command, struct plugin *plugin)
{
int err, fd, num;
const char *desc = "Write Intel Bucket Thresholds for Latency Statistics Tracking";
const char *bucket_thresholds = "Bucket Threshold List, comma separated list: 0, 10, 20 ...";
const char *write = "Set write bucket Thresholds for latency tracking (read default)";
const __u32 nsid = 0;
const __u8 fid = 0xf7;
const __u32 cdw12 = 0x0;
const __u32 save = 0;
__u32 result;
struct config {
int write;
char *bucket_thresholds;
};
struct config cfg = {
.write = 0,
.bucket_thresholds = "",
};
OPT_ARGS(opts) = {
OPT_FLAG("write", 'w', &cfg.write, write),
OPT_LIST("bucket-thresholds", 't', &cfg.bucket_thresholds,
bucket_thresholds),
OPT_END()
};
fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0)
return fd;
/* Query maj and minor version first to figure out the amount of
* valid buckets a user is allowed to modify. Read or write doesn't
* matter
*/
err = nvme_get_log(fd, NVME_NSID_ALL, 0xc2,
false, NVME_NO_LOG_LSP, sizeof(media_version),
media_version);
if (err) {
fprintf(stderr, "Querying media version failed. NVMe Status:%s(%x)\n",
nvme_status_to_string(err), err);
goto close_fd;
}
if (media_version[0] == 1000) {
int thresholds[OPTANE_V1000_BUCKET_LEN] = {0};
num = argconfig_parse_comma_sep_array(cfg.bucket_thresholds,
thresholds,
sizeof(thresholds));
if (num == -1) {
fprintf(stderr, "ERROR: Bucket list is malformed\n");
goto close_fd;
}
err = nvme_set_feature(fd, nsid, fid, cfg.write ? 0x1 : 0x0,
cdw12, save, OPTANE_V1000_BUCKET_LEN,
thresholds, &result);
if (err > 0) {
fprintf(stderr, "NVMe Status:%s(%x)\n",
nvme_status_to_string(err), err);
} else if (err < 0) {
perror("Enable latency tracking");
fprintf(stderr, "Command failed while parsing.\n");
}
} else {
fprintf(stderr, "Unsupported command\n");
}
close_fd:
close(fd);
return err;
}

View file

@ -11,6 +11,7 @@ PLUGIN(NAME("intel", "Intel vendor specific extensions"),
ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl)
ENTRY("internal-log", "Retrieve Intel internal firmware log, save it", get_internal_log)
ENTRY("lat-stats", "Retrieve Intel IO Latency Statistics log, show it", get_lat_stats_log)
ENTRY("set-bucket-thresholds", "Set Latency Stats Bucket Values, save it", set_lat_stats_thresholds)
ENTRY("lat-stats-tracking", "Enable and disable Latency Statistics logging.", enable_lat_stats_tracking)
ENTRY("market-name", "Retrieve Intel Marketing Name log, show it", get_market_log)
ENTRY("smart-log-add", "Retrieve Intel SMART Log, show it", get_additional_smart_log)

View file

@ -3,6 +3,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include "linux/nvme_ioctl.h"
@ -19,9 +20,23 @@
#include "memblaze-utils.h"
enum {
MB_FEAT_POWER_MGMT = 0xc6,
// feature id
MB_FEAT_POWER_MGMT = 0x02,
MB_FEAT_HIGH_LATENCY = 0xE1,
// log id
GLP_ID_VU_GET_READ_LATENCY_HISTOGRAM = 0xC1,
GLP_ID_VU_GET_WRITE_LATENCY_HISTOGRAM = 0xC2,
GLP_ID_VU_GET_HIGH_LATENCY_LOG = 0xC3,
MB_FEAT_CLEAR_ERRORLOG = 0xF7,
};
#define LOG_PAGE_SIZE (0x1000)
#define DO_PRINT_FLAG (1)
#define NOT_PRINT_FLAG (0)
#define FID_C1_LOG_FILENAME "log_c1.csv"
#define FID_C2_LOG_FILENAME "log_c2.csv"
#define FID_C3_LOG_FILENAME "log_c3.csv"
/*
* Return -1 if @fw1 < @fw2
* Return 0 if @fw1 == @fw2
@ -53,18 +68,26 @@ static int compare_fw_version(const char *fw1, const char *fw2)
#define MEMBLAZE_FORMAT (0)
#define INTEL_FORMAT (1)
// 2.83 = raisin
#define IS_RAISIN(str) (!strcmp(str, "2.83"))
// 2.13 = papaya
#define IS_PAPAYA(str) (!strcmp(str, "2.13"))
#define STR_VER_SIZE 5
// 2.83 = raisin
#define IS_RAISIN(str) (!strcmp(str, "2.83"))
// 2.94 = kumquat
#define IS_KUMQUAT(str) (!strcmp(str, "2.94"))
// 0.60 = loquat
#define IS_LOQUAT(str) (!strcmp(str, "0.60"))
#define STR_VER_SIZE (5)
int getlogpage_format_type(char *fw_ver)
{
char fw_ver_local[STR_VER_SIZE];
strncpy(fw_ver_local, fw_ver, STR_VER_SIZE);
*(fw_ver_local + STR_VER_SIZE - 1) = '\0';
if ( IS_RAISIN(fw_ver_local) )
if ( IS_RAISIN(fw_ver_local)
|| IS_KUMQUAT(fw_ver_local)
|| IS_LOQUAT(fw_ver_local)
)
{
return INTEL_FORMAT;
}
@ -128,7 +151,7 @@ static __u64 raw_2_u64(const __u8 *buf, size_t len)
#define STR17_04 ", min: "
#define STR17_05 ", curr: "
#define STR18_01 "power_loss_protection"
#define STR19_01 "read_fail"
#define STR19_01 "read_fail_count"
#define STR20_01 "thermal_throttle_time"
#define STR21_01 "flash_media_error"
@ -380,7 +403,42 @@ static int show_memblaze_smart_log(int fd, __u32 nsid, const char *devname,
return err;
}
static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
int parse_params(char *str, int number, ...)
{
va_list argp;
int *param;
char *c;
int value;
va_start(argp, number);
while (number > 0) {
c = strtok(str, ",");
if ( c == NULL) {
printf("No enough parameters. abort...\n");
exit(EINVAL);
}
if (isalnum(*c) == 0) {
printf("%s is not a valid number\n", c);
return 1;
}
value = atoi(c);
param = va_arg(argp, int *);
*param = value;
if (str) {
str = strchr(str, ',');
if (str) { str++; }
}
number--;
}
va_end(argp);
return 0;
}
static int mb_get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
struct nvme_memblaze_smart_log smart_log;
int err, fd;
@ -408,7 +466,7 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
return fd;
err = nvme_get_log(fd, cfg.namespace_id, 0xca, false,
sizeof(smart_log), &smart_log);
NVME_NO_LOG_LSP, sizeof(smart_log), &smart_log);
if (!err) {
if (!cfg.raw_binary)
err = show_memblaze_smart_log(fd, cfg.namespace_id, devicename, &smart_log);
@ -423,213 +481,262 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
static char *mb_feature_to_string(int feature)
{
switch (feature) {
case MB_FEAT_POWER_MGMT: return "Memblaze power management";
default: return "Unknown";
}
switch (feature) {
case MB_FEAT_POWER_MGMT: return "Memblaze power management";
case MB_FEAT_HIGH_LATENCY: return "Memblaze high latency log";
case MB_FEAT_CLEAR_ERRORLOG: return "Memblaze clear error log";
default: return "Unknown";
}
}
static int get_additional_feature(int argc, char **argv, struct command *cmd, struct plugin *plugin)
static int mb_get_powermanager_status(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Read operating parameters of the "\
"specified controller. Operating parameters are grouped "\
"and identified by Feature Identifiers; each Feature "\
"Identifier contains one or more attributes that may affect "\
"behaviour of the feature. Each Feature has three possible "\
"settings: default, saveable, and current. If a Feature is "\
"saveable, it may be modified by set-feature. Default values "\
"are vendor-specific and not changeable. Use set-feature to "\
"change saveable Features.\n\n"\
"Available additional feature id:\n"\
"0xc6: Memblaze power management\n"\
" (value 0 - 25w, 1 - 20w, 2 - 15w)";
const char *raw = "show feature in binary format";
const char *namespace_id = "identifier of desired namespace";
const char *feature_id = "hexadecimal feature name";
const char *sel = "[0-3]: curr./default/saved/supp.";
const char *data_len = "buffer len (if) data is returned";
const char *cdw11 = "dword 11 for interrupt vector config";
const char *human_readable = "show infos in readable format";
int err, fd;
__u32 result;
void *buf = NULL;
const char *desc = "Get Memblaze power management ststus\n (value 0 - 25w, 1 - 20w, 2 - 15w)";
int err, fd;
__u32 result;
__u32 feature_id = MB_FEAT_POWER_MGMT;
struct config {
__u32 namespace_id;
__u32 feature_id;
__u8 sel;
__u32 cdw11;
__u32 data_len;
int raw_binary;
int human_readable;
};
OPT_ARGS(opts) = {
OPT_END()
};
struct config cfg = {
.namespace_id = 1,
.feature_id = 0,
.sel = 0,
.cdw11 = 0,
.data_len = 0,
};
fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0) return fd;
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
OPT_UINT("feature-id", 'f', &cfg.feature_id, feature_id),
OPT_BYTE("sel", 's', &cfg.sel, sel),
OPT_UINT("data-len", 'l', &cfg.data_len, data_len),
OPT_UINT("cdw11", 'c', &cfg.cdw11, cdw11),
OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable),
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
OPT_END()
};
fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0)
return fd;
if (cfg.sel > 7) {
fprintf(stderr, "invalid 'select' param:%d\n", cfg.sel);
return EINVAL;
}
if (!cfg.feature_id) {
fprintf(stderr, "feature-id required param\n");
return EINVAL;
}
if (cfg.data_len) {
if (posix_memalign(&buf, getpagesize(), cfg.data_len))
exit(ENOMEM);
memset(buf, 0, cfg.data_len);
}
err = nvme_get_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.sel, cfg.cdw11,
cfg.data_len, buf, &result);
if (!err) {
printf("get-feature:0x%02x (%s), %s value: %#08x\n", cfg.feature_id,
mb_feature_to_string(cfg.feature_id),
nvme_select_to_string(cfg.sel), result);
if (cfg.human_readable)
nvme_feature_show_fields(cfg.feature_id, result, buf);
else {
if (buf) {
if (!cfg.raw_binary)
d(buf, cfg.data_len, 16, 1);
else
d_raw(buf, cfg.data_len);
}
}
} else if (err > 0)
fprintf(stderr, "NVMe Status:%s(%x)\n",
nvme_status_to_string(err), err);
if (buf)
free(buf);
return err;
err = nvme_get_feature(fd, 0, feature_id, 0, 0, 0, NULL, &result);
if (err < 0) {
perror("get-feature");
}
if (!err) {
printf("get-feature:0x%02x (%s), %s value: %#08x\n", feature_id,
mb_feature_to_string(feature_id),
nvme_select_to_string(0), result);
} else if (err > 0)
fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
return err;
}
static int set_additional_feature(int argc, char **argv, struct command *cmd, struct plugin *plugin)
static int mb_set_powermanager_status(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Modify the saveable or changeable "\
"current operating parameters of the controller. Operating "\
"parameters are grouped and identified by Feature "\
"Identifiers. Feature settings can be applied to the entire "\
"controller and all associated namespaces, or to only a few "\
"namespace(s) associated with the controller. Default values "\
"for each Feature are vendor-specific and may not be modified."\
"Use get-feature to determine which Features are supported by "\
"the controller and are saveable/changeable.\n\n"\
"Available additional feature id:\n"\
"0xc6: Memblaze power management\n"\
" (value 0 - 25w, 1 - 20w, 2 - 15w)";
const char *namespace_id = "desired namespace";
const char *feature_id = "hex feature name (required)";
const char *data_len = "buffer length if data required";
const char *data = "optional file for feature data (default stdin)";
const char *value = "new value of feature (required)";
const char *save = "specifies that the controller shall save the attribute";
int err, fd;
__u32 result;
void *buf = NULL;
int ffd = STDIN_FILENO;
const char *desc = "Set Memblaze power management status\n (value 0 - 25w, 1 - 20w, 2 - 15w)";
const char *value = "new value of feature (required)";
const char *save = "specifies that the controller shall save the attribute";
int err, fd;
__u32 result;
struct config {
char *file;
__u32 namespace_id;
__u32 feature_id;
__u32 value;
__u32 data_len;
int save;
};
struct config {
__u32 feature_id;
__u32 value;
int save;
};
struct config cfg = {
.file = "",
.namespace_id = 0,
.feature_id = 0,
.value = 0,
.data_len = 0,
.save = 0,
};
struct config cfg = {
.feature_id = MB_FEAT_POWER_MGMT,
.value = 0,
.save = 0,
};
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
OPT_UINT("feature-id", 'f', &cfg.feature_id, feature_id),
OPT_UINT("value", 'v', &cfg.value, value),
OPT_UINT("data-len", 'l', &cfg.data_len, data_len),
OPT_FILE("data", 'd', &cfg.file, data),
OPT_FLAG("save", 's', &cfg.save, save),
OPT_END()
};
OPT_ARGS(opts) = {
OPT_UINT("value", 'v', &cfg.value, value),
OPT_FLAG("save", 's', &cfg.save, save),
OPT_END()
};
fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0)
return fd;
fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0) return fd;
if (!cfg.feature_id) {
fprintf(stderr, "feature-id required param\n");
return EINVAL;
}
err = nvme_set_feature(fd, 0, cfg.feature_id, cfg.value, 0, cfg.save, 0, NULL, &result);
if (err < 0) {
perror("set-feature");
}
if (!err) {
printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id,
mb_feature_to_string(cfg.feature_id), cfg.value);
} else if (err > 0)
fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
if (cfg.data_len) {
if (posix_memalign(&buf, getpagesize(), cfg.data_len))
exit(ENOMEM);
memset(buf, 0, cfg.data_len);
}
if (buf) {
if (strlen(cfg.file)) {
ffd = open(cfg.file, O_RDONLY);
if (ffd <= 0) {
fprintf(stderr, "no firmware file provided\n");
err = EINVAL;
goto free;
}
}
if (read(ffd, (void *)buf, cfg.data_len) < 0) {
fprintf(stderr, "failed to read data buffer from input file\n");
err = EINVAL;
goto free;
}
}
err = nvme_set_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.value,
0, cfg.save, cfg.data_len, buf, &result);
if (err < 0) {
perror("set-feature");
goto free;
}
if (!err) {
printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id,
mb_feature_to_string(cfg.feature_id), cfg.value);
if (buf)
d(buf, cfg.data_len, 16, 1);
} else if (err > 0)
fprintf(stderr, "NVMe Status:%s(%x)\n",
nvme_status_to_string(err), err);
free:
if (buf)
free(buf);
return err;
return err;
}
#define P2MIN (1)
#define P2MAX (5000)
#define MB_FEAT_HIGH_LATENCY_VALUE_SHIFT (15)
static int mb_set_high_latency_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Set Memblaze high latency log\n"\
" input parameter p1,p2\n"\
" p1 value: 0 is disable, 1 is enable\n"\
" p2 value: 1 .. 5000 ms";
const char *param = "input parameters";
int err, fd;
__u32 result;
int param1 = 0, param2 = 0;
struct config {
__u32 feature_id;
char * param;
__u32 value;
};
struct config cfg = {
.feature_id = MB_FEAT_HIGH_LATENCY,
.param = "0,0",
.value = 0,
};
OPT_ARGS(opts) = {
OPT_LIST("param", 'p', &cfg.param, param),
OPT_END()
};
fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0) return fd;
if (parse_params(cfg.param, 2, &param1, &param2)) {
printf("setfeature: invalid formats %s\n", cfg.param);
exit(EINVAL);
}
if ((param1 == 1) && (param2 < P2MIN || param2 > P2MAX)) {
printf("setfeature: invalid high io latency threshold %d\n", param2);
exit(EINVAL);
}
cfg.value = (param1 << MB_FEAT_HIGH_LATENCY_VALUE_SHIFT) | param2;
err = nvme_set_feature(fd, 0, cfg.feature_id, cfg.value, 0, 0, 0, NULL, &result);
if (err < 0) {
perror("set-feature");
}
if (!err) {
printf("set-feature:0x%02X (%s), value:%#08x\n", cfg.feature_id,
mb_feature_to_string(cfg.feature_id), cfg.value);
} else if (err > 0)
fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
return err;
}
static int glp_high_latency_show_bar(FILE *fdi, int print)
{
fPRINT_PARAM1("Memblaze High Latency Log\n");
fPRINT_PARAM1("---------------------------------------------------------------------------------------------\n");
fPRINT_PARAM1("Timestamp Type QID CID NSID StartLBA NumLBA Latency\n");
fPRINT_PARAM1("---------------------------------------------------------------------------------------------\n");
return 0;
}
/* High latency log page definiton
* Total 32 bytes
*/
typedef struct
{
__u8 port;
__u8 revision;
__u16 rsvd;
__u8 opcode;
__u8 sqe;
__u16 cid;
__u32 nsid;
__u32 latency;
__u64 sLBA;
__u16 numLBA;
__u16 timestampH;
__u32 timestampL;
} log_page_high_latency_t; /* total 32 bytes */
static int find_deadbeef(char *buf)
{
if (((*(buf + 0) & 0xff) == 0xef) && ((*(buf + 1) & 0xff) == 0xbe) && \
((*(buf + 2) & 0xff) == 0xad) && ((*(buf + 3) & 0xff) == 0xde))
{
return 1;
}
return 0;
}
#define TIME_STR_SIZE (44)
static int glp_high_latency(FILE *fdi, char *buf, int buflen, int print)
{
log_page_high_latency_t *logEntry;
char string[TIME_STR_SIZE];
int i, entrySize;
__u64 timestamp;
time_t tt = 0;
struct tm *t = NULL;
int millisec = 0;
if (find_deadbeef(buf)) return 0;
entrySize = sizeof(log_page_high_latency_t);
for (i = 0; i < buflen; i += entrySize)
{
logEntry = (log_page_high_latency_t *)(buf + i);
if (logEntry->latency == 0 && logEntry->revision == 0)
{
return 1;
}
if (0 == logEntry->timestampH) // generate host time string
{
snprintf(string, sizeof(string), "%d", logEntry->timestampL);
}
else // sort
{
timestamp = logEntry->timestampH - 1;
timestamp = timestamp << 32;
timestamp += logEntry->timestampL;
tt = timestamp / 1000;
millisec = timestamp % 1000;
t = gmtime(&tt);
snprintf(string, sizeof(string), "%4d%02d%02d--%02d:%02d:%02d.%03d UTC",
1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, millisec);
}
fprintf(fdi, "%-32s %-7x %-6x %-6x %-8x %4x%08x %-8x %-d\n",
string, logEntry->opcode, logEntry->sqe, logEntry->cid, logEntry->nsid,
(__u32)(logEntry->sLBA >> 32), (__u32)logEntry->sLBA, logEntry->numLBA, logEntry->latency);
if (print)
{
printf("%-32s %-7x %-6x %-6x %-8x %4x%08x %-8x %-d\n",
string, logEntry->opcode, logEntry->sqe, logEntry->cid, logEntry->nsid,
(__u32)(logEntry->sLBA >> 32), (__u32)logEntry->sLBA, logEntry->numLBA, logEntry->latency);
}
}
return 1;
}
static int mb_high_latency_log_print(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Get Memblaze high latency log";
int err, fd;
char buf[LOG_PAGE_SIZE];
FILE *fdi = NULL;
fdi = fopen(FID_C3_LOG_FILENAME, "w+");
OPT_ARGS(opts) = {
OPT_END()
};
fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0) return fd;
glp_high_latency_show_bar(fdi, DO_PRINT_FLAG);
err = nvme_get_log(fd, NVME_NSID_ALL, GLP_ID_VU_GET_HIGH_LATENCY_LOG, 0, NVME_NO_LOG_LSP, sizeof(buf), &buf);
while ( 1) {
if (!glp_high_latency(fdi, buf, LOG_PAGE_SIZE, DO_PRINT_FLAG)) break;
err = nvme_get_log(fd, NVME_NSID_ALL, GLP_ID_VU_GET_HIGH_LATENCY_LOG, 0, NVME_NO_LOG_LSP, sizeof(buf), &buf);
if ( err) {
fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
break;
}
}
if (NULL != fdi) fclose(fdi);
return err;
}
static int memblaze_fw_commit(int fd, int select)
{
struct nvme_admin_cmd cmd = {
@ -641,7 +748,7 @@ static int memblaze_fw_commit(int fd, int select)
return nvme_submit_admin_passthru(fd, &cmd);
}
static int memblaze_selective_download(int argc, char **argv, struct command *cmd, struct plugin *plugin)
static int mb_selective_download(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc =
"This performs a selective firmware download, which allows the user to "
@ -757,3 +864,287 @@ out:
return err;
}
static void ioLatencyHistogramOutput(FILE *fd, int index, int start, int end, char *unit0,
char *unit1, unsigned int *pHistogram, int print)
{
int len;
char string[64], subString0[12], subString1[12];
len = snprintf(subString0, sizeof(subString0), "%d%s", start, unit0);
if (end != 0x7FFFFFFF)
{
len = snprintf(subString1, sizeof(subString1), "%d%s", end, unit1);
}
else
{
len = snprintf(subString1, sizeof(subString1), "%s", "+INF");
}
len = snprintf(string, sizeof(string), "%-11d %-11s %-11s %-11u\n", index, subString0, subString1,
pHistogram[index]);
fwrite(string, 1, len, fd);
if (print)
{
printf("%s", string);
}
}
int io_latency_histogram(char *file, char *buf, int print, int logid)
{
FILE *fdi = fopen(file, "w+");
int i, index;
char unit[2][3];
unsigned int *revision = (unsigned int *)buf;
if (logid == GLP_ID_VU_GET_READ_LATENCY_HISTOGRAM)
{
fPRINT_PARAM1("Memblaze IO Read Command Latency Histogram\n");
}
else if (logid == GLP_ID_VU_GET_WRITE_LATENCY_HISTOGRAM)
{
fPRINT_PARAM1("Memblaze IO Write Command Latency Histogram\n");
}
fPRINT_PARAM2("Major Revision : %d\n", revision[1]);
fPRINT_PARAM2("Minor Revision : %d\n", revision[0]);
buf += 8;
if (revision[1] == 1 && revision[0] == 0)
{
fPRINT_PARAM1("--------------------------------------------------\n");
fPRINT_PARAM1("Bucket Start End Value \n");
fPRINT_PARAM1("--------------------------------------------------\n");
index = 0;
strcpy(unit[0], "us");
strcpy(unit[1], "us");
for (i = 0; i < 32; i++, index++)
{
if (i == 31)
{
strcpy(unit[1], "ms");
ioLatencyHistogramOutput(fdi, index, i * 32, 1, unit[0], unit[1], (unsigned int *)buf, print);
}
else
{
ioLatencyHistogramOutput(fdi, index, i * 32, (i + 1) * 32, unit[0], unit[1], (unsigned int *)buf,
print);
}
}
strcpy(unit[0], "ms");
strcpy(unit[1], "ms");
for (i = 1; i < 32; i++, index++)
{
ioLatencyHistogramOutput(fdi, index, i, i + 1, unit[0], unit[1], (unsigned int *)buf, print);
}
for (i = 1; i < 32; i++, index++)
{
if (i == 31)
{
strcpy(unit[1], "s");
ioLatencyHistogramOutput(fdi, index, i * 32, 1, unit[0], unit[1], (unsigned int *)buf, print);
}
else
{
ioLatencyHistogramOutput(fdi, index, i * 32, (i + 1) * 32, unit[0], unit[1], (unsigned int *)buf,
print);
}
}
strcpy(unit[0], "s");
strcpy(unit[1], "s");
for (i = 1; i < 4; i++, index++)
{
ioLatencyHistogramOutput(fdi, index, i, i + 1, unit[0], unit[1], (unsigned int *)buf, print);
}
ioLatencyHistogramOutput(fdi, index, i, 0x7FFFFFFF, unit[0], unit[1], (unsigned int *)buf, print);
}
else
{
fPRINT_PARAM1("Unsupported io latency histogram revision\n");
}
fclose(fdi);
return 1;
}
static int mb_lat_stats_log_print(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
char stats[LOG_PAGE_SIZE];
int err = 0;
int fd;
char f1[] = FID_C1_LOG_FILENAME;
char f2[] = FID_C2_LOG_FILENAME;
const char *desc = "Get Latency Statistics log and show it.";
const char *write = "Get write statistics (read default)";
struct config {
int write;
};
struct config cfg = {
.write = 0,
};
OPT_ARGS(opts) = {
OPT_FLAG("write", 'w', &cfg.write, write),
OPT_END()
};
fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0) return fd;
err = nvme_get_log(fd, NVME_NSID_ALL, cfg.write ? 0xc2 : 0xc1, false, NVME_NO_LOG_LSP, sizeof(stats), &stats);
if (!err)
io_latency_histogram(cfg.write ? f2 : f1, stats, DO_PRINT_FLAG,
cfg.write ? GLP_ID_VU_GET_WRITE_LATENCY_HISTOGRAM : GLP_ID_VU_GET_READ_LATENCY_HISTOGRAM);
else
fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
close(fd);
return err;
}
#define OP 0xFC
#define FID 0x68
static int memblaze_clear_error_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
int err, fd;
char *desc = "Clear Memblaze devices error log.";
//const char *value = "new value of feature (required)";
//const char *save = "specifies that the controller shall save the attribute";
__u32 result;
struct config {
__u32 feature_id;
__u32 value;
int save;
};
struct config cfg = {
.feature_id = 0xf7,
.value = 0x534d0001,
.save = 0,
};
OPT_ARGS(opts) = {
OPT_END()
};
fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0)
return fd;
err = nvme_set_feature(fd, 0, cfg.feature_id, cfg.value, 0, cfg.save, 0, NULL, &result);
if (err < 0) {
perror("set-feature");
}
if (!err) {
printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id, mb_feature_to_string(cfg.feature_id), cfg.value);
} else if (err > 0)
fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
/*
struct nvme_admin_cmd admin_cmd = {
.opcode = OP,
.cdw10 = FID,
};
err = nvme_submit_admin_passthru(fd, &admin_cmd);
if (!err) {
printf("OP(0x%2X) FID(0x%2X) Clear error log success.\n", OP, FID);
} else {
printf("NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
};
*/
return err;
}
static int mb_set_lat_stats(int argc, char **argv,
struct command *command, struct plugin *plugin)
{
int err, fd;
const char *desc = (
"Enable/Disable Latency Statistics Tracking.\n"
"No argument prints current status.");
const char *enable_desc = "Enable LST";
const char *disable_desc = "Disable LST";
const __u32 nsid = 0;
const __u8 fid = 0xe2;
const __u8 sel = 0;
const __u32 cdw11 = 0x0;
const __u32 cdw12 = 0x0;
const __u32 data_len = 32;
const __u32 save = 0;
__u32 result;
void *buf = NULL;
struct config {
bool enable, disable;
};
struct config cfg = {
.enable = false,
.disable = false,
};
const struct argconfig_commandline_options command_line_options[] = {
{"enable", 'e', "", CFG_NONE, &cfg.enable, no_argument, enable_desc},
{"disable", 'd', "", CFG_NONE, &cfg.disable, no_argument, disable_desc},
{NULL}
};
fd = parse_and_open(argc, argv, desc, command_line_options);
enum Option {
None = -1,
True = 1,
False = 0,
};
enum Option option = None;
if (cfg.enable && cfg.disable)
printf("Cannot enable and disable simultaneously.");
else if (cfg.enable || cfg.disable)
option = cfg.enable;
if (fd < 0)
return fd;
switch (option) {
case None:
err = nvme_get_feature(fd, nsid, fid, sel, cdw11, data_len, buf,
&result);
if (!err) {
printf(
"Latency Statistics Tracking (FID 0x%X) is currently (%i).\n",
fid, result);
} else {
printf("Could not read feature id 0xE2.\n");
return err;
}
break;
case True:
case False:
err = nvme_set_feature(fd, nsid, fid, option, cdw12, save,
data_len, buf, &result);
if (err > 0) {
fprintf(stderr, "NVMe Status:%s(%x)\n",
nvme_status_to_string(err), err);
} else if (err < 0) {
perror("Enable latency tracking");
fprintf(stderr, "Command failed while parsing.\n");
} else {
printf("Successfully set enable bit for FID (0x%X) to %i.\n",
fid, option);
}
break;
default:
printf("%d not supported.\n", option);
return EINVAL;
}
return fd;
}

View file

@ -14,10 +14,15 @@
PLUGIN(NAME("memblaze", "Memblaze vendor specific extensions"),
COMMAND_LIST(
ENTRY("smart-log-add", "Retrieve Memblaze SMART Log, show it", get_additional_smart_log)
ENTRY("get-feature-add", "Get Memblaze feature and show the resulting value", get_additional_feature)
ENTRY("set-feature-add", "Set a Memblaze feature and show the resulting value", set_additional_feature)
ENTRY("select-download", "Selective Firmware Download", memblaze_selective_download)
ENTRY("smart-log-add", "Retrieve Memblaze SMART Log, show it", mb_get_additional_smart_log)
ENTRY("get-pm-status", "Get Memblaze Power Manager Status", mb_get_powermanager_status)
ENTRY("set-pm-status", "Set Memblaze Power Manager Status", mb_set_powermanager_status)
ENTRY("select-download", "Selective Firmware Download", mb_selective_download)
ENTRY("lat-stats", "Enable and disable Latency Statistics logging", mb_set_lat_stats)
ENTRY("lat-stats-print", "Retrieve IO Latency Statistics log, show it", mb_lat_stats_log_print)
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)
)
);

View file

@ -160,5 +160,68 @@ struct nvme_p4_smart_log
u8 resv[SMART_INFO_NEW_SIZE - sizeof(struct nvme_p4_smart_log_item) * NR_SMART_ITEMS];
};
// base
#define DD do{ printf("=Memblaze= %s[%d]-%s():\n", __FILE__, __LINE__, __func__); }while(0)
#define DE(str) do{ printf("===ERROR!=== %s[%d]-%s():str=%s\n", __FILE__, __LINE__, __func__, \
str); }while(0)
// integer
#define DI(i) do{ printf("=Memblaze= %s[%d]-%s():int=%d\n", __FILE__, __LINE__, __func__, \
(int)i); } while(0)
#define DPI(prompt, i) do{ printf("=Memblaze= %s[%d]-%s():%s=%d\n", __FILE__, __LINE__, __func__, \
prompt, i); }while(0)
#define DAI(prompt, i, arr, max) do{ printf("=Memblaze= %s[%d]-%s():%s", __FILE__, __LINE__, __func__, prompt); \
for(i=0;i<max;i++) printf(" %d:%d", i, arr[i]); \
printf("\n"); }while(0)
// char
#define DC(c) do{ printf("=Memblaze= %s[%d]-%s():char=%c\n", __FILE__, __LINE__, __func__, c); \
}while(0)
#define DPC(prompt, c) do{ printf("=Memblaze= %s[%d]-%s():%s=%c\n", __FILE__, __LINE__, __func__, \
prompt, c); }while(0)
// address
#define DA(add) do{ printf("=Memblaze= %s[%d]-%s():address=0x%08X\n", __FILE__, __LINE__, \
__func__, add); }while(0)
#define DPA(prompt, add) do{ printf("=Memblaze= %s[%d]-%s():%s=0x%08X\n", __FILE__, __LINE__, __func__, \
prompt, add); }while(0)
// string
#define DS(str) do{ printf("=Memblaze= %s[%d]-%s():str=%s\n", __FILE__, __LINE__, __func__, str); \
}while(0)
#define DPS(prompt, str) do{ printf("=Memblaze= %s[%d]-%s():%s=%s\n", __FILE__, __LINE__, __func__, \
prompt, str); }while(0)
#define DAS(prompt, i, arr, max) do{ printf("=Memblaze= %s[%d]-%s():%s", __FILE__, __LINE__, __func__, prompt); \
for(i=0;i<max;i++) printf(" %d:%s", i, arr[i]); \
printf("\n"); }while(0)
// array
#define DR(str, k) do{ int ip; for(ip=0;ip<k;ip++) if(NULL != argv[ip]) \
printf("=Memblaze= %s[%d]-%s():%d=%s\n", \
__FILE__, __LINE__, __func__, ip, str[ip]); }while(0)
#define DARG do{ DPI("argc", argc); \
int ip; for(ip=0;ip<argc;ip++) if(NULL != argv[ip]) \
printf("=Memblaze= %s[%d]-%s():%d=%s\n", \
__FILE__, __LINE__, __func__, ip, argv[ip]); }while(0)
#define fPRINT_PARAM1(format) \
{ \
do \
{ \
fprintf(fdi, format);\
if (print) \
{ \
printf(format); \
} \
} while (0); \
}
#define fPRINT_PARAM2(format, value) \
{ \
do \
{ \
fprintf(fdi, format, value);\
if (print) \
{ \
printf(format, value); \
} \
} while (0); \
}
#endif // __MEMBLAZE_UTILS_H__

File diff suppressed because it is too large Load diff

View file

@ -12,7 +12,17 @@ PLUGIN(NAME("micron", "Micron vendor specific extensions"),
ENTRY("vs-pcie-stats", "Retrieve Micron PCIe error stats", micron_pcie_stats)
ENTRY("clear-pcie-correctable-errors", "Clear correctable PCIe errors", micron_clear_pcie_correctable_errors)
ENTRY("vs-internal-log", "Retrieve Micron logs", micron_internal_logs)
ENTRY("vs-telemetry-controller-option", "Enable/Disable controller telemetry log generation", micron_telemetry_cntrl_option)
ENTRY("vs-nand-stats", "Retrieve NAND Stats", micron_nand_stats)
ENTRY("vs-drive-info", "Retrieve Drive information", micron_drive_info)
ENTRY("plugin-version", "Display plugin version info", micron_plugin_version)
ENTRY("cloud-SSD-plugin-version", "Display plugin version info", micron_cloud_ssd_plugin_version)
ENTRY("log-page-directory", "Retrieve log page directory", micron_logpage_dir)
ENTRY("vs-fw-activate-history", "Display FW activation history", micron_fw_activation_history)
ENTRY("vs-error-reason-identifier", "Retrieve Error reason", micron_error_reason)
ENTRY("vs-smart-add-log", "Retrieve extended SMART data", micron_ocp_smart_health_logs)
ENTRY("clear-fw-activate-history", "Clear FW activation history", micron_clr_fw_activation_history)
ENTRY("vs-smbus-option", "Enable/Disable SMBUS on the drive", micron_smbus_option)
)
);

View file

@ -25,7 +25,6 @@
#include "nvme.h"
#include "nvme-ioctl.h"
#include "json.h"
#include "suffix.h"
@ -197,7 +196,7 @@ static void netapp_get_ontap_labels(char *vsname, char *nspath,
vol_name, "/", ns_name);
}
static void netapp_smdevice_json(struct json_array *devices, char *devname,
static void netapp_smdevice_json(struct json_object *devices, char *devname,
char *arrayname, char *volname, int nsid, char *nguid,
char *ctrl, char *astate, char *size, long long lba,
long long nsze)
@ -219,7 +218,7 @@ static void netapp_smdevice_json(struct json_array *devices, char *devname,
json_array_add_value_object(devices, device_attrs);
}
static void netapp_ontapdevice_json(struct json_array *devices, char *devname,
static void netapp_ontapdevice_json(struct json_object *devices, char *devname,
char *vsname, char *nspath, int nsid, char *uuid,
char *size, long long lba, long long nsze)
{
@ -241,7 +240,7 @@ static void netapp_ontapdevice_json(struct json_array *devices, char *devname,
static void netapp_smdevices_print(struct smdevice_info *devices, int count, int format)
{
struct json_object *root = NULL;
struct json_array *json_devices = NULL;
struct json_object *json_devices = NULL;
int i, slta;
char array_label[ARRAY_LABEL_LEN / 2 + 1];
char volume_label[VOLUME_LABEL_LEN / 2 + 1];
@ -266,7 +265,7 @@ static void netapp_smdevices_print(struct smdevice_info *devices, int count, int
else if (format == NJSON) {
/* prepare for json output */
root = json_create_object();
json_devices = json_create_array();
json_devices = json_create_object();
}
for (i = 0; i < count; i++) {
@ -304,7 +303,7 @@ static void netapp_ontapdevices_print(struct ontapdevice_info *devices,
int count, int format)
{
struct json_object *root = NULL;
struct json_array *json_devices = NULL;
struct json_object *json_devices = NULL;
char vsname[ONTAP_LABEL_LEN] = " ";
char nspath[ONTAP_NS_PATHLEN] = " ";
long long lba;
@ -332,7 +331,7 @@ static void netapp_ontapdevices_print(struct ontapdevice_info *devices,
} else if (format == NJSON) {
/* prepare for json output */
root = json_create_object();
json_devices = json_create_array();
json_devices = json_create_object();
}
for (i = 0; i < count; i++) {

View file

@ -0,0 +1,58 @@
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>
#include "linux/nvme_ioctl.h"
#include "common.h"
#include "nvme.h"
#include "nvme-print.h"
#include "nvme-ioctl.h"
#include "plugin.h"
#include "argconfig.h"
#include "suffix.h"
#define CREATE_CMD
#include "nvidia-nvme.h"
struct nvme_vu_id_ctrl_field {
__u16 json_rpc_2_0_mjr;
__u16 json_rpc_2_0_mnr;
__u16 json_rpc_2_0_ter;
__u8 reserved0[1018];
};
static void json_nvidia_id_ctrl(struct nvme_vu_id_ctrl_field *id,
char *json_rpc_2_0_ver, struct json_object *root)
{
json_object_add_value_string(root, "json_rpc_2_0_ver",
json_rpc_2_0_ver);
}
static void nvidia_id_ctrl(__u8 *vs, struct json_object *root)
{
struct nvme_vu_id_ctrl_field *id = (struct nvme_vu_id_ctrl_field *)vs;
char json_rpc_2_0_ver[16] = { 0 };
snprintf(json_rpc_2_0_ver, sizeof(json_rpc_2_0_ver), "0x%04x%04x%04x",
le16_to_cpu(id->json_rpc_2_0_mjr),
le16_to_cpu(id->json_rpc_2_0_mnr),
le16_to_cpu(id->json_rpc_2_0_ter));
if (root) {
json_nvidia_id_ctrl(id, json_rpc_2_0_ver, root);
return;
}
printf("json_rpc_2_0_ver : %s\n", json_rpc_2_0_ver);
}
static int id_ctrl(int argc, char **argv, struct command *cmd,
struct plugin *plugin)
{
return __id_ctrl(argc, argv, cmd, plugin, nvidia_id_ctrl);
}

View file

@ -0,0 +1,17 @@
#undef CMD_INC_FILE
#define CMD_INC_FILE plugins/nvidia/nvidia-nvme
#if !defined(NVIDIA_NVME) || defined(CMD_HEADER_MULTI_READ)
#define NVIDIA_NVME
#include "cmd.h"
PLUGIN(NAME("nvidia", "NVIDIA vendor specific extensions"),
COMMAND_LIST(
ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl)
)
);
#endif
#include "define_cmd.h"

View file

@ -8,6 +8,8 @@
#include <asm/byteorder.h>
#include <sys/ioctl.h>
#include <sys/sysinfo.h>
#include <sys/stat.h>
#include <unistd.h>
#include "linux/nvme_ioctl.h"
@ -15,7 +17,6 @@
#include "nvme-print.h"
#include "nvme-ioctl.h"
#include "nvme-status.h"
#include "json.h"
#include "plugin.h"
#include "argconfig.h"
@ -28,36 +29,40 @@
#define SECTOR_SHIFT 9
#define SFX_GET_FREESPACE _IOWR('N', 0x240, struct sfx_freespace_ctx)
#define IDEMA_CAP(exp_GB) (((__u64)exp_GB - 50ULL) * 1953504ULL + 97696368ULL)
#define NVME_IOCTL_CLR_CARD _IO('N', 0x47)
#define IDEMA_CAP(exp_GB) (((__u64)exp_GB - 50ULL) * 1953504ULL + 97696368ULL)
#define IDEMA_CAP2GB(exp_sector) (((__u64)exp_sector - 97696368ULL) / 1953504ULL + 50ULL)
enum {
SFX_LOG_LATENCY_READ_STATS = 0xc1,
SFX_LOG_SMART = 0xc2,
SFX_LOG_LATENCY_WRITE_STATS = 0xc3,
SFX_LOG_LATENCY_WRITE_STATS = 0xc3,
SFX_LOG_QUAL = 0xc4,
SFX_LOG_MISMATCHLBA = 0xc5,
SFX_LOG_MEDIA = 0xc6,
SFX_LOG_BBT = 0xc7,
SFX_LOG_IDENTIFY = 0xcc,
SFX_FEAT_ATOMIC = 0x01,
SFX_FEAT_UP_P_CAP = 0xac,
SFX_FEAT_CLR_CARD = 0xdc,
};
enum sfx_nvme_admin_opcode {
nvme_admin_query_cap_info = 0xd3,
nvme_admin_change_cap = 0xd4,
nvme_admin_sfx_set_features = 0xd5,
nvme_admin_sfx_get_features = 0xd6,
nvme_admin_sfx_set_features = 0xd5,
nvme_admin_sfx_get_features = 0xd6,
};
struct sfx_freespace_ctx
{
__u64 free_space;
__u64 phy_cap; /* physical capacity, in unit of sector */
__u64 phy_space; /* physical space considering OP, in unit of sector */
__u64 user_space; /* user required space, in unit of sector*/
__u64 hw_used; /* hw space used in 4K */
__u64 app_written; /* app data written in 4K */
__u64 phy_cap; /* physical capacity, in unit of sector */
__u64 phy_space; /* physical space considering OP, in unit of sector */
__u64 user_space; /* user required space, in unit of sector*/
__u64 hw_used; /* hw space used in 4K */
__u64 app_written; /* app data written in 4K */
};
struct nvme_capacity_info {
@ -66,7 +71,7 @@ struct nvme_capacity_info {
__u64 used_space;
__u64 free_space;
};
struct __attribute__((packed)) nvme_additional_smart_log_item {
struct __attribute__((packed)) nvme_additional_smart_log_item {
uint8_t key;
uint8_t _kp[2];
uint8_t norm;
@ -112,11 +117,10 @@ int nvme_change_cap(int fd, __u32 nsid, __u64 capacity)
struct nvme_admin_cmd cmd = {
.opcode = nvme_admin_change_cap,
.nsid = nsid,
.cdw10 = (capacity & 0xffffffff),
.cdw11 = (capacity >> 32),
.cdw10 = (capacity & 0xffffffff),
.cdw11 = (capacity >> 32),
};
return nvme_submit_passthru(fd, NVME_IOCTL_ADMIN_CMD,&cmd);
}
@ -267,65 +271,65 @@ static void show_sfx_smart_log(struct nvme_additional_smart_log *smart,
unsigned int nsid, const char *devname)
{
printf("Additional Smart Log for ScaleFlux device:%s namespace-id:%x\n",
devname, nsid);
printf("key normalized raw\n");
printf("program_fail_count : %3d%% %"PRIu64"\n",
smart->program_fail_cnt.norm,
int48_to_long(smart->program_fail_cnt.raw));
printf("erase_fail_count : %3d%% %"PRIu64"\n",
smart->erase_fail_cnt.norm,
int48_to_long(smart->erase_fail_cnt.raw));
printf("wear_leveling : %3d%% min: %u, max: %u, avg: %u\n",
smart->wear_leveling_cnt.norm,
le16_to_cpu(smart->wear_leveling_cnt.wear_level.min),
le16_to_cpu(smart->wear_leveling_cnt.wear_level.max),
le16_to_cpu(smart->wear_leveling_cnt.wear_level.avg));
printf("end_to_end_error_detection_count: %3d%% %"PRIu64"\n",
smart->e2e_err_cnt.norm,
int48_to_long(smart->e2e_err_cnt.raw));
printf("crc_error_count : %3d%% %"PRIu64"\n",
smart->crc_err_cnt.norm,
int48_to_long(smart->crc_err_cnt.raw));
printf("timed_workload_media_wear : %3d%% %.3f%%\n",
smart->timed_workload_media_wear.norm,
((float)int48_to_long(smart->timed_workload_media_wear.raw)) / 1024);
printf("timed_workload_host_reads : %3d%% %"PRIu64"%%\n",
smart->timed_workload_host_reads.norm,
int48_to_long(smart->timed_workload_host_reads.raw));
printf("timed_workload_timer : %3d%% %"PRIu64" min\n",
smart->timed_workload_timer.norm,
int48_to_long(smart->timed_workload_timer.raw));
printf("thermal_throttle_status : %3d%% %u%%, cnt: %u\n",
smart->thermal_throttle_status.norm,
smart->thermal_throttle_status.thermal_throttle.pct,
smart->thermal_throttle_status.thermal_throttle.count);
printf("retry_buffer_overflow_count : %3d%% %"PRIu64"\n",
smart->retry_buffer_overflow_cnt.norm,
int48_to_long(smart->retry_buffer_overflow_cnt.raw));
printf("pll_lock_loss_count : %3d%% %"PRIu64"\n",
smart->pll_lock_loss_cnt.norm,
int48_to_long(smart->pll_lock_loss_cnt.raw));
printf("nand_bytes_written : %3d%% sectors: %"PRIu64"\n",
smart->nand_bytes_written.norm,
int48_to_long(smart->nand_bytes_written.raw));
printf("host_bytes_written : %3d%% sectors: %"PRIu64"\n",
smart->host_bytes_written.norm,
int48_to_long(smart->host_bytes_written.raw));
printf("raid_recover_cnt : %3d%% %"PRIu64"\n",
smart->raid_recover_cnt.norm,
int48_to_long(smart->raid_recover_cnt.raw));
printf("read_ecc_cnt : %3d%% %"PRIu64"\n",
smart->read_ecc_cnt.norm,
int48_to_long(smart->read_ecc_cnt.raw));
printf("prog_timeout_cnt : %3d%% %"PRIu64"\n",
smart->prog_timeout_cnt.norm,
int48_to_long(smart->prog_timeout_cnt.raw));
printf("erase_timeout_cnt : %3d%% %"PRIu64"\n",
smart->erase_timeout_cnt.norm,
int48_to_long(smart->erase_timeout_cnt.raw));
printf("read_timeout_cnt : %3d%% %"PRIu64"\n",
smart->read_timeout_cnt.norm,
int48_to_long(smart->read_timeout_cnt.raw));
devname, nsid);
printf("key normalized raw\n");
printf("program_fail_count : %3d%% %"PRIu64"\n",
smart->program_fail_cnt.norm,
int48_to_long(smart->program_fail_cnt.raw));
printf("erase_fail_count : %3d%% %"PRIu64"\n",
smart->erase_fail_cnt.norm,
int48_to_long(smart->erase_fail_cnt.raw));
printf("wear_leveling : %3d%% min: %u, max: %u, avg: %u\n",
smart->wear_leveling_cnt.norm,
le16_to_cpu(smart->wear_leveling_cnt.wear_level.min),
le16_to_cpu(smart->wear_leveling_cnt.wear_level.max),
le16_to_cpu(smart->wear_leveling_cnt.wear_level.avg));
printf("end_to_end_error_detection_count: %3d%% %"PRIu64"\n",
smart->e2e_err_cnt.norm,
int48_to_long(smart->e2e_err_cnt.raw));
printf("crc_error_count : %3d%% %"PRIu64"\n",
smart->crc_err_cnt.norm,
int48_to_long(smart->crc_err_cnt.raw));
printf("timed_workload_media_wear : %3d%% %.3f%%\n",
smart->timed_workload_media_wear.norm,
((float)int48_to_long(smart->timed_workload_media_wear.raw)) / 1024);
printf("timed_workload_host_reads : %3d%% %"PRIu64"%%\n",
smart->timed_workload_host_reads.norm,
int48_to_long(smart->timed_workload_host_reads.raw));
printf("timed_workload_timer : %3d%% %"PRIu64" min\n",
smart->timed_workload_timer.norm,
int48_to_long(smart->timed_workload_timer.raw));
printf("thermal_throttle_status : %3d%% %u%%, cnt: %u\n",
smart->thermal_throttle_status.norm,
smart->thermal_throttle_status.thermal_throttle.pct,
smart->thermal_throttle_status.thermal_throttle.count);
printf("retry_buffer_overflow_count : %3d%% %"PRIu64"\n",
smart->retry_buffer_overflow_cnt.norm,
int48_to_long(smart->retry_buffer_overflow_cnt.raw));
printf("pll_lock_loss_count : %3d%% %"PRIu64"\n",
smart->pll_lock_loss_cnt.norm,
int48_to_long(smart->pll_lock_loss_cnt.raw));
printf("nand_bytes_written : %3d%% sectors: %"PRIu64"\n",
smart->nand_bytes_written.norm,
int48_to_long(smart->nand_bytes_written.raw));
printf("host_bytes_written : %3d%% sectors: %"PRIu64"\n",
smart->host_bytes_written.norm,
int48_to_long(smart->host_bytes_written.raw));
printf("raid_recover_cnt : %3d%% %"PRIu64"\n",
smart->raid_recover_cnt.norm,
int48_to_long(smart->raid_recover_cnt.raw));
printf("read_ecc_cnt : %3d%% %"PRIu64"\n",
smart->read_ecc_cnt.norm,
int48_to_long(smart->read_ecc_cnt.raw));
printf("prog_timeout_cnt : %3d%% %"PRIu64"\n",
smart->prog_timeout_cnt.norm,
int48_to_long(smart->prog_timeout_cnt.raw));
printf("erase_timeout_cnt : %3d%% %"PRIu64"\n",
smart->erase_timeout_cnt.norm,
int48_to_long(smart->erase_timeout_cnt.raw));
printf("read_timeout_cnt : %3d%% %"PRIu64"\n",
smart->read_timeout_cnt.norm,
int48_to_long(smart->read_timeout_cnt.raw));
}
static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
@ -357,8 +361,8 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
fd = parse_and_open(argc, argv, desc, opts);
err = nvme_get_log(fd, cfg.namespace_id, 0xca, false, sizeof(smart_log),
(void *)&smart_log);
err = nvme_get_log(fd, cfg.namespace_id, 0xca, false, NVME_NO_LOG_LSP,
sizeof(smart_log), (void *)&smart_log);
if (!err) {
if (cfg.json)
show_sfx_smart_log_jsn(&smart_log, cfg.namespace_id, devicename);
@ -373,7 +377,6 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
return err;
}
struct sfx_lat_stats {
__u16 maj;
__u16 min;
@ -440,7 +443,8 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct
fd = parse_and_open(argc, argv, desc, opts);
err = nvme_get_log(fd, 0xffffffff, cfg.write ? 0xc3 : 0xc1, false, sizeof(stats), (void *)&stats);
err = nvme_get_log(fd, 0xffffffff, cfg.write ? 0xc3 : 0xc1, false, NVME_NO_LOG_LSP,
sizeof(stats), (void *)&stats);
if (!err) {
if (!cfg.raw_binary)
show_lat_stats(&stats, cfg.write);
@ -448,7 +452,7 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct
d_raw((unsigned char *)&stats, sizeof(stats));
} else if (err > 0)
fprintf(stderr, "NVMe Status:%s(%x)\n",
nvme_status_to_string(err), err);
nvme_status_to_string(err), err);
return err;
}
@ -517,16 +521,16 @@ static void bd_table_show(unsigned char *bd_table, __u64 table_size)
bb_elem = (__u64 *)(bd_table + 5 * sizeof(__u32));
printf("Bad Block Table \n");
printf("MF_BB_COUNT: %u\n", mf_bb_count);
printf("GROWN_BB_COUNT: %u\n", grown_bb_count);
printf("TOTAL_BB_COUNT: %u\n", total_bb_count);
printf("REMAP_MFBB_COUNT: %u\n", remap_mfbb_count);
printf("REMAP_GBB_COUNT: %u\n", remap_gbb_count);
printf("MF_BB_COUNT: %u\n", mf_bb_count);
printf("GROWN_BB_COUNT: %u\n", grown_bb_count);
printf("TOTAL_BB_COUNT: %u\n", total_bb_count);
printf("REMAP_MFBB_COUNT: %u\n", remap_mfbb_count);
printf("REMAP_GBB_COUNT: %u\n", remap_gbb_count);
printf("REMAP_MFBB_TABLE [");
i = 0;
while (bb_elem < elem_end && i < remap_mfbb_count) {
printf(" 0x%llx", *(bb_elem++));
printf(" 0x%"PRIx64"", (uint64_t)*(bb_elem++));
i++;
}
printf(" ]\n");
@ -534,14 +538,14 @@ static void bd_table_show(unsigned char *bd_table, __u64 table_size)
printf("REMAP_GBB_TABLE [");
i = 0;
while (bb_elem < elem_end && i < remap_gbb_count) {
printf(" 0x%llx",*(bb_elem++));
printf(" 0x%"PRIx64"", (uint64_t)*(bb_elem++));
i++;
}
printf(" ]\n");
}
/**
* @brief "hooks of sfx get-bad-block"
* @brief "hooks of sfx get-bad-block"
*
* @param argc
* @param argv
@ -592,10 +596,16 @@ static int sfx_get_bad_block(int argc, char **argv, struct command *cmd, struct
static void show_cap_info(struct sfx_freespace_ctx *ctx)
{
printf("user sectors: %#llx\n", ctx->user_space);
printf("totl physical sectors: %#llx\n", ctx->phy_space);
printf("free physical sectors: %#llx\n", ctx->free_space);
printf("used physical sectors: %#llx\n", ctx->phy_space - ctx->free_space);
printf("logic capacity:%5lluGB(0x%"PRIx64")\n",
IDEMA_CAP2GB(ctx->user_space), (uint64_t)ctx->user_space);
printf("provisioned capacity:%5lluGB(0x%"PRIx64")\n",
IDEMA_CAP2GB(ctx->phy_space), (uint64_t)ctx->phy_space);
printf("free provisioned capacity:%5lluGB(0x%"PRIx64")\n",
IDEMA_CAP2GB(ctx->free_space), (uint64_t)ctx->free_space);
printf("used provisioned capacity:%5lluGB(0x%"PRIx64")\n",
IDEMA_CAP2GB(ctx->phy_space) - IDEMA_CAP2GB(ctx->free_space),
(uint64_t)(ctx->phy_space - ctx->free_space));
}
static int query_cap_info(int argc, char **argv, struct command *cmd, struct plugin *plugin)
@ -631,40 +641,92 @@ static int query_cap_info(int argc, char **argv, struct command *cmd, struct plu
return err;
}
static int change_cap_mem_check(int fd, __u64 trg_in_4k)
static int change_sanity_check(int fd, __u64 trg_in_4k, int *shrink)
{
struct sfx_freespace_ctx freespace_ctx = { 0 };
struct sysinfo s_info;
__u64 mem_need = 0;
__u64 cur_in_4k = 0;
__u64 provisoned_cap_4k = 0;
__u32 cnt_ms = 0;
int extend = 0;
while (ioctl(fd, SFX_GET_FREESPACE, &freespace_ctx)) {
if (cnt_ms++ > 600) {//1min
fprintf(stderr, "vu ioctl fail, errno %d\r\n", errno);
return -1;
}
usleep(100000);
}
/*
* capacity illegal check
*/
provisoned_cap_4k = freespace_ctx.phy_space >>
(SFX_PAGE_SHIFT - SECTOR_SHIFT);
if (trg_in_4k < provisoned_cap_4k ||
trg_in_4k > ((__u64)provisoned_cap_4k * 4)) {
fprintf(stderr,
"WARNING: Only support 1.0~4.0 x provisoned capacity!\n");
if (trg_in_4k < provisoned_cap_4k) {
fprintf(stderr,
"WARNING: The target capacity is less than 1.0 x provisioned capacity!\n");
} else {
fprintf(stderr,
"WARNING: The target capacity is larger than 4.0 x provisioned capacity!\n");
}
return -1;
}
if (trg_in_4k > ((__u64)provisoned_cap_4k*4)) {
fprintf(stderr, "WARNING: the target capacity is too large\n");
return -1;
}
/*
* check whether mem enough if extend
* */
cur_in_4k = freespace_ctx.user_space >> (SFX_PAGE_SHIFT - SECTOR_SHIFT);
if (cur_in_4k > trg_in_4k) {
extend = (cur_in_4k <= trg_in_4k);
if (extend) {
if (sysinfo(&s_info) < 0) {
printf("change-cap query mem info fail\n");
return -1;
}
mem_need = (trg_in_4k - cur_in_4k) * 8;
if (s_info.freeram <= 10 || mem_need > s_info.freeram) {
fprintf(stderr,
"WARNING: Free memory is not enough! "
"Please drop cache or extend more memory and retry\n"
"WARNING: Memory needed is %"PRIu64", free memory is %"PRIu64"\n",
(uint64_t)mem_need, (uint64_t)s_info.freeram);
return -1;
}
}
*shrink = !extend;
return 0;
}
/**
* @brief prompt and get user confirm input
*
* @param str, prompt string
*
* @return 0, cancled; 1 confirmed
*/
static int sfx_confirm_change(const char *str)
{
char confirm;
fprintf(stderr, "WARNING: %s.\n"
"Use the force [--force] option to suppress this warning.\n", str);
fprintf(stderr, "Confirm Y/y, Others cancel:\n");
confirm = fgetc(stdin);
if (confirm != 'y' && confirm != 'Y') {
fprintf(stderr, "Cancled.\n");
return 0;
}
if (sysinfo(&s_info) < 0) {
printf("change-cap query mem info fail\n");
return -1;
}
mem_need = (trg_in_4k - cur_in_4k) * 8;
if (s_info.freeram <= 10 || mem_need > s_info.freeram) {
fprintf(stderr, "WARNING: mem needed is %llu, free mem is %lu\n"
"Insufficient memory, please drop cache or add free memory and retry\n",
mem_need, s_info.freeram);
return -1;
}
return 0;
fprintf(stderr, "Sending operation ... \n");
return 1;
}
static int change_cap(int argc, char **argv, struct command *cmd, struct plugin *plugin)
@ -678,6 +740,8 @@ static int change_cap(int argc, char **argv, struct command *cmd, struct plugin
const char *force = "The \"I know what I'm doing\" flag, skip confirmation before sending command";
__u64 cap_in_4k = 0;
__u64 cap_in_sec = 0;
int shrink = 0;
struct config {
__u64 cap_in_byte;
__u32 capacity_in_gb;
@ -694,7 +758,7 @@ static int change_cap(int argc, char **argv, struct command *cmd, struct plugin
OPT_ARGS(opts) = {
OPT_UINT("cap", 'c', &cfg.capacity_in_gb, cap_gb),
OPT_UINT("cap-byte", 'z', &cfg.cap_in_byte, cap_byte),
OPT_SUFFIX("cap-byte", 'z', &cfg.cap_in_byte, cap_byte),
OPT_FLAG("force", 'f', &cfg.force, force),
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
OPT_FLAG("json", 'j', &cfg.json, json),
@ -706,22 +770,21 @@ static int change_cap(int argc, char **argv, struct command *cmd, struct plugin
return fd;
}
if (!cfg.force) {
fprintf(stderr, "WARNING: Changing capacity may irrevocably delete user data.\n"
"You have 10 seconds to press Ctrl-C to cancel this operation.\n\n"
"Use the force [--force|-f] option to suppress this warning.\n");
sleep(10);
fprintf(stderr, "Sending operation ... \n");
}
cap_in_sec = IDEMA_CAP(cfg.capacity_in_gb);
cap_in_4k = cap_in_sec >> 3;
if (cfg.cap_in_byte)
cap_in_4k = cfg.cap_in_byte >> 12;
printf("%dG %lluB %llu 4K\n",
cfg.capacity_in_gb, cfg.cap_in_byte, cap_in_4k);
if (change_cap_mem_check(fd, cap_in_4k))
printf("%dG %"PRIu64"B %"PRIu64" 4K\n",
cfg.capacity_in_gb, (uint64_t)cfg.cap_in_byte, (uint64_t)cap_in_4k);
if (change_sanity_check(fd, cap_in_4k, &shrink)) {
printf("ScaleFlux change-capacity: fail\n");
return err;
}
if (!cfg.force && shrink && !sfx_confirm_change("Changing Cap may irrevocably delete this device's data")) {
return 0;
}
err = nvme_change_cap(fd, 0xffffffff, cap_in_4k);
if (err < 0)
@ -731,20 +794,54 @@ static int change_cap(int argc, char **argv, struct command *cmd, struct plugin
nvme_status_to_string(err), err);
else {
printf("ScaleFlux change-capacity: success\n");
if(ioctl(fd, BLKRRPART) < 0) {
fprintf(stderr, "failed to re-read partition table\n");
err = EFAULT;
}
ioctl(fd, BLKRRPART);
}
return err;
}
static int sfx_verify_chr(int fd)
{
static struct stat nvme_stat;
int err = fstat(fd, &nvme_stat);
if (err < 0) {
perror("fstat");
return errno;
}
if (!S_ISCHR(nvme_stat.st_mode)) {
fprintf(stderr,
"Error: requesting clean card on non-controller handle\n");
return ENOTBLK;
}
return 0;
}
static int sfx_clean_card(int fd)
{
int ret;
ret = sfx_verify_chr(fd);
if (ret)
return ret;
ret = ioctl(fd, NVME_IOCTL_CLR_CARD);
if (ret)
perror("Ioctl Fail.");
else
printf("ScaleFlux clean card success\n");
return ret;
}
char *sfx_feature_to_string(int feature)
{
switch (feature) {
case SFX_FEAT_ATOMIC: return "ATOMIC";
case SFX_FEAT_ATOMIC:
return "ATOMIC";
case SFX_FEAT_UP_P_CAP:
return "UPDATE_PROVISION_CAPACITY";
default: return "Unknown";
default:
return "Unknown";
}
}
@ -752,27 +849,34 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl
{
int err = 0, fd;
char *desc = "ScaleFlux internal set features\n"
"feature id 1: ATOMIC";
"feature id 1: ATOMIC\n"
"value 0: Disable atomic write\n"
" 1: Enable atomic write";
const char *value = "new value of feature (required)";
const char *feature_id = "hex feature name (required)";
const char *namespace_id = "desired namespace";
const char *force = "The \"I know what I'm doing\" flag, skip confirmation before sending command";
struct nvme_id_ns ns;
struct config {
__u32 namespace_id;
__u32 feature_id;
__u32 value;
__u32 force;
};
struct config cfg = {
.namespace_id = 1,
.feature_id = 0,
.value = 0,
.force = 0,
};
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
OPT_UINT("feature-id", 'f', &cfg.feature_id, feature_id),
OPT_UINT("value", 'v', &cfg.value, value),
OPT_UINT("value", 'v', &cfg.value, value),
OPT_FLAG("force", 's', &cfg.force, force),
OPT_END()
};
@ -786,7 +890,17 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl
return EINVAL;
}
if (cfg.feature_id == SFX_FEAT_ATOMIC) {
if (cfg.feature_id == SFX_FEAT_CLR_CARD) {
/*Warning for clean card*/
if (!cfg.force && !sfx_confirm_change("Going to clean device's data, confirm umount fs and try again")) {
return 0;
} else {
return sfx_clean_card(fd);
}
}
if (cfg.feature_id == SFX_FEAT_ATOMIC && cfg.value != 0) {
if (cfg.namespace_id != 0xffffffff) {
err = nvme_identify_ns(fd, cfg.namespace_id, 0, &ns);
if (err) {
@ -806,14 +920,25 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl
return EFAULT;
}
}
} else if (cfg.feature_id == SFX_FEAT_UP_P_CAP) {
if (cfg.value <= 0) {
fprintf(stderr, "Invalid Param\n");
return EINVAL;
}
/*Warning for change pacp by GB*/
if (!cfg.force && !sfx_confirm_change("Changing physical capacity may irrevocably delete this device's data")) {
return 0;
}
}
err = nvme_sfx_set_features(fd, cfg.namespace_id, cfg.feature_id, cfg.value);
if (err < 0) {
perror("ScaleFlux-set-feature");
return errno;
} else if (!err) {
printf("ScaleFlux set-feature:%02x (%s), value:%#08x\n", cfg.feature_id,
printf("ScaleFlux set-feature:%#02x (%s), value:%d\n", cfg.feature_id,
sfx_feature_to_string(cfg.feature_id), cfg.value);
} else if (err > 0)
fprintf(stderr, "NVMe Status:%s(%x)\n",

View file

@ -14,12 +14,10 @@ PLUGIN(NAME("sfx", "ScaleFlux vendor specific extensions"),
ENTRY("query-cap", "Query current capacity info", query_cap_info)
ENTRY("change-cap", "Dynamic change capacity", change_cap)
ENTRY("set-feature", "Set a feature", sfx_set_feature)
ENTRY("get-feature", "get a feature", sfx_get_feature)
ENTRY("get-feature", "Get a feature", sfx_get_feature)
)
);
#endif
#include "define_cmd.h"

View file

@ -36,7 +36,6 @@
#include "plugin.h"
#include "argconfig.h"
#include "suffix.h"
#include "json.h"
#define CREATE_CMD
@ -132,7 +131,7 @@ static char *log_pages_supp_print(__u32 pageID)
static void json_log_pages_supp(log_page_map *logPageMap)
{
struct json_object *root;
struct json_array *logPages;
struct json_object *logPages;
__u32 i = 0;
root = json_create_object();
@ -177,7 +176,8 @@ static int log_pages_supp(int argc, char **argv, struct command *cmd,
};
fd = parse_and_open(argc, argv, desc, opts);
err = nvme_get_log(fd, 1, 0xc5, false, sizeof(logPageMap), &logPageMap);
err = nvme_get_log(fd, 1, 0xc5, false, NVME_NO_LOG_LSP,
sizeof(logPageMap), &logPageMap);
if (!err) {
if (strcmp(cfg.output_format,"json")) {
printf ("Seagate Supported Log-pages count :%d\n",
@ -312,7 +312,7 @@ static char *print_ext_smart_id(__u8 attrId)
return "RAIS_ECC_CORRECT_ERR_COUNT";
break;
case VS_ATTR_ID_UNCORRECTABLE_RAISE_ERRORS:
return "Uncorrectable read error count";/*VS_ATTR_ID_UNCORRECTABLE_RAISE_ERRORS*/
return "Uncorrectable RAISE error count";/*VS_ATTR_ID_UNCORRECTABLE_RAISE_ERRORS*/
break;
case VS_ATTR_ID_DRIVE_LIFE_PROTECTION_STATUS:
return "DRIVE_LIFE_PROTECTION_STATUS";
@ -493,7 +493,7 @@ static void json_print_smart_log(struct json_object *root,
EXTENDED_SMART_INFO_T *ExtdSMARTInfo )
{
/*struct json_object *root; */
struct json_array *lbafs;
struct json_object *lbafs;
int index = 0;
static __u64 lsbGbErased = 0, msbGbErased = 0, lsbLifWrtToFlash = 0, msbLifWrtToFlash = 0,
@ -650,7 +650,7 @@ static void json_print_smart_log_CF(struct json_object *root,
vendor_log_page_CF *pLogPageCF)
{
/*struct json_object *root;*/
struct json_array *logPages;
struct json_object *logPages;
unsigned int currentTemp, maxTemp;
char buf[40];
@ -715,11 +715,9 @@ static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugi
EXTENDED_SMART_INFO_T ExtdSMARTInfo;
vendor_log_page_CF logPageCF;
int fd;
struct json_object *root;
struct json_array *lbafs;
struct json_object *root = json_create_object();
struct json_object *lbafs = json_create_array();
struct json_object *lbafs_ExtSmart, *lbafs_DramSmart;
root = json_create_object();
lbafs = json_create_array();
const char *desc = "Retrieve Seagate Extended SMART information for the given device ";
const char *output_format = "output in binary format";
@ -741,7 +739,8 @@ static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugi
if (strcmp(cfg.output_format,"json"))
printf("Seagate Extended SMART Information :\n");
err = nvme_get_log(fd, 1, 0xC4, false, sizeof(ExtdSMARTInfo), &ExtdSMARTInfo);
err = nvme_get_log(fd, 1, 0xC4, false, NVME_NO_LOG_LSP,
sizeof(ExtdSMARTInfo), &ExtdSMARTInfo);
if (!err) {
if (strcmp(cfg.output_format,"json")) {
printf("%-39s %-15s %-19s \n", "Description", "Ext-Smart-Id", "Ext-Smart-Value");
@ -763,7 +762,8 @@ static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugi
* Next get Log Page 0xCF
*/
err = nvme_get_log(fd, 1, 0xCF, false, sizeof(logPageCF), &logPageCF);
err = nvme_get_log(fd, 1, 0xCF, false, NVME_NO_LOG_LSP,
sizeof(logPageCF), &logPageCF);
if (!err) {
if(strcmp(cfg.output_format,"json")) {
/*printf("Seagate DRAM Supercap SMART Attributes :\n");*/
@ -860,7 +860,8 @@ static int temp_stats(int argc, char **argv, struct command *cmd, struct plugin
}
/* STEP-2 : Get Max temperature form Ext SMART-id 194 */
err = nvme_get_log(fd, 1, 0xC4, false, sizeof(ExtdSMARTInfo), &ExtdSMARTInfo);
err = nvme_get_log(fd, 1, 0xC4, false, NVME_NO_LOG_LSP,
sizeof(ExtdSMARTInfo), &ExtdSMARTInfo);
if (!err) {
for(index = 0; index < NUMBER_EXTENDED_SMART_ATTRIBUTES; index++) {
if (ExtdSMARTInfo.vendorData[index].AttributeNumber == VS_ATTR_ID_MAX_LIFE_TEMPERATURE) {
@ -882,7 +883,8 @@ static int temp_stats(int argc, char **argv, struct command *cmd, struct plugin
fprintf(stderr, "NVMe Status:%s(%x)\n",
nvme_status_to_string(err), err);
cf_err = nvme_get_log(fd, 1, 0xCF, false, sizeof(ExtdSMARTInfo), &logPageCF);
cf_err = nvme_get_log(fd, 1, 0xCF, false, NVME_NO_LOG_LSP,
sizeof(ExtdSMARTInfo), &logPageCF);
if(!cf_err) {
scCurrentTemp = logPageCF.AttrCF.SuperCapCurrentTemperature;
@ -1011,7 +1013,8 @@ static int vs_pcie_error_log(int argc, char **argv, struct command *cmd, struct
if(strcmp(cfg.output_format,"json"))
printf("Seagate PCIe error counters Information :\n");
err = nvme_get_log(fd, 1, 0xCB, false, sizeof(pcieErrorLog), &pcieErrorLog);
err = nvme_get_log(fd, 1, 0xCB, false, NVME_NO_LOG_LSP,
sizeof(pcieErrorLog), &pcieErrorLog);
if (!err) {
if(strcmp(cfg.output_format,"json")) {
print_vs_pcie_error_log(pcieErrorLog);

View file

@ -11,7 +11,6 @@
#include "nvme.h"
#include "nvme-print.h"
#include "nvme-ioctl.h"
#include "json.h"
#include "plugin.h"
#include "argconfig.h"
@ -143,7 +142,7 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
fd = parse_and_open(argc, argv, desc, opts);
err = nvme_get_log(fd, cfg.namespace_id, 0xca, false,
sizeof(smart_log), &smart_log);
NVME_NO_LOG_LSP, sizeof(smart_log), &smart_log);
if (!err) {
if (!cfg.raw_binary)
show_shannon_smart_log(&smart_log, cfg.namespace_id, devicename);
@ -182,7 +181,7 @@ static int get_additional_feature(int argc, char **argv, struct command *cmd, st
struct config {
__u32 namespace_id;
__u32 feature_id;
enum nvme_feat feature_id;
__u8 sel;
__u32 cdw11;
__u32 data_len;
@ -192,7 +191,7 @@ static int get_additional_feature(int argc, char **argv, struct command *cmd, st
struct config cfg = {
.namespace_id = 1,
.feature_id = 0,
.feature_id = NVME_FEAT_NONE,
.sel = 0,
.cdw11 = 0,
.data_len = 0,

View file

@ -393,7 +393,7 @@ static int nvme_get_vendor_log(int fd, __u32 namespace_id, int log_page,
goto end;
}
err = nvme_get_log(fd, namespace_id, log_page, false,
log_len, log);
NVME_NO_LOG_LSP, log_len, log);
if (err) {
fprintf(stderr, "%s: couldn't get log 0x%x\n", __func__,
log_page);

View file

@ -633,7 +633,7 @@ static void vt_parse_detail_identify(const struct nvme_id_ctrl *ctrl)
const char *VWCtable[2] = {"0 = a volatile write cache is not present",
"1 = a volatile write cache is present"};
const char *NVSCCtable[2] = {"0 = the format of all NVM Vendor Specific Commands are vendor specific",
const char *ICSVSCCtable[2] = {"0 = the format of all NVM Vendor Specific Commands are vendor specific",
"1 = all NVM Vendor Specific Commands use the format defined in NVM Express specification"};
const char *SGLSSubtable[4] = {"00b = SGLs are not supported",
@ -883,11 +883,11 @@ static void vt_parse_detail_identify(const struct nvme_id_ctrl *ctrl)
vt_convert_data_buffer_to_hex_string(&buf[528], 2, true, s);
printf(" \"Atomic Write Unit Power Fail\":\"%sh\",\n", s);
temp = ctrl->nvscc;
temp = ctrl->icsvscc;
printf(" \"NVM Vendor Specific Command Configuration\":{\n");
vt_convert_data_buffer_to_hex_string(&buf[530], 1, true, s);
printf(" \"Value\":\"%sh\",\n", s);
vt_build_identify_lv2(temp, 0, 1, NVSCCtable, true);
vt_build_identify_lv2(temp, 0, 1, ICSVSCCtable, true);
vt_convert_data_buffer_to_hex_string(&buf[532], 2, true, s);
printf(" \"Atomic Compare 0 Write Unit\":\"%sh\",\n", s);

File diff suppressed because it is too large Load diff

View file

@ -25,11 +25,16 @@ PLUGIN(NAME("wdc", "Western Digital vendor specific extensions"),
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("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-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)
)
);

View file

@ -144,3 +144,18 @@ int wdc_UtilsStrCompare(char *pcSrc, char *pcDst)
return *pcSrc - *pcDst;
}
void wdc_StrFormat(char *formatter, size_t fmt_sz, char *tofmt, size_t tofmtsz)
{
fmt_sz = snprintf(formatter,fmt_sz, "%-*.*s",
(int)tofmtsz, (int)tofmtsz, tofmt);
/* trim() the obnoxious trailing white lines */
while (fmt_sz) {
if (formatter[fmt_sz - 1] != ' ' && formatter[fmt_sz - 1] != '\0') {
formatter[fmt_sz] = '\0';
break;
}
fmt_sz--;
}
}

View file

@ -74,4 +74,5 @@ int wdc_UtilsGetTime(PUtilsTimeInfo timeInfo);
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);

148
plugins/ymtc/ymtc-nvme.c Normal file
View file

@ -0,0 +1,148 @@
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "linux/nvme_ioctl.h"
#include "nvme.h"
#include "nvme-print.h"
#include "nvme-ioctl.h"
#include "plugin.h"
#include "argconfig.h"
#include "suffix.h"
#define CREATE_CMD
#include "ymtc-nvme.h"
#include "ymtc-utils.h"
static void get_ymtc_smart_info(struct nvme_ymtc_smart_log *smart, int index, u8 *nm_val, u8 *raw_val)
{
memcpy(nm_val, smart->itemArr[index].nmVal, NM_SIZE);
memcpy(raw_val, smart->itemArr[index].rawVal, RAW_SIZE);
}
static int show_ymtc_smart_log(int fd, __u32 nsid, const char *devname,
struct nvme_ymtc_smart_log *smart)
{
struct nvme_id_ctrl ctrl;
char fw_ver[10];
int err = 0;
u8 *nm = malloc(NM_SIZE * sizeof(u8));
u8 *raw = malloc(RAW_SIZE * sizeof(u8));
err = nvme_identify_ctrl(fd, &ctrl);
if (err)
return err;
snprintf(fw_ver, sizeof(fw_ver), "%c.%c%c.%c%c%c%c",
ctrl.fr[0], ctrl.fr[1], ctrl.fr[2], ctrl.fr[3],
ctrl.fr[4], ctrl.fr[5], ctrl.fr[6]);
/* Table Title */
printf("Additional Smart Log for NVME device:%s namespace-id:%x\n", devname, nsid);
/* Clumn Name*/
printf("key normalized raw\n");
/* 00 SI_VD_PROGRAM_FAIL */
get_ymtc_smart_info(smart, SI_VD_PROGRAM_FAIL, nm, raw);
printf("program_fail_count : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw));
/* 01 SI_VD_ERASE_FAIL */
get_ymtc_smart_info(smart, SI_VD_ERASE_FAIL, nm, raw);
printf("erase_fail_count : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw));
/* 02 SI_VD_WEARLEVELING_COUNT */
get_ymtc_smart_info(smart, SI_VD_WEARLEVELING_COUNT, nm, raw);
printf("wear_leveling : %3d%% min: %u, max: %u, avg: %u\n", *nm,
*raw, *(raw+2), *(raw+4));
/* 03 SI_VD_E2E_DECTECTION_COUNT */
get_ymtc_smart_info(smart, SI_VD_E2E_DECTECTION_COUNT, nm, raw);
printf("end_to_end_error_detection_count: %3d%% %"PRIu64"\n", *nm, int48_to_long(raw));
/* 04 SI_VD_PCIE_CRC_ERR_COUNT */
get_ymtc_smart_info(smart, SI_VD_PCIE_CRC_ERR_COUNT, nm, raw);
printf("crc_error_count : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw));
/* 08 SI_VD_THERMAL_THROTTLE_STATUS */
get_ymtc_smart_info(smart, SI_VD_THERMAL_THROTTLE_STATUS, nm, raw);
printf("thermal_throttle_status : %3d%% %"PRIu64"%%, cnt: %"PRIu64"\n", *nm,
int48_to_long(raw), int48_to_long(raw+1));
/* 11 SI_VD_TOTAL_WRITE */
get_ymtc_smart_info(smart, SI_VD_TOTAL_WRITE, nm, raw);
printf("nand_bytes_written : %3d%% sectors: %"PRIu64"\n", *nm, int48_to_long(raw));
/* 12 SI_VD_HOST_WRITE */
get_ymtc_smart_info(smart, SI_VD_HOST_WRITE, nm, raw);
printf("host_bytes_written : %3d%% sectors: %"PRIu64"\n", *nm, int48_to_long(raw));
/* 14 SI_VD_TOTAL_READ */
get_ymtc_smart_info(smart, SI_VD_TOTAL_READ, nm, raw);
printf("nand_bytes_read : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw));
/* 15 SI_VD_TEMPT_SINCE_BORN */
get_ymtc_smart_info(smart, SI_VD_TEMPT_SINCE_BORN, nm, raw);
printf("tempt_since_born : %3d%% max: %u, min: %u, curr: %u\n", *nm,
*raw, *(raw+2), *(raw+4));
/* 16 SI_VD_POWER_CONSUMPTION */
get_ymtc_smart_info(smart, SI_VD_POWER_CONSUMPTION, nm, raw);
printf("power_consumption : %3d%% max: %u, min: %u, curr: %u\n", *nm,
*raw, *(raw+2), *(raw+4));
/* 17 SI_VD_TEMPT_SINCE_BOOTUP */
get_ymtc_smart_info(smart, SI_VD_TEMPT_SINCE_BOOTUP, nm, raw);
printf("tempt_since_bootup : %3d%% max: %u, min: %u, curr: %u\n", *nm, *raw,
*(raw+2), *(raw+4));
/* 18 SI_VD_POWER_LOSS_PROTECTION */
get_ymtc_smart_info(smart, SI_VD_POWER_LOSS_PROTECTION, nm, raw);
printf("power_loss_protection : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw));
/* 19 SI_VD_READ_FAIL */
get_ymtc_smart_info(smart, SI_VD_READ_FAIL, nm, raw);
printf("read_fail : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw));
/* 20 SI_VD_THERMAL_THROTTLE_TIME */
get_ymtc_smart_info(smart, SI_VD_THERMAL_THROTTLE_TIME, nm, raw);
printf("thermal_throttle_time : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw));
/* 21 SI_VD_FLASH_MEDIA_ERROR */
get_ymtc_smart_info(smart, SI_VD_FLASH_MEDIA_ERROR, nm, raw);
printf("flash_error_media_count : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw));
free(nm);
free(raw);
return err;
}
static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
struct nvme_ymtc_smart_log smart_log;
int err, fd;
char *desc = "Get Ymtc vendor specific additional smart log (optionally, "\
"for the specified namespace), and show it.";
const char *namespace = "(optional) desired namespace";
const char *raw = "dump output in binary format";
struct config {
__u32 namespace_id;
int raw_binary;
};
struct config cfg = {
.namespace_id = NVME_NSID_ALL,
};
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace),
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
OPT_END()
};
fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0)
return fd;
err = nvme_get_log(fd, cfg.namespace_id, 0xca, false,
NVME_NO_LOG_LSP, sizeof(smart_log), &smart_log);
if (!err) {
if (!cfg.raw_binary)
err = show_ymtc_smart_log(fd, cfg.namespace_id, devicename, &smart_log);
else
d_raw((unsigned char *)&smart_log, sizeof(smart_log));
}
if (err > 0)
fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
return err;
}

24
plugins/ymtc/ymtc-nvme.h Normal file
View file

@ -0,0 +1,24 @@
#undef CMD_INC_FILE
#define CMD_INC_FILE plugins/ymtc/ymtc-nvme
#if !defined(YMTC_NVME) || defined(CMD_HEADER_MULTI_READ)
#define YMTC_NVME
#include "cmd.h"
#include "common.h"
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
PLUGIN(NAME("ymtc", "Ymtc vendor specific extensions"),
COMMAND_LIST(
ENTRY("smart-log-add", "Retrieve Ymtc SMART Log, show it", get_additional_smart_log)
)
);
#endif
#include "define_cmd.h"

80
plugins/ymtc/ymtc-utils.h Normal file
View file

@ -0,0 +1,80 @@
#ifndef __YMTC_UTILS_H__
#define __YMTC_UTILS_H__
#define SMART_INFO_SIZE 4096
#define ID_SIZE 3
#define NM_SIZE 2
#define RAW_SIZE 7
typedef unsigned char u8;
/* Additional smart external ID */
#define SI_VD_PROGRAM_FAIL_ID 0xAB
#define SI_VD_ERASE_FAIL_ID 0xAC
#define SI_VD_WEARLEVELING_COUNT_ID 0xAD
#define SI_VD_E2E_DECTECTION_COUNT_ID 0xB8
#define SI_VD_PCIE_CRC_ERR_COUNT_ID 0xC7
#define SI_VD_TIMED_WORKLOAD_MEDIA_WEAR_ID 0xE2
#define SI_VD_TIMED_WORKLOAD_HOST_READ_ID 0xE3
#define SI_VD_TIMED_WORKLOAD_TIMER_ID 0xE4
#define SI_VD_THERMAL_THROTTLE_STATUS_ID 0xEA
#define SI_VD_RETRY_BUFF_OVERFLOW_COUNT_ID 0xF0
#define SI_VD_PLL_LOCK_LOSS_COUNT_ID 0xF3
#define SI_VD_TOTAL_WRITE_ID 0xF4
#define SI_VD_HOST_WRITE_ID 0xF5
#define SI_VD_SYSTEM_AREA_LIFE_LEFT_ID 0xF6
#define SI_VD_TOTAL_READ_ID 0xFA
#define SI_VD_TEMPT_SINCE_BORN_ID 0xE7
#define SI_VD_POWER_CONSUMPTION_ID 0xE8
#define SI_VD_TEMPT_SINCE_BOOTUP_ID 0xAF
#define SI_VD_POWER_LOSS_PROTECTION_ID 0xEC
#define SI_VD_READ_FAIL_ID 0xF2
#define SI_VD_THERMAL_THROTTLE_TIME_ID 0xEB
#define SI_VD_FLASH_MEDIA_ERROR_ID 0xED
/* Addtional smart internal ID */
typedef enum
{
/* smart attr following intel */
SI_VD_PROGRAM_FAIL = 0, /* 0xAB */
SI_VD_ERASE_FAIL = 1, /* 0xAC */
SI_VD_WEARLEVELING_COUNT = 2,/* 0xAD */
SI_VD_E2E_DECTECTION_COUNT = 3, /* 0xB8 */
SI_VD_PCIE_CRC_ERR_COUNT = 4, /* 0xC7, 2 port data in one attribute */
SI_VD_THERMAL_THROTTLE_STATUS = 8, /* 0xEA */
SI_VD_TOTAL_WRITE = 11, /* 0xF4, unit is 32MiB */
SI_VD_HOST_WRITE = 12, /* 0xF5, unit is 32MiB */
SI_VD_TOTAL_READ = 14, /* 0xFA, unit is 32MiB */
/* smart attr self defined */
SI_VD_TEMPT_SINCE_BORN = 15, /* 0xE7 */
SI_VD_POWER_CONSUMPTION = 16, /* 0xE8 */
SI_VD_TEMPT_SINCE_BOOTUP = 17, /* 0xAF */
SI_VD_POWER_LOSS_PROTECTION = 18, /* 0xEC */
SI_VD_READ_FAIL = 19, /* 0xF2 */
SI_VD_THERMAL_THROTTLE_TIME = 20, /* 0xEB */
SI_VD_FLASH_MEDIA_ERROR = 21, /* 0xED */
NR_SMART_ITEMS,
} si_vendor_smart_item_e;
// Intel Format
struct nvme_ymtc_smart_log_item
{
/* Item identifier */
u8 id[ID_SIZE];
/* Normalized value or percentage. In the range from 0 to 100. */
u8 nmVal[NM_SIZE];
/* raw value */
u8 rawVal[RAW_SIZE];
};
struct nvme_ymtc_smart_log
{
struct nvme_ymtc_smart_log_item itemArr[NR_SMART_ITEMS];
u8 resv[SMART_INFO_SIZE - sizeof(struct nvme_ymtc_smart_log_item) * NR_SMART_ITEMS];
};
#endif // __YMTC_UTILS_H__

923
plugins/zns/zns.c Normal file
View file

@ -0,0 +1,923 @@
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>
#include <linux/fs.h>
#include <sys/stat.h>
#include "nvme.h"
#include "nvme-ioctl.h"
#include "nvme-print.h"
#include "nvme-status.h"
#define CREATE_CMD
#include "zns.h"
static const char *namespace_id = "Namespace identifier to use";
static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Send an ZNS specific Identify Controller command to "\
"the given device and report information about the specified "\
"controller in various formats.";
enum nvme_print_flags flags;
struct nvme_zns_id_ctrl ctrl;
int fd, err = -1;
struct config {
char *output_format;
};
struct config cfg = {
.output_format = "normal",
};
OPT_ARGS(opts) = {
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
OPT_END()
};
fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0)
return errno;
err = flags = validate_output_format(cfg.output_format);
if (flags < 0)
goto close_fd;
err = nvme_zns_identify_ctrl(fd, &ctrl);
if (!err)
nvme_show_zns_id_ctrl(&ctrl, flags);
else if (err > 0)
nvme_show_status(err);
else
perror("zns identify controller");
close_fd:
close(fd);
return nvme_status_to_errno(err, false);
}
static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Send an ZNS specific Identify Namespace command to "\
"the given device and report information about the specified "\
"namespace in varios formats.";
const char *vendor_specific = "dump binary vendor fields";
const char *human_readable = "show identify in readable format";
enum nvme_print_flags flags;
struct nvme_zns_id_ns ns;
struct nvme_id_ns id_ns;
int fd, err = -1;
struct config {
char *output_format;
__u32 namespace_id;
int human_readable;
int vendor_specific;
};
struct config cfg = {
.output_format = "normal",
};
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
OPT_FLAG("vendor-specific", 'v', &cfg.vendor_specific, vendor_specific),
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable),
OPT_END()
};
fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0)
return errno;
flags = validate_output_format(cfg.output_format);
if (flags < 0)
goto close_fd;
if (cfg.vendor_specific)
flags |= VS;
if (cfg.human_readable)
flags |= VERBOSE;
if (!cfg.namespace_id) {
err = cfg.namespace_id = nvme_get_nsid(fd);
if (err < 0) {
perror("get-namespace-id");
goto close_fd;
}
}
err = nvme_identify_ns(fd, cfg.namespace_id, false, &id_ns);
if (err) {
nvme_show_status(err);
goto close_fd;
}
err = nvme_zns_identify_ns(fd, cfg.namespace_id, &ns);
if (!err)
nvme_show_zns_id_ns(&ns, &id_ns, flags);
else if (err > 0)
nvme_show_status(err);
else
perror("zns identify namespace");
close_fd:
close(fd);
return nvme_status_to_errno(err, false);
}
static int __zns_mgmt_send(int fd, __u32 namespace_id, __u64 zslba,
bool select_all, enum nvme_zns_send_action zsa, __u32 data_len, void *buf)
{
int err;
err = nvme_zns_mgmt_send(fd, namespace_id, zslba, select_all, zsa,
data_len, buf);
close(fd);
return err;
}
static int zns_mgmt_send(int argc, char **argv, struct command *cmd, struct plugin *plugin,
const char *desc, enum nvme_zns_send_action zsa)
{
const char *zslba = "starting LBA of the zone for this command";
const char *select_all = "send command to all zones";
int err, fd;
char *command;
struct config {
__u64 zslba;
__u32 namespace_id;
bool select_all;
};
struct config cfg = {
};
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
OPT_SUFFIX("start-lba", 's', &cfg.zslba, zslba),
OPT_FLAG("select-all", 'a', &cfg.select_all, select_all),
OPT_END()
};
err = fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0)
return errno;
err = asprintf(&command, "%s-%s", plugin->name, cmd->name);
if (err < 0)
goto close_fd;
if (!cfg.namespace_id) {
err = cfg.namespace_id = nvme_get_nsid(fd);
if (err < 0) {
perror("get-namespace-id");
goto free;
}
}
err = __zns_mgmt_send(fd, cfg.namespace_id, cfg.zslba,
cfg.select_all, zsa, 0, NULL);
if (!err)
printf("%s: Success, action:%d zone:%"PRIx64" all:%d nsid:%d\n",
command, zsa, (uint64_t)cfg.zslba, (int)cfg.select_all,
cfg.namespace_id);
else if (err > 0)
nvme_show_status(err);
else
perror(desc);
free:
free(command);
close_fd:
close(fd);
return nvme_status_to_errno(err, false);
}
static int get_zdes_bytes(int fd, __u32 nsid)
{
struct nvme_zns_id_ns ns;
struct nvme_id_ns id_ns;
__u8 lbaf;
int err;
err = nvme_identify_ns(fd, nsid, false, &id_ns);
if (err > 0){
nvme_show_status(err);
return err;
}
else if (err < 0){
perror("identify namespace");
return err;
}
err = nvme_zns_identify_ns(fd, nsid, &ns);
if (err > 0){
nvme_show_status(err);
return err;
}
else if (err < 0){
perror("zns identify namespace");
return err;
}
lbaf = id_ns.flbas & NVME_NS_FLBAS_LBA_MASK;
return ns.lbafe[lbaf].zdes << 6;
}
static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Zone Management Send";
const char *zslba = "starting LBA of the zone for this command";
const char *select_all = "send command to all zones";
const char *zsa = "zone send action";
const char *data_len = "buffer length if data required";
const char *data = "optional file for data (default stdin)";
int fd, ffd = STDIN_FILENO, err = -1;
void *buf = NULL;
struct config {
__u64 zslba;
__u32 namespace_id;
bool select_all;
__u8 zsa;
int data_len;
char *file;
};
struct config cfg = {
};
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
OPT_SUFFIX("start-lba", 's', &cfg.zslba, zslba),
OPT_FLAG("select-all", 'a', &cfg.select_all, select_all),
OPT_BYTE("zsa", 'z', &cfg.zsa, zsa),
OPT_UINT("data-len", 'l', &cfg.data_len, data_len),
OPT_FILE("data", 'd', &cfg.file, data),
OPT_END()
};
fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0)
return errno;
if (!cfg.namespace_id) {
err = cfg.namespace_id = nvme_get_nsid(fd);
if (err < 0) {
perror("get-namespace-id");
goto close_fd;
}
}
if (!cfg.zsa) {
fprintf(stderr, "zone send action must be specified\n");
err = -EINVAL;
goto close_fd;
}
if (cfg.zsa == NVME_ZNS_ZSA_SET_DESC_EXT) {
if(!cfg.data_len) {
cfg.data_len = get_zdes_bytes(fd, cfg.namespace_id);
if (cfg.data_len == 0) {
fprintf(stderr,
"Zone Descriptor Extensions are not supported\n");
goto close_fd;
} else if (cfg.data_len < 0) {
err = cfg.data_len;
goto close_fd;
}
}
if (posix_memalign(&buf, getpagesize(), cfg.data_len)) {
fprintf(stderr, "can not allocate feature payload\n");
goto close_fd;
}
memset(buf, 0, cfg.data_len);
if (cfg.file) {
ffd = open(cfg.file, O_RDONLY);
if (ffd < 0) {
perror(cfg.file);
goto free;
}
}
err = read(ffd, (void *)buf, cfg.data_len);
if (err < 0) {
perror("read");
goto close_ffd;
}
} else {
if (cfg.file || cfg.data_len) {
fprintf(stderr,
"data, data_len only valid with set extended descriptor\n");
err = -EINVAL;
goto close_fd;
}
}
err = __zns_mgmt_send(fd, cfg.namespace_id, cfg.zslba, cfg.select_all,
cfg.zsa, cfg.data_len, buf);
if (!err)
printf("zone-mgmt-send: Success, action:%d zone:%"PRIx64" "
"all:%d nsid:%d\n",
cfg.zsa, (uint64_t)cfg.zslba, (int)cfg.select_all,
cfg.namespace_id);
else if (err > 0)
nvme_show_status(err);
else
perror("zns zone-mgmt-send");
close_ffd:
if (cfg.file)
close(ffd);
free:
free(buf);
close_fd:
close(fd);
return nvme_status_to_errno(err, false);
}
static int close_zone(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Close zones\n";
return zns_mgmt_send(argc, argv, cmd, plugin, desc, NVME_ZNS_ZSA_CLOSE);
}
static int finish_zone(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Finish zones\n";
return zns_mgmt_send(argc, argv, cmd, plugin, desc, NVME_ZNS_ZSA_FINISH);
}
static int open_zone(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Open zones\n";
return zns_mgmt_send(argc, argv, cmd, plugin, desc, NVME_ZNS_ZSA_OPEN);
}
static int reset_zone(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Reset zones\n";
return zns_mgmt_send(argc, argv, cmd, plugin, desc, NVME_ZNS_ZSA_RESET);
}
static int offline_zone(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Offline zones\n";
return zns_mgmt_send(argc, argv, cmd, plugin, desc, NVME_ZNS_ZSA_OFFLINE);
}
static int set_zone_desc(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Set Zone Descriptor Extension\n";
const char *zslba = "starting LBA of the zone for this command";
const char *data = "optional file for zone extention data (default stdin)";
int fd, ffd = STDIN_FILENO, err;
void *buf = NULL;
__u32 data_len;
struct config {
__u64 zslba;
__u32 namespace_id;
char *file;
};
struct config cfg = {
};
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
OPT_SUFFIX("start-lba", 's', &cfg.zslba, zslba),
OPT_FILE("data", 'd', &cfg.file, data),
OPT_END()
};
fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0)
return errno;
if (!cfg.namespace_id) {
err = cfg.namespace_id = nvme_get_nsid(fd);
if (err < 0) {
perror("get-namespace-id");
goto close_fd;
}
}
data_len = get_zdes_bytes(fd, cfg.namespace_id);
if (!data_len) {
fprintf(stderr,
"zone format does not provide descriptor extention\n");
errno = EINVAL;
err = -1;
goto close_fd;
}
buf = calloc(1, data_len);
if (!buf) {
perror("could not alloc memory for zone desc");
err = -ENOMEM;
goto close_fd;
}
if (cfg.file) {
ffd = open(cfg.file, O_RDONLY);
if (ffd < 0) {
perror(cfg.file);
err = -1;
goto free;
}
}
err = read(ffd, (void *)buf, data_len);
if (err < 0) {
perror("read");
goto close_ffd;
}
err = __zns_mgmt_send(fd, cfg.namespace_id, cfg.zslba, 0,
NVME_ZNS_ZSA_SET_DESC_EXT, data_len, buf);
if (!err)
printf("set-zone-desc: Success, zone:%"PRIx64" nsid:%d\n",
(uint64_t)cfg.zslba, cfg.namespace_id);
else if (err > 0)
nvme_show_status(err);
else
perror("zns set-zone-desc");
close_ffd:
if (cfg.file)
close(ffd);
free:
free(buf);
close_fd:
close(fd);
return nvme_status_to_errno(err, false);
}
static int zone_mgmt_recv(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Zone Management Receive";
const char *zslba = "starting LBA of the zone";
const char *zra = "Zone Receive Action";
const char *zrasf = "Zone Receive Action Specific Field(Reporting Options)";
const char *partial = "Zone Receive Action Specific Features(Partial Report)";
const char *data_len = "length of data in bytes";
enum nvme_print_flags flags;
int fd, err = -1;
void *data = NULL;
struct config {
char *output_format;
__u64 zslba;
__u32 namespace_id;
__u8 zra;
__u8 zrasf;
bool partial;
__u32 data_len;
};
struct config cfg = {
.output_format = "normal",
};
OPT_ARGS(opts) = {
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
OPT_SUFFIX("start-lba", 's', &cfg.zslba, zslba),
OPT_BYTE("zra", 'z', &cfg.zra, zra),
OPT_BYTE("zrasf", 'S', &cfg.zrasf, zrasf),
OPT_FLAG("partial", 'p', &cfg.partial, partial),
OPT_UINT("data-len", 'l', &cfg.data_len, data_len),
OPT_END()
};
fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0)
return errno;
flags = validate_output_format(cfg.output_format);
if (flags < 0)
goto close_fd;
if (!cfg.namespace_id) {
err = cfg.namespace_id = nvme_get_nsid(fd);
if (err < 0) {
perror("get-namespace-id");
goto close_fd;
}
}
if (cfg.zra == NVME_ZNS_ZRA_REPORT_ZONES && !cfg.data_len) {
fprintf(stderr, "error: data len is needed for NVME_ZRA_ZONE_REPORT\n");
err = -EINVAL;
goto close_fd;
}
if (cfg.data_len) {
data = calloc(1, cfg.data_len);
if (!data) {
perror("could not alloc memory for zone mgmt receive data");
err = -ENOMEM;
goto close_fd;
}
}
err = nvme_zns_mgmt_recv(fd, cfg.namespace_id, cfg.zslba, cfg.zra,
cfg.zrasf, cfg.partial, cfg.data_len, data);
if (!err)
printf("zone-mgmt-recv: Success, action:%d zone:%"PRIx64" nsid:%d\n",
cfg.zra, (uint64_t)cfg.zslba, cfg.namespace_id);
else if (err > 0)
nvme_show_status(err);
else
perror("zns zone-mgmt-recv");
free(data);
close_fd:
close(fd);
return nvme_status_to_errno(err, false);
}
static int report_zones(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Retrieve the Report Zones data structure";
const char *zslba = "starting LBA of the zone";
const char *num_descs = "number of descriptors to retrieve (default: all of them)";
const char *state = "state of zones to list";
const char *ext = "set to use the extended report zones";
const char *part = "set to use the partial report";
const char *human_readable = "show report zones in readable format";
enum nvme_print_flags flags;
int fd, zdes = 0, err = -1;
__u32 report_size;
void *report;
bool huge = false;
struct config {
char *output_format;
__u64 zslba;
__u32 namespace_id;
int num_descs;
int state;
int human_readable;
bool extended;
bool partial;
};
struct config cfg = {
.output_format = "normal",
.num_descs = -1,
};
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
OPT_SUFFIX("start-lba", 's', &cfg.zslba, zslba),
OPT_UINT("descs", 'd', &cfg.num_descs, num_descs),
OPT_UINT("state", 'S', &cfg.state, state),
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable),
OPT_FLAG("extended", 'e', &cfg.extended, ext),
OPT_FLAG("partial", 'p', &cfg.partial, part),
OPT_END()
};
fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0)
return errno;
flags = validate_output_format(cfg.output_format);
if (flags < 0)
goto close_fd;
if (cfg.human_readable)
flags |= VERBOSE;
if (!cfg.namespace_id) {
err = cfg.namespace_id = nvme_get_nsid(fd);
if (err < 0) {
perror("get-namespace-id");
goto close_fd;
}
}
if (cfg.extended) {
zdes = get_zdes_bytes(fd, cfg.namespace_id);
if (zdes < 0) {
err = zdes;
goto close_fd;
}
}
if (cfg.num_descs == -1) {
struct nvme_zone_report r;
err = nvme_zns_report_zones(fd, cfg.namespace_id, 0,
0, cfg.state, 0, sizeof(r), &r);
if (err > 0) {
nvme_show_status(err);
goto close_fd;
} else if (err < 0) {
perror("zns report-zones");
goto close_fd;
}
cfg.num_descs = le64_to_cpu(r.nr_zones);
}
report_size = sizeof(struct nvme_zone_report) + cfg.num_descs *
(sizeof(struct nvme_zns_desc) + cfg.num_descs * zdes);
report = nvme_alloc(report_size, &huge);
if (!report) {
perror("alloc");
err = -ENOMEM;
goto close_fd;
}
err = nvme_zns_report_zones(fd, cfg.namespace_id, cfg.zslba,
cfg.extended, cfg.state, cfg.partial, report_size, report);
if (!err)
nvme_show_zns_report_zones(report, cfg.num_descs, zdes,
report_size, flags);
else if (err > 0)
nvme_show_status(err);
else
perror("zns report-zones");
nvme_free(report, huge);
close_fd:
close(fd);
return nvme_status_to_errno(err, false);
}
static int zone_append(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "The zone append command is used to write to a zone "\
"using the slba of the zone, and the write will be appended from the "\
"write pointer of the zone";
const char *zslba = "starting LBA of the zone";
const char *data = "file containing data to write";
const char *metadata = "file with metadata to be written";
const char *limited_retry = "limit media access attempts";
const char *fua = "force unit access";
const char *prinfo = "protection information action and checks field";
const char *piremap = "protection information remap (for type 1 PI)";
const char *ref_tag = "reference tag (for end to end PI)";
const char *lbat = "logical block application tag (for end to end PI)";
const char *lbatm = "logical block application tag mask (for end to end PI)";
const char *metadata_size = "size of metadata in bytes";
const char *data_size = "size of data in bytes";
const char *latency = "output latency statistics";
int err = -1, fd, dfd = STDIN_FILENO, mfd = STDIN_FILENO;
unsigned int lba_size, meta_size;
void *buf = NULL, *mbuf = NULL;
__u16 nblocks, control = 0;
__u64 result;
struct timeval start_time, end_time;
struct nvme_id_ns ns;
struct config {
char *data;
char *metadata;
__u64 zslba;
__u64 data_size;
__u64 metadata_size;
int limited_retry;
int fua;
__u32 namespace_id;
__u32 ref_tag;
__u16 lbat;
__u16 lbatm;
__u8 prinfo;
int piremap;
int latency;
};
struct config cfg = {
};
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
OPT_SUFFIX("zslba", 's', &cfg.zslba, zslba),
OPT_SUFFIX("data-size", 'z', &cfg.data_size, data_size),
OPT_SUFFIX("metadata-size", 'y', &cfg.metadata_size, metadata_size),
OPT_FILE("data", 'd', &cfg.data, data),
OPT_FILE("metadata", 'M', &cfg.metadata, metadata),
OPT_FLAG("limited-retry", 'l', &cfg.limited_retry, limited_retry),
OPT_FLAG("force-unit-access", 'f', &cfg.fua, fua),
OPT_UINT("ref-tag", 'r', &cfg.ref_tag, ref_tag),
OPT_SHRT("app-tag-mask", 'm', &cfg.lbatm, lbatm),
OPT_SHRT("app-tag", 'a', &cfg.lbat, lbat),
OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo),
OPT_FLAG("piremap", 'P', &cfg.piremap, piremap),
OPT_FLAG("latency", 't', &cfg.latency, latency),
OPT_END()
};
fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0)
return errno;
if (!cfg.data_size) {
fprintf(stderr, "Append size not provided\n");
errno = EINVAL;
goto close_fd;
}
if (!cfg.namespace_id) {
err = cfg.namespace_id = nvme_get_nsid(fd);
if (err < 0) {
perror("get-namespace-id");
goto close_fd;
}
}
err = nvme_identify_ns(fd, cfg.namespace_id, false, &ns);
if (err) {
nvme_show_status(err);
goto close_fd;
}
lba_size = 1 << ns.lbaf[(ns.flbas & 0x0f)].ds;
if (cfg.data_size & (lba_size - 1)) {
fprintf(stderr,
"Data size:%#"PRIx64" not aligned to lba size:%#x\n",
(uint64_t)cfg.data_size, lba_size);
errno = EINVAL;
goto close_ns;
}
meta_size = ns.lbaf[(ns.flbas & 0x0f)].ms;
if (meta_size && !(meta_size == 8 && (cfg.prinfo & 0x8)) &&
(!cfg.metadata_size || cfg.metadata_size % meta_size)) {
fprintf(stderr,
"Metadata size:%#"PRIx64" not aligned to metadata size:%#x\n",
(uint64_t)cfg.metadata_size, meta_size);
errno = EINVAL;
goto close_ns;
}
if (cfg.prinfo > 0xf) {
fprintf(stderr, "Invalid value for prinfo:%#x\n", cfg.prinfo);
errno = EINVAL;
goto close_ns;
}
if (cfg.data) {
dfd = open(cfg.data, O_RDONLY);
if (dfd < 0) {
perror(cfg.data);
goto close_ns;
}
}
if (posix_memalign(&buf, getpagesize(), cfg.data_size)) {
fprintf(stderr, "No memory for data size:%"PRIx64"\n",
(uint64_t)cfg.data_size);
goto close_dfd;
}
memset(buf, 0, cfg.data_size);
err = read(dfd, buf, cfg.data_size);
if (err < 0) {
perror("read-data");
goto free_data;
}
if (cfg.metadata) {
mfd = open(cfg.metadata, O_RDONLY);
if (mfd < 0) {
perror(cfg.metadata);
err = -1;
goto close_dfd;
}
}
if (cfg.metadata_size) {
if (posix_memalign(&mbuf, getpagesize(), meta_size)) {
fprintf(stderr, "No memory for metadata size:%d\n",
meta_size);
err = -1;
goto close_mfd;
}
memset(mbuf, 0, cfg.metadata_size);
err = read(mfd, mbuf, cfg.metadata_size);
if (err < 0) {
perror("read-metadata");
goto free_meta;
}
}
nblocks = (cfg.data_size / lba_size) - 1;
control |= (cfg.prinfo << 10);
if (cfg.limited_retry)
control |= NVME_RW_LR;
if (cfg.fua)
control |= NVME_RW_FUA;
if (cfg.piremap)
control |= NVME_RW_PIREMAP;
gettimeofday(&start_time, NULL);
err = nvme_zns_append(fd, cfg.namespace_id, cfg.zslba, nblocks,
control, cfg.ref_tag, cfg.lbat, cfg.lbatm,
cfg.data_size, buf, cfg.metadata_size, mbuf,
&result);
gettimeofday(&end_time, NULL);
if (cfg.latency)
printf(" latency: zone append: %llu us\n",
elapsed_utime(start_time, end_time));
if (!err)
printf("Success appended data to LBA %"PRIx64"\n", (uint64_t)result);
else if (err > 0)
nvme_show_status(err);
else
perror("zns zone-append");
free_meta:
free(mbuf);
close_mfd:
if (cfg.metadata)
close(mfd);
free_data:
free(buf);
close_dfd:
if (cfg.data)
close(dfd);
close_ns:
close_fd:
close(fd);
return nvme_status_to_errno(err, false);
}
static int changed_zone_list(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Retrieve Changed Zone log for the given device";
const char *rae = "retain an asynchronous event";
struct nvme_zns_changed_zone_log log;
enum nvme_print_flags flags;
int fd, err = -1;
struct config {
char *output_format;
__u32 namespace_id;
bool rae;
};
struct config cfg = {
.output_format = "normal",
};
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
OPT_FLAG("rae", 'r', &cfg.rae, rae),
OPT_END()
};
fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0)
return errno;
flags = validate_output_format(cfg.output_format);
if (flags < 0)
goto close_fd;
if (!cfg.namespace_id) {
err = cfg.namespace_id = nvme_get_nsid(fd);
if (err < 0) {
perror("get-namespace-id");
goto close_fd;
}
}
err = nvme_get_log(fd, cfg.namespace_id, NVME_LOG_ZONE_CHANGED_LIST,
cfg.rae, NVME_NO_LOG_LSP, sizeof(log), &log);
if (!err)
nvme_show_zns_changed(&log, flags);
else if (err > 0)
nvme_show_status(err);
else
perror("zns changed-zone-list");
close_fd:
close(fd);
return nvme_status_to_errno(err, false);
}

30
plugins/zns/zns.h Normal file
View file

@ -0,0 +1,30 @@
#undef CMD_INC_FILE
#define CMD_INC_FILE plugins/zns/zns
#if !defined(ZNS_NVME) || defined(CMD_HEADER_MULTI_READ)
#define ZNS_NVME
#include "cmd.h"
PLUGIN(NAME("zns", "Zoned Namespace Command Set"),
COMMAND_LIST(
ENTRY("id-ctrl", "Retrieve ZNS controller identification", id_ctrl)
ENTRY("id-ns", "Retrieve ZNS namespace identification", id_ns)
ENTRY("zone-mgmt-recv", "Sends the zone management receive command", zone_mgmt_recv)
ENTRY("zone-mgmt-send", "Sends the zone management send command", zone_mgmt_send)
ENTRY("report-zones", "Retrieve the Report Zones report", report_zones)
ENTRY("close-zone", "Closes one or more zones", close_zone)
ENTRY("finish-zone", "Finishes one or more zones", finish_zone)
ENTRY("open-zone", "Opens one or more zones", open_zone)
ENTRY("reset-zone", "Resets one or more zones", reset_zone)
ENTRY("offline-zone", "Offlines one or more zones", offline_zone)
ENTRY("set-zone-desc", "Attaches zone descriptor extension data", set_zone_desc)
ENTRY("zone-append", "Writes data and metadata (if applicable), appended to the end of the requested zone", zone_append)
ENTRY("changed-zone-list", "Retrieves the changed zone list log", changed_zone_list)
)
);
#endif
#include "define_cmd.h"