1
0
Fork 0

Adding upstream version 2.5.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-16 12:24:03 +01:00
parent 7819359ae2
commit acf5b2ec4c
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
507 changed files with 19440 additions and 17258 deletions

View file

@ -28,15 +28,15 @@ static void json_amzn_id_ctrl(struct nvme_vu_id_ctrl_field *id,
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;
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] == ' ') {
if (id->bdev[++len] == ' ')
break;
}
}
snprintf(bdev, len+1, "%s", id->bdev);

View file

@ -104,13 +104,12 @@ static int nvme_dera_get_device_status(int fd, enum dera_device_status *result)
.addr = (__u64)(uintptr_t)NULL,
.data_len = 0,
.cdw10 = 0,
.cdw12 = 0x104,
.cdw12 = 0x104,
};
err = nvme_submit_admin_passthru(fd, &cmd, NULL);
if (!err && result) {
if (!err && result)
*result = cmd.result;
}
return err;
}
@ -130,13 +129,12 @@ static int get_status(int argc, char **argv, struct command *cmd, struct plugin
err = parse_and_open(&dev, argc, argv, desc, opts);
if (err)
return err;
err = nvme_get_log_simple(dev_fd(dev), 0xc0, sizeof(log), &log);
if (err) {
goto exit;
}
const char* dev_status[] = {
err = nvme_get_log_simple(dev_fd(dev), 0xc0, sizeof(log), &log);
if (err)
goto exit;
static const char *dev_status[] = {
"Normal",
"Quick Rebuilding",
"Full Rebuilding",
@ -148,25 +146,22 @@ static int get_status(int argc, char **argv, struct command *cmd, struct plugin
"Firmware Committing",
"Over Temperature" };
const char *volt_status[] = {
static const char *volt_status[] = {
"Normal",
"Initial Low",
"Runtime Low",
};
err = nvme_dera_get_device_status(dev_fd(dev), &state);
if (!err){
if (state > 0 && state < 4){
if (!err) {
if (state > 0 && state < 4)
printf("device_status : %s %d%% completed\n", dev_status[state], log.rebuild_percent);
}
else{
else
printf("device_status : %s\n", dev_status[state]);
}
}
else {
} else {
goto exit;
}
printf("dev_status_up : %s\n", dev_status[log.dev_status_up]);
printf("cap_aged : %s\n", log.cap_aged == 1 ? "True" : "False");
printf("cap_aged_ratio : %d%%\n", log.cap_aged_ratio < 100 ? log.cap_aged_ratio : 100);
@ -188,12 +183,10 @@ static int get_status(int argc, char **argv, struct command *cmd, struct plugin
printf("fw_loader_version : %.*s\n", 8, log.fw_loader_version);
printf("uefi_driver_version : %.*s\n", 8, log.uefi_driver_version);
if (log.pcie_volt_status < sizeof(volt_status) / sizeof(const char *)){
if (log.pcie_volt_status < sizeof(volt_status) / sizeof(const char *))
printf("pcie_volt_status : %s\n", volt_status[log.pcie_volt_status]);
}
else{
else
printf("pcie_volt_status : Unknown\n");
}
printf("current_pcie_volt : %d mV\n", log.current_pcie_volt[1] << 8 | log.current_pcie_volt[0]);
printf("init_pcie_volt_low_cnt : %d\n", log.init_pcie_volt_low[1] << 8 | log.init_pcie_volt_low[0]);

View file

@ -121,7 +121,7 @@ static int fdp_usage(int argc, char **argv, struct command *cmd, struct plugin *
};
struct config cfg = {
.egid = 0,
.egid = 0,
.output_format = "normal",
.raw_binary = false,
};
@ -192,7 +192,7 @@ static int fdp_stats(int argc, char **argv, struct command *cmd, struct plugin *
};
struct config cfg = {
.egid = 0,
.egid = 0,
.output_format = "normal",
.raw_binary = false,
};
@ -251,8 +251,8 @@ static int fdp_events(int argc, char **argv, struct command *cmd, struct plugin
};
struct config cfg = {
.egid = 0,
.host_events = false,
.egid = 0,
.host_events = false,
.output_format = "normal",
.raw_binary = false,
};
@ -424,9 +424,8 @@ static int fdp_update(int argc, char **argv, struct command *cmd, struct plugin
}
}
for (unsigned int i = 0; i < npids; i++) {
for (unsigned int i = 0; i < npids; i++)
buf[i] = cpu_to_le16(pids[i]);
}
err = nvme_fdp_reclaim_unit_handle_update(dev_fd(dev), cfg.namespace_id, npids, buf);
if (err) {
@ -449,6 +448,7 @@ static int fdp_set_events(int argc, char **argv, struct command *cmd, struct plu
const char *enable = "Enable/disable event";
const char *event_types = "Comma-separated list of event types";
const char *ph = "Placement Handle";
const char *save = "specifies that the controller shall save the attribute";
struct nvme_dev *dev;
int err = -1;
@ -458,19 +458,22 @@ static int fdp_set_events(int argc, char **argv, struct command *cmd, struct plu
struct config {
__u32 namespace_id;
__u16 ph;
char *event_types;
bool enable;
__u16 ph;
char *event_types;
bool enable;
bool save;
};
struct config cfg = {
.enable = false,
.enable = false,
.save = false,
};
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
OPT_SHRT("placement-handle", 'p', &cfg.ph, ph),
OPT_FLAG("enable", 'e', &cfg.enable, enable),
OPT_FLAG("save", 's', &cfg.save, save),
OPT_LIST("event-types", 't', &cfg.event_types, event_types),
OPT_END()
};
@ -506,14 +509,14 @@ static int fdp_set_events(int argc, char **argv, struct command *cmd, struct plu
}
}
for (unsigned int i = 0; i < nev; i++) {
for (unsigned int i = 0; i < nev; i++)
buf[i] = (__u8)evts[i];
}
struct nvme_set_features_args args = {
.args_size = sizeof(args),
.fd = dev_fd(dev),
.fid = NVME_FEAT_FID_FDP_EVENTS,
.save = cfg.save,
.nsid = cfg.namespace_id,
.cdw11 = (nev << 16) | cfg.ph,
.cdw12 = cfg.enable ? 0x1 : 0x0,

View file

@ -47,9 +47,9 @@
struct huawei_list_item {
char node[1024];
struct nvme_id_ctrl ctrl;
unsigned nsid;
unsigned int nsid;
struct nvme_id_ns ns;
unsigned block;
unsigned int block;
char ns_name[NS_NAME_LEN];
char array_name[ARRAY_NAME_LEN];
bool huawei_device;
@ -98,23 +98,19 @@ static int huawei_get_nvme_info(int fd, struct huawei_list_item *item, const cha
item->block = S_ISBLK(nvme_stat_info.st_mode);
if (item->ns.vs[0] == 0) {
len = snprintf(item->ns_name, NS_NAME_LEN, "%s", "----");
if (len < 0)
return -EINVAL;
}
else {
} else {
memcpy(item->ns_name, item->ns.vs, NS_NAME_LEN);
item->ns_name[NS_NAME_LEN - 1] = '\0';
}
if (item->ctrl.vs[0] == 0) {
len = snprintf(item->array_name, ARRAY_NAME_LEN, "%s", "----");
if (len < 0)
if (len < 0)
return -EINVAL;
}
else {
} else {
memcpy(item->array_name, item->ctrl.vs, ARRAY_NAME_LEN);
item->array_name[ARRAY_NAME_LEN - 1] = '\0';
}
@ -123,9 +119,8 @@ static int huawei_get_nvme_info(int fd, struct huawei_list_item *item, const cha
static void format(char *formatter, size_t fmt_sz, char *tofmt, size_t tofmtsz)
{
fmt_sz = snprintf(formatter, fmt_sz, "%-*.*s", (int)tofmtsz, (int)tofmtsz, tofmt);
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') {
@ -137,7 +132,7 @@ static void format(char *formatter, size_t fmt_sz, char *tofmt, size_t tofmtsz)
}
static void huawei_json_print_list_items(struct huawei_list_item *list_items,
unsigned len)
unsigned int len)
{
struct json_object *root;
struct json_object *devices;
@ -210,8 +205,9 @@ static void huawei_print_list_item(struct huawei_list_item *list_item,
struct huawei_list_element_len element_len)
{
__u8 lba_index;
nvme_id_ns_flbas_to_lbaf_inuse(list_item->ns.flbas, &lba_index);
unsigned long long int lba = 1ULL << list_item->ns.lbaf[lba_index].ds;
unsigned long long lba = 1ULL << list_item->ns.lbaf[lba_index].ds;
double nsze = le64_to_cpu(list_item->ns.nsze) * lba;
double nuse = le64_to_cpu(list_item->ns.nuse) * lba;
@ -223,8 +219,7 @@ static void huawei_print_list_item(struct huawei_list_item *list_item,
char *nguid = nguid_buf;
int i;
sprintf(usage,"%6.2f %2sB / %6.2f %2sB", nuse, u_suffix,
nsze, s_suffix);
sprintf(usage, "%6.2f %2sB / %6.2f %2sB", nuse, u_suffix, nsze, s_suffix);
memset(nguid, 0, sizeof(nguid_buf));
for (i = 0; i < sizeof(list_item->ns.nguid); i++)
@ -247,37 +242,37 @@ static unsigned int choose_len(unsigned int old_len, unsigned int cur_len, unsig
temp_len = (cur_len > default_len) ? cur_len : default_len;
if (temp_len > old_len)
{
return temp_len;
}
return old_len;
}
static unsigned int huawei_get_ns_len(struct huawei_list_item *list_items, unsigned len, unsigned default_len)
static unsigned int huawei_get_ns_len(struct huawei_list_item *list_items, unsigned int len,
unsigned int default_len)
{
int i;
unsigned int min_len = default_len;
for (i = 0 ; i < len ; i++)
min_len = choose_len(min_len , strlen(list_items->ns_name), default_len);
min_len = choose_len(min_len, strlen(list_items->ns_name), default_len);
return min_len;
}
static int huawei_get_array_len(struct huawei_list_item *list_items, unsigned len, unsigned default_len)
static int huawei_get_array_len(struct huawei_list_item *list_items, unsigned int len,
unsigned int default_len)
{
int i;
int min_len = default_len;
for (i = 0 ; i < len ; i++)
min_len = choose_len(min_len , strlen(list_items->array_name), default_len);
min_len = choose_len(min_len, strlen(list_items->array_name), default_len);
return min_len;
}
static void huawei_print_list_items(struct huawei_list_item *list_items, unsigned len)
static void huawei_print_list_items(struct huawei_list_item *list_items, unsigned int len)
{
unsigned i;
unsigned int i;
struct huawei_list_element_len element_len;
element_len.node = 16;
@ -350,13 +345,12 @@ static int huawei_list(int argc, char **argv, struct command *command,
close(fd);
goto out_free_list_items;
}
if (list_items[huawei_num].huawei_device == true) {
if (list_items[huawei_num].huawei_device == true)
huawei_num++;
}
close(fd);
}
if (huawei_num > 0){
if (huawei_num > 0) {
if (fmt == JSON)
huawei_json_print_list_items(list_items, huawei_num);
else

View file

@ -146,11 +146,13 @@ static int nvme_vucmd(int fd, unsigned char opcode, unsigned int cdw12,
memset(&cmd, 0, sizeof(cmd));
cmd.opcode = opcode;
cmd.cdw2 = IGVSC_SIG;
cmd.cdw10 = data_len / 4;
cmd.cdw12 = cdw12;
cmd.cdw13 = cdw13;
cmd.cdw14 = cdw14;
cmd.cdw15 = cdw15;
cmd.nsid = 0;
cmd.nsid = 0xffffffff;
cmd.addr = (__u64)(__u64)(uintptr_t)data;
cmd.data_len = data_len;
return nvme_submit_admin_passthru(fd, &cmd, NULL);
@ -198,8 +200,8 @@ static int innogrit_vsc_geteventlog(int argc, char **argv,
ret = nvme_vucmd(dev_fd(dev), 0xFE, 0x82, 0x03, 0x00, 0x00, (char *)data, 4096);
if (ret == -1)
return ret;
if (data[0] == 0x5A)
if (data[0] == 0x5A)
ivsctype = 1;
else
ivsctype = 0;
@ -227,8 +229,9 @@ static int innogrit_vsc_geteventlog(int argc, char **argv,
icount++;
memset(data, 0, 4096);
if (ivsctype == 1)
ret = nvme_vucmd(dev_fd(dev), 0xFE, 0x60, 0x00, 0x00, 0x00,(char *)data, 4096);
if (ivsctype == 1)
ret = nvme_vucmd(dev_fd(dev), 0xFE, 0x60, 0x00, 0x00, 0x00, (char *)data,
4096);
else
ret = nvme_vucmd(dev_fd(dev), NVME_VSC_GET_EVENT_LOG, 0, 0,
(SRB_SIGNATURE >> 32),
@ -345,10 +348,10 @@ static int innogrit_vsc_getcdump(int argc, char **argv, struct command *command,
ret = nvme_vucmd(dev_fd(dev), 0xFE, 0x82, 0x03, 0x00, 0x00, (char *)data, 4096);
if (ret == -1)
return ret;
if (data[0] == 0x5A) {
ivsctype = 1;
ret = nvme_vucmd(dev_fd(dev), 0xFE, 0x82, 0x08, 0x00, 0x00,(char *)data, 4096);
ret = nvme_vucmd(dev_fd(dev), 0xFE, 0x82, 0x08, 0x00, 0x00, (char *)data, 4096);
} else {
ivsctype = 0;
ret = nvme_vucmd(dev_fd(dev), NVME_VSC_GET, VSC_FN_GET_CDUMP, 0x00,
@ -403,12 +406,13 @@ static int innogrit_vsc_getcdump(int argc, char **argv, struct command *command,
for (icur = 0; icur < itotal; icur += 4096) {
memset(data, 0, 4096);
if (busevsc) {
if (ivsctype == 1)
ret = nvme_vucmd(dev_fd(dev), 0xFE, 0x82, 0x08, 0x00, 0x00,(char *)data, 4096);
if (ivsctype == 1)
ret = nvme_vucmd(dev_fd(dev), 0xFE, 0x82, 0x08, 0x00, 0x00,
(char *)data, 4096);
else
ret = nvme_vucmd(dev_fd(dev), NVME_VSC_GET, VSC_FN_GET_CDUMP, 0x00,
(SRB_SIGNATURE >> 32), (SRB_SIGNATURE & 0xFFFFFFFF),
(char *)data, 4096);
(char *)data, 4096);
} else {
ret = nvme_get_nsid_log(dev_fd(dev), true,
0x07,
@ -429,12 +433,13 @@ static int innogrit_vsc_getcdump(int argc, char **argv, struct command *command,
if (ipackindex != ipackcount) {
memset(data, 0, 4096);
if (busevsc) {
if (ivsctype == 1)
ret = nvme_vucmd(dev_fd(dev), 0xFE, 0x82, 0x08, 0x00, 0x00,(char *)data, 4096);
if (ivsctype == 1)
ret = nvme_vucmd(dev_fd(dev), 0xFE, 0x82, 0x08, 0x00, 0x00,
(char *)data, 4096);
else
ret = nvme_vucmd(dev_fd(dev), NVME_VSC_GET, VSC_FN_GET_CDUMP, 0x00,
(SRB_SIGNATURE >> 32), (SRB_SIGNATURE & 0xFFFFFFFF),
(char *)data, 4096);
(char *)data, 4096);
} else {
ret = nvme_get_nsid_log(dev_fd(dev), true,
0x07,

View file

@ -7,6 +7,7 @@
#define NVME_VSC_GET 0xE6
#define VSC_FN_GET_CDUMP 0x08
#define EVLOG_SIG 0x65766C67
#define IGVSC_SIG 0x69677673
#define SRB_SIGNATURE 0x544952474F4E4E49ULL
#define XCLEAN_LINE "\033[K"

View file

@ -23,215 +23,211 @@
void show_r1_vendor_log(r1_cli_vendor_log_t *vendorlog)
{
int i = 0;
int i = 0;
if (vendorlog->device_state == 0) {
printf("device_state : [healthy]\n");
} else {
printf("device_state : [warning]\n");
}
if (vendorlog->device_state == 0)
printf("device_state : [healthy]\n");
else
printf("device_state : [warning]\n");
printf("commit id : %s\n", vendorlog->commit_id);
printf("mcu data id(mcu) : 0x%x\n", le32_to_cpu(vendorlog->mcu_data_id));
printf("power_info(mcu) : %u mW\n", le32_to_cpu(vendorlog->power_info));
printf("voltage_info(mcu) : %u mV\n", le32_to_cpu(vendorlog->voltage_info));
printf("current_info(mcu) : %u mA\n", le32_to_cpu(vendorlog->current_info));
printf("history max_power(mcu) : %u mW\n", le32_to_cpu(vendorlog->max_power));
printf("disk_max_temper(mcu) : %d C\n", le32_to_cpu(vendorlog->disk_max_temper) - 273);
printf("disk_overtemper_cout(mcu) : %u\n", le32_to_cpu(vendorlog->disk_overtemper_cout));
printf("ctrl_max_temper(mcu) : %d C\n", le32_to_cpu(vendorlog->ctrl_max_temper) - 273);
printf("ctrl_overtemper_cout(mcu) : %u\n", le32_to_cpu(vendorlog->ctrl_overtemper_cout));
printf("nand_max_temper(mcu) : %d C\n", le32_to_cpu(vendorlog->nand_max_temper) - 273);
printf("nand_overtemper_cout(mcu) : %u\n", le32_to_cpu(vendorlog->nand_overtemper_cout));
printf("commit id : %s\n", vendorlog->commit_id);
printf("mcu data id(mcu) : 0x%x\n", le32_to_cpu(vendorlog->mcu_data_id));
printf("power_info(mcu) : %u mW\n", le32_to_cpu(vendorlog->power_info));
printf("voltage_info(mcu) : %u mV\n", le32_to_cpu(vendorlog->voltage_info));
printf("current_info(mcu) : %u mA\n", le32_to_cpu(vendorlog->current_info));
printf("history max_power(mcu) : %u mW\n", le32_to_cpu(vendorlog->max_power));
printf("disk_max_temper(mcu) : %d C\n", le32_to_cpu(vendorlog->disk_max_temper) - 273);
printf("disk_overtemper_cout(mcu) : %u\n", le32_to_cpu(vendorlog->disk_overtemper_cout));
printf("ctrl_max_temper(mcu) : %d C\n", le32_to_cpu(vendorlog->ctrl_max_temper) - 273);
printf("ctrl_overtemper_cout(mcu) : %u\n", le32_to_cpu(vendorlog->ctrl_overtemper_cout));
printf("nand_max_temper(mcu) : %d C\n", le32_to_cpu(vendorlog->nand_max_temper) - 273);
printf("nand_overtemper_cout(mcu) : %u\n", le32_to_cpu(vendorlog->nand_overtemper_cout));
for (i = 0; i < 4; i++) {
printf("temperature[%d](mcu) : %d C\n", i, le32_to_cpu(vendorlog->current_temp[i]) - 273);
}
for (i = 0; i < 4; i++)
printf("temperature[%d](mcu) : %d C\n", i, le32_to_cpu(vendorlog->current_temp[i]) - 273);
printf("CAP Time from 32v to 27v(mcu) : %u ms\n", le32_to_cpu(vendorlog->cap_transtime.cap_trans_time1));
printf("CAP Time from 27v to 10v(mcu) : %u ms\n", le32_to_cpu(vendorlog->cap_transtime.cap_trans_time2));
printf("cap_health_state(mcu) : %u\n", le32_to_cpu(vendorlog->cap_health_state));
printf("warning bit(mcu) : 0x%x%08x\n", le32_to_cpu(vendorlog->detail_warning[1]),
le32_to_cpu(vendorlog->detail_warning[0]));
printf("-->high_format_fail : %x\n", vendorlog->detail_warning_bit.high_format_fail);
printf("-->low_format_fail : %x\n", vendorlog->detail_warning_bit.low_format_fail);
printf("-->current sensor : %x\n", vendorlog->detail_warning_bit.self_test_fail1);
printf("-->nand temp sensor : %x\n", vendorlog->detail_warning_bit.self_test_fail2);
printf("-->board temp sensor : %x\n", vendorlog->detail_warning_bit.self_test_fail3);
printf("-->cntl temp sensor : %x\n", vendorlog->detail_warning_bit.self_test_fail4);
printf("-->cap_timer_test_fail : %x\n", vendorlog->detail_warning_bit.capacitance_test_fail);
printf("-->readOnly_after_rebuild : %x\n", vendorlog->detail_warning_bit.readOnly_after_rebuild);
printf("-->firmware_loss : %x\n", vendorlog->detail_warning_bit.firmware_loss);
printf("-->cap_self_test : %x\n", vendorlog->detail_warning_bit.cap_unsupply);
printf("-->spare_space_warning : %x\n", vendorlog->detail_warning_bit.spare_space_warning);
printf("-->lifetime_warning : %x\n", vendorlog->detail_warning_bit.lifetime_warning);
printf("-->temp_high_warning : %x\n", vendorlog->detail_warning_bit.temp_high_warning);
printf("-->temp_low_warning : %x\n", vendorlog->detail_warning_bit.temp_low_warning);
printf("-->mcu_disable(mcu) : %x\n", vendorlog->detail_warning_bit.mcu_disable);
printf("warning history bit(mcu) : 0x%x%08x\n", le32_to_cpu(vendorlog->detail_warning_his[1]),
le32_to_cpu(vendorlog->detail_warning_his[0]));
printf("-->high_format_fail : %x\n", vendorlog->detail_warning_his_bit.high_format_fail);
printf("-->low_format_fail : %x\n", vendorlog->detail_warning_his_bit.low_format_fail);
printf("-->current sensor : %x\n", vendorlog->detail_warning_his_bit.self_test_fail1);
printf("-->nand temp sensor : %x\n", vendorlog->detail_warning_his_bit.self_test_fail2);
printf("-->board temp sensor : %x\n", vendorlog->detail_warning_his_bit.self_test_fail3);
printf("-->cntl temp sensor : %x\n", vendorlog->detail_warning_his_bit.self_test_fail4);
printf("-->cap_timer_test_fail : %x\n", vendorlog->detail_warning_his_bit.capacitance_test_fail);
printf("-->readOnly_after_rebuild : %x\n", vendorlog->detail_warning_his_bit.readOnly_after_rebuild);
printf("-->firmware_loss : %x\n", vendorlog->detail_warning_his_bit.firmware_loss);
printf("-->cap_self_test : %x\n", vendorlog->detail_warning_his_bit.cap_unsupply);
printf("-->spare_space_warning : %x\n", vendorlog->detail_warning_his_bit.spare_space_warning);
printf("-->lifetime_warning : %x\n", vendorlog->detail_warning_his_bit.lifetime_warning);
printf("-->temp_high_warning : %x\n", vendorlog->detail_warning_his_bit.temp_high_warning);
printf("-->temp_low_warning : %x\n", vendorlog->detail_warning_his_bit.temp_low_warning);
printf("-->mcu_disable(mcu) : %x\n", vendorlog->detail_warning_his_bit.mcu_disable);
printf("CAP Time from 32v to 27v(mcu) : %u ms\n", le32_to_cpu(vendorlog->cap_transtime.cap_trans_time1));
printf("CAP Time from 27v to 10v(mcu) : %u ms\n", le32_to_cpu(vendorlog->cap_transtime.cap_trans_time2));
printf("cap_health_state(mcu) : %u\n", le32_to_cpu(vendorlog->cap_health_state));
printf("warning bit(mcu) : 0x%x%08x\n", le32_to_cpu(vendorlog->detail_warning[1]),
le32_to_cpu(vendorlog->detail_warning[0]));
printf("-->high_format_fail : %x\n", vendorlog->detail_warning_bit.high_format_fail);
printf("-->low_format_fail : %x\n", vendorlog->detail_warning_bit.low_format_fail);
printf("-->current sensor : %x\n", vendorlog->detail_warning_bit.self_test_fail1);
printf("-->nand temp sensor : %x\n", vendorlog->detail_warning_bit.self_test_fail2);
printf("-->board temp sensor : %x\n", vendorlog->detail_warning_bit.self_test_fail3);
printf("-->cntl temp sensor : %x\n", vendorlog->detail_warning_bit.self_test_fail4);
printf("-->cap_timer_test_fail : %x\n", vendorlog->detail_warning_bit.capacitance_test_fail);
printf("-->readOnly_after_rebuild : %x\n", vendorlog->detail_warning_bit.readOnly_after_rebuild);
printf("-->firmware_loss : %x\n", vendorlog->detail_warning_bit.firmware_loss);
printf("-->cap_self_test : %x\n", vendorlog->detail_warning_bit.cap_unsupply);
printf("-->spare_space_warning : %x\n", vendorlog->detail_warning_bit.spare_space_warning);
printf("-->lifetime_warning : %x\n", vendorlog->detail_warning_bit.lifetime_warning);
printf("-->temp_high_warning : %x\n", vendorlog->detail_warning_bit.temp_high_warning);
printf("-->temp_low_warning : %x\n", vendorlog->detail_warning_bit.temp_low_warning);
printf("-->mcu_disable(mcu) : %x\n", vendorlog->detail_warning_bit.mcu_disable);
printf("warning history bit(mcu) : 0x%x%08x\n", le32_to_cpu(vendorlog->detail_warning_his[1]),
le32_to_cpu(vendorlog->detail_warning_his[0]));
printf("-->high_format_fail : %x\n", vendorlog->detail_warning_his_bit.high_format_fail);
printf("-->low_format_fail : %x\n", vendorlog->detail_warning_his_bit.low_format_fail);
printf("-->current sensor : %x\n", vendorlog->detail_warning_his_bit.self_test_fail1);
printf("-->nand temp sensor : %x\n", vendorlog->detail_warning_his_bit.self_test_fail2);
printf("-->board temp sensor : %x\n", vendorlog->detail_warning_his_bit.self_test_fail3);
printf("-->cntl temp sensor : %x\n", vendorlog->detail_warning_his_bit.self_test_fail4);
printf("-->cap_timer_test_fail : %x\n", vendorlog->detail_warning_his_bit.capacitance_test_fail);
printf("-->readOnly_after_rebuild : %x\n", vendorlog->detail_warning_his_bit.readOnly_after_rebuild);
printf("-->firmware_loss : %x\n", vendorlog->detail_warning_his_bit.firmware_loss);
printf("-->cap_self_test : %x\n", vendorlog->detail_warning_his_bit.cap_unsupply);
printf("-->spare_space_warning : %x\n", vendorlog->detail_warning_his_bit.spare_space_warning);
printf("-->lifetime_warning : %x\n", vendorlog->detail_warning_his_bit.lifetime_warning);
printf("-->temp_high_warning : %x\n", vendorlog->detail_warning_his_bit.temp_high_warning);
printf("-->temp_low_warning : %x\n", vendorlog->detail_warning_his_bit.temp_low_warning);
printf("-->mcu_disable(mcu) : %x\n", vendorlog->detail_warning_his_bit.mcu_disable);
for (i = 0; i < 4; i++) {
printf("[%d]nand_bytes_written : %" PRIu64 " GB\n", i, le64_to_cpu(vendorlog->nand_bytes_written[i]));
}
for (i = 0; i < 4; i++)
printf("[%d]nand_bytes_written : %" PRIu64 " GB\n", i, le64_to_cpu(vendorlog->nand_bytes_written[i]));
for (i = 0; i < 4; i++) {
printf("[%d]io_apptag_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_apptag_err));
printf("[%d]io_guard_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_guard_err));
printf("[%d]io_reftag_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_reftag_err));
printf("[%d]io_read_fail_cout : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_read_fail_cout));
printf("[%d]io_write_fail_cout : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_write_fail_cout));
printf("[%d]io_dma_disable_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_dma_disable_err));
printf("[%d]io_dma_fatal_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_dma_fatal_err));
printf("[%d]io_dma_linkdown_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_dma_linkdown_err));
printf("[%d]io_dma_timeout_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_dma_timeout_err));
printf("[%d]lba_err[0] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[0]));
printf("[%d]lba_err[1] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[1]));
printf("[%d]lba_err[2] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[2]));
printf("[%d]lba_err[3] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[3]));
printf("[%d]lba_err[4] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[4]));
printf("[%d]lba_err[5] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[5]));
}
for (i = 0; i < 4; i++) {
printf("[%d]io_apptag_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_apptag_err));
printf("[%d]io_guard_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_guard_err));
printf("[%d]io_reftag_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_reftag_err));
printf("[%d]io_read_fail_cout : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_read_fail_cout));
printf("[%d]io_write_fail_cout : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_write_fail_cout));
printf("[%d]io_dma_disable_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_dma_disable_err));
printf("[%d]io_dma_fatal_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_dma_fatal_err));
printf("[%d]io_dma_linkdown_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_dma_linkdown_err));
printf("[%d]io_dma_timeout_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_dma_timeout_err));
printf("[%d]lba_err[0] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[0]));
printf("[%d]lba_err[1] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[1]));
printf("[%d]lba_err[2] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[2]));
printf("[%d]lba_err[3] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[3]));
printf("[%d]lba_err[4] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[4]));
printf("[%d]lba_err[5] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[5]));
}
printf("temp_throttle_per : %u\n", le32_to_cpu(vendorlog->temp_throttle_per));
printf("port0_flreset_cnt : %" PRIu64 "\n", le64_to_cpu(vendorlog->port0_fundamental_reset_cnt));
printf("port0_hot_reset_cnt : %" PRIu64 "\n", le64_to_cpu(vendorlog->port0_hot_reset_cnt));
printf("port0_func_reset_cnt : %" PRIu64 "\n", le64_to_cpu(vendorlog->port0_func_reset_cnt));
printf("port0_linkdown_cnt : %" PRIu64 "\n", le64_to_cpu(vendorlog->port0_linkdown_cnt));
printf("port0_ctrl_reset_cnt : %" PRIu64 "\n", le64_to_cpu(vendorlog->port0_ctrl_reset_cnt));
printf("ces_RcvErr_cnt : %u\n", le32_to_cpu(vendorlog->ces_RcvErr_cnt));
printf("ces_BadTlp_cnt : %u\n", le32_to_cpu(vendorlog->ces_BadTlp_cnt));
printf("ces_BadDllp_cnt : %u\n", le32_to_cpu(vendorlog->ces_BadDllp_cnt));
printf("ces_Rplyover_cnt : %u\n", le32_to_cpu(vendorlog->ces_Rplyover_cnt));
printf("ces_RplyTo_cnt : %u\n", le32_to_cpu(vendorlog->ces_RplyTo_cnt));
printf("ces_Hlo_cnt : %u\n", le32_to_cpu(vendorlog->ces_Hlo_cnt));
printf("scan doorbell err cnt : %u\n", le32_to_cpu(vendorlog->scan_db_err_cnt));
printf("doorbell interrupt err cnt : %u\n", le32_to_cpu(vendorlog->db_int_err_cnt));
printf("temp_throttle_per : %u\n", le32_to_cpu(vendorlog->temp_throttle_per));
printf("port0_flreset_cnt : %" PRIu64 "\n", le64_to_cpu(vendorlog->port0_fundamental_reset_cnt));
printf("port0_hot_reset_cnt : %" PRIu64 "\n", le64_to_cpu(vendorlog->port0_hot_reset_cnt));
printf("port0_func_reset_cnt : %" PRIu64 "\n", le64_to_cpu(vendorlog->port0_func_reset_cnt));
printf("port0_linkdown_cnt : %" PRIu64 "\n", le64_to_cpu(vendorlog->port0_linkdown_cnt));
printf("port0_ctrl_reset_cnt : %" PRIu64 "\n", le64_to_cpu(vendorlog->port0_ctrl_reset_cnt));
printf("ces_RcvErr_cnt : %u\n", le32_to_cpu(vendorlog->ces_RcvErr_cnt));
printf("ces_BadTlp_cnt : %u\n", le32_to_cpu(vendorlog->ces_BadTlp_cnt));
printf("ces_BadDllp_cnt : %u\n", le32_to_cpu(vendorlog->ces_BadDllp_cnt));
printf("ces_Rplyover_cnt : %u\n", le32_to_cpu(vendorlog->ces_Rplyover_cnt));
printf("ces_RplyTo_cnt : %u\n", le32_to_cpu(vendorlog->ces_RplyTo_cnt));
printf("ces_Hlo_cnt : %u\n", le32_to_cpu(vendorlog->ces_Hlo_cnt));
printf("scan doorbell err cnt : %u\n", le32_to_cpu(vendorlog->scan_db_err_cnt));
printf("doorbell interrupt err cnt : %u\n", le32_to_cpu(vendorlog->db_int_err_cnt));
printf("------------ncm-----------------------\n");
for (i = 0; i < 4; i++) {
printf("------------part%d-----------------------\n", i);
printf("[%d]nand_rd_unc_count : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_rd_unc_cnt));
printf("[%d]nand_rd_srr_count : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_rd_srr_cnt));
printf("[%d]nand_rd_sdecode_count : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_rd_soft_decode_cnt));
printf("[%d]nand_rd_rb_fail_count : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_rd_rebuild_fail_cnt));
printf("[%d]nand_prg_fail_count : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_prg_fail_cnt));
printf("[%d]nand_eras_fail_count : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_eras_fail_cnt));
printf("[%d]nand_rd_count : %" PRIu64 "\n", i,
le64_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_rd_cnt));
printf("[%d]nand_prg_count : %" PRIu64 "\n", i,
le64_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_prg_cnt));
printf("[%d]nand_eras_count : %" PRIu64 "\n", i,
le64_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_eras_cnt));
printf("[%d]BE_scan_unc_count : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].BE_scan_unc_cnt));
printf("[%d]rebuild_req_cnt : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].rebuild_req_cnt));
printf("[%d]retry_req_cnt : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].retry_req_cnt));
printf("[%d]retry_success_cnt : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].retry_success_cnt));
printf("[%d]prg_badblk_num : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].prg_badblk_num));
printf("[%d]eras_badblk_num : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].eras_badblk_num));
printf("[%d]read_badblk_num : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].unc_badblk_num));
}
printf("------------ncm-----------------------\n");
for (i = 0; i < 4; i++) {
printf("------------part%d-----------------------\n", i);
printf("[%d]nand_rd_unc_count : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_rd_unc_cnt));
printf("[%d]nand_rd_srr_count : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_rd_srr_cnt));
printf("[%d]nand_rd_sdecode_count : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_rd_soft_decode_cnt));
printf("[%d]nand_rd_rb_fail_count : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_rd_rebuild_fail_cnt));
printf("[%d]nand_prg_fail_count : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_prg_fail_cnt));
printf("[%d]nand_eras_fail_count : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_eras_fail_cnt));
printf("[%d]nand_rd_count : %" PRIu64 "\n", i,
le64_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_rd_cnt));
printf("[%d]nand_prg_count : %" PRIu64 "\n", i,
le64_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_prg_cnt));
printf("[%d]nand_eras_count : %" PRIu64 "\n", i,
le64_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_eras_cnt));
printf("[%d]BE_scan_unc_count : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].BE_scan_unc_cnt));
printf("[%d]rebuild_req_cnt : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].rebuild_req_cnt));
printf("[%d]retry_req_cnt : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].retry_req_cnt));
printf("[%d]retry_success_cnt : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].retry_success_cnt));
printf("[%d]prg_badblk_num : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].prg_badblk_num));
printf("[%d]eras_badblk_num : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].eras_badblk_num));
printf("[%d]read_badblk_num : %u\n", i,
le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].unc_badblk_num));
}
printf("[%d]temp_ctrl_limit_count : %u\n", i, le32_to_cpu(vendorlog->temp_ctrl_limit_cnt));
printf("[%d]temp_ctrl_stop_count : %u\n", i, le32_to_cpu(vendorlog->temp_ctrl_stop_cnt));
printf("------------wlm-----------------------\n");
for (i = 0; i < 4; i++) {
printf("------------part%d-----------------------\n", i);
printf("[%d]fbb_count : %u\n", i,
le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].fbb_count));
printf("[%d]ebb_count : %u\n", i,
le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].ebb_count));
printf("[%d]lbb_count : %u\n", i,
le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].lbb_count));
printf("[%d]gc_read_count : %u\n", i,
le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].gc_read_count));
printf("[%d]gc_write_count : %u\n", i,
le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].gc_write_count));
printf("[%d]gc_write_fail_count : %u\n", i,
le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].gc_write_fail_count));
printf("[%d]force_gc_count : %u\n", i,
le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].force_gc_count));
printf("[%d]avg_pe_count : %u\n", i,
le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].avg_pe_count));
printf("[%d]max_pe_count : %u\n", i,
le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].max_pe_count));
printf("[%d]free_blk_num1 : %u\n", i,
le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].free_blk_num1));
printf("[%d]free_blk_num2 : %u\n", i,
le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].free_blk_num2));
}
printf("[%d]temp_ctrl_limit_count : %u\n", i, le32_to_cpu(vendorlog->temp_ctrl_limit_cnt));
printf("[%d]temp_ctrl_stop_count : %u\n", i, le32_to_cpu(vendorlog->temp_ctrl_stop_cnt));
printf("------------wlm-----------------------\n");
for (i = 0; i < 4; i++) {
printf("------------part%d-----------------------\n", i);
printf("[%d]fbb_count : %u\n", i,
le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].fbb_count));
printf("[%d]ebb_count : %u\n", i,
le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].ebb_count));
printf("[%d]lbb_count : %u\n", i,
le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].lbb_count));
printf("[%d]gc_read_count : %u\n", i,
le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].gc_read_count));
printf("[%d]gc_write_count : %u\n", i,
le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].gc_write_count));
printf("[%d]gc_write_fail_count : %u\n", i,
le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].gc_write_fail_count));
printf("[%d]force_gc_count : %u\n", i,
le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].force_gc_count));
printf("[%d]avg_pe_count : %u\n", i,
le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].avg_pe_count));
printf("[%d]max_pe_count : %u\n", i,
le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].max_pe_count));
printf("[%d]free_blk_num1 : %u\n", i,
le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].free_blk_num1));
printf("[%d]free_blk_num2 : %u\n", i,
le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].free_blk_num2));
}
printf("------------lkm-----------------------\n");
printf("[%d]e2e_check_err_count1 : %u\n", i, le32_to_cpu(vendorlog->e2e_check_err_cnt1));
printf("[%d]e2e_check_err_count2 : %u\n", i, le32_to_cpu(vendorlog->e2e_check_err_cnt2));
printf("[%d]e2e_check_err_count3 : %u\n", i, le32_to_cpu(vendorlog->e2e_check_err_cnt3));
printf("[%d]e2e_check_err_count4 : %u\n", i, le32_to_cpu(vendorlog->e2e_check_err_cnt4));
printf("------------lkm-----------------------\n");
printf("[%d]e2e_check_err_count1 : %u\n", i, le32_to_cpu(vendorlog->e2e_check_err_cnt1));
printf("[%d]e2e_check_err_count2 : %u\n", i, le32_to_cpu(vendorlog->e2e_check_err_cnt2));
printf("[%d]e2e_check_err_count3 : %u\n", i, le32_to_cpu(vendorlog->e2e_check_err_cnt3));
printf("[%d]e2e_check_err_count4 : %u\n", i, le32_to_cpu(vendorlog->e2e_check_err_cnt4));
}
void show_r1_media_err_log(r1_cli_vendor_log_t *vendorlog)
{
int i, j;
int i, j;
for (i = 0; i < 4; i++) {
printf("DM%d read err lba:\n", i);
for (j = 0; j < 10; j++) {
printf("[%d]lba : %" PRIu64 "\n", j, le64_to_cpu(vendorlog->media_err[i].lba_err[j]));
}
}
for (i = 0; i < 4; i++) {
printf("DM%d read err lba:\n", i);
for (j = 0; j < 10; j++)
printf("[%d]lba : %" PRIu64 "\n", j, le64_to_cpu(vendorlog->media_err[i].lba_err[j]));
}
}
static int nvme_get_vendor_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
__u8 local_mem[BYTE_OF_4K];
char *desc = "Get the Inspur vendor log";
struct nvme_dev *dev;
int err;
__u8 local_mem[BYTE_OF_4K];
char *desc = "Get the Inspur vendor log";
struct nvme_dev *dev;
int err;
OPT_ARGS(opts) = { OPT_END() };
OPT_ARGS(opts) = { OPT_END() };
err = parse_and_open(&dev, argc, argv, desc, opts);
if (err)
return err;
err = parse_and_open(&dev, argc, argv, desc, opts);
if (err)
return err;
memset(local_mem, 0, BYTE_OF_4K);
err = nvme_get_log_simple(dev_fd(dev),
(enum nvme_cmd_get_log_lid)VENDOR_SMART_LOG_PAGE,
sizeof(r1_cli_vendor_log_t), local_mem);
if (!err) {
show_r1_vendor_log((r1_cli_vendor_log_t *)local_mem);
show_r1_media_err_log((r1_cli_vendor_log_t *)local_mem);
} else {
nvme_show_status(err);
}
memset(local_mem, 0, BYTE_OF_4K);
err = nvme_get_log_simple(dev_fd(dev),
(enum nvme_cmd_get_log_lid)VENDOR_SMART_LOG_PAGE,
sizeof(r1_cli_vendor_log_t), local_mem);
if (!err) {
show_r1_vendor_log((r1_cli_vendor_log_t *)local_mem);
show_r1_media_err_log((r1_cli_vendor_log_t *)local_mem);
} else {
nvme_show_status(err);
}
dev_close(dev);
return err;
dev_close(dev);
return err;
}

View file

@ -16,25 +16,25 @@
#define CREATE_CMD
#include "intel-nvme.h"
struct __attribute__((packed)) nvme_additional_smart_log_item {
struct __packed nvme_additional_smart_log_item {
__u8 key;
__u8 _kp[2];
__u8 norm;
__u8 _np;
union __attribute__((packed)) {
union __packed {
__u8 raw[6];
struct __attribute__((packed)) wear_level {
struct __packed wear_level {
__le16 min;
__le16 max;
__le16 avg;
} wear_level;
struct __attribute__((packed)) thermal_throttle {
struct __packed thermal_throttle {
__u8 pct;
__u32 count;
} thermal_throttle;
} ;
};
__u8 _rp;
} ;
};
struct nvme_additional_smart_log {
struct nvme_additional_smart_log_item program_fail_cnt;
@ -79,7 +79,7 @@ static void json_intel_id_ctrl(struct nvme_vu_id_ctrl_field *id,
struct json_object *root)
{
json_object_add_value_int(root, "ss", id->ss);
json_object_add_value_string(root, "health", health );
json_object_add_value_string(root, "health", health);
json_object_add_value_int(root, "cls", id->cls);
json_object_add_value_int(root, "nlw", id->nlw);
json_object_add_value_int(root, "scap", id->scap);
@ -92,7 +92,7 @@ static void json_intel_id_ctrl(struct nvme_vu_id_ctrl_field *id,
static void intel_id_ctrl(__u8 *vs, struct json_object *root)
{
struct nvme_vu_id_ctrl_field* id = (struct nvme_vu_id_ctrl_field *)vs;
struct nvme_vu_id_ctrl_field *id = (struct nvme_vu_id_ctrl_field *)vs;
char health[21] = { 0 };
char bl[9] = { 0 };
@ -100,15 +100,10 @@ static void intel_id_ctrl(__u8 *vs, struct json_object *root)
char mic_bl[5] = { 0 };
char mic_fw[5] = { 0 };
if (id->health[0]==0)
{
snprintf(health, 21, "%s", "healthy");
}
if (id->health[0] == 0)
snprintf(health, 21, "%s", "healthy");
else
{
snprintf(health, 21, "%s", id->health);
}
snprintf(health, 21, "%s", id->health);
snprintf(bl, 9, "%s", id->bl);
snprintf(ww, 19, "%02X%02X%02X%02X%02X%02X%02X%02X", id->ww[7],
@ -203,57 +198,57 @@ static void show_intel_smart_log_jsn(struct nvme_additional_smart_log *smart,
entry_stats = json_create_object();
json_object_add_value_int(entry_stats, "normalized", smart->retry_buffer_overflow_cnt.norm);
json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->retry_buffer_overflow_cnt.raw));
json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->retry_buffer_overflow_cnt.raw));
json_object_add_value_object(dev_stats, "retry_buffer_overflow_count", entry_stats);
entry_stats = json_create_object();
json_object_add_value_int(entry_stats, "normalized", smart->pll_lock_loss_cnt.norm);
json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->pll_lock_loss_cnt.raw));
json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->pll_lock_loss_cnt.raw));
json_object_add_value_object(dev_stats, "pll_lock_loss_count", entry_stats);
entry_stats = json_create_object();
json_object_add_value_int(entry_stats, "normalized", smart->nand_bytes_written.norm);
json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->nand_bytes_written.raw));
json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->nand_bytes_written.raw));
json_object_add_value_object(dev_stats, "nand_bytes_written", entry_stats);
entry_stats = json_create_object();
json_object_add_value_int(entry_stats, "normalized", smart->host_bytes_written.norm);
json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->host_bytes_written.raw));
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_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_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_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_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_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_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_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);
@ -337,11 +332,11 @@ static void show_intel_smart_log(struct nvme_additional_smart_log *smart,
static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Get Intel vendor specific additional smart log (optionally, "\
"for the specified namespace), and show it.";
const char *desc =
"Get Intel vendor specific additional smart log (optionally, for the specified namespace), and show it.";
const char *namespace = "(optional) desired namespace";
const char *raw = "Dump output in binary format";
const char *json= "Dump output in json format";
const char *json = "Dump output in json format";
struct nvme_additional_smart_log smart_log;
struct nvme_dev *dev;
@ -379,9 +374,9 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
dev->name);
else
d_raw((unsigned char *)&smart_log, sizeof(smart_log));
}
else if (err > 0)
} else if (err > 0) {
nvme_show_status(err);
}
dev_close(dev);
return err;
}
@ -490,7 +485,7 @@ struct intel_lat_stats {
__u32 data[1216];
};
struct __attribute__((__packed__)) optane_lat_stats {
struct __packed optane_lat_stats {
__u16 maj;
__u16 min;
__u64 data[9];
@ -645,7 +640,7 @@ static void show_optane_lat_stats_bucket(struct optane_lat_stats *stats,
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]);
printf("%-*lu\n", COL_WIDTH, (unsigned long)stats->data[i]);
}
@ -888,6 +883,7 @@ static void json_lat_stats_v1000_0(struct optane_lat_stats *stats, int write)
}
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]);
@ -900,12 +896,13 @@ static void json_lat_stats_v1000_0(struct optane_lat_stats *stats, int write)
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,
v1000_bucket.write[i + 1] - 1,
NOINF, i);
show_optane_lat_stats_bucket(stats, v1000_bucket.write[i],
@ -916,7 +913,7 @@ static void show_lat_stats_v1000_0(struct optane_lat_stats *stats, int write)
show_optane_lat_stats_bucket(stats,
v1000_bucket.read[i],
NOINF,
v1000_bucket.read[i + 1] -1,
v1000_bucket.read[i + 1] - 1,
NOINF, i);
show_optane_lat_stats_bucket(stats, v1000_bucket.read[i],
@ -924,7 +921,7 @@ static void show_lat_stats_v1000_0(struct optane_lat_stats *stats, int write)
POSINF, i);
}
printf("Average latency since last reset: %lu us\n", (long unsigned int)stats->data[8]);
printf("Average latency since last reset: %lu us\n", (unsigned long)stats->data[8]);
}
@ -1035,7 +1032,7 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct
const char *desc = "Get Intel Latency Statistics log and show it.";
const char *raw = "Dump output in binary format";
const char *json= "Dump output in json format";
const char *json = "Dump output in json format";
const char *write = "Get write statistics (read default)";
struct config {
@ -1159,11 +1156,11 @@ struct intel_event_header {
};
struct intel_vu_log {
struct intel_vu_version ver;
__u32 header;
__u32 size;
__u32 numcores;
__u8 reserved[4080];
struct intel_vu_version ver;
__u32 header;
__u32 size;
__u32 numcores;
__u8 reserved[4080];
};
struct intel_vu_nlog {
@ -1197,7 +1194,7 @@ struct intel_cd_log {
__u32 reserved2 : 16;
} fields;
__u32 entireDword;
} u;
} u;
};
static void print_intel_nlog(struct intel_vu_nlog *intel_nlog)
@ -1272,7 +1269,7 @@ static int write_header(__u8 *buf, int fd, size_t amnt)
return 0;
}
static int read_header(struct nvme_passthru_cmd *cmd,__u8 *buf, int ioctl_fd,
static int read_header(struct nvme_passthru_cmd *cmd, __u8 *buf, int ioctl_fd,
__u32 dw12, int nsid)
{
memset(cmd, 0, sizeof(*cmd));
@ -1476,7 +1473,7 @@ static int get_internal_log(int argc, char **argv, struct command *command,
if (err)
goto out;
} else if(cfg.log == 0) {
} else if (cfg.log == 0) {
/* If the user selected to read the entire nlog */
if (count > 1)
cdlog.u.fields.selectNlog = i;
@ -1640,7 +1637,7 @@ static int enable_lat_stats_tracking(int argc, char **argv,
break;
default:
printf("%d not supported.\n", option);
return EINVAL;
return -EINVAL;
}
dev_close(dev);
return err;
@ -1697,6 +1694,7 @@ static int set_lat_stats_thresholds(int argc, char **argv,
if (media_version[0] == 1000) {
int thresholds[OPTANE_V1000_BUCKET_LEN] = {0};
num = argconfig_parse_comma_sep_array(cfg.bucket_thresholds,
thresholds,
sizeof(thresholds));

File diff suppressed because it is too large Load diff

View file

@ -2,220 +2,216 @@
#ifndef __MEMBLAZE_UTILS_H__
#define __MEMBLAZE_UTILS_H__
#define SMART_INFO_OLD_SIZE 512
#define SMART_INFO_NEW_SIZE 4096
#define SMART_INFO_OLD_SIZE 512
#define SMART_INFO_NEW_SIZE 4096
#define ID_SIZE 3
#define NM_SIZE 2
#define RAW_SIZE 7
#define ID_SIZE 3
#define NM_SIZE 2
#define RAW_SIZE 7
// Intel Format & new format
/* Raisin Additional smart external ID */
#define RAISIN_SI_VD_PROGRAM_FAIL_ID 0xAB
#define RAISIN_SI_VD_ERASE_FAIL_ID 0xAC
#define RAISIN_SI_VD_WEARLEVELING_COUNT_ID 0xAD
#define RAISIN_SI_VD_E2E_DECTECTION_COUNT_ID 0xB8
#define RAISIN_SI_VD_PCIE_CRC_ERR_COUNT_ID 0xC7
#define RAISIN_SI_VD_TIMED_WORKLOAD_MEDIA_WEAR_ID 0xE2
#define RAISIN_SI_VD_TIMED_WORKLOAD_HOST_READ_ID 0xE3
#define RAISIN_SI_VD_TIMED_WORKLOAD_TIMER_ID 0xE4
#define RAISIN_SI_VD_THERMAL_THROTTLE_STATUS_ID 0xEA
#define RAISIN_SI_VD_RETRY_BUFF_OVERFLOW_COUNT_ID 0xF0
#define RAISIN_SI_VD_PLL_LOCK_LOSS_COUNT_ID 0xF3
#define RAISIN_SI_VD_TOTAL_WRITE_ID 0xF4
#define RAISIN_SI_VD_HOST_WRITE_ID 0xF5
#define RAISIN_SI_VD_SYSTEM_AREA_LIFE_LEFT_ID 0xF6
#define RAISIN_SI_VD_TOTAL_READ_ID 0xFA
#define RAISIN_SI_VD_TEMPT_SINCE_BORN_ID 0xE7
#define RAISIN_SI_VD_POWER_CONSUMPTION_ID 0xE8
#define RAISIN_SI_VD_TEMPT_SINCE_BOOTUP_ID 0xAF
#define RAISIN_SI_VD_POWER_LOSS_PROTECTION_ID 0xEC
#define RAISIN_SI_VD_READ_FAIL_ID 0xF2
#define RAISIN_SI_VD_THERMAL_THROTTLE_TIME_ID 0xEB
#define RAISIN_SI_VD_FLASH_MEDIA_ERROR_ID 0xED
#define RAISIN_SI_VD_PROGRAM_FAIL_ID 0xAB
#define RAISIN_SI_VD_ERASE_FAIL_ID 0xAC
#define RAISIN_SI_VD_WEARLEVELING_COUNT_ID 0xAD
#define RAISIN_SI_VD_E2E_DECTECTION_COUNT_ID 0xB8
#define RAISIN_SI_VD_PCIE_CRC_ERR_COUNT_ID 0xC7
#define RAISIN_SI_VD_TIMED_WORKLOAD_MEDIA_WEAR_ID 0xE2
#define RAISIN_SI_VD_TIMED_WORKLOAD_HOST_READ_ID 0xE3
#define RAISIN_SI_VD_TIMED_WORKLOAD_TIMER_ID 0xE4
#define RAISIN_SI_VD_THERMAL_THROTTLE_STATUS_ID 0xEA
#define RAISIN_SI_VD_RETRY_BUFF_OVERFLOW_COUNT_ID 0xF0
#define RAISIN_SI_VD_PLL_LOCK_LOSS_COUNT_ID 0xF3
#define RAISIN_SI_VD_TOTAL_WRITE_ID 0xF4
#define RAISIN_SI_VD_HOST_WRITE_ID 0xF5
#define RAISIN_SI_VD_SYSTEM_AREA_LIFE_LEFT_ID 0xF6
#define RAISIN_SI_VD_TOTAL_READ_ID 0xFA
#define RAISIN_SI_VD_TEMPT_SINCE_BORN_ID 0xE7
#define RAISIN_SI_VD_POWER_CONSUMPTION_ID 0xE8
#define RAISIN_SI_VD_TEMPT_SINCE_BOOTUP_ID 0xAF
#define RAISIN_SI_VD_POWER_LOSS_PROTECTION_ID 0xEC
#define RAISIN_SI_VD_READ_FAIL_ID 0xF2
#define RAISIN_SI_VD_THERMAL_THROTTLE_TIME_ID 0xEB
#define RAISIN_SI_VD_FLASH_MEDIA_ERROR_ID 0xED
/* Raisin Addtional smart internal ID */
typedef enum
{
/* smart attr following intel */
RAISIN_SI_VD_PROGRAM_FAIL = 0, /* 0xAB */
RAISIN_SI_VD_ERASE_FAIL = 1, /* 0xAC */
RAISIN_SI_VD_WEARLEVELING_COUNT = 2,/* 0xAD */
RAISIN_SI_VD_E2E_DECTECTION_COUNT = 3, /* 0xB8 */
RAISIN_SI_VD_PCIE_CRC_ERR_COUNT = 4, /* 0xC7, 2 port data in one attribute */
RAISIN_SI_VD_TIMED_WORKLOAD_MEDIA_WEAR = 5, /* 0xE2 , unknown definition*/
RAISIN_SI_VD_TIMED_WORKLOAD_HOST_READ = 6, /* 0xE3 , unknown definition */
RAISIN_SI_VD_TIMED_WORKLOAD_TIMER = 7, /* 0xE4 , unknown definition */
RAISIN_SI_VD_THERMAL_THROTTLE_STATUS = 8, /* 0xEA */
RAISIN_SI_VD_RETRY_BUFF_OVERFLOW_COUNT = 9, /* 0xF0, unknown definition*/
RAISIN_SI_VD_PLL_LOCK_LOSS_COUNT = 10, /* 0xF3, unknown definition*/
RAISIN_SI_VD_TOTAL_WRITE = 11, /* 0xF4, unit is 32MiB */
RAISIN_SI_VD_HOST_WRITE = 12, /* 0xF5, unit is 32MiB */
RAISIN_SI_VD_SYSTEM_AREA_LIFE_LEFT = 13, /* 0xF6, unknown definition*/
RAISIN_SI_VD_TOTAL_READ = 14, /* 0xFA, unit is 32MiB */
/* smart attr following intel */
RAISIN_SI_VD_PROGRAM_FAIL = 0, /* 0xAB */
RAISIN_SI_VD_ERASE_FAIL = 1, /* 0xAC */
RAISIN_SI_VD_WEARLEVELING_COUNT = 2,/* 0xAD */
RAISIN_SI_VD_E2E_DECTECTION_COUNT = 3, /* 0xB8 */
RAISIN_SI_VD_PCIE_CRC_ERR_COUNT = 4, /* 0xC7, 2 port data in one attribute */
RAISIN_SI_VD_TIMED_WORKLOAD_MEDIA_WEAR = 5, /* 0xE2 , unknown definition*/
RAISIN_SI_VD_TIMED_WORKLOAD_HOST_READ = 6, /* 0xE3 , unknown definition */
RAISIN_SI_VD_TIMED_WORKLOAD_TIMER = 7, /* 0xE4 , unknown definition */
RAISIN_SI_VD_THERMAL_THROTTLE_STATUS = 8, /* 0xEA */
RAISIN_SI_VD_RETRY_BUFF_OVERFLOW_COUNT = 9, /* 0xF0, unknown definition*/
RAISIN_SI_VD_PLL_LOCK_LOSS_COUNT = 10, /* 0xF3, unknown definition*/
RAISIN_SI_VD_TOTAL_WRITE = 11, /* 0xF4, unit is 32MiB */
RAISIN_SI_VD_HOST_WRITE = 12, /* 0xF5, unit is 32MiB */
RAISIN_SI_VD_SYSTEM_AREA_LIFE_LEFT = 13, /* 0xF6, unknown definition*/
RAISIN_SI_VD_TOTAL_READ = 14, /* 0xFA, unit is 32MiB */
/* smart attr self defined */
RAISIN_SI_VD_TEMPT_SINCE_BORN = 15, /* 0xE7 */
RAISIN_SI_VD_POWER_CONSUMPTION = 16, /* 0xE8 */
RAISIN_SI_VD_TEMPT_SINCE_BOOTUP = 17, /* 0xAF */
RAISIN_SI_VD_POWER_LOSS_PROTECTION = 18, /* 0xEC */
RAISIN_SI_VD_READ_FAIL = 19, /* 0xF2 */
RAISIN_SI_VD_THERMAL_THROTTLE_TIME = 20, /* 0xEB */
RAISIN_SI_VD_FLASH_MEDIA_ERROR = 21, /* 0xED */
RAISIN_SI_VD_SMART_INFO_ITEMS_MAX,
/* smart attr self defined */
RAISIN_SI_VD_TEMPT_SINCE_BORN = 15, /* 0xE7 */
RAISIN_SI_VD_POWER_CONSUMPTION = 16, /* 0xE8 */
RAISIN_SI_VD_TEMPT_SINCE_BOOTUP = 17, /* 0xAF */
RAISIN_SI_VD_POWER_LOSS_PROTECTION = 18, /* 0xEC */
RAISIN_SI_VD_READ_FAIL = 19, /* 0xF2 */
RAISIN_SI_VD_THERMAL_THROTTLE_TIME = 20, /* 0xEB */
RAISIN_SI_VD_FLASH_MEDIA_ERROR = 21, /* 0xED */
RAISIN_SI_VD_SMART_INFO_ITEMS_MAX,
} RAISIN_si_vendor_smart_item_e;
// Memblaze Format & old format
enum {
/*0*/TOTAL_WRITE = 0,
/*1*/TOTAL_READ,
/*2*/THERMAL_THROTTLE,
/*3*/TEMPT_SINCE_RESET,
/*4*/POWER_CONSUMPTION,
/*5*/TEMPT_SINCE_BOOTUP,
/*6*/POWER_LOSS_PROTECTION,
/*7*/WEARLEVELING_COUNT,
/*8*/HOST_WRITE,
/*9*/THERMAL_THROTTLE_CNT,
/*10*/CORRECT_PCIE_PORT0,
/*11*/CORRECT_PCIE_PORT1,
/*12*/REBUILD_FAIL,
/*13*/ERASE_FAIL,
/*14*/PROGRAM_FAIL,
/*15*/READ_FAIL,
/*16*/NR_SMART_ITEMS = RAISIN_SI_VD_SMART_INFO_ITEMS_MAX,
/*0*/TOTAL_WRITE = 0,
/*1*/TOTAL_READ,
/*2*/THERMAL_THROTTLE,
/*3*/TEMPT_SINCE_RESET,
/*4*/POWER_CONSUMPTION,
/*5*/TEMPT_SINCE_BOOTUP,
/*6*/POWER_LOSS_PROTECTION,
/*7*/WEARLEVELING_COUNT,
/*8*/HOST_WRITE,
/*9*/THERMAL_THROTTLE_CNT,
/*10*/CORRECT_PCIE_PORT0,
/*11*/CORRECT_PCIE_PORT1,
/*12*/REBUILD_FAIL,
/*13*/ERASE_FAIL,
/*14*/PROGRAM_FAIL,
/*15*/READ_FAIL,
/*16*/NR_SMART_ITEMS = RAISIN_SI_VD_SMART_INFO_ITEMS_MAX,
};
// Memblaze Format & old format
#pragma pack(push, 1)
struct nvme_memblaze_smart_log_item {
__u8 id[3];
union {
__u8 __nmval[2];
__le16 nmval;
};
union {
__u8 rawval[6];
struct temperature {
__le16 max;
__le16 min;
__le16 curr;
} temperature;
struct power {
__le16 max;
__le16 min;
__le16 curr;
} power;
struct thermal_throttle_mb {
__u8 on;
__u32 count;
} thermal_throttle;
struct temperature_p {
__le16 max;
__le16 min;
} temperature_p;
struct power_loss_protection {
__u8 curr;
} power_loss_protection;
struct wearleveling_count {
__le16 min;
__le16 max;
__le16 avg;
} wearleveling_count;
struct thermal_throttle_cnt {
__u8 active;
__le32 cnt;
} thermal_throttle_cnt;
};
__u8 resv;
__u8 id[3];
union {
__u8 __nmval[2];
__le16 nmval;
};
union {
__u8 rawval[6];
struct temperature {
__le16 max;
__le16 min;
__le16 curr;
} temperature;
struct power {
__le16 max;
__le16 min;
__le16 curr;
} power;
struct thermal_throttle_mb {
__u8 on;
__u32 count;
} thermal_throttle;
struct temperature_p {
__le16 max;
__le16 min;
} temperature_p;
struct power_loss_protection {
__u8 curr;
} power_loss_protection;
struct wearleveling_count {
__le16 min;
__le16 max;
__le16 avg;
} wearleveling_count;
struct thermal_throttle_cnt {
__u8 active;
__le32 cnt;
} thermal_throttle_cnt;
};
__u8 resv;
};
#pragma pack(pop)
struct nvme_memblaze_smart_log {
struct nvme_memblaze_smart_log_item items[NR_SMART_ITEMS];
__u8 resv[SMART_INFO_OLD_SIZE - sizeof(struct nvme_memblaze_smart_log_item) * NR_SMART_ITEMS];
struct nvme_memblaze_smart_log_item items[NR_SMART_ITEMS];
__u8 resv[SMART_INFO_OLD_SIZE - sizeof(struct nvme_memblaze_smart_log_item) * NR_SMART_ITEMS];
};
// Intel Format & new format
struct nvme_p4_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];
/* 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_p4_smart_log
{
struct nvme_p4_smart_log_item itemArr[NR_SMART_ITEMS];
struct nvme_p4_smart_log_item itemArr[NR_SMART_ITEMS];
/**
* change 512 to 4096.
* because micron's getlogpage request,the size of many commands have changed to 4k.
* request size > user malloc size,casuing parameters that are closed in momery are dirty.
*/
__u8 resv[SMART_INFO_NEW_SIZE - sizeof(struct nvme_p4_smart_log_item) * NR_SMART_ITEMS];
/**
* change 512 to 4096.
* because micron's getlogpage request,the size of many commands have changed to 4k.
* request size > user malloc size,casuing parameters that are closed in momery are dirty.
*/
__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)
#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)
#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)
#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)
#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)
#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 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 { \
if (fdi) \
fprintf(fdi, format); \
if (print) \
printf(format); \
} while (0); \
}
#define fPRINT_PARAM1(format) \
do { \
if (fdi) \
fprintf(fdi, format); \
if (print) \
printf(format); \
} while (0)
#define fPRINT_PARAM2(format, value) \
{ \
do { \
if (fdi) \
fprintf(fdi, format, value); \
if (print) \
printf(format, value); \
} while (0); \
}
#define fPRINT_PARAM2(format, value) \
do { \
if (fdi) \
fprintf(fdi, format, value); \
if (print) \
printf(format, value); \
} while (0)
#endif // __MEMBLAZE_UTILS_H__

View file

@ -12,6 +12,7 @@ if json_c_dep.found()
'plugins/intel/intel-nvme.c',
'plugins/memblaze/memblaze-nvme.c',
'plugins/micron/micron-nvme.c',
'plugins/nbft/nbft-plugin.c',
'plugins/netapp/netapp-nvme.c',
'plugins/nvidia/nvidia-nvme.c',
'plugins/scaleflux/sfx-nvme.c',

File diff suppressed because it is too large Load diff

563
plugins/nbft/nbft-plugin.c Normal file
View file

@ -0,0 +1,563 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <errno.h>
#include <stdio.h>
#include <fnmatch.h>
#include "nvme-print.h"
#include "nvme.h"
#include "nbft.h"
#include "libnvme.h"
#include "fabrics.h"
#define CREATE_CMD
#include "nbft-plugin.h"
static const char dash[100] = {[0 ... 98] = '-', [99] = '\0'};
#define PCI_SEGMENT(sbdf) ((sbdf & 0xffff0000) >> 16)
#define PCI_BUS(sbdf) ((sbdf & 0x0000ff00) >> 8)
#define PCI_DEV(sbdf) ((sbdf & 0x000000f8) >> 3)
#define PCI_FUNC(sbdf) ((sbdf & 0x00000007) >> 0)
static const char *pci_sbdf_to_string(__u16 pci_sbdf)
{
static char pcidev[13];
snprintf(pcidev, sizeof(pcidev), "%x:%x:%x.%x",
PCI_SEGMENT(pci_sbdf),
PCI_BUS(pci_sbdf),
PCI_DEV(pci_sbdf),
PCI_FUNC(pci_sbdf));
return pcidev;
}
static char *mac_addr_to_string(unsigned char mac_addr[6])
{
static char mac_string[18];
snprintf(mac_string, sizeof(mac_string), "%02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0],
mac_addr[1],
mac_addr[2],
mac_addr[3],
mac_addr[4],
mac_addr[5]);
return mac_string;
}
static json_object *hfi_to_json(struct nbft_info_hfi *hfi)
{
struct json_object *hfi_json;
hfi_json = json_create_object();
if (!hfi_json)
return NULL;
if (json_object_add_value_int(hfi_json, "index", hfi->index)
|| json_object_add_value_string(hfi_json, "transport", hfi->transport))
goto fail;
if (strcmp(hfi->transport, "tcp") == 0) {
if (json_object_add_value_string(hfi_json, "pcidev",
pci_sbdf_to_string(hfi->tcp_info.pci_sbdf))
|| json_object_add_value_string(hfi_json, "mac_addr",
mac_addr_to_string(hfi->tcp_info.mac_addr))
|| json_object_add_value_int(hfi_json, "vlan",
hfi->tcp_info.vlan)
|| json_object_add_value_int(hfi_json, "ip_origin",
hfi->tcp_info.ip_origin)
|| json_object_add_value_string(hfi_json, "ipaddr",
hfi->tcp_info.ipaddr)
|| json_object_add_value_int(hfi_json, "subnet_mask_prefix",
hfi->tcp_info.subnet_mask_prefix)
|| json_object_add_value_string(hfi_json, "gateway_ipaddr",
hfi->tcp_info.gateway_ipaddr)
|| json_object_add_value_int(hfi_json, "route_metric",
hfi->tcp_info.route_metric)
|| json_object_add_value_string(hfi_json, "primary_dns_ipaddr",
hfi->tcp_info.primary_dns_ipaddr)
|| json_object_add_value_string(hfi_json, "secondary_dns_ipaddr",
hfi->tcp_info.secondary_dns_ipaddr)
|| json_object_add_value_string(hfi_json, "dhcp_server_ipaddr",
hfi->tcp_info.dhcp_server_ipaddr)
|| (hfi->tcp_info.host_name
&& json_object_add_value_string(hfi_json, "host_name",
hfi->tcp_info.host_name))
|| json_object_add_value_int(hfi_json, "this_hfi_is_default_route",
hfi->tcp_info.this_hfi_is_default_route)
|| json_object_add_value_int(hfi_json, "dhcp_override",
hfi->tcp_info.dhcp_override))
goto fail;
else
return hfi_json;
}
fail:
json_free_object(hfi_json);
return NULL;
}
static json_object *ssns_to_json(struct nbft_info_subsystem_ns *ss)
{
struct json_object *ss_json;
struct json_object *hfi_array_json;
char json_str[40];
char *json_str_p;
int i;
ss_json = json_create_object();
if (!ss_json)
return NULL;
hfi_array_json = json_create_array();
if (!hfi_array_json)
goto fail;
for (i = 0; i < ss->num_hfis; i++)
if (json_array_add_value_object(hfi_array_json,
json_object_new_int(ss->hfis[i]->index)))
goto fail;
if (json_object_add_value_int(ss_json, "index", ss->index)
|| json_object_add_value_int(ss_json, "num_hfis", ss->num_hfis)
|| json_object_object_add(ss_json, "hfis", hfi_array_json)
|| json_object_add_value_string(ss_json, "transport", ss->transport)
|| json_object_add_value_string(ss_json, "traddr", ss->traddr)
|| json_object_add_value_string(ss_json, "trsvcid", ss->trsvcid)
|| json_object_add_value_int(ss_json, "subsys_port_id", ss->subsys_port_id)
|| json_object_add_value_int(ss_json, "nsid", ss->nsid))
goto fail;
memset(json_str, 0, sizeof(json_str));
json_str_p = json_str;
switch (ss->nid_type) {
case NBFT_INFO_NID_TYPE_EUI64:
if (json_object_add_value_string(ss_json, "nid_type", "eui64"))
goto fail;
for (i = 0; i < 8; i++)
json_str_p += sprintf(json_str_p, "%02x", ss->nid[i]);
break;
case NBFT_INFO_NID_TYPE_NGUID:
if (json_object_add_value_string(ss_json, "nid_type", "nguid"))
goto fail;
for (i = 0; i < 16; i++)
json_str_p += sprintf(json_str_p, "%02x", ss->nid[i]);
break;
case NBFT_INFO_NID_TYPE_NS_UUID:
if (json_object_add_value_string(ss_json, "nid_type", "uuid"))
goto fail;
nvme_uuid_to_string(ss->nid, json_str);
break;
default:
break;
}
if (json_object_add_value_string(ss_json, "nid", json_str))
goto fail;
if ((ss->subsys_nqn
&& json_object_add_value_string(ss_json, "subsys_nqn", ss->subsys_nqn))
|| json_object_add_value_int(ss_json, "controller_id", ss->controller_id)
|| json_object_add_value_int(ss_json, "asqsz", ss->asqsz)
|| (ss->dhcp_root_path_string
&& json_object_add_value_string(ss_json, "dhcp_root_path_string",
ss->dhcp_root_path_string))
|| json_object_add_value_int(ss_json, "pdu_header_digest_required",
ss->pdu_header_digest_required)
|| json_object_add_value_int(ss_json, "data_digest_required",
ss->data_digest_required))
goto fail;
return ss_json;
fail:
json_free_object(ss_json);
return NULL;
}
static json_object *discovery_to_json(struct nbft_info_discovery *disc)
{
struct json_object *disc_json;
disc_json = json_create_object();
if (!disc_json)
return NULL;
if (json_object_add_value_int(disc_json, "index", disc->index)
|| (disc->security
&& json_object_add_value_int(disc_json, "security", disc->security->index))
|| (disc->hfi
&& json_object_add_value_int(disc_json, "hfi", disc->hfi->index))
|| (disc->uri
&& json_object_add_value_string(disc_json, "uri", disc->uri))
|| (disc->nqn
&& json_object_add_value_string(disc_json, "nqn", disc->nqn))) {
json_free_object(disc_json);
return NULL;
} else
return disc_json;
}
static const char *primary_admin_host_flag_to_str(unsigned int primary)
{
static const char * const str[] = {
[NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_NOT_INDICATED] = "not indicated",
[NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_UNSELECTED] = "unselected",
[NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_SELECTED] = "selected",
[NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_RESERVED] = "reserved",
};
if (primary > NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_RESERVED)
return "INVALID";
return str[primary];
}
static struct json_object *nbft_to_json(struct nbft_info *nbft, bool show_subsys,
bool show_hfi, bool show_discovery)
{
struct json_object *nbft_json, *host_json;
nbft_json = json_create_object();
if (!nbft_json)
return NULL;
if (json_object_add_value_string(nbft_json, "filename", nbft->filename))
goto fail;
host_json = json_create_object();
if (!host_json)
goto fail;
if ((nbft->host.nqn
&& json_object_add_value_string(host_json, "nqn", nbft->host.nqn))
|| (nbft->host.id
&& json_object_add_value_string(host_json, "id",
util_uuid_to_string(nbft->host.id))))
goto fail;
json_object_add_value_int(host_json, "host_id_configured",
nbft->host.host_id_configured);
json_object_add_value_int(host_json, "host_nqn_configured",
nbft->host.host_nqn_configured);
json_object_add_value_string(host_json, "primary_admin_host_flag",
primary_admin_host_flag_to_str(nbft->host.primary));
if (json_object_object_add(nbft_json, "host", host_json)) {
json_free_object(host_json);
goto fail;
}
if (show_subsys) {
struct json_object *subsys_array_json, *subsys_json;
struct nbft_info_subsystem_ns **ss;
subsys_array_json = json_create_array();
if (!subsys_array_json)
goto fail;
for (ss = nbft->subsystem_ns_list; ss && *ss; ss++) {
subsys_json = ssns_to_json(*ss);
if (!subsys_json)
goto fail;
if (json_object_array_add(subsys_array_json, subsys_json)) {
json_free_object(subsys_json);
goto fail;
}
}
if (json_object_object_add(nbft_json, "subsystem", subsys_array_json)) {
json_free_object(subsys_array_json);
goto fail;
}
}
if (show_hfi) {
struct json_object *hfi_array_json, *hfi_json;
struct nbft_info_hfi **hfi;
hfi_array_json = json_create_array();
if (!hfi_array_json)
goto fail;
for (hfi = nbft->hfi_list; hfi && *hfi; hfi++) {
hfi_json = hfi_to_json(*hfi);
if (!hfi_json)
goto fail;
if (json_object_array_add(hfi_array_json, hfi_json)) {
json_free_object(hfi_json);
goto fail;
}
}
if (json_object_object_add(nbft_json, "hfi", hfi_array_json)) {
json_free_object(hfi_array_json);
goto fail;
}
}
if (show_discovery) {
struct json_object *discovery_array_json, *discovery_json;
struct nbft_info_discovery **disc;
discovery_array_json = json_create_array();
if (!discovery_array_json)
goto fail;
for (disc = nbft->discovery_list; disc && *disc; disc++) {
discovery_json = discovery_to_json(*disc);
if (!discovery_json)
goto fail;
if (json_object_array_add(discovery_array_json, discovery_json)) {
json_free_object(discovery_json);
goto fail;
}
}
if (json_object_object_add(nbft_json, "discovery", discovery_array_json)) {
json_free_object(discovery_array_json);
goto fail;
}
}
return nbft_json;
fail:
json_free_object(nbft_json);
return NULL;
}
static int json_show_nbfts(struct list_head *nbft_list, bool show_subsys,
bool show_hfi, bool show_discovery)
{
struct json_object *nbft_json_array, *nbft_json;
struct nbft_file_entry *entry;
nbft_json_array = json_create_array();
if (!nbft_json_array)
return -ENOMEM;
list_for_each(nbft_list, entry, node) {
nbft_json = nbft_to_json(entry->nbft, show_subsys, show_hfi, show_discovery);
if (!nbft_json)
goto fail;
if (json_object_array_add(nbft_json_array, nbft_json)) {
json_free_object(nbft_json);
goto fail;
}
}
json_print_object(nbft_json_array, NULL);
printf("\n");
json_free_object(nbft_json_array);
return 0;
fail:
json_free_object(nbft_json_array);
return -ENOMEM;
}
static void print_nbft_hfi_info(struct nbft_info *nbft)
{
struct nbft_info_hfi **hfi;
unsigned int ip_width = 8, gw_width = 8, dns_width = 8;
hfi = nbft->hfi_list;
if (!hfi || !*hfi)
return;
for (; *hfi; hfi++) {
unsigned int len;
len = strlen((*hfi)->tcp_info.ipaddr);
if (len > ip_width)
ip_width = len;
len = strlen((*hfi)->tcp_info.gateway_ipaddr);
if (len > gw_width)
gw_width = len;
len = strlen((*hfi)->tcp_info.primary_dns_ipaddr);
if (len > dns_width)
dns_width = len;
}
printf("\nNBFT HFIs:\n\n");
printf("%-3.3s|%-4.4s|%-10.10s|%-17.17s|%-4.4s|%-*.*s|%-4.4s|%-*.*s|%-*.*s\n",
"Idx", "Trsp", "PCI Addr", "MAC Addr", "DHCP",
ip_width, ip_width, "IP Addr", "Mask",
gw_width, gw_width, "Gateway", dns_width, dns_width, "DNS");
printf("%-.3s+%-.4s+%-.10s+%-.17s+%-.4s+%-.*s+%-.4s+%-.*s+%-.*s\n",
dash, dash, dash, dash, dash, ip_width, dash, dash,
gw_width, dash, dns_width, dash);
for (hfi = nbft->hfi_list; *hfi; hfi++)
printf("%-3d|%-4.4s|%-10.10s|%-17.17s|%-4.4s|%-*.*s|%-4d|%-*.*s|%-*.*s\n",
(*hfi)->index,
(*hfi)->transport,
pci_sbdf_to_string((*hfi)->tcp_info.pci_sbdf),
mac_addr_to_string((*hfi)->tcp_info.mac_addr),
(*hfi)->tcp_info.dhcp_override ? "yes" : "no",
ip_width, ip_width, (*hfi)->tcp_info.ipaddr,
(*hfi)->tcp_info.subnet_mask_prefix,
gw_width, gw_width, (*hfi)->tcp_info.gateway_ipaddr,
dns_width, dns_width, (*hfi)->tcp_info.primary_dns_ipaddr);
}
static void print_nbft_discovery_info(struct nbft_info *nbft)
{
struct nbft_info_discovery **disc;
unsigned int nqn_width = 20, uri_width = 12;
disc = nbft->discovery_list;
if (!disc || !*disc)
return;
for (; *disc; disc++) {
size_t len;
len = strlen((*disc)->uri);
if (len > uri_width)
uri_width = len;
len = strlen((*disc)->nqn);
if (len > nqn_width)
nqn_width = len;
}
printf("\nNBFT Discovery Controllers:\n\n");
printf("%-3.3s|%-*.*s|%-*.*s\n", "Idx", uri_width, uri_width, "URI",
nqn_width, nqn_width, "NQN");
printf("%-.3s+%-.*s+%-.*s\n", dash, uri_width, dash, nqn_width, dash);
for (disc = nbft->discovery_list; *disc; disc++)
printf("%-3d|%-*.*s|%-*.*s\n", (*disc)->index,
uri_width, uri_width, (*disc)->uri,
nqn_width, nqn_width, (*disc)->nqn);
}
#define HFIS_LEN 20
static size_t print_hfis(const struct nbft_info_subsystem_ns *ss, char buf[HFIS_LEN])
{
char hfi_buf[HFIS_LEN];
size_t len, ofs;
int i;
len = snprintf(hfi_buf, sizeof(hfi_buf), "%d", ss->hfis[0]->index);
for (i = 1; i < ss->num_hfis; i++) {
ofs = len;
len += snprintf(hfi_buf + ofs, sizeof(hfi_buf) - ofs, ",%d",
ss->hfis[i]->index);
/*
* If the list doesn't fit in HFIS_LEN characters,
* truncate and end with "..."
*/
if (len >= sizeof(hfi_buf)) {
while (ofs < sizeof(hfi_buf) - 1)
hfi_buf[ofs++] = '.';
hfi_buf[ofs] = '\0';
len = sizeof(hfi_buf) - 1;
break;
}
}
if (buf)
memcpy(buf, hfi_buf, len + 1);
return len;
}
static void print_nbft_subsys_info(struct nbft_info *nbft)
{
struct nbft_info_subsystem_ns **ss;
unsigned int nqn_width = 20, adr_width = 8, hfi_width = 4;
ss = nbft->subsystem_ns_list;
if (!ss || !*ss)
return;
for (; *ss; ss++) {
size_t len;
len = strlen((*ss)->subsys_nqn);
if (len > nqn_width)
nqn_width = len;
len = strlen((*ss)->traddr);
if (len > adr_width)
adr_width = len;
len = print_hfis(*ss, NULL);
if (len > hfi_width)
hfi_width = len;
}
printf("\nNBFT Subsystems:\n\n");
printf("%-3.3s|%-*.*s|%-4.4s|%-*.*s|%-5.5s|%-*.*s\n",
"Idx", nqn_width, nqn_width, "NQN",
"Trsp", adr_width, adr_width, "Address", "SvcId", hfi_width, hfi_width, "HFIs");
printf("%-.3s+%-.*s+%-.4s+%-.*s+%-.5s+%-.*s\n",
dash, nqn_width, dash, dash, adr_width, dash, dash, hfi_width, dash);
for (ss = nbft->subsystem_ns_list; *ss; ss++) {
char hfi_buf[HFIS_LEN];
print_hfis(*ss, hfi_buf);
printf("%-3d|%-*.*s|%-4.4s|%-*.*s|%-5.5s|%-*.*s\n",
(*ss)->index, nqn_width, nqn_width, (*ss)->subsys_nqn,
(*ss)->transport, adr_width, adr_width, (*ss)->traddr,
(*ss)->trsvcid, hfi_width, hfi_width, hfi_buf);
}
}
static void normal_show_nbft(struct nbft_info *nbft, bool show_subsys,
bool show_hfi, bool show_discovery)
{
printf("%s:\n", nbft->filename);
if ((!nbft->hfi_list || !*nbft->hfi_list) &&
(!nbft->security_list || !*nbft->security_list) &&
(!nbft->discovery_list || !*nbft->discovery_list) &&
(!nbft->subsystem_ns_list || !*nbft->subsystem_ns_list))
printf("(empty)\n");
else {
if (show_subsys)
print_nbft_subsys_info(nbft);
if (show_hfi)
print_nbft_hfi_info(nbft);
if (show_discovery)
print_nbft_discovery_info(nbft);
}
}
static void normal_show_nbfts(struct list_head *nbft_list, bool show_subsys,
bool show_hfi, bool show_discovery)
{
bool not_first = false;
struct nbft_file_entry *entry;
list_for_each(nbft_list, entry, node) {
if (not_first)
printf("\n");
normal_show_nbft(entry->nbft, show_subsys, show_hfi, show_discovery);
not_first = true;
}
}
int show_nbft(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Display contents of the ACPI NBFT files.";
struct list_head nbft_list;
char *format = "normal";
char *nbft_path = NBFT_SYSFS_PATH;
enum nvme_print_flags flags;
int ret;
bool show_subsys = false, show_hfi = false, show_discovery = false;
OPT_ARGS(opts) = {
OPT_FMT("output-format", 'o', &format, "Output format: normal|json"),
OPT_FLAG("subsystem", 's', &show_subsys, "show NBFT subsystems"),
OPT_FLAG("hfi", 'H', &show_hfi, "show NBFT HFIs"),
OPT_FLAG("discovery", 'd', &show_discovery, "show NBFT discovery controllers"),
OPT_STRING("nbft-path", 0, "STR", &nbft_path, "user-defined path for NBFT tables"),
OPT_END()
};
ret = argconfig_parse(argc, argv, desc, opts);
if (ret)
return ret;
ret = flags = validate_output_format(format);
if (ret < 0)
return ret;
if (!(show_subsys || show_hfi || show_discovery))
show_subsys = show_hfi = show_discovery = true;
list_head_init(&nbft_list);
ret = read_nbft_files(&nbft_list, nbft_path);
if (!ret) {
if (flags == NORMAL)
normal_show_nbfts(&nbft_list, show_subsys, show_hfi, show_discovery);
else if (flags == JSON)
ret = json_show_nbfts(&nbft_list, show_subsys, show_hfi, show_discovery);
free_nbfts(&nbft_list);
}
return ret;
}

View file

@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#undef CMD_INC_FILE
#define CMD_INC_FILE plugins/nbft/nbft-plugin
#if !defined(NBFT) || defined(CMD_HEADER_MULTI_READ)
#define NBFT
#include "cmd.h"
PLUGIN(NAME("nbft", "ACPI NBFT table extensions", NVME_VERSION),
COMMAND_LIST(
ENTRY("show", "Show contents of ACPI NBFT tables", show_nbft)
)
);
#endif
#include "define_cmd.h"

View file

@ -1,18 +1,18 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2018 NetApp, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
* Copyright (c) 2018 NetApp, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <stdio.h>
#include <dirent.h>
@ -57,14 +57,14 @@ enum {
static const char *dev_path = "/dev/";
struct smdevice_info {
unsigned nsid;
unsigned int nsid;
struct nvme_id_ctrl ctrl;
struct nvme_id_ns ns;
char dev[265];
};
struct ontapdevice_info {
unsigned nsid;
unsigned int nsid;
struct nvme_id_ctrl ctrl;
struct nvme_id_ns ns;
unsigned char uuid[NVME_UUID_LEN];
@ -107,6 +107,7 @@ static void netapp_get_ns_size(char *size, unsigned long long *lba,
struct nvme_id_ns *ns)
{
__u8 lba_index;
nvme_id_ns_flbas_to_lbaf_inuse(ns->flbas, &lba_index);
*lba = 1ULL << ns->lbaf[lba_index].ds;
double nsze = le64_to_cpu(ns->nsze) * (*lba);
@ -237,8 +238,8 @@ static void netapp_smdevices_print(struct smdevice_info *devices, int count, int
char array_label[ARRAY_LABEL_LEN / 2 + 1];
char volume_label[VOLUME_LABEL_LEN / 2 + 1];
char nguid_str[33];
char basestr[] = "%s, Array Name %s, Volume Name %s, NSID %d, "
"Volume ID %s, Controller %c, Access State %s, %s\n";
char basestr[] =
"%s, Array Name %s, Volume Name %s, NSID %d, Volume ID %s, Controller %c, Access State %s, %s\n";
char columnstr[] = "%-16s %-30s %-30s %4d %32s %c %-12s %9s\n";
char *formatstr = basestr; /* default to "normal" output format */
__u8 lba_index;
@ -254,8 +255,7 @@ static void netapp_smdevices_print(struct smdevice_info *devices, int count, int
"------------------------------", "----",
"--------------------------------", "----",
"------------", "---------");
}
else if (format == NJSON) {
} else if (format == NJSON) {
/* prepare for json output */
root = json_create_object();
json_devices = json_create_array();
@ -263,7 +263,7 @@ static void netapp_smdevices_print(struct smdevice_info *devices, int count, int
for (i = 0; i < count; i++) {
nvme_id_ns_flbas_to_lbaf_inuse(devices[i].ns.flbas, &lba_index);
unsigned long long int lba = 1ULL << devices[i].ns.lbaf[lba_index].ds;
unsigned long long lba = 1ULL << devices[i].ns.lbaf[lba_index].ds;
double nsze = le64_to_cpu(devices[i].ns.nsze) * lba;
const char *s_suffix = suffix_si_get(&nsze);
char size[128];
@ -464,7 +464,7 @@ static int netapp_ontapdevices_get_info(int fd, struct ontapdevice_info *item,
err = nvme_get_ontap_c2_log(fd, item->nsid, item->log_data, ONTAP_C2_LOG_SIZE);
if (err) {
fprintf(stderr, "Unable to get log page data for %s (%s)\n",
dev, err < 0 ? strerror(-err):
dev, err < 0 ? strerror(-err) :
nvme_status_to_string(err, false));
return 0;
}
@ -553,7 +553,7 @@ static int netapp_smdevices(int argc, char **argv, struct command *command,
smdevices = calloc(num, sizeof(*smdevices));
if (!smdevices) {
fprintf(stderr, "Unable to allocate memory for devices.\n");
return ENOMEM;
return -ENOMEM;
}
for (i = 0; i < num; i++) {

View file

@ -3,5 +3,6 @@ sources += [
'plugins/ocp/ocp-nvme.c',
'plugins/ocp/ocp-clear-fw-update-history.c',
'plugins/ocp/ocp-smart-extended-log.c',
'plugins/ocp/ocp-fw-activation-history.c',
]

View file

@ -16,6 +16,5 @@ int ocp_clear_fw_update_history(int argc, char **argv, struct command *cmd, stru
{
const char *desc = "OCP Clear Firmware Update History";
return ocp_clear_feature(argc, argv, desc,
OCP_FID_CLEAR_FW_ACTIVATION_HISTORY);
return ocp_clear_feature(argc, argv, desc, OCP_FID_CLEAR_FW_ACTIVATION_HISTORY);
}

View file

@ -0,0 +1,223 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2022 Solidigm.
*
* Author: karl.dedow@solidigm.com
*/
#include "ocp-fw-activation-history.h"
#include <errno.h>
#include <stdio.h>
#include "common.h"
#include "nvme-print.h"
#include "ocp-utils.h"
static const unsigned char ocp_fw_activation_history_guid[16] = {
0x6D, 0x79, 0x9a, 0x76,
0xb4, 0xda, 0xf6, 0xa3,
0xe2, 0x4d, 0xb2, 0x8a,
0xac, 0xf3, 0x1c, 0xd1
};
struct __packed fw_activation_history_entry {
__u8 ver_num;
__u8 entry_length;
__u16 reserved1;
__u16 activation_count;
__u64 timestamp;
__u64 reserved2;
__u64 power_cycle_count;
char previous_fw[8];
char new_fw[8];
__u8 slot_number;
__u8 commit_action;
__u16 result;
__u8 reserved3[14];
};
struct __packed fw_activation_history {
__u8 log_id;
__u8 reserved1[3];
__u32 valid_entries;
struct fw_activation_history_entry entries[20];
__u8 reserved2[2790];
__u16 log_page_version;
__u64 log_page_guid[2];
};
static void ocp_fw_activation_history_normal(const struct fw_activation_history *fw_history)
{
printf("Firmware History Log:\n");
printf(" %-26s%d\n", "log identifier:", fw_history->log_id);
printf(" %-26s%d\n", "valid entries:", le32_to_cpu(fw_history->valid_entries));
printf(" entries:\n");
for (int index = 0; index < fw_history->valid_entries; index++) {
const struct fw_activation_history_entry *entry = &fw_history->entries[index];
printf(" entry[%d]:\n", le32_to_cpu(index));
printf(" %-22s%d\n", "version number:", entry->ver_num);
printf(" %-22s%d\n", "entry length:", entry->entry_length);
printf(" %-22s%d\n", "activation count:",
le16_to_cpu(entry->activation_count));
printf(" %-22s%"PRIu64"\n", "timestamp:",
le64_to_cpu(entry->timestamp));
printf(" %-22s%"PRIu64"\n", "power cycle count:",
le64_to_cpu(entry->power_cycle_count));
printf(" %-22s%.*s\n", "previous firmware:", (int)sizeof(entry->previous_fw),
entry->previous_fw);
printf(" %-22s%.*s\n", "new firmware:", (int)sizeof(entry->new_fw),
entry->new_fw);
printf(" %-22s%d\n", "slot number:", entry->slot_number);
printf(" %-22s%d\n", "commit action type:", entry->commit_action);
printf(" %-22s%d\n", "result:", le16_to_cpu(entry->result));
}
printf(" %-26s%d\n", "log page version:",
le16_to_cpu(fw_history->log_page_version));
printf(" %-26s0x%"PRIx64"%"PRIx64"\n", "log page guid:",
le64_to_cpu(fw_history->log_page_guid[1]),
le64_to_cpu(fw_history->log_page_guid[0]));
printf("\n");
}
static void ocp_fw_activation_history_json(const struct fw_activation_history *fw_history)
{
struct json_object *root = json_create_object();
json_object_add_value_uint(root, "log identifier", fw_history->log_id);
json_object_add_value_uint(root, "valid entries", le32_to_cpu(fw_history->valid_entries));
struct json_object *entries = json_create_array();
for (int index = 0; index < fw_history->valid_entries; index++) {
const struct fw_activation_history_entry *entry = &fw_history->entries[index];
struct json_object *entry_obj = json_create_object();
json_object_add_value_uint(entry_obj, "version number", entry->ver_num);
json_object_add_value_uint(entry_obj, "entry length", entry->entry_length);
json_object_add_value_uint(entry_obj, "activation count",
le16_to_cpu(entry->activation_count));
json_object_add_value_uint64(entry_obj, "timestamp",
le64_to_cpu(entry->timestamp));
json_object_add_value_uint(entry_obj, "power cycle count",
le64_to_cpu(entry->power_cycle_count));
struct json_object *fw = json_object_new_string_len(entry->previous_fw,
sizeof(entry->previous_fw));
json_object_add_value_object(entry_obj, "previous firmware", fw);
fw = json_object_new_string_len(entry->new_fw, sizeof(entry->new_fw));
json_object_add_value_object(entry_obj, "new firmware", fw);
json_object_add_value_uint(entry_obj, "slot number", entry->slot_number);
json_object_add_value_uint(entry_obj, "commit action type", entry->commit_action);
json_object_add_value_uint(entry_obj, "result", le16_to_cpu(entry->result));
json_array_add_value_object(entries, entry_obj);
}
json_object_add_value_array(root, "entries", entries);
json_object_add_value_uint(root, "log page version",
le16_to_cpu(fw_history->log_page_version));
char guid[2 * sizeof(fw_history->log_page_guid) + 3] = { 0 };
sprintf(guid, "0x%"PRIx64"%"PRIx64"",
le64_to_cpu(fw_history->log_page_guid[1]),
le64_to_cpu(fw_history->log_page_guid[0]));
json_object_add_value_string(root, "log page guid", guid);
json_print_object(root, NULL);
json_free_object(root);
printf("\n");
}
int ocp_fw_activation_history_log(int argc, char **argv, struct command *cmd,
struct plugin *plugin)
{
const __u8 log_id = 0xC2;
const char *description = "Retrieves the OCP firmware activation history log.";
char *format = "normal";
OPT_ARGS(options) = {
OPT_FMT("output-format", 'o', &format, "output format : normal | json"),
OPT_END()
};
struct nvme_dev *dev = NULL;
int err = parse_and_open(&dev, argc, argv, description, options);
if (err)
return err;
int uuid_index = 0;
/*
* Best effort attempt at uuid. Otherwise, assume no index (i.e. 0)
* Log GUID check will ensure correctness of returned data
*/
ocp_get_uuid_index(dev, &uuid_index);
struct fw_activation_history fw_history = { 0 };
struct nvme_get_log_args args = {
.lpo = 0,
.result = NULL,
.log = &fw_history,
.args_size = sizeof(args),
.fd = dev_fd(dev),
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
.lid = log_id,
.len = sizeof(fw_history),
.nsid = NVME_NSID_ALL,
.csi = NVME_CSI_NVM,
.lsi = NVME_LOG_LSI_NONE,
.lsp = 0,
.uuidx = uuid_index,
.rae = false,
.ot = false,
};
err = nvme_get_log(&args);
if (err)
nvme_show_status(err);
dev_close(dev);
int guid_cmp_res = memcmp(fw_history.log_page_guid, ocp_fw_activation_history_guid,
sizeof(ocp_fw_activation_history_guid));
if (!err && guid_cmp_res) {
fprintf(stderr,
"Error: Unexpected data. Log page guid does not match with expected.\n");
err = -EINVAL;
}
if (!err) {
const enum nvme_print_flags print_flag = validate_output_format(format);
if (print_flag == JSON)
ocp_fw_activation_history_json(&fw_history);
else if (print_flag == NORMAL)
ocp_fw_activation_history_normal(&fw_history);
else {
fprintf(stderr, "Error: Invalid output format.\n");
err = -EINVAL;
}
}
return err;
}

View file

@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2022 Solidigm.
*
* Authors: karl.dedow@solidigm.com
*/
#ifndef OCP_FIRMWARE_ACTIVATION_HISTORY_H
#define OCP_FIRMWARE_ACTIVATION_HISTORY_H
struct command;
struct plugin;
int ocp_fw_activation_history_log(int argc, char **argv,
struct command *cmd, struct plugin *plugin);
#endif

File diff suppressed because it is too large Load diff

View file

@ -17,9 +17,15 @@ PLUGIN(NAME("ocp", "OCP cloud SSD extensions", NVME_VERSION),
COMMAND_LIST(
ENTRY("smart-add-log", "Retrieve extended SMART Information", smart_add_log)
ENTRY("latency-monitor-log", "Get Latency Monitor Log Page", ocp_latency_monitor_log)
ENTRY("set-latency-monitor-feature", "Set Latency Monitor feature", ocp_set_latency_monitor_feature)
ENTRY("internal-log", "Retrieve and save internal device telemetry log", ocp_telemetry_log)
ENTRY("clear-fw-activate-history", "Clear firmware update history log", clear_fw_update_history)
ENTRY("eol-plp-failure-mode", "Define EOL or PLP circuitry failure mode.", eol_plp_failure_mode)
ENTRY("clear-pcie-correctable-error-counters", "Clear PCIe correctable error counters", clear_pcie_corectable_error_counters)
ENTRY("vs-fw-activate-history", "Get firmware activation history log", fw_activation_history_log)
ENTRY("unsupported-reqs-log", "Get Unsupported Requirements Log Page", ocp_unsupported_requirements_log)
ENTRY("error-recovery-log", "Retrieve Error Recovery Log Page", ocp_error_recovery_log)
ENTRY("device-capability-log", "Get Device capabilities Requirements Log Page", ocp_device_capabilities_log)
)
);

View file

@ -26,7 +26,7 @@ static __u8 scao_guid[C0_GUID_LENGTH] = {
0xC9, 0x14, 0xD5, 0xAF
};
typedef enum {
enum {
SCAO_PMUW = 0, /* Physical media units written */
SCAO_PMUR = 16, /* Physical media units read */
SCAO_BUNBR = 32, /* Bad user nand blocks raw */
@ -62,7 +62,7 @@ typedef enum {
SCAO_PSCC = 200, /* Power State Change Count */
SCAO_LPV = 494, /* Log page version */
SCAO_LPG = 496, /* Log page GUID */
} SMART_CLOUD_ATTRIBUTE_OFFSETS;
};
static void ocp_print_C0_log_normal(void *data)
{
@ -71,10 +71,10 @@ static void ocp_print_C0_log_normal(void *data)
printf("SMART Cloud Attributes :-\n");
printf(" Physical media units written - %"PRIu64" %"PRIu64"\n",
printf(" Physical media units written - %"PRIu64" %"PRIu64"\n",
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW + 8] & 0xFFFFFFFFFFFFFFFF),
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW] & 0xFFFFFFFFFFFFFFFF));
printf(" Physical media units read - %"PRIu64" %"PRIu64"\n",
printf(" Physical media units read - %"PRIu64" %"PRIu64"\n",
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR + 8] & 0xFFFFFFFFFFFFFFFF),
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR] & 0xFFFFFFFFFFFFFFFF));
printf(" Bad user nand blocks - Raw %"PRIu64"\n",
@ -105,7 +105,7 @@ static void ocp_print_C0_log_normal(void *data)
(uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MNUDEC]));
printf(" Number of Thermal throttling events %d\n",
(__u8)log_data[SCAO_NTTE]);
printf(" Current throttling status 0x%x\n",
printf(" Current throttling status 0x%x\n",
(__u8)log_data[SCAO_CTS]);
printf(" PCIe correctable error count %"PRIu64"\n",
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PCEC]));
@ -286,14 +286,12 @@ static int get_c0_log_page(int fd, char *format)
fprintf(stderr, "ERROR : OCP : Unknown GUID in C0 Log Page data\n");
fprintf(stderr, "ERROR : OCP : Expected GUID: 0x");
for (j = 0; j < 16; j++) {
for (j = 0; j < 16; j++)
fprintf(stderr, "%x", scao_guid[j]);
}
fprintf(stderr, "\nERROR : OCP : Actual GUID: 0x");
for (j = 0; j < 16; j++) {
for (j = 0; j < 16; j++)
fprintf(stderr, "%x", data[SCAO_LPG + j]);
}
fprintf(stderr, "\n");
ret = -1;

View file

@ -3,19 +3,23 @@
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <linux/fs.h>
#include <inttypes.h>
#include <asm/byteorder.h>
#include <sys/sysinfo.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <time.h>
#include "common.h"
#include "nvme.h"
#include "libnvme.h"
#include "plugin.h"
#include "linux/types.h"
#include "nvme-wrap.h"
#include "nvme-print.h"
#define CREATE_CMD
@ -57,8 +61,7 @@ enum sfx_nvme_admin_opcode {
nvme_admin_sfx_get_features = 0xd6,
};
struct sfx_freespace_ctx
{
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 */
@ -66,6 +69,10 @@ struct sfx_freespace_ctx
__u64 hw_used; /* hw space used in 4K */
__u64 app_written; /* app data written in 4K */
__u64 out_of_space;
__u64 map_unit;
__u64 max_user_space;
__u64 extendible_user_cap_lba_count;
__u64 friendly_change_cap_support;
};
struct nvme_capacity_info {
@ -75,72 +82,73 @@ struct nvme_capacity_info {
__u64 free_space;
};
struct __attribute__((packed)) nvme_additional_smart_log_item {
struct __packed nvme_additional_smart_log_item {
__u8 key;
__u8 _kp[2];
__u8 norm;
__u8 _np;
union __attribute__((packed)) {
union __packed {
__u8 raw[6];
struct __attribute__((packed)) wear_level {
struct __packed wear_level {
__le16 min;
__le16 max;
__le16 avg;
} wear_level;
struct __attribute__((packed)) thermal_throttle {
struct __packed thermal_throttle {
__u8 pct;
__u32 count;
} thermal_throttle;
} ;
};
__u8 _rp;
} ;
};
struct nvme_additional_smart_log {
struct nvme_additional_smart_log_item program_fail_cnt;
struct nvme_additional_smart_log_item erase_fail_cnt;
struct nvme_additional_smart_log_item wear_leveling_cnt;
struct nvme_additional_smart_log_item e2e_err_cnt;
struct nvme_additional_smart_log_item crc_err_cnt;
struct nvme_additional_smart_log_item timed_workload_media_wear;
struct nvme_additional_smart_log_item timed_workload_host_reads;
struct nvme_additional_smart_log_item timed_workload_timer;
struct nvme_additional_smart_log_item thermal_throttle_status;
struct nvme_additional_smart_log_item retry_buffer_overflow_cnt;
struct nvme_additional_smart_log_item pll_lock_loss_cnt;
struct nvme_additional_smart_log_item nand_bytes_written;
struct nvme_additional_smart_log_item host_bytes_written;
struct nvme_additional_smart_log_item raid_recover_cnt; // errors which can be recovered by RAID
struct nvme_additional_smart_log_item prog_timeout_cnt;
struct nvme_additional_smart_log_item erase_timeout_cnt;
struct nvme_additional_smart_log_item read_timeout_cnt;
struct nvme_additional_smart_log_item read_ecc_cnt;//retry cnt
struct nvme_additional_smart_log_item non_media_crc_err_cnt;
struct nvme_additional_smart_log_item compression_path_err_cnt;
struct nvme_additional_smart_log_item out_of_space_flag;
struct nvme_additional_smart_log_item physical_usage_ratio;
struct nvme_additional_smart_log_item grown_bb; //grown bad block
struct nvme_additional_smart_log_item program_fail_cnt;
struct nvme_additional_smart_log_item erase_fail_cnt;
struct nvme_additional_smart_log_item wear_leveling_cnt;
struct nvme_additional_smart_log_item e2e_err_cnt;
struct nvme_additional_smart_log_item crc_err_cnt;
struct nvme_additional_smart_log_item timed_workload_media_wear;
struct nvme_additional_smart_log_item timed_workload_host_reads;
struct nvme_additional_smart_log_item timed_workload_timer;
struct nvme_additional_smart_log_item thermal_throttle_status;
struct nvme_additional_smart_log_item retry_buffer_overflow_cnt;
struct nvme_additional_smart_log_item pll_lock_loss_cnt;
struct nvme_additional_smart_log_item nand_bytes_written;
struct nvme_additional_smart_log_item host_bytes_written;
struct nvme_additional_smart_log_item raid_recover_cnt; /* errors which can be recovered by RAID */
struct nvme_additional_smart_log_item prog_timeout_cnt;
struct nvme_additional_smart_log_item erase_timeout_cnt;
struct nvme_additional_smart_log_item read_timeout_cnt;
struct nvme_additional_smart_log_item read_ecc_cnt; /* retry cnt */
struct nvme_additional_smart_log_item non_media_crc_err_cnt;
struct nvme_additional_smart_log_item compression_path_err_cnt;
struct nvme_additional_smart_log_item out_of_space_flag;
struct nvme_additional_smart_log_item physical_usage_ratio;
struct nvme_additional_smart_log_item grown_bb; /* grown bad block */
};
int nvme_query_cap(int fd, __u32 nsid, __u32 data_len, void *data)
{
int rc = 0;
struct nvme_passthru_cmd cmd = {
.opcode = nvme_admin_query_cap_info,
.nsid = nsid,
.addr = (__u64)(uintptr_t) data,
.data_len = data_len,
};
int rc = 0;
struct nvme_passthru_cmd cmd = {
.opcode = nvme_admin_query_cap_info,
.nsid = nsid,
.addr = (__u64)(uintptr_t) data,
.data_len = data_len,
};
rc = ioctl(fd, SFX_GET_FREESPACE, data);
return rc == 0 ? 0 : nvme_submit_admin_passthru(fd, &cmd, NULL);
rc = ioctl(fd, SFX_GET_FREESPACE, data);
return rc ? nvme_submit_admin_passthru(fd, &cmd, NULL) : 0;
}
int nvme_change_cap(int fd, __u32 nsid, __u64 capacity)
{
struct nvme_passthru_cmd cmd = {
.opcode = nvme_admin_change_cap,
.nsid = nsid,
.cdw10 = (capacity & 0xffffffff),
.cdw11 = (capacity >> 32),
.opcode = nvme_admin_change_cap,
.nsid = nsid,
.cdw10 = (capacity & 0xffffffff),
.cdw11 = (capacity >> 32),
};
return nvme_submit_admin_passthru(fd, &cmd, NULL);
@ -149,10 +157,10 @@ int nvme_change_cap(int fd, __u32 nsid, __u64 capacity)
int nvme_sfx_set_features(int fd, __u32 nsid, __u32 fid, __u32 value)
{
struct nvme_passthru_cmd cmd = {
.opcode = nvme_admin_sfx_set_features,
.nsid = nsid,
.cdw10 = fid,
.cdw11 = value,
.opcode = nvme_admin_sfx_set_features,
.nsid = nsid,
.cdw10 = fid,
.cdw11 = value,
};
return nvme_submit_admin_passthru(fd, &cmd, NULL);
@ -161,16 +169,15 @@ int nvme_sfx_set_features(int fd, __u32 nsid, __u32 fid, __u32 value)
int nvme_sfx_get_features(int fd, __u32 nsid, __u32 fid, __u32 *result)
{
int err = 0;
struct nvme_passthru_cmd cmd = {
.opcode = nvme_admin_sfx_get_features,
.nsid = nsid,
.cdw10 = fid,
struct nvme_passthru_cmd cmd = {
.opcode = nvme_admin_sfx_get_features,
.nsid = nsid,
.cdw10 = fid,
};
err = nvme_submit_admin_passthru(fd, &cmd, NULL);
if (!err && result) {
if (!err && result)
*result = cmd.result;
}
return err;
}
@ -398,11 +405,11 @@ static void show_sfx_smart_log(struct nvme_additional_smart_log *smart,
static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
struct nvme_additional_smart_log smart_log;
char *desc = "Get ScaleFlux vendor specific additional smart log (optionally, "\
"for the specified namespace), and show it.";
char *desc =
"Get ScaleFlux vendor specific additional smart log (optionally, for the specified namespace), and show it.";
const char *namespace = "(optional) desired namespace";
const char *raw = "dump output in binary format";
const char *json= "Dump output in json format";
const char *json = "Dump output in json format";
struct nvme_dev *dev;
struct config {
__u32 namespace_id;
@ -438,14 +445,14 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
dev->name);
else
d_raw((unsigned char *)&smart_log, sizeof(smart_log));
}
else if (err > 0)
} else if (err > 0) {
nvme_show_status(err);
}
dev_close(dev);
return err;
}
struct __attribute__((__packed__)) sfx_lat_stats_vanda {
struct __packed sfx_lat_stats_vanda {
__u16 maj;
__u16 min;
__u32 bucket_1[32]; /* 0~1ms, step 32us */
@ -456,7 +463,7 @@ struct __attribute__((__packed__)) sfx_lat_stats_vanda {
__u32 bucket_6[1]; /* 4s+, specifically 4096ms+ */
};
struct __attribute__((__packed__)) sfx_lat_stats_myrtle {
struct __packed sfx_lat_stats_myrtle {
__u16 maj;
__u16 min;
__u32 bucket_1[64]; /* 0us~63us, step 1us */
@ -482,7 +489,7 @@ struct __attribute__((__packed__)) sfx_lat_stats_myrtle {
};
struct __attribute__((__packed__)) sfx_lat_status_ver {
struct __packed sfx_lat_status_ver {
__u16 maj;
__u16 min;
};
@ -646,23 +653,22 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct
sizeof(stats), (void *)&stats);
if (!err) {
if ((stats.ver.maj == VANDA_MAJOR_IDX) && (stats.ver.min == VANDA_MINOR_IDX)) {
if (!cfg.raw_binary) {
if (!cfg.raw_binary)
show_lat_stats_vanda(&stats.vanda, cfg.write);
} else {
else
d_raw((unsigned char *)&stats.vanda, sizeof(struct sfx_lat_stats_vanda));
}
} else if ((stats.ver.maj == MYRTLE_MAJOR_IDX) && (stats.ver.min == MYRTLE_MINOR_IDX)) {
if (!cfg.raw_binary) {
if (!cfg.raw_binary)
show_lat_stats_myrtle(&stats.myrtle, cfg.write);
} else {
else
d_raw((unsigned char *)&stats.myrtle, sizeof(struct sfx_lat_stats_myrtle));
}
} else {
printf("ScaleFlux IO %s Command Latency Statistics Invalid Version Maj %d Min %d\n",
cfg.write ? "Write" : "Read", stats.ver.maj, stats.ver.min);
}
} else if (err > 0)
} else if (err > 0) {
nvme_show_status(err);
}
dev_close(dev);
return err;
}
@ -697,7 +703,7 @@ static int get_bb_table(int fd, __u32 nsid, unsigned char *buf, __u64 size)
{
if (fd < 0 || !buf || size != 256*4096*sizeof(unsigned char)) {
fprintf(stderr, "Invalid Param \r\n");
return EINVAL;
return -EINVAL;
}
return sfx_nvme_get_log(fd, nsid, SFX_LOG_BBT, size, (void *)buf);
@ -731,7 +737,7 @@ static void bd_table_show(unsigned char *bd_table, __u64 table_size)
remap_gbb_count = *((__u32 *)(bd_table + 4 * sizeof(__u32)));
bb_elem = (__u64 *)(bd_table + 5 * sizeof(__u32));
printf("Bad Block Table \n");
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);
@ -792,7 +798,7 @@ static int sfx_get_bad_block(int argc, char **argv, struct command *cmd, struct
err = get_bb_table(dev_fd(dev), 0xffffffff, data_buf, buf_size);
if (err < 0) {
perror("get-bad-block");
} else if (err != 0) {
} else if (err) {
nvme_show_status(err);
} else {
bd_table_show(data_buf, buf_size);
@ -816,6 +822,7 @@ static void show_cap_info(struct sfx_freespace_ctx *ctx)
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));
printf("map_unit :0x%"PRIx64"K\n", (uint64_t)(ctx->map_unit * 4));
}
static int query_cap_info(int argc, char **argv, struct command *cmd, struct plugin *plugin)
@ -845,11 +852,10 @@ static int query_cap_info(int argc, char **argv, struct command *cmd, struct plu
}
if (!err) {
if (!cfg.raw_binary) {
if (!cfg.raw_binary)
show_cap_info(&ctx);
} else {
else
d_raw((unsigned char *)&ctx, sizeof(ctx));
}
}
dev_close(dev);
return err;
@ -864,9 +870,8 @@ static int change_sanity_check(int fd, __u64 trg_in_4k, int *shrink)
__u64 provisoned_cap_4k = 0;
int extend = 0;
if (nvme_query_cap(fd, 0xffffffff, sizeof(freespace_ctx), &freespace_ctx)) {
return -1;
}
if (nvme_query_cap(fd, 0xffffffff, sizeof(freespace_ctx), &freespace_ctx))
return -1;
/*
* capacity illegal check
@ -877,13 +882,12 @@ static int change_sanity_check(int fd, __u64 trg_in_4k, int *shrink)
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) {
if (trg_in_4k < provisoned_cap_4k)
fprintf(stderr,
"WARNING: The target capacity is less than 1.0 x provisioned capacity!\n");
} else {
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)) {
@ -893,7 +897,7 @@ static int change_sanity_check(int fd, __u64 trg_in_4k, int *shrink)
/*
* check whether mem enough if extend
* */
*/
cur_in_4k = freespace_ctx.user_space >> (SFX_PAGE_SHIFT - SECTOR_SHIFT);
extend = (cur_in_4k <= trg_in_4k);
if (extend) {
@ -904,10 +908,9 @@ static int change_sanity_check(int fd, __u64 trg_in_4k, int *shrink)
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);
"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;
}
}
@ -926,6 +929,7 @@ static int change_sanity_check(int fd, __u64 trg_in_4k, int *shrink)
static int sfx_confirm_change(const char *str)
{
unsigned char confirm;
fprintf(stderr, "WARNING: %s.\n"
"Use the force [--force] option to suppress this warning.\n", str);
@ -935,7 +939,7 @@ static int sfx_confirm_change(const char *str)
fprintf(stderr, "Cancled.\n");
return 0;
}
fprintf(stderr, "Sending operation ... \n");
fprintf(stderr, "Sending operation ...\n");
return 1;
}
@ -993,11 +997,11 @@ static int change_cap(int argc, char **argv, struct command *cmd, struct plugin
}
err = nvme_change_cap(dev_fd(dev), 0xffffffff, cap_in_4k);
if (err < 0)
if (err < 0) {
perror("sfx-change-cap");
else if (err != 0)
} else if (err) {
nvme_show_status(err);
else {
} else {
printf("ScaleFlux change-capacity: success\n");
ioctl(dev_fd(dev), BLKRRPART);
}
@ -1017,7 +1021,7 @@ static int sfx_verify_chr(int fd)
if (!S_ISCHR(nvme_stat.st_mode)) {
fprintf(stderr,
"Error: requesting clean card on non-controller handle\n");
return ENOTBLK;
return -ENOTBLK;
}
return 0;
}
@ -1041,13 +1045,12 @@ static int sfx_clean_card(int fd)
char *sfx_feature_to_string(int feature)
{
switch (feature) {
case SFX_FEAT_ATOMIC:
return "ATOMIC";
case SFX_FEAT_UP_P_CAP:
return "UPDATE_PROVISION_CAPACITY";
default:
return "Unknown";
case SFX_FEAT_ATOMIC:
return "ATOMIC";
case SFX_FEAT_UP_P_CAP:
return "UPDATE_PROVISION_CAPACITY";
default:
return "Unknown";
}
}
@ -1093,7 +1096,7 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl
if (!cfg.feature_id) {
fprintf(stderr, "feature-id required param\n");
dev_close(dev);
return EINVAL;
return -EINVAL;
}
if (cfg.feature_id == SFX_FEAT_CLR_CARD) {
@ -1107,7 +1110,7 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl
}
if (cfg.feature_id == SFX_FEAT_ATOMIC && cfg.value != 0) {
if (cfg.feature_id == SFX_FEAT_ATOMIC && cfg.value) {
if (cfg.namespace_id != 0xffffffff) {
err = nvme_identify_ns(dev_fd(dev), cfg.namespace_id,
&ns);
@ -1125,14 +1128,14 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl
if ((ns.flbas & 0xf) != 1) {
printf("Please change-sector size to 4K, then retry\n");
dev_close(dev);
return EFAULT;
return -EFAULT;
}
}
} else if (cfg.feature_id == SFX_FEAT_UP_P_CAP) {
if (cfg.value <= 0) {
fprintf(stderr, "Invalid Param\n");
dev_close(dev);
return EINVAL;
return -EINVAL;
}
/*Warning for change pacp by GB*/
@ -1153,8 +1156,9 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl
} else if (!err) {
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)
} else if (err > 0) {
nvme_show_status(err);
}
dev_close(dev);
return err;
@ -1192,7 +1196,7 @@ static int sfx_get_feature(int argc, char **argv, struct command *cmd, struct pl
if (!cfg.feature_id) {
fprintf(stderr, "feature-id required param\n");
dev_close(dev);
return EINVAL;
return -EINVAL;
}
err = nvme_sfx_get_features(dev_fd(dev), cfg.namespace_id,
@ -1204,10 +1208,481 @@ static int sfx_get_feature(int argc, char **argv, struct command *cmd, struct pl
} else if (!err) {
printf("ScaleFlux get-feature:%02x (%s), value:%d\n", cfg.feature_id,
sfx_feature_to_string(cfg.feature_id), result);
} else if (err > 0)
} else if (err > 0) {
nvme_show_status(err);
}
dev_close(dev);
return err;
}
static int nvme_parse_evtlog(void *pevent_log_info, __u32 log_len, char *output)
{
__u32 offset = 0;
__u32 length = log_len;
__u16 fw_core;
__u64 fw_time;
__u8 code_level;
__u8 code_type;
char str_buffer[512];
__u32 str_pos;
FILE *fd;
int err = 0;
enum sfx_evtlog_level {
sfx_evtlog_level_warning,
sfx_evtlog_level_error,
};
const char *sfx_evtlog_warning[4] = {
"RESERVED",
"TOO_MANY_BB",
"LOW_SPACE",
"HIGH_TEMPERATURE"
};
const char *sfx_evtlog_error[14] = {
"RESERVED",
"HAS_ASSERT",
"HAS_PANIC_DUMP",
"INVALID_FORMAT_CAPACITY",
"MAT_FAILED",
"FREEZE_DUE_TO_RECOVERY_FAILED",
"RFS_BROKEN",
"MEDIA_ERR_ON_PAGE_IN",
"MEDIA_ERR_ON_MPAGE_HEADER",
"CAPACITOR_BROKEN",
"READONLY_DUE_TO_RECOVERY_FAILED",
"RD_ERR_IN_GSD_RECOVERY",
"RD_ERR_ON_PF_RECOVERY",
"MEDIA_ERR_ON_FULL_RECOVERY"
};
struct sfx_nvme_evtlog_info {
__u16 time_stamp[4];
__u64 magic1;
__u8 reverse[10];
char evt_name[32];
__u64 magic2;
char fw_ver[24];
char bl2_ver[32];
__u16 code;
__u16 assert_id;
} __packed;
struct sfx_nvme_evtlog_info *info = NULL;
fd = fopen(output, "w+");
if (!fd) {
fprintf(stderr, "Failed to open %s file to write\n", output);
err = ENOENT;
goto ret;
}
while (length > 0) {
info = (struct sfx_nvme_evtlog_info *)(pevent_log_info + offset);
if ((info->magic1 == 0x474F4C545645) &&
(info->magic2 == 0x38B0B3ABA9BA)) {
memset(str_buffer, 0, 512);
str_pos = 0;
fw_core = info->time_stamp[3];
snprintf(str_buffer + str_pos, 16, "[%d-", fw_core);
str_pos = strlen(str_buffer);
fw_time = ((__u64)info->time_stamp[2] << 32) + ((__u64)info->time_stamp[1] << 16) + (__u64)info->time_stamp[0];
convert_ts(fw_time, str_buffer + str_pos);
str_pos = strlen(str_buffer);
strcpy(str_buffer + str_pos, "] event-log:\n");
str_pos = strlen(str_buffer);
snprintf(str_buffer + str_pos, 128,
" > fw_version: %s\n > bl2_version: %s\n",
info->fw_ver, info->bl2_ver);
str_pos = strlen(str_buffer);
code_level = (info->code & 0x100) >> 8;
code_type = (info->code % 0x100);
if (code_level == sfx_evtlog_level_warning) {
snprintf(str_buffer + str_pos, 128,
" > error_str: [WARNING][%s]\n\n",
sfx_evtlog_warning[code_type]);
} else {
if (info->assert_id)
snprintf(str_buffer + str_pos, 128,
" > error_str: [ERROR][%s]\n > assert_id: %d\n\n",
sfx_evtlog_error[code_type], info->assert_id);
else
snprintf(str_buffer + str_pos, 128,
" > error_str: [ERROR][%s]\n\n",
sfx_evtlog_error[code_type]);
}
str_pos = strlen(str_buffer);
if (fwrite(str_buffer, 1, str_pos, fd) != str_pos) {
fprintf(stderr, "Failed to write parse result to output file\n");
goto close_fd;
}
}
offset++;
length--;
if (!(offset % (log_len / 100)) || (offset == log_len))
util_spinner("Parse", (float) (offset) / (float) (log_len));
}
printf("\nParse-evtlog: Success\n");
close_fd:
fclose(fd);
ret:
return err;
}
static int nvme_dump_evtlog(struct nvme_dev *dev, __u32 namespace_id, __u32 storage_medium,
char *file, bool parse, char *output)
{
struct nvme_persistent_event_log *pevent;
void *pevent_log_info;
__u8 lsp_base;
__u32 offset = 0;
__u32 length = 0;
__u32 log_len;
__u32 single_len;
bool huge;
int err = 0;
FILE *fd = NULL;
struct nvme_get_log_args args = {
.args_size = sizeof(args),
.fd = dev_fd(dev),
.lid = NVME_LOG_LID_PERSISTENT_EVENT,
.nsid = namespace_id,
.lpo = NVME_LOG_LPO_NONE,
.lsp = NVME_LOG_LSP_NONE,
.lsi = NVME_LOG_LSI_NONE,
.rae = false,
.uuidx = NVME_UUID_NONE,
.csi = NVME_CSI_NVM,
.ot = false,
.len = 0,
.log = NULL,
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
.result = NULL,
};
if (!storage_medium) {
lsp_base = 0;
single_len = 64 * 1024 - 4;
} else {
lsp_base = 4;
single_len = 32 * 1024;
}
pevent = calloc(sizeof(*pevent), sizeof(__u8));
if (!pevent) {
err = -ENOMEM;
goto ret;
}
args.lsp = lsp_base + NVME_PEVENT_LOG_RELEASE_CTX;
args.log = pevent;
args.len = sizeof(*pevent);
err = nvme_get_log(&args);
if (err) {
fprintf(stderr, "Unable to get evtlog lsp=0x%x, ret = 0x%x\n", args.lsp, err);
goto free_pevent;
}
args.lsp = lsp_base + NVME_PEVENT_LOG_EST_CTX_AND_READ;
err = nvme_get_log(&args);
if (err) {
fprintf(stderr, "Unable to get evtlog lsp=0x%x, ret = 0x%x\n", args.lsp, err);
goto free_pevent;
}
log_len = le64_to_cpu(pevent->tll);
if (log_len % 4)
log_len = (log_len / 4 + 1) * 4;
pevent_log_info = nvme_alloc(single_len, &huge);
if (!pevent_log_info) {
err = -ENOMEM;
goto free_pevent;
}
fd = fopen(file, "wb+");
if (!fd) {
fprintf(stderr, "Failed to open %s file to write\n", file);
err = ENOENT;
goto free;
}
args.lsp = lsp_base + NVME_PEVENT_LOG_READ;
args.log = pevent_log_info;
length = log_len;
while (length > 0) {
args.lpo = offset;
if (length > single_len) {
args.len = single_len;
} else {
memset(args.log, 0, args.len);
args.len = length;
}
err = nvme_get_log(&args);
if (err) {
fprintf(stderr, "Unable to get evtlog offset=0x%x len 0x%x ret = 0x%x\n", offset, args.len, err);
goto close_fd;
}
if (fwrite(args.log, 1, args.len, fd) != args.len) {
fprintf(stderr, "Failed to write evtlog to file\n");
goto close_fd;
}
offset += args.len;
length -= args.len;
util_spinner("Parse", (float) (offset) / (float) (log_len));
}
printf("\nDump-evtlog: Success\n");
if (parse) {
nvme_free(pevent_log_info, huge);
pevent_log_info = nvme_alloc(log_len, &huge);
if (!pevent_log_info) {
fprintf(stderr, "Failed to alloc enough memory 0x%x to parse evtlog\n", log_len);
err = -ENOMEM;
goto close_fd;
}
fclose(fd);
fd = fopen(file, "rb");
if (!fd) {
fprintf(stderr, "Failed to open %s file to read\n", file);
err = ENOENT;
goto free;
}
if (fread(pevent_log_info, 1, log_len, fd) != log_len) {
fprintf(stderr, "Failed to read evtlog to buffer\n");
goto close_fd;
}
err = nvme_parse_evtlog(pevent_log_info, log_len, output);
}
close_fd:
fclose(fd);
free:
nvme_free(pevent_log_info, huge);
free_pevent:
free(pevent);
ret:
return err;
}
static int sfx_dump_evtlog(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
char *desc = "dump evtlog into file and parse";
const char *file = "evtlog file(required)";
const char *namespace_id = "desired namespace";
const char *storage_medium = "evtlog storage medium\n"
"0: nand(default) 1: nor";
const char *parse = "parse error & warning evtlog from evtlog file";
const char *output = "parse result output file";
struct nvme_dev *dev;
int err = 0;
struct config {
char *file;
__u32 namespace_id;
__u32 storage_medium;
bool parse;
char *output;
};
struct config cfg = {
.file = NULL,
.namespace_id = 0xffffffff,
.storage_medium = 0,
.parse = false,
.output = NULL,
};
OPT_ARGS(opts) = {
OPT_FILE("file", 'f', &cfg.file, file),
OPT_UINT("namespace_id", 'n', &cfg.namespace_id, namespace_id),
OPT_UINT("storage_medium", 's', &cfg.storage_medium, storage_medium),
OPT_FLAG("parse", 'p', &cfg.parse, parse),
OPT_FILE("output", 'o', &cfg.output, output),
OPT_END()
};
err = parse_and_open(&dev, argc, argv, desc, opts);
if (err)
goto ret;
if (!cfg.file) {
fprintf(stderr, "file required param\n");
err = EINVAL;
goto close_dev;
}
if (cfg.parse && !cfg.output) {
fprintf(stderr, "output file required if evtlog need be parsed\n");
err = EINVAL;
goto close_dev;
}
err = nvme_dump_evtlog(dev, cfg.namespace_id, cfg.storage_medium, cfg.file, cfg.parse, cfg.output);
close_dev:
dev_close(dev);
ret:
return err;
}
static int nvme_expand_cap(struct nvme_dev *dev, __u32 namespace_id, __u64 namespace_size,
__u64 namespace_cap, __u32 lbaf, __u32 units)
{
struct dirent **devices;
char dev_name[32] = "";
int i = 0;
int num = 0;
int err = 0;
struct sfx_expand_cap_info {
__u64 namespace_size;
__u64 namespace_cap;
__u8 reserve[10];
__u8 lbaf;
__u8 reserve1[5];
} __packed;
if (S_ISCHR(dev->direct.stat.st_mode))
snprintf(dev_name, 32, "%sn%u", dev->name, namespace_id);
else
strcpy(dev_name, dev->name);
num = scandir("/dev", &devices, nvme_namespace_filter, alphasort);
if (num <= 0) {
err = num;
goto ret;
}
if (strcmp(dev_name, devices[num-1]->d_name)) {
fprintf(stderr, "Expand namespace not the last one\n");
err = EINVAL;
goto free_devices;
}
if (!units) {
namespace_size = IDEMA_CAP(namespace_size) / (1 << (lbaf * 3));
namespace_cap = IDEMA_CAP(namespace_cap) / (1 << (lbaf * 3));
}
struct sfx_expand_cap_info info = {
.namespace_size = namespace_size,
.namespace_cap = namespace_cap,
.lbaf = lbaf,
};
struct nvme_passthru_cmd cmd = {
.opcode = nvme_admin_ns_mgmt,
.nsid = namespace_id,
.addr = (__u64)(uintptr_t)&info,
.data_len = sizeof(info),
.cdw10 = 0x0e,
};
err = nvme_submit_admin_passthru(dev_fd(dev), &cmd, NULL);
if (err) {
fprintf(stderr, "Create ns failed\n");
nvme_show_status(err);
goto free_devices;
}
free_devices:
for (i = 0; i < num; i++)
free(devices[i]);
free(devices);
ret:
return err;
}
static int sfx_expand_cap(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
char *desc = "expand capacity";
const char *namespace_id = "desired namespace";
const char *namespace_size = "namespace size(required)";
const char *namespace_cap = "namespace capacity(required)";
const char *lbaf = "LBA format to apply\n"
"0: 512(default) 1: 4096";
const char *units = "namespace size/capacity units\n"
"0: GB(default) 1: LBA";
struct nvme_dev *dev;
int err = 0;
struct config {
__u32 namespace_id;
__u64 namespace_size;
__u64 namespace_cap;
__u32 lbaf;
__u32 units;
};
struct config cfg = {
.namespace_id = 0xffffffff,
.lbaf = 0,
.units = 0,
};
OPT_ARGS(opts) = {
OPT_UINT("namespace_id", 'n', &cfg.namespace_id, namespace_id),
OPT_LONG("namespace_size", 's', &cfg.namespace_size, namespace_size),
OPT_LONG("namespace_cap", 'c', &cfg.namespace_cap, namespace_cap),
OPT_UINT("lbaf", 'l', &cfg.lbaf, lbaf),
OPT_UINT("units", 'u', &cfg.units, units),
OPT_END()
};
err = parse_and_open(&dev, argc, argv, desc, opts);
if (err)
goto ret;
if (cfg.namespace_id == 0xffffffff) {
if (S_ISCHR(dev->direct.stat.st_mode)) {
fprintf(stderr, "namespace_id or blk device required\n");
err = EINVAL;
goto ret;
} else {
cfg.namespace_id = atoi(&dev->name[strlen(dev->name) - 1]);
}
}
if (!cfg.namespace_size) {
fprintf(stderr, "namespace_size required param\n");
err = EINVAL;
goto close_dev;
}
if (!cfg.namespace_cap) {
fprintf(stderr, "namespace_cap required param\n");
err = EINVAL;
goto close_dev;
}
err = nvme_expand_cap(dev, cfg.namespace_id, cfg.namespace_size, cfg.namespace_cap, cfg.lbaf, cfg.units);
if (err)
goto close_dev;
printf("%s: Success, create nsid:%d\n", cmd->name, cfg.namespace_id);
close_dev:
dev_close(dev);
ret:
return err;
}

View file

@ -16,6 +16,8 @@ PLUGIN(NAME("sfx", "ScaleFlux vendor specific extensions", NVME_VERSION),
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("dump-evtlog", "dump evtlog into file and parse warning & error log", sfx_dump_evtlog)
ENTRY("expand-cap", "expand the last namespace capacity lossless", sfx_expand_cap)
)
);

View file

@ -54,79 +54,54 @@ static char *log_pages_supp_print(__u32 pageID)
switch (pageID) {
case 0x01:
return "ERROR_INFORMATION";
break;
case 0x02:
return "SMART_INFORMATION";
break;
case 0x03:
return "FW_SLOT_INFORMATION";
break;
case 0x04:
return "CHANGED_NAMESPACE_LIST";
break;
case 0x05:
return "COMMANDS_SUPPORTED_AND_EFFECTS";
break;
case 0x06:
return "DEVICE_SELF_TEST";
break;
case 0x07:
return "TELEMETRY_HOST_INITIATED";
break;
case 0x08:
return "TELEMETRY_CONTROLLER_INITIATED";
break;
case 0xC0:
return "VS_MEDIA_SMART_LOG";
break;
case 0xC1:
return "VS_DEBUG_LOG1";
break;
case 0xC2:
return "VS_SEC_ERROR_LOG_PAGE";
break;
case 0xC3:
return "VS_LIFE_TIME_DRIVE_HISTORY";
break;
case 0xC4:
return "VS_EXTENDED_SMART_INFO";
break;
case 0xC5:
return "VS_LIST_SUPPORTED_LOG_PAGE";
break;
case 0xC6:
return "VS_POWER_MONITOR_LOG_PAGE";
break;
case 0xC7:
return "VS_CRITICAL_EVENT_LOG_PAGE";
break;
case 0xC8:
return "VS_RECENT_DRIVE_HISTORY";
break;
case 0xC9:
return "VS_SEC_ERROR_LOG_PAGE";
break;
case 0xCA:
return "VS_LIFE_TIME_DRIVE_HISTORY";
break;
case 0xCB:
return "VS_PCIE_ERROR_LOG_PAGE";
break;
case 0xCF:
return "DRAM Supercap SMART Attributes";
break;
case 0xD6:
return "VS_OEM2_WORK_LOAD";
break;
case 0xD7:
return "VS_OEM2_FW_SECURITY";
break;
case 0xD8:
return "VS_OEM2_REVISION";
break;
default:
return "UNKNOWN";
break;
}
}
@ -136,9 +111,8 @@ static int stx_is_jag_pan(char *devMN)
for (int i = 0; i < STX_NUM_LEGACY_DRV; i++) {
match_found = strncmp(devMN, stx_jag_pan_mn[i], strlen(stx_jag_pan_mn[i]));
if (match_found == 0) {
if (!match_found)
break;
}
}
return match_found;
@ -157,6 +131,7 @@ static void json_log_pages_supp(log_page_map *logPageMap)
for (i = 0; i < le32_to_cpu(logPageMap->NumLogPages); i++) {
struct json_object *lbaf = json_create_object();
json_object_add_value_int(lbaf, "logpage_id",
le32_to_cpu(logPageMap->LogPageEntry[i].LogPageID));
json_object_add_value_string(lbaf, "logpage_name",
@ -199,9 +174,9 @@ static int log_pages_supp(int argc, char **argv, struct command *cmd,
sizeof(logPageMap), &logPageMap);
if (!err) {
if (strcmp(cfg.output_format, "json")) {
printf ("Seagate Supported Log-pages count :%d\n",
printf("Seagate Supported Log-pages count :%d\n",
le32_to_cpu(logPageMap.NumLogPages));
printf ("%-15s %-30s\n", "LogPage-Id", "LogPage-Name");
printf("%-15s %-30s\n", "LogPage-Id", "LogPage-Name");
for (fmt = 0; fmt < 45; fmt++)
printf("-");
@ -227,154 +202,107 @@ static int log_pages_supp(int argc, char **argv, struct command *cmd,
/* EOF Command for "log-pages-supp" */
/***************************************
* Extended-SMART Information
***************************************/
* Extended-SMART Information
***************************************/
static char *print_ext_smart_id(__u8 attrId)
{
switch (attrId) {
case VS_ATTR_ID_SOFT_READ_ERROR_RATE:
return "Soft ECC error count";
break;
case VS_ATTR_ID_REALLOCATED_SECTOR_COUNT:
return "Bad NAND block count";
break;
case VS_ATTR_ID_POWER_ON_HOURS:
return "Power On Hours";
break;
case VS_ATTR_ID_POWER_FAIL_EVENT_COUNT:
return "Power Fail Event Count";
break;
case VS_ATTR_ID_DEVICE_POWER_CYCLE_COUNT:
return "Device Power Cycle Count";
break;
case VS_ATTR_ID_RAW_READ_ERROR_RATE:
return "Raw Read Error Count";
break;
case VS_ATTR_ID_GROWN_BAD_BLOCK_COUNT:
return "Bad NAND block count";
break;
case VS_ATTR_ID_END_2_END_CORRECTION_COUNT:
return "SSD End to end correction counts";
break;
case VS_ATTR_ID_MIN_MAX_WEAR_RANGE_COUNT:
return "User data erase counts";
break;
case VS_ATTR_ID_REFRESH_COUNT:
return "Refresh count";
break;
case VS_ATTR_ID_BAD_BLOCK_COUNT_USER:
return "User data erase fail count";
break;
case VS_ATTR_ID_BAD_BLOCK_COUNT_SYSTEM:
return "System area erase fail count";
break;
case VS_ATTR_ID_THERMAL_THROTTLING_STATUS:
return "Thermal throttling status and count";
break;
case VS_ATTR_ID_ALL_PCIE_CORRECTABLE_ERROR_COUNT:
return "PCIe Correctable Error count";
break;
case VS_ATTR_ID_ALL_PCIE_UNCORRECTABLE_ERROR_COUNT:
return "PCIe Uncorrectable Error count";
break;
case VS_ATTR_ID_INCOMPLETE_SHUTDOWN_COUNT:
return "Incomplete shutdowns";
break;
case VS_ATTR_ID_GB_ERASED_LSB:
return "LSB of Flash GB erased";
break;
case VS_ATTR_ID_GB_ERASED_MSB:
return "MSB of Flash GB erased";
break;
case VS_ATTR_ID_LIFETIME_DEVSLEEP_EXIT_COUNT:
return "LIFETIME_DEV_SLEEP_EXIT_COUNT";
break;
case VS_ATTR_ID_LIFETIME_ENTERING_PS4_COUNT:
return "LIFETIME_ENTERING_PS4_COUNT";
break;
case VS_ATTR_ID_LIFETIME_ENTERING_PS3_COUNT:
return "LIFETIME_ENTERING_PS3_COUNT";
break;
case VS_ATTR_ID_RETIRED_BLOCK_COUNT:
return "Retired block count";
break;
case VS_ATTR_ID_PROGRAM_FAILURE_COUNT:
return "Program fail count";
break;
case VS_ATTR_ID_ERASE_FAIL_COUNT:
return "Erase Fail Count";
break;
case VS_ATTR_ID_AVG_ERASE_COUNT:
return "System data % used";
break;
case VS_ATTR_ID_UNEXPECTED_POWER_LOSS_COUNT:
return "Unexpected power loss count";
break;
case VS_ATTR_ID_WEAR_RANGE_DELTA:
return "Wear range delta";
break;
case VS_ATTR_ID_SATA_INTERFACE_DOWNSHIFT_COUNT:
return "PCIE_INTF_DOWNSHIFT_COUNT";
break;
case VS_ATTR_ID_END_TO_END_CRC_ERROR_COUNT:
return "E2E_CRC_ERROR_COUNT";
break;
case VS_ATTR_ID_UNCORRECTABLE_READ_ERRORS:
return "Uncorrectable Read Error Count";
break;
case VS_ATTR_ID_MAX_LIFE_TEMPERATURE:
return "Max lifetime temperature";
break;
case VS_ATTR_ID_RAISE_ECC_CORRECTABLE_ERROR_COUNT:
return "RAIS_ECC_CORRECT_ERR_COUNT";
break;
case VS_ATTR_ID_UNCORRECTABLE_RAISE_ERRORS:
return "Uncorrectable RAISE error count";
break;
case VS_ATTR_ID_DRIVE_LIFE_PROTECTION_STATUS:
return "DRIVE_LIFE_PROTECTION_STATUS";
break;
case VS_ATTR_ID_REMAINING_SSD_LIFE:
return "Remaining SSD life";
break;
case VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_LSB:
return "LSB of Physical (NAND) bytes written";
break;
case VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_MSB:
return "MSB of Physical (NAND) bytes written";
break;
case VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_LSB:
return "LSB of Physical (HOST) bytes written";
break;
case VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_MSB:
return "MSB of Physical (HOST) bytes written";
break;
case VS_ATTR_ID_LIFETIME_READS_TO_HOST_LSB:
return "LSB of Physical (NAND) bytes read";
break;
case VS_ATTR_ID_LIFETIME_READS_TO_HOST_MSB:
return "MSB of Physical (NAND) bytes read";
break;
case VS_ATTR_ID_FREE_SPACE:
return "Free Space";
break;
case VS_ATTR_ID_TRIM_COUNT_LSB:
return "LSB of Trim count";
break;
case VS_ATTR_ID_TRIM_COUNT_MSB:
return "MSB of Trim count";
break;
case VS_ATTR_ID_OP_PERCENTAGE:
return "OP percentage";
break;
case VS_ATTR_ID_MAX_SOC_LIFE_TEMPERATURE:
return "Max lifetime SOC temperature";
break;
default:
return "Un-Known";
}
}
}
static __u64 smart_attribute_vs(__u16 verNo, SmartVendorSpecific attr)
@ -451,14 +379,13 @@ static void print_smart_log(__u16 verNo, SmartVendorSpecific attr, int lastAttr)
hideAttr = 1;
}
if ((attr.AttributeNumber != 0) && (hideAttr != 1)) {
if ((attr.AttributeNumber) && (hideAttr != 1)) {
printf("%-40s", print_ext_smart_id(attr.AttributeNumber));
printf("%-15d", attr.AttributeNumber);
printf(" 0x%016"PRIx64"\n", (uint64_t)smart_attribute_vs(verNo, attr));
}
if (lastAttr == 1) {
sprintf(strBuf, "%s", (print_ext_smart_id(VS_ATTR_ID_GB_ERASED_LSB) + 7));
printf("%-40s", strBuf);
@ -516,7 +443,8 @@ static void json_print_smart_log(struct json_object *root, EXTENDED_SMART_INFO_T
for (index = 0; index < NUMBER_EXTENDED_SMART_ATTRIBUTES; index++) {
struct json_object *lbaf = json_create_object();
if (ExtdSMARTInfo->vendorData[index].AttributeNumber != 0) {
if (ExtdSMARTInfo->vendorData[index].AttributeNumber) {
json_object_add_value_string(lbaf, "attribute_name", print_ext_smart_id(ExtdSMARTInfo->vendorData[index].AttributeNumber));
json_object_add_value_int(lbaf, "attribute_id", ExtdSMARTInfo->vendorData[index].AttributeNumber);
json_object_add_value_int(lbaf, "attribute_value", smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]));
@ -612,8 +540,9 @@ static void json_print_smart_log(struct json_object *root, EXTENDED_SMART_INFO_T
static void print_smart_log_CF(vendor_log_page_CF *pLogPageCF)
{
__u64 currentTemp, maxTemp;
printf("\n\nSeagate DRAM Supercap SMART Attributes :\n");
printf("%-39s %-19s \n", "Description", "Supercap Attributes");
printf("%-39s %-19s\n", "Description", "Supercap Attributes");
printf("%-40s", "Super-cap current temperature");
currentTemp = pLogPageCF->AttrCF.SuperCapCurrentTemperature;
@ -698,7 +627,7 @@ static void json_print_smart_log_CF(struct json_object *root, vendor_log_page_CF
static void print_stx_smart_log_C0(STX_EXT_SMART_LOG_PAGE_C0 *pLogPageC0)
{
printf("\n\nSeagate SMART Health Attributes :\n");
printf("%-39s %-19s \n", "Description", "Health Attributes");
printf("%-39s %-19s\n", "Description", "Health Attributes");
printf("%-40s", "Physical Media Units Written");
printf(" 0x%016"PRIx64"%016"PRIx64"\n", le64_to_cpu(pLogPageC0->phyMediaUnitsWrt.MS__u64),
@ -986,7 +915,7 @@ static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugi
err = parse_and_open(&dev, argc, argv, desc, opts);
if (err) {
printf ("\nDevice not found \n");
printf("\nDevice not found\n");
return -1;
}
@ -1008,12 +937,11 @@ static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugi
return err;
}
if (stx_is_jag_pan(modelNo) == 0) {
if (!stx_is_jag_pan(modelNo)) {
err = nvme_get_log_simple(dev_fd(dev), 0xC4, sizeof(ExtdSMARTInfo), &ExtdSMARTInfo);
if (!err) {
if (strcmp(cfg.output_format, "json")) {
printf("%-39s %-15s %-19s \n", "Description", "Ext-Smart-Id", "Ext-Smart-Value");
printf("%-39s %-15s %-19s\n", "Description", "Ext-Smart-Id", "Ext-Smart-Value");
for (index = 0; index < 80; index++)
printf("-");
printf("\n");
@ -1046,15 +974,15 @@ static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugi
json_print_object(root, NULL);
json_free_object(root);
}
} else if (err > 0)
} else if (err > 0) {
nvme_show_status(err);
}
} else {
err = nvme_get_log_simple(dev_fd(dev), 0xC0, sizeof(ehExtSmart), &ehExtSmart);
if (!err) {
if (strcmp(cfg.output_format, "json")) {
print_stx_smart_log_C0(&ehExtSmart);
} else {
lbafs_ExtSmart = json_create_object();
json_print_stx_smart_log_C0(lbafs_ExtSmart, &ehExtSmart);
@ -1075,7 +1003,7 @@ static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugi
sizeof(ExtdSMARTInfo), &ExtdSMARTInfo);
if (!err) {
if (strcmp(cfg.output_format, "json")) {
printf("%-39s %-15s %-19s \n", "Description", "Ext-Smart-Id", "Ext-Smart-Value");
printf("%-39s %-15s %-19s\n", "Description", "Ext-Smart-Id", "Ext-Smart-Value");
for (index = 0; index < 80; index++)
printf("-");
printf("\n");
@ -1105,10 +1033,12 @@ static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugi
json_array_add_value_object(lbafs, lbafs_DramSmart);
json_print_object(root, NULL);
}
} else if (!strcmp(cfg.output_format, "json"))
} else if (!strcmp(cfg.output_format, "json")) {
json_print_object(root, NULL);
} else if (err > 0)
}
} else if (err > 0) {
nvme_show_status(err);
}
dev_close(dev);
@ -1123,8 +1053,7 @@ static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugi
static void json_temp_stats(__u32 temperature, __u32 PcbTemp, __u32 SocTemp, __u32 maxTemperature,
__u32 MaxSocTemp, __u32 cf_err, __u32 scCurrentTemp, __u32 scMaxTem)
{
struct json_object *root;
root = json_create_object();
struct json_object *root = json_create_object();
json_object_add_value_int(root, "Current temperature", temperature);
json_object_add_value_int(root, "Current PCB temperature", PcbTemp);
@ -1167,7 +1096,7 @@ static int temp_stats(int argc, char **argv, struct command *cmd, struct plugin
err = parse_and_open(&dev, argc, argv, desc, opts);
if (err) {
printf ("\nDevice not found \n");;
printf("\nDevice not found\n");
return -1;
}
@ -1239,19 +1168,16 @@ static int temp_stats(int argc, char **argv, struct command *cmd, struct plugin
***************************************/
static void print_vs_pcie_error_log(pcie_error_log_page pcieErrorLog)
{
__u32 correctPcieEc = 0;
__u32 uncorrectPcieEc = 0;
correctPcieEc = pcieErrorLog.BadDllpErrCnt + pcieErrorLog.BadTlpErrCnt
+ pcieErrorLog.RcvrErrCnt + pcieErrorLog.ReplayTOErrCnt
+ pcieErrorLog.ReplayNumRolloverErrCnt;
uncorrectPcieEc = pcieErrorLog.FCProtocolErrCnt + pcieErrorLog.DllpProtocolErrCnt
+ pcieErrorLog.CmpltnTOErrCnt + pcieErrorLog.RcvrQOverflowErrCnt
+ pcieErrorLog.UnexpectedCplTlpErrCnt + pcieErrorLog.CplTlpURErrCnt
+ pcieErrorLog.CplTlpCAErrCnt + pcieErrorLog.ReqCAErrCnt
+ pcieErrorLog.ReqURErrCnt + pcieErrorLog.EcrcErrCnt
+ pcieErrorLog.MalformedTlpErrCnt + pcieErrorLog.CplTlpPoisonedErrCnt
+ pcieErrorLog.MemRdTlpPoisonedErrCnt;
__u32 correctPcieEc = pcieErrorLog.BadDllpErrCnt + pcieErrorLog.BadTlpErrCnt +
pcieErrorLog.RcvrErrCnt + pcieErrorLog.ReplayTOErrCnt +
pcieErrorLog.ReplayNumRolloverErrCnt;
__u32 uncorrectPcieEc = pcieErrorLog.FCProtocolErrCnt + pcieErrorLog.DllpProtocolErrCnt +
pcieErrorLog.CmpltnTOErrCnt + pcieErrorLog.RcvrQOverflowErrCnt +
pcieErrorLog.UnexpectedCplTlpErrCnt + pcieErrorLog.CplTlpURErrCnt +
pcieErrorLog.CplTlpCAErrCnt + pcieErrorLog.ReqCAErrCnt +
pcieErrorLog.ReqURErrCnt + pcieErrorLog.EcrcErrCnt +
pcieErrorLog.MalformedTlpErrCnt + pcieErrorLog.CplTlpPoisonedErrCnt +
pcieErrorLog.MemRdTlpPoisonedErrCnt;
printf("%-45s : %u\n", "PCIe Correctable Error Count", correctPcieEc);
printf("%-45s : %u\n", "PCIe Un-Correctable Error Count", uncorrectPcieEc);
@ -1279,21 +1205,17 @@ static void print_vs_pcie_error_log(pcie_error_log_page pcieErrorLog)
static void json_vs_pcie_error_log(pcie_error_log_page pcieErrorLog)
{
struct json_object *root;
root = json_create_object();
__u32 correctPcieEc = 0;
__u32 uncorrectPcieEc = 0;
correctPcieEc = pcieErrorLog.BadDllpErrCnt + pcieErrorLog.BadTlpErrCnt
+ pcieErrorLog.RcvrErrCnt + pcieErrorLog.ReplayTOErrCnt
+ pcieErrorLog.ReplayNumRolloverErrCnt;
uncorrectPcieEc = pcieErrorLog.FCProtocolErrCnt + pcieErrorLog.DllpProtocolErrCnt
+ pcieErrorLog.CmpltnTOErrCnt + pcieErrorLog.RcvrQOverflowErrCnt
+ pcieErrorLog.UnexpectedCplTlpErrCnt + pcieErrorLog.CplTlpURErrCnt
+ pcieErrorLog.CplTlpCAErrCnt + pcieErrorLog.ReqCAErrCnt
+ pcieErrorLog.ReqURErrCnt + pcieErrorLog.EcrcErrCnt
+ pcieErrorLog.MalformedTlpErrCnt + pcieErrorLog.CplTlpPoisonedErrCnt
+ pcieErrorLog.MemRdTlpPoisonedErrCnt;
struct json_object *root = json_create_object();
__u32 correctPcieEc = pcieErrorLog.BadDllpErrCnt + pcieErrorLog.BadTlpErrCnt +
pcieErrorLog.RcvrErrCnt + pcieErrorLog.ReplayTOErrCnt +
pcieErrorLog.ReplayNumRolloverErrCnt;
__u32 uncorrectPcieEc = pcieErrorLog.FCProtocolErrCnt + pcieErrorLog.DllpProtocolErrCnt +
pcieErrorLog.CmpltnTOErrCnt + pcieErrorLog.RcvrQOverflowErrCnt +
pcieErrorLog.UnexpectedCplTlpErrCnt + pcieErrorLog.CplTlpURErrCnt +
pcieErrorLog.CplTlpCAErrCnt + pcieErrorLog.ReqCAErrCnt +
pcieErrorLog.ReqURErrCnt + pcieErrorLog.EcrcErrCnt +
pcieErrorLog.MalformedTlpErrCnt + pcieErrorLog.CplTlpPoisonedErrCnt +
pcieErrorLog.MemRdTlpPoisonedErrCnt;
json_object_add_value_int(root, "PCIe Correctable Error Count", correctPcieEc);
json_object_add_value_int(root, "PCIe Un-Correctable Error Count", uncorrectPcieEc);
@ -1341,7 +1263,7 @@ static int vs_pcie_error_log(int argc, char **argv, struct command *cmd, struct
err = parse_and_open(&dev, argc, argv, desc, opts);
if (err) {
printf ("\nDevice not found \n");;
printf("\nDevice not found\n");
return -1;
}
@ -1351,13 +1273,14 @@ static int vs_pcie_error_log(int argc, char **argv, struct command *cmd, struct
err = nvme_get_log_simple(dev_fd(dev), 0xCB,
sizeof(pcieErrorLog), &pcieErrorLog);
if (!err) {
if (strcmp(cfg.output_format, "json")) {
if (strcmp(cfg.output_format, "json"))
print_vs_pcie_error_log(pcieErrorLog);
} else
else
json_vs_pcie_error_log(pcieErrorLog);
} else if (err > 0)
} else if (err > 0) {
nvme_show_status(err);
}
dev_close(dev);
return err;
@ -1384,8 +1307,8 @@ static void print_stx_vs_fw_activate_history(stx_fw_activ_history_log_page fwAct
printf(" %-4d ", fwActivHis.fwActHisEnt[i].fwActivCnt);
time_t t = fwActivHis.fwActHisEnt[i].timeStamp / 1000;
struct tm ts;
ts = *localtime(&t);
struct tm ts = *localtime(&t);
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &ts);
printf(" %-20s ", buf);
printf("%-5" PRId64 " ",
@ -1401,7 +1324,7 @@ static void print_stx_vs_fw_activate_history(stx_fw_activ_history_log_page fwAct
printf(" %-2d ", fwActivHis.fwActHisEnt[i].slotNum);
printf(" 0x%02x ", fwActivHis.fwActHisEnt[i].commitActionType);
printf(" 0x%02x \n", fwActivHis.fwActHisEnt[i].result);
printf(" 0x%02x\n", fwActivHis.fwActHisEnt[i].result);
}
} else {
printf("%s\n", "Do not have valid FW Activation History");
@ -1410,14 +1333,13 @@ static void print_stx_vs_fw_activate_history(stx_fw_activ_history_log_page fwAct
static void json_stx_vs_fw_activate_history(stx_fw_activ_history_log_page fwActivHis)
{
struct json_object *root;
root = json_create_object();
struct json_object *root = json_create_object();
__u32 i;
char buf[80];
struct json_object *historyLogPage;
historyLogPage = json_create_array();
struct json_object *historyLogPage = json_create_array();
json_object_add_value_array(root, "Seagate FW Activation History", historyLogPage);
if (fwActivHis.numValidFwActHisEnt > 0) {
@ -1429,8 +1351,8 @@ static void json_stx_vs_fw_activate_history(stx_fw_activ_history_log_page fwActi
json_object_add_value_int(lbaf, "Counter", fwActivHis.fwActHisEnt[i].fwActivCnt);
time_t t = fwActivHis.fwActHisEnt[i].timeStamp / 1000;
struct tm ts;
ts = *localtime(&t);
struct tm ts = *localtime(&t);
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &ts);
printf(" %-20s ", buf);
json_object_add_value_string(lbaf, "Timestamp", buf);
@ -1479,7 +1401,7 @@ static int stx_vs_fw_activate_history(int argc, char **argv, struct command *cmd
err = parse_and_open(&dev, argc, argv, desc, opts);
if (err < 0) {
printf ("\nDevice not found \n");;
printf("\nDevice not found\n");
return -1;
}
@ -1488,13 +1410,14 @@ static int stx_vs_fw_activate_history(int argc, char **argv, struct command *cmd
err = nvme_get_log_simple(dev_fd(dev), 0xC2, sizeof(fwActivHis), &fwActivHis);
if (!err) {
if (strcmp(cfg.output_format, "json")) {
if (strcmp(cfg.output_format, "json"))
print_stx_vs_fw_activate_history(fwActivHis);
} else
else
json_stx_vs_fw_activate_history(fwActivHis);
} else if (err > 0)
} else if (err > 0) {
nvme_show_status(err);
}
dev_close(dev);
return err;
@ -1527,7 +1450,7 @@ static int clear_fw_activate_history(int argc, char **argv, struct command *cmd,
err = parse_and_open(&dev, argc, argv, desc, opts);
if (err < 0) {
printf ("\nDevice not found \n");
printf("\nDevice not found\n");
return -1;
}
@ -1539,10 +1462,9 @@ static int clear_fw_activate_history(int argc, char **argv, struct command *cmd,
return err;
}
if (stx_is_jag_pan(modelNo) == 0) {
printf ("\nDevice does not support Clear FW Activation History \n");
if (!stx_is_jag_pan(modelNo)) {
printf("\nDevice does not support Clear FW Activation History\n");
} else {
struct nvme_set_features_args args = {
.args_size = sizeof(args),
.fd = dev_fd(dev),
@ -1560,7 +1482,7 @@ static int clear_fw_activate_history(int argc, char **argv, struct command *cmd,
};
err = nvme_set_features(&args);
if (err)
fprintf(stderr, "%s: couldn't clear PCIe correctable errors \n",
fprintf(stderr, "%s: couldn't clear PCIe correctable errors\n",
__func__);
}
@ -1602,7 +1524,7 @@ static int vs_clr_pcie_correctable_errs(int argc, char **argv, struct command *c
err = parse_and_open(&dev, argc, argv, desc, opts);
if (err) {
printf ("\nDevice not found \n");;
printf("\nDevice not found\n");
return -1;
}
@ -1615,27 +1537,27 @@ static int vs_clr_pcie_correctable_errs(int argc, char **argv, struct command *c
return err;
}
if (stx_is_jag_pan(modelNo) == 0) {
if (!stx_is_jag_pan(modelNo)) {
err = nvme_set_features_simple(dev_fd(dev), 0xE1, 0, 0xCB, cfg.save, &result);
} else {
struct nvme_set_features_args args = {
.args_size = sizeof(args),
.fd = dev_fd(dev),
.fid = 0xC3,
.nsid = 0,
.cdw11 = 0x80000000,
.cdw12 = 0,
.save = 0,
.uuidx = 0,
.cdw15 = 0,
.data_len = 0,
.data = NULL,
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
.result = &result,
};
err = nvme_set_features(&args);
if (err)
fprintf(stderr, "%s: couldn't clear PCIe correctable errors \n", __func__);
.args_size = sizeof(args),
.fd = dev_fd(dev),
.fid = 0xC3,
.nsid = 0,
.cdw11 = 0x80000000,
.cdw12 = 0,
.save = 0,
.uuidx = 0,
.cdw15 = 0,
.data_len = 0,
.data = NULL,
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
.result = &result,
};
err = nvme_set_features(&args);
if (err)
fprintf(stderr, "%s: couldn't clear PCIe correctable errors\n", __func__);
}
err = nvme_set_features_simple(dev_fd(dev), 0xE1, 0, 0xCB, cfg.save, &result);
@ -1651,11 +1573,11 @@ static int vs_clr_pcie_correctable_errs(int argc, char **argv, struct command *c
static int get_host_tele(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Capture the Telemetry Host-Initiated Data in either " \
"hex-dump (default) or binary format";
const char *desc =
"Capture the Telemetry Host-Initiated Data in either hex-dump (default) or binary format";
const char *namespace_id = "desired namespace";
const char *log_specific = "1 - controller shall capture Data representing the internal " \
"state of the controller at the time the command is processed. " \
const char *log_specific = "1 - controller shall capture Data representing the internal\n"
"state of the controller at the time the command is processed.\n"
"0 - controller shall not update the Telemetry Host Initiated Data.";
const char *raw = "output in raw format";
struct nvme_temetry_log_hdr tele_log;
@ -1706,10 +1628,11 @@ static int get_host_tele(int argc, char **argv, struct command *cmd, struct plug
d((unsigned char *)(&tele_log), sizeof(tele_log), 16, 1);
} else
seaget_d_raw((unsigned char *)(&tele_log), sizeof(tele_log), dump_fd);
} else if (err > 0)
} else if (err > 0) {
nvme_show_status(err);
else
} else {
perror("log page");
}
blkCnt = 0;
@ -1718,7 +1641,7 @@ static int get_host_tele(int argc, char **argv, struct command *cmd, struct plug
blksToGet = ((maxBlk - blkCnt) >= TELEMETRY_BLOCKS_TO_READ) ? TELEMETRY_BLOCKS_TO_READ : (maxBlk - blkCnt);
if (blksToGet == 0) {
if (!blksToGet) {
dev_close(dev);
return err;
}
@ -1729,7 +1652,7 @@ static int get_host_tele(int argc, char **argv, struct command *cmd, struct plug
if (!log) {
fprintf(stderr, "could not alloc buffer for log\n");
dev_close(dev);
return EINVAL;
return -EINVAL;
}
memset(log, 0, bytesToGet);
@ -1761,10 +1684,11 @@ static int get_host_tele(int argc, char **argv, struct command *cmd, struct plug
d((unsigned char *)log, bytesToGet, 16, 1);
} else
seaget_d_raw((unsigned char *)log, bytesToGet, dump_fd);
} else if (err > 0)
} else if (err > 0) {
nvme_show_status(err);
else
} else {
perror("log page");
}
blkCnt += blksToGet;
@ -1777,8 +1701,8 @@ static int get_host_tele(int argc, char **argv, struct command *cmd, struct plug
static int get_ctrl_tele(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Capture the Telemetry Controller-Initiated Data in either " \
"hex-dump (default) or binary format";
const char *desc =
"Capture the Telemetry Controller-Initiated Data in either hex-dump (default) or binary format";
const char *namespace_id = "desired namespace";
const char *raw = "output in raw format";
struct nvme_dev *dev;
@ -1826,10 +1750,11 @@ static int get_ctrl_tele(int argc, char **argv, struct command *cmd, struct plug
d((unsigned char *)(&tele_log), sizeof(tele_log), 16, 1);
} else
seaget_d_raw((unsigned char *)(&tele_log), sizeof(tele_log), dump_fd);
} else if (err > 0)
} else if (err > 0) {
nvme_show_status(err);
else
} else {
perror("log page");
}
blkCnt = 0;
@ -1838,7 +1763,7 @@ static int get_ctrl_tele(int argc, char **argv, struct command *cmd, struct plug
blksToGet = ((maxBlk - blkCnt) >= TELEMETRY_BLOCKS_TO_READ) ? TELEMETRY_BLOCKS_TO_READ : (maxBlk - blkCnt);
if (blksToGet == 0)
if (!blksToGet)
return err;
bytesToGet = (unsigned long long)blksToGet * 512;
@ -1846,7 +1771,7 @@ static int get_ctrl_tele(int argc, char **argv, struct command *cmd, struct plug
if (!log) {
fprintf(stderr, "could not alloc buffer for log\n");
return EINVAL;
return -EINVAL;
}
memset(log, 0, bytesToGet);
@ -1878,10 +1803,11 @@ static int get_ctrl_tele(int argc, char **argv, struct command *cmd, struct plug
d((unsigned char *)log, bytesToGet, 16, 1);
} else
seaget_d_raw((unsigned char *)log, bytesToGet, dump_fd);
} else if (err > 0)
} else if (err > 0) {
nvme_show_status(err);
else
} else {
perror("log page");
}
blkCnt += blksToGet;
@ -1895,21 +1821,20 @@ static int get_ctrl_tele(int argc, char **argv, struct command *cmd, struct plug
void seaget_d_raw(unsigned char *buf, int len, int fd)
{
if (write(fd, (void *)buf, len) <= 0)
printf("%s: Write Failed\n", __FUNCTION__);
printf("%s: Write Failed\n", __func__);
}
static int vs_internal_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Capture the Telemetry Controller-Initiated Data in " \
"binary format";
const char *desc = "Capture the Telemetry Controller-Initiated Data in binary format";
const char *namespace_id = "desired namespace";
const char *file = "dump file";
struct nvme_dev *dev;
int err, dump_fd;
int flags = O_WRONLY | O_CREAT;
int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
int mode = 0664;
struct nvme_temetry_log_hdr tele_log;
__le64 offset = 0;
__u16 log_id;
@ -1942,7 +1867,7 @@ static int vs_internal_log(int argc, char **argv, struct command *cmd, struct pl
if (dump_fd < 0) {
perror(cfg.file);
dev_close(dev);
return EINVAL;
return -EINVAL;
}
}
@ -1954,10 +1879,11 @@ static int vs_internal_log(int argc, char **argv, struct command *cmd, struct pl
offset += 512;
seaget_d_raw((unsigned char *)(&tele_log), sizeof(tele_log), dump_fd);
} else if (err > 0)
} else if (err > 0) {
nvme_show_status(err);
else
} else {
perror("log page");
}
blkCnt = 0;
@ -1966,9 +1892,8 @@ static int vs_internal_log(int argc, char **argv, struct command *cmd, struct pl
blksToGet = ((maxBlk - blkCnt) >= TELEMETRY_BLOCKS_TO_READ) ? TELEMETRY_BLOCKS_TO_READ : (maxBlk - blkCnt);
if (blksToGet == 0) {
if (!blksToGet)
goto out;
}
bytesToGet = (unsigned long long)blksToGet * 512;
log = malloc(bytesToGet);
@ -2004,10 +1929,11 @@ static int vs_internal_log(int argc, char **argv, struct command *cmd, struct pl
seaget_d_raw((unsigned char *)log, bytesToGet, dump_fd);
} else if (err > 0)
} else if (err > 0) {
nvme_show_status(err);
else
} else {
perror("log page");
}
blkCnt += blksToGet;
@ -2024,7 +1950,7 @@ out:
/*SEAGATE-PLUGIN Version */
static int seagate_plugin_version(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
printf("Seagate-Plugin version : %d.%d \n",
printf("Seagate-Plugin version : %d.%d\n",
SEAGATE_PLUGIN_VERSION_MAJOR,
SEAGATE_PLUGIN_VERSION_MINOR);
return 0;
@ -2034,7 +1960,7 @@ static int seagate_plugin_version(int argc, char **argv, struct command *cmd, st
/*OCP SEAGATE-PLUGIN Version */
static int stx_ocp_plugin_version(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
printf("Seagate-OCP-Plugin version : %d.%d \n",
printf("Seagate-OCP-Plugin version : %d.%d\n",
SEAGATE_OCP_PLUGIN_VERSION_MAJOR,
SEAGATE_OCP_PLUGIN_VERSION_MINOR);
return 0;

View file

@ -16,25 +16,25 @@
#define CREATE_CMD
#include "shannon-nvme.h"
typedef enum {
enum {
PROGRAM_FAIL_CNT,
ERASE_FAIL_CNT,
WEARLEVELING_COUNT,
E2E_ERR_CNT,
CRC_ERR_CNT,
TIME_WORKLOAD_MEDIA_WEAR,
TIME_WORKLOAD_HOST_READS,
TIME_WORKLOAD_TIMER,
THERMAL_THROTTLE,
RETRY_BUFFER_OVERFLOW,
PLL_LOCK_LOSS,
TIME_WORKLOAD_MEDIA_WEAR,
TIME_WORKLOAD_HOST_READS,
TIME_WORKLOAD_TIMER,
THERMAL_THROTTLE,
RETRY_BUFFER_OVERFLOW,
PLL_LOCK_LOSS,
NAND_WRITE,
HOST_WRITE,
SRAM_ERROR_CNT,
ADD_SMART_ITEMS,
}addtional_smart_items;
};
#pragma pack(push,1)
#pragma pack(push, 1)
struct nvme_shannon_smart_log_item {
__u8 rsv1[3];
__u8 norm;
@ -45,7 +45,7 @@ struct nvme_shannon_smart_log_item {
__le16 min;
__le16 max;
__le16 avg;
} wear_level ;
} wear_level;
struct thermal_throttle {
__u8 st;
__u32 count;
@ -57,68 +57,67 @@ struct nvme_shannon_smart_log_item {
struct nvme_shannon_smart_log {
struct nvme_shannon_smart_log_item items[ADD_SMART_ITEMS];
__u8 vend_spec_resv;
__u8 vend_spec_resv;
};
static void show_shannon_smart_log(struct nvme_shannon_smart_log *smart,
unsigned int nsid, const char *devname)
static void show_shannon_smart_log(struct nvme_shannon_smart_log *smart, unsigned int nsid,
const char *devname)
{
printf("Additional Smart Log for NVME device:%s namespace-id:%x\n",
devname, nsid);
devname, nsid);
printf("key normalized value\n");
printf("program_fail_count : %3d%% %"PRIu64"\n",
smart->items[PROGRAM_FAIL_CNT].norm,
int48_to_long(smart->items[PROGRAM_FAIL_CNT].item_val));
smart->items[PROGRAM_FAIL_CNT].norm,
int48_to_long(smart->items[PROGRAM_FAIL_CNT].item_val));
printf("erase_fail_count : %3d%% %"PRIu64"\n",
smart->items[ERASE_FAIL_CNT].norm,
int48_to_long(smart->items[ERASE_FAIL_CNT].item_val));
smart->items[ERASE_FAIL_CNT].norm,
int48_to_long(smart->items[ERASE_FAIL_CNT].item_val));
printf("wear_leveling : %3d%% min: %u, max: %u, avg: %u\n",
smart->items[WEARLEVELING_COUNT].norm,
le16_to_cpu(smart->items[WEARLEVELING_COUNT].wear_level.min),
le16_to_cpu(smart->items[WEARLEVELING_COUNT].wear_level.max),
le16_to_cpu(smart->items[WEARLEVELING_COUNT].wear_level.avg));
smart->items[WEARLEVELING_COUNT].norm,
le16_to_cpu(smart->items[WEARLEVELING_COUNT].wear_level.min),
le16_to_cpu(smart->items[WEARLEVELING_COUNT].wear_level.max),
le16_to_cpu(smart->items[WEARLEVELING_COUNT].wear_level.avg));
printf("end_to_end_error_detection_count: %3d%% %"PRIu64"\n",
smart->items[E2E_ERR_CNT].norm,
int48_to_long(smart->items[E2E_ERR_CNT].item_val));
smart->items[E2E_ERR_CNT].norm,
int48_to_long(smart->items[E2E_ERR_CNT].item_val));
printf("crc_error_count : %3d%% %"PRIu64"\n",
smart->items[CRC_ERR_CNT].norm,
int48_to_long(smart->items[CRC_ERR_CNT].item_val));
smart->items[CRC_ERR_CNT].norm,
int48_to_long(smart->items[CRC_ERR_CNT].item_val));
printf("timed_workload_media_wear : %3d%% %.3f%%\n",
smart->items[TIME_WORKLOAD_MEDIA_WEAR].norm,
((float)int48_to_long(smart->items[TIME_WORKLOAD_MEDIA_WEAR].item_val)) / 1024);
smart->items[TIME_WORKLOAD_MEDIA_WEAR].norm,
((float)int48_to_long(smart->items[TIME_WORKLOAD_MEDIA_WEAR].item_val)) / 1024);
printf("timed_workload_host_reads : %3d%% %"PRIu64"%%\n",
smart->items[TIME_WORKLOAD_HOST_READS].norm,
int48_to_long(smart->items[TIME_WORKLOAD_HOST_READS].item_val));
smart->items[TIME_WORKLOAD_HOST_READS].norm,
int48_to_long(smart->items[TIME_WORKLOAD_HOST_READS].item_val));
printf("timed_workload_timer : %3d%% %"PRIu64" min\n",
smart->items[TIME_WORKLOAD_TIMER].norm,
int48_to_long(smart->items[TIME_WORKLOAD_TIMER].item_val));
smart->items[TIME_WORKLOAD_TIMER].norm,
int48_to_long(smart->items[TIME_WORKLOAD_TIMER].item_val));
printf("thermal_throttle_status : %3d%% CurTTSta: %u%%, TTCnt: %u\n",
smart->items[THERMAL_THROTTLE].norm,
smart->items[THERMAL_THROTTLE].thermal_throttle.st,
smart->items[THERMAL_THROTTLE].thermal_throttle.count);
smart->items[THERMAL_THROTTLE].norm,
smart->items[THERMAL_THROTTLE].thermal_throttle.st,
smart->items[THERMAL_THROTTLE].thermal_throttle.count);
printf("retry_buffer_overflow_count : %3d%% %"PRIu64"\n",
smart->items[RETRY_BUFFER_OVERFLOW].norm,
int48_to_long(smart->items[RETRY_BUFFER_OVERFLOW].item_val));
smart->items[RETRY_BUFFER_OVERFLOW].norm,
int48_to_long(smart->items[RETRY_BUFFER_OVERFLOW].item_val));
printf("pll_lock_loss_count : %3d%% %"PRIu64"\n",
smart->items[PLL_LOCK_LOSS].norm,
int48_to_long(smart->items[PLL_LOCK_LOSS].item_val));
smart->items[PLL_LOCK_LOSS].norm,
int48_to_long(smart->items[PLL_LOCK_LOSS].item_val));
printf("nand_bytes_written : %3d%% sectors: %"PRIu64"\n",
smart->items[NAND_WRITE].norm,
int48_to_long(smart->items[NAND_WRITE].item_val));
smart->items[NAND_WRITE].norm,
int48_to_long(smart->items[NAND_WRITE].item_val));
printf("host_bytes_written : %3d%% sectors: %"PRIu64"\n",
smart->items[HOST_WRITE].norm,
int48_to_long(smart->items[HOST_WRITE].item_val));
printf("sram_error_count : %3d%% %"PRIu64"\n",
smart->items[RETRY_BUFFER_OVERFLOW].norm,
int48_to_long(smart->items[SRAM_ERROR_CNT].item_val));
smart->items[HOST_WRITE].norm,
int48_to_long(smart->items[HOST_WRITE].item_val));
printf("sram_error_count : %3d%% %"PRIu64"\n",
smart->items[RETRY_BUFFER_OVERFLOW].norm,
int48_to_long(smart->items[SRAM_ERROR_CNT].item_val));
}
static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
struct nvme_shannon_smart_log smart_log;
char *desc = "Get Shannon vendor specific additional smart log (optionally, "\
"for the specified namespace), and show it.";
char *desc =
"Get Shannon 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 nvme_dev *dev;
@ -134,7 +133,7 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace),
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
OPT_END()
};
@ -145,30 +144,29 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
sizeof(smart_log), &smart_log);
if (!err) {
if (!cfg.raw_binary)
show_shannon_smart_log(&smart_log, cfg.namespace_id,
dev->name);
show_shannon_smart_log(&smart_log, cfg.namespace_id, dev->name);
else
d_raw((unsigned char *)&smart_log, sizeof(smart_log));
}
else if (err > 0)
} else if (err > 0) {
nvme_show_status(err);
}
dev_close(dev);
return err;
}
static int get_additional_feature(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 "\
"behavior 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"\
"0x02: Shannon power management\n";
const char *desc = "Read operating parameters of the\n"
"specified controller. Operating parameters are grouped\n"
"and identified by Feature Identifiers; each Feature\n"
"Identifier contains one or more attributes that may affect\n"
"behavior of the feature. Each Feature has three possible\n"
"settings: default, saveable, and current. If a Feature is\n"
"saveable, it may be modified by set-feature. Default values\n"
"are vendor-specific and not changeable. Use set-feature to\n"
"change saveable Features.\n\n"
"Available additional feature id:\n"
"0x02: Shannon power management\n";
const char *raw = "show infos in binary format";
const char *namespace_id = "identifier of desired namespace";
const char *feature_id = "hexadecimal feature name";
@ -194,19 +192,19 @@ static int get_additional_feature(int argc, char **argv, struct command *cmd, st
struct config cfg = {
.namespace_id = 1,
.feature_id = 0,
.sel = 0,
.cdw11 = 0,
.data_len = 0,
.sel = 0,
.cdw11 = 0,
.data_len = 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_BYTE("sel", 's', &cfg.sel, sel),
OPT_UINT("data-len", 'l', &cfg.data_len, data_len),
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
OPT_UINT("cdw11", 'c', &cfg.cdw11, cdw11),
OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable),
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_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
OPT_UINT("cdw11", 'c', &cfg.cdw11, cdw11),
OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable),
OPT_END()
};
@ -217,16 +215,15 @@ static int get_additional_feature(int argc, char **argv, struct command *cmd, st
if (cfg.sel > 7) {
fprintf(stderr, "invalid 'select' param:%d\n", cfg.sel);
dev_close(dev);
return EINVAL;
return -EINVAL;
}
if (!cfg.feature_id) {
fprintf(stderr, "feature-id required param\n");
dev_close(dev);
return EINVAL;
return -EINVAL;
}
if (cfg.data_len) {
if (posix_memalign(&buf, getpagesize(), cfg.data_len))
{
if (posix_memalign(&buf, getpagesize(), cfg.data_len)) {
dev_close(dev);
exit(ENOMEM);
}
@ -247,23 +244,7 @@ static int get_additional_feature(int argc, char **argv, struct command *cmd, st
.result = &result,
};
err = nvme_get_features(&args);
if (!err) {
#if 0
printf("get-feature:0x%02x (%s), %s value: %#08x\n", cfg.feature_id,
nvme_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);
}
}
#endif
} else if (err > 0)
if (err > 0)
nvme_show_status(err);
if (buf)
free(buf);
@ -272,17 +253,17 @@ static int get_additional_feature(int argc, char **argv, struct command *cmd, st
static int set_additional_feature(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"\
"0x02: Shannon power management\n";
const char *desc = "Modify the saveable or changeable\n"
"current operating parameters of the controller. Operating\n"
"parameters are grouped and identified by Feature\n"
"Identifiers. Feature settings can be applied to the entire\n"
"controller and all associated namespaces, or to only a few\n"
"namespace(s) associated with the controller. Default values\n"
"for each Feature are vendor-specific and may not be modified.\n"
"Use get-feature to determine which Features are supported by\n"
"the controller and are saveable/changeable.\n\n"
"Available additional feature id:\n"
"0x02: Shannon power management\n";
const char *namespace_id = "desired namespace";
const char *feature_id = "hex feature name (required)";
const char *data_len = "buffer length if data required";
@ -305,21 +286,21 @@ static int set_additional_feature(int argc, char **argv, struct command *cmd, st
};
struct config cfg = {
.file = "",
.file = "",
.namespace_id = 0,
.feature_id = 0,
.value = 0,
.value = 0,
.data_len = 0,
.save = 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_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()
};
@ -330,14 +311,14 @@ static int set_additional_feature(int argc, char **argv, struct command *cmd, st
if (!cfg.feature_id) {
fprintf(stderr, "feature-id required param\n");
dev_close(dev);
return EINVAL;
return -EINVAL;
}
if (cfg.data_len) {
if (posix_memalign(&buf, getpagesize(), cfg.data_len)){
if (posix_memalign(&buf, getpagesize(), cfg.data_len)) {
fprintf(stderr, "can not allocate feature payload\n");
dev_close(dev);
return ENOMEM;
return -ENOMEM;
}
memset(buf, 0, cfg.data_len);
}
@ -380,10 +361,6 @@ static int set_additional_feature(int argc, char **argv, struct command *cmd, st
goto free;
}
if (!err) {
#if 0
printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id,
nvme_feature_to_string(cfg.feature_id), cfg.value);
#endif
if (buf)
d(buf, cfg.data_len, 16, 1);
} else if (err > 0)

View file

@ -1,8 +1,13 @@
sources += [
'plugins/solidigm/solidigm-id-ctrl.c',
'plugins/solidigm/solidigm-util.c',
'plugins/solidigm/solidigm-smart.c',
'plugins/solidigm/solidigm-garbage-collection.c',
'plugins/solidigm/solidigm-latency-tracking.c',
'plugins/solidigm/solidigm-log-page-dir.c',
'plugins/solidigm/solidigm-telemetry.c',
'plugins/solidigm/solidigm-internal-logs.c',
'plugins/solidigm/solidigm-market-log.c',
]
subdir('solidigm-telemetry')

View file

@ -21,26 +21,27 @@
#include "solidigm-garbage-collection.h"
#include "solidigm-util.h"
typedef struct __attribute__((packed)) gc_item {
struct __packed gc_item {
__le32 timer_type;
__le64 timestamp;
} gc_item_t;
};
#define VU_GC_MAX_ITEMS 100
typedef struct garbage_control_collection_log {
struct garbage_control_collection_log {
__le16 version_major;
__le16 version_minor;
gc_item_t item[VU_GC_MAX_ITEMS];
struct __packed gc_item item[VU_GC_MAX_ITEMS];
__u8 reserved[2892];
} garbage_control_collection_log_t;
};
static void vu_gc_log_show_json(garbage_control_collection_log_t *payload, const char *devname)
static void vu_gc_log_show_json(struct garbage_control_collection_log *payload, const char *devname)
{
struct json_object *gc_entries = json_create_array();
for (int i = 0; i < VU_GC_MAX_ITEMS; i++) {
gc_item_t item = payload->item[i];
struct __packed gc_item item = payload->item[i];
struct json_object *entry = json_create_object();
json_object_add_value_int(entry, "timestamp", le64_to_cpu(item.timestamp));
json_object_add_value_int(entry, "timer_type", le32_to_cpu(item.timer_type));
json_array_add_value_object(gc_entries, entry);
@ -50,7 +51,7 @@ static void vu_gc_log_show_json(garbage_control_collection_log_t *payload, const
json_free_object(gc_entries);
}
static void vu_gc_log_show(garbage_control_collection_log_t *payload, const char *devname,
static void vu_gc_log_show(struct garbage_control_collection_log *payload, const char *devname,
__u8 uuid_index)
{
printf("Solidigm Garbage Collection Log for NVME device:%s UUID-idx:%d\n", devname,
@ -58,7 +59,8 @@ static void vu_gc_log_show(garbage_control_collection_log_t *payload, const char
printf("Timestamp Timer Type\n");
for (int i = 0; i < VU_GC_MAX_ITEMS; i++) {
gc_item_t item = payload->item[i];
struct __packed gc_item item = payload->item[i];
printf("%-13" PRIu64 " %d\n", le64_to_cpu(item.timestamp), le32_to_cpu(item.timer_type));
}
}
@ -88,15 +90,16 @@ int solidigm_get_garbage_collection_log(int argc, char **argv, struct command *c
return err;
enum nvme_print_flags flags = validate_output_format(cfg.output_format);
if (flags == -EINVAL) {
fprintf(stderr, "Invalid output format '%s'\n", cfg.output_format);
dev_close(dev);
return EINVAL;
return -EINVAL;
}
uuid_index = solidigm_get_vu_uuid_index(dev);
garbage_control_collection_log_t gc_log;
struct garbage_control_collection_log gc_log;
const int solidigm_vu_gc_log_id = 0xfd;
struct nvme_get_log_args args = {
.lpo = 0,
@ -118,15 +121,13 @@ int solidigm_get_garbage_collection_log(int argc, char **argv, struct command *c
err = nvme_get_log(&args);
if (!err) {
if (flags & BINARY) {
if (flags & BINARY)
d_raw((unsigned char *)&gc_log, sizeof(gc_log));
} else if (flags & JSON) {
else if (flags & JSON)
vu_gc_log_show_json(&gc_log, dev->name);
} else {
else
vu_gc_log_show(&gc_log, dev->name, uuid_index);
}
}
else if (err > 0) {
} else if (err > 0) {
nvme_show_status(err);
}

View file

@ -0,0 +1,73 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2023 Solidigm.
*
* Author: leonardo.da.cunha@solidigm.com
*/
#include <inttypes.h>
#include "common.h"
#include "solidigm-id-ctrl.h"
struct __packed nvme_vu_id_ctrl_field { /* CDR MR5 */
__u8 rsvd1[3];
__u8 ss;
char health[20];
__u8 cls;
__u8 nlw;
__u8 scap;
__u8 sstat;
char bl[8];
__u8 rsvd2[38];
__le64 ww;
char mic_bl[4];
char mic_fw[4];
};
void sldgm_id_ctrl(uint8_t *vs, struct json_object *root)
{
// text output aligns nicely with property name up to 10 chars
const char *str_ss = "stripeSize";
const char *str_health = "health";
const char *str_cls = "linkSpeed";
const char *str_nlw = "negLnkWdth";
const char *str_scap = "secCapab";
const char *str_sstat = "secStatus";
const char *str_bl = "bootLoader";
const char *str_ww = "wwid";
const char *str_mic_bl = "bwLimGran";
const char *str_mic_fw = "ioLimGran";
struct nvme_vu_id_ctrl_field *id = (struct nvme_vu_id_ctrl_field *)vs;
const char str_heathy[sizeof(id->health)] = "healthy";
const char *health = id->health[0] ? id->health : str_heathy;
if (root == NULL) {
printf("%-10s: %u\n", str_ss, id->ss);
printf("%-10s: %.*s\n", str_health, (int)sizeof(id->health), health);
printf("%-10s: %u\n", str_cls, id->cls);
printf("%-10s: %u\n", str_nlw, id->nlw);
printf("%-10s: %u\n", str_scap, id->scap);
printf("%-10s: %u\n", str_sstat, id->sstat);
printf("%-10s: %.*s\n", str_bl, (int)sizeof(id->bl), id->bl);
printf("%-10s: 0x%016"PRIx64"\n", str_ww, le64_to_cpu(id->ww));
printf("%-10s: %.*s\n", str_mic_bl, (int)sizeof(id->mic_bl), id->mic_bl);
printf("%-10s: %.*s\n", str_mic_fw, (int)sizeof(id->mic_fw), id->mic_fw);
return;
}
json_object_add_value_uint(root, str_ss, id->ss);
json_object_object_add(root, str_health,
json_object_new_string_len(health, sizeof(id->health)));
json_object_add_value_uint(root, str_cls, id->cls);
json_object_add_value_uint(root, str_nlw, id->nlw);
json_object_add_value_uint(root, str_scap, id->scap);
json_object_add_value_uint(root, str_sstat, id->sstat);
json_object_object_add(root, str_bl, json_object_new_string_len(id->bl, sizeof(id->bl)));
json_object_add_value_uint64(root, str_ww, le64_to_cpu(id->ww));
json_object_object_add(root, str_mic_bl,
json_object_new_string_len(id->mic_bl, sizeof(id->mic_bl)));
json_object_object_add(root, str_mic_fw,
json_object_new_string_len(id->mic_fw, sizeof(id->mic_fw)));
}

View file

@ -0,0 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2023 Solidigm.
*
* Author: leonardo.da.cunha@solidigm.com
*/
#include <inttypes.h>
#include "util/json.h"
void sldgm_id_ctrl(uint8_t *vs, struct json_object *root);

View file

@ -0,0 +1,597 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2023 Solidigm.
*
* Authors: leonardo.da.cunha@solidigm.com
* shankaralingegowda.singonahalli@solidigm.com
*/
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>
#include <linux/limits.h>
#include "common.h"
#include "nvme.h"
#include "libnvme.h"
#include "plugin.h"
#include "nvme-print.h"
#define DWORD_SIZE 4
enum log_type {
NLOG = 0,
EVENTLOG = 1,
ASSERTLOG = 2,
};
#pragma pack(push, internal_logs, 1)
struct version {
__u16 major;
__u16 minor;
};
struct event_dump_instance {
__u32 numeventdumps;
__u32 coresize;
__u32 coreoffset;
__u32 eventidoffset[16];
__u8 eventIdValidity[16];
};
struct commom_header {
struct version ver;
__u32 header_size;
__u32 log_size;
__u32 numcores;
};
struct event_dump_header {
struct commom_header header;
__u32 eventidsize;
struct event_dump_instance edumps[0];
};
struct assert_dump_core {
__u32 coreoffset;
__u32 assertsize;
__u8 assertdumptype;
__u8 assertvalid;
__u8 reserved[2];
};
struct assert_dump_header {
struct commom_header header;
struct assert_dump_core core[];
};
struct nlog_dump_header_common {
struct version ver;
__u32 logselect;
__u32 totalnlogs;
__u32 nlognum;
char nlogname[4];
__u32 nlogbytesize;
__u32 nlogprimarybuffsize;
__u32 tickspersecond;
__u32 corecount;
};
struct nlog_dump_header3_0 {
struct nlog_dump_header_common common;
__u32 nlogpausestatus;
__u32 selectoffsetref;
__u32 selectnlogpause;
__u32 selectaddedoffset;
__u32 nlogbufnum;
__u32 nlogbufnummax;
};
struct nlog_dump_header4_0 {
struct nlog_dump_header_common common;
__u64 nlogpausestatus;
__u32 selectoffsetref;
__u32 selectnlogpause;
__u32 selectaddedoffset;
__u32 nlogbufnum;
__u32 nlogbufnummax;
__u32 coreselected;
__u32 reserved[2];
};
struct nlog_dump_header4_1 {
struct nlog_dump_header_common common;
__u64 nlogpausestatus;
__u32 selectoffsetref;
__u32 selectnlogpause;
__u32 selectaddedoffset;
__u32 nlogbufnum;
__u32 nlogbufnummax;
__u32 coreselected;
__u32 lpaPointer1High;
__u32 lpaPointer1Low;
__u32 lpaPointer2High;
__u32 lpaPointer2Low;
};
#pragma pack(pop, internal_logs)
struct config {
__u32 namespace_id;
char *file_prefix;
char *type;
bool verbose;
};
static void print_nlog_header(__u8 *buffer)
{
struct nlog_dump_header_common *nlog_header = (struct nlog_dump_header_common *) buffer;
if (nlog_header->ver.major >= 3) {
printf("Version Major %u\n", nlog_header->ver.major);
printf("Version Minor %u\n", nlog_header->ver.minor);
printf("Log_select %u\n", nlog_header->logselect);
printf("totalnlogs %u\n", nlog_header->totalnlogs);
printf("nlognum %u\n", nlog_header->nlognum);
printf("nlogname %c%c%c%c\n", nlog_header->nlogname[3], nlog_header->nlogname[2],
nlog_header->nlogname[1], nlog_header->nlogname[0]);
printf("nlogbytesize %u\n", nlog_header->nlogbytesize);
printf("nlogprimarybuffsize %u\n", nlog_header->nlogprimarybuffsize);
printf("tickspersecond %u\n", nlog_header->tickspersecond);
printf("corecount %u\n", nlog_header->corecount);
}
if (nlog_header->ver.major >= 4) {
struct nlog_dump_header4_0 *nlog_header = (struct nlog_dump_header4_0 *) buffer;
printf("nlogpausestatus %"PRIu64"\n", (uint64_t)nlog_header->nlogpausestatus);
printf("selectoffsetref %u\n", nlog_header->selectoffsetref);
printf("selectnlogpause %u\n", nlog_header->selectnlogpause);
printf("selectaddedoffset %u\n", nlog_header->selectaddedoffset);
printf("nlogbufnum %u\n", nlog_header->nlogbufnum);
printf("nlogbufnummax %u\n", nlog_header->nlogbufnummax);
printf("coreselected %u\n\n", nlog_header->coreselected);
}
}
#define INTERNAL_LOG_MAX_BYTE_TRANSFER 4096
#define INTERNAL_LOG_MAX_DWORD_TRANSFER (INTERNAL_LOG_MAX_BYTE_TRANSFER / 4)
static int cmd_dump_repeat(struct nvme_passthru_cmd *cmd, __u32 total_dw_size,
int out_fd, int ioctl_fd, bool force_max_transfer)
{
int err = 0;
while (total_dw_size > 0) {
size_t dword_tfer = min(INTERNAL_LOG_MAX_DWORD_TRANSFER, total_dw_size);
cmd->cdw10 = force_max_transfer ? INTERNAL_LOG_MAX_DWORD_TRANSFER : dword_tfer;
cmd->data_len = dword_tfer * 4;
err = nvme_submit_admin_passthru(ioctl_fd, cmd, NULL);
if (err)
return err;
if (out_fd > 0) {
err = write(out_fd, (const void *)(uintptr_t)cmd->addr, cmd->data_len);
if (err < 0) {
perror("write failure");
return err;
}
err = 0;
}
total_dw_size -= dword_tfer;
cmd->cdw13 += dword_tfer;
}
return err;
}
static int write_header(__u8 *buf, int fd, size_t amnt)
{
if (write(fd, buf, amnt) < 0)
return 1;
return 0;
}
static int read_header(struct nvme_passthru_cmd *cmd, int ioctl_fd)
{
memset((void *)(uintptr_t)cmd->addr, 0, INTERNAL_LOG_MAX_BYTE_TRANSFER);
return cmd_dump_repeat(cmd, INTERNAL_LOG_MAX_DWORD_TRANSFER, -1, ioctl_fd, false);
}
static int get_serial_number(char *str, int fd)
{
struct nvme_id_ctrl ctrl = {0};
int err;
err = nvme_identify_ctrl(fd, &ctrl);
if (err)
return err;
/* Remove trailing spaces */
for (int i = sizeof(ctrl.sn) - 1; i && ctrl.sn[i] == ' '; i--)
ctrl.sn[i] = '\0';
sprintf(str, "%-.*s", (int)sizeof(ctrl.sn), ctrl.sn);
return err;
}
static int dump_assert_logs(struct nvme_dev *dev, struct config cfg)
{
__u8 buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
__u8 head_buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
char file_path[PATH_MAX];
struct assert_dump_header *ad = (struct assert_dump_header *) head_buf;
struct nvme_passthru_cmd cmd = {
.opcode = 0xd2,
.nsid = cfg.namespace_id,
.addr = (unsigned long)(void *)head_buf,
.cdw12 = ASSERTLOG,
.cdw13 = 0,
};
int output, err;
err = read_header(&cmd, dev_fd(dev));
if (err)
return err;
sprintf(file_path, "%s_AssertLog.bin", cfg.file_prefix);
output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (output < 0)
return -errno;
err = write_header((__u8 *)ad, output, ad->header.header_size * DWORD_SIZE);
if (err) {
perror("write failure");
close(output);
return err;
}
cmd.addr = (unsigned long)(void *)buf;
if (cfg.verbose) {
printf("Assert Log, cores: %d log size: %d header size: %d\n", ad->header.numcores,
ad->header.log_size * DWORD_SIZE, ad->header.header_size * DWORD_SIZE);
for (__u32 i = 0; i < ad->header.numcores; i++)
printf("core %d assert size: %d\n", i, ad->core[i].assertsize * DWORD_SIZE);
}
for (__u32 i = 0; i < ad->header.numcores; i++) {
if (!ad->core[i].assertvalid)
continue;
cmd.cdw13 = ad->core[i].coreoffset;
err = cmd_dump_repeat(&cmd, ad->core[i].assertsize,
output,
dev_fd(dev), false);
if (err) {
close(output);
return err;
}
}
close(output);
printf("Successfully wrote log to %s\n", file_path);
return err;
}
static int dump_event_logs(struct nvme_dev *dev, struct config cfg)
{
__u8 buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
__u8 head_buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
char file_path[PATH_MAX];
struct event_dump_header *ehdr = (struct event_dump_header *) head_buf;
struct nvme_passthru_cmd cmd = {
.opcode = 0xd2,
.nsid = cfg.namespace_id,
.addr = (unsigned long)(void *)head_buf,
.cdw12 = EVENTLOG,
.cdw13 = 0,
};
int output;
int core_num, err;
err = read_header(&cmd, dev_fd(dev));
if (err)
return err;
sprintf(file_path, "%s_EventLog.bin", cfg.file_prefix);
output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (output < 0)
return -errno;
err = write_header(head_buf, output, INTERNAL_LOG_MAX_BYTE_TRANSFER);
core_num = ehdr->header.numcores;
if (err) {
close(output);
return err;
}
cmd.addr = (unsigned long)(void *)buf;
if (cfg.verbose)
printf("Event Log, cores: %d log size: %d\n", core_num, ehdr->header.log_size * 4);
for (__u32 j = 0; j < core_num; j++) {
if (cfg.verbose) {
for (int k = 0 ; k < 16; k++) {
printf("core: %d event: %d ", j, k);
printf("validity: %d ", ehdr->edumps[j].eventIdValidity[k]);
printf("offset: %d\n", ehdr->edumps[j].eventidoffset[k]);
}
}
cmd.cdw13 = ehdr->edumps[j].coreoffset;
err = cmd_dump_repeat(&cmd, ehdr->edumps[j].coresize,
output, dev_fd(dev), false);
if (err) {
close(output);
return err;
}
}
close(output);
printf("Successfully wrote log to %s\n", file_path);
return err;
}
static size_t get_nlog_header_size(struct nlog_dump_header_common *nlog_header)
{
switch (nlog_header->ver.major) {
case 3:
return sizeof(struct nlog_dump_header3_0);
case 4:
if (nlog_header->ver.minor == 0)
return sizeof(struct nlog_dump_header4_0);
return sizeof(struct nlog_dump_header4_1);
default:
return INTERNAL_LOG_MAX_BYTE_TRANSFER;
}
}
/* dumps nlogs from specified core or all cores when core = -1 */
static int dump_nlogs(struct nvme_dev *dev, struct config cfg, int core)
{
int err = 0;
__u32 count, core_num;
__u8 buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
char file_path[PATH_MAX];
struct nlog_dump_header_common *nlog_header = (struct nlog_dump_header_common *)buf;
struct nvme_passthru_cmd cmd = {
.opcode = 0xd2,
.nsid = cfg.namespace_id,
.addr = (unsigned long)(void *)buf
};
struct dump_select {
union {
struct {
__u32 selectLog : 3;
__u32 selectCore : 2;
__u32 selectNlog : 8;
};
__u32 raw;
};
} log_select;
int output;
bool is_open = false;
size_t header_size = 0;
log_select.selectCore = core < 0 ? 0 : core;
do {
log_select.selectNlog = 0;
do {
cmd.cdw13 = 0;
cmd.cdw12 = log_select.raw;
err = read_header(&cmd, dev_fd(dev));
if (err) {
if (is_open)
close(output);
return err;
}
count = nlog_header->totalnlogs;
core_num = core < 0 ? nlog_header->corecount : 0;
if (!header_size) {
sprintf(file_path, "%s_NLog.bin", cfg.file_prefix);
output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (output < 0)
return -errno;
header_size = get_nlog_header_size(nlog_header);
is_open = true;
}
err = write_header(buf, output, header_size);
if (err)
break;
if (cfg.verbose)
print_nlog_header(buf);
cmd.cdw13 = 0x400;
err = cmd_dump_repeat(&cmd, nlog_header->nlogbytesize / 4,
output, dev_fd(dev), true);
if (err)
break;
} while (++log_select.selectNlog < count);
if (err)
break;
} while (++log_select.selectCore < core_num);
if (is_open) {
close(output);
printf("Successfully wrote log to %s\n", file_path);
}
return err;
}
enum telemetry_type {
HOSTGENOLD,
HOSTGENNEW,
CONTROLLER
};
static int dump_telemetry(struct nvme_dev *dev, struct config cfg, enum telemetry_type ttype)
{
struct nvme_telemetry_log *log = NULL;
size_t log_size = 0;
int err = 0, output;
__u8 *buffer = NULL;
size_t bytes_remaining = 0;
int data_area = NVME_TELEMETRY_DA_3;
char file_path[PATH_MAX];
char *log_name;
switch (ttype) {
case HOSTGENNEW:
log_name = "TelemetryHostGenNew";
break;
case HOSTGENOLD:
log_name = "TelemetryHostGenOld";
break;
case CONTROLLER:
log_name = "TelemetryController";
break;
default:
return -EINVAL;
}
sprintf(file_path, "%s_%s.bin", cfg.file_prefix, log_name);
output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (output < 0)
return -errno;
switch (ttype) {
case HOSTGENNEW:
err = nvme_get_new_host_telemetry(dev_fd(dev), &log,
data_area, &log_size);
break;
case HOSTGENOLD:
err = nvme_get_host_telemetry(dev_fd(dev), &log,
data_area, &log_size);
break;
case CONTROLLER:
err = nvme_get_ctrl_telemetry(dev_fd(dev), true, &log,
data_area, &log_size);
break;
}
if (err)
goto tele_close_output;
bytes_remaining = log_size;
buffer = (__u8 *)log;
while (bytes_remaining) {
ssize_t bytes_written = write(output, buffer, bytes_remaining);
if (bytes_written < 0) {
err = -errno;
goto tele_close_output;
}
bytes_remaining -= bytes_written;
buffer += bytes_written;
}
printf("Successfully wrote log to %s\n", file_path);
tele_close_output:
free(log);
close(output);
return err;
}
int solidigm_get_internal_log(int argc, char **argv, struct command *command,
struct plugin *plugin)
{
char sn_prefix[sizeof(((struct nvme_id_ctrl *)0)->sn)+1];
int log_count = 0;
int err;
struct nvme_dev *dev;
bool all = false;
const char *desc = "Get Debug Firmware Logs and save them.";
const char *type =
"Log type: ALL, CONTROLLERINITTELEMETRY, HOSTINITTELEMETRY, HOSTINITTELEMETRYNOGEN, NLOG, ASSERT, EVENT. Defaults to ALL.";
const char *prefix = "Output file prefix; defaults to device serial number.";
const char *verbose = "To print out verbose info.";
const char *namespace_id = "Namespace to get logs from.";
struct config cfg = {
.namespace_id = NVME_NSID_ALL,
.file_prefix = NULL,
.type = NULL,
};
OPT_ARGS(opts) = {
OPT_STR("type", 't', &cfg.type, type),
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
OPT_FILE("file-prefix", 'p', &cfg.file_prefix, prefix),
OPT_FLAG("verbose", 'v', &cfg.verbose, verbose),
OPT_END()
};
err = parse_and_open(&dev, argc, argv, desc, opts);
if (err)
return err;
if (!cfg.file_prefix) {
err = get_serial_number(sn_prefix, dev_fd(dev));
if (err)
goto out_dev;
cfg.file_prefix = sn_prefix;
}
if (!cfg.type)
cfg.type = "ALL";
else {
for (char *p = cfg.type; *p; ++p)
*p = toupper(*p);
}
if (!strcmp(cfg.type, "ALL"))
all = true;
if (all || !strcmp(cfg.type, "ASSERT")) {
err = dump_assert_logs(dev, cfg);
if (err == 0)
log_count++;
else if (err < 0)
perror("Assert log");
}
if (all || !strcmp(cfg.type, "EVENT")) {
err = dump_event_logs(dev, cfg);
if (err == 0)
log_count++;
else if (err < 0)
perror("Eventt log");
}
if (all || !strcmp(cfg.type, "NLOG")) {
err = dump_nlogs(dev, cfg, -1);
if (err == 0)
log_count++;
else if (err < 0)
perror("Nlog");
}
if (all || !strcmp(cfg.type, "CONTROLLERINITTELEMETRY")) {
err = dump_telemetry(dev, cfg, CONTROLLER);
if (err == 0)
log_count++;
else if (err < 0)
perror("Telemetry Controller Initated");
}
if (all || !strcmp(cfg.type, "HOSTINITTELEMETRYNOGEN")) {
err = dump_telemetry(dev, cfg, HOSTGENOLD);
if (err == 0)
log_count++;
else if (err < 0)
perror("Previously existing Telemetry Host Initated");
}
if (all || !strcmp(cfg.type, "HOSTINITTELEMETRY")) {
err = dump_telemetry(dev, cfg, HOSTGENNEW);
if (err == 0)
log_count++;
else if (err < 0)
perror("Telemetry Host Initated");
}
if (log_count == 0) {
if (err > 0)
nvme_show_status(err);
} else if ((log_count > 1) || cfg.verbose)
printf("Total: %d log files with prefix: %s\n", log_count, cfg.file_prefix);
out_dev:
/* Redundant close() to make static code analysis happy */
close(dev->direct.fd);
dev_close(dev);
return err;
}

View file

@ -0,0 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2023 Solidigm.
*
* Author: leonardo.da.cunha@solidigm.com
*/
int solidigm_get_internal_log(int argc, char **argv, struct command *cmd, struct plugin *plugin);

View file

@ -94,7 +94,6 @@ static void latency_tracker_bucket_parse(const struct latency_tracker *lt, int i
__u32 bucket_data = le32_to_cpu(lt->stats.data[id]);
if (lt->print_flags == NORMAL) {
printf("%-*d", COL_WIDTH, id);
get_time_unit_label(buffer, lower_us, true);
@ -137,12 +136,10 @@ static void latency_tracker_parse_linear(const struct latency_tracker *lt,
__u32 bytes_per, __u32 us_step,
bool nonzero_print)
{
for (int i = (start_offset / bytes_per) - 1;
i < end_offset / bytes_per; i++) {
if (nonzero_print && lt->stats.data[i] == 0)
for (int i = (start_offset / bytes_per) - 1; i < end_offset / bytes_per; i++) {
if (nonzero_print && !lt->stats.data[i])
continue;
latency_tracker_bucket_parse(lt, i, us_step * i,
us_step * (i + 1), true);
latency_tracker_bucket_parse(lt, i, us_step * i, us_step * (i + 1), true);
}
}
@ -153,6 +150,7 @@ static void latency_tracker_parse_linear(const struct latency_tracker *lt,
static int latency_tracker_bucket_pos2us(const struct latency_tracker *lt, int i)
{
__u32 base_val = 1 << lt->base_range_bits;
if (i < (base_val << 1))
return i;
@ -171,15 +169,15 @@ static int latency_tracker_bucket_pos2us(const struct latency_tracker *lt, int i
* "values" : {
*/
static void latency_tracker_populate_json_root(const struct latency_tracker *lt,
struct json_object *root)
struct json_object *root)
{
struct json_object *subroot = json_create_object();
json_object_add_value_object(root, "latstats", subroot);
json_object_add_value_string(subroot, "type", lt->cfg.write ? "write" : "read");
if (lt->has_average_latency_field) {
json_object_add_value_uint64(subroot, "average_latency", le64_to_cpu(lt->stats.average_latency));
}
if (lt->has_average_latency_field)
json_object_add_value_uint64(subroot, "average_latency",
le64_to_cpu(lt->stats.average_latency));
json_object_add_value_object(subroot, "values", lt->bucket_list);
}
@ -199,13 +197,12 @@ static void latency_tracker_parse_4_0(const struct latency_tracker *lt)
int lower_us = latency_tracker_bucket_pos2us(lt, i);
int upper_us = latency_tracker_bucket_pos2us(lt, i + 1);
latency_tracker_bucket_parse(lt, i, lower_us,
upper_us,
latency_tracker_bucket_parse(lt, i, lower_us, upper_us,
i < (lt->bucket_list_size - 1));
}
}
static void print_dash_separator()
static void print_dash_separator(void)
{
printf("--------------------------------------------------\n");
}
@ -218,16 +215,14 @@ static void latency_tracker_pre_parse(struct latency_tracker *lt)
printf("UUID-idx: %d\n", lt->uuid_index);
printf("Major Revision: %u\nMinor Revision: %u\n",
le16_to_cpu(lt->stats.version_major), le16_to_cpu(lt->stats.version_minor));
if (lt->has_average_latency_field) {
if (lt->has_average_latency_field)
printf("Average Latency: %" PRIu64 "\n", le64_to_cpu(lt->stats.average_latency));
}
print_dash_separator();
printf("%-12s%-12s%-12s%-20s\n", "Bucket", "Start", "End", "Value");
print_dash_separator();
}
if (lt->print_flags == JSON) {
if (lt->print_flags == JSON)
lt->bucket_list = json_object_new_array();
}
}
static void latency_tracker_post_parse(struct latency_tracker *lt)
@ -253,11 +248,10 @@ static void latency_tracker_parse(struct latency_tracker *lt)
latency_tracker_parse_3_0(lt);
break;
case 4:
if (version_minor >= 8){
if (version_minor >= 8)
lt->has_average_latency_field = true;
}
latency_tracker_pre_parse(lt);
if (version_minor == 0){
if (!version_minor) {
lt->base_range_bits = BASE_RANGE_BITS_4_0;
lt->bucket_list_size = BUCKET_LIST_SIZE_4_0;
}
@ -275,7 +269,7 @@ static void latency_tracker_parse(struct latency_tracker *lt)
#define LATENCY_TRACKING_FID 0xe2
#define LATENCY_TRACKING_FID_DATA_LEN 32
static int latency_tracking_is_enable(struct latency_tracker *lt, __u32 * enabled)
static int latency_tracking_is_enable(struct latency_tracker *lt, __u32 *enabled)
{
struct nvme_get_features_args args_get = {
.args_size = sizeof(args_get),
@ -298,13 +292,12 @@ static int latency_tracking_enable(struct latency_tracker *lt)
__u32 result;
int err;
if (!(lt->cfg.enable || lt->cfg.disable)){
if (!(lt->cfg.enable || lt->cfg.disable))
return 0;
}
if (lt->cfg.enable && lt->cfg.disable){
fprintf(stderr,"Cannot enable and disable simultaneously.\n");
return EINVAL;
if (lt->cfg.enable && lt->cfg.disable) {
fprintf(stderr, "Cannot enable and disable simultaneously.\n");
return -EINVAL;
}
struct nvme_set_features_args args_set = {
@ -345,9 +338,9 @@ static int latency_tracker_get_log(struct latency_tracker *lt)
{
int err;
if (lt->cfg.read && lt->cfg.write){
fprintf(stderr,"Cannot capture read and write logs simultaneously.\n");
return EINVAL;
if (lt->cfg.read && lt->cfg.write) {
fprintf(stderr, "Cannot capture read and write logs simultaneously.\n");
return -EINVAL;
}
if (!(lt->cfg.read || lt->cfg.write))
@ -422,31 +415,31 @@ int solidigm_get_latency_tracking_log(int argc, char **argv, struct command *cmd
if (lt.print_flags == -EINVAL) {
fprintf(stderr, "Invalid output format '%s'\n", lt.cfg.output_format);
dev_close(dev);
return EINVAL;
return -EINVAL;
}
if (lt.cfg.type > 0xf) {
fprintf(stderr, "Invalid Log type value '%d'\n", lt.cfg.type);
dev_close(dev);
return EINVAL;
return -EINVAL;
}
if (lt.cfg.type && !(lt.cfg.read || lt.cfg.write)) {
fprintf(stderr, "Log type option valid only when retrieving statistics\n");
dev_close(dev);
return EINVAL;
return -EINVAL;
}
lt.uuid_index = solidigm_get_vu_uuid_index(dev);
err = latency_tracking_enable(&lt);
if (err){
if (err) {
dev_close(dev);
return err;
}
err = latency_tracker_get_log(&lt);
if (err){
if (err) {
dev_close(dev);
return err;
}
@ -460,16 +453,16 @@ int solidigm_get_latency_tracking_log(int argc, char **argv, struct command *cmd
if (!err) {
if (lt.print_flags == JSON) {
struct json_object *root = json_create_object();
json_object_add_value_int(root,"enabled", enabled);
json_object_add_value_int(root, "enabled", enabled);
json_print_object(root, NULL);
json_free_object(root);
printf("\n");
} else if (lt.print_flags == BINARY) {
putchar(enabled);
} else {
printf(
"Latency Statistics Tracking (UUID-idx:%d, FID:0x%X) is currently %i.\n",
lt.uuid_index, LATENCY_TRACKING_FID, enabled);
printf("Latency Statistics Tracking (UUID-idx:%d, FID:0x%X) is currently %i.\n",
lt.uuid_index, LATENCY_TRACKING_FID, enabled);
}
} else {
fprintf(stderr, "Could not read feature id 0xE2.\n");

View file

@ -0,0 +1,300 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2023 Solidigm.
*
* Author: karl.dedow@solidigm.com
*/
#include "solidigm-log-page-dir.h"
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include "common.h"
#include "nvme-print.h"
#include "plugins/ocp/ocp-utils.h"
#define MIN_VENDOR_LID 0xC0
#define SOLIDIGM_MAX_UUID 2
static const char dash[100] = {[0 ... 99] = '-'};
struct lid_dir {
struct __packed {
bool supported;
const char *str;
} lid[NVME_LOG_SUPPORTED_LOG_PAGES_MAX];
};
static void init_lid_dir(struct lid_dir *lid_dir)
{
static const char *unknown_str = "Unknown";
for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) {
lid_dir->lid[lid].supported = false;
lid_dir->lid[lid].str = unknown_str;
}
}
static bool is_invalid_uuid(const struct nvme_id_uuid_list_entry entry)
{
static const unsigned char ALL_ZERO_UUID[NVME_UUID_LEN] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
return memcmp(ALL_ZERO_UUID, entry.uuid, NVME_UUID_LEN) == 0;
}
static bool is_solidigm_uuid(const struct nvme_id_uuid_list_entry entry)
{
static const unsigned char SOLIDIGM_UUID[NVME_UUID_LEN] = {
0x96, 0x19, 0x58, 0x6e, 0xc1, 0x1b, 0x43, 0xad,
0xaa, 0xaa, 0x65, 0x41, 0x87, 0xf6, 0xbb, 0xb2
};
return memcmp(SOLIDIGM_UUID, entry.uuid, NVME_UUID_LEN) == 0;
}
static bool is_ocp_uuid(const struct nvme_id_uuid_list_entry entry)
{
static const unsigned char OCP_UUID[NVME_UUID_LEN] = {
0xc1, 0x94, 0xd5, 0x5b, 0xe0, 0x94, 0x47, 0x94,
0xa2, 0x1d, 0x29, 0x99, 0x8f, 0x56, 0xbe, 0x6f
};
return memcmp(OCP_UUID, entry.uuid, NVME_UUID_LEN) == 0;
}
static int get_supported_log_pages_log(struct nvme_dev *dev, int uuid_index,
struct nvme_supported_log_pages *supported)
{
static const __u8 LID;
memset(supported, 0, sizeof(*supported));
struct nvme_get_log_args args = {
.lpo = 0,
.result = NULL,
.log = supported,
.args_size = sizeof(args),
.fd = dev_fd(dev),
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
.lid = LID,
.len = sizeof(*supported),
.nsid = NVME_NSID_ALL,
.csi = NVME_CSI_NVM,
.lsi = NVME_LOG_LSI_NONE,
.lsp = 0,
.uuidx = uuid_index,
.rae = false,
.ot = false,
};
return nvme_get_log(&args);
}
static struct lid_dir *get_standard_lids(struct nvme_supported_log_pages *supported)
{
static struct lid_dir standard_dir = { 0 };
init_lid_dir(&standard_dir);
standard_dir.lid[0x00].str = "Supported Log Pages";
standard_dir.lid[0x01].str = "Error Information";
standard_dir.lid[0x02].str = "SMART / Health Information";
standard_dir.lid[0x03].str = "Firmware Slot Information";
standard_dir.lid[0x04].str = "Changed Namespace List";
standard_dir.lid[0x05].str = "Commands Supported and Effects";
standard_dir.lid[0x06].str = "Device Self Test";
standard_dir.lid[0x07].str = "Telemetry Host-Initiated";
standard_dir.lid[0x08].str = "Telemetry Controller-Initiated";
standard_dir.lid[0x09].str = "Endurance Group Information";
standard_dir.lid[0x0A].str = "Predictable Latency Per NVM Set";
standard_dir.lid[0x0B].str = "Predictable Latency Event Aggregate";
standard_dir.lid[0x0C].str = "Asymmetric Namespace Access";
standard_dir.lid[0x0D].str = "Persistent Event Log";
standard_dir.lid[0x0E].str = "Predictable Latency Event Aggregate";
standard_dir.lid[0x0F].str = "Endurance Group Event Aggregate";
standard_dir.lid[0x10].str = "Media Unit Status";
standard_dir.lid[0x11].str = "Supported Capacity Configuration List";
standard_dir.lid[0x12].str = "Feature Identifiers Supported and Effects";
standard_dir.lid[0x13].str = "NVMe-MI Commands Supported and Effects";
standard_dir.lid[0x14].str = "Command and Feature lockdown";
standard_dir.lid[0x15].str = "Boot Partition";
standard_dir.lid[0x16].str = "Rotational Media Information";
standard_dir.lid[0x70].str = "Discovery";
standard_dir.lid[0x80].str = "Reservation Notification";
standard_dir.lid[0x81].str = "Sanitize Status";
for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) {
if (!supported->lid_support[lid] || lid >= MIN_VENDOR_LID)
continue;
standard_dir.lid[lid].supported = true;
}
return &standard_dir;
}
static void update_vendor_lid_supported(struct nvme_supported_log_pages *supported,
struct lid_dir *lid_dir)
{
for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) {
if (!supported->lid_support[lid] || lid < MIN_VENDOR_LID)
continue;
lid_dir->lid[lid].supported = true;
}
}
static struct lid_dir *get_solidigm_lids(struct nvme_supported_log_pages *supported)
{
static struct lid_dir solidigm_dir = { 0 };
init_lid_dir(&solidigm_dir);
solidigm_dir.lid[0xC1].str = "Read Commands Latency Statistics";
solidigm_dir.lid[0xC2].str = "Write Commands Latency Statistics";
solidigm_dir.lid[0xC4].str = "Endurance Manager Statistics";
solidigm_dir.lid[0xC5].str = "Temperature Statistics";
solidigm_dir.lid[0xCA].str = "SMART Attributes";
update_vendor_lid_supported(supported, &solidigm_dir);
return &solidigm_dir;
}
static struct lid_dir *get_ocp_lids(struct nvme_supported_log_pages *supported)
{
static struct lid_dir ocp_dir = { 0 };
init_lid_dir(&ocp_dir);
ocp_dir.lid[0xC0].str = "OCP SMART / Health Information Extended";
ocp_dir.lid[0xC1].str = "OCP Error Recovery";
ocp_dir.lid[0xC2].str = "OCP Firmware Activation History";
ocp_dir.lid[0xC3].str = "OCP Latency Monitor";
ocp_dir.lid[0xC4].str = "OCP Device Capabilities";
ocp_dir.lid[0xC5].str = "OCP Unsupported Requirements";
update_vendor_lid_supported(supported, &ocp_dir);
return &ocp_dir;
}
static void supported_log_pages_normal(struct lid_dir *lid_dir[SOLIDIGM_MAX_UUID + 1])
{
printf("%-5s %-4s %-42s\n", "uuidx", "LID", "Description");
printf("%-.5s %-.4s %-.42s\n", dash, dash, dash);
for (int uuid_index = 0; uuid_index <= SOLIDIGM_MAX_UUID; uuid_index++) {
if (!lid_dir[uuid_index])
continue;
for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) {
if (!lid_dir[uuid_index]->lid[lid].supported)
continue;
printf("%-5d 0x%02x %s\n", le32_to_cpu(uuid_index), le32_to_cpu(lid),
lid_dir[uuid_index]->lid[lid].str);
}
}
}
static void supported_log_pages_json(struct lid_dir *lid_dir[SOLIDIGM_MAX_UUID + 1])
{
struct json_object *root = json_create_array();
for (int uuid_index = 0; uuid_index <= SOLIDIGM_MAX_UUID; uuid_index++) {
if (!lid_dir[uuid_index])
continue;
for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) {
if (!lid_dir[uuid_index]->lid[lid].supported)
continue;
struct json_object *lid_obj = json_create_object();
json_object_add_value_uint(lid_obj, "uuidx", le32_to_cpu(uuid_index));
json_object_add_value_uint(lid_obj, "lid", le32_to_cpu(lid));
json_object_add_value_string(lid_obj, "description",
lid_dir[uuid_index]->lid[lid].str);
json_array_add_value_object(root, lid_obj);
}
}
json_print_object(root, NULL);
json_free_object(root);
printf("\n");
}
int solidigm_get_log_page_directory_log(int argc, char **argv, struct command *cmd,
struct plugin *plugin)
{
const int NO_UUID_INDEX = 0;
const char *description = "Retrieves list of supported log pages for each UUID index.";
char *format = "normal";
OPT_ARGS(options) = {
OPT_FMT("output-format", 'o', &format, "output format : normal | json"),
OPT_END()
};
struct nvme_dev *dev = NULL;
int err = parse_and_open(&dev, argc, argv, description, options);
if (err)
return err;
struct lid_dir *lid_dirs[SOLIDIGM_MAX_UUID + 1] = { 0 };
struct nvme_id_uuid_list uuid_list = { 0 };
struct nvme_supported_log_pages supported = { 0 };
err = get_supported_log_pages_log(dev, NO_UUID_INDEX, &supported);
if (!err) {
lid_dirs[NO_UUID_INDEX] = get_standard_lids(&supported);
// Assume VU logs are the Solidigm log pages if UUID not supported.
if (nvme_identify_uuid(dev_fd(dev), &uuid_list)) {
struct lid_dir *solidigm_lid_dir = get_solidigm_lids(&supported);
// Transfer supported Solidigm lids to lid directory at UUID index 0
for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) {
if (solidigm_lid_dir->lid[lid].supported)
lid_dirs[NO_UUID_INDEX]->lid[lid] = solidigm_lid_dir->lid[lid];
}
} else {
for (int uuid_index = 1; uuid_index <= SOLIDIGM_MAX_UUID; uuid_index++) {
if (is_invalid_uuid(uuid_list.entry[uuid_index - 1]))
break;
else if (get_supported_log_pages_log(dev, uuid_index, &supported))
continue;
if (is_solidigm_uuid(uuid_list.entry[uuid_index - 1]))
lid_dirs[uuid_index] = get_solidigm_lids(&supported);
else if (is_ocp_uuid(uuid_list.entry[uuid_index - 1]))
lid_dirs[uuid_index] = get_ocp_lids(&supported);
}
}
} else {
nvme_show_status(err);
}
if (!err) {
const enum nvme_print_flags print_flag = validate_output_format(format);
if (print_flag == NORMAL) {
supported_log_pages_normal(lid_dirs);
} else if (print_flag == JSON) {
supported_log_pages_json(lid_dirs);
} else {
fprintf(stderr, "Error: Invalid output format specified: %s.\n", format);
err = -EINVAL;
}
}
/* Redundant close() to make static code analysis happy */
close(dev->direct.fd);
dev_close(dev);
return err;
}

View file

@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2023 Solidigm.
*
* Authors: karl.dedow@solidigm.com
*/
#ifndef SOLIDIGM_LOG_PAGE_DIRECTORY_H
#define SOLIDIGM_LOG_PAGE_DIRECTORY_H
struct command;
struct plugin;
int solidigm_get_log_page_directory_log(int argc, char **argv, struct command *cmd,
struct plugin *plugin);
#endif

View file

@ -0,0 +1,63 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2023 Solidigm.
*
* Authors: leonardo.da.cunha@solidigm.com
* Hardeep.Dhillon@solidigm.com
*/
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>
#include <linux/limits.h>
#include "common.h"
#include "nvme.h"
#include "libnvme.h"
#include "plugin.h"
#include "nvme-print.h"
#define MARKET_LOG_MAX_SIZE 512
int sldgm_get_market_log(int argc, char **argv, struct command *command,
struct plugin *plugin)
{
const char *desc = "Get Solidigm Marketing Name log and show it.";
const char *raw = "dump output in binary format";
struct nvme_dev *dev;
char log[MARKET_LOG_MAX_SIZE];
int err;
struct config {
bool raw_binary;
};
struct config cfg = {
};
OPT_ARGS(opts) = {
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
OPT_END()
};
err = parse_and_open(&dev, argc, argv, desc, opts);
if (err)
return err;
err = nvme_get_log_simple(dev_fd(dev), 0xdd, sizeof(log), log);
if (!err) {
if (!cfg.raw_binary)
printf("Solidigm Marketing Name Log:\n%s\n", log);
else
d_raw((unsigned char *)&log, sizeof(log));
} else if (err > 0)
nvme_show_status(err);
/* Redundant close() to make static code analysis happy */
close(dev->direct.fd);
dev_close(dev);
return err;
}

View file

@ -0,0 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2023 Solidigm.
*
* Author: hardeep.dhillon@solidigm.com
*/
int sldgm_get_market_log(int argc, char **argv, struct command *cmd, struct plugin *plugin);

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2022 Solidigm.
* Copyright (c) 2022-2023 Solidigm.
*
* Author: leonardo.da.cunha@solidigm.com
*/
@ -10,19 +10,34 @@
#define CREATE_CMD
#include "solidigm-nvme.h"
#include "solidigm-id-ctrl.h"
#include "solidigm-smart.h"
#include "solidigm-internal-logs.h"
#include "solidigm-garbage-collection.h"
#include "solidigm-latency-tracking.h"
#include "solidigm-telemetry.h"
#include "solidigm-log-page-dir.h"
#include "solidigm-market-log.h"
#include "plugins/ocp/ocp-clear-fw-update-history.h"
#include "plugins/ocp/ocp-smart-extended-log.h"
#include "plugins/ocp/ocp-fw-activation-history.h"
static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
return __id_ctrl(argc, argv, cmd, plugin, sldgm_id_ctrl);
}
static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
return solidigm_get_additional_smart_log(argc, argv, cmd, plugin);
}
static int get_internal_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
return solidigm_get_internal_log(argc, argv, cmd, plugin);
}
static int get_garbage_collection_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
return solidigm_get_garbage_collection_log(argc, argv, cmd, plugin);
@ -49,3 +64,21 @@ static int smart_cloud(int argc, char **argv, struct command *cmd,
{
return ocp_smart_add_log(argc, argv, cmd, plugin);
}
static int fw_activation_history(int argc, char **argv, struct command *cmd,
struct plugin *plugin)
{
return ocp_fw_activation_history_log(argc, argv, cmd, plugin);
}
static int get_log_page_directory_log(int argc, char **argv, struct command *cmd,
struct plugin *plugin)
{
return solidigm_get_log_page_directory_log(argc, argv, cmd, plugin);
}
static int get_market_log(int argc, char **argv, struct command *cmd,
struct plugin *plugin)
{
return sldgm_get_market_log(argc, argv, cmd, plugin);
}

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2022 Solidigm.
* Copyright (c) 2022-2023 Solidigm.
*
* Author: leonardo.da.cunha@solidigm.com
*/
@ -13,18 +13,21 @@
#include "cmd.h"
#define SOLIDIGM_PLUGIN_VERSION "0.8"
#define SOLIDIGM_PLUGIN_VERSION "0.14"
PLUGIN(NAME("solidigm", "Solidigm vendor specific extensions", SOLIDIGM_PLUGIN_VERSION),
COMMAND_LIST(
ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl)
ENTRY("smart-log-add", "Retrieve Solidigm SMART Log", get_additional_smart_log)
ENTRY("vs-smart-add-log", "Get SMART / health extended log (redirects to ocp plug-in)", smart_cloud)
ENTRY("vs-internal-log", "Retrieve Debug log binaries", get_internal_log)
ENTRY("garbage-collect-log", "Retrieve Garbage Collection Log", get_garbage_collection_log)
ENTRY("market-log", "Retrieve Market Log", get_market_log)
ENTRY("latency-tracking-log", "Enable/Retrieve Latency tracking Log", get_latency_tracking_log)
ENTRY("parse-telemetry-log", "Parse Telemetry Log binary", get_telemetry_log)
ENTRY("clear-fw-activate-history",
"Clear firmware update history log (redirects to ocp plug-in)",
clear_fw_update_history)
ENTRY("clear-fw-activate-history", "Clear firmware update history log (redirects to ocp plug-in)", clear_fw_update_history)
ENTRY("vs-fw-activate-history", "Get firmware activation history log (redirects to ocp plug-in)", fw_activation_history)
ENTRY("log-page-directory", "Retrieve log page directory", get_log_page_directory_log)
)
);

View file

@ -21,32 +21,31 @@
#include "solidigm-smart.h"
#include "solidigm-util.h"
struct __attribute__((packed)) nvme_additional_smart_log_item {
struct __packed nvme_additional_smart_log_item {
__u8 id;
__u8 _kp[2];
__u8 normalized;
__u8 _np;
union __attribute__((packed)) {
union __packed {
__u8 raw[6];
struct __attribute__((packed)) wear_level {
struct __packed wear_level {
__le16 min;
__le16 max;
__le16 avg;
} wear_level;
struct __attribute__((packed)) thermal_throttle {
struct __packed thermal_throttle {
__u8 pct;
__u32 count;
} thermal_throttle;
} ;
};
__u8 _rp;
} ;
typedef struct nvme_additional_smart_log_item smart_log_item_t;
};
#define VU_SMART_PAGE_SIZE 512
#define VU_SMART_MAX_ITEMS VU_SMART_PAGE_SIZE / sizeof(smart_log_item_t)
typedef struct vu_smart_log {
smart_log_item_t item[VU_SMART_MAX_ITEMS];
} vu_smart_log_t;
#define VU_SMART_MAX_ITEMS (VU_SMART_PAGE_SIZE / sizeof(struct nvme_additional_smart_log_item))
struct vu_smart_log {
struct nvme_additional_smart_log_item item[VU_SMART_MAX_ITEMS];
};
static char *id_to_name(__u8 id)
{
@ -110,11 +109,10 @@ static char *id_to_name(__u8 id)
}
}
static void smart_log_item_print(smart_log_item_t *item)
static void smart_log_item_print(struct nvme_additional_smart_log_item *item)
{
if (!item->id) {
if (!item->id)
return;
}
printf("%#x %-45s %3d ",
item->id, id_to_name(item->id), item->normalized);
@ -136,13 +134,12 @@ static void smart_log_item_print(smart_log_item_t *item)
}
}
static void smart_log_item_add_json(smart_log_item_t *item, struct json_object *dev_stats)
static void smart_log_item_add_json(struct nvme_additional_smart_log_item *item, struct json_object *dev_stats)
{
struct json_object *entry_stats = json_create_object();
if (!item->id) {
if (!item->id)
return;
}
json_object_add_value_int(entry_stats, "normalized", item->normalized);
@ -162,15 +159,14 @@ static void smart_log_item_add_json(smart_log_item_t *item, struct json_object *
json_object_add_value_object(dev_stats, id_to_name(item->id), entry_stats);
}
static void vu_smart_log_show_json(vu_smart_log_t *payload, unsigned int nsid, const char *devname)
static void vu_smart_log_show_json(struct vu_smart_log *payload, unsigned int nsid, const char *devname)
{
struct json_object *dev_stats = json_create_object();
smart_log_item_t *item = payload->item;
struct nvme_additional_smart_log_item *item = payload->item;
struct json_object *root;
for (int i = 0; i < VU_SMART_MAX_ITEMS; i++) {
for (int i = 0; i < VU_SMART_MAX_ITEMS; i++)
smart_log_item_add_json(&item[i], dev_stats);
}
root = json_create_object();
json_object_add_value_string(root, "Solidigm SMART log", devname);
@ -180,26 +176,25 @@ static void vu_smart_log_show_json(vu_smart_log_t *payload, unsigned int nsid, c
json_free_object(root);
}
static void vu_smart_log_show(vu_smart_log_t *payload, unsigned int nsid, const char *devname,
static void vu_smart_log_show(struct vu_smart_log *payload, unsigned int nsid, const char *devname,
__u8 uuid_index)
{
smart_log_item_t *item = payload->item;
struct nvme_additional_smart_log_item *item = payload->item;
printf("Additional Smart Log for NVMe device:%s namespace-id:%x UUID-idx:%d\n",
devname, nsid, uuid_index);
printf("ID KEY Normalized Raw\n");
for (int i = 0; i < VU_SMART_MAX_ITEMS; i++) {
for (int i = 0; i < VU_SMART_MAX_ITEMS; i++)
smart_log_item_print(&item[i]);
}
}
int solidigm_get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Get Solidigm vendor specific smart log (optionally, "\
"for the specified namespace), and show it.";
const char *desc =
"Get Solidigm vendor specific smart log (optionally, for the specified namespace), and show it.";
const int solidigm_vu_smart_log_id = 0xCA;
vu_smart_log_t smart_log_payload;
struct vu_smart_log smart_log_payload;
enum nvme_print_flags flags;
struct nvme_dev *dev;
int err;
@ -254,15 +249,14 @@ int solidigm_get_additional_smart_log(int argc, char **argv, struct command *cmd
err = nvme_get_log(&args);
if (!err) {
if (flags & JSON) {
if (flags & JSON)
vu_smart_log_show_json(&smart_log_payload,
cfg.namespace_id, dev->name);
} else if (flags & BINARY) {
else if (flags & BINARY)
d_raw((unsigned char *)&smart_log_payload, sizeof(smart_log_payload));
} else {
else
vu_smart_log_show(&smart_log_payload, cfg.namespace_id,
dev->name, uuid_index);
}
} else if (err > 0) {
nvme_show_status(err);
}

View file

@ -112,7 +112,7 @@ int solidigm_get_telemetry_log(int argc, char **argv, struct command *cmd, struc
}
if (cfg.cfg_file) {
char *conf_str = 0;
char *conf_str = NULL;
size_t length = 0;
err = read_file2buffer(cfg.cfg_file, &conf_str, &length);
@ -121,9 +121,10 @@ int solidigm_get_telemetry_log(int argc, char **argv, struct command *cmd, struc
cfg.cfg_file, strerror(err));
goto close_fd;
}
struct json_tokener * jstok = json_tokener_new();
struct json_tokener *jstok = json_tokener_new();
tl.configuration = json_tokener_parse_ex(jstok, conf_str, length);
free(conf_str);
if (jstok->err != json_tokener_success) {
SOLIDIGM_LOG_WARNING("Parsing error on JSON configuration file %s: %s (at offset %d)",
cfg.cfg_file,
@ -160,11 +161,7 @@ int solidigm_get_telemetry_log(int argc, char **argv, struct command *cmd, struc
goto close_fd;
}
}
solidigm_telemetry_log_header_parse(&tl);
if (cfg.cfg_file)
solidigm_telemetry_log_data_areas_parse(&tl, cfg.data_area);
else
solidigm_telemetry_log_cod_parse(&tl);
solidigm_telemetry_log_data_areas_parse(&tl, cfg.data_area);
json_print_object(tl.root, NULL);
json_free_object(tl.root);

View file

@ -51,22 +51,20 @@ const char *oemDataMapDesc[] = {
"All Time Current Max Wear Level", // 0x28
"Media Wear Remaining", // 0x29
"Total Non-Defrag Writes", // 0x2A
"Number of sectors relocated in reaction to an error" //Uid 0x2B = 43
"Media Health Relocations" //Uid 0x2B = 43
};
static const char * getOemDataMapDescription(__u32 id)
static const char *getOemDataMapDescription(uint32_t id)
{
if (id < (sizeof(oemDataMapDesc) / sizeof(oemDataMapDesc[0]))) {
if (id < ARRAY_SIZE(oemDataMapDesc))
return oemDataMapDesc[id];
}
return "unknown";
}
#define OEMSIGNATURE 0x504D4443
#pragma pack(push, cod, 1)
struct cod_header
{
struct cod_header {
uint32_t versionMajor;
uint32_t versionMinor;
uint32_t Signature; //!Fixed signature value (0x504D4443) for identification and validation
@ -75,8 +73,7 @@ struct cod_header
uint8_t Reserved[12];
};
struct cod_item
{
struct cod_item {
uint32_t DataFieldMapUid; //!The data field unique identifier value
uint32_t reserved1 : 8;
uint32_t dataFieldType : 8;
@ -90,8 +87,7 @@ struct cod_item
uint8_t Reserved2[8];
};
struct cod_map
{
struct cod_map {
struct cod_header header;
struct cod_item items[];
};
@ -100,8 +96,7 @@ struct cod_map
void solidigm_telemetry_log_cod_parse(struct telemetry_log *tl)
{
enum cod_field_type
{
enum cod_field_type {
INTEGER,
FLOAT,
STRING,
@ -118,77 +113,78 @@ void solidigm_telemetry_log_cod_parse(struct telemetry_log *tl)
return;
if (!json_object_object_get_ex(telemetry_header, "reasonIdentifier", &reason_id))
return;
if (!json_object_object_get_ex(reason_id, "OemDataMapOffset", &COD_offset))
if (!json_object_object_get_ex(reason_id, "oemDataMapOffset", &COD_offset))
return;
__u64 offset = json_object_get_int(COD_offset);
uint64_t offset = json_object_get_int(COD_offset);
if (offset == 0) {
if (!offset)
return;
}
if ((offset + sizeof(struct cod_header)) > tl->log_size) {
SOLIDIGM_LOG_WARNING("Warning: COD map header out of bounds.");
return;
}
const struct cod_map *data = (struct cod_map *) (((__u8 *)tl->log ) + offset);
const struct cod_map *data = (struct cod_map *) (((uint8_t *)tl->log) + offset);
uint32_t signature = be32_to_cpu(data->header.Signature);
if ( signature != OEMSIGNATURE){
if (signature != OEMSIGNATURE) {
SOLIDIGM_LOG_WARNING("Warning: Unsupported COD data signature %x!", signature);
return;
}
if ((offset + data->header.MapSizeInBytes) > tl->log_size){
if ((offset + data->header.MapSizeInBytes) > tl->log_size) {
SOLIDIGM_LOG_WARNING("Warning: COD map data out of bounds.");
return;
}
struct json_object *cod = json_create_object();
json_object_object_add(tl->root, "cod", cod);
for (int i =0 ; i < data->header.EntryCount; i++) {
for (uint64_t i = 0; i < data->header.EntryCount; i++) {
if ((offset + sizeof(struct cod_header) + (i + 1) * sizeof(struct cod_item)) >
tl->log_size){
SOLIDIGM_LOG_WARNING("Warning: COD data out of bounds at item %d!", i);
tl->log_size) {
SOLIDIGM_LOG_WARNING("Warning: COD data out of bounds at item %"PRIu64"!",
i);
return;
}
struct cod_item item = data->items[i];
if (item.DataFieldOffset + item.DataFieldOffset > tl->log_size) {
if (item.DataFieldOffset + item.DataFieldOffset > tl->log_size)
continue;
}
if (item.dataInvalid) {
if (item.dataInvalid)
continue;
}
uint8_t *val = ((uint8_t *)tl->log )+ item.DataFieldOffset;
uint8_t *val = ((uint8_t *)tl->log) + item.DataFieldOffset;
const char *key = getOemDataMapDescription(item.DataFieldMapUid);
switch(item.dataFieldType){
case(INTEGER):
if (item.issigned) {
json_object_object_add(cod, key,
json_object_new_int64(le64_to_cpu(*(uint64_t *)val)));
} else {
json_object_add_value_uint64(cod, key, le64_to_cpu(*(uint64_t *)val));
}
break;
case(FLOAT):
json_object_add_value_float(cod, key, *(float *) val);
break;
case(STRING):
switch (item.dataFieldType) {
case INTEGER:
if (item.issigned)
json_object_object_add(cod, key,
json_object_new_string_len((const char *)val, item.DataFieldSizeInBytes));
break;
case(TWO_BYTE_ASCII):
json_object_object_add(cod, key,
json_object_new_string_len((const char *)val,2));
break;
case(FOUR_BYTE_ASCII):
json_object_object_add(cod, key,
json_object_new_string_len((const char *)val, 4));
break;
default:
SOLIDIGM_LOG_WARNING("Warning: Unknown COD field type (%d)", item.DataFieldMapUid);
json_object_new_int64(le64_to_cpu(*(uint64_t *)val)));
else
json_object_add_value_uint64(cod, key, le64_to_cpu(*(uint64_t *)val));
break;
case FLOAT:
json_object_add_value_float(cod, key, *(float *)val);
break;
case STRING:
json_object_object_add(cod, key,
json_object_new_string_len((const char *)val, item.DataFieldSizeInBytes));
break;
case TWO_BYTE_ASCII:
json_object_object_add(cod, key,
json_object_new_string_len((const char *)val, 2));
break;
case FOUR_BYTE_ASCII:
json_object_object_add(cod, key,
json_object_new_string_len((const char *)val, 4));
break;
default:
SOLIDIGM_LOG_WARNING("Warning: Unknown COD field type (%d)", item.DataFieldMapUid);
break;
}
}
}

View file

@ -4,13 +4,17 @@
*
* Author: leonardo.da.cunha@solidigm.com
*/
#include <stdbool.h>
#include "util/json.h"
#include <stdio.h>
#include <string.h>
#include "config.h"
// max 16 bit unsigned integer nummber 65535
#define MAX_16BIT_NUM_AS_STRING_SIZE 6
#define OBJ_NAME_PREFIX "UID_"
#define NLOG_OBJ_PREFIX OBJ_NAME_PREFIX "NLOG_"
static bool config_get_by_version(const struct json_object *obj, int version_major,
int version_minor, struct json_object **value)
{
@ -28,17 +32,45 @@ static bool config_get_by_version(const struct json_object *obj, int version_maj
return value != NULL;
}
bool solidigm_config_get_by_token_version(const struct json_object *obj, int token_id,
bool solidigm_config_get_struct_by_token_version(const struct json_object *config, int token_id,
int version_major, int version_minor,
struct json_object **value)
{
struct json_object *token_obj = NULL;
struct json_object *token = NULL;
char str_key[MAX_16BIT_NUM_AS_STRING_SIZE];
snprintf(str_key, sizeof(str_key), "%d", token_id);
if (!json_object_object_get_ex(obj, str_key, &token_obj))
if (!json_object_object_get_ex(config, str_key, &token))
return false;
if (!config_get_by_version(token_obj, version_major, version_minor, value))
if (!config_get_by_version(token, version_major, version_minor, value))
return false;
return value != NULL;
}
const char *solidigm_config_get_nlog_obj_name(const struct json_object *config, uint32_t token)
{
struct json_object *nlog_names = NULL;
struct json_object *obj_name;
char hex_header[STR_HEX32_SIZE];
const char *name;
if (!json_object_object_get_ex(config, "TELEMETRY_OBJECT_UIDS", &nlog_names))
return NULL;
snprintf(hex_header, STR_HEX32_SIZE, "0x%08X", token);
if (!json_object_object_get_ex(nlog_names, hex_header, &obj_name))
return NULL;
name = json_object_get_string(obj_name);
if (strncmp(NLOG_OBJ_PREFIX, name, strlen(NLOG_OBJ_PREFIX)))
return NULL;
return &name[strlen(OBJ_NAME_PREFIX)];
}
struct json_object *solidigm_config_get_nlog_formats(const struct json_object *config)
{
struct json_object *nlog_formats = NULL;
json_object_object_get_ex(config, "NLOG_FORMATS", &nlog_formats);
return nlog_formats;
}

View file

@ -7,7 +7,13 @@
#include <stdbool.h>
#include "util/json.h"
bool solidigm_config_get_by_token_version(const struct json_object *obj,
#define STR_HEX32_SIZE sizeof("0x00000000")
bool solidigm_config_get_struct_by_token_version(const struct json_object *obj,
int key, int subkey,
int subsubkey,
struct json_object **value);
const char *solidigm_config_get_nlog_obj_name(const struct json_object *config, uint32_t token);
struct json_object *solidigm_config_get_nlog_formats(const struct json_object *config);

View file

@ -6,25 +6,29 @@
*/
#include "common.h"
#include "header.h"
#include "cod.h"
#include "data-area.h"
#include "config.h"
#include "nlog.h"
#include <ctype.h>
#define SIGNED_INT_PREFIX "int"
#define BITS_IN_BYTE 8
#define MAX_WARNING_SIZE 1024
#define MAX_ARRAY_RANK 16
static bool telemetry_log_get_value(const struct telemetry_log *tl,
uint32_t offset_bit, uint32_t size_bit,
uint64_t offset_bit, uint32_t size_bit,
bool is_signed, struct json_object **val_obj)
{
uint32_t offset_bit_from_byte;
uint32_t additional_size_byte;
uint32_t offset_byte;
uint32_t val;
uint64_t val;
if (size_bit == 0) {
if (!size_bit) {
char err_msg[MAX_WARNING_SIZE];
snprintf(err_msg, MAX_WARNING_SIZE,
@ -34,7 +38,7 @@ static bool telemetry_log_get_value(const struct telemetry_log *tl,
return false;
}
additional_size_byte = (size_bit - 1) ? (size_bit - 1) / BITS_IN_BYTE : 0;
offset_byte = offset_bit / BITS_IN_BYTE;
offset_byte = (uint32_t)offset_bit / BITS_IN_BYTE;
if (offset_byte > (tl->log_size - additional_size_byte)) {
char err_msg[MAX_WARNING_SIZE];
@ -47,15 +51,14 @@ static bool telemetry_log_get_value(const struct telemetry_log *tl,
return false;
}
offset_bit_from_byte = offset_bit - (offset_byte * BITS_IN_BYTE);
offset_bit_from_byte = (uint32_t) (offset_bit - ((uint64_t)offset_byte * BITS_IN_BYTE));
if ((size_bit + offset_bit_from_byte) > (sizeof(uint64_t) * BITS_IN_BYTE)) {
char err_msg[MAX_WARNING_SIZE];
snprintf(err_msg, MAX_WARNING_SIZE,
"Value crossing 64 bit, byte aligned bounday, "
"not supported. size_bit=%u, offset_bit_from_byte=%u.",
size_bit, offset_bit_from_byte);
"Value crossing 64 bit, byte aligned bounday, not supported. size_bit=%u, offset_bit_from_byte=%u.",
size_bit, offset_bit_from_byte);
*val_obj = json_object_new_string(err_msg);
return false;
@ -67,7 +70,7 @@ static bool telemetry_log_get_value(const struct telemetry_log *tl,
val &= (1ULL << size_bit) - 1;
if (is_signed) {
if (val >> (size_bit - 1))
val |= -1ULL << size_bit;
val |= (0ULL - 1) << size_bit;
*val_obj = json_object_new_int64(val);
} else {
*val_obj = json_object_new_uint64(val);
@ -78,23 +81,24 @@ static bool telemetry_log_get_value(const struct telemetry_log *tl,
static int telemetry_log_structure_parse(const struct telemetry_log *tl,
struct json_object *struct_def,
size_t parent_offset_bit,
uint64_t parent_offset_bit,
struct json_object *output,
struct json_object *metadata)
{
struct json_object *obj_arraySizeArray = NULL;
struct json_object *obj = NULL;
struct json_object *obj_memberList;
struct json_object *major_dimension;
struct json_object *major_dimension = NULL;
struct json_object *sub_output;
bool is_enumeration = false;
bool has_member_list;
const char *type = "";
const char *name;
size_t array_rank;
size_t offset_bit;
size_t size_bit;
uint32_t linear_array_pos_bit;
uint64_t offset_bit;
uint32_t size_bit;
uint64_t linear_array_pos_bit;
uint32_t array_size_dimension[MAX_ARRAY_RANK];
if (!json_object_object_get_ex(struct_def, "name", &obj)) {
SOLIDIGM_LOG_WARNING("Warning: Structure definition missing property 'name': %s",
@ -113,22 +117,22 @@ static int telemetry_log_structure_parse(const struct telemetry_log *tl,
type = json_object_get_string(obj);
if (!json_object_object_get_ex(struct_def, "offsetBit", &obj)) {
SOLIDIGM_LOG_WARNING("Warning: Structure definition missing "
"property 'offsetBit': %s",
json_object_to_json_string(struct_def));
SOLIDIGM_LOG_WARNING(
"Warning: Structure definition missing property 'offsetBit': %s",
json_object_to_json_string(struct_def));
return -1;
}
offset_bit = json_object_get_uint64(obj);
if (!json_object_object_get_ex(struct_def, "sizeBit", &obj)) {
SOLIDIGM_LOG_WARNING("Warning: Structure definition missing "
"property 'sizeBit': %s",
json_object_to_json_string(struct_def));
SOLIDIGM_LOG_WARNING(
"Warning: Structure definition missing property 'sizeBit': %s",
json_object_to_json_string(struct_def));
return -1;
}
size_bit = json_object_get_uint64(obj);
size_bit = (uint32_t)json_object_get_uint64(obj);
if (json_object_object_get_ex(struct_def, "enum", &obj))
is_enumeration = json_object_get_boolean(obj);
@ -139,25 +143,30 @@ static int telemetry_log_structure_parse(const struct telemetry_log *tl,
if (!json_object_object_get_ex(struct_def, "arraySize",
&obj_arraySizeArray)) {
SOLIDIGM_LOG_WARNING("Warning: Structure definition missing "
"property 'arraySize': %s",
json_object_to_json_string(struct_def));
SOLIDIGM_LOG_WARNING(
"Warning: Structure definition missing property 'arraySize': %s",
json_object_to_json_string(struct_def));
return -1;
}
array_rank = json_object_array_length(obj_arraySizeArray);
if (array_rank == 0) {
SOLIDIGM_LOG_WARNING("Warning: Structure property 'arraySize' "
"don't support flexible array: %s",
json_object_to_json_string(struct_def));
if (!array_rank) {
SOLIDIGM_LOG_WARNING(
"Warning: Structure property 'arraySize' don't support flexible array: %s",
json_object_to_json_string(struct_def));
return -1;
}
if (array_rank > MAX_ARRAY_RANK) {
SOLIDIGM_LOG_WARNING(
"Warning: Structure property 'arraySize' don't support more than %d dimensions: %s",
MAX_ARRAY_RANK, json_object_to_json_string(struct_def));
return -1;
}
uint32_t array_size_dimension[array_rank];
for (size_t i = 0; i < array_rank; i++) {
struct json_object *dimension = json_object_array_get_idx(obj_arraySizeArray, i);
array_size_dimension[i] = json_object_get_uint64(dimension);
array_size_dimension[i] = json_object_get_int(dimension);
major_dimension = dimension;
}
if (array_rank > 1) {
@ -165,7 +174,7 @@ static int telemetry_log_structure_parse(const struct telemetry_log *tl,
uint32_t prev_index_offset_bit = 0;
struct json_object *dimension_output;
for (int i = 1; i < (array_rank - 1); i++)
for (unsigned int i = 1; i < (array_rank - 1); i++)
linear_pos_per_index *= array_size_dimension[i];
dimension_output = json_create_array();
@ -181,9 +190,9 @@ static int telemetry_log_structure_parse(const struct telemetry_log *tl,
json_object_get(major_dimension);
json_object_array_del_idx(obj_arraySizeArray, array_rank - 1, 1);
for (int i = 0 ; i < array_size_dimension[0]; i++) {
for (unsigned int i = 0 ; i < array_size_dimension[0]; i++) {
struct json_object *sub_array = json_create_array();
size_t offset;
uint64_t offset;
offset = parent_offset_bit + prev_index_offset_bit;
@ -214,7 +223,7 @@ static int telemetry_log_structure_parse(const struct telemetry_log *tl,
if (is_enumeration || !has_member_list) {
bool is_signed = !strncmp(type, SIGNED_INT_PREFIX, sizeof(SIGNED_INT_PREFIX)-1);
struct json_object *val_obj;
size_t offset;
uint64_t offset;
offset = parent_offset_bit + offset_bit + linear_array_pos_bit;
if (telemetry_log_get_value(tl, offset, size_bit, is_signed, &val_obj)) {
@ -223,10 +232,10 @@ static int telemetry_log_structure_parse(const struct telemetry_log *tl,
else
json_object_object_add(sub_output, name, val_obj);
} else {
SOLIDIGM_LOG_WARNING("Warning: %s From property '%s', "
"array index %u, structure definition: %s",
json_object_get_string(val_obj),
name, j, json_object_to_json_string(struct_def));
SOLIDIGM_LOG_WARNING(
"Warning: %s From property '%s', array index %u, structure definition: %s",
json_object_get_string(val_obj), name, j,
json_object_to_json_string(struct_def));
json_free_object(val_obj);
}
} else {
@ -241,7 +250,7 @@ static int telemetry_log_structure_parse(const struct telemetry_log *tl,
num_members = json_object_array_length(obj_memberList);
for (int k = 0; k < num_members; k++) {
struct json_object *member = json_object_array_get_idx(obj_memberList, k);
size_t offset;
uint64_t offset;
offset = parent_offset_bit + offset_bit + linear_array_pos_bit;
telemetry_log_structure_parse(tl, member, offset,
@ -293,6 +302,27 @@ static int telemetry_log_data_area_get_offset(const struct telemetry_log *tl,
return 0;
}
static int telemetry_log_nlog_parse(const struct telemetry_log *tl, struct json_object *formats,
uint64_t nlog_file_offset, uint64_t nlog_size,
struct json_object *output, struct json_object *metadata)
{
/* boundary check */
if (tl->log_size < (nlog_file_offset + nlog_size)) {
const char *name = "";
int media_bank = -1;
struct json_object *jobj;
if (json_object_object_get_ex(metadata, "objName", &jobj))
name = json_object_get_string(jobj);
if (json_object_object_get_ex(metadata, "mediaBankId", &jobj))
media_bank = json_object_get_int(jobj);
SOLIDIGM_LOG_WARNING("%s:%d do not fit this log dump.", name, media_bank);
return -1;
}
return solidigm_nlog_parse(((char *) tl->log) + nlog_file_offset,
nlog_size, formats, metadata, output);
}
struct toc_item {
uint32_t OffsetBytes;
uint32_t ContentSizeBytes;
@ -319,7 +349,6 @@ struct telemetry_object_header {
uint8_t Reserved[3];
};
static void telemetry_log_data_area_toc_parse(const struct telemetry_log *tl,
enum nvme_telemetry_da da,
struct json_object *toc_array,
@ -331,30 +360,35 @@ static void telemetry_log_data_area_toc_parse(const struct telemetry_log *tl,
char *payload;
uint32_t da_offset;
uint32_t da_size;
struct json_object *nlog_formats;
if (telemetry_log_data_area_get_offset(tl, da, &da_offset, &da_size))
return;
toc = (struct table_of_contents *)(((char *)tl->log) + da_offset);
payload = (char *) tl->log;
nlog_formats = solidigm_config_get_nlog_formats(tl->configuration);
for (int i = 0; i < toc->header.TableOfContentsCount; i++) {
struct json_object *structure_definition = NULL;
struct json_object *toc_item;
uint32_t obj_offset;
bool has_struct;
const char *nlog_name = NULL;
uint32_t header_offset = sizeof(const struct telemetry_object_header);
if ((char *)&toc->items[i] > (((char *)toc) + da_size - sizeof(const struct toc_item))) {
SOLIDIGM_LOG_WARNING("Warning: Data Area %d, "
"Table of Contents item %d "
"crossed Data Area size.", da, i);
if ((char *)&toc->items[i] >
(((char *)toc) + da_size - sizeof(const struct toc_item))) {
SOLIDIGM_LOG_WARNING(
"Warning: Data Area %d, Table of Contents item %d crossed Data Area size.",
da, i);
return;
}
obj_offset = toc->items[i].OffsetBytes;
if ((obj_offset + sizeof(const struct telemetry_object_header)) > da_size) {
SOLIDIGM_LOG_WARNING("Warning: Data Area %d, item %d "
"data, crossed Data Area size.", da, i);
SOLIDIGM_LOG_WARNING(
"Warning: Data Area %d, item %d data, crossed Data Area size.", da, i);
continue;
}
@ -372,53 +406,67 @@ static void telemetry_log_data_area_toc_parse(const struct telemetry_log *tl,
json_object_add_value_uint(toc_item, "objectId", header->Token);
json_object_add_value_uint(toc_item, "mediaBankId", header->CoreId);
has_struct = solidigm_config_get_by_token_version(tl->configuration,
header->Token,
header->versionMajor,
header->versionMinor,
&structure_definition);
has_struct = solidigm_config_get_struct_by_token_version(tl->configuration,
header->Token,
header->versionMajor,
header->versionMinor,
&structure_definition);
if (!has_struct) {
if (!nlog_formats)
continue;
nlog_name = solidigm_config_get_nlog_obj_name(tl->configuration,
header->Token);
if (!nlog_name)
continue;
}
struct json_object *tele_obj_item = json_create_object();
json_object_array_add(tele_obj_array, tele_obj_item);
json_object_get(toc_item);
json_object_add_value_object(tele_obj_item, "metadata", toc_item);
struct json_object *parsed_struct = json_create_object();
json_object_add_value_object(tele_obj_item, "objectData", parsed_struct);
struct json_object *obj_hasTelemObjHdr = NULL;
uint64_t object_file_offset;
if (json_object_object_get_ex(structure_definition,
"hasTelemObjHdr",
&obj_hasTelemObjHdr)) {
bool hasHeader = json_object_get_boolean(obj_hasTelemObjHdr);
if (hasHeader)
header_offset = 0;
}
object_file_offset = ((uint64_t)da_offset) + obj_offset + header_offset;
if (has_struct) {
struct json_object *tele_obj_item = json_create_object();
json_object_array_add(tele_obj_array, tele_obj_item);
json_object_get(toc_item);
json_object_add_value_object(tele_obj_item, "metadata", toc_item);
struct json_object *parsed_struct = json_create_object();
json_object_add_value_object(tele_obj_item, "objectData", parsed_struct);
struct json_object *obj_hasTelemObjHdr = NULL;
uint32_t header_offset = sizeof(const struct telemetry_object_header);
uint32_t file_offset;
if (json_object_object_get_ex(structure_definition,
"hasTelemObjHdr",
&obj_hasTelemObjHdr)) {
bool hasHeader = json_object_get_boolean(obj_hasTelemObjHdr);
if (hasHeader)
header_offset = 0;
}
file_offset = da_offset + obj_offset + header_offset;
telemetry_log_structure_parse(tl, structure_definition,
BITS_IN_BYTE * file_offset,
parsed_struct, toc_item);
BITS_IN_BYTE * object_file_offset,
parsed_struct, toc_item);
} else if (nlog_formats) {
json_object_object_add(toc_item, "objName",
json_object_new_string(nlog_name));
telemetry_log_nlog_parse(tl, nlog_formats, object_file_offset,
toc->items[i].ContentSizeBytes - header_offset,
parsed_struct, toc_item);
}
}
}
int solidigm_telemetry_log_data_areas_parse(const struct telemetry_log *tl,
int solidigm_telemetry_log_data_areas_parse(struct telemetry_log *tl,
enum nvme_telemetry_da last_da)
{
struct json_object *tele_obj_array = json_create_array();
struct json_object *toc_array = json_create_array();
json_object_add_value_array(tl->root, "tableOfContents", toc_array);
json_object_add_value_array(tl->root, "telemetryObjects", tele_obj_array);
for (enum nvme_telemetry_da da = NVME_TELEMETRY_DA_1; da <= last_da; da++)
telemetry_log_data_area_toc_parse(tl, da, toc_array, tele_obj_array);
solidigm_telemetry_log_header_parse(tl);
solidigm_telemetry_log_cod_parse(tl);
if (tl->configuration) {
json_object_add_value_array(tl->root, "tableOfContents", toc_array);
json_object_add_value_array(tl->root, "telemetryObjects", tele_obj_array);
for (enum nvme_telemetry_da da = NVME_TELEMETRY_DA_1; da <= last_da; da++)
telemetry_log_data_area_toc_parse(tl, da, toc_array, tele_obj_array);
}
return 0;
}

View file

@ -4,8 +4,7 @@
*
* Author: leonardo.da.cunha@solidigm.com
*/
#include "common.h"
#include "telemetry-log.h"
int solidigm_telemetry_log_data_areas_parse(const struct telemetry_log *tl,
int solidigm_telemetry_log_data_areas_parse(struct telemetry_log *tl,
enum nvme_telemetry_da last_da);

View file

@ -9,8 +9,7 @@
#include "header.h"
#pragma pack(push, reason_indentifier, 1)
struct reason_indentifier_1_0
{
struct reason_indentifier_1_0 {
uint16_t versionMajor;
uint16_t versionMinor;
uint32_t reasonCode; //! 0 denotes no issue. All other values denote a potential issue.
@ -24,8 +23,7 @@ static_assert(sizeof(const struct reason_indentifier_1_0) ==
MEMBER_SIZE(struct nvme_telemetry_log, rsnident),
"Size mismatch for reason_indentifier_1_0");
struct reason_indentifier_1_1
{
struct reason_indentifier_1_1 {
uint16_t versionMajor;
uint16_t versionMinor;
uint32_t reasonCode; //! 0 denotes no issue. All other values denote a potential issue.
@ -42,8 +40,7 @@ static_assert(sizeof(const struct reason_indentifier_1_1) ==
MEMBER_SIZE(struct nvme_telemetry_log, rsnident),
"Size mismatch for reason_indentifier_1_1");
struct reason_indentifier_1_2
{
struct reason_indentifier_1_2 {
uint16_t versionMajor;
uint16_t versionMinor;
uint32_t reasonCode; //! 0 denotes no issue. All other values denote a potential issue.
@ -69,14 +66,21 @@ static void telemetry_log_reason_id_parse1_0_ext(const struct telemetry_log *tl,
struct json_object *reserved;
ri = (struct reason_indentifier_1_0 *) tl->log->rsnident;
json_object_object_add(reason_id, "FirmwareVersion", json_object_new_string_len(ri->FirmwareVersion, sizeof(ri->FirmwareVersion)));
json_object_object_add(reason_id, "BootloaderVersion", json_object_new_string_len(ri->BootloaderVersion, sizeof(ri->BootloaderVersion)));
json_object_object_add(reason_id, "SerialNumber", json_object_new_string_len(ri->SerialNumber, sizeof(ri->SerialNumber)));
json_object_object_add(reason_id, "firmwareVersion",
json_object_new_string_len(ri->FirmwareVersion,
sizeof(ri->FirmwareVersion)));
json_object_object_add(reason_id, "bootloaderVersion",
json_object_new_string_len(ri->BootloaderVersion,
sizeof(ri->BootloaderVersion)));
json_object_object_add(reason_id, "serialNumber",
json_object_new_string_len(ri->SerialNumber,
sizeof(ri->SerialNumber)));
reserved = json_create_array();
json_object_add_value_array(reason_id, "Reserved", reserved);
for ( int i=0; i < sizeof(ri->Reserved); i++) {
json_object_add_value_array(reason_id, "reserved", reserved);
for (int i = 0; i < sizeof(ri->Reserved); i++) {
struct json_object *val = json_object_new_int(ri->Reserved[i]);
json_object_array_add(reserved, val);
}
}
@ -88,17 +92,27 @@ static void telemetry_log_reason_id_parse1_1_ext(const struct telemetry_log *tl,
struct json_object *reserved;
ri = (struct reason_indentifier_1_1 *) tl->log->rsnident;
json_object_object_add(reason_id, "FirmwareVersion", json_object_new_string_len(ri->FirmwareVersion, sizeof(ri->FirmwareVersion)));
json_object_object_add(reason_id, "BootloaderVersion", json_object_new_string_len(ri->BootloaderVersion, sizeof(ri->BootloaderVersion)));
json_object_object_add(reason_id, "SerialNumber", json_object_new_string_len(ri->SerialNumber, sizeof(ri->SerialNumber)));
json_object_add_value_uint64(reason_id, "OemDataMapOffset", le64_to_cpu(ri->OemDataMapOffset));
json_object_add_value_uint(reason_id, "TelemetryMajorVersion", le16_to_cpu(ri->TelemetryMajorVersion));
json_object_add_value_uint(reason_id, "TelemetryMinorVersion", le16_to_cpu(ri->TelemetryMinorVersion));
json_object_object_add(reason_id, "firmwareVersion",
json_object_new_string_len(ri->FirmwareVersion,
sizeof(ri->FirmwareVersion)));
json_object_object_add(reason_id, "bootloaderVersion",
json_object_new_string_len(ri->BootloaderVersion,
sizeof(ri->BootloaderVersion)));
json_object_object_add(reason_id, "serialNumber",
json_object_new_string_len(ri->SerialNumber,
sizeof(ri->SerialNumber)));
json_object_add_value_uint64(reason_id, "oemDataMapOffset",
le64_to_cpu(ri->OemDataMapOffset));
json_object_add_value_uint(reason_id, "telemetryMajorVersion",
le16_to_cpu(ri->TelemetryMajorVersion));
json_object_add_value_uint(reason_id, "telemetryMinorVersion",
le16_to_cpu(ri->TelemetryMinorVersion));
reserved = json_create_array();
json_object_add_value_array(reason_id, "Reserved", reserved);
json_object_add_value_array(reason_id, "reserved", reserved);
for (int i = 0; i < sizeof(ri->Reserved); i++) {
struct json_object *val = json_object_new_int(ri->Reserved[i]);
json_object_array_add(reserved, val);
}
}
@ -112,23 +126,30 @@ static void telemetry_log_reason_id_parse1_2_ext(const struct telemetry_log *tl,
ri = (struct reason_indentifier_1_2 *) tl->log->rsnident;
json_object_object_add(reason_id, "SerialNumber", json_object_new_string_len(ri->SerialNumber, sizeof(ri->SerialNumber)));
json_object_add_value_uint64(reason_id, "OemDataMapOffset", le64_to_cpu(ri->OemDataMapOffset));
json_object_add_value_uint(reason_id, "TelemetryMajorVersion", le16_to_cpu(ri->TelemetryMajorVersion));
json_object_add_value_uint(reason_id, "TelemetryMinorVersion", le16_to_cpu(ri->TelemetryMinorVersion));
json_object_add_value_uint(reason_id, "ProductFamilyId", ri->ProductFamilyId);
json_object_object_add(reason_id, "serialNumber",
json_object_new_string_len(ri->SerialNumber,
sizeof(ri->SerialNumber)));
json_object_add_value_uint64(reason_id, "oemDataMapOffset",
le64_to_cpu(ri->OemDataMapOffset));
json_object_add_value_uint(reason_id, "telemetryMajorVersion",
le16_to_cpu(ri->TelemetryMajorVersion));
json_object_add_value_uint(reason_id, "telemetryMinorVersion",
le16_to_cpu(ri->TelemetryMinorVersion));
json_object_add_value_uint(reason_id, "productFamilyId", ri->ProductFamilyId);
reserved = json_create_array();
json_object_add_value_array(reason_id, "Reserved2", reserved);
json_object_add_value_array(reason_id, "reserved2", reserved);
for (int i = 0; i < sizeof(ri->Reserved2); i++) {
struct json_object *val = json_object_new_int(ri->Reserved2[i]);
json_object_array_add(reserved, val);
}
dp_reserved = json_create_array();
json_object_add_value_array(reason_id, "DualPortReserved", dp_reserved);
json_object_add_value_array(reason_id, "dualPortReserved", dp_reserved);
for (int i = 0; i < sizeof(ri->DualPortReserved); i++) {
struct json_object *val = json_object_new_int(ri->DualPortReserved[i]);
json_object_array_add(dp_reserved, val);
}
}
@ -137,23 +158,26 @@ static void solidigm_telemetry_log_reason_id_parse(const struct telemetry_log *t
{
const struct reason_indentifier_1_0 *ri1_0 =
(struct reason_indentifier_1_0 *) tl->log->rsnident;
__u16 version_major = le16_to_cpu(ri1_0->versionMajor);
__u16 version_minor = le16_to_cpu(ri1_0->versionMinor);
uint16_t version_major = le16_to_cpu(ri1_0->versionMajor);
uint16_t version_minor = le16_to_cpu(ri1_0->versionMinor);
json_object_add_value_uint(reason_id, "versionMajor", version_major);
json_object_add_value_uint(reason_id, "versionMinor", version_minor);
json_object_add_value_uint(reason_id, "reasonCode", le32_to_cpu(ri1_0->reasonCode));
json_object_add_value_object(reason_id, "DriveStatus", json_object_new_string_len(ri1_0->DriveStatus, sizeof(ri1_0->DriveStatus)));
json_object_add_value_object(reason_id, "driveStatus",
json_object_new_string_len(ri1_0->DriveStatus,
sizeof(ri1_0->DriveStatus)));
if (version_major == 1) {
switch (version_minor) {
case 0:
telemetry_log_reason_id_parse1_0_ext(tl, reason_id);
break;
case 1:
telemetry_log_reason_id_parse1_1_ext(tl, reason_id);
break;
default:
telemetry_log_reason_id_parse1_2_ext(tl, reason_id);
case 0:
telemetry_log_reason_id_parse1_0_ext(tl, reason_id);
break;
case 1:
telemetry_log_reason_id_parse1_1_ext(tl, reason_id);
break;
default:
telemetry_log_reason_id_parse1_2_ext(tl, reason_id);
break;
}
}
}

View file

@ -3,4 +3,5 @@ sources += [
'plugins/solidigm/solidigm-telemetry/header.c',
'plugins/solidigm/solidigm-telemetry/config.c',
'plugins/solidigm/solidigm-telemetry/data-area.c',
'plugins/solidigm/solidigm-telemetry/nlog.c',
]

View file

@ -0,0 +1,130 @@
// SPDX-License-Identifier: MIT
/*
* Copyright (c) 2023 Solidigm.
*
* Author: leonardo.da.cunha@solidigm.com
*/
#include "nlog.h"
#include "config.h"
#include <string.h>
#include <math.h>
#include <stdio.h>
#define LOG_ENTRY_HEADER_SIZE 1
#define LOG_ENTRY_TIMESTAMP_SIZE 2
#define LOG_ENTRY_NUM_ARGS_MAX 8
#define LOG_ENTRY_MAX_SIZE (LOG_ENTRY_HEADER_SIZE + LOG_ENTRY_TIMESTAMP_SIZE + \
LOG_ENTRY_NUM_ARGS_MAX)
#define NUM_ARGS_MASK ((1 << ((int)log2(LOG_ENTRY_NUM_ARGS_MAX)+1)) - 1)
#define MAX_HEADER_MISMATCH_TRACK 10
static int formats_find(struct json_object *formats, uint32_t val, struct json_object **format)
{
char hex_header[STR_HEX32_SIZE];
snprintf(hex_header, STR_HEX32_SIZE, "0x%08X", val);
return json_object_object_get_ex(formats, hex_header, format);
}
static uint32_t nlog_get_pos(const uint32_t *nlog, const uint32_t nlog_size, int pos)
{
return nlog[pos % nlog_size];
}
static uint32_t nlog_get_events(const uint32_t *nlog, const uint32_t nlog_size, int start_offset,
struct json_object *formats, struct json_object *events, uint32_t *tail_mismatches)
{
uint32_t event_count = 0;
int last_bad_header_pos = nlog_size + 1; // invalid nlog offset
uint32_t tail_count = 0;
for (int i = nlog_size - start_offset - 1; i >= -start_offset; i--) {
struct json_object *format;
uint32_t header = nlog_get_pos(nlog, nlog_size, i);
uint32_t num_data;
if (header == 0 || !formats_find(formats, header, &format)) {
if (event_count > 0) {
//check if fould circular buffer tail
if (i != (last_bad_header_pos - 1)) {
if (tail_mismatches &&
(tail_count < MAX_HEADER_MISMATCH_TRACK))
tail_mismatches[tail_count] = header;
tail_count++;
}
last_bad_header_pos = i;
}
continue;
}
num_data = header & NUM_ARGS_MASK;
if (events) {
struct json_object *event = json_object_new_array();
struct json_object *param = json_object_new_array();
uint32_t val = nlog_get_pos(nlog, nlog_size, i - 1);
json_object_array_add(events, event);
json_object_array_add(event, json_object_new_int64(val));
val = nlog_get_pos(nlog, nlog_size, i - 2);
json_object_array_add(event, json_object_new_int64(val));
json_object_array_add(event, json_object_new_int64(header));
json_object_array_add(event, param);
for (uint32_t j = 0; j < num_data; j++) {
val = nlog_get_pos(nlog, nlog_size, i - 3 - j);
json_object_array_add(param, json_object_new_int64(val));
}
json_object_get(format);
json_object_array_add(event, format);
}
i -= 2 + num_data;
event_count++;
}
return tail_count;
}
int solidigm_nlog_parse(const char *buffer, uint64_t buff_size, struct json_object *formats,
struct json_object *metadata, struct json_object *output)
{
uint32_t smaller_tail_count = UINT32_MAX;
int best_offset = 0;
uint32_t offset_tail_mismatches[LOG_ENTRY_MAX_SIZE][MAX_HEADER_MISMATCH_TRACK];
struct json_object *events = json_object_new_array();
const uint32_t *nlog = (uint32_t *)buffer;
const uint32_t nlog_size = buff_size / sizeof(uint32_t);
for (int i = 0; i < LOG_ENTRY_MAX_SIZE; i++) {
uint32_t tail_count = nlog_get_events(nlog, nlog_size, i, formats, NULL,
offset_tail_mismatches[i]);
if (tail_count < smaller_tail_count) {
best_offset = i;
smaller_tail_count = tail_count;
}
if (tail_count == 0)
break;
}
if (smaller_tail_count > 1) {
const char *name = "";
int media_bank = -1;
char str_mismatches[(STR_HEX32_SIZE + 1) * MAX_HEADER_MISMATCH_TRACK];
int pos = 0;
int show_mismatch_num = smaller_tail_count < MAX_HEADER_MISMATCH_TRACK ?
smaller_tail_count : MAX_HEADER_MISMATCH_TRACK;
struct json_object *jobj;
if (json_object_object_get_ex(metadata, "objName", &jobj))
name = json_object_get_string(jobj);
if (json_object_object_get_ex(metadata, "mediaBankId", &jobj))
media_bank = json_object_get_int(jobj);
for (int i = 0; i < show_mismatch_num; i++)
pos += snprintf(&str_mismatches[pos], STR_HEX32_SIZE + 1, "0x%08X ",
offset_tail_mismatches[best_offset][i]);
SOLIDIGM_LOG_WARNING("%s:%d with %d header mismatches ( %s). Configuration file may be missing format headers.",
name, media_bank, smaller_tail_count, str_mismatches);
}
nlog_get_events(nlog, nlog_size, best_offset, formats, events, NULL);
json_object_object_add(output, "events", events);
return 0;
}

View file

@ -0,0 +1,11 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright (c) 2023 Solidigm.
*
* Author: leonardo.da.cunha@solidigm.com
*/
#include "telemetry-log.h"
int solidigm_nlog_parse(const char *buffer, uint64_t bufer_size,
struct json_object *formats, struct json_object *metadata,
struct json_object *output);

View file

@ -21,37 +21,37 @@ static const __u32 OP_SCT_STATUS = 0xE0;
static const __u32 OP_SCT_COMMAND_TRANSFER = 0xE0;
static const __u32 OP_SCT_DATA_TRANSFER = 0xE1;
static const __u32 DW10_SCT_STATUS_COMMAND = 0x0;
static const __u32 DW10_SCT_STATUS_COMMAND;
static const __u32 DW10_SCT_COMMAND_TRANSFER = 0x1;
static const __u32 DW11_SCT_STATUS_COMMAND = 0x0;
static const __u32 DW11_SCT_COMMAND_TRANSFER = 0x0;
static const __u32 DW11_SCT_STATUS_COMMAND;
static const __u32 DW11_SCT_COMMAND_TRANSFER;
static const __u16 INTERNAL_LOG_ACTION_CODE = 0xFFFB;
static const __u16 CURRENT_LOG_FUNCTION_CODE = 0x0001;
static const __u16 SAVED_LOG_FUNCTION_CODE = 0x0002;
/* A bitmask field for supported devices */
typedef enum {
MASK_0 = 1 << 0,
MASK_1 = 1 << 1,
enum {
MASK_0 = 1 << 0,
MASK_1 = 1 << 1,
/*
* Future devices can use the remaining 31 bits from this field
* and should use 1 << 2, 1 << 3, etc.
*/
MASK_IGNORE = 0
} DeviceMask;
};
/* Internal device codes */
typedef enum {
enum {
CODE_0 = 0x0D,
CODE_1 = 0x10
} DeviceCode;
};
static int nvme_sct_op(int fd, __u32 opcode, __u32 cdw10, __u32 cdw11, void* data, __u32 data_len )
static int nvme_sct_op(int fd, __u32 opcode, __u32 cdw10, __u32 cdw11, void *data, __u32 data_len)
{
void *metadata = NULL;
void *metadata = NULL;
const __u32 cdw2 = 0;
const __u32 cdw3 = 0;
const __u32 cdw12 = 0;
@ -63,26 +63,23 @@ static int nvme_sct_op(int fd, __u32 opcode, __u32 cdw10, __u32 cdw11, void* da
const __u32 namespace_id = 0x0;
const __u32 flags = 0;
const __u32 rsvd = 0;
int err = 0;
__u32 result;
err = nvme_admin_passthru(fd, opcode, flags, rsvd,
namespace_id, cdw2, cdw3, cdw10,
cdw11, cdw12, cdw13, cdw14, cdw15,
data_len, data, metadata_len, metadata,
timeout, &result);
return err;
return nvme_admin_passthru(fd, opcode, flags, rsvd, namespace_id, cdw2, cdw3, cdw10, cdw11,
cdw12, cdw13, cdw14, cdw15, data_len, data, metadata_len,
metadata, timeout, &result);
}
static int nvme_get_sct_status(int fd, __u32 device_mask)
{
int err;
void* data = NULL;
void *data = NULL;
size_t data_len = 512;
unsigned char *status;
__u32 supported = 0;
if (posix_memalign(&data, getpagesize(), data_len))
return ENOMEM;
return -ENOMEM;
memset(data, 0, data_len);
err = nvme_sct_op(fd, OP_SCT_STATUS, DW10_SCT_STATUS_COMMAND, DW11_SCT_STATUS_COMMAND, data, data_len);
@ -102,22 +99,19 @@ static int nvme_get_sct_status(int fd, __u32 device_mask)
/* Check if device is supported */
if (device_mask != MASK_IGNORE) {
__u32 supported = 0;
switch (status[1]) {
case CODE_0:
supported = (device_mask & MASK_0);
break;
case CODE_1:
supported = (device_mask & MASK_1);
break;
default:
break;
};
if (0 == supported) {
fprintf(stderr, "%s: command unsupported on this device: (0x%x)\n",__func__, status[1]);
if (!supported) {
fprintf(stderr, "%s: command unsupported on this device: (0x%x)\n", __func__, status[1]);
err = -1;
errno = EINVAL;
goto end;
@ -142,7 +136,7 @@ static int nvme_sct_command_transfer_log(int fd, bool current)
function_code = SAVED_LOG_FUNCTION_CODE;
if (posix_memalign(&data, getpagesize(), data_len))
return ENOMEM;
return -ENOMEM;
memset(data, 0, data_len);
memcpy(data, &action_code, sizeof(action_code));
@ -153,7 +147,7 @@ static int nvme_sct_command_transfer_log(int fd, bool current)
return err;
}
static int nvme_sct_data_transfer(int fd, void* data, size_t data_len, size_t offset)
static int nvme_sct_data_transfer(int fd, void *data, size_t data_len, size_t offset)
{
__u32 dw10, dw11, lba_count = (data_len) / 512;
@ -170,7 +164,7 @@ static int nvme_sct_data_transfer(int fd, void* data, size_t data_len, size_t of
return nvme_sct_op(fd, OP_SCT_DATA_TRANSFER, dw10, dw11, data, data_len);
}
static int d_raw_to_fd(const unsigned char *buf, unsigned len, int fd)
static int d_raw_to_fd(const unsigned char *buf, unsigned int len, int fd)
{
int written = 0;
int remaining = len;
@ -207,26 +201,26 @@ static void progress_runner(float progress)
fprintf(stdout, " ");
}
fprintf(stdout, "] %d %%\r",(int)(progress * 100.0));
fprintf(stdout, "] %d %%\r", (int)(progress * 100.0));
fflush(stdout);
}
static int nvme_get_internal_log(int fd, const char* const filename, bool current)
static int nvme_get_internal_log(int fd, const char *const filename, bool current)
{
int err;
int o_fd = -1;
void* page_data = NULL;
void *page_data = NULL;
const size_t page_sector_len = 32;
const size_t page_data_len = page_sector_len * 512; /* 32 sectors per page */
uint32_t* area1_last_page;
uint32_t* area2_last_page;
uint32_t* area3_last_page;
uint32_t *area1_last_page;
uint32_t *area2_last_page;
uint32_t *area3_last_page;
uint32_t log_sectors = 0;
size_t pages;
__u32 pages_chunk;
/*
* By trial and error it seems that the largest transfer chunk size
* is 128 * 32 = 4k sectors = 2MB
* is 128 * 32 = 4k sectors = 2MB
*/
const __u32 max_pages = 128;
size_t i;
@ -248,7 +242,7 @@ static int nvme_get_internal_log(int fd, const char* const filename, bool curren
/* Read the header to get the last log page - offsets 8->11, 12->15, 16->19 */
err = nvme_sct_data_transfer(fd, page_data, page_data_len, 0);
if (err) {
fprintf(stderr, "%s: SCT data transfer failed, page 0\n",__func__);
fprintf(stderr, "%s: SCT data transfer failed, page 0\n", __func__);
goto end;
}
@ -274,7 +268,7 @@ static int nvme_get_internal_log(int fd, const char* const filename, bool curren
o_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (o_fd < 0) {
fprintf(stderr, "%s: couldn't output file %s\n", __func__, filename);
err = EINVAL;
err = -EINVAL;
goto end;
}
err = d_raw_to_fd(page_data, page_data_len, o_fd);
@ -286,7 +280,7 @@ static int nvme_get_internal_log(int fd, const char* const filename, bool curren
/* Now read the rest */
for (i = 1; i < pages;) {
__u32 pages_chunk = max_pages;
pages_chunk = max_pages;
if (pages_chunk + i >= pages)
pages_chunk = pages - i;
@ -318,23 +312,21 @@ static int nvme_get_internal_log(int fd, const char* const filename, bool curren
}
progress = 1.0f;
progress_runner(progress);
fprintf(stdout,"\n");
fprintf(stdout, "\n");
err = nvme_get_sct_status(fd, MASK_IGNORE);
if (err) {
fprintf(stderr, "%s: bad SCT status\n", __func__);
goto end;
}
end:
if (o_fd >= 0) {
if (o_fd >= 0)
close(o_fd);
}
if (page_data) {
if (page_data)
free(page_data);
}
return err;
}
static int nvme_get_internal_log_file(int fd, const char* const filename, bool current)
static int nvme_get_internal_log_file(int fd, const char *const filename, bool current)
{
int err;
@ -366,20 +358,20 @@ static void default_show_vendor_log_c0(struct nvme_dev *dev, __u32 nsid,
{
printf("Vendor Log Page Directory 0xC0 for NVME device:%s namespace-id:%x\n",
dev->name, nsid);
printf("Error Log : %u \n", smart->items[ERROR_LOG_C0]);
printf("SMART Health Log : %u \n", smart->items[SMART_HEALTH_LOG_C0]);
printf("Firmware Slot Info : %u \n", smart->items[FIRMWARE_SLOT_INFO_C0]);
printf("Command Effects : %u \n", smart->items[COMMAND_EFFECTS_C0]);
printf("Device Self Test : %u \n", smart->items[DEVICE_SELF_TEST_C0]);
printf("Log Page Directory : %u \n", smart->items[LOG_PAGE_DIRECTORY_C0]);
printf("SMART Attributes : %u \n", smart->items[SMART_ATTRIBUTES_C0]);
printf("Error Log : %u\n", smart->items[ERROR_LOG_C0]);
printf("SMART Health Log : %u\n", smart->items[SMART_HEALTH_LOG_C0]);
printf("Firmware Slot Info : %u\n", smart->items[FIRMWARE_SLOT_INFO_C0]);
printf("Command Effects : %u\n", smart->items[COMMAND_EFFECTS_C0]);
printf("Device Self Test : %u\n", smart->items[DEVICE_SELF_TEST_C0]);
printf("Log Page Directory : %u\n", smart->items[LOG_PAGE_DIRECTORY_C0]);
printf("SMART Attributes : %u\n", smart->items[SMART_ATTRIBUTES_C0]);
}
static int nvme_get_vendor_log(struct nvme_dev *dev, __u32 namespace_id,
int log_page, const char* const filename)
int log_page, const char *const filename)
{
int err;
void* log = NULL;
void *log = NULL;
size_t log_len = 512;
if (posix_memalign(&log, getpagesize(), log_len)) {
@ -389,9 +381,8 @@ static int nvme_get_vendor_log(struct nvme_dev *dev, __u32 namespace_id,
/* Check device supported */
err = nvme_get_sct_status(dev_fd(dev), MASK_0 | MASK_1);
if (err) {
if (err)
goto end;
}
err = nvme_get_nsid_log(dev_fd(dev), false, log_page, namespace_id,
log_len, log);
if (err) {
@ -405,7 +396,7 @@ static int nvme_get_vendor_log(struct nvme_dev *dev, __u32 namespace_id,
if (o_fd < 0) {
fprintf(stderr, "%s: couldn't output file %s\n",
__func__, filename);
err = EINVAL;
err = -EINVAL;
goto end;
}
err = d_raw_to_fd(log, log_len, o_fd);
@ -422,12 +413,11 @@ static int nvme_get_vendor_log(struct nvme_dev *dev, __u32 namespace_id,
if (log_page == 0xc0)
default_show_vendor_log_c0(dev, namespace_id, log);
else
d(log, log_len,16,1);
d(log, log_len, 16, 1);
}
end:
if (log) {
if (log)
free(log);
}
return err;
}
@ -442,7 +432,7 @@ static int vendor_log(int argc, char **argv, struct command *cmd, struct plugin
struct config {
__u32 namespace_id;
const char* output_file;
const char *output_file;
int log;
};
@ -461,13 +451,13 @@ static int vendor_log(int argc, char **argv, struct command *cmd, struct plugin
err = parse_and_open(&dev, argc, argv, desc, opts);
if (err) {
fprintf(stderr,"%s: failed to parse arguments\n", __func__);
return EINVAL;
fprintf(stderr, "%s: failed to parse arguments\n", __func__);
return -EINVAL;
}
if ((cfg.log != 0xC0) && (cfg.log != 0xCA)) {
fprintf(stderr, "%s: invalid log page 0x%x - should be 0xC0 or 0xCA\n", __func__, cfg.log);
err = EINVAL;
err = -EINVAL;
goto end;
}
@ -491,7 +481,7 @@ static int internal_log(int argc, char **argv, struct command *cmd, struct plugi
int err;
struct config {
const char* output_file;
const char *output_file;
bool prev_log;
};
@ -501,15 +491,15 @@ static int internal_log(int argc, char **argv, struct command *cmd, struct plugi
};
OPT_ARGS(opts) = {
OPT_FILE("output-file", 'o', &cfg.output_file, output_file),
OPT_FILE("output-file", 'o', &cfg.output_file, output_file),
OPT_FLAG("prev-log", 'p', &cfg.prev_log, prev_log),
OPT_END()
};
err = parse_and_open(&dev, argc, argv, desc, opts);
if (err) {
fprintf(stderr,"%s: failed to parse arguments\n", __func__);
return EINVAL;
fprintf(stderr, "%s: failed to parse arguments\n", __func__);
return -EINVAL;
}
if (cfg.prev_log)
@ -520,7 +510,7 @@ static int internal_log(int argc, char **argv, struct command *cmd, struct plugi
err = nvme_get_internal_log_file(dev_fd(dev), cfg.output_file,
!cfg.prev_log);
if (err < 0)
fprintf(stderr, "%s: couldn't get fw log \n", __func__);
fprintf(stderr, "%s: couldn't get fw log\n", __func__);
if (err > 0)
nvme_show_status(err);
@ -547,8 +537,8 @@ static int clear_correctable_errors(int argc, char **argv, struct command *cmd,
err = parse_and_open(&dev, argc, argv, desc, opts);
if (err) {
fprintf(stderr,"%s: failed to parse arguments\n", __func__);
return EINVAL;
fprintf(stderr, "%s: failed to parse arguments\n", __func__);
return -EINVAL;
}
/* Check device supported */
@ -573,7 +563,7 @@ static int clear_correctable_errors(int argc, char **argv, struct command *cmd,
};
err = nvme_set_features(&args);
if (err)
fprintf(stderr, "%s: couldn't clear PCIe correctable errors \n",
fprintf(stderr, "%s: couldn't clear PCIe correctable errors\n",
__func__);
end:
if (err > 0)

View file

@ -21,7 +21,7 @@ static int getHealthValue(int argc, char **argv, struct command *cmd, struct plu
{
struct nvme_smart_log smart_log;
char *desc = "Get nvme health percentage.";
int percent_used = 0, healthvalue=0;
int percent_used = 0, healthvalue = 0;
struct nvme_dev *dev;
int result;
@ -31,59 +31,55 @@ static int getHealthValue(int argc, char **argv, struct command *cmd, struct plu
result = parse_and_open(&dev, argc, argv, desc, opts);
if (result) {
printf("\nDevice not found \n");;
printf("\nDevice not found\n");
return -1;
}
result = nvme_get_log_smart(dev_fd(dev), 0xffffffff, false, &smart_log);
if (!result) {
printf("Transcend NVME heath value: ");
percent_used =smart_log.percent_used;
if(percent_used>100 || percent_used<0)
{
percent_used = smart_log.percent_used;
if (percent_used > 100 || percent_used < 0) {
printf("0%%\n");
}
else
{
} else {
healthvalue = 100 - percent_used;
printf("%d%%\n",healthvalue);
printf("%d%%\n", healthvalue);
}
}
dev_close(dev);
return result;
}
static int getBadblock(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
char *desc = "Get nvme bad block number.";
struct nvme_dev *dev;
int result;
OPT_ARGS(opts) = {
OPT_END()
};
result = parse_and_open(&dev, argc, argv, desc, opts);
if (result) {
printf("\nDevice not found \n");;
printf("\nDevice not found\n");
return -1;
}
unsigned char data[1]={0};
unsigned char data[1] = {0};
struct nvme_passthru_cmd nvmecmd;
memset(&nvmecmd,0,sizeof(nvmecmd));
nvmecmd.opcode=OP_BAD_BLOCK;
nvmecmd.cdw10=DW10_BAD_BLOCK;
nvmecmd.cdw12=DW12_BAD_BLOCK;
memset(&nvmecmd, 0, sizeof(nvmecmd));
nvmecmd.opcode = OP_BAD_BLOCK;
nvmecmd.cdw10 = DW10_BAD_BLOCK;
nvmecmd.cdw12 = DW12_BAD_BLOCK;
nvmecmd.addr = (__u64)(uintptr_t)data;
nvmecmd.data_len = 0x1;
result = nvme_submit_admin_passthru(dev_fd(dev), &nvmecmd, NULL);
if(!result) {
if (!result) {
int badblock = data[0];
printf("Transcend NVME badblock count: %d\n",badblock);
printf("Transcend NVME badblock count: %d\n", badblock);
}
dev_close(dev);
return result;

View file

@ -19,7 +19,7 @@
#define CREATE_CMD
#include "virtium-nvme.h"
#define MIN2(a, b) ( ((a) < (b))? (a) : (b))
#define MIN2(a, b) (((a) < (b)) ? (a) : (b))
#define HOUR_IN_SECONDS 3600
@ -30,26 +30,26 @@
static char vt_default_log_file_name[256];
struct vtview_log_header {
char path[256];
char test_name[256];
long int time_stamp;
struct nvme_id_ctrl raw_ctrl;
struct nvme_firmware_slot raw_fw;
char path[256];
char test_name[256];
long time_stamp;
struct nvme_id_ctrl raw_ctrl;
struct nvme_firmware_slot raw_fw;
};
struct vtview_smart_log_entry {
char path[256];
long int time_stamp;
char path[256];
long time_stamp;
struct nvme_id_ns raw_ns;
struct nvme_id_ctrl raw_ctrl;
struct nvme_smart_log raw_smart;
};
struct vtview_save_log_settings {
double run_time_hrs;
double log_record_frequency_hrs;
const char* output_file;
const char* test_name;
double run_time_hrs;
double log_record_frequency_hrs;
const char *output_file;
const char *test_name;
};
static void vt_initialize_header_buffer(struct vtview_log_header *pbuff)
@ -72,7 +72,7 @@ static void vt_convert_data_buffer_to_hex_string(const unsigned char *bufPtr,
memset(output, 0, (size * 2) + 1);
for (i = 0; i < size; i++) {
if(isReverted)
if (isReverted)
pos = size - 1 - i;
else
pos = i;
@ -86,7 +86,7 @@ static void vt_convert_data_buffer_to_hex_string(const unsigned char *bufPtr,
* Log file name will be generated automatically if user leave log file option blank.
* Log file name will be generated as vtView-Smart-log-date-time.txt
*/
static void vt_generate_vtview_log_file_name(char* fname)
static void vt_generate_vtview_log_file_name(char *fname)
{
time_t current;
struct tm tstamp;
@ -112,17 +112,19 @@ static void vt_convert_smart_data_to_human_readable_format(struct vtview_smart_l
char *curlocale;
char *templocale;
__u8 lba_index;
nvme_id_ns_flbas_to_lbaf_inuse(smart->raw_ns.flbas, &lba_index);
curlocale = setlocale(LC_ALL, NULL);
templocale = strdup(curlocale);
if (NULL == templocale)
if (!templocale)
printf("Cannot malloc buffer\n");
setlocale(LC_ALL, "C");
unsigned long long int lba = 1ULL << smart->raw_ns.lbaf[lba_index].ds;
unsigned long long lba = 1ULL << smart->raw_ns.lbaf[lba_index].ds;
capacity = le64_to_cpu(smart->raw_ns.nsze) * lba;
snprintf(tempbuff, sizeof(tempbuff), "log;%s;%lu;%s;%s;%-.*s;", smart->raw_ctrl.sn, smart->time_stamp, smart->path,
@ -167,7 +169,8 @@ static void vt_convert_smart_data_to_human_readable_format(struct vtview_smart_l
for (i = 0; i < 8; i++) {
__s32 temp = le16_to_cpu(smart->raw_smart.temp_sensor[i]);
if (0 == temp) {
if (!temp) {
snprintf(tempbuff, sizeof(tempbuff), "Temperature_Sensor_%d;NC;", i);
strcat(text, tempbuff);
continue;
@ -217,7 +220,7 @@ static int vt_append_text_file(const char *text, const char *filename)
FILE *f;
f = fopen(filename, "a");
if(NULL == f) {
if (!f) {
printf("Cannot open %s\n", filename);
return -1;
}
@ -247,11 +250,11 @@ static void vt_process_string(char *str, const size_t size)
{
size_t i;
if (size == 0)
if (!size)
return;
i = size - 1;
while ((0 != i) && (' ' == str[i])) {
while (i && (' ' == str[i])) {
str[i] = 0;
i--;
}
@ -262,11 +265,11 @@ static int vt_add_entry_to_log(const int fd, const char *path, const struct vtvi
struct vtview_smart_log_entry smart;
const char *filename;
int ret = 0;
unsigned nsid = 0;
unsigned int nsid = 0;
memset(smart.path, 0, sizeof(smart.path));
strncpy(smart.path, path, sizeof(smart.path) - 1);
if(NULL == cfg->output_file)
if (!cfg->output_file)
filename = vt_default_log_file_name;
else
filename = cfg->output_file;
@ -301,7 +304,7 @@ static int vt_add_entry_to_log(const int fd, const char *path, const struct vtvi
vt_process_string(smart.raw_ctrl.mn, sizeof(smart.raw_ctrl.mn));
ret = vt_append_log(&smart, filename);
return (ret);
return ret;
}
static int vt_update_vtview_log_header(const int fd, const char *path, const struct vtview_save_log_settings *cfg)
@ -318,9 +321,9 @@ static int vt_update_vtview_log_header(const int fd, const char *path, const str
}
strcpy(header.path, path);
if (NULL == cfg->test_name)
if (!cfg->test_name) {
strcpy(header.test_name, DEFAULT_TEST_NAME);
else {
} else {
if (strlen(cfg->test_name) > sizeof(header.test_name)) {
printf("test name too long\n");
errno = EINVAL;
@ -329,7 +332,7 @@ static int vt_update_vtview_log_header(const int fd, const char *path, const str
strcpy(header.test_name, cfg->test_name);
}
if(NULL == cfg->output_file)
if (!cfg->output_file)
filename = vt_default_log_file_name;
else
filename = cfg->output_file;
@ -353,7 +356,7 @@ static int vt_update_vtview_log_header(const int fd, const char *path, const str
vt_process_string(header.raw_ctrl.mn, sizeof(header.raw_ctrl.mn));
ret = vt_append_header(&header, filename);
return (ret);
return ret;
}
static void vt_build_identify_lv2(unsigned int data, unsigned int start,
@ -371,13 +374,13 @@ static void vt_build_identify_lv2(unsigned int data, unsigned int start,
printf(" \"bit %u\":\"%ub %s\"\n", i, temp, table[pos]);
printf(" %s", table[pos + 1]);
if((end - 1) != i || !isEnd)
if ((end - 1) != i || !isEnd)
printf(",\n");
else
printf("\n");
}
if(isEnd)
if (isEnd)
printf(" },\n");
}
@ -418,7 +421,7 @@ static void vt_build_power_state_descriptor(const struct nvme_id_ctrl *ctrl)
unsigned int temp;
printf("%6d", i);
buf = (unsigned char*) (&ctrl->psd[i]);
buf = (unsigned char *) (&ctrl->psd[i]);
vt_convert_data_buffer_to_hex_string(&buf[0], 4, true, s);
printf("%9sh", s);
@ -469,36 +472,35 @@ static void vt_build_power_state_descriptor(const struct nvme_id_ctrl *ctrl)
}
static void vt_dump_hex_data(const unsigned char *pbuff, size_t pbuffsize) {
static void vt_dump_hex_data(const unsigned char *pbuff, size_t pbuffsize)
{
char textbuf[33];
unsigned long int i, j;
unsigned long i, j;
textbuf[32] = '\0';
printf("[%08X] ", 0);
for (i = 0; i < pbuffsize; i++) {
printf("%02X ", pbuff[i]);
if (pbuff[i] >= ' ' && pbuff[i] <= '~')
if (pbuff[i] >= ' ' && pbuff[i] <= '~')
textbuf[i % 32] = pbuff[i];
else
else
textbuf[i % 32] = '.';
if ((((i + 1) % 8) == 0) || ((i + 1) == pbuffsize)) {
if (!(((i + 1) % 8)) || ((i + 1) == pbuffsize)) {
printf(" ");
if ((i + 1) % 32 == 0) {
if (!((i + 1) % 32)) {
printf(" %s\n", textbuf);
if((i + 1) != pbuffsize)
printf("[%08lX] ", (i + 1));
}
else if (i + 1 == pbuffsize) {
if ((i + 1) != pbuffsize)
printf("[%08lX] ", (i + 1));
} else if (i + 1 == pbuffsize) {
textbuf[(i + 1) % 32] = '\0';
if(((i + 1) % 8) == 0)
if (!((i + 1) % 8))
printf(" ");
for (j = ((i + 1) % 32); j < 32; j++) {
printf(" ");
if(((j + 1) % 8) == 0)
if (!((j + 1) % 8))
printf(" ");
}
@ -515,174 +517,174 @@ static void vt_parse_detail_identify(const struct nvme_id_ctrl *ctrl)
char s[1024] = "";
const char *CMICtable[6] = {"0 = the NVM subsystem contains only a single NVM subsystem port",
"1 = the NVM subsystem may contain more than one subsystem ports",
"0 = the NVM subsystem contains only a single controller",
"1 = the NVM subsystem may contain two or more controllers (see section 1.4.1)",
"0 = the controller is associated with a PCI Function or a Fabrics connection",
"1 = the controller is associated with an SR-IOV Virtual Function"};
"1 = the NVM subsystem may contain more than one subsystem ports",
"0 = the NVM subsystem contains only a single controller",
"1 = the NVM subsystem may contain two or more controllers (see section 1.4.1)",
"0 = the controller is associated with a PCI Function or a Fabrics connection",
"1 = the controller is associated with an SR-IOV Virtual Function"};
const char *OAEStable[20] = {"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"0 = does not support sending the Namespace Attribute Notices event nor the associated Changed Namespace List log page",
"1 = supports sending the Namespace Attribute Notices & the associated Changed Namespace List log page",
"0 = does not support sending Firmware Activation Notices event",
"1 = supports sending Firmware Activation Notices"};
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"0 = does not support sending the Namespace Attribute Notices event nor the associated Changed Namespace List log page",
"1 = supports sending the Namespace Attribute Notices & the associated Changed Namespace List log page",
"0 = does not support sending Firmware Activation Notices event",
"1 = supports sending Firmware Activation Notices"};
const char *CTRATTtable[4] = {"0 = does not support a 128-bit Host Identifier",
"1 = supports a 128-bit Host Identifier",
"0 = does not support Non-Operational Power State Permissive Mode",
"1 = supports Non-Operational Power State Permissive Mode"};
"1 = supports a 128-bit Host Identifier",
"0 = does not support Non-Operational Power State Permissive Mode",
"1 = supports Non-Operational Power State Permissive Mode"};
const char *OACStable[18] = {"0 = does not support the Security Send and Security Receive commands",
"1 = supports the Security Send and Security Receive commands",
"0 = does not support the Format NVM command",
"1 = supports the Format NVM command",
"0 = does not support the Firmware Commit and Firmware Image Download commands",
"1 = supports the Firmware Commit and Firmware Image Download commands",
"0 = does not support the Namespace Management capability",
"1 = supports the Namespace Management capability",
"0 = does not support the Device Self-test command",
"1 = supports the Device Self-test command",
"0 = does not support Directives",
"1 = supports Directive Send & Directive Receive commands",
"0 = does not support the NVMe-MI Send and NVMe-MI Receive commands",
"1 = supports the NVMe-MI Send and NVMe-MI Receive commands",
"0 = does not support the Virtualization Management command",
"1 = supports the Virtualization Management command",
"0 = does not support the Doorbell Buffer Config command",
"1 = supports the Doorbell Buffer Config command"};
"1 = supports the Security Send and Security Receive commands",
"0 = does not support the Format NVM command",
"1 = supports the Format NVM command",
"0 = does not support the Firmware Commit and Firmware Image Download commands",
"1 = supports the Firmware Commit and Firmware Image Download commands",
"0 = does not support the Namespace Management capability",
"1 = supports the Namespace Management capability",
"0 = does not support the Device Self-test command",
"1 = supports the Device Self-test command",
"0 = does not support Directives",
"1 = supports Directive Send & Directive Receive commands",
"0 = does not support the NVMe-MI Send and NVMe-MI Receive commands",
"1 = supports the NVMe-MI Send and NVMe-MI Receive commands",
"0 = does not support the Virtualization Management command",
"1 = supports the Virtualization Management command",
"0 = does not support the Doorbell Buffer Config command",
"1 = supports the Doorbell Buffer Config command"};
const char *FRMWtable[10] = {"0 = the 1st firmware slot (slot 1) is read/write",
"1 = the 1st firmware slot (slot 1) is read only",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"0 = requires a reset for firmware to be activated",
"1 = supports firmware activation without a reset"};
"1 = the 1st firmware slot (slot 1) is read only",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"0 = requires a reset for firmware to be activated",
"1 = supports firmware activation without a reset"};
const char *LPAtable[8] = {"0 = does not support the SMART / Health information log page on a per namespace basis",
"1 = supports the SMART / Health information log page on a per namespace basis",
"0 = does not support the Commands Supported & Effects log page",
"1 = supports the Commands Supported Effects log page",
"0 = does not support extended data for Get Log Page",
"1 = supports extended data for Get Log Page (including extended Number of Dwords and Log Page Offset fields)",
"0 = does not support the Telemetry Host-Initiated and Telemetry Controller-Initiated log pages and Telemetry Log Notices events",
"1 = supports the Telemetry Host-Initiated and Telemetry Controller-Initiated log pages and sending Telemetry Log Notices" };
"1 = supports the SMART / Health information log page on a per namespace basis",
"0 = does not support the Commands Supported & Effects log page",
"1 = supports the Commands Supported Effects log page",
"0 = does not support extended data for Get Log Page",
"1 = supports extended data for Get Log Page (including extended Number of Dwords and Log Page Offset fields)",
"0 = does not support the Telemetry Host-Initiated and Telemetry Controller-Initiated log pages and Telemetry Log Notices events",
"1 = supports the Telemetry Host-Initiated and Telemetry Controller-Initiated log pages and sending Telemetry Log Notices"};
const char *AVSCCtable[2] = {"0 = the format of all Admin Vendor Specific Commands are vendor specific",
"1 = all Admin Vendor Specific Commands use the format defined in NVM Express specification"};
"1 = all Admin Vendor Specific Commands use the format defined in NVM Express specification"};
const char *APSTAtable[2] = {"0 = does not support autonomous power state transitions",
"1 = supports autonomous power state transitions"};
"1 = supports autonomous power state transitions"};
const char *DSTOtable[2] = {"0 = the NVM subsystem supports one device self-test operation per controller at a time",
"1 = the NVM subsystem supports only one device self-test operation in progress at a time"};
"1 = the NVM subsystem supports only one device self-test operation in progress at a time"};
const char *HCTMAtable[2] = {"0 = does not support host controlled thermal management",
"1 = supports host controlled thermal management. Supports Set Features & Get Features commands with the Feature Identifier field set to 10h"};
"1 = supports host controlled thermal management. Supports Set Features & Get Features commands with the Feature Identifier field set to 10h"};
const char *SANICAPtable[6] = {"0 = does not support the Crypto Erase sanitize operation",
"1 = supports the Crypto Erase sanitize operation",
"0 = does not support the Block Erase sanitize operation",
"1 = supports the Block Erase sanitize operation",
"0 = does not support the Overwrite sanitize operation",
"1 = supports the Overwrite sanitize operation"};
"1 = supports the Crypto Erase sanitize operation",
"0 = does not support the Block Erase sanitize operation",
"1 = supports the Block Erase sanitize operation",
"0 = does not support the Overwrite sanitize operation",
"1 = supports the Overwrite sanitize operation"};
const char *ONCStable[14] = {"0 = does not support the Compare command",
"1 = supports the Compare command",
"0 = does not support the Write Uncorrectable command",
"1 = supports the Write Uncorrectable command",
"0 = does not support the Dataset Management command",
"1 = supports the Dataset Management command",
"0 = does not support the Write Zeroes command",
"1 = supports the Write Zeroes command",
"0 = does not support the Save field set to a non-zero value in the Set Features and the Get Features commands",
"1 = supports the Save field set to a non-zero value in the Set Features and the Get Features commands", \
"0 = does not support reservations",
"1 = supports reservations",
"0 = does not support the Timestamp feature (refer to section 5.21.1.14)",
"1 = supports the Timestamp feature"};
"1 = supports the Compare command",
"0 = does not support the Write Uncorrectable command",
"1 = supports the Write Uncorrectable command",
"0 = does not support the Dataset Management command",
"1 = supports the Dataset Management command",
"0 = does not support the Write Zeroes command",
"1 = supports the Write Zeroes command",
"0 = does not support the Save field set to a non-zero value in the Set Features and the Get Features commands",
"1 = supports the Save field set to a non-zero value in the Set Features and the Get Features commands",
"0 = does not support reservations",
"1 = supports reservations",
"0 = does not support the Timestamp feature (refer to section 5.21.1.14)",
"1 = supports the Timestamp feature"};
const char *FUSEStable[2] = {"0 = does not support the Compare and Write fused operation",
"1 = supports the Compare and Write fused operation"};
"1 = supports the Compare and Write fused operation"};
const char *FNAtable[6] = {"0 = supports format on a per namespace basis",
"1 = all namespaces shall be configured with the same attributes and a format (excluding secure erase) of any namespace results in a format of all namespaces in an NVM subsystem",
"0 = any secure erase performed as part of a format results in a secure erase of a particular namespace specified",
"1 = any secure erase performed as part of a format operation results in a secure erase of all namespaces in the NVM subsystem",
"0 = cryptographic erase is not supported",
"1 = cryptographic erase is supported as part of the secure erase functionality"};
"1 = all namespaces shall be configured with the same attributes and a format (excluding secure erase) of any namespace results in a format of all namespaces in an NVM subsystem",
"0 = any secure erase performed as part of a format results in a secure erase of a particular namespace specified",
"1 = any secure erase performed as part of a format operation results in a secure erase of all namespaces in the NVM subsystem",
"0 = cryptographic erase is not supported",
"1 = cryptographic erase is supported as part of the secure erase functionality"};
const char *VWCtable[2] = {"0 = a volatile write cache is not present",
"1 = a volatile write cache is present"};
"1 = a volatile write cache is present"};
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"};
"1 = all NVM Vendor Specific Commands use the format defined in NVM Express specification"};
const char *SGLSSubtable[4] = {"00b = SGLs are not supported",
"01b = SGLs are supported. There is no alignment nor granularity requirement for Data Blocks",
"10b = SGLs are supported. There is a Dword alignment and granularity requirement for Data Blocks",
"11b = Reserved"};
"01b = SGLs are supported. There is no alignment nor granularity requirement for Data Blocks",
"10b = SGLs are supported. There is a Dword alignment and granularity requirement for Data Blocks",
"11b = Reserved"};
const char *SGLStable[42] = {"Used",
"Used",
"Used",
"Used",
"0 = does not support the Keyed SGL Data Block descriptor",
"1 = supports the Keyed SGL Data Block descriptor",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"0 = the SGL Bit Bucket descriptor is not supported",
"1 = the SGL Bit Bucket descriptor is supported",
"0 = use of a byte aligned contiguous physical buffer of metadata is not supported",
"1 = use of a byte aligned contiguous physical buffer of metadata is supported",
"0 = the SGL length shall be equal to the amount of data to be transferred",
"1 = supports commands that contain a data or metadata SGL of a length larger than the amount of data to be transferred",
"0 = use of Metadata Pointer (MPTR) that contains an address of an SGL segment containing exactly one SGL Descriptor that is Qword aligned is not supported",
"1 = use of Metadata Pointer (MPTR) that contains an address of an SGL segment containing exactly one SGL Descriptor that is Qword aligned is supported",
"0 = the Address field specifying an offset is not supported",
"1 = supports the Address field in SGL Data Block, SGL Segment, and SGL Last Segment descriptor types specifying an offset"};
"Used",
"Used",
"Used",
"0 = does not support the Keyed SGL Data Block descriptor",
"1 = supports the Keyed SGL Data Block descriptor",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"0 = the SGL Bit Bucket descriptor is not supported",
"1 = the SGL Bit Bucket descriptor is supported",
"0 = use of a byte aligned contiguous physical buffer of metadata is not supported",
"1 = use of a byte aligned contiguous physical buffer of metadata is supported",
"0 = the SGL length shall be equal to the amount of data to be transferred",
"1 = supports commands that contain a data or metadata SGL of a length larger than the amount of data to be transferred",
"0 = use of Metadata Pointer (MPTR) that contains an address of an SGL segment containing exactly one SGL Descriptor that is Qword aligned is not supported",
"1 = use of Metadata Pointer (MPTR) that contains an address of an SGL segment containing exactly one SGL Descriptor that is Qword aligned is supported",
"0 = the Address field specifying an offset is not supported",
"1 = supports the Address field in SGL Data Block, SGL Segment, and SGL Last Segment descriptor types specifying an offset"};
buf = (unsigned char *)(ctrl);
@ -791,12 +793,12 @@ static void vt_parse_detail_identify(const struct nvme_id_ctrl *ctrl)
vt_convert_data_buffer_to_hex_string(&buf[296], 16, true, s);
printf(" \"Unallocated NVM Capacity\":\"%sh\",\n", s);
temp = le32_to_cpu(ctrl->rpmbs);
temp = le32_to_cpu(ctrl->rpmbs);
printf(" \"Replay Protected Memory Block Support\":{\n");
vt_convert_data_buffer_to_hex_string(&buf[312], 4, true, s);
printf(" \"Value\":\"%sh\",\n", s);
printf(" \"Number of RPMB Units\":\"%u\",\n", (temp & 0x00000003));
snprintf(s, sizeof(s), ((temp >> 3) & 0x00000007)? "Reserved" : "HMAC SHA-256");
snprintf(s, sizeof(s), ((temp >> 3) & 0x00000007) ? "Reserved" : "HMAC SHA-256");
printf(" \"Authentication Method\":\"%u: %s\",\n", ((temp >> 3) & 0x00000007), s);
printf(" \"Total Size\":\"%u\",\n", ((temp >> 16) & 0x000000FF));
printf(" \"Access Size\":\"%u\",\n", ((temp >> 24) & 0x000000FF));
@ -917,18 +919,18 @@ static void vt_parse_detail_identify(const struct nvme_id_ctrl *ctrl)
static int vt_save_smart_to_vtview_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
int ret, err = 0;
long int total_time = 0;
long int freq_time = 0;
long int cur_time = 0;
long int remain_time = 0;
long int start_time = 0;
long int end_time = 0;
long total_time = 0;
long freq_time = 0;
long cur_time = 0;
long remain_time = 0;
long start_time = 0;
long end_time = 0;
char path[256] = "";
char *desc = "Save SMART data into log file with format that is easy to analyze (comma delimited). Maximum log file will be 4K.\n\n"
"Typical usages:\n\n"
"Temperature characterization: \n"
"Temperature characterization:\n"
"\tvirtium save-smart-to-vtview-log /dev/yourDevice --run-time=100 --record-frequency=0.25 --test-name=burn-in-at-(-40)\n\n"
"Endurance testing : \n"
"Endurance testing :\n"
"\tvirtium save-smart-to-vtview-log /dev/yourDevice --run-time=100 --record-frequency=1 --test-name=Endurance-test-JEDEG-219-workload\n\n"
"Just logging :\n"
"\tvirtium save-smart-to-vtview-log /dev/yourDevice";
@ -979,13 +981,13 @@ static int vt_save_smart_to_vtview_log(int argc, char **argv, struct command *cm
if (ret) {
err = EINVAL;
dev_close(dev);
return (err);
return err;
}
total_time = cfg.run_time_hrs * (float)HOUR_IN_SECONDS;
freq_time = cfg.log_record_frequency_hrs * (float)HOUR_IN_SECONDS;
if(freq_time == 0)
if (!freq_time)
freq_time = 1;
start_time = time(NULL);
@ -995,7 +997,7 @@ static int vt_save_smart_to_vtview_log(int argc, char **argv, struct command *cm
while (1) {
cur_time = time(NULL);
if(cur_time >= end_time)
if (cur_time >= end_time)
break;
ret = vt_add_entry_to_log(dev_fd(dev), path, &cfg);
@ -1011,7 +1013,7 @@ static int vt_save_smart_to_vtview_log(int argc, char **argv, struct command *cm
}
dev_close(dev);
return (err);
return err;
}
static int vt_show_identify(int argc, char **argv, struct command *cmd, struct plugin *plugin)
@ -1037,7 +1039,7 @@ static int vt_show_identify(int argc, char **argv, struct command *cmd, struct p
if (ret) {
printf("Cannot read identify device\n");
dev_close(dev);
return (-1);
return -1;
}
vt_process_string(ctrl.sn, sizeof(ctrl.sn));
@ -1045,5 +1047,5 @@ static int vt_show_identify(int argc, char **argv, struct command *cmd, struct p
vt_parse_detail_identify(&ctrl);
dev_close(dev);
return (err);
return err;
}

File diff suppressed because it is too large Load diff

View file

@ -38,7 +38,7 @@ int wdc_UtilsSnprintf(char *buffer, unsigned int sizeOfBuffer, const char *forma
return res;
}
void wdc_UtilsDeleteCharFromString(char* buffer, int buffSize, char charToRemove)
void wdc_UtilsDeleteCharFromString(char *buffer, int buffSize, char charToRemove)
{
int i = 0;
int count = 0;
@ -62,7 +62,7 @@ int wdc_UtilsGetTime(PUtilsTimeInfo timeInfo)
time_t currTime;
struct tm currTimeInfo;
if(!timeInfo)
if (!timeInfo)
return WDC_STATUS_INVALID_PARAMETER;
tzset();
@ -81,7 +81,7 @@ int wdc_UtilsGetTime(PUtilsTimeInfo timeInfo)
#if defined(__GLIBC__) && !defined(__UCLIBC__) && !defined(__MUSL__)
timeInfo->zone = -currTimeInfo.tm_gmtoff / 60;
#else
timeInfo->zone = -1 * (timezone / SECONDS_IN_MIN);
timeInfo->zone = -1 * (timezone / SECONDS_IN_MIN);
#endif
return WDC_STATUS_SUCCESS;
@ -92,7 +92,7 @@ int wdc_UtilsCreateDir(char *path)
int retStatus;
int status = WDC_STATUS_SUCCESS;
if (!path )
if (!path)
return WDC_STATUS_INVALID_PARAMETER;
retStatus = mkdir(path, 0x999);
@ -125,7 +125,7 @@ int wdc_WriteToFile(char *fileName, char *buffer, unsigned int bufferLen)
status = WDC_STATUS_UNABLE_TO_WRITE_ALL_DATA;
end:
if(file)
if (file)
fclose(file);
return status;
}
@ -151,9 +151,7 @@ int wdc_UtilsStrCompare(char *pcSrc, char *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);
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') {

View file

@ -17,145 +17,145 @@
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);
memcpy(nm_val, smart->itemArr[index].nmVal, NM_SIZE);
memcpy(raw_val, smart->itemArr[index].rawVal, RAW_SIZE);
}
static int show_ymtc_smart_log(struct nvme_dev *dev, __u32 nsid,
struct nvme_ymtc_smart_log *smart)
{
struct nvme_id_ctrl ctrl;
char fw_ver[10];
int err = 0;
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));
u8 *nm = malloc(NM_SIZE * sizeof(u8));
u8 *raw = malloc(RAW_SIZE * sizeof(u8));
if (!nm) {
if (raw)
free(raw);
return -1;
}
if (!raw) {
free(nm);
return -1;
}
err = nvme_identify_ctrl(dev_fd(dev), &ctrl);
if (err) {
free(nm);
free(raw);
return err;
}
if (!nm) {
if (raw)
free(raw);
return -1;
}
if (!raw) {
free(nm);
return -1;
}
err = nvme_identify_ctrl(dev_fd(dev), &ctrl);
if (err) {
free(nm);
free(raw);
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]);
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",
dev->name, 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,
*(uint16_t *)raw, *(uint16_t *)(raw+2), *(uint16_t *)(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%% %"PRIu32"\n", *nm, *(uint32_t *)raw);
/* 08 SI_VD_THERMAL_THROTTLE_STATUS */
get_ymtc_smart_info(smart, SI_VD_THERMAL_THROTTLE_STATUS, nm, raw);
printf("thermal_throttle_status : %3d%% %d%%, cnt: %"PRIu32"\n", *nm,
*raw, *(uint32_t *)(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,
*(uint16_t *)raw-273, *(uint16_t *)(raw+2)-273, *(int16_t *)(raw+4)-273);
/* 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,
*(uint16_t *)raw, *(uint16_t *)(raw+2), *(uint16_t *)(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,
*(uint16_t *)raw-273, *(uint16_t *)(raw+2)-273, *(uint16_t *)(raw+4)-273);
/* 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%% %u, time: %"PRIu32"\n", *nm,
*raw, *(uint32_t *)(raw+1));
/* 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));
/* Table Title */
printf("Additional Smart Log for NVME device:%s namespace-id:%x\n",
dev->name, 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,
*(uint16_t *)raw, *(uint16_t *)(raw+2), *(uint16_t *)(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%% %"PRIu32"\n", *nm, *(uint32_t *)raw);
/* 08 SI_VD_THERMAL_THROTTLE_STATUS */
get_ymtc_smart_info(smart, SI_VD_THERMAL_THROTTLE_STATUS, nm, raw);
printf("thermal_throttle_status : %3d%% %d%%, cnt: %"PRIu32"\n", *nm,
*raw, *(uint32_t *)(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,
*(uint16_t *)raw-273, *(uint16_t *)(raw+2)-273, *(int16_t *)(raw+4)-273);
/* 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,
*(uint16_t *)raw, *(uint16_t *)(raw+2), *(uint16_t *)(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,
*(uint16_t *)raw-273, *(uint16_t *)(raw+2)-273, *(uint16_t *)(raw+4)-273);
/* 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%% %u, time: %"PRIu32"\n", *nm,
*raw, *(uint32_t *)(raw+1));
/* 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);
free(nm);
free(raw);
return err;
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;
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 nvme_dev *dev;
struct config {
__u32 namespace_id;
bool raw_binary;
};
int err;
struct nvme_ymtc_smart_log smart_log;
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 nvme_dev *dev;
struct config {
__u32 namespace_id;
bool raw_binary;
};
int err;
struct config cfg = {
.namespace_id = NVME_NSID_ALL,
};
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()
};
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace),
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
OPT_END()
};
err = parse_and_open(&dev, argc, argv, desc, opts);
if (err)
return err;
err = parse_and_open(&dev, argc, argv, desc, opts);
if (err)
return err;
err = nvme_get_nsid_log(dev_fd(dev), false, 0xca, cfg.namespace_id,
sizeof(smart_log), &smart_log);
if (!err) {
if (!cfg.raw_binary)
err = show_ymtc_smart_log(dev, cfg.namespace_id, &smart_log);
else
d_raw((unsigned char *)&smart_log, sizeof(smart_log));
}
if (err > 0)
nvme_show_status(err);
err = nvme_get_nsid_log(dev_fd(dev), false, 0xca, cfg.namespace_id,
sizeof(smart_log), &smart_log);
if (!err) {
if (!cfg.raw_binary)
err = show_ymtc_smart_log(dev, cfg.namespace_id, &smart_log);
else
d_raw((unsigned char *)&smart_log, sizeof(smart_log));
}
if (err > 0)
nvme_show_status(err);
dev_close(dev);
return err;
dev_close(dev);
return err;
}

View file

@ -49,9 +49,8 @@ static int print_zns_list_ns(nvme_ns_t ns)
return err;
}
if (supported) {
if (supported)
nvme_show_list_item(ns);
}
return err;
}
@ -63,21 +62,17 @@ static int print_zns_list(nvme_root_t nvme_root)
nvme_subsystem_t s;
nvme_ctrl_t c;
nvme_ns_t n;
nvme_for_each_host(nvme_root, h)
{
nvme_for_each_subsystem(h, s)
{
nvme_subsystem_for_each_ns(s, n)
{
nvme_for_each_host(nvme_root, h) {
nvme_for_each_subsystem(h, s) {
nvme_subsystem_for_each_ns(s, n) {
err = print_zns_list_ns(n);
if (err)
return err;
}
nvme_subsystem_for_each_ctrl(s, c)
{
nvme_ctrl_for_each_ns(c, n)
{
nvme_subsystem_for_each_ctrl(s, c) {
nvme_ctrl_for_each_ns(c, n) {
err = print_zns_list_ns(n);
if (err)
return err;
@ -114,9 +109,9 @@ static int list(int argc, char **argv, struct command *cmd,
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.";
const char *desc = "Send a ZNS specific Identify Controller command to\n"
"the given device and report information about the specified\n"
"controller in various formats.";
enum nvme_print_flags flags;
struct nvme_zns_id_ctrl ctrl;
@ -158,9 +153,9 @@ close_fd:
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 *desc = "Send a ZNS specific Identify Namespace command to\n"
"the given device and report information about the specified\n"
"namespace in varios formats.";
const char *vendor_specific = "dump binary vendor fields";
const char *human_readable = "show identify in readable format";
@ -292,11 +287,11 @@ static int zns_mgmt_send(int argc, char **argv, struct command *cmd, struct plug
printf("%s: Success, action:%d zone:%"PRIx64" all:%d zcapc:%u nsid:%d\n",
command, zsa, (uint64_t)cfg.zslba, (int)cfg.select_all,
zcapc, cfg.namespace_id);
}
else if (err > 0)
} else if (err > 0) {
nvme_show_status(err);
else
} else {
perror(desc);
}
free:
free(command);
close_dev:
@ -337,8 +332,8 @@ static int get_zdes_bytes(int fd, __u32 nsid)
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"\
"(for flush action, last lba to flush)";
const char *zslba =
"starting LBA of the zone for this command(for flush action, last lba to flush)";
const char *zsaso = "Zone Send Action Specific Option";
const char *select_all = "send command to all zones";
const char *zsa = "zone send action";
@ -356,8 +351,8 @@ static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plu
bool zsaso;
bool select_all;
__u8 zsa;
int data_len;
char *file;
int data_len;
char *file;
__u32 timeout;
};
@ -394,13 +389,12 @@ static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plu
}
if (cfg.zsa == NVME_ZNS_ZSA_SET_DESC_EXT) {
if(!cfg.data_len) {
if (!cfg.data_len) {
int data_len = get_zdes_bytes(dev_fd(dev),
cfg.namespace_id);
if (data_len == 0) {
fprintf(stderr,
"Zone Descriptor Extensions are not supported\n");
fprintf(stderr, "Zone Descriptor Extensions are not supported\n");
goto close_dev;
} else if (data_len < 0) {
err = data_len;
@ -429,8 +423,7 @@ static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plu
}
} else {
if (cfg.file || cfg.data_len) {
fprintf(stderr,
"data, data_len only valid with set extended descriptor\n");
fprintf(stderr, "data, data_len only valid with set extended descriptor\n");
err = -EINVAL;
goto close_dev;
}
@ -451,10 +444,8 @@ static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plu
};
err = nvme_zns_mgmt_send(&args);
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);
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
@ -542,7 +533,7 @@ static int open_zone(int argc, char **argv, struct command *cmd, struct plugin *
err = nvme_zns_mgmt_send(&args);
if (!err)
printf("zns-open-zone: Success zone slba:%"PRIx64" nsid:%d\n",
(uint64_t)cfg.zslba, cfg.namespace_id);
(uint64_t)cfg.zslba, cfg.namespace_id);
else
nvme_show_status(err);
close_dev:
@ -656,7 +647,7 @@ static int set_zone_desc(int argc, char **argv, struct command *cmd, struct plug
err = nvme_zns_mgmt_send(&args);
if (!err)
printf("set-zone-desc: Success, zone:%"PRIx64" nsid:%d\n",
(uint64_t)cfg.zslba, cfg.namespace_id);
(uint64_t)cfg.zslba, cfg.namespace_id);
else if (err > 0)
nvme_show_status(err);
else
@ -723,7 +714,7 @@ static int zrwa_flush_zone(int argc, char **argv, struct command *cmd, struct pl
err = nvme_zns_mgmt_send(&args);
if (!err)
printf("zrwa-flush-zone: Success, lba:%"PRIx64" nsid:%d\n",
(uint64_t)cfg.lba, cfg.namespace_id);
(uint64_t)cfg.lba, cfg.namespace_id);
else
nvme_show_status(err);
close_dev:
@ -737,7 +728,7 @@ static int zone_mgmt_recv(int argc, char **argv, struct command *cmd, struct plu
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 *partial = "Zone Receive Action Specific Features(Partial Report)";
const char *data_len = "length of data in bytes";
enum nvme_print_flags flags;
@ -816,7 +807,7 @@ static int zone_mgmt_recv(int argc, char **argv, struct command *cmd, struct plu
err = nvme_zns_mgmt_recv(&args);
if (!err)
printf("zone-mgmt-recv: Success, action:%d zone:%"PRIx64" nsid:%d\n",
cfg.zra, (uint64_t)cfg.zslba, cfg.namespace_id);
cfg.zra, (uint64_t)cfg.zslba, cfg.namespace_id);
else if (err > 0)
nvme_show_status(err);
else
@ -921,9 +912,8 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi
if (!err) {
/* get zsze field from zns id ns data - needed for offset calculation */
nvme_id_ns_flbas_to_lbaf_inuse(id_ns.flbas, &lbaf);
zsze = le64_to_cpu(id_zns.lbafe[lbaf].zsze);
}
else {
zsze = le64_to_cpu(id_zns.lbafe[lbaf].zsze);
} else {
nvme_show_status(err);
goto close_dev;
}
@ -942,17 +932,15 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi
if (err > 0) {
nvme_show_status(err);
goto free_buff;
}
else if (err < 0) {
} else if (err < 0) {
perror("zns report-zones");
goto free_buff;
}
total_nr_zones = le64_to_cpu(buff->nr_zones);
if (cfg.num_descs == -1) {
if (cfg.num_descs == -1)
cfg.num_descs = total_nr_zones;
}
nr_zones = cfg.num_descs;
if (nr_zones < nr_zones_chunks)
@ -994,15 +982,20 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi
}
if (!err)
nvme_show_zns_report_zones(report, nr_zones_chunks,
zdes, log_len, flags, zone_list);
nvme_show_zns_report_zones(report, nr_zones_chunks,
zdes, log_len, zone_list, flags);
nr_zones_retrieved += nr_zones_chunks;
offset = le64_to_cpu(report->entries[nr_zones_chunks-1].zslba) + zsze;
}
}
if (flags & JSON)
json_nvme_finish_zone_list(total_nr_zones, zone_list);
if (flags & JSON) {
struct print_ops *ops;
ops = nvme_get_json_print_ops(flags);
if (ops)
ops->zns_finish_zone_list(total_nr_zones, zone_list);
}
nvme_free(report, huge);
@ -1015,9 +1008,9 @@ close_dev:
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 *desc = "The zone append command is used to write to a zone\n"
"using the slba of the zone, and the write will be appended from the\n"
"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";
@ -1116,7 +1109,7 @@ static int zone_append(int argc, char **argv, struct command *cmd, struct plugin
meta_size = ns.lbaf[lba_index].ms;
if (meta_size && !(meta_size == 8 && (cfg.prinfo & 0x8)) &&
(!cfg.metadata_size || cfg.metadata_size % meta_size)) {
(!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);
@ -1125,7 +1118,7 @@ static int zone_append(int argc, char **argv, struct command *cmd, struct plugin
}
if (cfg.prinfo > 0xf) {
fprintf(stderr, "Invalid value for prinfo:%#x\n", cfg.prinfo);
fprintf(stderr, "Invalid value for prinfo:%#x\n", cfg.prinfo);
errno = EINVAL;
goto close_dev;
}
@ -1208,7 +1201,7 @@ static int zone_append(int argc, char **argv, struct command *cmd, struct plugin
gettimeofday(&end_time, NULL);
if (cfg.latency)
printf(" latency: zone append: %llu us\n",
elapsed_utime(start_time, end_time));
elapsed_utime(start_time, end_time));
if (!err)
printf("Success appended data to LBA %"PRIx64"\n", (uint64_t)result);