Merging upstream version 1.14.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
868b5312e8
commit
d6fd2fdea9
305 changed files with 20664 additions and 6099 deletions
59
plugins/amzn/amzn-nvme.c
Normal file
59
plugins/amzn/amzn-nvme.c
Normal 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
17
plugins/amzn/amzn-nvme.h
Normal 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"
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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, ¶m1, ¶m2)) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -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
|
@ -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)
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -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++) {
|
||||
|
|
58
plugins/nvidia/nvidia-nvme.c
Normal file
58
plugins/nvidia/nvidia-nvme.c
Normal 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);
|
||||
}
|
17
plugins/nvidia/nvidia-nvme.h
Normal file
17
plugins/nvidia/nvidia-nvme.h
Normal 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"
|
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
@ -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)
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -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--;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
148
plugins/ymtc/ymtc-nvme.c
Normal 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
24
plugins/ymtc/ymtc-nvme.h
Normal 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
80
plugins/ymtc/ymtc-utils.h
Normal 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
923
plugins/zns/zns.c
Normal 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
30
plugins/zns/zns.h
Normal 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"
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue