Adding upstream version 2.7.1.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
04338f02fe
commit
d6e1a5d456
663 changed files with 15529 additions and 6994 deletions
|
@ -646,7 +646,7 @@ static int glp_high_latency_show_bar(FILE *fdi, int print)
|
|||
}
|
||||
|
||||
/*
|
||||
* High latency log page definiton
|
||||
* High latency log page definition
|
||||
* Total 32 bytes
|
||||
*/
|
||||
struct log_page_high_latency {
|
||||
|
@ -1197,3 +1197,646 @@ static int mb_set_lat_stats(int argc, char **argv,
|
|||
dev_close(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
// Global definitions
|
||||
|
||||
static inline int K2C(int k) // KELVINS_2_CELSIUS
|
||||
{
|
||||
return (k - 273);
|
||||
};
|
||||
|
||||
// Global ID definitions
|
||||
|
||||
enum {
|
||||
// feature ids
|
||||
FID_LATENCY_FEATURE = 0xd0,
|
||||
|
||||
// log ids
|
||||
LID_SMART_LOG_ADD = 0xca,
|
||||
LID_LATENCY_STATISTICS = 0xd0,
|
||||
LID_HIGH_LATENCY_LOG = 0xd1,
|
||||
LID_PERFORMANCE_STATISTICS = 0xd2,
|
||||
};
|
||||
|
||||
// smart-log-add
|
||||
|
||||
struct smart_log_add_item {
|
||||
uint32_t index;
|
||||
char *attr;
|
||||
};
|
||||
|
||||
struct __packed wear_level {
|
||||
__le16 min;
|
||||
__le16 max;
|
||||
__le16 avg;
|
||||
};
|
||||
|
||||
struct __packed smart_log_add_item_12 {
|
||||
uint8_t id;
|
||||
uint8_t rsvd[2];
|
||||
uint8_t norm;
|
||||
uint8_t rsvd1;
|
||||
union {
|
||||
struct wear_level wear_level; // 0xad
|
||||
struct temp_since_born { // 0xe7
|
||||
__le16 max;
|
||||
__le16 min;
|
||||
__le16 curr;
|
||||
} temp_since_born;
|
||||
struct power_consumption { // 0xe8
|
||||
__le16 max;
|
||||
__le16 min;
|
||||
__le16 curr;
|
||||
} power_consumption;
|
||||
struct temp_since_power_on { // 0xaf
|
||||
__le16 max;
|
||||
__le16 min;
|
||||
__le16 curr;
|
||||
} temp_since_power_on;
|
||||
uint8_t raw[6];
|
||||
};
|
||||
uint8_t rsvd2;
|
||||
};
|
||||
|
||||
struct __packed smart_log_add_item_10 {
|
||||
uint8_t id;
|
||||
uint8_t norm;
|
||||
union {
|
||||
struct wear_level wear_level; // 0xad
|
||||
uint8_t raw[6];
|
||||
};
|
||||
uint8_t rsvd[2];
|
||||
};
|
||||
|
||||
struct smart_log_add {
|
||||
union {
|
||||
union {
|
||||
struct smart_log_add_v0 {
|
||||
struct smart_log_add_item_12 program_fail_count;
|
||||
struct smart_log_add_item_12 erase_fail_count;
|
||||
struct smart_log_add_item_12 wear_leveling_count;
|
||||
struct smart_log_add_item_12 end_to_end_error_count;
|
||||
struct smart_log_add_item_12 crc_error_count;
|
||||
struct smart_log_add_item_12 timed_workload_media_wear;
|
||||
struct smart_log_add_item_12 timed_workload_host_reads;
|
||||
struct smart_log_add_item_12 timed_workload_timer;
|
||||
struct smart_log_add_item_12 thermal_throttle_status;
|
||||
struct smart_log_add_item_12 retry_buffer_overflow_counter;
|
||||
struct smart_log_add_item_12 pll_lock_loss_count;
|
||||
struct smart_log_add_item_12 nand_bytes_written;
|
||||
struct smart_log_add_item_12 host_bytes_written;
|
||||
struct smart_log_add_item_12 system_area_life_remaining;
|
||||
struct smart_log_add_item_12 nand_bytes_read;
|
||||
struct smart_log_add_item_12 temperature;
|
||||
struct smart_log_add_item_12 power_consumption;
|
||||
struct smart_log_add_item_12 power_on_temperature;
|
||||
struct smart_log_add_item_12 power_loss_protection;
|
||||
struct smart_log_add_item_12 read_fail_count;
|
||||
struct smart_log_add_item_12 thermal_throttle_time;
|
||||
struct smart_log_add_item_12 flash_error_media_count;
|
||||
} v0;
|
||||
|
||||
struct smart_log_add_item_12 v0_raw[22];
|
||||
};
|
||||
|
||||
union {
|
||||
struct smart_log_add_v2 {
|
||||
struct smart_log_add_item_12 program_fail_count;
|
||||
struct smart_log_add_item_12 erase_fail_count;
|
||||
struct smart_log_add_item_12 wear_leveling_count;
|
||||
struct smart_log_add_item_12 end_to_end_error_count;
|
||||
struct smart_log_add_item_12 crc_error_count;
|
||||
struct smart_log_add_item_12 timed_workload_media_wear;
|
||||
struct smart_log_add_item_12 timed_workload_host_reads;
|
||||
struct smart_log_add_item_12 timed_workload_timer;
|
||||
struct smart_log_add_item_12 thermal_throttle_status;
|
||||
struct smart_log_add_item_12 lifetime_write_amplification;
|
||||
struct smart_log_add_item_12 pll_lock_loss_count;
|
||||
struct smart_log_add_item_12 nand_bytes_written;
|
||||
struct smart_log_add_item_12 host_bytes_written;
|
||||
struct smart_log_add_item_12 system_area_life_remaining;
|
||||
struct smart_log_add_item_12 firmware_update_count;
|
||||
struct smart_log_add_item_12 dram_cecc_count;
|
||||
struct smart_log_add_item_12 dram_uecc_count;
|
||||
struct smart_log_add_item_12 xor_pass_count;
|
||||
struct smart_log_add_item_12 xor_fail_count;
|
||||
struct smart_log_add_item_12 xor_invoked_count;
|
||||
struct smart_log_add_item_12 inflight_read_io_cmd;
|
||||
struct smart_log_add_item_12 flash_error_media_count;
|
||||
struct smart_log_add_item_12 nand_bytes_read;
|
||||
struct smart_log_add_item_12 temp_since_born;
|
||||
struct smart_log_add_item_12 power_consumption;
|
||||
struct smart_log_add_item_12 temp_since_bootup;
|
||||
struct smart_log_add_item_12 thermal_throttle_time;
|
||||
} v2;
|
||||
|
||||
struct smart_log_add_item_12 v2_raw[27];
|
||||
};
|
||||
|
||||
union {
|
||||
struct smart_log_add_v3 {
|
||||
struct smart_log_add_item_10 program_fail_count;
|
||||
struct smart_log_add_item_10 erase_fail_count;
|
||||
struct smart_log_add_item_10 wear_leveling_count;
|
||||
struct smart_log_add_item_10 ext_e2e_err_count;
|
||||
struct smart_log_add_item_10 crc_err_count;
|
||||
struct smart_log_add_item_10 nand_bytes_written;
|
||||
struct smart_log_add_item_10 host_bytes_written;
|
||||
struct smart_log_add_item_10 reallocated_sector_count;
|
||||
struct smart_log_add_item_10 uncorrectable_sector_count;
|
||||
struct smart_log_add_item_10 nand_uecc_detection;
|
||||
struct smart_log_add_item_10 nand_xor_correction;
|
||||
struct smart_log_add_item_10 gc_count;
|
||||
struct smart_log_add_item_10 dram_uecc_detection_count;
|
||||
struct smart_log_add_item_10 sram_uecc_detection_count;
|
||||
struct smart_log_add_item_10 internal_raid_recovery_fail_count;
|
||||
struct smart_log_add_item_10 inflight_cmds;
|
||||
struct smart_log_add_item_10 internal_e2e_err_count;
|
||||
struct smart_log_add_item_10 die_fail_count;
|
||||
struct smart_log_add_item_10 wear_leveling_execution_count;
|
||||
struct smart_log_add_item_10 read_disturb_count;
|
||||
struct smart_log_add_item_10 data_retention_count;
|
||||
struct smart_log_add_item_10 capacitor_health;
|
||||
} v3;
|
||||
|
||||
struct smart_log_add_item_10 v3_raw[24];
|
||||
};
|
||||
|
||||
uint8_t raw[512];
|
||||
};
|
||||
};
|
||||
|
||||
static void smart_log_add_v0_print(struct smart_log_add_item_12 *item, int item_count)
|
||||
{
|
||||
static const struct smart_log_add_item items[0xff] = {
|
||||
[0xab] = {0, "program_fail_count" },
|
||||
[0xac] = {1, "erase_fail_count" },
|
||||
[0xad] = {2, "wear_leveling_count" },
|
||||
[0xb8] = {3, "end_to_end_error_count" },
|
||||
[0xc7] = {4, "crc_error_count" },
|
||||
[0xe2] = {5, "timed_workload_media_wear" },
|
||||
[0xe3] = {6, "timed_workload_host_reads" },
|
||||
[0xe4] = {7, "timed_workload_timer" },
|
||||
[0xea] = {8, "thermal_throttle_status" },
|
||||
[0xf0] = {9, "retry_buffer_overflow_counter"},
|
||||
[0xf3] = {10, "pll_lock_loss_count" },
|
||||
[0xf4] = {11, "nand_bytes_written" },
|
||||
[0xf5] = {12, "host_bytes_written" },
|
||||
[0xf6] = {13, "system_area_life_remaining" },
|
||||
[0xfa] = {14, "nand_bytes_read" },
|
||||
[0xe7] = {15, "temperature" },
|
||||
[0xe8] = {16, "power_consumption" },
|
||||
[0xaf] = {17, "power_on_temperature" },
|
||||
[0xec] = {18, "power_loss_protection" },
|
||||
[0xf2] = {19, "read_fail_count" },
|
||||
[0xeb] = {20, "thermal_throttle_time" },
|
||||
[0xed] = {21, "flash_error_media_count" },
|
||||
};
|
||||
|
||||
for (int i = 0; i < item_count; i++, item++) {
|
||||
if (item->id == 0)
|
||||
continue;
|
||||
|
||||
printf("%#-12" PRIx8 "%-36s%-12d", item->id, items[item->id].attr, item->norm);
|
||||
switch (item->id) {
|
||||
case 0xad:
|
||||
printf("min: %d, max: %d, avg: %d\n",
|
||||
le16_to_cpu(item->wear_level.min),
|
||||
le16_to_cpu(item->wear_level.max),
|
||||
le16_to_cpu(item->wear_level.avg));
|
||||
break;
|
||||
case 0xe7:
|
||||
printf("max: %d °C (%d K), min: %d °C (%d K), curr: %d °C (%d K)\n",
|
||||
K2C(le16_to_cpu(item->temp_since_born.max)),
|
||||
le16_to_cpu(item->temp_since_born.max),
|
||||
K2C(le16_to_cpu(item->temp_since_born.min)),
|
||||
le16_to_cpu(item->temp_since_born.min),
|
||||
K2C(le16_to_cpu(item->temp_since_born.curr)),
|
||||
le16_to_cpu(item->temp_since_born.curr));
|
||||
break;
|
||||
case 0xe8:
|
||||
printf("max: %d, min: %d, curr: %d\n",
|
||||
le16_to_cpu(item->power_consumption.max),
|
||||
le16_to_cpu(item->power_consumption.min),
|
||||
le16_to_cpu(item->power_consumption.curr));
|
||||
break;
|
||||
case 0xaf:
|
||||
printf("max: %d °C (%d K), min: %d °C (%d K), curr: %d °C (%d K)\n",
|
||||
K2C(le16_to_cpu(item->temp_since_power_on.max)),
|
||||
le16_to_cpu(item->temp_since_power_on.max),
|
||||
K2C(le16_to_cpu(item->temp_since_power_on.min)),
|
||||
le16_to_cpu(item->temp_since_power_on.min),
|
||||
K2C(le16_to_cpu(item->temp_since_power_on.curr)),
|
||||
le16_to_cpu(item->temp_since_power_on.curr));
|
||||
break;
|
||||
default:
|
||||
printf("%" PRIu64 "\n", int48_to_long(item->raw));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void smart_log_add_v2_print(struct smart_log_add_item_12 *item, int item_count)
|
||||
{
|
||||
static const struct smart_log_add_item items[0xff] = {
|
||||
[0xab] = {0, "program_fail_count" },
|
||||
[0xac] = {1, "erase_fail_count" },
|
||||
[0xad] = {2, "wear_leveling_count" },
|
||||
[0xb8] = {3, "end_to_end_error_count" },
|
||||
[0xc7] = {4, "crc_error_count" },
|
||||
[0xe2] = {5, "timed_workload_media_wear" },
|
||||
[0xe3] = {6, "timed_workload_host_reads" },
|
||||
[0xe4] = {7, "timed_workload_timer" },
|
||||
[0xea] = {8, "thermal_throttle_status" },
|
||||
[0xf0] = {9, "lifetime_write_amplification"},
|
||||
[0xf3] = {10, "pll_lock_loss_count" },
|
||||
[0xf4] = {11, "nand_bytes_written" },
|
||||
[0xf5] = {12, "host_bytes_written" },
|
||||
[0xf6] = {13, "system_area_life_remaining" },
|
||||
[0xf9] = {14, "firmware_update_count" },
|
||||
[0xfa] = {15, "dram_cecc_count" },
|
||||
[0xfb] = {16, "dram_uecc_count" },
|
||||
[0xfc] = {17, "xor_pass_count" },
|
||||
[0xfd] = {18, "xor_fail_count" },
|
||||
[0xfe] = {19, "xor_invoked_count" },
|
||||
[0xe5] = {20, "inflight_read_io_cmd" },
|
||||
[0xe6] = {21, "flash_error_media_count" },
|
||||
[0xf8] = {22, "nand_bytes_read" },
|
||||
[0xe7] = {23, "temp_since_born" },
|
||||
[0xe8] = {24, "power_consumption" },
|
||||
[0xaf] = {25, "temp_since_bootup" },
|
||||
[0xeb] = {26, "thermal_throttle_time" },
|
||||
};
|
||||
|
||||
for (int i = 0; i < item_count; i++, item++) {
|
||||
if (item->id == 0)
|
||||
continue;
|
||||
|
||||
printf("%#-12" PRIx8 "%-36s%-12d", item->id, items[item->id].attr, item->norm);
|
||||
switch (item->id) {
|
||||
case 0xad:
|
||||
printf("min: %d, max: %d, avg: %d\n",
|
||||
le16_to_cpu(item->wear_level.min),
|
||||
le16_to_cpu(item->wear_level.max),
|
||||
le16_to_cpu(item->wear_level.avg));
|
||||
break;
|
||||
case 0xe7:
|
||||
printf("max: %d °C (%d K), min: %d °C (%d K), curr: %d °C (%d K)\n",
|
||||
K2C(le16_to_cpu(item->temp_since_born.max)),
|
||||
le16_to_cpu(item->temp_since_born.max),
|
||||
K2C(le16_to_cpu(item->temp_since_born.min)),
|
||||
le16_to_cpu(item->temp_since_born.min),
|
||||
K2C(le16_to_cpu(item->temp_since_born.curr)),
|
||||
le16_to_cpu(item->temp_since_born.curr));
|
||||
break;
|
||||
case 0xe8:
|
||||
printf("max: %d, min: %d, curr: %d\n",
|
||||
le16_to_cpu(item->power_consumption.max),
|
||||
le16_to_cpu(item->power_consumption.min),
|
||||
le16_to_cpu(item->power_consumption.curr));
|
||||
break;
|
||||
case 0xaf:
|
||||
printf("max: %d °C (%d K), min: %d °C (%d K), curr: %d °C (%d K)\n",
|
||||
K2C(le16_to_cpu(item->temp_since_power_on.max)),
|
||||
le16_to_cpu(item->temp_since_power_on.max),
|
||||
K2C(le16_to_cpu(item->temp_since_power_on.min)),
|
||||
le16_to_cpu(item->temp_since_power_on.min),
|
||||
K2C(le16_to_cpu(item->temp_since_power_on.curr)),
|
||||
le16_to_cpu(item->temp_since_power_on.curr));
|
||||
break;
|
||||
default:
|
||||
printf("%" PRIu64 "\n", int48_to_long(item->raw));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void smart_log_add_v3_print(struct smart_log_add_item_10 *item, int item_count)
|
||||
{
|
||||
static const struct smart_log_add_item items[0xff] = {
|
||||
[0xab] = {0, "program_fail_count" },
|
||||
[0xac] = {1, "erase_fail_count" },
|
||||
[0xad] = {2, "wear_leveling_count" },
|
||||
[0xb8] = {3, "ext_e2e_err_count" },
|
||||
[0xc7] = {4, "crc_err_count" },
|
||||
[0xf4] = {5, "nand_bytes_written" },
|
||||
[0xf5] = {6, "host_bytes_written" },
|
||||
[0xd0] = {7, "reallocated_sector_count" },
|
||||
[0xd1] = {8, "uncorrectable_sector_count" },
|
||||
[0xd2] = {9, "nand_uecc_detection" },
|
||||
[0xd3] = {10, "nand_xor_correction" },
|
||||
[0xd4] = {12, "gc_count" }, // 11 is reserved
|
||||
[0xd5] = {13, "dram_uecc_detection_count" },
|
||||
[0xd6] = {14, "sram_uecc_detection_count" },
|
||||
[0xd7] = {15, "internal_raid_recovery_fail_count"},
|
||||
[0xd8] = {16, "inflight_cmds" },
|
||||
[0xd9] = {17, "internal_e2e_err_count" },
|
||||
[0xda] = {19, "die_fail_count" }, // 18 is reserved
|
||||
[0xdb] = {20, "wear_leveling_execution_count" },
|
||||
[0xdc] = {21, "read_disturb_count" },
|
||||
[0xdd] = {22, "data_retention_count" },
|
||||
[0xde] = {23, "capacitor_health" },
|
||||
};
|
||||
|
||||
for (int i = 0; i < item_count; i++, item++) {
|
||||
if (item->id == 0)
|
||||
continue;
|
||||
|
||||
printf("%#-12" PRIx8 "%-36s%-12d", item->id, items[item->id].attr, item->norm);
|
||||
switch (item->id) {
|
||||
case 0xad:
|
||||
printf("min: %d, max: %d, avg: %d\n",
|
||||
le16_to_cpu(item->wear_level.min),
|
||||
le16_to_cpu(item->wear_level.max),
|
||||
le16_to_cpu(item->wear_level.avg));
|
||||
break;
|
||||
default:
|
||||
printf("%" PRIu64 "\n", int48_to_long(item->raw));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void smart_log_add_print(struct smart_log_add *log, const char *devname)
|
||||
{
|
||||
uint8_t version = log->raw[511];
|
||||
|
||||
printf("Version: %u\n", version);
|
||||
printf("\n");
|
||||
printf("Additional Smart Log for NVMe device: %s\n", devname);
|
||||
printf("\n");
|
||||
|
||||
printf("%-12s%-36s%-12s%s\n", "Id", "Key", "Normalized", "Raw");
|
||||
|
||||
switch (version) {
|
||||
case 0:
|
||||
return smart_log_add_v0_print(&log->v0_raw[0],
|
||||
sizeof(struct smart_log_add_v0) / sizeof(struct smart_log_add_item_12));
|
||||
case 2:
|
||||
return smart_log_add_v2_print(&log->v2_raw[0],
|
||||
sizeof(struct smart_log_add_v2) / sizeof(struct smart_log_add_item_12));
|
||||
case 3:
|
||||
return smart_log_add_v3_print(&log->v3_raw[0],
|
||||
sizeof(struct smart_log_add_v3) / sizeof(struct smart_log_add_item_10));
|
||||
|
||||
case 1:
|
||||
fprintf(stderr, "Version %d: N/A\n", version);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Version %d: Not supported yet\n", version);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int mb_get_smart_log_add(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
// Get the configuration
|
||||
|
||||
struct config {
|
||||
bool raw_binary;
|
||||
};
|
||||
|
||||
struct config cfg = {0};
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, "dump the whole log buffer in binary format"),
|
||||
OPT_END()};
|
||||
|
||||
// Open device
|
||||
|
||||
struct nvme_dev *dev = NULL;
|
||||
|
||||
err = parse_and_open(&dev, argc, argv, cmd->help, opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
// Get log
|
||||
|
||||
struct smart_log_add log = {0};
|
||||
|
||||
err = nvme_get_log_simple(dev_fd(dev), LID_SMART_LOG_ADD, sizeof(struct smart_log_add), &log);
|
||||
if (!err) {
|
||||
if (!cfg.raw_binary)
|
||||
smart_log_add_print(&log, dev->name);
|
||||
else
|
||||
d_raw((unsigned char *)&log, sizeof(struct smart_log_add));
|
||||
} else if (err > 0) {
|
||||
nvme_show_status(err);
|
||||
} else {
|
||||
nvme_show_error("%s: %s", cmd->name, nvme_strerror(errno));
|
||||
}
|
||||
|
||||
// Close device
|
||||
|
||||
dev_close(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
// performance-monitor
|
||||
|
||||
struct latency_stats_bucket {
|
||||
char *start_threshold;
|
||||
char *end_threshold;
|
||||
};
|
||||
|
||||
struct __packed latency_stats {
|
||||
union {
|
||||
struct latency_stats_v2_0 {
|
||||
uint32_t minor_version;
|
||||
uint32_t major_version;
|
||||
uint32_t bucket_read_data[32];
|
||||
uint32_t rsvd[32];
|
||||
uint32_t bucket_write_data[32];
|
||||
uint32_t rsvd1[32];
|
||||
uint32_t bucket_trim_data[32];
|
||||
uint32_t rsvd2[32];
|
||||
uint8_t rsvd3[248];
|
||||
} v2_0;
|
||||
uint8_t raw[1024];
|
||||
};
|
||||
};
|
||||
|
||||
struct __packed high_latency_log {
|
||||
union {
|
||||
struct high_latency_log_v1 {
|
||||
uint32_t version;
|
||||
struct high_latency_log_entry {
|
||||
uint64_t timestamp; // ms
|
||||
uint32_t latency;
|
||||
uint32_t qid;
|
||||
uint32_t opcode : 8;
|
||||
uint32_t fuse : 2;
|
||||
uint32_t psdt : 2;
|
||||
uint32_t cid : 16;
|
||||
uint32_t rsvd : 4;
|
||||
uint32_t nsid;
|
||||
uint64_t slba;
|
||||
uint32_t nlb : 16;
|
||||
uint32_t dtype : 8;
|
||||
uint32_t pinfo : 4;
|
||||
uint32_t fua : 1;
|
||||
uint32_t lr : 1;
|
||||
uint32_t rsvd1 : 2;
|
||||
uint8_t rsvd2[28];
|
||||
} entries[1024];
|
||||
} v1;
|
||||
uint8_t raw[4 + 1024 * 64];
|
||||
};
|
||||
};
|
||||
|
||||
struct __packed performance_stats {
|
||||
union {
|
||||
struct performance_stats_v1 {
|
||||
uint8_t version;
|
||||
uint8_t rsvd[3];
|
||||
struct performance_stats_timestamp {
|
||||
uint8_t timestamp[6];
|
||||
struct performance_stats_entry {
|
||||
uint16_t read_iops; // K IOPS
|
||||
uint16_t read_bandwidth; // MiB
|
||||
uint32_t read_latency; // us
|
||||
uint32_t read_latency_max; // us
|
||||
uint16_t write_iops; // K IOPS
|
||||
uint16_t write_bandwidth; // MiB
|
||||
uint32_t write_latency; // us
|
||||
uint32_t write_latency_max; // us
|
||||
} entries[3600];
|
||||
} timestamps[24];
|
||||
} v1;
|
||||
uint8_t raw[4 + 24 * (6 + 3600 * 24)];
|
||||
};
|
||||
};
|
||||
|
||||
static int mb_set_latency_feature(int argc, char **argv, struct command *cmd,
|
||||
struct plugin *plugin)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
// Get the configuration
|
||||
|
||||
struct config {
|
||||
uint32_t perf_monitor;
|
||||
uint32_t cmd_mask;
|
||||
uint32_t read_threshold;
|
||||
uint32_t write_threshold;
|
||||
uint32_t de_allocate_trim_threshold;
|
||||
};
|
||||
|
||||
struct config cfg = {0};
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
OPT_UINT("sel-perf-log", 's', &cfg.perf_monitor,
|
||||
"Select features to turn on, default: Disable\n"
|
||||
" bit 0: latency statistics\n"
|
||||
" bit 1: high latency log\n"
|
||||
" bit 2: Performance stat"),
|
||||
OPT_UINT("set-commands-mask", 'm', &cfg.cmd_mask,
|
||||
"Set Enable, default: Disable\n"
|
||||
" bit 0: Read commands\n"
|
||||
" bit 1: high Write commands\n"
|
||||
" bit 2: De-allocate/TRIM (this bit is not worked for Performance stat.)"),
|
||||
OPT_UINT("set-read-threshold", 'r', &cfg.read_threshold,
|
||||
"set read high latency log threshold, it's a 0-based value and unit is 10ms"),
|
||||
OPT_UINT("set-write-threshold", 'w', &cfg.write_threshold,
|
||||
"set write high latency log threshold, it's a 0-based value and unit is 10ms"),
|
||||
OPT_UINT("set-trim-threshold", 't', &cfg.de_allocate_trim_threshold,
|
||||
"set trim high latency log threshold, it's a 0-based value and unit is 10ms"),
|
||||
OPT_END()};
|
||||
|
||||
// Open device
|
||||
|
||||
struct nvme_dev *dev = NULL;
|
||||
|
||||
err = parse_and_open(&dev, argc, argv, cmd->help, opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
||||
// Set feature
|
||||
|
||||
uint32_t result = 0;
|
||||
|
||||
struct nvme_set_features_args args = {
|
||||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.fid = FID_LATENCY_FEATURE,
|
||||
.nsid = 0,
|
||||
.cdw11 = 0 | cfg.perf_monitor,
|
||||
.cdw12 = 0 | cfg.cmd_mask,
|
||||
.cdw13 = 0 |
|
||||
(cfg.read_threshold & 0xff) |
|
||||
((cfg.write_threshold & 0xff) << 8) |
|
||||
((cfg.de_allocate_trim_threshold & 0xff) << 16),
|
||||
.cdw15 = 0,
|
||||
.save = 0,
|
||||
.uuidx = 0,
|
||||
.data = NULL,
|
||||
.data_len = 0,
|
||||
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
|
||||
.result = &result,
|
||||
};
|
||||
|
||||
err = nvme_set_features(&args);
|
||||
if (!err)
|
||||
printf("%s have done successfully. result = %#" PRIx32 ".\n", cmd->name, result);
|
||||
else if (err > 0)
|
||||
nvme_show_status(err);
|
||||
else
|
||||
nvme_show_error("%s: %s", cmd->name, nvme_strerror(errno));
|
||||
|
||||
// Close device
|
||||
|
||||
dev_close(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mb_get_latency_feature(int argc, char **argv, struct command *cmd,
|
||||
struct plugin *plugin)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
// Get the configuration
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
OPT_END()};
|
||||
|
||||
// Open device
|
||||
|
||||
struct nvme_dev *dev = NULL;
|
||||
|
||||
err = parse_and_open(&dev, argc, argv, cmd->help, opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
// Get feature
|
||||
|
||||
uint32_t result = 0;
|
||||
|
||||
err = nvme_get_features_simple(dev_fd(dev), FID_LATENCY_FEATURE, 0, &result);
|
||||
if (!err) {
|
||||
printf("%s have done successfully. result = %#" PRIx32 ".\n", cmd->name, result);
|
||||
|
||||
printf("latency statistics enable status = %d\n", (result & (0x01 << 0)) >> 0);
|
||||
printf("high latency enable status = %d\n", (result & (0x01 << 1)) >> 1);
|
||||
printf("performance stat enable status = %d\n", (result & (0x01 << 2)) >> 2);
|
||||
|
||||
printf("Monitor Read command = %d\n", (result & (0x01 << 4)) >> 4);
|
||||
printf("Monitor Write command = %d\n", (result & (0x01 << 5)) >> 5);
|
||||
printf("Monitor Trim command = %d\n", (result & (0x01 << 6)) >> 6);
|
||||
|
||||
printf("Threshold for Read = %dms\n", (((result & (0xff << 8)) >> 8) + 1) * 10);
|
||||
printf("Threshold for Write = %dms\n", (((result & (0xff << 16)) >> 16) + 1) * 10);
|
||||
printf("Threshold for Trim = %dms\n", (((result & (0xff << 24)) >> 24) + 1) * 10);
|
||||
} else if (err > 0) {
|
||||
nvme_show_status(err);
|
||||
} else {
|
||||
nvme_show_error("%s: %s", cmd->name, nvme_strerror(errno));
|
||||
}
|
||||
|
||||
// Close device
|
||||
|
||||
dev_close(dev);
|
||||
return err;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue