summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2022-07-26 05:11:40 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2022-07-26 05:18:07 +0000
commit2e650c1f5f2f79e7db10dec5dcdd1cffcaf47891 (patch)
tree82f2949088d2502e947b83ba9973de54f9bf4402 /plugins
parentReleasing debian version 2.0-1. (diff)
downloadnvme-cli-2e650c1f5f2f79e7db10dec5dcdd1cffcaf47891.tar.xz
nvme-cli-2e650c1f5f2f79e7db10dec5dcdd1cffcaf47891.zip
Merging upstream version 2.1~rc0 (Closes: #1015722).
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'plugins')
-rw-r--r--plugins/amzn/amzn-nvme.c1
-rw-r--r--plugins/amzn/amzn-nvme.h1
-rw-r--r--plugins/dell/dell-nvme.c54
-rw-r--r--plugins/dell/dell-nvme.h18
-rw-r--r--plugins/dera/dera-nvme.c4
-rw-r--r--plugins/dera/dera-nvme.h1
-rw-r--r--plugins/huawei/huawei-nvme.c64
-rw-r--r--plugins/huawei/huawei-nvme.h1
-rw-r--r--plugins/innogrit/innogrit-nvme.c402
-rw-r--r--plugins/innogrit/innogrit-nvme.h20
-rw-r--r--plugins/innogrit/typedef.h72
-rw-r--r--plugins/intel/intel-nvme.c51
-rw-r--r--plugins/intel/intel-nvme.h1
-rw-r--r--plugins/memblaze/memblaze-nvme.c97
-rw-r--r--plugins/memblaze/memblaze-nvme.h1
-rw-r--r--plugins/memblaze/memblaze-utils.h37
-rw-r--r--plugins/meson.build6
-rw-r--r--plugins/micron/micron-nvme.c593
-rw-r--r--plugins/micron/micron-nvme.h1
-rw-r--r--plugins/netapp/netapp-nvme.c38
-rw-r--r--plugins/netapp/netapp-nvme.h1
-rw-r--r--plugins/nvidia/nvidia-nvme.c1
-rw-r--r--plugins/nvidia/nvidia-nvme.h1
-rw-r--r--plugins/ocp/ocp-nvme.c18
-rw-r--r--plugins/ocp/ocp-nvme.h2
-rw-r--r--plugins/scaleflux/sfx-nvme.c328
-rw-r--r--plugins/scaleflux/sfx-nvme.h1
-rw-r--r--plugins/seagate/seagate-diag.h1
-rw-r--r--plugins/seagate/seagate-nvme.c85
-rw-r--r--plugins/seagate/seagate-nvme.h1
-rw-r--r--plugins/shannon/shannon-nvme.c6
-rw-r--r--plugins/shannon/shannon-nvme.h1
-rw-r--r--plugins/solidigm/meson.build5
-rw-r--r--plugins/solidigm/solidigm-garbage-collection.c111
-rw-r--r--plugins/solidigm/solidigm-garbage-collection.h8
-rw-r--r--plugins/solidigm/solidigm-latency-tracking.c470
-rw-r--r--plugins/solidigm/solidigm-latency-tracking.h9
-rw-r--r--plugins/solidigm/solidigm-nvme.c30
-rw-r--r--plugins/solidigm/solidigm-nvme.h28
-rw-r--r--plugins/solidigm/solidigm-smart.c250
-rw-r--r--plugins/solidigm/solidigm-smart.h8
-rw-r--r--plugins/toshiba/toshiba-nvme.c5
-rw-r--r--plugins/toshiba/toshiba-nvme.h1
-rw-r--r--plugins/transcend/transcend-nvme.c5
-rw-r--r--plugins/transcend/transcend-nvme.h1
-rw-r--r--plugins/virtium/virtium-nvme.c37
-rw-r--r--plugins/virtium/virtium-nvme.h1
-rw-r--r--plugins/wdc/wdc-nvme.c1894
-rw-r--r--plugins/wdc/wdc-nvme.h7
-rw-r--r--plugins/wdc/wdc-utils.c1
-rw-r--r--plugins/wdc/wdc-utils.h1
-rw-r--r--plugins/ymtc/ymtc-nvme.c35
-rw-r--r--plugins/ymtc/ymtc-nvme.h1
-rw-r--r--plugins/ymtc/ymtc-utils.h1
-rw-r--r--plugins/zns/zns.c16
-rw-r--r--plugins/zns/zns.h1
56 files changed, 4286 insertions, 549 deletions
diff --git a/plugins/amzn/amzn-nvme.c b/plugins/amzn/amzn-nvme.c
index cd7d555..e04aa53 100644
--- a/plugins/amzn/amzn-nvme.c
+++ b/plugins/amzn/amzn-nvme.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
diff --git a/plugins/amzn/amzn-nvme.h b/plugins/amzn/amzn-nvme.h
index f969c0e..f6c4f8b 100644
--- a/plugins/amzn/amzn-nvme.h
+++ b/plugins/amzn/amzn-nvme.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#undef CMD_INC_FILE
#define CMD_INC_FILE plugins/amzn/amzn-nvme
diff --git a/plugins/dell/dell-nvme.c b/plugins/dell/dell-nvme.c
new file mode 100644
index 0000000..8ed10e7
--- /dev/null
+++ b/plugins/dell/dell-nvme.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright © 2022 Dell Inc. or its subsidiaries. All Rights Reserved.
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+
+#define CREATE_CMD
+#include "dell-nvme.h"
+
+#define ARRAY_NAME_LEN 80
+
+struct nvme_vu_id_ctrl_field {
+ __u16 dell_mjr;
+ __u16 dell_mnr;
+ __u16 dell_ter;
+ __u8 reserved0[1018];
+};
+
+static void dell_id_ctrl(__u8 *vs, struct json_object *root)
+{
+ struct nvme_vu_id_ctrl_field *id = (struct nvme_vu_id_ctrl_field *)vs;
+ char array_ver[16] = { 0 };
+ char array_name[ARRAY_NAME_LEN + 1] = {0};
+
+ snprintf(array_ver, sizeof(array_ver), "0x%04x%04x%04x",
+ le16_to_cpu(id->dell_mjr),
+ le16_to_cpu(id->dell_mnr),
+ le16_to_cpu(id->dell_ter));
+
+ memcpy(array_name, vs + sizeof(array_ver), ARRAY_NAME_LEN);
+
+ if (root) {
+ json_object_add_value_string(root, "array_name", strlen(array_name) > 1 ? array_name : "NULL");
+ json_object_add_value_string(root, "array_ver", array_ver);
+ return;
+ }
+
+ printf("array_name : %s\n", strlen(array_name) > 1 ? array_name : "NULL");
+ printf("array_ver : %s\n", array_ver);
+}
+
+static int id_ctrl(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ return __id_ctrl(argc, argv, cmd, plugin, dell_id_ctrl);
+}
diff --git a/plugins/dell/dell-nvme.h b/plugins/dell/dell-nvme.h
new file mode 100644
index 0000000..aaf0de1
--- /dev/null
+++ b/plugins/dell/dell-nvme.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/dell/dell-nvme
+
+#if !defined(DELL_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define DELL_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("dell", "DELL vendor specific extensions", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/dera/dera-nvme.c b/plugins/dera/dera-nvme.c
index f36fc67..1390be0 100644
--- a/plugins/dera/dera-nvme.c
+++ b/plugins/dera/dera-nvme.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
@@ -186,7 +187,7 @@ 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{
@@ -204,6 +205,7 @@ exit:
if (err > 0)
nvme_show_status(err);
+ close(fd);
return err;
}
diff --git a/plugins/dera/dera-nvme.h b/plugins/dera/dera-nvme.h
index d3a8b0b..a5bb0ae 100644
--- a/plugins/dera/dera-nvme.h
+++ b/plugins/dera/dera-nvme.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#undef CMD_INC_FILE
#define CMD_INC_FILE plugins/dera/dera-nvme
diff --git a/plugins/huawei/huawei-nvme.c b/plugins/huawei/huawei-nvme.c
index 116025b..572086c 100644
--- a/plugins/huawei/huawei-nvme.c
+++ b/plugins/huawei/huawei-nvme.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2017-2019 Huawei Corporation or its affiliates.
*
@@ -92,7 +93,8 @@ static int huawei_get_nvme_info(int fd, struct huawei_list_item *item, const cha
if (err < 0)
return err;
- strcpy(item->node, node);
+ strncpy(item->node, node, sizeof(item->node));
+ item->node[sizeof(item->node) - 1] = '\0';
item->block = S_ISBLK(nvme_stat_info.st_mode);
if (item->ns.vs[0] == 0) {
@@ -204,20 +206,20 @@ static void huawei_print_list_head(struct huawei_list_element_len element_len)
element_len.usage, dash, element_len.array_name, dash);
}
-static void huawei_print_list_item(struct huawei_list_item list_item,
- struct huawei_list_element_len element_len)
+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);
- long long int lba = 1 << 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;
+ 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;
+ double nsze = le64_to_cpu(list_item->ns.nsze) * lba;
+ double nuse = le64_to_cpu(list_item->ns.nuse) * lba;
const char *s_suffix = suffix_si_get(&nsze);
const char *u_suffix = suffix_si_get(&nuse);
char usage[128];
- char nguid_buf[2 * sizeof(list_item.ns.nguid) + 1];
+ char nguid_buf[2 * sizeof(list_item->ns.nguid) + 1];
char *nguid = nguid_buf;
int i;
@@ -225,16 +227,17 @@ static void huawei_print_list_item(struct huawei_list_item list_item,
nsze, s_suffix);
memset(nguid, 0, sizeof(nguid_buf));
- for (i = 0; i < sizeof(list_item.ns.nguid); i++)
- nguid += sprintf(nguid, "%02x", list_item.ns.nguid[i]);
+ for (i = 0; i < sizeof(list_item->ns.nguid); i++)
+ nguid += sprintf(nguid, "%02x", list_item->ns.nguid[i]);
printf("%-*.*s %-*.*s %-*.*s %-*d %-*.*s %-*.*s\n",
- element_len.node, element_len.node, list_item.node,
- element_len.ns_name, element_len.ns_name, list_item.ns_name,
+ element_len.node, element_len.node, list_item->node,
+ element_len.ns_name, element_len.ns_name, list_item->ns_name,
element_len.nguid, element_len.nguid, nguid_buf,
- element_len.ns_id, list_item.nsid,
+ element_len.ns_id, list_item->nsid,
element_len.usage, element_len.usage, usage,
- element_len.array_name, element_len.array_name, list_item.array_name);
+ element_len.array_name, element_len.array_name,
+ list_item->array_name);
}
@@ -287,7 +290,7 @@ static void huawei_print_list_items(struct huawei_list_item *list_items, unsigne
huawei_print_list_head(element_len);
for (i = 0 ; i < len ; i++)
- huawei_print_list_item(list_items[i], element_len);
+ huawei_print_list_item(&list_items[i], element_len);
}
static int huawei_list(int argc, char **argv, struct command *command,
@@ -296,7 +299,7 @@ static int huawei_list(int argc, char **argv, struct command *command,
char path[264];
struct dirent **devices;
struct huawei_list_item *list_items;
- unsigned int i, n, fd, ret;
+ unsigned int i, n, ret;
unsigned int huawei_num = 0;
int fmt;
const char *desc = "Retrieve basic information for the given huawei device";
@@ -313,7 +316,10 @@ static int huawei_list(int argc, char **argv, struct command *command,
OPT_END()
};
- argconfig_parse(argc, argv, desc, opts);
+ ret = argconfig_parse(argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
fmt = validate_output_format(cfg.output_format);
if (fmt != JSON && fmt != NORMAL)
return -EINVAL;
@@ -325,18 +331,29 @@ static int huawei_list(int argc, char **argv, struct command *command,
list_items = calloc(n, sizeof(*list_items));
if (!list_items) {
fprintf(stderr, "can not allocate controller list payload\n");
- return ENOMEM;
+ ret = ENOMEM;
+ goto out_free_devices;
}
for (i = 0; i < n; i++) {
+ int fd;
+
snprintf(path, sizeof(path), "/dev/%s", devices[i]->d_name);
fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Cannot open device %s: %s\n",
+ path, strerror(errno));
+ continue;
+ }
ret = huawei_get_nvme_info(fd, &list_items[huawei_num], path);
- if (ret)
- return ret;
+ if (ret) {
+ close(fd);
+ goto out_free_list_items;
+ }
if (list_items[huawei_num].huawei_device == true) {
huawei_num++;
}
+ close(fd);
}
if (huawei_num > 0){
@@ -345,13 +362,14 @@ static int huawei_list(int argc, char **argv, struct command *command,
else
huawei_print_list_items(list_items, huawei_num);
}
-
+out_free_list_items:
+ free(list_items);
+out_free_devices:
for (i = 0; i < n; i++)
free(devices[i]);
free(devices);
- free(list_items);
- return 0;
+ return ret;
}
static void huawei_do_id_ctrl(__u8 *vs, struct json_object *root)
diff --git a/plugins/huawei/huawei-nvme.h b/plugins/huawei/huawei-nvme.h
index 175ddd5..f49e6fd 100644
--- a/plugins/huawei/huawei-nvme.h
+++ b/plugins/huawei/huawei-nvme.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#undef CMD_INC_FILE
#define CMD_INC_FILE plugins/huawei/huawei-nvme
diff --git a/plugins/innogrit/innogrit-nvme.c b/plugins/innogrit/innogrit-nvme.c
new file mode 100644
index 0000000..214fe72
--- /dev/null
+++ b/plugins/innogrit/innogrit-nvme.c
@@ -0,0 +1,402 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "nvme-print.h"
+#include "typedef.h"
+
+#define CREATE_CMD
+#include "innogrit-nvme.h"
+
+static int innogrit_smart_log_additional(int argc, char **argv,
+ struct command *command,
+ struct plugin *plugin)
+{
+ struct nvme_smart_log smart_log = { 0 };
+ int fd, i, iindex;
+ struct vsc_smart_log *pvsc_smart = (struct vsc_smart_log *)smart_log.rsvd232;
+ const char *desc = "Retrieve additional SMART log for the given device ";
+ const char *namespace = "(optional) desired namespace";
+
+ struct config {
+ __u32 namespace_id;
+ };
+
+ struct config cfg = {
+ .namespace_id = NVME_NSID_ALL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ nvme_get_log_smart(fd, cfg.namespace_id, true, &smart_log);
+ nvme_show_smart_log(&smart_log, cfg.namespace_id, devicename, NORMAL);
+
+ printf("DW0[0-1] Defect Cnt : %u\n", pvsc_smart->defect_cnt);
+ printf("DW0[2-3] Slc Spb Cnt : %u\n", pvsc_smart->slc_spb_cnt);
+ printf("DW1 Slc Total Ec Cnt : %u\n", pvsc_smart->slc_total_ec_cnt);
+ printf("DW2 Slc Max Ec Cnt : %u\n", pvsc_smart->slc_max_ec_cnt);
+ printf("DW3 Slc Min Ec Cnt : %u\n", pvsc_smart->slc_min_ec_cnt);
+ printf("DW4 Slc Avg Ec Cnt : %u\n", pvsc_smart->slc_avg_ec_cnt);
+ printf("DW5 Total Ec Cnt : %u\n", pvsc_smart->total_ec_cnt);
+ printf("DW6 Max Ec Cnt : %u\n", pvsc_smart->max_ec_cnt);
+ printf("DW7 Min Ec Cnt : %u\n", pvsc_smart->min_ec_cnt);
+ printf("DW8 Avg Ec Cnt : %u\n", pvsc_smart->avg_ec_cnt);
+ printf("DW9 Mrd Rr Good Cnt : %u\n", pvsc_smart->mrd_rr_good_cnt);
+ printf("DW10 Ard Rr Good Cnt : %u\n", pvsc_smart->ard_rr_good_cnt);
+ printf("DW11 Preset Cnt : %u\n", pvsc_smart->preset_cnt);
+ printf("DW12 Nvme Reset Cnt : %u\n", pvsc_smart->nvme_reset_cnt);
+ printf("DW13 Low Pwr Cnt : %u\n", pvsc_smart->low_pwr_cnt);
+ printf("DW14 Wa : %u\n", pvsc_smart->wa);
+ printf("DW15 Ps3 Entry Cnt : %u\n", pvsc_smart->ps3_entry_cnt);
+ printf("DW16[0] highest_temp[0] : %u\n", pvsc_smart->highest_temp[0]);
+ printf("DW16[1] highest_temp[1] : %u\n", pvsc_smart->highest_temp[1]);
+ printf("DW16[2] highest_temp[2] : %u\n", pvsc_smart->highest_temp[2]);
+ printf("DW16[3] highest_temp[3] : %u\n", pvsc_smart->highest_temp[3]);
+ printf("DW17 weight_ec : %u\n", pvsc_smart->weight_ec);
+ printf("DW18 slc_cap_mb : %u\n", pvsc_smart->slc_cap_mb);
+ printf("DW19-20 nand_page_write_cnt : %llu\n", pvsc_smart->nand_page_write_cnt);
+
+ iindex = 21;
+ for (i = 0; i < (sizeof(pvsc_smart->reserved2)/4); i++) {
+ if (pvsc_smart->reserved2[i] != 0)
+ printf("DW%-37d : %u\n", iindex, pvsc_smart->reserved2[i]);
+ iindex++;
+ }
+
+ return 0;
+}
+
+static int sort_eventlog_fn(const void *a, const void *b)
+{
+ const struct eventlog_addindex *l = a;
+ const struct eventlog_addindex *r = b;
+ int rc;
+
+ if (l->ms > r->ms) {
+ rc = 1;
+ } else if (l->ms < r->ms) {
+ rc = -1;
+ } else {
+ if (l->iindex < r->iindex)
+ rc = -1;
+ else
+ rc = 1;
+ }
+
+ return rc;
+}
+
+static void sort_eventlog(struct eventlog *data16ksrc, unsigned int icount)
+{
+ struct eventlog_addindex peventlogadd[512];
+ unsigned int i;
+
+ for (i = 0; i < icount; i++) {
+ memcpy(&peventlogadd[i], &data16ksrc[i], sizeof(struct eventlog));
+ peventlogadd[i].iindex = i;
+ }
+
+ qsort(peventlogadd, icount, sizeof(struct eventlog_addindex), sort_eventlog_fn);
+
+ for (i = 0; i < icount; i++)
+ memcpy(&data16ksrc[i], &peventlogadd[i], sizeof(struct eventlog));
+}
+
+static unsigned char setfilecontent(char *filenamea, unsigned char *buffer,
+ unsigned int buffersize)
+{
+ FILE *fp = NULL;
+ int rc;
+
+ if (buffersize == 0)
+ return true;
+ fp = fopen(filenamea, "a+");
+ rc = fwrite(buffer, 1, buffersize, fp);
+ fclose(fp);
+ if (rc != buffersize)
+ return false;
+ return true;
+}
+
+static int nvme_vucmd(int fd, unsigned char opcode, unsigned int cdw12,
+ unsigned int cdw13, unsigned int cdw14,
+ unsigned int cdw15, char *data, int data_len)
+{
+ struct nvme_passthru_cmd cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opcode = opcode;
+ cmd.cdw12 = cdw12;
+ cmd.cdw13 = cdw13;
+ cmd.cdw14 = cdw14;
+ cmd.cdw15 = cdw15;
+ cmd.nsid = 0;
+ cmd.addr = (__u64)(__u64)(uintptr_t)data;
+ cmd.data_len = data_len;
+ return nvme_submit_admin_passthru(fd, &cmd, NULL);
+}
+
+static int innogrit_vsc_geteventlog(int argc, char **argv,
+ struct command *command,
+ struct plugin *plugin)
+{
+ time_t timep;
+ struct tm *logtime;
+ int icount, ioffset16k, iblock;
+ char currentdir[128], filename[512];
+ unsigned char data[4096], data16k[SIZE_16K], zerob[32];
+ unsigned int *pcheckdata;
+ unsigned int isize, icheck_stopvalue, iend;
+ unsigned char bSortLog = false, bget_nextlog = true;
+ struct evlg_flush_hdr *pevlog = (struct evlg_flush_hdr *)data;
+ int fd, ret = -1;
+ const char *desc = "Recrieve event log for the given device ";
+ const char *clean_opt = "(optional) 1 for clean event log";
+
+ struct config {
+ __u32 clean_flg;
+ };
+
+ struct config cfg = {
+ .clean_flg = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("clean_flg", 'c', &cfg.clean_flg, clean_opt),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+
+ if (getcwd(currentdir, 128) == NULL)
+ return -1;
+
+ time(&timep);
+ logtime = localtime(&timep);
+ sprintf(filename, "%s/eventlog_%02d%02d-%02d%02d%02d.elog", currentdir, logtime->tm_mon+1,
+ logtime->tm_mday, logtime->tm_hour, logtime->tm_min, logtime->tm_sec);
+
+ iblock = 0;
+ ioffset16k = 0;
+ memset(data16k, 0, SIZE_16K);
+ memset(zerob, 0, 32);
+
+ icount = 0;
+ while (bget_nextlog) {
+ if (icount % 100 == 0) {
+ printf("\rWait for Dump EventLog " XCLEAN_LINE);
+ fflush(stdout);
+ icount = 0;
+ } else if (icount % 5 == 0) {
+ printf(".");
+ fflush(stdout);
+ }
+ icount++;
+
+ memset(data, 0, 4096);
+ ret = nvme_vucmd(fd, NVME_VSC_GET_EVENT_LOG, 0, 0, (SRB_SIGNATURE >> 32),
+ (SRB_SIGNATURE & 0xFFFFFFFF), (char *)data, 4096);
+ if (ret == -1)
+ return ret;
+
+ pcheckdata = (unsigned int *)&data[4096 - 32];
+ icheck_stopvalue = pcheckdata[1];
+
+ if (icheck_stopvalue == 0xFFFFFFFF) {
+ isize = pcheckdata[0];
+ if (isize == 0) {
+ /* Finish Log */
+ bget_nextlog = false;
+ } else if (bSortLog) {
+ /* No Full 4K Package */
+ for (iend = 0; iend < isize - 32; iend += sizeof(struct eventlog)) {
+ if (memcmp(&data[iend], zerob, sizeof(struct eventlog)) != 0) {
+ memcpy(&data16k[ioffset16k], &data[iend], sizeof(struct eventlog));
+ ioffset16k += sizeof(struct eventlog);
+ }
+ }
+ } else {
+ setfilecontent(filename, data, isize);
+ }
+ } else {
+ /* Full 4K Package */
+ if ((pevlog->signature == EVLOG_SIG) && (pevlog->log_type == 1))
+ bSortLog = true;
+
+ if (bSortLog) {
+ for (iend = 0; iend < SIZE_4K; iend += sizeof(struct eventlog)) {
+ if (memcmp(&data[iend], zerob, sizeof(struct eventlog)) != 0) {
+ memcpy(&data16k[ioffset16k], &data[iend], sizeof(struct eventlog));
+ ioffset16k += sizeof(struct eventlog);
+ }
+ }
+
+ iblock++;
+ if (iblock == 4) {
+ sort_eventlog((struct eventlog *)(data16k + sizeof(struct evlg_flush_hdr)),
+ (ioffset16k - sizeof(struct evlg_flush_hdr))/sizeof(struct eventlog));
+ setfilecontent(filename, data16k, ioffset16k);
+ ioffset16k = 0;
+ iblock = 0;
+ memset(data16k, 0, SIZE_16K);
+ }
+ } else {
+ setfilecontent(filename, data, SIZE_4K);
+ }
+
+ }
+ }
+
+ if (bSortLog) {
+ if (ioffset16k > 0) {
+ sort_eventlog((struct eventlog *)(data16k + sizeof(struct evlg_flush_hdr)),
+ (ioffset16k - sizeof(struct evlg_flush_hdr))/sizeof(struct eventlog));
+ setfilecontent(filename, data16k, ioffset16k);
+ }
+ }
+
+ printf("\r" XCLEAN_LINE "Dump eventLog finish to %s\n", filename);
+ chmod(filename, 0666);
+
+ if (cfg.clean_flg == 1) {
+ printf("Clean eventlog\n");
+ nvme_vucmd(fd, NVME_VSC_CLEAN_EVENT_LOG, 0, 0, (SRB_SIGNATURE >> 32),
+ (SRB_SIGNATURE & 0xFFFFFFFF), (char *)NULL, 0);
+ }
+
+ return ret;
+}
+
+static int innogrit_vsc_getcdump(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ time_t timep;
+ struct tm *logtime;
+ char currentdir[128], filename[512], fname[128];
+ unsigned int itotal, icur;
+ unsigned char data[4096];
+ struct cdumpinfo cdumpinfo;
+ unsigned char busevsc = false;
+ unsigned int ipackcount, ipackindex;
+ char fwvera[32];
+ int fd, ret = -1;
+ const char *desc = "Recrieve cdump data for the given device ";
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ if (getcwd(currentdir, 128) == NULL)
+ return -1;
+
+ time(&timep);
+ logtime = localtime(&timep);
+
+ ipackindex = 0;
+ memset(data, 0, 4096);
+ if (nvme_vucmd(fd, NVME_VSC_GET, VSC_FN_GET_CDUMP, 0x00, (SRB_SIGNATURE >> 32),
+ (SRB_SIGNATURE & 0xFFFFFFFF), (char *)data, 4096) == 0) {
+ memcpy(&cdumpinfo, &data[3072], sizeof(cdumpinfo));
+ if (cdumpinfo.sig == 0x5a5b5c5d) {
+ busevsc = true;
+ ipackcount = cdumpinfo.ipackcount;
+ if (ipackcount == 0) {
+ itotal = 0;
+ } else {
+ itotal = cdumpinfo.cdumppack[ipackindex].ilenth;
+ memset(fwvera, 0, sizeof(fwvera));
+ memcpy(fwvera, cdumpinfo.cdumppack[ipackindex].fwver, 8);
+ sprintf(fname, "cdump_%02d%02d-%02d%02d%02d_%d_%s.cdp", logtime->tm_mon+1,
+ logtime->tm_mday, logtime->tm_hour, logtime->tm_min, logtime->tm_sec,
+ ipackindex, fwvera);
+ sprintf(filename, "%s/%s", currentdir, fname);
+ }
+ }
+ }
+
+ if (busevsc == false) {
+ memset(data, 0, 4096);
+ ret = nvme_get_nsid_log(fd, true, 0x07, NVME_NSID_ALL, 4096, data);
+ if (ret != 0)
+ return ret;
+
+ ipackcount = 1;
+ memcpy(&itotal, &data[4092], 4);
+ sprintf(fname, "cdump_%02d%02d-%02d%02d%02d.cdp", logtime->tm_mon+1, logtime->tm_mday,
+ logtime->tm_hour, logtime->tm_min, logtime->tm_sec);
+ sprintf(filename, "%s/%s", currentdir, fname);
+ }
+
+ if (itotal == 0) {
+ printf("no cdump data\n");
+ return 0;
+ }
+
+ while (ipackindex < ipackcount) {
+ memset(data, 0, 4096);
+ strcpy((char *)data, "cdumpstart");
+ setfilecontent(filename, data, strlen((char *)data));
+ for (icur = 0; icur < itotal; icur += 4096) {
+ memset(data, 0, 4096);
+ if (busevsc)
+ ret = nvme_vucmd(fd, NVME_VSC_GET, VSC_FN_GET_CDUMP, 0x00, (SRB_SIGNATURE >> 32),
+ (SRB_SIGNATURE & 0xFFFFFFFF), (char *)data, 4096);
+ else
+ ret = nvme_get_nsid_log(fd, true, 0x07, NVME_NSID_ALL, 4096, data);
+ if (ret != 0)
+ return ret;
+
+ setfilecontent(filename, data, 4096);
+
+ printf("\rWait for dump data %d%%" XCLEAN_LINE, ((icur+4096) * 100/itotal));
+ }
+ memset(data, 0, 4096);
+ strcpy((char *)data, "cdumpend");
+ setfilecontent(filename, data, strlen((char *)data));
+ printf("\r%s\n", fname);
+ ipackindex++;
+ if (ipackindex != ipackcount) {
+ memset(data, 0, 4096);
+ if (busevsc)
+ ret = nvme_vucmd(fd, NVME_VSC_GET, VSC_FN_GET_CDUMP, 0x00, (SRB_SIGNATURE >> 32),
+ (SRB_SIGNATURE & 0xFFFFFFFF), (char *)data, 4096);
+ else
+ ret = nvme_get_nsid_log(fd, true, 0x07, NVME_NSID_ALL, 4096, data);
+ if (ret != 0)
+ return ret;
+
+ itotal = cdumpinfo.cdumppack[ipackindex].ilenth;
+ memset(fwvera, 0, sizeof(fwvera));
+ memcpy(fwvera, cdumpinfo.cdumppack[ipackindex].fwver, 8);
+ sprintf(fname, "cdump_%02d%02d-%02d%02d%02d_%d_%s.cdp", logtime->tm_mon+1,
+ logtime->tm_mday, logtime->tm_hour, logtime->tm_min, logtime->tm_sec,
+ ipackindex, fwvera);
+ sprintf(filename, "%s/%s", currentdir, fname);
+ }
+
+ }
+
+ printf("\n");
+ return ret;
+}
diff --git a/plugins/innogrit/innogrit-nvme.h b/plugins/innogrit/innogrit-nvme.h
new file mode 100644
index 0000000..2de0502
--- /dev/null
+++ b/plugins/innogrit/innogrit-nvme.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/innogrit/innogrit-nvme
+
+#if !defined(INNOGRIT_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define INNOGRIT_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("innogrit", "innogrit vendor specific extensions", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("smart-log-add", "Retrieve innogrit SMART Log, show it", innogrit_smart_log_additional)
+ ENTRY("get-eventlog", "get event log", innogrit_vsc_geteventlog)
+ ENTRY("get-cdump", "get cdump data", innogrit_vsc_getcdump)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/innogrit/typedef.h b/plugins/innogrit/typedef.h
new file mode 100644
index 0000000..d4ea269
--- /dev/null
+++ b/plugins/innogrit/typedef.h
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#define SIZE_4K 4096
+#define SIZE_16K 16384
+
+#define NVME_VSC_GET_EVENT_LOG 0xC2
+#define NVME_VSC_CLEAN_EVENT_LOG 0xD8
+#define NVME_VSC_GET 0xE6
+#define VSC_FN_GET_CDUMP 0x08
+#define EVLOG_SIG 0x65766C67
+#define SRB_SIGNATURE 0x544952474F4E4E49ULL
+#define XCLEAN_LINE "\033[K"
+
+struct evlg_flush_hdr {
+ unsigned int signature;
+ unsigned int fw_ver[2];
+ unsigned int fw_type : 8;
+ unsigned int log_type : 8;
+ unsigned int project : 16;
+ unsigned int trace_cnt;
+ unsigned int sout_crc;
+ unsigned int reserved[2];
+};
+
+struct eventlog {
+ unsigned int ms;
+ unsigned int param[7];
+};
+
+struct eventlog_addindex {
+ unsigned int ms;
+ unsigned int param[7];
+ unsigned int iindex;
+};
+
+#pragma pack(push)
+#pragma pack(1)
+struct vsc_smart_log {
+ unsigned short defect_cnt;
+ unsigned short slc_spb_cnt;
+ unsigned int slc_total_ec_cnt;
+ unsigned int slc_max_ec_cnt;
+ unsigned int slc_min_ec_cnt;
+ unsigned int slc_avg_ec_cnt;
+ unsigned int total_ec_cnt;
+ unsigned int max_ec_cnt;
+ unsigned int min_ec_cnt;
+ unsigned int avg_ec_cnt;
+ unsigned int mrd_rr_good_cnt;
+ unsigned int ard_rr_good_cnt;
+ unsigned int preset_cnt;
+ unsigned int nvme_reset_cnt;
+ unsigned int low_pwr_cnt;
+ unsigned int wa;
+ unsigned int ps3_entry_cnt;
+ u_char highest_temp[4];
+ unsigned int weight_ec;
+ unsigned int slc_cap_mb;
+ unsigned long long nand_page_write_cnt;
+ unsigned int reserved2[49];
+};
+#pragma pack(pop)
+
+struct cdump_pack {
+ unsigned int ilenth;
+ char fwver[8];
+};
+
+struct cdumpinfo {
+ unsigned int sig;
+ unsigned int ipackcount;
+ struct cdump_pack cdumppack[32];
+};
diff --git a/plugins/intel/intel-nvme.c b/plugins/intel/intel-nvme.c
index 80d218c..1bf6627 100644
--- a/plugins/intel/intel-nvme.c
+++ b/plugins/intel/intel-nvme.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
@@ -179,7 +180,7 @@ 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->timed_workload_media_wear.norm);
- json_object_add_value_float(entry_stats, "raw", ((long double)int48_to_long(smart->timed_workload_media_wear.raw)) / 1024);
+ json_object_add_value_double(entry_stats, "raw", ((long double)int48_to_long(smart->timed_workload_media_wear.raw)) / 1024);
json_object_add_value_object(dev_stats, "timed_workload_media_wear", entry_stats);
entry_stats = json_create_object();
@@ -377,6 +378,7 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
}
else if (err > 0)
nvme_show_status(err);
+ close(fd);
return err;
}
@@ -412,6 +414,7 @@ static int get_market_log(int argc, char **argv, struct command *cmd, struct plu
d_raw((unsigned char *)&log, sizeof(log));
} else if (err > 0)
nvme_show_status(err);
+ close(fd);
return err;
}
@@ -472,6 +475,7 @@ static int get_temp_stats_log(int argc, char **argv, struct command *cmd, struct
d_raw((unsigned char *)&stats, sizeof(stats));
} else if (err > 0)
nvme_show_status(err);
+ close(fd);
return err;
}
@@ -1105,21 +1109,19 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct
sizeof(struct intel_lat_stats));
}
- if (!err) {
- if (cfg.json)
- json_lat_stats(cfg.write);
- else if (!cfg.raw_binary)
- show_lat_stats(cfg.write);
- else {
- if (media_version[0] == 1000)
- d_raw((unsigned char *)&v1000_stats,
- sizeof(v1000_stats));
- else
- d_raw((unsigned char *)&stats,
- sizeof(stats));
- }
- } else if (err > 0)
- nvme_show_status(err);
+ if (cfg.json)
+ json_lat_stats(cfg.write);
+ else if (!cfg.raw_binary)
+ show_lat_stats(cfg.write);
+ else {
+ if (media_version[0] == 1000)
+ d_raw((unsigned char *)&v1000_stats,
+ sizeof(v1000_stats));
+ else
+ d_raw((unsigned char *)&stats,
+ sizeof(stats));
+ }
+
close_fd:
close(fd);
return err;
@@ -1385,14 +1387,14 @@ static int get_internal_log(int argc, char **argv, struct command *command,
}
if (cfg.log > 2 || cfg.core > 4 || cfg.lnum > 255) {
- free(intel);
- return EINVAL;
+ err = -EINVAL;
+ goto out_free;
}
if (!cfg.file) {
err = setup_file(f, cfg.file, fd, cfg.log);
if (err)
- goto out;
+ goto out_free;
cfg.file = f;
}
@@ -1403,6 +1405,10 @@ static int get_internal_log(int argc, char **argv, struct command *command,
cdlog.u.fields.selectNlog = cfg.lnum < 0 ? 0 : cfg.lnum;
output = open(cfg.file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (output < 0) {
+ err = output;
+ goto out_free;
+ }
err = read_header(&cmd, buf, fd, cdlog.u.entireDword, cfg.namespace_id);
if (err)
@@ -1494,7 +1500,7 @@ static int get_internal_log(int argc, char **argv, struct command *command,
}
}
err = 0;
- out:
+out:
if (err > 0) {
nvme_show_status(err);
} else if (err < 0) {
@@ -1502,7 +1508,10 @@ static int get_internal_log(int argc, char **argv, struct command *command,
err = EIO;
} else
printf("Successfully wrote log to %s\n", cfg.file);
+ close(output);
+out_free:
free(intel);
+ close(fd);
return err;
}
@@ -1597,6 +1606,7 @@ static int enable_lat_stats_tracking(int argc, char **argv,
fid, result);
} else {
printf("Could not read feature id 0xE2.\n");
+ close(fd);
return err;
}
break;
@@ -1617,6 +1627,7 @@ static int enable_lat_stats_tracking(int argc, char **argv,
printf("%d not supported.\n", option);
return EINVAL;
}
+ close(fd);
return fd;
}
diff --git a/plugins/intel/intel-nvme.h b/plugins/intel/intel-nvme.h
index af1231a..165048a 100644
--- a/plugins/intel/intel-nvme.h
+++ b/plugins/intel/intel-nvme.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#undef CMD_INC_FILE
#define CMD_INC_FILE plugins/intel/intel-nvme
diff --git a/plugins/memblaze/memblaze-nvme.c b/plugins/memblaze/memblaze-nvme.c
index c0f4d66..a6a8ddf 100644
--- a/plugins/memblaze/memblaze-nvme.c
+++ b/plugins/memblaze/memblaze-nvme.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
@@ -161,6 +162,15 @@ static void show_memblaze_smart_log_new(struct nvme_memblaze_smart_log *s,
u8 *nm = malloc(NM_SIZE * sizeof(u8));
u8 *raw = malloc(RAW_SIZE * sizeof(u8));
+ if (!nm) {
+ if (raw)
+ free(raw);
+ return;
+ }
+ if (!raw) {
+ free(nm);
+ return;
+ }
/* Table Title */
printf("%s:%s %s:%x\n", STRN2_01, devname, STRN2_02, nsid);
/* Clumn Name*/
@@ -242,11 +252,11 @@ static void show_memblaze_smart_log_new(struct nvme_memblaze_smart_log *s,
static void show_memblaze_smart_log_old(struct nvme_memblaze_smart_log *smart,
unsigned int nsid, const char *devname, const char *fw_ver)
{
- char fw_ver_local[STR_VER_SIZE];
+ char fw_ver_local[STR_VER_SIZE + 1];
struct nvme_memblaze_smart_log_item *item;
strncpy(fw_ver_local, fw_ver, STR_VER_SIZE);
- *(fw_ver_local + STR_VER_SIZE - 1) = '\0';
+ *(fw_ver_local + STR_VER_SIZE) = '\0';
printf("Additional Smart Log for NVME device:%s namespace-id:%x\n", devname, nsid);
@@ -342,6 +352,15 @@ static void show_memblaze_smart_log_old(struct nvme_memblaze_smart_log *smart,
u8 *nm = malloc(NM_SIZE * sizeof(u8));
u8 *raw = malloc(RAW_SIZE * sizeof(u8));
+ if (!nm) {
+ if (raw)
+ free(raw);
+ return;
+ }
+ if (!raw) {
+ free(nm);
+ return;
+ }
/* 00 RAISIN_SI_VD_PROGRAM_FAIL */
get_memblaze_new_smart_info(s, PROGRAM_FAIL, nm, raw);
printf("%-32s : %3d%% %"PRIu64"\n",
@@ -407,11 +426,13 @@ int parse_params(char *str, int number, ...)
c = strtok(str, ",");
if ( c == NULL) {
printf("No enough parameters. abort...\n");
- exit(EINVAL);
+ va_end(argp);
+ return 1;
}
if (isalnum((int)*c) == 0) {
printf("%s is not a valid number\n", c);
+ va_end(argp);
return 1;
}
value = atoi(c);
@@ -467,6 +488,7 @@ static int mb_get_additional_smart_log(int argc, char **argv, struct command *cm
if (err > 0)
nvme_show_status(err);
+ close(fd);
return err;
}
@@ -517,6 +539,7 @@ static int mb_get_powermanager_status(int argc, char **argv, struct command *cmd
nvme_select_to_string(0), result);
} else if (err > 0)
nvme_show_status(err);
+ close(fd);
return err;
}
@@ -574,6 +597,7 @@ static int mb_set_powermanager_status(int argc, char **argv, struct command *cmd
} else if (err > 0)
nvme_show_status(err);
+ close(fd);
return err;
}
@@ -613,11 +637,13 @@ static int mb_set_high_latency_log(int argc, char **argv, struct command *cmd, s
if (parse_params(cfg.param, 2, &param1, &param2)) {
printf("setfeature: invalid formats %s\n", cfg.param);
- exit(EINVAL);
+ close(fd);
+ return EINVAL;
}
if ((param1 == 1) && (param2 < P2MIN || param2 > P2MAX)) {
printf("setfeature: invalid high io latency threshold %d\n", param2);
- exit(EINVAL);
+ close(fd);
+ return EINVAL;
}
cfg.value = (param1 << MB_FEAT_HIGH_LATENCY_VALUE_SHIFT) | param2;
@@ -646,6 +672,7 @@ static int mb_set_high_latency_log(int argc, char **argv, struct command *cmd, s
} else if (err > 0)
nvme_show_status(err);
+ close(fd);
return err;
}
@@ -726,9 +753,14 @@ static int glp_high_latency(FILE *fdi, char *buf, int buflen, int print)
1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, millisec);
}
- fprintf(fdi, "%-32s %-7x %-6x %-6x %-8x %4x%08x %-8x %-d\n",
- string, logEntry->opcode, logEntry->sqe, logEntry->cid, logEntry->nsid,
- (__u32)(logEntry->sLBA >> 32), (__u32)logEntry->sLBA, logEntry->numLBA, logEntry->latency);
+ if (fdi) {
+ fprintf(fdi, "%-32s %-7x %-6x %-6x %-8x %4x%08x %-8x %-d\n",
+ string, logEntry->opcode, logEntry->sqe,
+ logEntry->cid, logEntry->nsid,
+ (__u32)(logEntry->sLBA >> 32),
+ (__u32)logEntry->sLBA, logEntry->numLBA,
+ logEntry->latency);
+ }
if (print)
{
printf("%-32s %-7x %-6x %-6x %-8x %4x%08x %-8x %-d\n",
@@ -746,7 +778,6 @@ static int mb_high_latency_log_print(int argc, char **argv, struct command *cmd,
char buf[LOG_PAGE_SIZE];
FILE *fdi = NULL;
- fdi = fopen(FID_C3_LOG_FILENAME, "w+");
OPT_ARGS(opts) = {
OPT_END()
};
@@ -754,6 +785,8 @@ static int mb_high_latency_log_print(int argc, char **argv, struct command *cmd,
fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0) return fd;
+ fdi = fopen(FID_C3_LOG_FILENAME, "w+");
+
glp_high_latency_show_bar(fdi, DO_PRINT_FLAG);
err = nvme_get_log_simple(fd, GLP_ID_VU_GET_HIGH_LATENCY_LOG, sizeof(buf), &buf);
@@ -767,6 +800,7 @@ static int mb_high_latency_log_print(int argc, char **argv, struct command *cmd,
}
if (NULL != fdi) fclose(fdi);
+ close(fd);
return err;
}
@@ -852,23 +886,26 @@ static int mb_selective_download(int argc, char **argv, struct command *cmd, str
if (err < 0) {
perror("fstat");
err = errno;
+ goto out_close;
}
fw_size = sb.st_size;
if (fw_size & 0x3) {
fprintf(stderr, "Invalid size:%d for f/w image\n", fw_size);
err = EINVAL;
- goto out;
+ goto out_close;
}
if (posix_memalign(&fw_buf, getpagesize(), fw_size)) {
fprintf(stderr, "No memory for f/w size:%d\n", fw_size);
err = ENOMEM;
- goto out;
+ goto out_close;
}
- if (read(fw_fd, fw_buf, fw_size) != ((ssize_t)(fw_size)))
- return EIO;
+ if (read(fw_fd, fw_buf, fw_size) != ((ssize_t)(fw_size))) {
+ err = errno;
+ goto out_free;
+ }
while (fw_size > 0) {
xfer = min(xfer, fw_size);
@@ -885,10 +922,10 @@ static int mb_selective_download(int argc, char **argv, struct command *cmd, str
err = nvme_fw_download(&args);
if (err < 0) {
perror("fw-download");
- goto out;
+ goto out_free;
} else if (err != 0) {
nvme_show_status(err);
- goto out;
+ goto out_free;
}
fw_buf += xfer;
fw_size -= xfer;
@@ -902,7 +939,12 @@ static int mb_selective_download(int argc, char **argv, struct command *cmd, str
fprintf(stderr, "Update successful! Please power cycle for changes to take effect\n");
}
+out_free:
+ free(fw_buf);
+out_close:
+ close(fw_fd);
out:
+ close(fd);
return err;
}
@@ -912,22 +954,17 @@ static void ioLatencyHistogramOutput(FILE *fd, int index, int start, int end, ch
int len;
char string[64], subString0[12], subString1[12];
- len = snprintf(subString0, sizeof(subString0), "%d%s", start, unit0);
+ snprintf(subString0, sizeof(subString0), "%d%s", start, unit0);
if (end != 0x7FFFFFFF)
- {
- len = snprintf(subString1, sizeof(subString1), "%d%s", end, unit1);
- }
+ snprintf(subString1, sizeof(subString1), "%d%s", end, unit1);
else
- {
- len = snprintf(subString1, sizeof(subString1), "%s", "+INF");
- }
- len = snprintf(string, sizeof(string), "%-11d %-11s %-11s %-11u\n", index, subString0, subString1,
+ snprintf(subString1, sizeof(subString1), "%s", "+INF");
+ len = snprintf(string, sizeof(string), "%-11d %-11s %-11s %-11u\n",
+ index, subString0, subString1,
pHistogram[index]);
fwrite(string, 1, len, fd);
if (print)
- {
printf("%s", string);
- }
}
int io_latency_histogram(char *file, char *buf, int print, int logid)
@@ -1006,7 +1043,8 @@ int io_latency_histogram(char *file, char *buf, int print, int logid)
fPRINT_PARAM1("Unsupported io latency histogram revision\n");
}
- fclose(fdi);
+ if (fdi)
+ fclose(fdi);
return 1;
}
@@ -1116,6 +1154,7 @@ static int memblaze_clear_error_log(int argc, char **argv, struct command *cmd,
printf("NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
};
*/
+ close(fd);
return err;
}
@@ -1208,6 +1247,7 @@ static int mb_set_lat_stats(int argc, char **argv,
fid, result);
} else {
printf("Could not read feature id 0xE2.\n");
+ close(fd);
return err;
}
break;
@@ -1226,8 +1266,9 @@ static int mb_set_lat_stats(int argc, char **argv,
break;
default:
printf("%d not supported.\n", option);
- return EINVAL;
+ err = EINVAL;
}
- return fd;
+ close(fd);
+ return err;
}
diff --git a/plugins/memblaze/memblaze-nvme.h b/plugins/memblaze/memblaze-nvme.h
index 6f10bd7..87314c6 100644
--- a/plugins/memblaze/memblaze-nvme.h
+++ b/plugins/memblaze/memblaze-nvme.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#undef CMD_INC_FILE
#define CMD_INC_FILE plugins/memblaze/memblaze-nvme
diff --git a/plugins/memblaze/memblaze-utils.h b/plugins/memblaze/memblaze-utils.h
index 6fdee39..84263f3 100644
--- a/plugins/memblaze/memblaze-utils.h
+++ b/plugins/memblaze/memblaze-utils.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef __MEMBLAZE_UTILS_H__
#define __MEMBLAZE_UTILS_H__
@@ -199,28 +200,24 @@ struct nvme_p4_smart_log
printf("=Memblaze= %s[%d]-%s():%d=%s\n", \
__FILE__, __LINE__, __func__, ip, argv[ip]); }while(0)
-#define fPRINT_PARAM1(format) \
- { \
- do \
- { \
- fprintf(fdi, format);\
- if (print) \
- { \
- printf(format); \
- } \
- } while (0); \
+#define fPRINT_PARAM1(format) \
+ { \
+ do { \
+ if (fdi) \
+ fprintf(fdi, format); \
+ if (print) \
+ printf(format); \
+ } while (0); \
}
-#define fPRINT_PARAM2(format, value) \
- { \
- do \
- { \
- fprintf(fdi, format, value);\
- if (print) \
- { \
- printf(format, value); \
- } \
- } while (0); \
+#define fPRINT_PARAM2(format, value) \
+ { \
+ do { \
+ if (fdi) \
+ fprintf(fdi, format, value); \
+ if (print) \
+ printf(format, value); \
+ } while (0); \
}
#endif // __MEMBLAZE_UTILS_H__
diff --git a/plugins/meson.build b/plugins/meson.build
index 6f21362..b3af39b 100644
--- a/plugins/meson.build
+++ b/plugins/meson.build
@@ -1,8 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
sources += [
'plugins/amzn/amzn-nvme.c',
+ 'plugins/dell/dell-nvme.c',
'plugins/dera/dera-nvme.c',
'plugins/huawei/huawei-nvme.c',
'plugins/intel/intel-nvme.c',
+ 'plugins/innogrit/innogrit-nvme.c',
'plugins/memblaze/memblaze-nvme.c',
'plugins/micron/micron-nvme.c',
'plugins/netapp/netapp-nvme.c',
@@ -10,6 +14,7 @@ sources += [
'plugins/scaleflux/sfx-nvme.c',
'plugins/seagate/seagate-nvme.c',
'plugins/shannon/shannon-nvme.c',
+ 'plugins/solidigm/solidigm-nvme.c',
'plugins/toshiba/toshiba-nvme.c',
'plugins/transcend/transcend-nvme.c',
'plugins/virtium/virtium-nvme.c',
@@ -19,3 +24,4 @@ sources += [
'plugins/zns/zns.c',
'plugins/ocp/ocp-nvme.c',
]
+subdir('solidigm')
diff --git a/plugins/micron/micron-nvme.c b/plugins/micron/micron-nvme.c
index d333c4c..d7ac3d4 100644
--- a/plugins/micron/micron-nvme.c
+++ b/plugins/micron/micron-nvme.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
#include <stdio.h>
#include <string.h>
#include <ctype.h>
@@ -21,7 +22,7 @@
/* Supported Vendor specific feature ids */
#define MICRON_FEATURE_CLEAR_PCI_CORRECTABLE_ERRORS 0xC3
-#define MICRON_FEATURE_CLEAR_FW_ACTIVATION_HISTORY 0xCE
+#define MICRON_FEATURE_CLEAR_FW_ACTIVATION_HISTORY 0xC1
#define MICRON_FEATURE_TELEMETRY_CONTROL_OPTION 0xCF
#define MICRON_FEATURE_SMBUS_OPTION 0xD5
@@ -36,12 +37,12 @@
#define CommonChunkSize 16 * 4096
#define min(x, y) ((x) > (y) ? (y) : (x))
-#define SensorCount 2
+#define SensorCount 8
/* Plugin version major_number.minor_number.patch */
static const char *__version_major = "1";
static const char *__version_minor = "0";
-static const char *__version_patch = "8";
+static const char *__version_patch = "14";
/* supported models of micron plugin; new models should be added at the end
* before UNKNOWN_MODEL. Make sure M5410 is first in the list !
@@ -87,13 +88,15 @@ static int ReadSysFile(const char *file, unsigned short *id)
char idstr[32] = { '\0' };
int fd = open(file, O_RDONLY);
- if (fd > 0) {
- ret = read(fd, idstr, sizeof(idstr));
- close(fd);
+ if (fd < 0) {
+ perror(file);
+ return fd;
}
- if (fd < 0 || ret < 0)
- perror(file);
+ ret = read(fd, idstr, sizeof(idstr));
+ close(fd);
+ if (ret < 0)
+ perror("read");
else
*id = strtol(idstr, NULL, 16);
@@ -249,6 +252,7 @@ static int SetupDebugDataDirectories(char *strSN, char *strFilePath,
if (':' == fileLocation[length - 1]) {
if ((strTemp = (char *)malloc(length + 2)) == NULL) {
+ free(fileLocation);
goto exit_status;
}
strcpy(strTemp, fileLocation);
@@ -257,6 +261,7 @@ static int SetupDebugDataDirectories(char *strSN, char *strFilePath,
length = (int)strlen(strTemp);
if ((fileLocation = (char *)malloc(length + 1)) == NULL) {
+ free(strTemp);
goto exit_status;
}
@@ -290,17 +295,27 @@ static int SetupDebugDataDirectories(char *strSN, char *strFilePath,
j++;
}
- mkdir(strMainDirName, 0777);
+ if (mkdir(strMainDirName, 0777) < 0) {
+ err = -1;
+ goto exit_status;
+ }
if (strOSDirName != NULL) {
sprintf(strOSDirName, "%s/%s", strMainDirName, "OS");
- mkdir(strOSDirName, 0777);
-
+ if (mkdir(strOSDirName, 0777) < 0) {
+ rmdir(strMainDirName);
+ err = -1;
+ goto exit_status;
+ }
}
if (strCtrlDirName != NULL) {
sprintf(strCtrlDirName, "%s/%s", strMainDirName, "Controller");
- mkdir(strCtrlDirName, 0777);
-
+ if (mkdir(strCtrlDirName, 0777) < 0) {
+ if (strOSDirName != NULL)
+ rmdir(strOSDirName);
+ rmdir(strMainDirName);
+ err = -1;
+ }
}
exit_status:
@@ -327,7 +342,8 @@ static int GetLogPageSize(int nFD, unsigned char ucLogID, int *nLogSize)
err = -1;
}
} else {
- printf ("Getting size of log page : 0x%X failed with %d\n", ucLogID, err);
+ printf ("Getting size of log page : 0x%X failed with %d (ignored)!\n",
+ ucLogID, err);
*nLogSize = 0;
}
}
@@ -402,8 +418,10 @@ static int NVMEResetLog(int nFD, unsigned char ucLogID, int nBufferSize,
while (err == 0 && llMaxSize > 0) {
err = NVMEGetLogPage(nFD, ucLogID, (unsigned char *)pBuffer, nBufferSize);
- if (err)
+ if (err) {
+ free(pBuffer);
return err;
+ }
if (pBuffer[0] == 0xdeadbeef)
break;
@@ -498,14 +516,13 @@ static int micron_selective_download(int argc, char **argv,
};
fd = parse_and_open(argc, argv, desc, opts);
-
if (fd < 0)
return fd;
if (strlen(cfg.select) != 3) {
fprintf(stderr, "Invalid select flag\n");
- err = EINVAL;
- goto out;
+ close(fd);
+ return EINVAL;
}
for (int i = 0; i < 3; i++) {
@@ -520,21 +537,22 @@ static int micron_selective_download(int argc, char **argv,
selectNo = 26;
} else {
fprintf(stderr, "Invalid select flag\n");
- err = EINVAL;
- goto out;
+ close(fd);
+ return EINVAL;
}
fw_fd = open(cfg.fw, O_RDONLY);
if (fw_fd < 0) {
fprintf(stderr, "no firmware file provided\n");
- err = EINVAL;
- goto out;
+ close(fd);
+ return EINVAL;
}
err = fstat(fw_fd, &sb);
if (err < 0) {
perror("fstat");
err = errno;
+ goto out;
}
fw_size = sb.st_size;
@@ -550,8 +568,10 @@ static int micron_selective_download(int argc, char **argv,
goto out;
}
- if (read(fw_fd, fw_buf, fw_size) != ((ssize_t) (fw_size)))
- return EIO;
+ if (read(fw_fd, fw_buf, fw_size) != ((ssize_t) (fw_size))) {
+ err = errno;
+ goto out_free;
+ }
while (fw_size > 0) {
xfer = min(xfer, fw_size);
@@ -568,10 +588,10 @@ static int micron_selective_download(int argc, char **argv,
err = nvme_fw_download(&args);
if (err < 0) {
perror("fw-download");
- goto out;
+ goto out_free;
} else if (err != 0) {
nvme_show_status(err);
- goto out;
+ goto out_free;
}
fw_buf += xfer;
fw_size -= xfer;
@@ -586,7 +606,11 @@ static int micron_selective_download(int argc, char **argv,
"Update successful! Power cycle for changes to take effect\n");
}
+out_free:
+ free(fw_buf);
out:
+ close(fw_fd);
+ close(fd);
return err;
}
@@ -723,7 +747,7 @@ static int micron_temp_stats(int argc, char **argv, struct command *cmd,
if (!err) {
temperature = ((smart_log.temperature[1] << 8) | smart_log.temperature[0]);
temperature = temperature ? temperature - 273 : 0;
- for (i = 0; i < SensorCount; i++) {
+ for (i = 0; i < SensorCount && tempSensors[i] != 0; i++) {
tempSensors[i] = le16_to_cpu(smart_log.temp_sensor[i]);
tempSensors[i] = tempSensors[i] ? tempSensors[i] - 273 : 0;
}
@@ -735,7 +759,7 @@ static int micron_temp_stats(int argc, char **argv, struct command *cmd,
json_object_add_value_array(root, "Micron temperature information", logPages);
sprintf(tempstr, "%u C", temperature);
json_object_add_value_string(stats, "Current Composite Temperature", tempstr);
- for (i = 0; i < SensorCount; i++) {
+ for (i = 0; i < SensorCount && tempSensors[i] != 0; i++) {
char sensor_str[256] = { 0 };
char datastr[64] = { 0 };
sprintf(sensor_str, "Temperature Sensor #%d", (i + 1));
@@ -749,11 +773,12 @@ static int micron_temp_stats(int argc, char **argv, struct command *cmd,
} else {
printf("Micron temperature information:\n");
printf("%-10s : %u C\n", "Current Composite Temperature", temperature);
- for (i = 0; i < SensorCount; i++) {
+ for (i = 0; i < SensorCount && tempSensors[i] != 0; i++) {
printf("%-10s%d : %u C\n", "Temperature Sensor #", i + 1, tempSensors[i]);
}
}
}
+ close(fd);
return err;
}
@@ -769,9 +794,11 @@ static int micron_pcie_stats(int argc, char **argv,
FILE *fp;
char correctable[8] = { 0 };
char uncorrectable[8] = { 0 };
+ struct nvme_passthru_cmd admin_cmd = { 0 };
eDriveModel eModel = UNKNOWN_MODEL;
char *res;
bool is_json = true;
+ bool counters = false;
struct format {
char *fmt;
};
@@ -780,29 +807,64 @@ static int micron_pcie_stats(int argc, char **argv,
struct format cfg = {
.fmt = "json",
};
+ struct pcie_error_counters {
+ __u16 receiver_error;
+ __u16 bad_tlp;
+ __u16 bad_dllp;
+ __u16 replay_num_rollover;
+ __u16 replay_timer_timeout;
+ __u16 advisory_non_fatal_error;
+ __u16 DLPES;
+ __u16 poisoned_tlp;
+ __u16 FCPC;
+ __u16 completion_timeout;
+ __u16 completion_abort;
+ __u16 unexpected_completion;
+ __u16 receiver_overflow;
+ __u16 malformed_tlp;
+ __u16 ecrc_error;
+ __u16 unsupported_request_error;
+ } pcie_error_counters = { 0 };
+
struct {
char *err;
int bit;
int val;
} pcie_correctable_errors[] = {
- { "Unsupported Request Error Status (URES)", 20},
- { "ECRC Error Status (ECRCES)", 19},
- { "Malformed TLP Status (MTS)", 18},
- { "Receiver Overflow Status (ROS)", 17},
- { "Unexpected Completion Status (UCS)", 16},
- { "Completer Abort Status (CAS)", 15},
- { "Completion Timeout Stats (CTS)", 14},
- { "Flow Control Protocol Error Status (FCPES)", 13},
- { "Poisoned TLP Status (PTS)", 12},
- { "Data Link Protocol Error Status (DLPES)", 4},
+ { "Unsupported Request Error Status (URES)", 20,
+ offsetof(struct pcie_error_counters, unsupported_request_error)},
+ { "ECRC Error Status (ECRCES)", 19,
+ offsetof(struct pcie_error_counters, ecrc_error)},
+ { "Malformed TLP Status (MTS)", 18,
+ offsetof(struct pcie_error_counters, malformed_tlp)},
+ { "Receiver Overflow Status (ROS)", 17,
+ offsetof(struct pcie_error_counters, receiver_overflow)},
+ { "Unexpected Completion Status (UCS)", 16,
+ offsetof(struct pcie_error_counters, unexpected_completion)},
+ { "Completer Abort Status (CAS)", 15,
+ offsetof(struct pcie_error_counters, completion_abort)},
+ { "Completion Timeout Status (CTS)", 14,
+ offsetof(struct pcie_error_counters, completion_timeout)},
+ { "Flow Control Protocol Error Status (FCPES)", 13,
+ offsetof(struct pcie_error_counters, FCPC)},
+ { "Poisoned TLP Status (PTS)", 12,
+ offsetof(struct pcie_error_counters, poisoned_tlp)},
+ { "Data Link Protocol Error Status (DLPES)", 4,
+ offsetof(struct pcie_error_counters, DLPES)},
},
pcie_uncorrectable_errors[] = {
- { "Advisory Non-Fatal Error Status (ANFES)", 13},
- { "Replay Timer Timeout Status (RTS)", 12},
- { "REPLY NUM Rollover Status (RRS)", 8},
- { "Bad DLLP Status (BDS)", 7},
- { "Bad TLP Status (BTS)", 6},
- { "Receiver Error Status (RES)", 0},
+ { "Advisory Non-Fatal Error Status (ANFES)", 13,
+ offsetof(struct pcie_error_counters, advisory_non_fatal_error)},
+ { "Replay Timer Timeout Status (RTS)", 12,
+ offsetof(struct pcie_error_counters, replay_timer_timeout)},
+ { "REPLAY_NUM Rollover Status (RRS)", 8,
+ offsetof(struct pcie_error_counters, replay_num_rollover)},
+ { "Bad DLLP Status (BDS)", 7,
+ offsetof(struct pcie_error_counters, bad_dllp)},
+ { "Bad TLP Status (BTS)", 6,
+ offsetof(struct pcie_error_counters, bad_tlp)},
+ { "Receiver Error Status (RES)", 0,
+ offsetof(struct pcie_error_counters, receiver_error)},
};
__u32 correctable_errors;
@@ -823,13 +885,26 @@ static int micron_pcie_stats(int argc, char **argv,
sscanf(argv[optind], "/dev/nvme%d", &ctrlIdx);
if ((eModel = GetDriveModel(ctrlIdx)) == UNKNOWN_MODEL) {
printf ("Unsupported drive model for vs-pcie-stats command\n");
- close(fd);
goto out;
}
if (strcmp(cfg.fmt, "normal") == 0)
is_json = false;
+ if (eModel == M5407) {
+ admin_cmd.opcode = 0xD6;
+ admin_cmd.addr = (__u64)(uintptr_t)&pcie_error_counters;
+ admin_cmd.data_len = sizeof(pcie_error_counters);
+ admin_cmd.cdw10 = 1;
+ err = nvme_submit_admin_passthru(fd, &admin_cmd, NULL);
+ if (!err) {
+ counters = true;
+ correctable_errors = 10;
+ uncorrectable_errors = 6;
+ goto print_stats;
+ }
+ }
+
if (strstr(argv[optind], "/dev/nvme") && strstr(argv[optind], "n1")) {
devicename = strrchr(argv[optind], '/');
} else if (strstr(argv[optind], "/dev/nvme")) {
@@ -841,7 +916,8 @@ static int micron_pcie_stats(int argc, char **argv,
goto out;
}
sprintf(strTempFile, "/sys/block/%s/device", devicename);
- sLinkSize = readlink(strTempFile, strTempFile2, 1024);
+ memset(strTempFile2, 0x0, 1024);
+ sLinkSize = readlink(strTempFile, strTempFile2, 1023);
if (sLinkSize < 0) {
err = -errno;
printf("Failed to read device\n");
@@ -849,7 +925,8 @@ static int micron_pcie_stats(int argc, char **argv,
}
if (strstr(strTempFile2, "../../nvme")) {
sprintf(strTempFile, "/sys/block/%s/device/device", devicename);
- sLinkSize = readlink(strTempFile, strTempFile2, 1024);
+ memset(strTempFile2, 0x0, 1024);
+ sLinkSize = readlink(strTempFile, strTempFile2, 1023);
if (sLinkSize < 0) {
err = -errno;
printf("Failed to read device\n");
@@ -868,6 +945,7 @@ static int micron_pcie_stats(int argc, char **argv,
res = fgets(correctable, sizeof(correctable), fp);
if (res == NULL) {
printf("Failed to retrieve error count\n");
+ pclose(fp);
goto out;
}
pclose(fp);
@@ -882,6 +960,7 @@ static int micron_pcie_stats(int argc, char **argv,
res = fgets(uncorrectable, sizeof(uncorrectable), fp);
if (res == NULL) {
printf("Failed to retrieve error count\n");
+ pclose(fp);
goto out;
}
pclose(fp);
@@ -889,32 +968,46 @@ static int micron_pcie_stats(int argc, char **argv,
correctable_errors = (__u32)strtol(correctable, NULL, 16);
uncorrectable_errors = (__u32)strtol(uncorrectable, NULL, 16);
+print_stats:
if (is_json) {
struct json_object *root = json_create_object();
struct json_object *pcieErrors = json_create_array();
struct json_object *stats = json_create_object();
+ __u8 *pcounter = (__u8 *)&pcie_error_counters;
json_object_add_value_array(root, "PCIE Stats", pcieErrors);
for (i = 0; i < sizeof(pcie_correctable_errors) / sizeof(pcie_correctable_errors[0]); i++) {
- json_object_add_value_int(stats, pcie_correctable_errors[i].err,
- ((correctable_errors >> pcie_correctable_errors[i].bit) & 1));
+ __u16 val = counters ? *(__u16 *)(pcounter + pcie_correctable_errors[i].val) :
+ (correctable_errors >> pcie_correctable_errors[i].bit) & 1;
+ json_object_add_value_int(stats, pcie_correctable_errors[i].err, val);
}
for (i = 0; i < sizeof(pcie_uncorrectable_errors) / sizeof(pcie_uncorrectable_errors[0]); i++) {
- json_object_add_value_int(stats, pcie_uncorrectable_errors[i].err,
- ((uncorrectable_errors >> pcie_uncorrectable_errors[i].bit) & 1));
+ __u16 val = counters ? *(__u16 *)(pcounter + pcie_uncorrectable_errors[i].val) :
+ (uncorrectable_errors >> pcie_uncorrectable_errors[i].bit) & 1;
+ json_object_add_value_int(stats, pcie_uncorrectable_errors[i].err, val);
}
json_array_add_value_object(pcieErrors, stats);
json_print_object(root, NULL);
printf("\n");
json_free_object(root);
+ } else if (counters == true) {
+ __u8 *pcounter = (__u8 *)&pcie_error_counters;
+ for (i = 0; i < sizeof(pcie_correctable_errors) / sizeof(pcie_correctable_errors[0]); i++) {
+ printf("%-42s : %-1hu\n", pcie_correctable_errors[i].err,
+ *(__u16 *)(pcounter + pcie_correctable_errors[i].val));
+ }
+ for (i = 0; i < sizeof(pcie_uncorrectable_errors) / sizeof(pcie_uncorrectable_errors[0]); i++) {
+ printf("%-42s : %-1hu\n", pcie_uncorrectable_errors[i].err,
+ *(__u16 *)(pcounter + pcie_uncorrectable_errors[i].val));
+ }
} else if (eModel == M5407 || eModel == M5410) {
for (i = 0; i < sizeof(pcie_correctable_errors) / sizeof(pcie_correctable_errors[0]); i++) {
- printf("%-40s : %-1d\n", pcie_correctable_errors[i].err,
+ printf("%-42s : %-1d\n", pcie_correctable_errors[i].err,
((correctable_errors >> pcie_correctable_errors[i].bit) & 1));
}
for (i = 0; i < sizeof(pcie_uncorrectable_errors) / sizeof(pcie_uncorrectable_errors[0]); i++) {
- printf("%-40s : %-1d\n", pcie_uncorrectable_errors[i].err,
+ printf("%-42s : %-1d\n", pcie_uncorrectable_errors[i].err,
((uncorrectable_errors >> pcie_uncorrectable_errors[i].bit) & 1));
}
} else {
@@ -924,6 +1017,8 @@ static int micron_pcie_stats(int argc, char **argv,
}
out:
+ if (fd > 0)
+ close(fd);
return err;
}
@@ -938,6 +1033,7 @@ static int micron_clear_pcie_correctable_errors(int argc, char **argv,
char tdevice[PATH_MAX] = { 0 };
ssize_t sLinkSize = 0;
eDriveModel model = UNKNOWN_MODEL;
+ struct nvme_passthru_cmd admin_cmd = { 0 };
char correctable[8] = { 0 };
int fd = -1;
FILE *fp;
@@ -955,13 +1051,22 @@ static int micron_clear_pcie_correctable_errors(int argc, char **argv,
/* For M51CX models, PCIe errors are cleared using 0xC3 feature */
if (model == M51CX) {
err = nvme_set_features_simple(fd, fid, 0, (1 << 31), false, &result);
- if (err == 0 && (err = (int)result) == 0)
- printf("Device correctable errors cleared!\n");
- else if (err > 0)
- nvme_show_status(err);
- else
- printf("Error clearing Device correctable errors = 0x%x\n", err);
- goto out;
+ if (err == 0 && (err = (int)result) == 0) {
+ printf("Device correctable errors are cleared!\n");
+ goto out;
+ }
+ } else if (model == M5407) {
+ admin_cmd.opcode = 0xD6;
+ admin_cmd.addr = 0;
+ admin_cmd.cdw10 = 0;
+ err = nvme_submit_admin_passthru(fd, &admin_cmd, NULL);
+ if (err == 0) {
+ printf("Device correctable error counters are cleared!\n");
+ goto out;
+ } else {
+ /* proceed to clear status bits using sysfs interface
+ printf("Error clearing PCIe correctable errors = 0x%x\n", err); */
+ }
}
if (strstr(argv[optind], "/dev/nvme") && strstr(argv[optind], "n1")) {
@@ -979,7 +1084,8 @@ static int micron_clear_pcie_correctable_errors(int argc, char **argv,
if (err < 0)
goto out;
- sLinkSize = readlink(strTempFile, strTempFile2, 1024);
+ memset(strTempFile2, 0x0, 1024);
+ sLinkSize = readlink(strTempFile, strTempFile2, 1023);
if (sLinkSize < 0) {
err = -errno;
printf("Failed to read device\n");
@@ -990,7 +1096,8 @@ static int micron_clear_pcie_correctable_errors(int argc, char **argv,
"/sys/block/%s/device/device", devicename);
if (err < 0)
goto out;
- sLinkSize = readlink(strTempFile, strTempFile2, 1024);
+ memset(strTempFile2, 0x0, 1024);
+ sLinkSize = readlink(strTempFile, strTempFile2, 1023);
if (sLinkSize < 0) {
err = -errno;
printf("Failed to read device\n");
@@ -1019,6 +1126,7 @@ static int micron_clear_pcie_correctable_errors(int argc, char **argv,
res = fgets(correctable, sizeof(correctable), fp);
if (res == NULL) {
printf("Failed to retrieve error count\n");
+ pclose(fp);
goto out;
}
pclose(fp);
@@ -1026,8 +1134,7 @@ static int micron_clear_pcie_correctable_errors(int argc, char **argv,
printf("Device correctable errors detected: %s\n", correctable);
err = 0;
out:
- if (fd > 0)
- close(fd);
+ close(fd);
return err;
}
@@ -1323,13 +1430,13 @@ static void print_nand_stats_fb(__u8 *buf, __u8 *buf2, __u8 nsze, bool is_json,
init_d0_log_page(buf2, nsze);
if (is_json) {
- for (int i = 4; i < 7; i++) {
+ for (int i = 0; i < 7; i++) {
json_object_add_value_string(stats,
d0_log_page[i].field,
d0_log_page[i].datastr);
}
} else {
- for (int i = 4; i < 7; i++) {
+ for (int i = 0; i < 7; i++) {
printf("%-40s : %s\n", d0_log_page[i].field, d0_log_page[i].datastr);
}
}
@@ -1670,14 +1777,14 @@ static void GetGenericLogs(int fd, const char *dir)
err = nvme_get_log_persistent_event(fd, NVME_PEVENT_LOG_EST_CTX_AND_READ,
sizeof(pevent_log), &pevent_log);
if (err) {
- fprintf(stderr, "Failed to set persistent event log read context");
+ fprintf(stderr, "Setting persistent event log read ctx failed (ignored)!\n");
return;
}
log_len = le64_to_cpu(pevent_log.tll);
pevent_log_info = nvme_alloc(log_len, &huge);
if (!pevent_log_info) {
- perror("could not alloc buffer for persistent event log page\n");
+ perror("could not alloc buffer for persistent event log page (ignored)!\n");
return;
}
err = nvme_get_log_persistent_event(fd, NVME_PEVENT_LOG_READ,
@@ -1704,7 +1811,7 @@ static void GetNSIDDInfo(int fd, const char *dir, int nsid)
static void GetOSConfig(const char *strOSDirName)
{
FILE *fpOSConfig = NULL;
- char strBuffer[1024], strTemp[1024];
+ char strBuffer[1024];
char strFileName[PATH_MAX];
int i;
@@ -1727,15 +1834,15 @@ static void GetOSConfig(const char *strOSDirName)
for (i = 0; i < 7; i++) {
fpOSConfig = fopen(strFileName, "a+");
- fprintf(fpOSConfig,
+ if (NULL != fpOSConfig) {
+ fprintf(fpOSConfig,
"\n\n\n\n%s\n-----------------------------------------------\n",
cmdArray[i].strcmdHeader);
- if (NULL != fpOSConfig) {
fclose(fpOSConfig);
fpOSConfig = NULL;
}
- strcpy(strTemp, cmdArray[i].strCommand);
- sprintf(strBuffer, strTemp, strFileName);
+ snprintf(strBuffer, sizeof(strBuffer) - 1,
+ cmdArray[i].strCommand, strFileName);
if (system(strBuffer))
fprintf(stderr, "Failed to send \"%s\"\n", strBuffer);
}
@@ -1821,10 +1928,11 @@ static int GetTelemetryData(int fd, const char *dir)
if (err == 0 && logSize > 0 && buffer != NULL) {
sprintf(msg, "telemetry log: 0x%X", tmap[i].log);
WriteData(buffer, logSize, dir, tmap[i].file, msg);
- if (buffer != NULL)
- free(buffer);
}
- buffer = NULL;
+ if (buffer) {
+ free(buffer);
+ buffer = NULL;
+ }
logSize = 0;
}
return err;
@@ -1885,7 +1993,7 @@ static int GetFeatureSettings(int fd, const char *dir)
WriteData(bufp, len, dir, fmap[i].file, msg);
}
} else {
- printf("Feature 0x%x data not retrieved, error %d (ignored)!\n",
+ fprintf(stderr, "Feature 0x%x data not retrieved, error %d (ignored)!\n",
fmap[i].id, err);
errcnt++;
}
@@ -1929,6 +2037,7 @@ static int micron_drive_info(int argc, char **argv, struct command *cmd,
if (model == UNKNOWN_MODEL) {
fprintf(stderr, "ERROR : Unsupported drive for vs-drive-info cmd");
+ close(fd);
return -1;
}
@@ -1943,16 +2052,19 @@ static int micron_drive_info(int argc, char **argv, struct command *cmd,
err = nvme_submit_admin_passthru(fd, &admin_cmd, NULL);
if (err) {
fprintf(stderr, "ERROR : drive-info opcode failed with 0x%x\n", err);
+ close(fd);
return -1;
}
} else {
err = nvme_identify_ctrl(fd, &ctrl);
if (err) {
fprintf(stderr, "ERROR : identify_ctrl() failed with 0x%x\n", err);
+ close(fd);
return -1;
}
dinfo.hw_ver_major = ctrl.vs[820];
dinfo.hw_ver_minor = ctrl.vs[821];
+ dinfo.ftl_unit_size = ctrl.vs[822];
}
if (is_json) {
@@ -1991,6 +2103,7 @@ static int micron_drive_info(int argc, char **argv, struct command *cmd,
}
}
+ close(fd);
return 0;
}
@@ -2010,12 +2123,6 @@ static int micron_plugin_version(int argc, char **argv, struct command *cmd,
return 0;
}
-static int micron_logpage_dir(int argc, char **argv, struct command *cmd,
- struct plugin *plugin)
-{
- printf("This command is not implemented for the drive\n");
- return 0;
-}
/* Binary format of firmware activation history entry */
struct __attribute__((__packed__)) fw_activation_history_entry {
__u8 version;
@@ -2050,8 +2157,8 @@ struct __attribute__((__packed__)) micron_fw_activation_history_table {
const char *fw_activation_history_table_header = "\
__________________________________________________________________________________\n\
| | | | | | | \n\
-Firmware | Power | Power | Previous | New FW | Slot | Commit | Result \n\
-Activation| On Hour | cycle | firmware | activated | number | Action | \n\
+Firmware | Power On | Power | Previous | New FW | Slot | Commit | Result \n\
+Activation| Hour | cycle | firmware | activated | number | Action | \n\
Counter | | count | | | | Type | \n\
__________|___________|_________|__________|___________|________|________|________\n";
@@ -2069,9 +2176,9 @@ static int display_fw_activate_entry (
char *ptr = formatted_entry;
int index = 0, entry_size = 82;
- if (entry->version != 1 || entry->length != 64) {
- fprintf(stderr, "unsupported entry ! version: %x with length: %d\n",
- entry->version, entry->length);
+ if ((entry->version != 1 && entry->version != 2) || entry->length != 64) {
+ /*fprintf(stderr, "unsupported entry ! version: %x with length: %d\n",
+ entry->version, entry->length); */
return -EINVAL;
}
@@ -2178,7 +2285,8 @@ static int micron_fw_activation_history(int argc, char **argv, struct command *c
(struct micron_fw_activation_history_table *)logC2;
/* check version and log page */
- if (table->version != 2 || table->log_page != 0xC2) {
+ if (table->log_page != 0xC2 || (table->version != 2 && table->version != 1))
+ {
fprintf(stderr, "Unsupported fw activation history page: %x, version: %x\n",
table->log_page, table->version);
goto out;
@@ -2200,8 +2308,7 @@ static int micron_fw_activation_history(int argc, char **argv, struct command *c
}
}
out:
- if (fd > 0)
- close(fd);
+ close(fd);
return err;
}
@@ -2254,6 +2361,7 @@ static int micron_latency_stats_track(int argc, char **argv, struct command *cmd
enable = 0;
} else if (strcmp(opt.option, "status")) {
printf("Invalid control option %s specified\n", opt.option);
+ close(fd);
return -1;
}
@@ -2274,6 +2382,7 @@ static int micron_latency_stats_track(int argc, char **argv, struct command *cmd
err = nvme_get_features(&g_args);
if (err != 0) {
printf("Failed to retrieve latency monitoring feature status\n");
+ close(fd);
return err;
}
@@ -2298,6 +2407,7 @@ static int micron_latency_stats_track(int argc, char **argv, struct command *cmd
} else if (result == 0) {
printf("\n");
}
+ close(fd);
return err;
}
@@ -2305,11 +2415,13 @@ static int micron_latency_stats_track(int argc, char **argv, struct command *cmd
if (enable == 1) {
if (opt.threshold > 2550) {
printf("The maximum threshold value cannot be more than 2550 ms\n");
+ close(fd);
return -1;
}
/* timing mask is in terms of 10ms units, so min allowed is 10ms */
else if ((opt.threshold % 10) != 0) {
printf("The threshold value should be multiple of 10 ms\n");
+ close(fd);
return -1;
}
opt.threshold /= 10;
@@ -2322,12 +2434,13 @@ static int micron_latency_stats_track(int argc, char **argv, struct command *cmd
} else if (!strcmp(opt.command, "write")) {
command_mask = 0x2;
timing_mask = (opt.threshold << 16);
- } else if (!strcmp(opt.command, "read")) {
+ } else if (!strcmp(opt.command, "trim")) {
command_mask = 0x4;
timing_mask = (opt.threshold << 8);
} else if (strcmp(opt.command, "all")) {
printf("Invalid command %s specified for option %s\n",
opt.command, opt.option);
+ close(fd);
return -1;
}
@@ -2349,11 +2462,11 @@ static int micron_latency_stats_track(int argc, char **argv, struct command *cmd
};
err = nvme_set_features(&args);
if (err == 0) {
- printf("Successfully %sed latency monitoring for %s commands\n",
- opt.option, opt.command);
+ printf("Successfully %sd latency monitoring for %s commands with %dms threshold\n",
+ opt.option, opt.command, opt.threshold == 0 ? 800 : opt.threshold * 10);
} else {
- printf("Failed to %s latency monitoring for %s commands\n",
- opt.option, opt.command);
+ printf("Failed to %s latency monitoring for %s commands with %dms threshold\n",
+ opt.option, opt.command, opt.threshold == 0 ? 800 : opt.threshold * 10);
}
close(fd);
@@ -2411,6 +2524,7 @@ static int micron_latency_stats_logs(int argc, char **argv, struct command *cmd,
if (err) {
if (err < 0)
printf("Unable to retrieve latency stats log the drive\n");
+ close(fd);
return err;
}
/* print header and each log entry */
@@ -2424,6 +2538,7 @@ static int micron_latency_stats_logs(int argc, char **argv, struct command *cmd,
log[i].deac, log[i].prinfo, log[i].fua, log[i].lr);
}
printf("\n");
+ close(fd);
return err;
}
@@ -2437,13 +2552,14 @@ static int micron_latency_stats_info(int argc, char **argv, struct command *cmd,
int fd = -1;
eDriveModel model = UNKNOWN_MODEL;
#define LATENCY_BUCKET_COUNT 32
+ #define LATENCY_BUCKET_RSVD 32
struct micron_latency_stats {
uint64_t version; /* major << 32 | minior */
- uint64_t all_cmds[LATENCY_BUCKET_COUNT];
- uint64_t read_cmds[LATENCY_BUCKET_COUNT];
- uint64_t write_cmds[LATENCY_BUCKET_COUNT];
- uint64_t trim_cmds[LATENCY_BUCKET_COUNT];
- uint32_t reserved[765]; /* round up to 4K */
+ uint64_t all_cmds[LATENCY_BUCKET_COUNT + LATENCY_BUCKET_RSVD];
+ uint64_t read_cmds[LATENCY_BUCKET_COUNT + LATENCY_BUCKET_RSVD];
+ uint64_t write_cmds[LATENCY_BUCKET_COUNT + LATENCY_BUCKET_RSVD];
+ uint64_t trim_cmds[LATENCY_BUCKET_COUNT + LATENCY_BUCKET_RSVD];
+ uint32_t reserved[255]; /* round up to 4K */
} log;
struct latency_thresholds {
@@ -2489,6 +2605,7 @@ static int micron_latency_stats_info(int argc, char **argv, struct command *cmd,
cmd_str = "Trim";
} else if (strcmp(opt.command, "all")) {
printf("Invalid command option %s to display latency stats\n", opt.command);
+ close(fd);
return -1;
}
@@ -2497,6 +2614,7 @@ static int micron_latency_stats_info(int argc, char **argv, struct command *cmd,
if (err) {
if (err < 0)
printf("Unable to retrieve latency stats log the drive\n");
+ close(fd);
return err;
}
printf("Micron IO %s Command Latency Statistics\n"
@@ -2518,6 +2636,7 @@ static int micron_latency_stats_info(int argc, char **argv, struct command *cmd,
printf("%2d %8s %8s %8"PRIu64"\n",
bucket, start, end, cmd_stats[b]);
}
+ close(fd);
return err;
}
@@ -2613,8 +2732,11 @@ static int micron_clr_fw_activation_history(int argc, char **argv,
return err;
}
- err = nvme_set_features_simple(fd, fid, 1, 0, 0, &result);
+ err = nvme_set_features_simple(fd, fid, 1 << 31, 0, 0, &result);
if (err == 0) err = (int)result;
+ else printf ("Failed to clear fw activation history, error = 0x%x\n", err);
+
+ close(fd);
return err;
}
@@ -2733,6 +2855,157 @@ static int micron_telemetry_cntrl_option(int argc, char **argv,
return err;
}
+/* M51XX models log page header */
+struct micron_common_log_header {
+ uint8_t id;
+ uint8_t version;
+ uint16_t pn;
+ uint32_t log_size;
+ uint32_t max_size;
+ uint32_t write_pointer;
+ uint32_t next_pointer;
+ uint32_t overwritten_bytes;
+ uint8_t flags;
+ uint8_t reserved[7];
+};
+
+/* helper function to retrieve logs with specific offset and max chunk size */
+int nvme_get_log_lpo(int fd, __u8 log_id, __u32 lpo, __u32 chunk,
+ __u32 data_len, void *data)
+{
+ __u32 offset = lpo, xfer_len = data_len;
+ void *ptr = data;
+ struct nvme_get_log_args args = {
+ .lpo = offset,
+ .result = NULL,
+ .log = ptr,
+ .args_size = sizeof(args),
+ .fd = fd,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .lid = log_id,
+ .len = xfer_len,
+ .nsid = NVME_NSID_ALL,
+ .csi = NVME_CSI_NVM,
+ .lsi = NVME_LOG_LSI_NONE,
+ .lsp = NVME_LOG_LSP_NONE,
+ .uuidx = NVME_UUID_NONE,
+ .rae = false,
+ .ot = false,
+ };
+ int ret = 0;
+
+ /* divide data into multiple chunks */
+ do {
+ xfer_len = data_len - offset;
+ if (xfer_len > chunk)
+ xfer_len = chunk;
+
+ args.lpo = offset;
+ args.log = ptr;
+ args.len = xfer_len;
+ ret = nvme_get_log(&args);
+ if (ret)
+ return ret;
+ offset += xfer_len;
+ ptr += xfer_len;
+ } while (offset < data_len);
+ return ret;
+}
+
+/* retrieves logs with common log format */
+static int get_common_log(int fd, uint8_t id, uint8_t **buf, int *size)
+{
+ struct micron_common_log_header hdr = { 0 };
+ int log_size = sizeof(hdr), first = 0, second = 0;
+ uint8_t *buffer = NULL;
+ int ret = -1;
+ int chunk = 0x4000; /* max chunk size to be used for these logs */
+
+ ret = nvme_get_log_simple(fd, id, sizeof(hdr), &hdr);
+ if (ret) {
+ fprintf(stderr, "pull hdr failed for %hhu with error: 0x%x\n", id, ret);
+ return ret;
+ }
+
+ if (hdr.id != id ||
+ hdr.log_size == 0 ||
+ hdr.max_size == 0 ||
+ hdr.write_pointer < sizeof(hdr))
+ {
+ fprintf(stderr, "invalid log data for LOG: 0x%X, id: 0x%X, size: %u, "
+ "max: %u, wp: %u, flags: %hhu, np: %u\n", id,
+ hdr.id, hdr.log_size, hdr.max_size, hdr.write_pointer,
+ hdr.flags, hdr.next_pointer);
+ return 1;
+ }
+
+ /* we may have just 32-bytes for some models; write to wfile if log hasn't
+ * yet reached its max size
+ */
+ if (hdr.log_size == sizeof(hdr)) {
+ buffer = (uint8_t *)malloc(sizeof(hdr));
+ if (buffer == NULL) {
+ fprintf(stderr, "malloc of %lu bytes failed for log: 0x%X\n",
+ sizeof(hdr), id);
+ return -ENOMEM;
+ }
+ memcpy(buffer,(uint8_t *)&hdr, sizeof(hdr));
+ } else if (hdr.log_size < hdr.max_size) {
+ buffer = (uint8_t *)malloc(sizeof(hdr) + hdr.log_size);
+ if (buffer == NULL) {
+ fprintf(stderr, "malloc of %lu bytes failed for log: 0x%X\n",
+ hdr.log_size + sizeof(hdr), id);
+ return -ENOMEM;
+ }
+ memcpy(buffer, &hdr, sizeof(hdr));
+ ret = nvme_get_log_lpo(fd, id, sizeof(hdr), chunk, hdr.log_size,
+ buffer + sizeof(hdr));
+ if (ret == 0) {
+ log_size += hdr.log_size;
+ }
+ } else if (hdr.log_size >= hdr.max_size) {
+ /* reached maximum, to maintain, sequence we need to depend on write
+ * pointer to detect wrap-overs. FW doesn't yet implement the condition
+ * hdr.log_size > hdr.max_size; also ignore over-written log data; we
+ * also ignore collisions for now
+ */
+ buffer = (uint8_t *)malloc(hdr.max_size + sizeof(hdr));
+ if (buffer == NULL) {
+ fprintf(stderr, "malloc of %lu bytes failed for log: 0x%X\n",
+ hdr.max_size + sizeof(hdr), id);
+ return -ENOMEM;
+ }
+ memcpy(buffer, &hdr, sizeof(hdr));
+
+ first = hdr.max_size - hdr.write_pointer;
+ second = hdr.write_pointer - sizeof(hdr);
+
+ if (first) {
+ ret = nvme_get_log_lpo(fd, id, hdr.write_pointer, chunk, first,
+ buffer + sizeof(hdr));
+ if (ret) {
+ free(buffer);
+ fprintf(stderr, "failed to get log: 0x%X\n", id);
+ return ret;
+ }
+ log_size += first;
+ }
+ if (second) {
+ ret = nvme_get_log_lpo(fd, id, sizeof(hdr), chunk, second,
+ buffer + sizeof(hdr) + first);
+ if (ret) {
+ fprintf(stderr, "failed to get log: 0x%X\n", id);
+ free(buffer);
+ return ret;
+ }
+ log_size += second;
+ }
+ }
+ *buf = buffer;
+ *size = log_size;
+ return ret;
+}
+
static int micron_internal_logs(int argc, char **argv, struct command *cmd,
struct plugin *plugin)
{
@@ -2747,7 +3020,7 @@ static int micron_internal_logs(int argc, char **argv, struct command *cmd,
struct nvme_id_ctrl ctrl;
char sn[20] = { 0 };
char msg[256] = { 0 };
-
+ int c_logs_index = 8; /* should be current size of aVendorLogs */
struct {
unsigned char ucLogPage;
const char *strFileName;
@@ -2788,6 +3061,16 @@ static int micron_internal_logs(int argc, char **argv, struct command *cmd,
{ 0xFE, "nvmelog_FE.bin", 4096, 256 * 1024 },
{ 0xFF, "nvmelog_FF.bin", 4096, 64 * 1024 },
{ 0xCA, "nvmelog_CA.bin", 512, 1024 }
+ },
+ aM51CXLogs[] = {
+ { 0xE1, "nvmelog_E1.bin", 0, 0 },
+ { 0xE2, "nvmelog_E2.bin", 0, 0 },
+ { 0xE3, "nvmelog_E3.bin", 0, 0 },
+ { 0xE4, "nvmelog_E4.bin", 0, 0 },
+ { 0xE5, "nvmelog_E5.bin", 0, 0 },
+ { 0xE8, "nvmelog_E8.bin", 0, 0 },
+ { 0xE9, "nvmelog_E9.bin", 0, 0 },
+ { 0xEA, "nvmelog_EA.bin", 0, 0 },
};
eDriveModel eModel;
@@ -2824,7 +3107,7 @@ static int micron_internal_logs(int argc, char **argv, struct command *cmd,
fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0)
- goto out;
+ return fd;
/* if telemetry type is specified, check for data area */
if (strlen(cfg.type) != 0) {
@@ -2832,19 +3115,16 @@ static int micron_internal_logs(int argc, char **argv, struct command *cmd,
cfg.log = 0x08;
} else if (strcmp(cfg.type, "host")) {
printf ("telemetry type (host or controller) should be specified i.e. -t=host\n");
- close(fd);
goto out;
}
if (cfg.data_area <= 0 || cfg.data_area > 3) {
printf ("data area must be selected using -d option ie --d=1,2,3\n");
- close(fd);
goto out;
}
telemetry_option = 1;
} else if (cfg.data_area > 0) {
printf ("data area option is valid only for telemetry option (i.e --type=host|controller)\n");
- close(fd);
goto out;
}
@@ -2860,7 +3140,6 @@ static int micron_internal_logs(int argc, char **argv, struct command *cmd,
sscanf(argv[optind], "/dev/nvme%d", &ctrlIdx);
if ((eModel = GetDriveModel(ctrlIdx)) == UNKNOWN_MODEL) {
printf ("Unsupported drive model for vs-internal-log collection\n");
- close(fd);
goto out;
}
@@ -2882,7 +3161,6 @@ static int micron_internal_logs(int argc, char **argv, struct command *cmd,
WriteData(buffer, logSize, dir, cfg.package, msg);
free(buffer);
}
- close(fd);
goto out;
}
@@ -2918,17 +3196,34 @@ static int micron_internal_logs(int argc, char **argv, struct command *cmd,
GetFeatureSettings(fd, strCtrlDirName);
if (eModel != M5410 && eModel != M5407) {
- memcpy(aVendorLogs, aM51XXLogs, sizeof(aM51XXLogs));
+ memcpy(&aVendorLogs[c_logs_index], aM51XXLogs, sizeof(aM51XXLogs));
+ c_logs_index += sizeof(aM51XXLogs)/sizeof(aM51XXLogs[0]);
if (eModel == M51AX)
- memcpy((char *)aVendorLogs + sizeof(aM51XXLogs), aM51AXLogs, sizeof(aM51AXLogs));
- else
- memcpy((char *)aVendorLogs + sizeof(aM51XXLogs), aM51BXLogs, sizeof(aM51BXLogs));
+ memcpy((char *)&aVendorLogs[c_logs_index], aM51AXLogs, sizeof(aM51AXLogs));
+ else if (eModel == M51BX)
+ memcpy((char *)&aVendorLogs[c_logs_index], aM51BXLogs, sizeof(aM51BXLogs));
+ else if (eModel == M51CX)
+ memcpy((char *)&aVendorLogs[c_logs_index], aM51CXLogs, sizeof(aM51CXLogs));
}
for (int i = 0; i < (int)(sizeof(aVendorLogs) / sizeof(aVendorLogs[0])) &&
aVendorLogs[i].ucLogPage != 0; i++) {
err = -1;
switch (aVendorLogs[i].ucLogPage) {
+ case 0xE1:
+ case 0xE5:
+ case 0xE9:
+ err = 1;
+ break;
+
+ case 0xE2:
+ case 0xE3:
+ case 0xE4:
+ case 0xE8:
+ case 0xEA:
+ err = get_common_log(fd, aVendorLogs[i].ucLogPage, &dataBuffer, &bSize);
+ break;
+
case 0xC1:
case 0xC2:
case 0xC4:
@@ -2964,9 +3259,11 @@ static int micron_internal_logs(int argc, char **argv, struct command *cmd,
case 0xF9:
case 0xFC:
case 0xFD:
- if (eModel == M51BX)
+ if (eModel == M51BX) {
(void)NVMEResetLog(fd, aVendorLogs[i].ucLogPage,
aVendorLogs[i].nLogSize, aVendorLogs[i].nMaxSize);
+ }
+ /* fallthrough */
default:
bSize = aVendorLogs[i].nLogSize;
dataBuffer = (unsigned char *)malloc(bSize);
@@ -3002,5 +3299,71 @@ static int micron_internal_logs(int argc, char **argv, struct command *cmd,
err = ZipAndRemoveDir(strMainDirName, cfg.package);
out:
+ close(fd);
+ return err;
+}
+
+#define MIN_LOG_SIZE 512
+static int micron_logpage_dir(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ int err = -1;
+ int fd = -1;
+ const char *desc = "List the supported log pages";
+ eDriveModel model = UNKNOWN_MODEL;
+ char logbuf[MIN_LOG_SIZE];
+ int i;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ if ((fd = micron_parse_options(argc, argv, desc, opts, &model)) < 0)
+ return err;
+
+ struct nvme_supported_logs {
+ uint8_t log_id;
+ uint8_t supported;
+ char *desc;
+ } log_list[] = {
+ {0x00, 0, "Support Log Pages"},
+ {0x01, 0, "Error Information"},
+ {0x02, 0, "SMART / Health Information"},
+ {0x03, 0, "Firmware Slot Information"},
+ {0x04, 0, "Changed Namespace List"},
+ {0x05, 0, "Commands Supported and Effects"},
+ {0x06, 0, "Device Self Test"},
+ {0x07, 0, "Telemetry Host-Initiated"},
+ {0x08, 0, "Telemetry Controller-Initiated"},
+ {0x09, 0, "Endurance Group Information"},
+ {0x0A, 0, "Predictable Latency Per NVM Set"},
+ {0x0B, 0, "Predictable Latency Event Aggregate"},
+ {0x0C, 0, "Asymmetric Namespace Access"},
+ {0x0D, 0, "Persistent Event Log"},
+ {0x0E, 0, "Predictable Latency Event Aggregate"},
+ {0x0F, 0, "Endurance Group Event Aggregate"},
+ {0x10, 0, "Media Unit Status"},
+ {0x11, 0, "Supported Capacity Configuration List"},
+ {0x12, 0, "Feature Identifiers Supported and Effects"},
+ {0x13, 0, "NVMe-MI Commands Supported and Effects"},
+ {0x14, 0, "Command and Feature lockdown"},
+ {0x15, 0, "Boot Partition"},
+ {0x16, 0, "Rotational Media Information"},
+ {0x70, 0, "Discovery"},
+ {0x80, 0, "Reservation Notification"},
+ {0x81, 0, "Sanitize Status"},
+ {0xC0, 0, "SMART Cloud Health Log"},
+ {0xC2, 0, "Firmware Activation History"},
+ {0xC3, 0, "Latency Monitor Log"},
+ };
+
+ printf("Supported log page list\nLog ID : Description\n");
+ for (i = 0; i < sizeof(log_list)/sizeof(log_list[0]); i++) {
+ err = nvme_get_log_simple(fd, log_list[i].log_id,
+ MIN_LOG_SIZE, &logbuf[0]);
+ if (err) continue;
+ printf("%02Xh : %s\n", log_list[i].log_id, log_list[i].desc);
+ }
+
return err;
}
diff --git a/plugins/micron/micron-nvme.h b/plugins/micron/micron-nvme.h
index c1b224e..4f7b892 100644
--- a/plugins/micron/micron-nvme.h
+++ b/plugins/micron/micron-nvme.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#undef CMD_INC_FILE
#define CMD_INC_FILE plugins/micron/micron-nvme
diff --git a/plugins/netapp/netapp-nvme.c b/plugins/netapp/netapp-nvme.c
index 9630442..b6bd3f6 100644
--- a/plugins/netapp/netapp-nvme.c
+++ b/plugins/netapp/netapp-nvme.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2018 NetApp, Inc.
*
@@ -103,12 +104,12 @@ static void netapp_nguid_to_str(char *str, __u8 *nguid)
str += sprintf(str, "%02x", nguid[i]);
}
-static void netapp_get_ns_size(char *size, long long *lba,
+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 = 1 << ns->lbaf[lba_index].ds;
+ *lba = 1ULL << ns->lbaf[lba_index].ds;
double nsze = le64_to_cpu(ns->nsze) * (*lba);
const char *s_suffix = suffix_si_get(&nsze);
@@ -263,7 +264,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);
- long long int lba = 1 << devices[i].ns.lbaf[lba_index].ds;
+ unsigned long long int 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];
@@ -302,7 +303,7 @@ static void netapp_ontapdevices_print(struct ontapdevice_info *devices,
struct json_object *json_devices = NULL;
char vsname[ONTAP_LABEL_LEN] = " ";
char nspath[ONTAP_NS_PATHLEN] = " ";
- long long lba;
+ unsigned long long lba;
char size[128];
char uuid_str[37] = " ";
int i;
@@ -392,8 +393,10 @@ static int netapp_smdevices_get_info(int fd, struct smdevice_info *item,
err = nvme_identify_ctrl(fd, &item->ctrl);
if (err) {
- fprintf(stderr, "Identify Controller failed to %s (%s)\n", dev,
- strerror(err));
+ fprintf(stderr,
+ "Identify Controller failed to %s (%s)\n", dev,
+ err < 0 ? strerror(-err) :
+ nvme_status_to_string(err, false));
return 0;
}
@@ -403,11 +406,13 @@ static int netapp_smdevices_get_info(int fd, struct smdevice_info *item,
err = nvme_get_nsid(fd, &item->nsid);
err = nvme_identify_ns(fd, item->nsid, &item->ns);
if (err) {
- fprintf(stderr, "Unable to identify namespace for %s (%s)\n",
- dev, strerror(err));
+ fprintf(stderr,
+ "Unable to identify namespace for %s (%s)\n",
+ dev, err < 0 ? strerror(-err) :
+ nvme_status_to_string(err, false));
return 0;
}
- strncpy(item->dev, dev, sizeof(item->dev));
+ strncpy(item->dev, dev, sizeof(item->dev) - 1);
return 1;
}
@@ -421,7 +426,8 @@ static int netapp_ontapdevices_get_info(int fd, struct ontapdevice_info *item,
err = nvme_identify_ctrl(fd, &item->ctrl);
if (err) {
fprintf(stderr, "Identify Controller failed to %s (%s)\n",
- dev, strerror(err));
+ dev, err < 0 ? strerror(-err) :
+ nvme_status_to_string(err, false));
return 0;
}
@@ -434,7 +440,8 @@ static int netapp_ontapdevices_get_info(int fd, struct ontapdevice_info *item,
err = nvme_identify_ns(fd, item->nsid, &item->ns);
if (err) {
fprintf(stderr, "Unable to identify namespace for %s (%s)\n",
- dev, strerror(err));
+ dev, err < 0 ? strerror(-err) :
+ nvme_status_to_string(err, false));
return 0;
}
@@ -446,7 +453,9 @@ static int netapp_ontapdevices_get_info(int fd, struct ontapdevice_info *item,
err = nvme_identify_ns_descs(fd, item->nsid, nsdescs);
if (err) {
fprintf(stderr, "Unable to identify namespace descriptor for %s (%s)\n",
- dev, strerror(err));
+ dev, err < 0 ? strerror(-err) :
+ nvme_status_to_string(err, false));
+ free(nsdescs);
return 0;
}
@@ -456,11 +465,12 @@ 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, strerror(err));
+ dev, err < 0 ? strerror(-err):
+ nvme_status_to_string(err, false));
return 0;
}
- strncpy(item->dev, dev, sizeof(item->dev));
+ strncpy(item->dev, dev, sizeof(item->dev) - 1);
return 1;
}
diff --git a/plugins/netapp/netapp-nvme.h b/plugins/netapp/netapp-nvme.h
index 2599db0..73de4b4 100644
--- a/plugins/netapp/netapp-nvme.h
+++ b/plugins/netapp/netapp-nvme.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#undef CMD_INC_FILE
#define CMD_INC_FILE plugins/netapp/netapp-nvme
diff --git a/plugins/nvidia/nvidia-nvme.c b/plugins/nvidia/nvidia-nvme.c
index 8ddd16f..71e0bc3 100644
--- a/plugins/nvidia/nvidia-nvme.c
+++ b/plugins/nvidia/nvidia-nvme.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
diff --git a/plugins/nvidia/nvidia-nvme.h b/plugins/nvidia/nvidia-nvme.h
index 74a20b8..3d870e1 100644
--- a/plugins/nvidia/nvidia-nvme.h
+++ b/plugins/nvidia/nvidia-nvme.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#undef CMD_INC_FILE
#define CMD_INC_FILE plugins/nvidia/nvidia-nvme
diff --git a/plugins/ocp/ocp-nvme.c b/plugins/ocp/ocp-nvme.c
index 6b7fc9d..56cfdff 100644
--- a/plugins/ocp/ocp-nvme.c
+++ b/plugins/ocp/ocp-nvme.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0-or-later
/* Copyright (c) 2022 Meta Platforms, Inc.
*
* Authors: Arthur Shau <arthurshau@fb.com>,
@@ -380,11 +380,6 @@ static int get_c0_log_page(int fd, char *format)
}
/* print the data */
- if (!data) {
- fprintf(stderr, "ERROR : OCP : Invalid buffer to read 0xC0 log\n");
- ret = -1;
- goto out;
- }
switch (fmt) {
case NORMAL:
ocp_print_C0_log_normal(data);
@@ -430,7 +425,7 @@ static int ocp_smart_add_log(int argc, char **argv, struct command *cmd,
if (ret)
fprintf(stderr, "ERROR : OCP : Failure reading the C0 Log Page, ret = %d\n",
ret);
-
+ close(fd);
return ret;
}
@@ -728,13 +723,6 @@ static int get_c3_log_page(int fd, char *format)
}
}
- /* print the data */
- if (!log_data) {
- fprintf(stderr,
- "ERROR : OCP : Invalid C3 log data buffer\n");
- ret = -1;
- goto out;
- }
switch (fmt) {
case NORMAL:
ocp_print_C3_log_normal(fd, log_data);
@@ -783,6 +771,6 @@ static int ocp_latency_monitor_log(int argc, char **argv, struct command *comman
fprintf(stderr,
"ERROR : OCP : Failure reading the C3 Log Page, ret = %d\n",
ret);
-
+ close(fd);
return ret;
}
diff --git a/plugins/ocp/ocp-nvme.h b/plugins/ocp/ocp-nvme.h
index 19378cd..3e3f437 100644
--- a/plugins/ocp/ocp-nvme.h
+++ b/plugins/ocp/ocp-nvme.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Copyright (c) 2022 Meta Platforms, Inc.
*
* Authors: Arthur Shau <arthurshau@fb.com>,
diff --git a/plugins/scaleflux/sfx-nvme.c b/plugins/scaleflux/sfx-nvme.c
index a6aaad5..0740e43 100644
--- a/plugins/scaleflux/sfx-nvme.c
+++ b/plugins/scaleflux/sfx-nvme.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
@@ -29,6 +30,12 @@
#define IDEMA_CAP(exp_GB) (((__u64)exp_GB - 50ULL) * 1953504ULL + 97696368ULL)
#define IDEMA_CAP2GB(exp_sector) (((__u64)exp_sector - 97696368ULL) / 1953504ULL + 50ULL)
+#define VANDA_MAJOR_IDX 0
+#define VANDA_MINOR_IDX 0
+
+#define MYRTLE_MAJOR_IDX 4
+#define MYRTLE_MINOR_IDX 1
+
enum {
SFX_LOG_LATENCY_READ_STATS = 0xc1,
SFX_LOG_SMART = 0xc2,
@@ -58,6 +65,7 @@ struct sfx_freespace_ctx
__u64 user_space; /* user required space, in unit of sector*/
__u64 hw_used; /* hw space used in 4K */
__u64 app_written; /* app data written in 4K */
+ __u64 out_of_space;
};
struct nvme_capacity_info {
@@ -66,25 +74,26 @@ struct nvme_capacity_info {
__u64 used_space;
__u64 free_space;
};
-struct __attribute__((packed)) nvme_additional_smart_log_item {
- uint8_t key;
- uint8_t _kp[2];
- uint8_t norm;
- uint8_t _np;
- union {
- uint8_t raw[6];
- struct wear_level {
- uint16_t min;
- uint16_t max;
- uint16_t avg;
- } wear_level ;
- struct thermal_throttle {
- uint8_t pct;
- uint32_t count;
+
+struct __attribute__((packed)) nvme_additional_smart_log_item {
+ __u8 key;
+ __u8 _kp[2];
+ __u8 norm;
+ __u8 _np;
+ union __attribute__((packed)) {
+ __u8 raw[6];
+ struct __attribute__((packed)) wear_level {
+ __le16 min;
+ __le16 max;
+ __le16 avg;
+ } wear_level;
+ struct __attribute__((packed)) thermal_throttle {
+ __u8 pct;
+ __u32 count;
} thermal_throttle;
- };
- uint8_t _rp;
-};
+ } ;
+ __u8 _rp;
+} ;
struct nvme_additional_smart_log {
struct nvme_additional_smart_log_item program_fail_cnt;
@@ -105,8 +114,26 @@ struct nvme_additional_smart_log {
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,
+ };
+
+ rc = ioctl(fd, SFX_GET_FREESPACE, data);
+ return rc == 0 ? 0 : nvme_submit_admin_passthru(fd, &cmd, NULL);
+}
int nvme_change_cap(int fd, __u32 nsid, __u64 capacity)
{
struct nvme_passthru_cmd cmd = {
@@ -255,6 +282,31 @@ static void show_sfx_smart_log_jsn(struct nvme_additional_smart_log *smart,
json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->read_ecc_cnt.raw));
json_object_add_value_object(dev_stats, "read_ecc_cnt", entry_stats);
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->non_media_crc_err_cnt.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->non_media_crc_err_cnt.raw));
+ json_object_add_value_object(dev_stats, "non_media_crc_err_cnt", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->compression_path_err_cnt.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->compression_path_err_cnt.raw));
+ json_object_add_value_object(dev_stats, "compression_path_err_cnt", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->out_of_space_flag.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->out_of_space_flag.raw));
+ json_object_add_value_object(dev_stats, "out_of_space_flag", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->physical_usage_ratio.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->physical_usage_ratio.raw));
+ json_object_add_value_object(dev_stats, "physical_usage_ratio", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->grown_bb.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->grown_bb.raw));
+ json_object_add_value_object(dev_stats, "grown_bb", entry_stats);
+
json_object_add_value_object(root, "Device stats", dev_stats);
json_print_object(root, NULL);
@@ -325,6 +377,22 @@ static void show_sfx_smart_log(struct nvme_additional_smart_log *smart,
printf("read_timeout_cnt : %3d%% %"PRIu64"\n",
smart->read_timeout_cnt.norm,
int48_to_long(smart->read_timeout_cnt.raw));
+ printf("non_media_crc_err_cnt : %3d%% %" PRIu64 "\n",
+ smart->non_media_crc_err_cnt.norm,
+ int48_to_long(smart->non_media_crc_err_cnt.raw));
+ printf("compression_path_err_cnt : %3d%% %" PRIu64 "\n",
+ smart->compression_path_err_cnt.norm,
+ int48_to_long(smart->compression_path_err_cnt.raw));
+ printf("out_of_space_flag : %3d%% %" PRIu64 "\n",
+ smart->out_of_space_flag.norm,
+ int48_to_long(smart->out_of_space_flag.raw));
+ printf("phy_capacity_used_ratio : %3d%% %" PRIu64 "\n",
+ smart->physical_usage_ratio.norm,
+ int48_to_long(smart->physical_usage_ratio.raw));
+ printf("grown_bb_count : %3d%% %" PRIu64 "\n",
+ smart->grown_bb.norm, int48_to_long(smart->grown_bb.raw));
+
+
}
static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
@@ -355,6 +423,9 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ return fd;
+ }
err = nvme_get_nsid_log(fd, false, 0xca, cfg.namespace_id,
sizeof(smart_log), (void *)&smart_log);
@@ -368,12 +439,13 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
}
else if (err > 0)
nvme_show_status(err);
+ close(fd);
return err;
}
-struct sfx_lat_stats {
- __u16 maj;
- __u16 min;
+struct __attribute__((__packed__)) sfx_lat_stats_vanda {
+ __u16 maj;
+ __u16 min;
__u32 bucket_1[32]; /* 0~1ms, step 32us */
__u32 bucket_2[31]; /* 1~32ms, step 1ms */
__u32 bucket_3[31]; /* 32ms~1s, step 32ms */
@@ -382,11 +454,50 @@ struct sfx_lat_stats {
__u32 bucket_6[1]; /* 4s+, specifically 4096ms+ */
};
-static void show_lat_stats(struct sfx_lat_stats *stats, int write)
+struct __attribute__((__packed__)) sfx_lat_stats_myrtle {
+ __u16 maj;
+ __u16 min;
+ __u32 bucket_1[64]; /* 0us~63us, step 1us */
+ __u32 bucket_2[64]; /* 63us~127us, step 1us */
+ __u32 bucket_3[64]; /* 127us~255us, step 2us */
+ __u32 bucket_4[64]; /* 255us~510us, step 4us */
+ __u32 bucket_5[64]; /* 510us~1.02ms step 8us */
+ __u32 bucket_6[64]; /* 1.02ms~2.04ms step 16us */
+ __u32 bucket_7[64]; /* 2.04ms~4.08ms step 32us */
+ __u32 bucket_8[64]; /* 4.08ms~8.16ms step 64us */
+ __u32 bucket_9[64]; /* 8.16ms~16.32ms step 128us */
+ __u32 bucket_10[64]; /* 16.32ms~32.64ms step 256us */
+ __u32 bucket_11[64]; /* 32.64ms~65.28ms step 512us */
+ __u32 bucket_12[64]; /* 65.28ms~130.56ms step 1.024ms */
+ __u32 bucket_13[64]; /* 130.56ms~261.12ms step 2.048ms */
+ __u32 bucket_14[64]; /* 261.12ms~522.24ms step 4.096ms */
+ __u32 bucket_15[64]; /* 522.24ms~1.04s step 8.192ms */
+ __u32 bucket_16[64]; /* 1.04s~2.09s step 16.384ms */
+ __u32 bucket_17[64]; /* 2.09s~4.18s step 32.768ms */
+ __u32 bucket_18[64]; /* 4.18s~8.36s step 65.536ms */
+ __u32 bucket_19[64]; /* 8.36s~ step 131.072ms */
+ __u64 average; /* average latency statistics */
+};
+
+
+struct __attribute__((__packed__)) sfx_lat_status_ver {
+ __u16 maj;
+ __u16 min;
+};
+
+struct sfx_lat_stats {
+ union {
+ struct sfx_lat_status_ver ver;
+ struct sfx_lat_stats_vanda vanda;
+ struct sfx_lat_stats_myrtle myrtle;
+ };
+};
+
+static void show_lat_stats_vanda(struct sfx_lat_stats_vanda *stats, int write)
{
int i;
- printf(" ScaleFlux IO %s Command Latency Statistics\n", write ? "Write" : "Read");
+ printf("ScaleFlux IO %s Command Latency Statistics\n", write ? "Write" : "Read");
printf("-------------------------------------\n");
printf("Major Revision : %u\n", stats->maj);
printf("Minor Revision : %u\n", stats->min);
@@ -413,6 +524,95 @@ static void show_lat_stats(struct sfx_lat_stats *stats, int write)
printf("Bucket %2d: %u\n", 0, stats->bucket_6[0]);
}
+static void show_lat_stats_myrtle(struct sfx_lat_stats_myrtle *stats, int write)
+{
+ int i;
+
+ printf("ScaleFlux IO %s Command Latency Statistics\n", write ? "Write" : "Read");
+ printf("-------------------------------------\n");
+ printf("Major Revision : %u\n", stats->maj);
+ printf("Minor Revision : %u\n", stats->min);
+
+ printf("\nGroup 1: Range is 0us~63us, step 1us\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_1[i]);
+
+ printf("\nGroup 2: Range is 63us~127us, step 1us\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_2[i]);
+
+ printf("\nGroup 3: Range is 127us~255us, step 2us\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_3[i]);
+
+ printf("\nGroup 4: Range is 255us~510us, step 4us\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_4[i]);
+
+ printf("\nGroup 5: Range is 510us~1.02ms step\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_5[i]);
+
+ printf("\nGroup 6: Range is 1.02ms~2.04ms step 16us\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_6[i]);
+
+ printf("\nGroup 7: Range is 2.04ms~4.08ms step 32us\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_7[i]);
+
+ printf("\nGroup 8: Range is 4.08ms~8.16ms step 64us\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_8[i]);
+
+ printf("\nGroup 9: Range is 8.16ms~16.32ms step 128us\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_9[i]);
+
+ printf("\nGroup 10: Range is 16.32ms~32.64ms step 256us\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_10[i]);
+
+ printf("\nGroup 11: Range is 32.64ms~65.28ms step 512us\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_11[i]);
+
+ printf("\nGroup 12: Range is 65.28ms~130.56ms step 1.024ms\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_12[i]);
+
+ printf("\nGroup 13: Range is 130.56ms~261.12ms step 2.048ms\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_13[i]);
+
+ printf("\nGroup 14: Range is 261.12ms~522.24ms step 4.096ms\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_14[i]);
+
+ printf("\nGroup 15: Range is 522.24ms~1.04s step 8.192ms\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_15[i]);
+
+ printf("\nGroup 16: Range is 1.04s~2.09s step 16.384ms\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_16[i]);
+
+ printf("\nGroup 17: Range is 2.09s~4.18s step 32.768ms\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_17[i]);
+
+ printf("\nGroup 18: Range is 4.18s~8.36s step 65.536ms\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_18[i]);
+
+ printf("\nGroup 19: Range is 8.36s~ step 131.072ms\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_19[i]);
+
+ printf("\nAverage latency statistics %lld\n", stats->average);
+}
+
+
static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
struct sfx_lat_stats stats;
@@ -436,15 +636,31 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct
};
fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ return fd;
+ }
err = nvme_get_log_simple(fd, cfg.write ? 0xc3 : 0xc1, sizeof(stats), (void *)&stats);
if (!err) {
- if (!cfg.raw_binary)
- show_lat_stats(&stats, cfg.write);
- else
- d_raw((unsigned char *)&stats, sizeof(stats));
+ if ((stats.ver.maj == VANDA_MAJOR_IDX) && (stats.ver.min == VANDA_MINOR_IDX)) {
+ if (!cfg.raw_binary) {
+ show_lat_stats_vanda(&stats.vanda, cfg.write);
+ } 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) {
+ show_lat_stats_myrtle(&stats.myrtle, cfg.write);
+ } 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",
+ write ? "Write" : "Read", stats.ver.maj, stats.ver.min);
+ }
} else if (err > 0)
nvme_show_status(err);
+ close(fd);
return err;
}
@@ -560,7 +776,6 @@ static int sfx_get_bad_block(int argc, char **argv, struct command *cmd, struct
};
fd = parse_and_open(argc, argv, desc, opts);
-
if (fd < 0) {
return fd;
}
@@ -568,6 +783,7 @@ static int sfx_get_bad_block(int argc, char **argv, struct command *cmd, struct
data_buf = malloc(buf_size);
if (!data_buf) {
fprintf(stderr, "malloc fail, errno %d\r\n", errno);
+ close(fd);
return -1;
}
@@ -582,6 +798,7 @@ static int sfx_get_bad_block(int argc, char **argv, struct command *cmd, struct
}
free(data_buf);
+ close(fd);
return 0;
}
@@ -603,18 +820,15 @@ static int query_cap_info(int argc, char **argv, struct command *cmd, struct plu
{
struct sfx_freespace_ctx ctx = { 0 };
int err = 0, fd;
- char *desc = "query current capacity info of vanda";
+ char *desc = "query current capacity info";
const char *raw = "dump output in binary format";
- const char *json= "Dump output in json format";
struct config {
bool raw_binary;
- bool json;
};
struct config cfg;
OPT_ARGS(opts) = {
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
- OPT_FLAG("json", 'j', &cfg.json, json),
OPT_END()
};
@@ -623,12 +837,19 @@ static int query_cap_info(int argc, char **argv, struct command *cmd, struct plu
return fd;
}
- if (ioctl(fd, SFX_GET_FREESPACE, &ctx)) {
- fprintf(stderr, "vu ioctl fail, errno %d\r\n", errno);
- return -1;
+ if (nvme_query_cap(fd, 0xffffffff, sizeof(ctx), &ctx)) {
+ perror("sfx-query-cap");
+ err = -1;
}
- show_cap_info(&ctx);
+ if (!err) {
+ if (!cfg.raw_binary) {
+ show_cap_info(&ctx);
+ } else {
+ d_raw((unsigned char *)&ctx, sizeof(ctx));
+ }
+ }
+ close(fd);
return err;
}
@@ -639,14 +860,10 @@ static int change_sanity_check(int fd, __u64 trg_in_4k, int *shrink)
__u64 mem_need = 0;
__u64 cur_in_4k = 0;
__u64 provisoned_cap_4k = 0;
- __u32 cnt_ms = 0;
int extend = 0;
- while (ioctl(fd, SFX_GET_FREESPACE, &freespace_ctx)) {
- if (cnt_ms++ > 600) {//1min
- return -1;
- }
- usleep(100000);
+ if (nvme_query_cap(fd, 0xffffffff, sizeof(freespace_ctx), &freespace_ctx)) {
+ return -1;
}
/*
@@ -706,12 +923,12 @@ static int change_sanity_check(int fd, __u64 trg_in_4k, int *shrink)
*/
static int sfx_confirm_change(const char *str)
{
- char confirm;
+ unsigned char confirm;
fprintf(stderr, "WARNING: %s.\n"
"Use the force [--force] option to suppress this warning.\n", str);
fprintf(stderr, "Confirm Y/y, Others cancel:\n");
- confirm = fgetc(stdin);
+ confirm = (unsigned char)fgetc(stdin);
if (confirm != 'y' && confirm != 'Y') {
fprintf(stderr, "Cancled.\n");
return 0;
@@ -723,9 +940,7 @@ static int sfx_confirm_change(const char *str)
static int change_cap(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
int err = -1, fd;
- char *desc = "query current capacity info of vanda";
- const char *raw = "dump output in binary format";
- const char *json= "Dump output in json format";
+ char *desc = "dynamic change capacity";
const char *cap_gb = "cap size in GB";
const char *cap_byte = "cap size in byte";
const char *force = "The \"I know what I'm doing\" flag, skip confirmation before sending command";
@@ -736,8 +951,6 @@ static int change_cap(int argc, char **argv, struct command *cmd, struct plugin
struct config {
__u64 cap_in_byte;
__u32 capacity_in_gb;
- bool raw_binary;
- bool json;
bool force;
};
@@ -751,8 +964,6 @@ static int change_cap(int argc, char **argv, struct command *cmd, struct plugin
OPT_UINT("cap", 'c', &cfg.capacity_in_gb, cap_gb),
OPT_SUFFIX("cap-byte", 'z', &cfg.cap_in_byte, cap_byte),
OPT_FLAG("force", 'f', &cfg.force, force),
- OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
- OPT_FLAG("json", 'j', &cfg.json, json),
OPT_END()
};
@@ -770,10 +981,12 @@ static int change_cap(int argc, char **argv, struct command *cmd, struct plugin
if (change_sanity_check(fd, cap_in_4k, &shrink)) {
printf("ScaleFlux change-capacity: fail\n");
+ close(fd);
return err;
}
if (!cfg.force && shrink && !sfx_confirm_change("Changing Cap may irrevocably delete this device's data")) {
+ close(fd);
return 0;
}
@@ -786,6 +999,7 @@ static int change_cap(int argc, char **argv, struct command *cmd, struct plugin
printf("ScaleFlux change-capacity: success\n");
ioctl(fd, BLKRRPART);
}
+ close(fd);
return err;
}
@@ -877,12 +1091,14 @@ 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");
+ close(fd);
return EINVAL;
}
if (cfg.feature_id == SFX_FEAT_CLR_CARD) {
/*Warning for clean card*/
if (!cfg.force && !sfx_confirm_change("Going to clean device's data, confirm umount fs and try again")) {
+ close(fd);
return 0;
} else {
return sfx_clean_card(fd);
@@ -898,6 +1114,7 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl
perror("identify-namespace");
else
nvme_show_status(err);
+ close(fd);
return err;
}
/*
@@ -905,17 +1122,20 @@ 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");
+ close(fd);
return EFAULT;
}
}
} else if (cfg.feature_id == SFX_FEAT_UP_P_CAP) {
if (cfg.value <= 0) {
fprintf(stderr, "Invalid Param\n");
+ close(fd);
return EINVAL;
}
/*Warning for change pacp by GB*/
if (!cfg.force && !sfx_confirm_change("Changing physical capacity may irrevocably delete this device's data")) {
+ close(fd);
return 0;
}
}
@@ -924,6 +1144,7 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl
if (err < 0) {
perror("ScaleFlux-set-feature");
+ close(fd);
return errno;
} else if (!err) {
printf("ScaleFlux set-feature:%#02x (%s), value:%d\n", cfg.feature_id,
@@ -931,6 +1152,7 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl
} else if (err > 0)
nvme_show_status(err);
+ close(fd);
return err;
}
@@ -959,19 +1181,20 @@ static int sfx_get_feature(int argc, char **argv, struct command *cmd, struct pl
};
fd = parse_and_open(argc, argv, desc, opts);
-
if (fd < 0) {
return fd;
}
if (!cfg.feature_id) {
fprintf(stderr, "feature-id required param\n");
+ close(fd);
return EINVAL;
}
err = nvme_sfx_get_features(fd, cfg.namespace_id, cfg.feature_id, &result);
if (err < 0) {
perror("ScaleFlux-get-feature");
+ close(fd);
return errno;
} else if (!err) {
printf("ScaleFlux get-feature:%02x (%s), value:%d\n", cfg.feature_id,
@@ -979,6 +1202,7 @@ static int sfx_get_feature(int argc, char **argv, struct command *cmd, struct pl
} else if (err > 0)
nvme_show_status(err);
+ close(fd);
return err;
}
diff --git a/plugins/scaleflux/sfx-nvme.h b/plugins/scaleflux/sfx-nvme.h
index fde5ba3..0b95d92 100644
--- a/plugins/scaleflux/sfx-nvme.h
+++ b/plugins/scaleflux/sfx-nvme.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#undef CMD_INC_FILE
#define CMD_INC_FILE plugins/scaleflux/sfx-nvme
diff --git a/plugins/seagate/seagate-diag.h b/plugins/seagate/seagate-diag.h
index 3dc2df7..139901d 100644
--- a/plugins/seagate/seagate-diag.h
+++ b/plugins/seagate/seagate-diag.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Do NOT modify or remove this copyright and license
*
diff --git a/plugins/seagate/seagate-nvme.c b/plugins/seagate/seagate-nvme.c
index 5f6ce90..516cb1e 100644
--- a/plugins/seagate/seagate-nvme.c
+++ b/plugins/seagate/seagate-nvme.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Do NOT modify or remove this copyright and license
*
@@ -147,6 +148,7 @@ static void json_log_pages_supp(log_page_map *logPageMap)
}
json_print_object(root, NULL);
printf("\n");
+ json_free_object(root);
}
static int log_pages_supp(int argc, char **argv, struct command *cmd,
@@ -174,6 +176,8 @@ static int log_pages_supp(int argc, char **argv, struct command *cmd,
};
fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
err = nvme_get_log_simple(fd, 0xc5, sizeof(logPageMap), &logPageMap);
if (!err) {
if (strcmp(cfg.output_format,"json")) {
@@ -199,6 +203,7 @@ static int log_pages_supp(int argc, char **argv, struct command *cmd,
if (err > 0)
nvme_show_status(err);
+ close(fd);
return err;
}
@@ -732,6 +737,11 @@ static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugi
};
fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ printf ("\nDevice not found \n");
+ return -1;
+ }
+
if (strcmp(cfg.output_format,"json"))
printf("Seagate Extended SMART Information :\n");
@@ -774,6 +784,7 @@ static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugi
} else if (err > 0)
nvme_show_status(err);
+ close(fd);
return err;
}
@@ -889,6 +900,7 @@ static int temp_stats(int argc, char **argv, struct command *cmd, struct plugin
if(!strcmp(cfg.output_format,"json"))
json_temp_stats(temperature, PcbTemp, SocTemp, maxTemperature, MaxSocTemp, cf_err, scCurrentTemp, scMaxTemp);
+ close(fd);
return err;
}
/* EOF Temperature Stats information */
@@ -1000,6 +1012,11 @@ static int vs_pcie_error_log(int argc, char **argv, struct command *cmd, struct
};
fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ printf ("\nDevice not found \n");;
+ return -1;
+ }
+
if(strcmp(cfg.output_format,"json"))
printf("Seagate PCIe error counters Information :\n");
@@ -1013,6 +1030,7 @@ static int vs_pcie_error_log(int argc, char **argv, struct command *cmd, struct
} else if (err > 0)
nvme_show_status(err);
+ close(fd);
return err;
}
/* EOF PCIE error-log information */
@@ -1038,14 +1056,18 @@ static int vs_clr_pcie_correctable_errs(int argc, char **argv, struct command *c
};
fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ printf ("\nDevice not found \n");;
+ return -1;
+ }
err = nvme_set_features_simple(fd, 0xE1, 0, 0xCB, cfg.save, &result);
if (err < 0) {
perror("set-feature");
- return errno;
}
+ close(fd);
return err;
}
@@ -1113,19 +1135,25 @@ static int get_host_tele(int argc, char **argv, struct command *cmd, struct plug
blkCnt = 0;
while(blkCnt < maxBlk) {
+ unsigned long long bytesToGet;
+
blksToGet = ((maxBlk - blkCnt) >= TELEMETRY_BLOCKS_TO_READ) ? TELEMETRY_BLOCKS_TO_READ : (maxBlk - blkCnt);
- if(blksToGet == 0)
+ if(blksToGet == 0) {
+ close(fd);
return err;
+ }
- log = malloc(blksToGet * 512);
+ bytesToGet = (unsigned long long)blksToGet * 512;
+ log = malloc(bytesToGet);
if (!log) {
fprintf(stderr, "could not alloc buffer for log\n");
+ close(fd);
return EINVAL;
}
- memset(log, 0, blksToGet * 512);
+ memset(log, 0, bytesToGet);
struct nvme_get_log_args args = {
.args_size = sizeof(args),
@@ -1139,21 +1167,21 @@ static int get_host_tele(int argc, char **argv, struct command *cmd, struct plug
.uuidx = 0,
.csi = NVME_CSI_NVM,
.ot = false,
- .len = blksToGet * 512,
+ .len = bytesToGet,
.log = (void *)log,
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
.result = NULL,
};
err = nvme_get_log(&args);
if (!err) {
- offset += blksToGet * 512;
+ offset += (__le64)bytesToGet;
if (!cfg.raw_binary) {
printf("\nBlock # :%d to %d\n", blkCnt + 1, blkCnt + blksToGet);
- d((unsigned char *)log, blksToGet * 512, 16, 1);
+ d((unsigned char *)log, bytesToGet, 16, 1);
} else
- seaget_d_raw((unsigned char *)log, blksToGet * 512, dump_fd);
+ seaget_d_raw((unsigned char *)log, bytesToGet, dump_fd);
} else if (err > 0)
nvme_show_status(err);
else
@@ -1164,6 +1192,7 @@ static int get_host_tele(int argc, char **argv, struct command *cmd, struct plug
free(log);
}
+ close(fd);
return err;
}
@@ -1225,19 +1254,22 @@ static int get_ctrl_tele(int argc, char **argv, struct command *cmd, struct plug
blkCnt = 0;
while(blkCnt < maxBlk) {
+ unsigned long long bytesToGet;
+
blksToGet = ((maxBlk - blkCnt) >= TELEMETRY_BLOCKS_TO_READ) ? TELEMETRY_BLOCKS_TO_READ : (maxBlk - blkCnt);
if(blksToGet == 0)
return err;
- log = malloc(blksToGet * 512);
+ bytesToGet = (unsigned long long)blksToGet * 512;
+ log = malloc(bytesToGet);
if (!log) {
fprintf(stderr, "could not alloc buffer for log\n");
return EINVAL;
}
- memset(log, 0, blksToGet * 512);
+ memset(log, 0, bytesToGet);
struct nvme_get_log_args args = {
.args_size = sizeof(args),
@@ -1251,21 +1283,21 @@ static int get_ctrl_tele(int argc, char **argv, struct command *cmd, struct plug
.uuidx = 0,
.csi = NVME_CSI_NVM,
.ot = false,
- .len = blksToGet * 512,
+ .len = bytesToGet,
.log = (void *)log,
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
.result = NULL,
};
err = nvme_get_log(&args);
if (!err) {
- offset += blksToGet * 512;
+ offset += (__le64)bytesToGet;
if (!cfg.raw_binary) {
printf("\nBlock # :%d to %d\n", blkCnt + 1, blkCnt + blksToGet);
- d((unsigned char *)log, blksToGet * 512, 16, 1);
+ d((unsigned char *)log, bytesToGet, 16, 1);
} else
- seaget_d_raw((unsigned char *)log, blksToGet * 512, dump_fd);
+ seaget_d_raw((unsigned char *)log, bytesToGet, dump_fd);
} else if (err > 0)
nvme_show_status(err);
else
@@ -1275,8 +1307,9 @@ static int get_ctrl_tele(int argc, char **argv, struct command *cmd, struct plug
free(log);
}
- return err;
+ close(fd);
+ return err;
}
void seaget_d_raw(unsigned char *buf, int len, int fd)
@@ -1334,6 +1367,7 @@ static int vs_internal_log(int argc, char **argv, struct command *cmd, struct pl
dump_fd = open(cfg.file, flags, mode);
if (dump_fd < 0) {
perror(cfg.file);
+ close(fd);
return EINVAL;
}
}
@@ -1358,20 +1392,24 @@ static int vs_internal_log(int argc, char **argv, struct command *cmd, struct pl
blkCnt = 0;
while(blkCnt < maxBlk) {
+ unsigned long long bytesToGet;
+
blksToGet = ((maxBlk - blkCnt) >= TELEMETRY_BLOCKS_TO_READ) ? TELEMETRY_BLOCKS_TO_READ : (maxBlk - blkCnt);
if(blksToGet == 0) {
- return err;
+ goto out;
}
- log = malloc(blksToGet * 512);
+ bytesToGet = (unsigned long long)blksToGet * 512;
+ log = malloc(bytesToGet);
if (!log) {
fprintf(stderr, "could not alloc buffer for log\n");
- return EINVAL;
+ err = EINVAL;
+ goto out;
}
- memset(log, 0, blksToGet * 512);
+ memset(log, 0, bytesToGet);
struct nvme_get_log_args args = {
.args_size = sizeof(args),
@@ -1385,16 +1423,16 @@ static int vs_internal_log(int argc, char **argv, struct command *cmd, struct pl
.uuidx = 0,
.csi = NVME_CSI_NVM,
.ot = false,
- .len = blksToGet * 512,
+ .len = bytesToGet,
.log = (void *)log,
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
.result = NULL,
};
err = nvme_get_log(&args);
if (!err) {
- offset += blksToGet * 512;
+ offset += (__le64)bytesToGet;
- seaget_d_raw((unsigned char *)log, blksToGet * 512, dump_fd);
+ seaget_d_raw((unsigned char *)log, bytesToGet, dump_fd);
} else if (err > 0)
nvme_show_status(err);
@@ -1405,10 +1443,11 @@ static int vs_internal_log(int argc, char **argv, struct command *cmd, struct pl
free(log);
}
-
+out:
if(strlen(cfg.file))
close(dump_fd);
+ close(fd);
return err;
}
diff --git a/plugins/seagate/seagate-nvme.h b/plugins/seagate/seagate-nvme.h
index a4989f1..6df1331 100644
--- a/plugins/seagate/seagate-nvme.h
+++ b/plugins/seagate/seagate-nvme.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Do NOT modify or remove this copyright and license
*
diff --git a/plugins/shannon/shannon-nvme.c b/plugins/shannon/shannon-nvme.c
index d79b119..220638f 100644
--- a/plugins/shannon/shannon-nvme.c
+++ b/plugins/shannon/shannon-nvme.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
@@ -137,6 +138,8 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
};
fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
err = nvme_get_nsid_log(fd, false, 0xca, cfg.namespace_id,
sizeof(smart_log), &smart_log);
if (!err) {
@@ -147,6 +150,7 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
}
else if (err > 0)
nvme_show_status(err);
+ close(fd);
return err;
}
@@ -156,7 +160,7 @@ static int get_additional_feature(int argc, char **argv, struct command *cmd, st
"specified controller. Operating parameters are grouped "\
"and identified by Feature Identifiers; each Feature "\
"Identifier contains one or more attributes that may affect "\
- "behaviour of the feature. Each Feature has three possible "\
+ "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 "\
diff --git a/plugins/shannon/shannon-nvme.h b/plugins/shannon/shannon-nvme.h
index 46fc697..255bb6b 100644
--- a/plugins/shannon/shannon-nvme.h
+++ b/plugins/shannon/shannon-nvme.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#undef CMD_INC_FILE
#define CMD_INC_FILE plugins/shannon/shannon-nvme
diff --git a/plugins/solidigm/meson.build b/plugins/solidigm/meson.build
new file mode 100644
index 0000000..fb0f6a9
--- /dev/null
+++ b/plugins/solidigm/meson.build
@@ -0,0 +1,5 @@
+sources += [
+ 'plugins/solidigm/solidigm-smart.c',
+ 'plugins/solidigm/solidigm-garbage-collection.c',
+ 'plugins/solidigm/solidigm-latency-tracking.c',
+]
diff --git a/plugins/solidigm/solidigm-garbage-collection.c b/plugins/solidigm/solidigm-garbage-collection.c
new file mode 100644
index 0000000..c7f1286
--- /dev/null
+++ b/plugins/solidigm/solidigm-garbage-collection.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "linux/types.h"
+#include "nvme-print.h"
+#include "solidigm-garbage-collection.h"
+
+typedef struct __attribute__((packed)) gc_item {
+ __le32 timer_type;
+ __le64 timestamp;
+} gc_item_t;
+
+#define VU_GC_MAX_ITEMS 100
+typedef struct garbage_control_collection_log {
+ __le16 version_major;
+ __le16 version_minor;
+ gc_item_t 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)
+{
+ 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 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);
+ }
+
+ json_print_object(gc_entries, NULL);
+ json_free_object(gc_entries);
+}
+
+static void vu_gc_log_show(garbage_control_collection_log_t *payload, const char *devname)
+{
+ printf("Solidigm Garbage Collection Log for NVME device: %s\n", devname);
+ printf("Timestamp Timer Type\n");
+
+ for (int i = 0; i < VU_GC_MAX_ITEMS; i++) {
+ gc_item_t item = payload->item[i];
+ printf("%-13lu %d\n",le64_to_cpu(item.timestamp), le32_to_cpu(item.timer_type));
+ }
+}
+
+int solidigm_get_garbage_collection_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Get and parse Solidigm vendor specific garbage collection event log.";
+
+ struct config {
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_END()
+ };
+
+ int fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ return fd;
+ }
+
+ enum nvme_print_flags flags = validate_output_format(cfg.output_format);
+ if (flags == -EINVAL) {
+ fprintf(stderr, "Invalid output format '%s'\n", cfg.output_format);
+ close(fd);
+ return fd;
+ }
+
+ garbage_control_collection_log_t gc_log;
+ const int solidigm_vu_gc_log_id = 0xfd;
+
+ int err = nvme_get_log_simple(fd, solidigm_vu_gc_log_id, sizeof(gc_log), &gc_log);
+ if (!err) {
+ if (flags & BINARY) {
+ d_raw((unsigned char *)&gc_log, sizeof(gc_log));
+ } else if (flags & JSON) {
+ vu_gc_log_show_json(&gc_log, devicename);
+ } else {
+ vu_gc_log_show(&gc_log, devicename);
+ }
+ }
+ else if (err > 0) {
+ nvme_show_status(err);
+ }
+
+ close(fd);
+ return err;
+}
diff --git a/plugins/solidigm/solidigm-garbage-collection.h b/plugins/solidigm/solidigm-garbage-collection.h
new file mode 100644
index 0000000..a3e34b2
--- /dev/null
+++ b/plugins/solidigm/solidigm-garbage-collection.h
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+int solidigm_get_garbage_collection_log(int argc, char **argv, struct command *cmd, struct plugin *plugin);
diff --git a/plugins/solidigm/solidigm-latency-tracking.c b/plugins/solidigm/solidigm-latency-tracking.c
new file mode 100644
index 0000000..0bfd611
--- /dev/null
+++ b/plugins/solidigm/solidigm-latency-tracking.c
@@ -0,0 +1,470 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "linux/types.h"
+#include "nvme-print.h"
+
+#define BUCKET_LIST_SIZE_4_0 152
+#define BUCKET_LIST_SIZE_4_1 1216
+
+#define BASE_RANGE_BITS_4_0 3
+#define BASE_RANGE_BITS_4_1 6
+
+struct latency_statistics {
+ __u16 version_major;
+ __u16 version_minor;
+ __u32 data[BUCKET_LIST_SIZE_4_1];
+ __u64 average_latency;
+};
+
+struct config {
+ bool enable;
+ bool disable;
+ bool read;
+ bool write;
+ unsigned char type;
+ char *output_format;
+};
+
+struct latency_tracker {
+ int fd;
+ struct config cfg;
+ enum nvme_print_flags print_flags;
+ struct latency_statistics stats;
+ struct json_object *bucket_list;
+ __u32 bucket_list_size;
+ __u8 base_range_bits;
+ bool has_average_latency_field;
+};
+
+/* COL_WIDTH controls width of columns in NORMAL output. */
+#define COL_WIDTH 12
+#define BUCKET_LABEL_MAX_SIZE 10
+
+#define US_IN_S 1000000
+#define US_IN_MS 1000
+
+/*
+ * Edge buckets may have range [#s, inf) in some
+ * latency statistics formats.
+ */
+static void get_time_unit_label(char *label, __u32 microseconds,
+ bool bonded)
+{
+ char *string = "us";
+ int divisor = 1;
+
+ if (!bonded) {
+ snprintf(label, BUCKET_LABEL_MAX_SIZE, "%s", "+INF");
+ return;
+ }
+
+ if (microseconds > US_IN_S) {
+ string = "s";
+ divisor = US_IN_S;
+ } else if (microseconds > US_IN_MS) {
+ string = "ms";
+ divisor = US_IN_MS;
+ }
+
+ snprintf(label, BUCKET_LABEL_MAX_SIZE, "%4.2f%s", (float) microseconds / divisor,
+ string);
+}
+
+static void latency_tracker_bucket_parse(const struct latency_tracker *lt, int id,
+ __u32 lower_us, __u32 upper_us, bool upper_bounded)
+{
+ char buffer[BUCKET_LABEL_MAX_SIZE] = "";
+ __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);
+ printf("%-*s", COL_WIDTH, buffer);
+
+ get_time_unit_label(buffer, upper_us, upper_bounded);
+ printf("%-*s", COL_WIDTH, buffer);
+
+ printf("%-*d\n", COL_WIDTH, bucket_data);
+ }
+
+ if (lt->print_flags == JSON) {
+ /*
+ * Creates a bucket under the "values" json_object. Format is:
+ * "values" : {
+ * "bucket" : {
+ * "id" : #,
+ * "start" : string,
+ * "end" : string,
+ * "value" : 0,
+ * },
+ */
+ struct json_object *bucket = json_create_object();
+
+ json_object_array_add(lt->bucket_list, bucket);
+ json_object_add_value_int(bucket, "id", id);
+
+ get_time_unit_label(buffer, lower_us, true);
+ json_object_add_value_string(bucket, "start", buffer);
+
+ get_time_unit_label(buffer, upper_us, upper_bounded);
+ json_object_add_value_string(bucket, "end", buffer);
+
+ json_object_add_value_int(bucket, "value", bucket_data);
+ }
+}
+
+static void latency_tracker_parse_linear(const struct latency_tracker *lt,
+ __u32 start_offset, __u32 end_offset,
+ __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)
+ continue;
+ latency_tracker_bucket_parse(lt, i, us_step * i,
+ us_step * (i + 1), true);
+ }
+}
+
+/*
+ * Calculates bucket time slot. Valid starting on 4.0 revision.
+ */
+
+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;
+
+ int error_bits = (i >> lt->base_range_bits) - 1;
+ int base = 1 << (error_bits + lt->base_range_bits);
+ int k = i % base_val;
+
+ return base + ((k + 0.5) * (1 << error_bits));
+}
+
+/*
+ * Creates a subroot in the following manner:
+ * {
+ * "latstats" : {
+ * "type" : "write" or "read",
+ * "values" : {
+ */
+static void latency_tracker_populate_json_root(const struct latency_tracker *lt,
+ 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));
+ }
+ json_object_add_value_object(subroot, "values", lt->bucket_list);
+}
+
+static void latency_tracker_parse_3_0(const struct latency_tracker *lt)
+{
+ latency_tracker_parse_linear(lt, 4, 131, 4, 32, false);
+ latency_tracker_parse_linear(lt, 132, 255, 4, 1024, false);
+ latency_tracker_parse_linear(lt, 256, 379, 4, 32768, false);
+ latency_tracker_parse_linear(lt, 380, 383, 4, 32, true);
+ latency_tracker_parse_linear(lt, 384, 387, 4, 32, true);
+ latency_tracker_parse_linear(lt, 388, 391, 4, 32, true);
+}
+
+static void latency_tracker_parse_4_0(const struct latency_tracker *lt)
+{
+ for (unsigned int i = 0; i < lt->bucket_list_size; i++) {
+ 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,
+ i < (lt->bucket_list_size - 1));
+ }
+}
+
+static void print_dash_separator()
+{
+ printf("--------------------------------------------------\n");
+}
+
+static void latency_tracker_pre_parse(struct latency_tracker *lt)
+{
+ if (lt->print_flags == NORMAL) {
+ printf("Solidigm IO %s Command Latency Tracking Statistics type %d\n",
+ lt->cfg.write ? "Write" : "Read", lt->cfg.type);
+ 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) {
+ printf("Average Latency: %lu\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) {
+ lt->bucket_list = json_object_new_array();
+ }
+}
+
+static void latency_tracker_post_parse(struct latency_tracker *lt)
+{
+ if (lt->print_flags == JSON) {
+ struct json_object *root = json_create_object();
+
+ latency_tracker_populate_json_root(lt, root);
+ json_print_object(root, NULL);
+ json_free_object(root);
+ printf("\n");
+ }
+}
+
+static void latency_tracker_parse(struct latency_tracker *lt)
+{
+ __u16 version_major = le16_to_cpu(lt->stats.version_major);
+ __u16 version_minor = le16_to_cpu(lt->stats.version_minor);
+
+ switch (version_major) {
+ case 3:
+ latency_tracker_pre_parse(lt);
+ latency_tracker_parse_3_0(lt);
+ break;
+ case 4:
+ if (version_minor >= 8){
+ lt->has_average_latency_field = true;
+ }
+ latency_tracker_pre_parse(lt);
+ if (version_minor == 0){
+ lt->base_range_bits = BASE_RANGE_BITS_4_0;
+ lt->bucket_list_size = BUCKET_LIST_SIZE_4_0;
+ }
+ latency_tracker_parse_4_0(lt);
+ break;
+ default:
+ printf("Unsupported revision (%u.%u)\n",
+ version_major, version_minor);
+ break;
+ }
+
+ latency_tracker_post_parse(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)
+{
+ struct nvme_get_features_args args_get = {
+ .args_size = sizeof(args_get),
+ .fd = lt->fd,
+ .fid = LATENCY_TRACKING_FID,
+ .nsid = 0,
+ .sel = 0,
+ .cdw11 = 0,
+ .uuidx = 0,
+ .data_len = LATENCY_TRACKING_FID_DATA_LEN,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = enabled,
+ };
+ return nvme_get_features(&args_get);
+}
+
+static int latency_tracking_enable(struct latency_tracker *lt)
+{
+ __u32 result;
+ int err;
+
+ 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;
+ }
+
+ struct nvme_set_features_args args_set = {
+ .args_size = sizeof(args_set),
+ .fd = lt->fd,
+ .fid = LATENCY_TRACKING_FID,
+ .nsid = 0,
+ .cdw11 = lt->cfg.enable,
+ .cdw12 = 0,
+ .save = 0,
+ .uuidx = 0,
+ .cdw15 = 0,
+ .data_len = LATENCY_TRACKING_FID_DATA_LEN,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ err = nvme_set_features(&args_set);
+ if (err > 0) {
+ nvme_show_status(err);
+ } else if (err < 0) {
+ perror("Enable latency tracking");
+ fprintf(stderr, "Command failed while parsing.\n");
+ } else {
+ if (lt->print_flags == NORMAL) {
+ printf("Successfully set enable bit for FID (0x%X) to %i.\n",
+ LATENCY_TRACKING_FID, lt->cfg.enable);
+ }
+ }
+ return err;
+}
+
+#define READ_LOG_ID 0xc1
+#define WRITE_LOG_ID 0xc2
+
+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))
+ return 0;
+
+ struct nvme_get_log_args args = {
+ .lpo = 0,
+ .result = NULL,
+ .log = &lt->stats,
+ .args_size = sizeof(args),
+ .fd = lt->fd,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .lid = lt->cfg.write ? WRITE_LOG_ID : READ_LOG_ID,
+ .len = sizeof(lt->stats),
+ .nsid = NVME_NSID_ALL,
+ .csi = NVME_CSI_NVM,
+ .lsi = NVME_LOG_LSI_NONE,
+ .lsp = lt->cfg.type,
+ .uuidx = NVME_UUID_NONE,
+ .rae = false,
+ .ot = false,
+ };
+
+ err = nvme_get_log(&args);
+ if (err)
+ return err;
+
+ if (lt->print_flags & BINARY)
+ d_raw((unsigned char *)&lt->stats,
+ sizeof(lt->stats));
+ else {
+ latency_tracker_parse(lt);
+ }
+ return err;
+}
+
+int solidigm_get_latency_tracking_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Get and Parse Solidigm Latency Tracking Statistics log.";
+ __u32 enabled;
+ int err;
+
+ struct latency_tracker lt = {
+ .cfg = {
+ .output_format = "normal",
+ },
+ .base_range_bits = BASE_RANGE_BITS_4_1,
+ .bucket_list_size = BUCKET_LIST_SIZE_4_1,
+ .has_average_latency_field = false,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("enable", 'e', &lt.cfg.enable, "Enable Latency Tracking"),
+ OPT_FLAG("disable", 'd', &lt.cfg.disable, "Disable Latency Tracking"),
+ OPT_FLAG("read", 'r', &lt.cfg.read, "Get read statistics"),
+ OPT_FLAG("write", 'w', &lt.cfg.write, "Get write statistics"),
+ OPT_BYTE("type", 't', &lt.cfg.type, "Log type to get"),
+ OPT_FMT("output-format", 'o', &lt.cfg.output_format, output_format),
+ OPT_END()
+ };
+
+ lt.fd = parse_and_open(argc, argv, desc, opts);
+ if (lt.fd < 0)
+ return lt.fd;
+
+ lt.print_flags = validate_output_format(lt.cfg.output_format);
+ if (lt.print_flags == -EINVAL) {
+ fprintf(stderr, "Invalid output format '%s'\n", lt.cfg.output_format);
+ close(lt.fd);
+ return EINVAL;
+ }
+
+ if (lt.cfg.type > 0xf) {
+ fprintf(stderr, "Invalid Log type value '%d'\n", lt.cfg.type);
+ close(lt.fd);
+ return EINVAL;
+ }
+
+ if (lt.cfg.type && !(lt.cfg.read || lt.cfg.write)) {
+ fprintf(stderr, "Log type option valid only when retrieving statistics\n");
+ close(lt.fd);
+ return EINVAL;
+ }
+
+ err = latency_tracking_enable(&lt);
+ if (err){
+ close(lt.fd);
+ return err;
+ }
+
+ err = latency_tracker_get_log(&lt);
+ if (err){
+ close(lt.fd);
+ return err;
+ }
+
+ if ((lt.cfg.read || lt.cfg.write || lt.cfg.enable || lt.cfg.disable)) {
+ close(lt.fd);
+ return 0;
+ }
+
+ err = latency_tracking_is_enable(&lt, &enabled);
+ if (!err) {
+ if (lt.print_flags == JSON) {
+ struct json_object *root = json_create_object();
+ 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 (FID 0x%X) is currently (%i).\n",
+ LATENCY_TRACKING_FID, enabled);
+ }
+ } else {
+ fprintf(stderr, "Could not read feature id 0xE2.\n");
+ }
+ close(lt.fd);
+ return err;
+}
diff --git a/plugins/solidigm/solidigm-latency-tracking.h b/plugins/solidigm/solidigm-latency-tracking.h
new file mode 100644
index 0000000..9a763a9
--- /dev/null
+++ b/plugins/solidigm/solidigm-latency-tracking.h
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+int solidigm_get_latency_tracking_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin);
diff --git a/plugins/solidigm/solidigm-nvme.c b/plugins/solidigm/solidigm-nvme.c
new file mode 100644
index 0000000..3eb3cc9
--- /dev/null
+++ b/plugins/solidigm/solidigm-nvme.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include "nvme.h"
+
+#define CREATE_CMD
+#include "solidigm-nvme.h"
+
+#include "solidigm-smart.h"
+#include "solidigm-garbage-collection.h"
+#include "solidigm-latency-tracking.h"
+
+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_garbage_collection_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ return solidigm_get_garbage_collection_log(argc, argv, cmd, plugin);
+}
+
+static int get_latency_tracking_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ return solidigm_get_latency_tracking_log(argc, argv, cmd, plugin);
+} \ No newline at end of file
diff --git a/plugins/solidigm/solidigm-nvme.h b/plugins/solidigm/solidigm-nvme.h
new file mode 100644
index 0000000..9fc8b45
--- /dev/null
+++ b/plugins/solidigm/solidigm-nvme.h
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/solidigm/solidigm-nvme
+
+#if !defined(SOLIDIGM_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define SOLIDIGM_NVME
+
+#include "cmd.h"
+
+#define SOLIDIGM_PLUGIN_VERSION "0.4"
+
+PLUGIN(NAME("solidigm", "Solidigm vendor specific extensions", SOLIDIGM_PLUGIN_VERSION),
+ COMMAND_LIST(
+ ENTRY("smart-log-add", "Retrieve Solidigm SMART Log", get_additional_smart_log)
+ ENTRY("garbage-collect-log", "Retrieve Garbage Collection Log", get_garbage_collection_log)
+ ENTRY("latency-tracking-log", "Enable/Retrieve Latency tracking Log", get_latency_tracking_log)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/solidigm/solidigm-smart.c b/plugins/solidigm/solidigm-smart.c
new file mode 100644
index 0000000..4b30cab
--- /dev/null
+++ b/plugins/solidigm/solidigm-smart.c
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <endian.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "linux/types.h"
+#include "nvme-print.h"
+
+#include "solidigm-smart.h"
+
+struct __attribute__((packed)) nvme_additional_smart_log_item {
+ __u8 id;
+ __u8 _kp[2];
+ __u8 normalized;
+ __u8 _np;
+ union __attribute__((packed)) {
+ __u8 raw[6];
+ struct __attribute__((packed)) wear_level {
+ __le16 min;
+ __le16 max;
+ __le16 avg;
+ } wear_level;
+ struct __attribute__((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;
+
+static char *id_to_name(__u8 id)
+{
+ switch (id) {
+ case 0x0D:
+ return "soft_ecc_error_rate";
+ case 0x05:
+ return "relocatable_sector_count";
+ case 0xAB:
+ return "program_fail_count";
+ case 0xAC:
+ return "erase_fail_count";
+ case 0xAD:
+ return "wear_leveling_count";
+ case 0xAE:
+ return "unexpected_power_loss";
+ case 0xB8:
+ return "e2e_error_detect_count";
+ case 0xC7:
+ return "crc_error_count";
+ case 0xE2:
+ return "media_wear_percentage";
+ case 0xE3:
+ return "host_reads";
+ case 0xE4:
+ return "timed_work_load";
+ case 0xE5:
+ return "read_commands_in_flight_counter";
+ case 0xE6:
+ return "write_commands_in_flight_counter";
+ case 0xEA:
+ return "thermal_throttle_status";
+ case 0xF0:
+ return "retry_buffer_overflow_counter";
+ case 0xF3:
+ return "pll_lock_loss_counter";
+ case 0xF4:
+ return "nand_bytes_written";
+ case 0xF5:
+ return "host_bytes_written";
+ case 0xF6:
+ return "host_context_wear_used";
+ case 0xF7:
+ return "performance_status_indicator";
+ case 0xF8:
+ return "media_bytes_read";
+ case 0xF9:
+ return "available_fw_downgrades";
+ case 0xFA:
+ return "host_read_collision_count";
+ case 0xFB:
+ return "host_write_collision_count";
+ case 0xFC:
+ return "xor_pass_count";
+ case 0xFD:
+ return "xor_fail_count";
+ case 0xFE:
+ return "xor_invoked_count";
+ default:
+ return "unknown";
+ }
+}
+
+static void smart_log_item_print(smart_log_item_t *item)
+{
+ if (!item->id) {
+ return;
+ }
+
+ printf("%#x %-45s %3d ",
+ item->id, id_to_name(item->id), item->normalized);
+
+ switch (item->id) {
+ case 0xAD:
+ printf("min: %u, max: %u, avg: %u\n",
+ le16_to_cpu(item->wear_level.min),
+ le16_to_cpu(item->wear_level.max),
+ le16_to_cpu(item->wear_level.avg));
+ return;
+ case 0xEA:
+ printf("%u%%, cnt: %u\n",
+ item->thermal_throttle.pct,
+ le32_to_cpu(item->thermal_throttle.count));
+ return;
+ default:
+ printf("%"PRIu64"\n", int48_to_long(item->raw));
+ }
+}
+
+static void smart_log_item_add_json(smart_log_item_t *item, struct json_object *dev_stats)
+{
+ struct json_object *entry_stats = json_create_object();
+
+ if (!item->id) {
+ return;
+ }
+
+ json_object_add_value_int(entry_stats, "normalized", item->normalized);
+
+ switch (item->id) {
+ case 0xAD:
+ json_object_add_value_int(entry_stats, "min", le16_to_cpu(item->wear_level.min));
+ json_object_add_value_int(entry_stats, "max", le16_to_cpu(item->wear_level.max));
+ json_object_add_value_int(entry_stats, "avg", le16_to_cpu(item->wear_level.avg));
+ break;
+ case 0xEA:
+ json_object_add_value_int(entry_stats, "percentage", item->thermal_throttle.pct);
+ json_object_add_value_int(entry_stats, "count", le32_to_cpu(item->thermal_throttle.count));
+ break;
+ default:
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(item->raw));
+ }
+ 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)
+{
+ struct json_object *dev_stats = json_create_object();
+ smart_log_item_t *item = payload->item;
+ struct json_object *root;
+
+ 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);
+ json_object_add_value_object(root, "Device stats", dev_stats);
+
+ json_print_object(root, NULL);
+ json_free_object(root);
+}
+
+static void vu_smart_log_show(vu_smart_log_t *payload, unsigned int nsid, const char *devname)
+{
+ smart_log_item_t *item = payload->item;
+
+ printf("Additional Smart Log for NVME device:%s namespace-id:%x\n",
+ devname, nsid);
+ printf("ID KEY Normalized Raw\n");
+
+ 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 int solidigm_vu_smart_log_id = 0xCA;
+ vu_smart_log_t smart_log_payload;
+ enum nvme_print_flags flags;
+ int fd, err;
+
+ struct config {
+ __u32 namespace_id;
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .namespace_id = NVME_NSID_ALL,
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, "(optional) desired namespace"),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ return fd;
+ }
+
+ flags = validate_output_format(cfg.output_format);
+ if (flags == -EINVAL) {
+ fprintf(stderr, "Invalid output format '%s'\n", cfg.output_format);
+ close(fd);
+ return fd;
+ }
+
+ err = nvme_get_log_simple(fd, solidigm_vu_smart_log_id, sizeof(smart_log_payload), &smart_log_payload);
+ if (!err) {
+ if (flags & JSON) {
+ vu_smart_log_show_json(&smart_log_payload, cfg.namespace_id, devicename);
+ } else if (flags & BINARY) {
+ d_raw((unsigned char *)&smart_log_payload, sizeof(smart_log_payload));
+ } else {
+ vu_smart_log_show(&smart_log_payload, cfg.namespace_id, devicename);
+ }
+ } else if (err > 0) {
+ nvme_show_status(err);
+ }
+
+ close(fd);
+ return err;
+}
+
diff --git a/plugins/solidigm/solidigm-smart.h b/plugins/solidigm/solidigm-smart.h
new file mode 100644
index 0000000..e19ebe5
--- /dev/null
+++ b/plugins/solidigm/solidigm-smart.h
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+int solidigm_get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin);
diff --git a/plugins/toshiba/toshiba-nvme.c b/plugins/toshiba/toshiba-nvme.c
index fd2e9c1..cf19352 100644
--- a/plugins/toshiba/toshiba-nvme.c
+++ b/plugins/toshiba/toshiba-nvme.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
@@ -148,6 +149,7 @@ static int nvme_sct_command_transfer_log(int fd, bool current)
memcpy(data + 2, &function_code, sizeof(function_code));
err = nvme_sct_op(fd, OP_SCT_COMMAND_TRANSFER, DW10_SCT_COMMAND_TRANSFER, DW11_SCT_COMMAND_TRANSFER, data, data_len);
+ free(data);
return err;
}
@@ -474,6 +476,7 @@ static int vendor_log(int argc, char **argv, struct command *cmd, struct plugin
end:
if (err > 0)
nvme_show_status(err);
+ close(fd);
return err;
}
@@ -517,6 +520,7 @@ static int internal_log(int argc, char **argv, struct command *cmd, struct plugi
if (err > 0)
nvme_show_status(err);
+ close(fd);
return err;
}
@@ -569,5 +573,6 @@ static int clear_correctable_errors(int argc, char **argv, struct command *cmd,
end:
if (err > 0)
nvme_show_status(err);
+ close(fd);
return err;
}
diff --git a/plugins/toshiba/toshiba-nvme.h b/plugins/toshiba/toshiba-nvme.h
index ebd7575..6208f5d 100644
--- a/plugins/toshiba/toshiba-nvme.h
+++ b/plugins/toshiba/toshiba-nvme.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#undef CMD_INC_FILE
#define CMD_INC_FILE plugins/toshiba/toshiba-nvme
diff --git a/plugins/transcend/transcend-nvme.c b/plugins/transcend/transcend-nvme.c
index 85d3cac..0a3d852 100644
--- a/plugins/transcend/transcend-nvme.c
+++ b/plugins/transcend/transcend-nvme.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
@@ -49,7 +50,7 @@ static int getHealthValue(int argc, char **argv, struct command *cmd, struct plu
}
}
-
+ close(fd);
return result;
}
@@ -83,6 +84,6 @@ static int getBadblock(int argc, char **argv, struct command *cmd, struct plugin
int badblock = data[0];
printf("Transcend NVME badblock count: %d\n",badblock);
}
-
+ close(fd);
return result;
}
diff --git a/plugins/transcend/transcend-nvme.h b/plugins/transcend/transcend-nvme.h
index 317793a..9c89883 100644
--- a/plugins/transcend/transcend-nvme.h
+++ b/plugins/transcend/transcend-nvme.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#undef CMD_INC_FILE
#define CMD_INC_FILE plugins/transcend/transcend-nvme
diff --git a/plugins/virtium/virtium-nvme.c b/plugins/virtium/virtium-nvme.c
index 7c2ebec..d9fc54e 100644
--- a/plugins/virtium/virtium-nvme.c
+++ b/plugins/virtium/virtium-nvme.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
@@ -132,7 +133,7 @@ static void vt_convert_smart_data_to_human_readable_format(struct vtview_smart_l
setlocale(LC_ALL, "C");
- long long int lba = 1 << smart->raw_ns.lbaf[lba_index].ds;
+ unsigned long long int 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,
@@ -270,16 +271,16 @@ static void vt_process_string(char *str, const size_t size)
static int vt_add_entry_to_log(const int fd, const char *path, const struct vtview_save_log_settings *cfg)
{
struct vtview_smart_log_entry smart;
- char filename[256] = "";
+ const char *filename;
int ret = 0;
unsigned nsid = 0;
memset(smart.path, 0, sizeof(smart.path));
- strcpy(smart.path, path);
+ strncpy(smart.path, path, sizeof(smart.path) - 1);
if(NULL == cfg->output_file)
- strcpy(filename, vt_default_log_file_name);
+ filename = vt_default_log_file_name;
else
- strcpy(filename, cfg->output_file);
+ filename = cfg->output_file;
smart.time_stamp = time(NULL);
ret = nvme_get_nsid(fd, &nsid);
@@ -317,21 +318,32 @@ static int vt_add_entry_to_log(const int fd, const char *path, const struct vtvi
static int vt_update_vtview_log_header(const int fd, const char *path, const struct vtview_save_log_settings *cfg)
{
struct vtview_log_header header;
- char filename[256] = "";
+ const char *filename;
int ret = 0;
vt_initialize_header_buffer(&header);
+ if (strlen(path) > sizeof(header.path)) {
+ printf("filename too long\n");
+ errno = EINVAL;
+ return -1;
+ }
strcpy(header.path, path);
if (NULL == 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;
+ return -1;
+ }
strcpy(header.test_name, cfg->test_name);
+ }
if(NULL == cfg->output_file)
- strcpy(filename, vt_default_log_file_name);
+ filename = vt_default_log_file_name;
else
- strcpy(filename, cfg->output_file);
+ filename = cfg->output_file;
printf("Log file: %s\n", filename);
header.time_stamp = time(NULL);
@@ -955,8 +967,13 @@ static int vt_save_smart_to_vtview_log(int argc, char **argv, struct command *cm
vt_generate_vtview_log_file_name(vt_default_log_file_name);
- if (argc >= 2)
+ if (argc >= 2) {
+ if (strlen(argv[1]) > sizeof(path) - 1) {
+ printf("Filename too long\n");
+ return -1;
+ }
strcpy(path, argv[1]);
+ }
fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0) {
diff --git a/plugins/virtium/virtium-nvme.h b/plugins/virtium/virtium-nvme.h
index 124ab18..0a04a35 100644
--- a/plugins/virtium/virtium-nvme.h
+++ b/plugins/virtium/virtium-nvme.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#undef CMD_INC_FILE
#define CMD_INC_FILE plugins/virtium/virtium-nvme
diff --git a/plugins/wdc/wdc-nvme.c b/plugins/wdc/wdc-nvme.c
index 486ee36..5be7e11 100644
--- a/plugins/wdc/wdc-nvme.c
+++ b/plugins/wdc/wdc-nvme.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2015-2018 Western Digital Corporation or its affiliates.
*
@@ -79,6 +80,8 @@
#define WDC_NVME_SN560_DEV_ID_1 0x2712
#define WDC_NVME_SN560_DEV_ID_2 0x2713
#define WDC_NVME_SN560_DEV_ID_3 0x2714
+#define WDC_NVME_SN860_DEV_ID 0x2730
+#define WDC_NVME_SN550_DEV_ID 0x2708
#define WDC_NVME_SXSLCL_DEV_ID 0x2001
#define WDC_NVME_SN520_DEV_ID 0x5003
#define WDC_NVME_SN520_DEV_ID_1 0x5004
@@ -96,6 +99,7 @@
#define WDC_NVME_ZN350_DEV_ID 0x5010
#define WDC_NVME_ZN350_DEV_ID_1 0x5018
#define WDC_NVME_SN810_DEV_ID 0x5011
+#define WDC_NVME_SN820CL_DEV_ID 0x5037
#define WDC_DRIVE_CAP_CAP_DIAG 0x0000000000000001
#define WDC_DRIVE_CAP_INTERNAL_LOG 0x0000000000000002
@@ -125,8 +129,10 @@
#define WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY 0x0000000002000000
#define WDC_DRIVE_CAP_CLOUD_SSD_VERSION 0x0000000004000000
#define WDC_DRIVE_CAP_PCIE_STATS 0x0000000008000000
-#define WDC_DRIVE_CAP_INFO_2 0x0000000010000000
+#define WDC_DRIVE_CAP_HW_REV_LOG_PAGE 0x0000000010000000
#define WDC_DRIVE_CAP_C3_LOG_PAGE 0x0000000020000000
+#define WDC_DRIVE_CAP_CLOUD_BOOT_SSD_VERSION 0x0000000040000000
+#define WDC_DRIVE_CAP_CLOUD_LOG_PAGE 0x0000000080000000
#define WDC_DRIVE_CAP_DRIVE_ESSENTIALS 0x0000000100000000
#define WDC_DRIVE_CAP_DUI_DATA 0x0000000200000000
@@ -136,6 +142,7 @@
#define WDC_DRIVE_CAP_OCP_C1_LOG_PAGE 0x0000002000000000
#define WDC_DRIVE_CAP_OCP_C4_LOG_PAGE 0x0000004000000000
#define WDC_DRIVE_CAP_OCP_C5_LOG_PAGE 0x0000008000000000
+#define WDC_DRIVE_CAP_DEVICE_WAF 0x0000010000000000
#define WDC_DRIVE_CAP_SMART_LOG_MASK (WDC_DRIVE_CAP_C0_LOG_PAGE | WDC_DRIVE_CAP_C1_LOG_PAGE | \
WDC_DRIVE_CAP_CA_LOG_PAGE | WDC_DRIVE_CAP_D0_LOG_PAGE)
#define WDC_DRIVE_CAP_CLEAR_PCIE_MASK (WDC_DRIVE_CAP_CLEAR_PCIE | \
@@ -350,6 +357,7 @@ static __u8 wdc_lat_mon_guid[WDC_C3_GUID_LENGTH] = { 0x92, 0x7a, 0xc0, 0x8c,
#define WDC_LOG_ID_C0 0xC0
#define WDC_LOG_ID_C1 0xC1
#define WDC_LOG_ID_C2 WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE
+#define WDC_LOG_ID_C3 0xC3
#define WDC_LOG_ID_C4 0xC4
#define WDC_LOG_ID_C5 0xC5
#define WDC_LOG_ID_C6 0xC6
@@ -487,6 +495,121 @@ typedef enum
WDC_DE_TYPE_ALL = 0xFFFFFFF,
} WDC_DRIVE_ESSENTIAL_TYPE;
+#define WDC_C0_GUID_LENGTH 16
+#define WDC_SCA_V1_NAND_STATS 0x1
+#define WDC_SCA_V1_ALL 0xF
+typedef enum
+{
+ SCAO_V1_PMUWT = 0, /* Physical media units written TLC */
+ SCAO_V1_PMUWS = 16, /* Physical media units written SLC */
+ SCAO_V1_BUNBN = 32, /* Bad user nand blocks normalized */
+ SCAO_V1_BUNBR = 34, /* Bad user nand blocks raw */
+ SCAO_V1_XRC = 40, /* XOR recovery count */
+ SCAO_V1_UREC = 48, /* Uncorrectable read error count */
+ SCAO_V1_EECE = 56, /* End to end corrected errors */
+ SCAO_V1_EEDE = 64, /* End to end detected errors */
+ SCAO_V1_EEUE = 72, /* End to end uncorrected errors */
+ SCAO_V1_SDPU = 80, /* System data percent used */
+ SCAO_V1_MNUDEC = 84, /* Min User data erase counts (TLC) */
+ SCAO_V1_MXUDEC = 92, /* Max User data erase counts (TLC) */
+ SCAO_V1_AVUDEC = 100, /* Average User data erase counts (TLC) */
+ SCAO_V1_MNEC = 108, /* Min Erase counts (SLC) */
+ SCAO_V1_MXEC = 116, /* Max Erase counts (SLC) */
+ SCAO_V1_AVEC = 124, /* Average Erase counts (SLC) */
+ SCAO_V1_PFCN = 132, /* Program fail count normalized */
+ SCAO_V1_PFCR = 134, /* Program fail count raw */
+ SCAO_V1_EFCN = 140, /* Erase fail count normalized */
+ SCAO_V1_EFCR = 142, /* Erase fail count raw */
+ SCAO_V1_PCEC = 148, /* PCIe correctable error count */
+ SCAO_V1_PFBU = 156, /* Percent free blocks (User) */
+ SCAO_V1_SVN = 160, /* Security Version Number */
+ SCAO_V1_PFBS = 168, /* Percent free blocks (System) */
+ SCAO_V1_DCC = 172, /* Deallocate Commands Completed */
+ SCAO_V1_TNU = 188, /* Total Namespace Utilization */
+ SCAO_V1_FCC = 196, /* Format NVM Commands Completed */
+ SCAO_V1_BBPG = 198, /* Background Back-Pressure Gauge */
+ SCAO_V1_SEEC = 202, /* Soft ECC error count */
+ SCAO_V1_RFSC = 210, /* Refresh count */
+ SCAO_V1_BSNBN = 218, /* Bad system nand blocks normalized */
+ SCAO_V1_BSNBR = 220, /* Bad system nand blocks raw */
+ SCAO_V1_EEST = 226, /* Endurance estimate */
+ SCAO_V1_TTC = 242, /* Thermal throttling count */
+ SCAO_V1_UIO = 244, /* Unaligned I/O */
+ SCAO_V1_PMUR = 252, /* Physical media units read */
+ SCAO_V1_RTOC = 268, /* Read command timeout count */
+ SCAO_V1_WTOC = 272, /* Write command timeout count */
+ SCAO_V1_TTOC = 276, /* Trim command timeout count */
+ SCAO_V1_PLRC = 284, /* PCIe Link Retraining Count */
+ SCAO_V1_PSCC = 292, /* Power State Change Count */
+ SCAO_V1_MAVF = 300, /* Boot SSD major version field */
+ SCAO_V1_MIVF = 302, /* Boot SSD minor version field */
+ SCAO_V1_PVF = 304, /* Boot SSD point version field */
+ SCAO_V1_EVF = 306, /* Boot SSD errata version field */
+ SCAO_V1_FTLUS = 308, /* FTL Unit Size */
+ SCAO_V1_TCGOS = 312, /* TCG Ownership Status */
+
+ SCAO_V1_LPV = 494, /* Log page version - 0x0001 */
+ SCAO_V1_LPG = 496, /* Log page GUID */
+} SMART_CLOUD_ATTRIBUTE_OFFSETS_V1;
+
+static __u8 ext_smart_guid[WDC_C0_GUID_LENGTH] = { 0x65, 0x43, 0x88, 0x78, 0xAC, 0xD8, 0x78, 0xA1,
+ 0x66, 0x42, 0x1E, 0x0F, 0x92, 0xD7, 0x6D, 0xC4 };
+
+typedef struct __attribute__((__packed__)) wdc_nvme_ext_smart_log
+{
+ __u8 ext_smart_pmuwt[16]; /* 000 Physical media units written TLC */
+ __u8 ext_smart_pmuws[16]; /* 016 Physical media units written SLC */
+ __u8 ext_smart_bunbc[8]; /* 032 Bad user nand block count */
+ __u64 ext_smart_xrc; /* 040 XOR recovery count */
+ __u64 ext_smart_urec; /* 048 Uncorrectable read error count */
+ __u64 ext_smart_eece; /* 056 End to end corrected errors */
+ __u64 ext_smart_eede; /* 064 End to end detected errors */
+ __u64 ext_smart_eeue; /* 072 End to end uncorrected errors */
+ __u8 ext_smart_sdpu; /* 080 System data percent used */
+ __u8 ext_smart_rsvd1[3]; /* 081 reserved */
+ __u64 ext_smart_mnudec; /* 084 Min User data erase counts (TLC) */
+ __u64 ext_smart_mxudec; /* 092 Max User data erase counts (TLC) */
+ __u64 ext_smart_avudec; /* 100 Average User data erase counts (TLC) */
+ __u64 ext_smart_mnec; /* 108 Min Erase counts (SLC) */
+ __u64 ext_smart_mxec; /* 116 Max Erase counts (SLC) */
+ __u64 ext_smart_avec; /* 124 Average Erase counts (SLC) */
+ __u8 ext_smart_pfc[8]; /* 132 Program fail count */
+ __u8 ext_smart_efc[8]; /* 140 Erase fail count */
+ __u64 ext_smart_pcec; /* 148 PCIe correctable error count */
+ __u8 ext_smart_pfbu; /* 156 Percent free blocks (User) */
+ __u8 ext_smart_rsvd2[3]; /* 157 reserved */
+ __u64 ext_smart_svn; /* 160 Security Version Number */
+ __u8 ext_smart_pfbs; /* 168 Percent free blocks (System) */
+ __u8 ext_smart_rsvd3[3]; /* 169 reserved */
+ __u8 ext_smart_dcc[16]; /* 172 Deallocate Commands Completed */
+ __u64 ext_smart_tnu; /* 188 Total Namespace Utilization */
+ __u16 ext_smart_fcc; /* 196 Format NVM Commands Completed */
+ __u8 ext_smart_bbpg; /* 198 Background Back-Pressure Gauge */
+ __u8 ext_smart_rsvd4[3]; /* 199 reserved */
+ __u64 ext_smart_seec; /* 202 Soft ECC error count */
+ __u64 ext_smart_rfsc; /* 210 Refresh count */
+ __u8 ext_smart_bsnbc[8]; /* 218 Bad system nand block count */
+ __u8 ext_smart_eest[16]; /* 226 Endurance estimate */
+ __u16 ext_smart_ttc; /* 242 Thermal throttling count */
+ __u64 ext_smart_uio; /* 244 Unaligned I/O */
+ __u8 ext_smart_pmur[16]; /* 252 Physical media units read */
+ __u32 ext_smart_rtoc; /* 268 Read command timeout count */
+ __u32 ext_smart_wtoc; /* 272 Write command timeout count */
+ __u32 ext_smart_ttoc; /* 276 Trim command timeout count */
+ __u8 ext_smart_rsvd5[4]; /* 280 reserved */
+ __u64 ext_smart_plrc; /* 284 PCIe Link Retraining Count */
+ __u64 ext_smart_pscc; /* 292 Power State Change Count */
+ __u16 ext_smart_maj; /* 300 Boot SSD major version field */
+ __u16 ext_smart_min; /* 302 Boot SSD minor version field */
+ __u16 ext_smart_pt; /* 304 Boot SSD point version field */
+ __u16 ext_smart_err; /* 306 Boot SSD errata version field */
+ __u32 ext_smart_ftlus; /* 308 FTL Unit Size */
+ __u32 ext_smart_tcgos; /* 312 TCG Ownership Status */
+ __u8 ext_smart_rsvd6[178]; /* 316 reserved */
+ __u16 ext_smart_lpv; /* 494 Log page version - 0x0001 */
+ __u8 ext_smart_lpg[16]; /* 496 Log page GUID */
+} wdc_nvme_ext_smart_log;
+
typedef enum
{
SCAO_PMUW = 0, /* Physical media units written */
@@ -520,12 +643,11 @@ typedef enum
SCAO_NUSE = 152, /* NUSE - Namespace utilization */
SCAO_PSC = 160, /* PLP start count */
SCAO_EEST = 176, /* Endurance estimate */
- SCAO_PLRC = 192, /* PCIe Link Retraining Count */
+ SCAO_PLRC = 192, /* PCIe Link Retraining Count */
+ SCAO_PSCC = 200, /* Power State Change Count */
SCAO_LPV = 494, /* Log page version */
SCAO_LPG = 496, /* Log page GUID */
-} SMART_CLOUD_ATTRIBUTE_OFFSETS;
-
-#define WDC_C0_GUID_LENGTH 16
+} SMART_CLOUD_ATTRIBUTE_OFFSETS_V3;
static __u8 scao_guid[WDC_C0_GUID_LENGTH] = { 0xC5, 0xAF, 0x10, 0x28, 0xEA, 0xBF, 0xF2, 0xA4,
0x9C, 0x4F, 0x6F, 0x7C, 0xC9, 0x14, 0xD5, 0xAF };
@@ -542,6 +664,54 @@ typedef enum
EOL_RRER = 108, /* Raw Read Error Rate */
} EOL_LOG_PAGE_C0_OFFSETS;
+#define WDC_NVME_C6_GUID_LENGTH 16
+#define WDC_NVME_GET_HW_REV_LOG_OPCODE 0xc6
+#define WDC_NVME_HW_REV_LOG_PAGE_LEN 512
+
+typedef struct __attribute__((__packed__)) wdc_nvme_hw_rev_log
+{
+ __u8 hw_rev_gdr; /* 0 Global Device HW Revision */
+ __u8 hw_rev_ar; /* 1 ASIC HW Revision */
+ __u8 hw_rev_pbc_mc; /* 2 PCB Manufacturer Code */
+ __u8 hw_rev_dram_mc; /* 3 DRAM Manufacturer Code */
+ __u8 hw_rev_nand_mc; /* 4 NAND Manufacturer Code */
+ __u8 hw_rev_pmic1_mc; /* 5 PMIC 1 Manufacturer Code */
+ __u8 hw_rev_pmic2_mc; /* 6 PMIC 2 Manufacturer Code */
+ __u8 hw_rev_c1_mc; /* 7 Other Component 1 Manf Code */
+ __u8 hw_rev_c2_mc; /* 8 Other Component 2 Manf Code */
+ __u8 hw_rev_c3_mc; /* 9 Other Component 3 Manf Code */
+ __u8 hw_rev_c4_mc; /* 10 Other Component 4 Manf Code */
+ __u8 hw_rev_c5_mc; /* 11 Other Component 5 Manf Code */
+ __u8 hw_rev_c6_mc; /* 12 Other Component 6 Manf Code */
+ __u8 hw_rev_c7_mc; /* 13 Other Component 7 Manf Code */
+ __u8 hw_rev_c8_mc; /* 14 Other Component 8 Manf Code */
+ __u8 hw_rev_c9_mc; /* 15 Other Component 9 Manf Code */
+ __u8 hw_rev_rsrvd1[48]; /* 16 Reserved 48 bytes */
+ __u8 hw_rev_dev_mdi[16]; /* 64 Device Manf Detailed Info */
+ __u8 hw_rev_asic_di[16]; /* 80 ASIC Detailed Info */
+ __u8 hw_rev_pcb_di[16]; /* 96 PCB Detailed Info */
+ __u8 hw_rev_dram_di[16]; /* 112 DRAM Detailed Info */
+ __u8 hw_rev_nand_di[16]; /* 128 NAND Detailed Info */
+ __u8 hw_rev_pmic1_di[16]; /* 144 PMIC1 Detailed Info */
+ __u8 hw_rev_pmic2_di[16]; /* 160 PMIC2 Detailed Info */
+ __u8 hw_rev_c1_di[16]; /* 176 Component 1 Detailed Info */
+ __u8 hw_rev_c2_di[16]; /* 192 Component 2 Detailed Info */
+ __u8 hw_rev_c3_di[16]; /* 208 Component 3 Detailed Info */
+ __u8 hw_rev_c4_di[16]; /* 224 Component 4 Detailed Info */
+ __u8 hw_rev_c5_di[16]; /* 240 Component 5 Detailed Info */
+ __u8 hw_rev_c6_di[16]; /* 256 Component 6 Detailed Info */
+ __u8 hw_rev_c7_di[16]; /* 272 Component 7 Detailed Info */
+ __u8 hw_rev_c8_di[16]; /* 288 Component 8 Detailed Info */
+ __u8 hw_rev_c9_di[16]; /* 304 Component 9 Detailed Info */
+ __u8 hw_rev_sn[32]; /* 320 Serial Number */
+ __u8 hw_rev_rsrvd2[142]; /* 352 Reserved 143 bytes */
+ __u16 hw_rev_version; /* 494 Log Page Version */
+ __u8 hw_rev_guid[16]; /* 496 Log Page GUID */
+} wdc_nvme_hw_rev_log;
+
+static __u8 hw_rev_log_guid[WDC_NVME_C6_GUID_LENGTH] = { 0xAA, 0xB0, 0x05, 0xF5, 0x13, 0x5E, 0x48, 0x15,
+ 0xAB, 0x89, 0x05, 0xBA, 0x8B, 0xE2, 0xBF, 0x3C };
+
typedef struct __attribute__((__packed__)) _WDC_DE_VU_FILE_META_DATA
{
__u8 fileName[WDC_DE_FILE_NAME_SIZE];
@@ -1161,7 +1331,7 @@ static int wdc_get_pci_ids(nvme_root_t r, uint32_t *device_id,
fprintf(stderr, "%s: Read of pci vendor id failed\n", __func__);
return -1;
}
-
+ id[ret < 32 ? ret : 31] = '\0';
if (id[strlen(id) - 1] == '\n')
id[strlen(id) - 1] = '\0';
@@ -1181,7 +1351,7 @@ static int wdc_get_pci_ids(nvme_root_t r, uint32_t *device_id,
fprintf(stderr, "%s: Read of pci device id failed\n", __func__);
return -1;
}
-
+ id[ret < 32 ? ret : 31] = '\0';
if (id[strlen(id) - 1] == '\n')
id[strlen(id) - 1] = '\0';
@@ -1348,6 +1518,12 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, int fd) {
case WDC_NVME_SN640_DEV_ID_2:
/* FALLTHRU */
case WDC_NVME_SN640_DEV_ID_3:
+ /* FALLTHRU */
+ case WDC_NVME_SN560_DEV_ID_1:
+ /* FALLTHRU */
+ case WDC_NVME_SN560_DEV_ID_2:
+ /* FALLTHRU */
+ case WDC_NVME_SN560_DEV_ID_3:
/* verify the 0xC0 log page is supported */
if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE) == true) {
capabilities |= WDC_DRIVE_CAP_C0_LOG_PAGE;
@@ -1400,6 +1576,8 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, int fd) {
case WDC_NVME_SN840_DEV_ID:
/* FALLTHRU */
case WDC_NVME_SN840_DEV_ID_1:
+ /* FALLTHRU */
+ case WDC_NVME_SN860_DEV_ID:
/* verify the 0xC0 log page is supported */
if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE) == true) {
capabilities |= WDC_DRIVE_CAP_C0_LOG_PAGE;
@@ -1430,9 +1608,7 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, int fd) {
case WDC_NVME_SN650_DEV_ID_3:
case WDC_NVME_SN650_DEV_ID_4:
case WDC_NVME_SN655_DEV_ID:
- case WDC_NVME_SN560_DEV_ID_1:
- case WDC_NVME_SN560_DEV_ID_2:
- case WDC_NVME_SN560_DEV_ID_3:
+ case WDC_NVME_SN550_DEV_ID:
/* verify the 0xC0 log page is supported */
if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE) == true) {
capabilities |= WDC_DRIVE_CAP_C0_LOG_PAGE;
@@ -1440,7 +1616,7 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, int fd) {
capabilities |= (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG |
WDC_DRIVE_CAP_DRIVE_STATUS | WDC_DRIVE_CAP_CLEAR_ASSERT |
- WDC_DRIVE_CAP_RESIZE | WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE |
+ WDC_DRIVE_CAP_RESIZE | WDC_DRIVE_CAP_CLEAR_PCIE |
WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY | WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY |
WDC_DRVIE_CAP_DISABLE_CTLR_TELE_LOG | WDC_DRIVE_CAP_REASON_ID |
WDC_DRIVE_CAP_LOG_PAGE_DIR | WDC_DRIVE_CAP_INFO |
@@ -1470,12 +1646,19 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, int fd) {
case WDC_NVME_SN810_DEV_ID:
capabilities = WDC_DRIVE_CAP_DUI_DATA;
break;
+ case WDC_NVME_SN820CL_DEV_ID:
+ capabilities = WDC_DRIVE_CAP_DUI_DATA | WDC_DRIVE_CAP_CLOUD_BOOT_SSD_VERSION |
+ WDC_DRIVE_CAP_CLOUD_LOG_PAGE | WDC_DRIVE_CAP_C0_LOG_PAGE |
+ WDC_DRIVE_CAP_HW_REV_LOG_PAGE | WDC_DRIVE_CAP_INFO |
+ WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE | WDC_DRIVE_CAP_NAND_STATS |
+ WDC_DRIVE_CAP_DEVICE_WAF | WDC_DRIVE_CAP_TEMP_STATS;
+ break;
case WDC_NVME_SN720_DEV_ID:
capabilities = WDC_DRIVE_CAP_DUI_DATA | WDC_DRIVE_CAP_NAND_STATS | WDC_DRIVE_CAP_NS_RESIZE;
break;
case WDC_NVME_SN730A_DEV_ID:
- capabilities = WDC_DRIVE_CAP_DUI | WDC_DRIVE_CAP_NAND_STATS | WDC_DRIVE_CAP_INFO_2
- | WDC_DRIVE_CAP_TEMP_STATS | WDC_DRIVE_CAP_VUC_CLEAR_PCIE | WDC_DRIVE_CAP_PCIE_STATS;
+ capabilities = WDC_DRIVE_CAP_DUI | WDC_DRIVE_CAP_NAND_STATS | WDC_DRIVE_CAP_INFO |
+ WDC_DRIVE_CAP_TEMP_STATS | WDC_DRIVE_CAP_VUC_CLEAR_PCIE | WDC_DRIVE_CAP_PCIE_STATS;
break;
case WDC_NVME_SN740_DEV_ID:
case WDC_NVME_SN740_DEV_ID_1:
@@ -1628,6 +1811,7 @@ static int wdc_create_log_file(char *file, __u8 *drive_log_data,
ret = write(fd, drive_log_data, WRITE_SIZE);
if (ret < 0) {
fprintf (stderr, "ERROR : WDC: write : %s\n", strerror(errno));
+ close(fd);
return -1;
}
drive_log_data += WRITE_SIZE;
@@ -1637,11 +1821,13 @@ static int wdc_create_log_file(char *file, __u8 *drive_log_data,
ret = write(fd, drive_log_data, drive_log_length);
if (ret < 0) {
fprintf(stderr, "ERROR : WDC : write : %s\n", strerror(errno));
+ close(fd);
return -1;
}
if (fsync(fd) < 0) {
fprintf(stderr, "ERROR : WDC : fsync : %s\n", strerror(errno));
+ close(fd);
return -1;
}
close(fd);
@@ -2204,13 +2390,12 @@ static int wdc_do_cap_telemetry_log(int fd, char *file, __u32 bs, int type, int
if (err) {
fprintf(stderr, "ERROR : WDC : nvme_identify_ctrl() failed "
"0x%x\n", err);
- goto close_fd;
+ return err;
}
if (!(ctrl.lpa & 0x8)) {
fprintf(stderr, "Telemetry Host-Initiated and Telemetry Controller-Initiated log pages not supported\n");
- err = -EINVAL;
- goto close_fd;
+ return -EINVAL;
}
r = nvme_scan(NULL);
@@ -2232,15 +2417,13 @@ static int wdc_do_cap_telemetry_log(int fd, char *file, __u32 bs, int type, int
}
else {
fprintf(stderr, "%s: Controller initiated option telemetry log page disabled\n", __func__);
- err = -EINVAL;
- goto close_fd;
+ return -EINVAL;
}
}
else {
fprintf(stderr, "ERROR : WDC: Get telemetry option feature failed.");
nvme_show_status(err);
- err = -EPERM;
- goto close_fd;
+ return -EPERM;
}
}
else {
@@ -2249,22 +2432,19 @@ static int wdc_do_cap_telemetry_log(int fd, char *file, __u32 bs, int type, int
}
} else {
fprintf(stderr, "%s: Invalid type parameter; type = %d\n", __func__, type);
- err = -EINVAL;
- goto close_fd;
+ return -EINVAL;
}
if (!file) {
fprintf(stderr, "%s: Please provide an output file!\n", __func__);
- err = -EINVAL;
- goto close_fd;
+ return -EINVAL;
}
output = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (output < 0) {
fprintf(stderr, "%s: Failed to open output file %s: %s!\n",
__func__, file, strerror(errno));
- err = output;
- goto close_fd;
+ return output;
}
if (ctrl_init)
@@ -2274,9 +2454,10 @@ static int wdc_do_cap_telemetry_log(int fd, char *file, __u32 bs, int type, int
else
err = nvme_get_host_telemetry(fd, &log, data_area, &full_size);
- if (err < 0)
+ if (err < 0) {
perror("get-telemetry-log");
- else if (err > 0) {
+ goto close_output;
+ } else if (err > 0) {
nvme_show_status(err);
fprintf(stderr, "%s: Failed to acquire telemetry header!\n", __func__);
goto close_output;
@@ -2309,17 +2490,13 @@ static int wdc_do_cap_telemetry_log(int fd, char *file, __u32 bs, int type, int
if (fsync(output) < 0) {
fprintf(stderr, "ERROR : %s: fsync : %s\n", __func__, strerror(errno));
- return -1;
+ err = -1;
}
free(log);
close_output:
close(output);
-close_fd:
- close(fd);
-
return err;
-
}
static int wdc_do_cap_diag(nvme_root_t r, int fd, char *file,
@@ -2757,7 +2934,7 @@ static int wdc_cap_diag(int argc, char **argv, struct command *command,
char *size = "Data retrieval transfer size.";
char f[PATH_MAX] = {0};
__u32 xfer_size = 0;
- int fd;
+ int fd, ret = 0;
__u64 capabilities = 0;
struct config {
@@ -2776,30 +2953,40 @@ static int wdc_cap_diag(int argc, char **argv, struct command *command,
OPT_END()
};
- r = nvme_scan(NULL);
-
fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0)
return fd;
+ r = nvme_scan(NULL);
+
if (cfg.file != NULL)
strncpy(f, cfg.file, PATH_MAX - 1);
if (cfg.xfer_size != 0)
xfer_size = cfg.xfer_size;
- if (wdc_get_serial_name(fd, f, PATH_MAX, "cap_diag") == -1) {
+ ret = wdc_get_serial_name(fd, f, PATH_MAX, "cap_diag");
+ if (ret) {
fprintf(stderr, "ERROR : WDC: failed to generate file name\n");
- return -1;
+ goto out;
+ }
+ if (cfg.file == NULL) {
+ if (strlen(f) > PATH_MAX - 5) {
+ fprintf(stderr, "ERROR : WDC: file name overflow\n");
+ ret = -1;
+ goto out;
+ }
+ strcat(f, ".bin");
}
- if (cfg.file == NULL)
- snprintf(f + strlen(f), PATH_MAX, "%s", ".bin");
capabilities = wdc_get_drive_capabilities(r, fd);
if ((capabilities & WDC_DRIVE_CAP_CAP_DIAG) == WDC_DRIVE_CAP_CAP_DIAG)
- return wdc_do_cap_diag(r, fd, f, xfer_size, 0, 0);
-
- fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ ret = wdc_do_cap_diag(r, fd, f, xfer_size, 0, 0);
+ else
+ fprintf(stderr,
+ "ERROR : WDC: unsupported device for this command\n");
+out:
nvme_free_tree(r);
- return 0;
+ close(fd);
+ return ret;
}
static int wdc_do_get_sn730_log_len(int fd, uint32_t *len_buf, uint32_t subopcode)
@@ -3047,7 +3234,7 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command
char fileSuffix[PATH_MAX] = {0};
nvme_root_t r;
__u32 xfer_size = 0;
- int fd;
+ int fd, ret = -1;
int telemetry_type = 0, telemetry_data_area = 0;
UtilsTimeInfo timeInfo;
__u8 timeStamp[MAX_PATH_LEN];
@@ -3089,16 +3276,14 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command
return fd;
r = nvme_scan(NULL);
- if (!wdc_check_device(r, fd)) {
- nvme_free_tree(r);
- return -1;
- }
+ if (!wdc_check_device(r, fd))
+ goto out;
+
if (cfg.xfer_size != 0)
xfer_size = cfg.xfer_size;
else {
fprintf(stderr, "ERROR : WDC : Invalid length\n");
- nvme_free_tree(r);
- return -1;
+ goto out;
}
if (cfg.file != NULL) {
@@ -3108,7 +3293,7 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command
verify_file = open(cfg.file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (verify_file < 0) {
fprintf(stderr, "ERROR : WDC: open : %s\n", strerror(errno));
- return -1;
+ goto out;
}
close(verify_file);
strncpy(f, cfg.file, PATH_MAX - 1);
@@ -3120,20 +3305,28 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command
timeInfo.hour, timeInfo.minute, timeInfo.second);
snprintf(fileSuffix, PATH_MAX, "_internal_fw_log_%s", (char*)timeStamp);
- if (wdc_get_serial_name(fd, f, PATH_MAX, fileSuffix) == -1) {
+ ret = wdc_get_serial_name(fd, f, PATH_MAX, fileSuffix);
+ if (ret) {
fprintf(stderr, "ERROR : WDC: failed to generate file name\n");
- return -1;
+ goto out;
}
}
- if (cfg.file == NULL)
- snprintf(f + strlen(f), PATH_MAX, "%s", ".bin");
+ if (cfg.file == NULL) {
+ if (strlen(f) > PATH_MAX - 5) {
+ fprintf(stderr, "ERROR : WDC: file name overflow\n");
+ ret = -1;
+ goto out;
+ }
+ strcat(f, ".bin");
+ }
fprintf(stderr, "%s: filename = %s\n", __func__, f);
if (cfg.data_area) {
if (cfg.data_area > 5 || cfg.data_area < 1) {
fprintf(stderr, "ERROR : WDC: Data area must be 1-5\n");
- return -1;
+ ret = -1;
+ goto out;
}
}
@@ -3152,7 +3345,8 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command
telemetry_data_area = cfg.data_area;
} else {
fprintf(stderr, "ERROR : WDC: Invalid type - Must be NONE, HOST or CONTROLLER\n");
- return -1;
+ ret = -1;
+ goto out;
}
capabilities = wdc_get_drive_capabilities(r, fd);
@@ -3160,8 +3354,9 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command
if (telemetry_data_area == 0)
telemetry_data_area = 3; /* Set the default DA to 3 if not specified */
- return wdc_do_cap_diag(r, fd, f, xfer_size,
- telemetry_type, telemetry_data_area);
+ ret = wdc_do_cap_diag(r, fd, f, xfer_size,
+ telemetry_type, telemetry_data_area);
+ goto out;
}
if ((capabilities & WDC_DRIVE_CAP_DUI) == WDC_DRIVE_CAP_DUI) {
if ((telemetry_type == WDC_TELEMETRY_TYPE_HOST) ||
@@ -3169,18 +3364,20 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command
if (telemetry_data_area == 0)
telemetry_data_area = 3; /* Set the default DA to 3 if not specified */
/* Get the desired telemetry log page */
- return wdc_do_cap_telemetry_log(fd, f, xfer_size, telemetry_type, telemetry_data_area);
- }
- else {
- if (cfg.data_area == 0) {
+ ret = wdc_do_cap_telemetry_log(fd, f, xfer_size,
+ telemetry_type, telemetry_data_area);
+ goto out;
+ } else {
+ if (cfg.data_area == 0)
cfg.data_area = 1;
- }
/* FW requirement - xfer size must be 256k for data area 4 */
if (cfg.data_area >= 4)
xfer_size = 0x40000;
- return wdc_do_cap_dui(fd, f, xfer_size, cfg.data_area,
- cfg.verbose, cfg.file_size, cfg.offset);
+ ret = wdc_do_cap_dui(fd, f, xfer_size, cfg.data_area,
+ cfg.verbose, cfg.file_size,
+ cfg.offset);
+ goto out;
}
}
if ((capabilities & WDC_DRIVE_CAP_DUI_DATA) == WDC_DRIVE_CAP_DUI_DATA){
@@ -3189,17 +3386,26 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command
if (telemetry_data_area == 0)
telemetry_data_area = 3; /* Set the default DA to 3 if not specified */
/* Get the desired telemetry log page */
- return wdc_do_cap_telemetry_log(fd, f, xfer_size, telemetry_type, telemetry_data_area);
- }
- else {
- return wdc_do_cap_dui(fd, f, xfer_size, WDC_NVME_DUI_MAX_DATA_AREA, cfg.verbose, 0, 0);
+ ret = wdc_do_cap_telemetry_log(fd, f, xfer_size,
+ telemetry_type, telemetry_data_area);
+ goto out;
+ } else {
+ ret = wdc_do_cap_dui(fd, f, xfer_size,
+ WDC_NVME_DUI_MAX_DATA_AREA,
+ cfg.verbose, 0, 0);
+ goto out;
}
}
if ((capabilities & WDC_SN730B_CAP_VUC_LOG) == WDC_SN730B_CAP_VUC_LOG)
- return wdc_do_sn730_get_and_tar(fd, f);
-
- fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
- return -1;
+ ret = wdc_do_sn730_get_and_tar(fd, f);
+ else {
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ ret = -1;
+ }
+out:
+ nvme_free_tree(r);
+ close(fd);
+ return ret;
}
static int wdc_do_crash_dump(int fd, char *file, int type)
@@ -3277,6 +3483,7 @@ static int wdc_crash_dump(int fd, char *file, int type)
{
char f[PATH_MAX] = {0};
const char *dump_type;
+ int ret;
if (file != NULL) {
strncpy(f, file, PATH_MAX - 1);
@@ -3287,11 +3494,13 @@ static int wdc_crash_dump(int fd, char *file, int type)
else
dump_type = "_crash_dump";
- if (wdc_get_serial_name(fd, f, PATH_MAX, dump_type) == -1) {
+ ret = wdc_get_serial_name(fd, f, PATH_MAX, dump_type);
+ if (ret)
fprintf(stderr, "ERROR : WDC : failed to generate file name\n");
- return -1;
- }
- return wdc_do_crash_dump(fd, f, type);
+ else
+ ret = wdc_do_crash_dump(fd, f, type); \
+ close(fd);
+ return ret;
}
static int wdc_do_drive_log(int fd, char *file)
@@ -3365,6 +3574,7 @@ static int wdc_drive_log(int argc, char **argv, struct command *command,
if (!wdc_check_device(r, fd)) {
nvme_free_tree(r);
+ close(fd);
return -1;
}
capabilities = wdc_get_drive_capabilities(r, fd);
@@ -3376,14 +3586,14 @@ static int wdc_drive_log(int argc, char **argv, struct command *command,
if (cfg.file != NULL) {
strncpy(f, cfg.file, PATH_MAX - 1);
}
- if (wdc_get_serial_name(fd, f, PATH_MAX, "drive_log") == -1) {
+ ret = wdc_get_serial_name(fd, f, PATH_MAX, "drive_log");
+ if (ret)
fprintf(stderr, "ERROR : WDC : failed to generate file name\n");
- nvme_free_tree(r);
- return -1;
- }
- ret = wdc_do_drive_log(fd, f);
+ else
+ ret = wdc_do_drive_log(fd, f);
}
nvme_free_tree(r);
+ close(fd);
return ret;
}
@@ -3417,6 +3627,7 @@ static int wdc_get_crash_dump(int argc, char **argv, struct command *command,
if (!wdc_check_device(r, fd)) {
nvme_free_tree(r);
+ close(fd);
return -1;
}
@@ -3433,6 +3644,7 @@ static int wdc_get_crash_dump(int argc, char **argv, struct command *command,
}
}
nvme_free_tree(r);
+ close(fd);
return ret;
}
@@ -3466,6 +3678,7 @@ static int wdc_get_pfail_dump(int argc, char **argv, struct command *command,
if (!wdc_check_device(r, fd)) {
nvme_free_tree(r);
+ close(fd);
return -1;
}
@@ -3480,6 +3693,7 @@ static int wdc_get_pfail_dump(int argc, char **argv, struct command *command,
}
}
nvme_free_tree(r);
+ close(fd);
return ret;
}
@@ -3553,6 +3767,7 @@ static int wdc_purge(int argc, char **argv,
if (!wdc_check_device(r, fd)) {
nvme_free_tree(r);
+ close(fd);
return -1;
}
@@ -3584,6 +3799,7 @@ static int wdc_purge(int argc, char **argv,
nvme_show_status(ret);
}
nvme_free_tree(r);
+ close(fd);
return ret;
}
@@ -3610,6 +3826,7 @@ static int wdc_purge_monitor(int argc, char **argv,
r = nvme_scan(NULL);
if (!wdc_check_device(r, fd)) {
nvme_free_tree(r);
+ close(fd);
return -1;
}
@@ -3642,6 +3859,7 @@ static int wdc_purge_monitor(int argc, char **argv,
nvme_show_status(ret);
}
nvme_free_tree(r);
+ close(fd);
return ret;
}
@@ -4234,7 +4452,7 @@ static void wdc_print_bd_ca_log_normal(void *data)
__u8 *byte_raw;
if (bd_data->field_id == 0x00) {
- raw = (__u64*)&bd_data->raw_value[1];
+ raw = (__u64*)&bd_data->raw_value[0];
printf("Additional Smart Log for NVME device:%s namespace-id:%x\n",
devicename, WDC_DE_GLOBAL_NSID);
printf("key normalized raw\n");
@@ -4245,7 +4463,7 @@ static void wdc_print_bd_ca_log_normal(void *data)
}
bd_data++;
if (bd_data->field_id == 0x01) {
- raw = (__u64*)&bd_data->raw_value[1];
+ raw = (__u64*)&bd_data->raw_value[0];
printf("erase_fail_count : %3"PRIu8"%% %"PRIu64"\n",
bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
} else {
@@ -4266,7 +4484,7 @@ static void wdc_print_bd_ca_log_normal(void *data)
}
bd_data++;
if (bd_data->field_id == 0x03) {
- raw = (__u64*)&bd_data->raw_value[1];
+ raw = (__u64*)&bd_data->raw_value[0];
printf("end_to_end_error_detection_count: %3"PRIu8"%% %"PRIu64"\n",
bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
} else {
@@ -4274,7 +4492,7 @@ static void wdc_print_bd_ca_log_normal(void *data)
}
bd_data++;
if (bd_data->field_id == 0x04) {
- raw = (__u64*)&bd_data->raw_value[1];
+ raw = (__u64*)&bd_data->raw_value[0];
printf("crc_error_count : %3"PRIu8"%% %"PRIu64"\n",
bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
} else {
@@ -4282,7 +4500,7 @@ static void wdc_print_bd_ca_log_normal(void *data)
}
bd_data++;
if (bd_data->field_id == 0x05) {
- raw = (__u64*)&bd_data->raw_value[1];
+ raw = (__u64*)&bd_data->raw_value[0];
printf("timed_workload_media_wear : %3"PRIu8"%% %-.3f%%\n",
bd_data->normalized_value,
safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 1024.0));
@@ -4291,7 +4509,7 @@ static void wdc_print_bd_ca_log_normal(void *data)
}
bd_data++;
if (bd_data->field_id == 0x06) {
- raw = (__u64*)&bd_data->raw_value[1];
+ raw = (__u64*)&bd_data->raw_value[0];
printf("timed_workload_host_reads : %3"PRIu8"%% %"PRIu64"%%\n",
bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
} else {
@@ -4299,7 +4517,7 @@ static void wdc_print_bd_ca_log_normal(void *data)
}
bd_data++;
if (bd_data->field_id == 0x07) {
- raw = (__u64*)&bd_data->raw_value[1];
+ raw = (__u64*)&bd_data->raw_value[0];
printf("timed_workload_timer : %3"PRIu8"%% %"PRIu64"\n",
bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
} else {
@@ -4316,7 +4534,7 @@ static void wdc_print_bd_ca_log_normal(void *data)
}
bd_data++;
if (bd_data->field_id == 0x09) {
- raw = (__u64*)&bd_data->raw_value[1];
+ raw = (__u64*)&bd_data->raw_value[0];
printf("retry_buffer_overflow_count : %3"PRIu8"%% %"PRIu64"\n",
bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
} else {
@@ -4324,7 +4542,7 @@ static void wdc_print_bd_ca_log_normal(void *data)
}
bd_data++;
if (bd_data->field_id == 0x0A) {
- raw = (__u64*)&bd_data->raw_value[1];
+ raw = (__u64*)&bd_data->raw_value[0];
printf("pll_lock_loss_count : %3"PRIu8"%% %"PRIu64"\n",
bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
} else {
@@ -4332,7 +4550,7 @@ static void wdc_print_bd_ca_log_normal(void *data)
}
bd_data++;
if (bd_data->field_id == 0x0B) {
- raw = (__u64*)&bd_data->raw_value[1];
+ raw = (__u64*)&bd_data->raw_value[0];
printf("nand_bytes_written : %3"PRIu8"%% sectors: %.f\n",
bd_data->normalized_value, safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF));
} else {
@@ -4340,7 +4558,7 @@ static void wdc_print_bd_ca_log_normal(void *data)
}
bd_data++;
if (bd_data->field_id == 0x0C) {
- raw = (__u64*)&bd_data->raw_value[1];
+ raw = (__u64*)&bd_data->raw_value[0];
printf("host_bytes_written : %3"PRIu8"%% sectors: %.f\n",
bd_data->normalized_value, safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF));
} else {
@@ -4368,7 +4586,7 @@ static void wdc_print_bd_ca_log_json(void *data)
root = json_create_object();
if (bd_data->field_id == 0x00) {
- raw = (__u64*)&bd_data->raw_value[1];
+ raw = (__u64*)&bd_data->raw_value[0];
json_object_add_value_int(root, "program_fail_count normalized",
bd_data->normalized_value);
json_object_add_value_int(root, "program_fail_count raw",
@@ -4378,7 +4596,7 @@ static void wdc_print_bd_ca_log_json(void *data)
}
bd_data++;
if (bd_data->field_id == 0x01) {
- raw = (__u64*)&bd_data->raw_value[1];
+ raw = (__u64*)&bd_data->raw_value[0];
json_object_add_value_int(root, "erase_fail_count normalized",
bd_data->normalized_value);
json_object_add_value_int(root, "erase_fail_count raw",
@@ -4400,7 +4618,7 @@ static void wdc_print_bd_ca_log_json(void *data)
}
bd_data++;
if (bd_data->field_id == 0x03) {
- raw = (__u64*)&bd_data->raw_value[1];
+ raw = (__u64*)&bd_data->raw_value[0];
json_object_add_value_int(root, "end_to_end_error_detection_count normalized",
bd_data->normalized_value);
json_object_add_value_int(root, "end_to_end_error_detection_count raw",
@@ -4410,7 +4628,7 @@ static void wdc_print_bd_ca_log_json(void *data)
}
bd_data++;
if (bd_data->field_id == 0x04) {
- raw = (__u64*)&bd_data->raw_value[1];
+ raw = (__u64*)&bd_data->raw_value[0];
json_object_add_value_int(root, "crc_error_count normalized",
bd_data->normalized_value);
json_object_add_value_int(root, "crc_error_count raw",
@@ -4420,17 +4638,17 @@ static void wdc_print_bd_ca_log_json(void *data)
}
bd_data++;
if (bd_data->field_id == 0x05) {
- raw = (__u64*)&bd_data->raw_value[1];
+ raw = (__u64*)&bd_data->raw_value[0];
json_object_add_value_int(root, "timed_workload_media_wear normalized",
bd_data->normalized_value);
- json_object_add_value_float(root, "timed_workload_media_wear raw",
+ json_object_add_value_double(root, "timed_workload_media_wear raw",
safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 1024.0));
} else {
goto invalid_id;
}
bd_data++;
if (bd_data->field_id == 0x06) {
- raw = (__u64*)&bd_data->raw_value[1];
+ raw = (__u64*)&bd_data->raw_value[0];
json_object_add_value_int(root, "timed_workload_host_reads normalized",
bd_data->normalized_value);
json_object_add_value_int(root, "timed_workload_host_reads raw",
@@ -4440,7 +4658,7 @@ static void wdc_print_bd_ca_log_json(void *data)
}
bd_data++;
if (bd_data->field_id == 0x07) {
- raw = (__u64*)&bd_data->raw_value[1];
+ raw = (__u64*)&bd_data->raw_value[0];
json_object_add_value_int(root, "timed_workload_timer normalized",
bd_data->normalized_value);
json_object_add_value_int(root, "timed_workload_timer",
@@ -4461,7 +4679,7 @@ static void wdc_print_bd_ca_log_json(void *data)
}
bd_data++;
if (bd_data->field_id == 0x09) {
- raw = (__u64*)&bd_data->raw_value[1];
+ raw = (__u64*)&bd_data->raw_value[0];
json_object_add_value_int(root, "retry_buffer_overflow_count normalized",
bd_data->normalized_value);
json_object_add_value_int(root, "retry_buffer_overflow_count raw",
@@ -4471,7 +4689,7 @@ static void wdc_print_bd_ca_log_json(void *data)
}
bd_data++;
if (bd_data->field_id == 0x0A) {
- raw = (__u64*)&bd_data->raw_value[1];
+ raw = (__u64*)&bd_data->raw_value[0];
json_object_add_value_int(root, "pll_lock_loss_count normalized",
bd_data->normalized_value);
json_object_add_value_int(root, "pll_lock_loss_count raw",
@@ -4481,20 +4699,20 @@ static void wdc_print_bd_ca_log_json(void *data)
}
bd_data++;
if (bd_data->field_id == 0x0B) {
- raw = (__u64*)&bd_data->raw_value[1];
+ raw = (__u64*)&bd_data->raw_value[0];
json_object_add_value_int(root, "nand_bytes_written normalized",
bd_data->normalized_value);
- json_object_add_value_float(root, "nand_bytes_written raw",
+ json_object_add_value_double(root, "nand_bytes_written raw",
safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF));
} else {
goto invalid_id;
}
bd_data++;
if (bd_data->field_id == 0x0C) {
- raw = (__u64*)&bd_data->raw_value[1];
+ raw = (__u64*)&bd_data->raw_value[0];
json_object_add_value_int(root, "host_bytes_written normalized",
bd_data->normalized_value);
- json_object_add_value_float(root, "host_bytes_written raw",
+ json_object_add_value_double(root, "host_bytes_written raw",
safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF));
} else {
goto invalid_id;
@@ -4678,6 +4896,7 @@ static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u
struct wdc_fw_act_history_log_format_c2 *fw_act_history_entry = (struct wdc_fw_act_history_log_format_c2 *)(data);
+ oldestEntryIdx = WDC_MAX_NUM_ACT_HIST_ENTRIES;
if (num_entries == WDC_MAX_NUM_ACT_HIST_ENTRIES) {
/* find lowest/oldest entry */
for (i = 0; i < num_entries; i++) {
@@ -4761,6 +4980,7 @@ static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u
struct wdc_fw_act_history_log_entry *fw_act_history_entry = (struct wdc_fw_act_history_log_entry *)(data + sizeof(struct wdc_fw_act_history_log_hdr));
+ oldestEntryIdx = WDC_MAX_NUM_ACT_HIST_ENTRIES;
if (num_entries == WDC_MAX_NUM_ACT_HIST_ENTRIES) {
/* find lowest/oldest entry */
for (i = 0; i < num_entries; i++) {
@@ -4840,6 +5060,7 @@ static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32
if(data[0] == WDC_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID) {
struct wdc_fw_act_history_log_format_c2 *fw_act_history_entry = (struct wdc_fw_act_history_log_format_c2 *)(data);
+ oldestEntryIdx = WDC_MAX_NUM_ACT_HIST_ENTRIES;
if (num_entries == WDC_MAX_NUM_ACT_HIST_ENTRIES) {
/* find lowest/oldest entry */
for (i = 0; i < num_entries; i++) {
@@ -4910,6 +5131,7 @@ static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32
else {
struct wdc_fw_act_history_log_entry *fw_act_history_entry = (struct wdc_fw_act_history_log_entry *)(data + sizeof(struct wdc_fw_act_history_log_hdr));
+ oldestEntryIdx = WDC_MAX_NUM_ACT_HIST_ENTRIES;
if (num_entries == WDC_MAX_NUM_ACT_HIST_ENTRIES) {
/* find lowest/oldest entry */
for (i = 0; i < num_entries; i++) {
@@ -4970,6 +5192,682 @@ static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32
json_free_object(root);
}
+static int nvme_get_ext_smart_cloud_log(int fd, __u8 **data, int uuid_index, __u32 namespace_id)
+{
+ int ret, i;
+ __u8 *log_ptr = NULL;
+
+ if ((log_ptr = (__u8*) malloc(sizeof (__u8) * WDC_NVME_SMART_CLOUD_ATTR_LEN)) == NULL) {
+ fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno));
+ return -1;
+ }
+
+ /* Get the 0xC0 log data */
+ struct nvme_get_log_args args = {
+ .args_size = sizeof(args),
+ .fd = fd,
+ .lid = WDC_NVME_GET_EOL_STATUS_LOG_OPCODE,
+ .nsid = namespace_id,
+ .lpo = 0,
+ .lsp = NVME_LOG_LSP_NONE,
+ .lsi = 0,
+ .rae = false,
+ .uuidx = uuid_index,
+ .csi = NVME_CSI_NVM,
+ .ot = false,
+ .len = WDC_NVME_SMART_CLOUD_ATTR_LEN,
+ .log = log_ptr,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ ret = nvme_get_log(&args);
+
+ if (ret == 0) {
+
+ /* Verify GUID matches */
+ for (i = 0; i < WDC_C0_GUID_LENGTH; i++) {
+ if (ext_smart_guid[i] != *&log_ptr[SCAO_V1_LPG + i]) {
+ fprintf(stderr, "ERROR : WDC : Unknown GUID in C0 Log Page V1 data\n");
+ int j;
+ fprintf(stderr, "ERROR : WDC : Expected GUID: 0x");
+ for (j = 0; j < WDC_C0_GUID_LENGTH; j++) {
+ fprintf(stderr, "%x", ext_smart_guid[j]);
+ }
+ fprintf(stderr, "\nERROR : WDC : Actual GUID: 0x");
+ for (j = 0; j < WDC_C0_GUID_LENGTH; j++) {
+ fprintf(stderr, "%x", *&log_ptr[SCAO_V1_LPG + j]);
+ }
+ fprintf(stderr, "\n");
+
+ ret = -1;
+ break;
+ }
+ }
+ }
+
+ *data = log_ptr;
+
+ return ret;
+}
+
+
+static int nvme_get_hw_rev_log(int fd, __u8 **data, int uuid_index, __u32 namespace_id)
+{
+ int ret, i;
+ wdc_nvme_hw_rev_log *log_ptr = NULL;
+
+ if ((log_ptr = (wdc_nvme_hw_rev_log *)malloc(sizeof (__u8) * WDC_NVME_HW_REV_LOG_PAGE_LEN)) == NULL) {
+ fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno));
+ return -1;
+ }
+
+ /* Get the 0xC0 log data */
+ struct nvme_get_log_args args = {
+ .args_size = sizeof(args),
+ .fd = fd,
+ .lid = WDC_NVME_GET_HW_REV_LOG_OPCODE,
+ .nsid = namespace_id,
+ .lpo = 0,
+ .lsp = NVME_LOG_LSP_NONE,
+ .lsi = 0,
+ .rae = false,
+ .uuidx = uuid_index,
+ .csi = NVME_CSI_NVM,
+ .ot = false,
+ .len = WDC_NVME_HW_REV_LOG_PAGE_LEN,
+ .log = log_ptr,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ ret = nvme_get_log(&args);
+
+ if (ret == 0) {
+
+ /* Verify GUID matches */
+ for (i = 0; i < WDC_NVME_C6_GUID_LENGTH; i++) {
+ if (hw_rev_log_guid[i] != log_ptr->hw_rev_guid[i]) {
+ fprintf(stderr, "ERROR : WDC : Unknown GUID in HW Revision Log Page data\n");
+ int j;
+ fprintf(stderr, "ERROR : WDC : Expected GUID: 0x");
+ for (j = 0; j < WDC_NVME_C6_GUID_LENGTH; j++) {
+ fprintf(stderr, "%x", hw_rev_log_guid[j]);
+ }
+ fprintf(stderr, "\nERROR : WDC : Actual GUID: 0x");
+ for (j = 0; j < WDC_NVME_C6_GUID_LENGTH; j++) {
+ fprintf(stderr, "%x", log_ptr->hw_rev_guid[j]);
+ }
+ fprintf(stderr, "\n");
+
+ ret = -1;
+ break;
+ }
+ }
+ }
+
+ *data = (__u8 *)log_ptr;
+
+ return ret;
+}
+
+
+static void wdc_print_hw_rev_log_normal(void *data)
+{
+ int i;
+ wdc_nvme_hw_rev_log *log_data = (wdc_nvme_hw_rev_log *)data;
+
+ printf(" Hardware Revision Log:- \n");
+
+ printf(" Global Device HW Revision : %d\n",
+ log_data->hw_rev_gdr);
+ printf(" ASIC HW Revision : %d\n",
+ log_data->hw_rev_ar);
+ printf(" PCB Manufacturer Code : %d\n",
+ log_data->hw_rev_pbc_mc);
+ printf(" DRAM Manufacturer Code : %d\n",
+ log_data->hw_rev_dram_mc);
+ printf(" NAND Manufacturer Code : %d\n",
+ log_data->hw_rev_nand_mc);
+ printf(" PMIC 1 Manufacturer Code : %d\n",
+ log_data->hw_rev_pmic1_mc);
+ printf(" PMIC 2 Manufacturer Code : %d\n",
+ log_data->hw_rev_pmic2_mc);
+ printf(" Other Component 1 Manf Code : %d\n",
+ log_data->hw_rev_c1_mc);
+ printf(" Other Component 2 Manf Code : %d\n",
+ log_data->hw_rev_c2_mc);
+ printf(" Other Component 3 Manf Code : %d\n",
+ log_data->hw_rev_c3_mc);
+ printf(" Other Component 4 Manf Code : %d\n",
+ log_data->hw_rev_c4_mc);
+ printf(" Other Component 5 Manf Code : %d\n",
+ log_data->hw_rev_c5_mc);
+ printf(" Other Component 6 Manf Code : %d\n",
+ log_data->hw_rev_c6_mc);
+ printf(" Other Component 7 Manf Code : %d\n",
+ log_data->hw_rev_c7_mc);
+ printf(" Other Component 8 Manf Code : %d\n",
+ log_data->hw_rev_c8_mc);
+ printf(" Other Component 9 Manf Code : %d\n",
+ log_data->hw_rev_c9_mc);
+
+ printf(" Device Manf Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_dev_mdi[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" ASIC Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_asic_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" PCB Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_pcb_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" DRAM Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_dram_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" NAND Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_nand_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" PMIC 1 Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_pmic1_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" PMIC 2 Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_pmic2_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" Component 1 Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_c1_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" Component 2 Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_c2_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" Component 3 Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_c3_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" Component 4 Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_c4_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" Component 5 Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_c5_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" Component 6 Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_c6_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" Component 7 Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_c7_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" Component 8 Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_c8_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" Component 9 Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_c9_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" Serial Number : 0x");
+ for (i = 0; i < 32; i++) {
+ if ((i > 1) & !(i % 8))
+ printf(" 0x");
+ printf("%02x", log_data->hw_rev_sn[i]);
+ }
+ printf("\n");
+
+ printf(" Log Page Version : %d\n",
+ log_data->hw_rev_version);
+ printf(" Log page GUID : 0x");
+ printf("%"PRIx64"%"PRIx64"\n",le64_to_cpu(*(uint64_t *)&log_data->hw_rev_guid[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_guid[0]));
+ printf("\n");
+}
+
+static void wdc_print_hw_rev_log_json(void *data)
+{
+ wdc_nvme_hw_rev_log *log_data = (wdc_nvme_hw_rev_log *)data;
+ struct json_object *root;
+ char json_data[80];
+
+ root = json_create_object();
+ json_object_add_value_uint(root, "Global Device HW Revision",
+ log_data->hw_rev_gdr);
+ json_object_add_value_uint(root, "ASIC HW Revision",
+ log_data->hw_rev_ar);
+ json_object_add_value_uint(root, "PCB Manufacturer Code",
+ log_data->hw_rev_pbc_mc);
+ json_object_add_value_uint(root, "DRAM Manufacturer Code",
+ log_data->hw_rev_dram_mc);
+ json_object_add_value_uint(root, "NAND Manufacturer Code",
+ log_data->hw_rev_nand_mc);
+ json_object_add_value_uint(root, "PMIC 1 Manufacturer Code",
+ log_data->hw_rev_pmic1_mc);
+ json_object_add_value_uint(root, "PMIC 2 Manufacturer Code",
+ log_data->hw_rev_pmic2_mc);
+ json_object_add_value_uint(root, "Other Component 1 Manf Code",
+ log_data->hw_rev_c1_mc);
+ json_object_add_value_uint(root, "Other Component 2 Manf Code",
+ log_data->hw_rev_c2_mc);
+ json_object_add_value_uint(root, "Other Component 3 Manf Code",
+ log_data->hw_rev_c3_mc);
+ json_object_add_value_uint(root, "Other Component 4 Manf Code",
+ log_data->hw_rev_c4_mc);
+ json_object_add_value_uint(root, "Other Component 5 Manf Code",
+ log_data->hw_rev_c5_mc);
+ json_object_add_value_uint(root, "Other Component 6 Manf Code",
+ log_data->hw_rev_c6_mc);
+ json_object_add_value_uint(root, "Other Component 7 Manf Code",
+ log_data->hw_rev_c7_mc);
+ json_object_add_value_uint(root, "Other Component 8 Manf Code",
+ log_data->hw_rev_c8_mc);
+ json_object_add_value_uint(root, "Other Component 9 Manf Code",
+ log_data->hw_rev_c9_mc);
+
+ memset((void*)json_data, 0, 40);
+ sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_dev_mdi[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_dev_mdi[0]));
+ json_object_add_value_string(root, "Device Manf Detailed Info", json_data);
+
+ memset((void*)json_data, 0, 40);
+ sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_asic_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_asic_di[0]));
+ json_object_add_value_string(root, "ASIC Detailed Info", json_data);
+
+ memset((void*)json_data, 0, 40);
+ sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pcb_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pcb_di[0]));
+ json_object_add_value_string(root, "PCB Detailed Info", json_data);
+
+ memset((void*)json_data, 0, 40);
+ sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_dram_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_dram_di[0]));
+ json_object_add_value_string(root, "DRAM Detailed Info", json_data);
+
+ memset((void*)json_data, 0, 40);
+ sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_nand_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_nand_di[0]));
+ json_object_add_value_string(root, "NAND Detailed Info", json_data);
+
+ memset((void*)json_data, 0, 40);
+ sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pmic1_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pmic1_di[0]));
+ json_object_add_value_string(root, "PMIC 1 Detailed Info", json_data);
+
+ memset((void*)json_data, 0, 40);
+ sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pmic2_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pmic2_di[0]));
+ json_object_add_value_string(root, "PMIC 2 Detailed Info", json_data);
+
+ memset((void*)json_data, 0, 40);
+ sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c1_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c1_di[0]));
+ json_object_add_value_string(root, "Component 1 Detailed Info", json_data);
+
+ memset((void*)json_data, 0, 40);
+ sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c2_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c2_di[0]));
+ json_object_add_value_string(root, "Component 2 Detailed Info", json_data);
+
+ memset((void*)json_data, 0, 40);
+ sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c3_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c3_di[0]));
+ json_object_add_value_string(root, "Component 3 Detailed Info", json_data);
+
+ memset((void*)json_data, 0, 40);
+ sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c4_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c4_di[0]));
+ json_object_add_value_string(root, "Component 4 Detailed Info", json_data);
+
+ memset((void*)json_data, 0, 40);
+ sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c5_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c5_di[0]));
+ json_object_add_value_string(root, "Component 5 Detailed Info", json_data);
+
+ memset((void*)json_data, 0, 40);
+ sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c6_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c6_di[0]));
+ json_object_add_value_string(root, "Component 6 Detailed Info", json_data);
+
+ memset((void*)json_data, 0, 40);
+ sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c7_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c7_di[0]));
+ json_object_add_value_string(root, "Component 7 Detailed Info", json_data);
+
+ memset((void*)json_data, 0, 40);
+ sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c8_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c8_di[0]));
+ json_object_add_value_string(root, "Component 8 Detailed Info", json_data);
+
+ memset((void*)json_data, 0, 40);
+ sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c9_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c9_di[0]));
+ json_object_add_value_string(root, "Component 9 Detailed Info", json_data);
+
+ memset((void*)json_data, 0, 80);
+ sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"%"PRIx64"%"PRIx64"",
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_sn[0]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_sn[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_sn[16]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_sn[24]));
+ json_object_add_value_string(root, "Serial Number", json_data);
+
+ json_object_add_value_uint(root, "Log Page Version",
+ le16_to_cpu(log_data->hw_rev_version));
+
+ memset((void*)json_data, 0, 40);
+ sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_guid[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_guid[0]));
+ json_object_add_value_string(root, "Log Page GUID", json_data);
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void wdc_print_ext_smart_cloud_log_normal(void *data, int mask)
+{
+ int i;
+ wdc_nvme_ext_smart_log *ext_smart_log_ptr = (wdc_nvme_ext_smart_log *)data;
+
+ if (mask == WDC_SCA_V1_NAND_STATS)
+ printf(" NAND Statistics :- \n");
+ else
+ printf(" SMART Cloud Attributes :- \n");
+
+ printf(" Physical Media Units Written TLC (Bytes) : %'.0Lf\n",
+ int128_to_double(ext_smart_log_ptr->ext_smart_pmuwt));
+ printf(" Physical Media Units Written SLC (Bytes) : %'.0Lf\n",
+ int128_to_double(ext_smart_log_ptr->ext_smart_pmuws));
+ printf(" Bad User NAND Block Count (Normalized) (Int) : %d\n",
+ le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_bunbc));
+ printf(" Bad User NAND Block Count (Raw) (Int) : %"PRIu64"\n",
+ le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_bunbc & 0xFFFFFFFFFFFF0000));
+ printf(" XOR Recovery Count (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_xrc));
+ printf(" Uncorrectable Read Error Count (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_urec));
+ if (mask == WDC_SCA_V1_ALL) {
+ printf(" SSD End to End correction counts (Corrected Errors) (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_eece));
+ printf(" SSD End to End correction counts (Detected Errors) (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_eede));
+ printf(" SSD End to End correction counts (Uncorrected E2E Errors) (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_eeue));
+ printf(" System Data %% life-used : %d %%\n",
+ ext_smart_log_ptr->ext_smart_sdpu);
+ }
+ printf(" User data erase counts (Minimum TLC) (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_mnudec));
+ printf(" User data erase counts (Maximum TLC) (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_mxudec));
+ printf(" User data erase counts (Minimum SLC) (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_mnec));
+ printf(" User data erase counts (Maximum SLC) (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_mxec));
+ printf(" User data erase counts (Average SLC) (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_avec));
+ printf(" User data erase counts (Average TLC) (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_avudec));
+ printf(" Program Fail Count (Normalized) (Int) : %d\n",
+ le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_pfc));
+ printf(" Program Fail Count (Raw) (Int) : %"PRIu64"\n",
+ le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_pfc & 0xFFFFFFFFFFFF0000));
+ printf(" Erase Fail Count (Normalized) (Int) : %d\n",
+ le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_efc));
+ printf(" Erase Fail Count (Raw) (Int) : %"PRIu64"\n",
+ le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_efc & 0xFFFFFFFFFFFF0000));
+ if (mask == WDC_SCA_V1_ALL) {
+ printf(" PCIe Correctable Error Count (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_pcec));
+ printf(" %% Free Blocks (User) (Int) : %d %%\n",
+ ext_smart_log_ptr->ext_smart_pfbu);
+ printf(" Security Version Number (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_svn));
+ printf(" %% Free Blocks (System) (Int) : %d %%\n",
+ ext_smart_log_ptr->ext_smart_pfbs);
+ printf(" NVMe Stats (# Data Set Management/TRIM Commands Completed) (Int) : %'.0Lf\n",
+ int128_to_double(ext_smart_log_ptr->ext_smart_dcc));
+ printf(" Total Namespace Utilization (nvme0n1 NUSE) (Bytes) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_tnu));
+ printf(" NVMe Stats (# NVMe Format Commands Completed) (Int) : %d\n",
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_fcc));
+ printf(" Background Back-Pressure Gauge(%%) (Int) : %d\n",
+ ext_smart_log_ptr->ext_smart_bbpg);
+ }
+ printf(" Total # of Soft ECC Error Count (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_seec));
+ if (mask == WDC_SCA_V1_ALL) {
+ printf(" Total # of Read Refresh Count (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_rfsc));
+ }
+ printf(" Bad System NAND Block Count (Normalized) (Int) : %d\n",
+ le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_bsnbc));
+ printf(" Bad System NAND Block Count (Raw) (Int) : %"PRIu64"\n",
+ le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_bsnbc & 0xFFFFFFFFFFFF0000));
+ printf(" Endurance Estimate (Total Writable Lifetime Bytes) (Bytes) : %'.0Lf\n",
+ int128_to_double(ext_smart_log_ptr->ext_smart_eest));
+ if (mask == WDC_SCA_V1_ALL) {
+ printf(" Thermal Throttling Status & Count (Number of thermal throttling events) (Int) : %d\n",
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_ttc));
+ printf(" Total # Unaligned I/O (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_uio));
+ }
+ printf(" Total Physical Media Units Read (Bytes) (Int) : %'.0Lf\n",
+ int128_to_double(ext_smart_log_ptr->ext_smart_pmur));
+ if (mask == WDC_SCA_V1_ALL) {
+ printf(" Command Timeout (# of READ Commands > 5 Seconds) (Int) : %"PRIu32"\n",
+ le32_to_cpu(ext_smart_log_ptr->ext_smart_rtoc));
+ printf(" Command Timeout (# of WRITE Commands > 5 Seconds) (Int) : %"PRIu32"\n",
+ le32_to_cpu(ext_smart_log_ptr->ext_smart_wtoc));
+ printf(" Command Timeout (# of TRIM Commands > 5 Seconds) (Int) : %"PRIu32"\n",
+ le32_to_cpu(ext_smart_log_ptr->ext_smart_ttoc));
+ printf(" Total PCIe Link Retraining Count (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_plrc));
+ printf(" Active Power State Change Count (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_pscc));
+ }
+ printf(" Cloud Boot SSD Spec Version (Int) : %d.%d.%d.%d\n",
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_maj),
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_min),
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_pt),
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_err));
+ printf(" Cloud Boot SSD HW Revision (Int) : %d.%d.%d.%d\n",
+ 0, 0, 0, 0);
+ if (mask == WDC_SCA_V1_ALL) {
+ printf(" FTL Unit Size : %"PRIu32"\n",
+ le32_to_cpu(ext_smart_log_ptr->ext_smart_ftlus));
+ printf(" TCG Ownership Status : %"PRIu32"\n",
+ le32_to_cpu(ext_smart_log_ptr->ext_smart_tcgos));
+ printf(" Log Page Version (Int) : %d\n",
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_lpv));
+ printf(" Log page GUID (Hex) : 0x");
+ for (i = WDC_C0_GUID_LENGTH; i > 0; i--)
+ printf("%02x", ext_smart_log_ptr->ext_smart_lpg[i-1]);
+ printf("\n");
+ }
+ printf("\n");
+}
+
+static void wdc_print_ext_smart_cloud_log_json(void *data, int mask)
+{
+ wdc_nvme_ext_smart_log *ext_smart_log_ptr = (wdc_nvme_ext_smart_log *)data;
+ struct json_object *root;
+
+ root = json_create_object();
+ json_object_add_value_double(root, "physical_media_units_bytes_tlc",
+ int128_to_double(ext_smart_log_ptr->ext_smart_pmuwt));
+ json_object_add_value_double(root, "physical_media_units_bytes_slc",
+ int128_to_double(ext_smart_log_ptr->ext_smart_pmuws));
+ json_object_add_value_uint(root, "bad_user_blocks_normalized",
+ le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_bunbc));
+ json_object_add_value_uint64(root, "bad_user_blocks_raw",
+ le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_bunbc & 0xFFFFFFFFFFFF0000));
+ json_object_add_value_uint64(root, "xor_recovery_count",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_xrc));
+ json_object_add_value_uint64(root, "uncorrectable_read_errors",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_urec));
+ if (mask == WDC_SCA_V1_ALL) {
+ json_object_add_value_uint64(root, "corrected_e2e_errors",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_eece));
+ json_object_add_value_uint64(root, "detected_e2e_errors",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_eede));
+ json_object_add_value_uint64(root, "uncorrected_e2e_errors",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_eeue));
+ json_object_add_value_uint(root, "system_data_life_used_pct",
+ (__u8)ext_smart_log_ptr->ext_smart_sdpu);
+ }
+ json_object_add_value_uint64(root, "min_slc_user_data_erase_count",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_mnec));
+ json_object_add_value_uint64(root, "min_tlc_user_data_erase_count",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_mnudec));
+ json_object_add_value_uint64(root, "max_slc_user_data_erase_count",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_mxec));
+ json_object_add_value_uint64(root, "max_tlc_user_data_erase_count",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_mxudec));
+ json_object_add_value_uint64(root, "avg_slc_user_data_erase_count",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_avec));
+ json_object_add_value_uint64(root, "avg_tlc_user_data_erase_count",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_avudec));
+ json_object_add_value_uint(root, "program_fail_count_normalized",
+ le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_pfc));
+ json_object_add_value_uint64(root, "program_fail_count_raw",
+ le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_pfc & 0xFFFFFFFFFFFF0000));
+ json_object_add_value_uint(root, "erase_fail_count_normalized",
+ le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_efc));
+ json_object_add_value_uint64(root, "erase_fail_count_raw",
+ le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_efc & 0xFFFFFFFFFFFF0000));
+ if (mask == WDC_SCA_V1_ALL) {
+ json_object_add_value_uint64(root, "pcie_correctable_errors",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_pcec));
+ json_object_add_value_uint(root, "pct_free_blocks_user",
+ (__u8)ext_smart_log_ptr->ext_smart_pfbu);
+ json_object_add_value_uint64(root, "security_version",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_svn));
+ json_object_add_value_uint(root, "pct_free_blocks_system",
+ (__u8)ext_smart_log_ptr->ext_smart_pfbs);
+ json_object_add_value_double(root, "num_of_trim_commands",
+ int128_to_double(ext_smart_log_ptr->ext_smart_dcc));
+ json_object_add_value_uint64(root, "total_nuse_bytes",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_tnu));
+ json_object_add_value_uint(root, "num_of_format_commands",
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_fcc));
+ json_object_add_value_uint(root, "background_pressure_gauge",
+ (__u8)ext_smart_log_ptr->ext_smart_bbpg);
+ }
+ json_object_add_value_uint64(root, "soft_ecc_error_count",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_seec));
+ if (mask == WDC_SCA_V1_ALL) {
+ json_object_add_value_uint64(root, "read_refresh_count",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_rfsc));
+ }
+ json_object_add_value_uint(root, "bad_system_block_normalized",
+ le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_bsnbc));
+ json_object_add_value_uint64(root, "bad_system_block_raw",
+ le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_bsnbc & 0xFFFFFFFFFFFF0000));
+ json_object_add_value_double(root, "endurance_est_bytes",
+ int128_to_double(ext_smart_log_ptr->ext_smart_eest));
+ if (mask == WDC_SCA_V1_ALL) {
+ json_object_add_value_uint(root, "num_throttling_events",
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_ttc));
+ json_object_add_value_uint64(root, "total_unaligned_io",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_uio));
+ }
+ json_object_add_value_double(root, "physical_media_units_read_bytes",
+ int128_to_double(ext_smart_log_ptr->ext_smart_pmur));
+ if (mask == WDC_SCA_V1_ALL) {
+ json_object_add_value_uint(root, "num_read_timeouts",
+ le32_to_cpu(ext_smart_log_ptr->ext_smart_rtoc));
+ json_object_add_value_uint(root, "num_write_timeouts",
+ le32_to_cpu(ext_smart_log_ptr->ext_smart_wtoc));
+ json_object_add_value_uint(root, "num_trim_timeouts",
+ le32_to_cpu(ext_smart_log_ptr->ext_smart_ttoc));
+ json_object_add_value_uint64(root, "pcie_link_retrain_count",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_plrc));
+ json_object_add_value_uint64(root, "active_power_state_change_count",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_pscc));
+ }
+ char vers_str[40];
+ memset((void*)vers_str, 0, 40);
+ sprintf((char*)vers_str, "%d.%d.%d.%d",
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_maj), le16_to_cpu(ext_smart_log_ptr->ext_smart_min),
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_pt), le16_to_cpu(ext_smart_log_ptr->ext_smart_err));
+ json_object_add_value_string(root, "cloud_boot_ssd_spec_ver", vers_str);
+ memset((void*)vers_str, 0, 40);
+ sprintf((char*)vers_str, "%d.%d.%d.%d", 0, 0, 0, 0);
+ json_object_add_value_string(root, "cloud_boot_ssd_hw_ver", vers_str);
+
+ if (mask == WDC_SCA_V1_ALL) {
+ json_object_add_value_uint(root, "ftl_unit_size",
+ le32_to_cpu(ext_smart_log_ptr->ext_smart_ftlus));
+ json_object_add_value_uint(root, "tcg_ownership_status",
+ le32_to_cpu(ext_smart_log_ptr->ext_smart_tcgos));
+ json_object_add_value_uint(root, "log_page_ver",
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_lpv));
+ char guid[40];
+ memset((void*)guid, 0, 40);
+ sprintf((char*)guid, "0x%"PRIx64"%"PRIx64"",le64_to_cpu(*(uint64_t *)&ext_smart_log_ptr->ext_smart_lpg[8]),
+ le64_to_cpu(*(uint64_t *)&ext_smart_log_ptr->ext_smart_lpg[0]));
+ json_object_add_value_string(root, "log_page_guid", guid);
+ }
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
static void wdc_print_smart_cloud_attr_C0_normal(void *data)
{
__u8 *log_data = (__u8*)data;
@@ -4977,12 +5875,8 @@ static void wdc_print_smart_cloud_attr_C0_normal(void *data)
printf(" SMART Cloud Attributes :- \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",
- (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(" Physical media units written : %'.0Lf\n", int128_to_double(&log_data[SCAO_PMUW]));
+ printf(" Physical media units read : %'.0Lf\n", int128_to_double(&log_data[SCAO_PMUR]));
printf(" Bad user nand blocks Raw : %"PRIu64"\n",
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BUNBR] & 0x0000FFFFFFFFFFFF));
printf(" Bad user nand blocks Normalized : %d\n",
@@ -5023,12 +5917,12 @@ static void wdc_print_smart_cloud_attr_C0_normal(void *data)
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN]));
printf(" NUSE Namespace utilization : %"PRIu64"\n",
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE]));
- printf(" PLP start count : %.0Lf\n", int128_to_double(&log_data[SCAO_PSC]));
- printf(" Endurance estimate : %.0Lf\n", int128_to_double(&log_data[SCAO_EEST]));
+ printf(" PLP start count : %'.0Lf\n", int128_to_double(&log_data[SCAO_PSC]));
+ printf(" Endurance estimate : %'.0Lf\n", int128_to_double(&log_data[SCAO_EEST]));
smart_log_ver = (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_LPV]);
printf(" Log page version : %"PRIu16"\n",smart_log_ver);
printf(" Log page GUID : 0x");
- printf("0x%"PRIx64"%"PRIx64"\n",(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]),
+ printf("%"PRIx64"%"PRIx64"\n",(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]),
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG]));
if(smart_log_ver > 2) {
printf(" Errata Version Field : %d\n",
@@ -5044,6 +5938,10 @@ static void wdc_print_smart_cloud_attr_C0_normal(void *data)
printf(" PCIe Link Retraining Count : %"PRIu64"\n",
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PLRC]));
}
+ if (smart_log_ver > 3) {
+ printf(" Power State Change Count : %"PRIu64"\n",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PSCC]));
+ }
printf("\n");
}
@@ -5054,14 +5952,10 @@ static void wdc_print_smart_cloud_attr_C0_json(void *data)
uint16_t smart_log_ver = 0;
root = json_create_object();
- json_object_add_value_uint64(root, "Physical media units written hi",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW+8] & 0xFFFFFFFFFFFFFFFF));
- json_object_add_value_uint64(root, "Physical media units written lo",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW] & 0xFFFFFFFFFFFFFFFF));
- json_object_add_value_uint64(root, "Physical media units read hi",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR+8] & 0xFFFFFFFFFFFFFFFF));
- json_object_add_value_uint64(root, "Physical media units read lo",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR] & 0xFFFFFFFFFFFFFFFF));
+ json_object_add_value_double(root, "Physical media units written",
+ int128_to_double(&log_data[SCAO_PMUW]));
+ json_object_add_value_double(root, "Physical media units read",
+ int128_to_double(&log_data[SCAO_PMUR]));
json_object_add_value_uint64(root, "Bad user nand blocks - Raw",
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BUNBR] & 0x0000FFFFFFFFFFFF));
json_object_add_value_uint(root, "Bad user nand blocks - Normalized",
@@ -5106,9 +6000,9 @@ static void wdc_print_smart_cloud_attr_C0_json(void *data)
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN]));
json_object_add_value_uint64(root, "NUSE - Namespace utilization",
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE]));
- json_object_add_value_uint(root, "PLP start count",
+ json_object_add_value_double(root, "PLP start count",
int128_to_double(&log_data[SCAO_PSC]));
- json_object_add_value_uint(root, "Endurance estimate",
+ json_object_add_value_double(root, "Endurance estimate",
int128_to_double(&log_data[SCAO_EEST]));
smart_log_ver = (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_LPV]);
json_object_add_value_uint(root, "Log page version", smart_log_ver);
@@ -5131,6 +6025,10 @@ static void wdc_print_smart_cloud_attr_C0_json(void *data)
json_object_add_value_uint64(root, "PCIe Link Retraining Count",
(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PLRC]));
}
+ if(smart_log_ver > 3) {
+ json_object_add_value_uint64(root, "Power State Change Count",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PSCC]));
+ }
json_print_object(root, NULL);
printf("\n");
json_free_object(root);
@@ -5187,6 +6085,23 @@ static void wdc_print_eol_c0_json(void *data)
json_free_object(root);
}
+static int wdc_print_ext_smart_cloud_log(void *data, int fmt)
+{
+ if (!data) {
+ fprintf(stderr, "ERROR : WDC : Invalid buffer to read 0xC0 V1 log\n");
+ return -1;
+ }
+ switch (fmt) {
+ case NORMAL:
+ wdc_print_ext_smart_cloud_log_normal(data, WDC_SCA_V1_ALL);
+ break;
+ case JSON:
+ wdc_print_ext_smart_cloud_log_json(data, WDC_SCA_V1_ALL);
+ break;
+ }
+ return 0;
+}
+
static int wdc_print_c0_cloud_attr_log(void *data, int fmt)
{
if (!data) {
@@ -5249,12 +6164,16 @@ static int wdc_get_c0_log_page(nvme_root_t r, int fd, char *format,
case WDC_NVME_SN640_DEV_ID_3:
case WDC_NVME_SN840_DEV_ID:
case WDC_NVME_SN840_DEV_ID_1:
+ case WDC_NVME_SN860_DEV_ID:
case WDC_NVME_SN650_DEV_ID:
case WDC_NVME_SN650_DEV_ID_1:
case WDC_NVME_SN650_DEV_ID_2:
case WDC_NVME_SN650_DEV_ID_3:
case WDC_NVME_SN650_DEV_ID_4:
case WDC_NVME_SN655_DEV_ID:
+ case WDC_NVME_SN560_DEV_ID_1:
+ case WDC_NVME_SN560_DEV_ID_2:
+ case WDC_NVME_SN560_DEV_ID_3:
cust_id = wdc_get_fw_cust_id(r, fd);
if (cust_id == WDC_INVALID_CUSTOMER_ID) {
fprintf(stderr, "%s: ERROR : WDC : invalid customer id\n", __func__);
@@ -5427,9 +6346,28 @@ static int wdc_get_c0_log_page(nvme_root_t r, int fd, char *format,
free(data);
break;
+ case WDC_NVME_SN820CL_DEV_ID:
+ /* Get the 0xC0 Extended Smart Cloud Attribute log data */
+ data = NULL;
+ ret = nvme_get_ext_smart_cloud_log(fd, &data, uuid_index, namespace_id);
+
+ if (strcmp(format, "json"))
+ nvme_show_status(ret);
+
+ if (ret == 0) {
+ /* parse the data */
+ wdc_print_ext_smart_cloud_log(data, fmt);
+ } else {
+ fprintf(stderr, "ERROR : WDC : Unable to read C0 Log Page V1 data\n");
+ ret = -1;
+ }
+
+ if (data)
+ free(data);
+ break;
+
default:
fprintf(stderr, "ERROR : WDC : Unknown device id - 0x%x\n", device_id);
-
ret = -1;
break;
@@ -5649,7 +6587,7 @@ static int wdc_get_ca_log_page(nvme_root_t r, int fd, char *format)
case WDC_NVME_SN640_DEV_ID_3:
case WDC_NVME_SN840_DEV_ID:
case WDC_NVME_SN840_DEV_ID_1:
-
+ case WDC_NVME_SN860_DEV_ID:
if (cust_id == WDC_CUSTOMER_ID_0x1005) {
if ((data = (__u8*) malloc(sizeof (__u8) * WDC_FB_CA_LOG_BUF_LEN)) == NULL) {
@@ -6223,6 +7161,285 @@ static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command,
out:
nvme_free_tree(r);
+ close(fd);
+ return ret;
+}
+
+static int wdc_vs_cloud_log(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve Cloud Log Smart/Health Information";
+ const char *namespace_id = "desired namespace id";
+ int fd;
+ nvme_root_t r;
+ int ret = 0;
+ __u64 capabilities = 0;
+ __u8 *data;
+ int fmt = -1;
+
+ struct config {
+ char *output_format;
+ __u32 namespace_id;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ .namespace_id = NVME_NSID_ALL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"),
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ r = nvme_scan(NULL);
+
+ capabilities = wdc_get_drive_capabilities(r, fd);
+
+ if ((capabilities & WDC_DRIVE_CAP_CLOUD_LOG_PAGE) == 0) {
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ ret = -1;
+ goto out;
+ }
+
+ data = NULL;
+ ret = nvme_get_ext_smart_cloud_log(fd, &data, 0, cfg.namespace_id);
+
+ if (strcmp(cfg.output_format, "json"))
+ nvme_show_status(ret);
+
+ if (ret == 0) {
+ fmt = validate_output_format(cfg.output_format);
+ if (fmt < 0) {
+ fprintf(stderr, "ERROR : WDC %s: invalid output format\n", __func__);
+ ret = fmt;
+ }
+
+ /* parse the data */
+ wdc_print_ext_smart_cloud_log(data, fmt);
+ } else {
+ fprintf(stderr, "ERROR : WDC : Unable to read C0 Log Page V1 data\n");
+ ret = -1;
+ }
+
+ if (data)
+ free(data);
+
+out:
+ nvme_free_tree(r);
+ close(fd);
+ return ret;
+}
+
+static int wdc_vs_hw_rev_log(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve Hardware Revision Log Information";
+ const char *namespace_id = "desired namespace id";
+ int fd;
+ nvme_root_t r;
+ int ret = 0;
+ __u64 capabilities = 0;
+ __u8 *data = NULL;
+ int fmt = -1;
+
+ struct config {
+ char *output_format;
+ __u32 namespace_id;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ .namespace_id = NVME_NSID_ALL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"),
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ r = nvme_scan(NULL);
+
+ capabilities = wdc_get_drive_capabilities(r, fd);
+
+ if ((capabilities & WDC_DRIVE_CAP_HW_REV_LOG_PAGE) == 0) {
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ ret = -1;
+ goto out;
+ }
+
+ ret = nvme_get_hw_rev_log(fd, &data, 0, cfg.namespace_id);
+
+ if (strcmp(cfg.output_format, "json"))
+ nvme_show_status(ret);
+
+ if (ret == 0) {
+ fmt = validate_output_format(cfg.output_format);
+ if (fmt < 0) {
+ fprintf(stderr, "ERROR : WDC %s: invalid output format\n", __func__);
+ ret = fmt;
+ goto free_buf;
+ }
+
+ if (!data) {
+ fprintf(stderr, "ERROR : WDC : Invalid buffer to read Hardware Revision log\n");
+ ret = -1;
+ goto out;
+ }
+ switch (fmt) {
+ case NORMAL:
+ wdc_print_hw_rev_log_normal(data);
+ break;
+ case JSON:
+ wdc_print_hw_rev_log_json(data);
+ break;
+ }
+ } else {
+ fprintf(stderr, "ERROR : WDC : Unable to read Hardware Revision Log Page data\n");
+ ret = -1;
+ }
+
+free_buf:
+ if (data)
+ free(data);
+
+out:
+ nvme_free_tree(r);
+ close(fd);
+ return ret;
+}
+
+static int wdc_vs_device_waf(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve Device Write Amplication Factor";
+ const char *namespace_id = "desired namespace id";
+ struct nvme_smart_log smart_log;
+ __u8 *data;
+ int fd;
+ nvme_root_t r;
+ int ret = 0;
+ int fmt = -1;
+ __u64 capabilities = 0;
+ wdc_nvme_ext_smart_log *ext_smart_log_ptr;
+ long double data_units_written = 0,
+ phys_media_units_written_tlc = 0,
+ phys_media_units_written_slc = 0;
+ struct json_object *root = NULL;
+ char tlc_waf_str[32] = { 0 },
+ slc_waf_str[32] = { 0 };
+
+ struct config {
+ char *output_format;
+ __u32 namespace_id;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ .namespace_id = NVME_NSID_ALL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"),
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ r = nvme_scan(NULL);
+
+ capabilities = wdc_get_drive_capabilities(r, fd);
+
+ if ((capabilities & WDC_DRIVE_CAP_DEVICE_WAF) == 0) {
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ ret = -1;
+ goto out;
+ }
+
+ /* get data units written from the smart log page */
+ ret = nvme_get_log_smart(fd, cfg.namespace_id, true, &smart_log);
+ if (!ret) {
+ data_units_written = int128_to_double(smart_log.data_units_written);
+ }
+ else if (ret > 0) {
+ nvme_show_status(ret);
+ ret = -1;
+ goto out;
+ } else {
+ fprintf(stderr, "smart log: %s\n", nvme_strerror(errno));
+ ret = -1;
+ goto out;
+ }
+
+ /* get Physical Media Units Written from extended smart/C0 log page */
+ data = NULL;
+ ret = nvme_get_ext_smart_cloud_log(fd, &data, 0, cfg.namespace_id);
+
+ if (ret == 0) {
+ ext_smart_log_ptr = (wdc_nvme_ext_smart_log *)data;
+ phys_media_units_written_tlc = int128_to_double(ext_smart_log_ptr->ext_smart_pmuwt);
+ phys_media_units_written_slc = int128_to_double(ext_smart_log_ptr->ext_smart_pmuws);
+
+ if (data)
+ free(data);
+ } else {
+ fprintf(stderr, "ERROR : WDC %s: get smart cloud log failure\n", __func__);
+ ret = -1;
+ goto out;
+ }
+
+ if (strcmp(cfg.output_format, "json"))
+ nvme_show_status(ret);
+
+ fmt = validate_output_format(cfg.output_format);
+ if (fmt < 0) {
+ fprintf(stderr, "ERROR : WDC %s: invalid output format\n", __func__);
+ ret = fmt;
+ goto out;
+ }
+
+ if (data_units_written == 0) {
+ fprintf(stderr, "ERROR : WDC %s: 0 data units written\n", __func__);
+ ret = -1;
+ goto out;
+ }
+
+ if (fmt == NORMAL) {
+ printf("Device Write Amplification Factor TLC : %4.2Lf\n",
+ (phys_media_units_written_tlc/data_units_written));
+ printf("Device Write Amplification Factor SLC : %4.2Lf\n",
+ (phys_media_units_written_slc/data_units_written));
+ }
+ else if (fmt == JSON) {
+ root = json_create_object();
+ sprintf(tlc_waf_str, "%4.2Lf", (phys_media_units_written_tlc/data_units_written));
+ sprintf(slc_waf_str, "%4.2Lf", (phys_media_units_written_slc/data_units_written));
+
+ json_object_add_value_string(root, "Device Write Amplification Factor TLC", tlc_waf_str);
+ json_object_add_value_string(root, "Device Write Amplification Factor SLC", slc_waf_str);
+
+ json_print_object(root, NULL);
+ printf("\n");
+
+ json_free_object(root);
+ }
+
+out:
+ nvme_free_tree(r);
+ close(fd);
return ret;
}
@@ -6266,6 +7483,8 @@ static int wdc_get_latency_monitor_log(int argc, char **argv, struct command *co
fprintf(stderr, "ERROR : WDC : Failure reading the Latency Monitor (C3) Log Page, ret = %d\n", ret);
out:
+ nvme_free_tree(r);
+ close(fd);
return ret;
}
@@ -6309,6 +7528,8 @@ static int wdc_get_error_recovery_log(int argc, char **argv, struct command *com
fprintf(stderr, "ERROR : WDC : Failure reading the Error Recovery (C1) Log Page, ret = 0x%x\n", ret);
out:
+ nvme_free_tree(r);
+ close(fd);
return ret;
}
@@ -6352,6 +7573,8 @@ static int wdc_get_dev_capabilities_log(int argc, char **argv, struct command *c
fprintf(stderr, "ERROR : WDC : Failure reading the Device Capabilities (C4) Log Page, ret = 0x%x\n", ret);
out:
+ nvme_free_tree(r);
+ close(fd);
return ret;
}
@@ -6395,6 +7618,8 @@ static int wdc_get_unsupported_reqs_log(int argc, char **argv, struct command *c
fprintf(stderr, "ERROR : WDC : Failure reading the Unsupported Requirements (C5) Log Page, ret = 0x%x\n", ret);
out:
+ nvme_free_tree(r);
+ close(fd);
return ret;
}
@@ -6480,6 +7705,7 @@ static int wdc_clear_pcie_correctable_errors(int argc, char **argv, struct comma
out:
nvme_free_tree(r);
+ close(fd);
return ret;
}
@@ -6597,6 +7823,7 @@ static int wdc_drive_status(int argc, char **argv, struct command *command,
out:
nvme_free_tree(r);
+ close(fd);
return ret;
}
@@ -6647,6 +7874,7 @@ static int wdc_clear_assert_dump(int argc, char **argv, struct command *command,
out:
nvme_free_tree(r);
+ close(fd);
return ret;
}
@@ -6834,7 +8062,8 @@ static int wdc_vs_fw_activate_history(int argc, char **argv, struct command *com
/* to retrieve fw activate history data */
if ((data = (__u8*) malloc(sizeof (__u8) * WDC_NVME_SMART_CLOUD_ATTR_LEN)) == NULL) {
fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno));
- return -1;
+ ret = -1;
+ goto out;
}
/* Get the 0xC0 log data */
@@ -6887,6 +8116,7 @@ static int wdc_vs_fw_activate_history(int argc, char **argv, struct command *com
fprintf(stderr, "ERROR : WDC : Failure reading the FW Activate History, ret = %d\n", ret);
out:
nvme_free_tree(r);
+ close(fd);
return ret;
}
@@ -6944,15 +8174,14 @@ static int wdc_clear_fw_activate_history(int argc, char **argv, struct command *
goto out;
}
- if (capabilities & WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY) {
+ if (capabilities & WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY)
ret = wdc_do_clear_fw_activate_history_vuc(fd);
- }
- else {
+ else
ret = wdc_do_clear_fw_activate_history_fid(fd);
- }
out:
nvme_free_tree(r);
+ close(fd);
return ret;
}
@@ -7043,6 +8272,7 @@ static int wdc_vs_telemetry_controller_option(int argc, char **argv, struct comm
out:
nvme_free_tree(r);
+ close(fd);
return ret;
}
@@ -7179,7 +8409,7 @@ static int wdc_get_log_dir_max_entries(int fd, __u32* maxNumOfEntries)
{
fprintf(stderr, "ERROR : WDC : %s: Failed to get headerPayloadSize from file directory 0x%x\n",
__func__, ret);
- goto end;
+ return ret;
}
fileIdOffsetsBufferSize = WDC_DE_FILE_HEADER_SIZE + (headerPayloadSize * WDC_DE_FILE_OFFSET_SIZE);
@@ -7201,9 +8431,8 @@ static int wdc_get_log_dir_max_entries(int fd, __u32* maxNumOfEntries)
continue;
(*maxNumOfEntries)++;
}
- end:
- if (!fileIdOffsetsBuffer)
- free(fileIdOffsetsBuffer);
+end:
+ free(fileIdOffsetsBuffer);
return ret;
}
@@ -7319,7 +8548,10 @@ static int wdc_fetch_log_file_from_device(int fd, __u32 fileId, __u16 spiDestn,
goto end;
}
- wdc_get_max_transfer_len(fd, &maximumTransferLength);
+ if (wdc_get_max_transfer_len(fd, &maximumTransferLength) < 0) {
+ ret = WDC_STATUS_FAILURE;
+ goto end;
+ }
/* Fetch Log File Data */
if ((fileSize >= maximumTransferLength) || (fileSize > 0xFFFFFFFF))
@@ -7379,7 +8611,8 @@ static int wdc_de_get_dump_trace(int fd, char * filePath, __u16 binFileNameLen,
return ret;
}
- wdc_get_max_transfer_len(fd, &maximumTransferLength);
+ if (wdc_get_max_transfer_len(fd, &maximumTransferLength) < 0)
+ return WDC_STATUS_FAILURE;
do
{
@@ -7757,7 +8990,7 @@ static int wdc_drive_essentials(int argc, char **argv, struct command *command,
char d[PATH_MAX] = {0};
char k[PATH_MAX] = {0};
char *d_ptr;
- int fd;
+ int fd, ret;
nvme_root_t r;
__u64 capabilities = 0;
@@ -7783,8 +9016,8 @@ static int wdc_drive_essentials(int argc, char **argv, struct command *command,
capabilities = wdc_get_drive_capabilities(r, fd);
if ((capabilities & WDC_DRIVE_CAP_DRIVE_ESSENTIALS) != WDC_DRIVE_CAP_DRIVE_ESSENTIALS) {
fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
- nvme_free_tree(r);
- return -1;
+ ret = -1;
+ goto out;
}
if (cfg.dirName != NULL) {
@@ -7794,7 +9027,11 @@ static int wdc_drive_essentials(int argc, char **argv, struct command *command,
d_ptr = NULL;
}
- return wdc_do_drive_essentials(r, fd, d_ptr, k);
+ ret = wdc_do_drive_essentials(r, fd, d_ptr, k);
+out:
+ nvme_free_tree(r);
+ close(fd);
+ return ret;
}
static int wdc_do_drive_resize(int fd, uint64_t new_size)
@@ -7885,6 +9122,7 @@ static int wdc_drive_resize(int argc, char **argv,
nvme_show_status(ret);
nvme_free_tree(r);
+ close(fd);
return ret;
}
@@ -7924,6 +9162,7 @@ static int wdc_namespace_resize(int argc, char **argv,
(cfg.op_option != 0xF))
{
fprintf(stderr, "ERROR : WDC: unsupported OP option parameter\n");
+ close(fd);
return -1;
}
@@ -7942,6 +9181,7 @@ static int wdc_namespace_resize(int argc, char **argv,
nvme_show_status(ret);
nvme_free_tree(r);
+ close(fd);
return ret;
}
@@ -8017,8 +9257,12 @@ static int wdc_reason_identifier(int argc, char **argv,
ret = -1;
goto close_fd;
}
-
- snprintf(f + strlen(f), PATH_MAX, "%s", ".bin");
+ if (strlen(f) > PATH_MAX - 5) {
+ fprintf(stderr, "ERROR : WDC: file name overflow\n");
+ ret = -1;
+ goto close_fd;
+ }
+ strcat(f, ".bin");
}
fprintf(stderr, "%s: filename = %s\n", __func__, f);
@@ -8060,6 +9304,7 @@ static const char *nvme_log_id_to_string(__u8 log_id)
case WDC_LOG_ID_C0: return "WDC Vendor Unique Log ID C0";
case WDC_LOG_ID_C1: return "WDC Vendor Unique Log ID C1";
case WDC_LOG_ID_C2: return "WDC Vendor Unique Log ID C2";
+ case WDC_LOG_ID_C3: return "WDC Vendor Unique Log ID C3";
case WDC_LOG_ID_C4: return "WDC Vendor Unique Log ID C4";
case WDC_LOG_ID_C5: return "WDC Vendor Unique Log ID C5";
case WDC_LOG_ID_C6: return "WDC Vendor Unique Log ID C6";
@@ -8114,6 +9359,7 @@ static int wdc_log_page_directory(int argc, char **argv, struct command *command
ret = validate_output_format(cfg.output_format);
if (ret < 0) {
fprintf(stderr, "%s: ERROR : WDC : invalid output format\n", __func__);
+ close(fd);
return ret;
}
ret = 0;
@@ -8172,6 +9418,7 @@ static int wdc_log_page_directory(int argc, char **argv, struct command *command
out:
nvme_free_tree(r);
+ close(fd);
return ret;
}
@@ -8229,7 +9476,11 @@ static int wdc_save_reason_id(int fd, __u8 *rsn_ident, int size)
/* make the nvmecli dir in /usr/local if it doesn't already exist */
if (stat(reason_id_path, &st) == -1) {
- mkdir(reason_id_path, 0700);
+ if (mkdir(reason_id_path, 0700) < 0) {
+ fprintf(stderr, "%s: ERROR : failed to mkdir %s : %s\n",
+ __func__, reason_id_path, strerror(errno));
+ return -1;
+ }
}
if (asprintf(&reason_id_file, "%s/%s%s", reason_id_path,
@@ -8472,9 +9723,9 @@ static void wdc_print_nand_stats_json(__u16 version, void *data)
case 0:
- json_object_add_value_float(root, "NAND Writes TLC (Bytes)",
+ json_object_add_value_double(root, "NAND Writes TLC (Bytes)",
int128_to_double(nand_stats->nand_write_tlc));
- json_object_add_value_float(root, "NAND Writes SLC (Bytes)",
+ json_object_add_value_double(root, "NAND Writes SLC (Bytes)",
int128_to_double(nand_stats->nand_write_slc));
json_object_add_value_uint(root, "NAND Program Failures",
le32_to_cpu(nand_stats->nand_prog_failure));
@@ -8495,9 +9746,9 @@ static void wdc_print_nand_stats_json(__u16 version, void *data)
case 3:
- json_object_add_value_float(root, "NAND Writes TLC (Bytes)",
+ json_object_add_value_double(root, "NAND Writes TLC (Bytes)",
int128_to_double(nand_stats_v3->nand_write_tlc));
- json_object_add_value_float(root, "NAND Writes SLC (Bytes)",
+ json_object_add_value_double(root, "NAND Writes SLC (Bytes)",
int128_to_double(nand_stats_v3->nand_write_slc));
temp_ptr = (__u64 *)nand_stats_v3->bad_nand_block_count;
temp_norm = (__u16)(*temp_ptr & 0x000000000000FFFF);
@@ -8548,7 +9799,7 @@ static void wdc_print_nand_stats_json(__u16 version, void *data)
le64_to_cpu(nand_stats_v3->security_version_number));
json_object_add_value_uint(root, "% Free Blocks (System)",
nand_stats_v3->percent_free_blocks_system);
- json_object_add_value_float(root, "Data Set Management Commands",
+ json_object_add_value_double(root, "Data Set Management Commands",
int128_to_double(nand_stats_v3->trim_completions));
json_object_add_value_uint64(root, "Estimate of Incomplete Trim Data",
le64_to_cpu(nand_stats_v3->trim_completions[16]));
@@ -8567,7 +9818,7 @@ static void wdc_print_nand_stats_json(__u16 version, void *data)
le16_to_cpu(temp_norm));
json_object_add_value_uint64(root, "Bad System Nand Block Count - Raw",
le64_to_cpu(temp_raw));
- json_object_add_value_float(root, "Endurance Estimate",
+ json_object_add_value_double(root, "Endurance Estimate",
int128_to_double(nand_stats_v3->endurance_estimate));
json_object_add_value_uint(root, "Thermal Throttling Status",
nand_stats_v3->thermal_throttling_st_ct[0]);
@@ -8575,7 +9826,7 @@ static void wdc_print_nand_stats_json(__u16 version, void *data)
nand_stats_v3->thermal_throttling_st_ct[1]);
json_object_add_value_uint64(root, "Unaligned I/O",
le64_to_cpu(nand_stats_v3->unaligned_IO));
- json_object_add_value_float(root, "Physical Media Units Read",
+ json_object_add_value_double(root, "Physical Media Units Read",
int128_to_double(nand_stats_v3->physical_media_units));
json_object_add_value_uint(root, "log page version",
le16_to_cpu(nand_stats_v3->log_page_version));
@@ -8677,6 +9928,43 @@ static void wdc_print_pcie_stats_json(struct wdc_vs_pcie_stats *pcie_stats)
json_free_object(root);
}
+static int wdc_do_vs_nand_stats_sn810_2(int fd, char *format)
+{
+ int ret;
+ int fmt = -1;
+ uint8_t *data = NULL;
+
+ data = NULL;
+ ret = nvme_get_ext_smart_cloud_log(fd, &data, 0, NVME_NSID_ALL);
+
+ if (ret) {
+ fprintf(stderr, "ERROR : WDC : %s : Failed to retreive NAND stats\n", __func__);
+ goto out;
+ } else {
+ fmt = validate_output_format(format);
+ if (fmt < 0) {
+ fprintf(stderr, "ERROR : WDC : %s : invalid output format\n", __func__);
+ ret = fmt;
+ goto out;
+ }
+
+ /* parse the data */
+ switch (fmt) {
+ case NORMAL:
+ wdc_print_ext_smart_cloud_log_normal(data, WDC_SCA_V1_NAND_STATS);
+ break;
+ case JSON:
+ wdc_print_ext_smart_cloud_log_json(data, WDC_SCA_V1_NAND_STATS);
+ break;
+ }
+ }
+
+out:
+ if (data)
+ free(data);
+ return ret;
+}
+
static int wdc_do_vs_nand_stats(int fd, char *format)
{
int ret;
@@ -8730,6 +10018,7 @@ static int wdc_vs_nand_stats(int argc, char **argv, struct command *command,
int ret = 0;
nvme_root_t r;
__u64 capabilities = 0;
+ uint32_t read_device_id = 0, read_vendor_id = 0;
struct config {
char *output_format;
@@ -8755,12 +10044,28 @@ static int wdc_vs_nand_stats(int argc, char **argv, struct command *command,
fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
ret = -1;
} else {
- ret = wdc_do_vs_nand_stats(fd, cfg.output_format);
- if (ret)
- fprintf(stderr, "ERROR : WDC : Failure reading NAND statistics, ret = %d\n", ret);
+ ret = wdc_get_pci_ids(r, &read_device_id, &read_vendor_id);
+ if (ret < 0)
+ {
+ fprintf(stderr, "ERROR : WDC: %s: failure to get pci ids, ret = %d\n", __func__, ret);
+ return -1;
+ }
+
+ switch (read_device_id) {
+ case WDC_NVME_SN820CL_DEV_ID:
+ ret = wdc_do_vs_nand_stats_sn810_2(fd, cfg.output_format);
+ break;
+ default:
+ ret = wdc_do_vs_nand_stats(fd, cfg.output_format);
+ break;
+ }
}
+ if (ret)
+ fprintf(stderr, "ERROR : WDC : Failure reading NAND statistics, ret = %d\n", ret);
+
nvme_free_tree(r);
+ close(fd);
return ret;
}
@@ -8856,6 +10161,7 @@ static int wdc_vs_pcie_stats(int argc, char **argv, struct command *command,
out:
nvme_free_tree(r);
+ close(fd);
return ret;
}
@@ -8872,10 +10178,15 @@ static int wdc_vs_drive_info(int argc, char **argv,
struct nvme_id_ctrl ctrl;
char vsData[32] = {0};
char major_rev = 0, minor_rev = 0;
+ __u8 *data = NULL;
+ __u32 ftl_unit_size = 0, tcg_dev_ownership = 0;
+ __u16 boot_spec_major = 0, boot_spec_minor = 0;
int fmt = -1;
struct json_object *root = NULL;
char formatter[41] = { 0 };
- char rev_str[8] = { 0 };
+ char rev_str[16] = { 0 };
+ uint32_t read_device_id = -1, read_vendor_id = -1;
+ wdc_nvme_ext_smart_log *ext_smart_log_ptr = NULL;
struct config {
char *output_format;
@@ -8897,6 +10208,7 @@ static int wdc_vs_drive_info(int argc, char **argv,
fmt = validate_output_format(cfg.output_format);
if (fmt < 0) {
fprintf(stderr, "ERROR : WDC %s invalid output format\n", __func__);
+ close(fd);
return fmt;
}
@@ -8905,6 +10217,7 @@ static int wdc_vs_drive_info(int argc, char **argv,
if (ret) {
fprintf(stderr, "ERROR : WDC %s: Identify Controller failed\n", __func__);
+ close(fd);
return ret;
}
@@ -8912,24 +10225,72 @@ static int wdc_vs_drive_info(int argc, char **argv,
wdc_check_device(r, fd);
capabilities = wdc_get_drive_capabilities(r, fd);
if ((capabilities & WDC_DRIVE_CAP_INFO) == WDC_DRIVE_CAP_INFO) {
- ret = wdc_do_drive_info(fd, &result);
+ ret = wdc_get_pci_ids(r, &read_device_id, &read_vendor_id);
+ if (ret < 0)
+ {
+ fprintf(stderr, "ERROR : WDC: %s: failure to get pci ids, ret = %d\n", __func__, ret);
+ goto out;
+ }
- if (!ret) {
- size = (__u16)((cpu_to_le32(result) & 0xffff0000) >> 16);
- rev = (double)(cpu_to_le32(result) & 0x0000ffff);
+ switch (read_device_id) {
+ case WDC_NVME_SN640_DEV_ID:
+ case WDC_NVME_SN640_DEV_ID_1:
+ case WDC_NVME_SN640_DEV_ID_2:
+ case WDC_NVME_SN640_DEV_ID_3:
+ case WDC_NVME_SN650_DEV_ID:
+ case WDC_NVME_SN650_DEV_ID_1:
+ case WDC_NVME_SN650_DEV_ID_2:
+ case WDC_NVME_SN650_DEV_ID_3:
+ case WDC_NVME_SN650_DEV_ID_4:
+ case WDC_NVME_SN655_DEV_ID:
+ case WDC_NVME_SN560_DEV_ID_1:
+ case WDC_NVME_SN560_DEV_ID_2:
+ case WDC_NVME_SN560_DEV_ID_3:
+ case WDC_NVME_SN550_DEV_ID:
+ case WDC_NVME_ZN350_DEV_ID:
+ case WDC_NVME_ZN350_DEV_ID_1:
+ ret = wdc_do_drive_info(fd, &result);
+
+ if (!ret) {
+ size = (__u16)((cpu_to_le32(result) & 0xffff0000) >> 16);
+ rev = (double)(cpu_to_le32(result) & 0x0000ffff);
+
+ if (fmt == NORMAL) {
+ printf("Drive HW Revison: %4.1f\n", (.1 * rev));
+ printf("FTL Unit Size: 0x%x KB\n", size);
+ printf("Customer SN: %-.*s\n", (int)sizeof(ctrl.sn), &ctrl.sn[0]);
+ }
+ else if (fmt == JSON) {
+ root = json_create_object();
+ sprintf(rev_str, "%4.1f", (.1 * rev));
+ json_object_add_value_string(root, "Drive HW Revison", rev_str);
+
+ json_object_add_value_int(root, "FTL Unit Size", le16_to_cpu(size));
+ wdc_StrFormat(formatter, sizeof(formatter), &ctrl.sn[0], sizeof(ctrl.sn));
+ json_object_add_value_string(root, "Customer SN", formatter);
+
+ json_print_object(root, NULL);
+ printf("\n");
+
+ json_free_object(root);
+ }
+ }
+ break;
+ case WDC_NVME_SN730A_DEV_ID:
+ memcpy(vsData, &ctrl.vs[0], 32);
+
+ major_rev = ctrl.sn[12];
+ minor_rev = ctrl.sn[13];
if (fmt == NORMAL) {
- printf("Drive HW Revison: %4.1f\n", (.1 * rev));
- printf("FTL Unit Size: 0x%x KB\n", size);
- printf("Customer SN: %-.*s\n", (int)sizeof(ctrl.sn), &ctrl.sn[0]);
+ printf("Drive HW Revision: %c.%c \n", major_rev, minor_rev);
+ printf("Customer SN: %-.*s\n", 14, &ctrl.sn[0]);
}
else if (fmt == JSON) {
root = json_create_object();
- sprintf(rev_str, "%4.1f", (.1 * rev));
+ sprintf(rev_str, "%c.%c", major_rev, minor_rev);
json_object_add_value_string(root, "Drive HW Revison", rev_str);
-
- json_object_add_value_int(root, "FTL Unit Size", le16_to_cpu(size));
- wdc_StrFormat(formatter, sizeof(formatter), &ctrl.sn[0], sizeof(ctrl.sn));
+ wdc_StrFormat(formatter, sizeof(formatter), &ctrl.sn[0], 14);
json_object_add_value_string(root, "Customer SN", formatter);
json_print_object(root, NULL);
@@ -8937,39 +10298,87 @@ static int wdc_vs_drive_info(int argc, char **argv,
json_free_object(root);
}
- }
- }
- else if ((capabilities & WDC_DRIVE_CAP_INFO_2) == WDC_DRIVE_CAP_INFO_2) {
- memcpy(vsData, &ctrl.vs[0], 32);
+ break;
+ case WDC_NVME_SN820CL_DEV_ID:
+ /* Get the Drive HW Rev from the C6 Log page */
+ ret = nvme_get_hw_rev_log(fd, &data, 0, NVME_NSID_ALL);
+ if (ret == 0) {
+ wdc_nvme_hw_rev_log *log_data = (wdc_nvme_hw_rev_log *)data;
+ major_rev = log_data->hw_rev_gdr;
- major_rev = ctrl.sn[12];
- minor_rev = ctrl.sn[13];
+ free(data);
+ data = NULL;
+ } else {
+ fprintf(stderr, "ERROR : WDC: %s: failure to get hw revision log\n", __func__);
+ ret = -1;
+ goto out;
+ }
- if (fmt == NORMAL) {
- printf("Drive HW Revision: %c.%c \n", major_rev, minor_rev);
- printf("Customer SN: %-.*s\n", 14, &ctrl.sn[0]);
- }
- else if (fmt == JSON) {
- root = json_create_object();
- sprintf(rev_str, "%c.%c", major_rev, minor_rev);
- json_object_add_value_string(root, "Drive HW Revison", rev_str);
- wdc_StrFormat(formatter, sizeof(formatter), &ctrl.sn[0], 14);
- json_object_add_value_string(root, "Customer SN", formatter);
-
- json_print_object(root, NULL);
- printf("\n");
+ /* Get the Smart C0 log page */
+ if ((capabilities & WDC_DRIVE_CAP_CLOUD_LOG_PAGE) == 0) {
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ ret = -1;
+ goto out;
+ }
+
+ ret = nvme_get_ext_smart_cloud_log(fd, &data, 0, NVME_NSID_ALL);
- json_free_object(root);
+ if (ret == 0) {
+ ext_smart_log_ptr = (wdc_nvme_ext_smart_log *)data;
+
+ /* Set the FTL Unit size */
+ ftl_unit_size = le32_to_cpu(ext_smart_log_ptr->ext_smart_ftlus);
+
+ /* Set the Boot Spec Version */
+ boot_spec_major = le16_to_cpu(ext_smart_log_ptr->ext_smart_maj);
+ boot_spec_minor = le16_to_cpu(ext_smart_log_ptr->ext_smart_min);
+
+ /* Set the Drive Ownership Status */
+ tcg_dev_ownership = le32_to_cpu(ext_smart_log_ptr->ext_smart_tcgos);
+ free(data);
+ } else {
+ fprintf(stderr, "ERROR : WDC: %s: failure to get extended smart cloud log\n", __func__);
+ ret = -1;
+ goto out;
+ }
+
+ if (fmt == NORMAL) {
+ printf("Drive HW Revision: %2d\n", major_rev);
+ printf("FTL Unit Size: %d\n", ftl_unit_size);
+ printf("HyperScale Boot Version Spec: %d.%d\n", boot_spec_major, boot_spec_minor);
+ printf("TCG Device Ownership Status: %2d\n", tcg_dev_ownership);
+
+ }
+ else if (fmt == JSON) {
+ root = json_create_object();
+
+ json_object_add_value_int(root, "Drive HW Revison", major_rev);
+ json_object_add_value_int(root, "FTL Unit Size", ftl_unit_size);
+ sprintf(rev_str, "%d.%d", boot_spec_major, boot_spec_minor);
+ json_object_add_value_string(root, "HyperScale Boot Version Spec", rev_str);
+ json_object_add_value_int(root, "TCG Device Ownership Status", tcg_dev_ownership);
+
+ json_print_object(root, NULL);
+ printf("\n");
+
+ json_free_object(root);
+ }
+
+ break;
+ default:
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ ret = -1;
+ break;
}
} else {
- fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
- nvme_free_tree(r);
- return -1;
+ fprintf(stderr, "ERROR : WDC: capability not supported by this device\n");
+ ret = -1;
}
-
+out:
nvme_show_status(ret);
nvme_free_tree(r);
+ close(fd);
return ret;
}
@@ -9008,7 +10417,7 @@ static int wdc_vs_temperature_stats(int argc, char **argv,
if (fmt < 0) {
fprintf(stderr, "ERROR : WDC : invalid output format\n");
ret = fmt;
- goto END;
+ goto out;
}
/* check if command is supported */
@@ -9016,17 +10425,17 @@ static int wdc_vs_temperature_stats(int argc, char **argv,
capabilities = wdc_get_drive_capabilities(r, fd);
if ((capabilities & WDC_DRIVE_CAP_TEMP_STATS) != WDC_DRIVE_CAP_TEMP_STATS) {
fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
- nvme_free_tree(r);
- return -1;
+ ret = -1;
+ goto out;
}
/* get the temperature stats or report errors */
ret = nvme_identify_ctrl(fd, &id_ctrl);
if (ret != 0)
- goto END;
+ goto out;
ret = nvme_get_log_smart(fd, NVME_NSID_ALL, false, &smart_log);
if (ret != 0)
- goto END;
+ goto out;
/* convert from Kelvin to degrees Celsius */
temperature = ((smart_log.temperature[1] << 8) | smart_log.temperature[0]) - 273;
@@ -9083,9 +10492,10 @@ static int wdc_vs_temperature_stats(int argc, char **argv,
else
printf("%s: Invalid format\n", __func__);
-END:
+out:
nvme_show_status(ret);
nvme_free_tree(r);
+ close(fd);
return ret;
}
@@ -9165,7 +10575,7 @@ static int wdc_capabilities(int argc, char **argv,
printf("namespace-resize : %s\n",
capabilities & WDC_DRIVE_CAP_NS_RESIZE ? "Supported" : "Not Supported");
printf("vs-drive-info : %s\n",
- capabilities & (WDC_DRIVE_CAP_INFO | WDC_DRIVE_CAP_INFO_2) ? "Supported" : "Not Supported");
+ capabilities & WDC_DRIVE_CAP_INFO ? "Supported" : "Not Supported");
printf("vs-temperature-stats : %s\n",
capabilities & WDC_DRIVE_CAP_TEMP_STATS ? "Supported" : "Not Supported");
printf("cloud-SSD-plugin-version : %s\n",
@@ -9178,8 +10588,19 @@ static int wdc_capabilities(int argc, char **argv,
capabilities & WDC_DRIVE_CAP_OCP_C4_LOG_PAGE ? "Supported" : "Not Supported");
printf("get-unsupported-reqs-log : %s\n",
capabilities & WDC_DRIVE_CAP_OCP_C5_LOG_PAGE ? "Supported" : "Not Supported");
- printf("capabilities : Supported\n");
+ printf("get-latency-monitor-log : %s\n",
+ capabilities & WDC_DRIVE_CAP_C3_LOG_PAGE ? "Supported" : "Not Supported");
+ printf("cloud-boot-SSD-version : %s\n",
+ capabilities & WDC_DRIVE_CAP_CLOUD_BOOT_SSD_VERSION ? "Supported" : "Not Supported");
+ printf("vs-cloud-log : %s\n",
+ capabilities & WDC_DRIVE_CAP_CLOUD_LOG_PAGE ? "Supported" : "Not Supported");
+ printf("vs-hw-rev-log : %s\n",
+ capabilities & WDC_DRIVE_CAP_HW_REV_LOG_PAGE ? "Supported" : "Not Supported");
+ printf("vs-device_waf : %s\n",
+ capabilities & WDC_DRIVE_CAP_DEVICE_WAF ? "Supported" : "Not Supported");
+ printf("capabilities : Supported\n");
nvme_free_tree(r);
+ close(fd);
return 0;
}
@@ -9212,9 +10633,72 @@ static int wdc_cloud_ssd_plugin_version(int argc, char **argv,
}
nvme_free_tree(r);
+ close(fd);
return 0;
}
+static int wdc_cloud_boot_SSD_version(int argc, char **argv,
+ struct command *command, struct plugin *plugin)
+{
+ const char *desc = "Get Cloud Boot SSD Version command.";
+ const char *namespace_id = "desired namespace id";
+ nvme_root_t r;
+ uint64_t capabilities = 0;
+ int fd, ret = -1;
+ int major = 0, minor = 0;
+ __u8 *data = NULL;
+ wdc_nvme_ext_smart_log *ext_smart_log_ptr = NULL;
+
+ struct config {
+ __u32 namespace_id;
+ };
+
+ struct config cfg = {
+ .namespace_id = NVME_NSID_ALL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ /* get capabilities */
+ r = nvme_scan(NULL);
+ wdc_check_device(r, fd);
+ capabilities = wdc_get_drive_capabilities(r, fd);
+
+ if ((capabilities & WDC_DRIVE_CAP_CLOUD_BOOT_SSD_VERSION) == WDC_DRIVE_CAP_CLOUD_BOOT_SSD_VERSION) {
+ /* Get the 0xC0 Smart Cloud Attribute V1 log data */
+ ret = nvme_get_ext_smart_cloud_log(fd, &data, 0, cfg.namespace_id);
+
+ ext_smart_log_ptr = (wdc_nvme_ext_smart_log *)data;
+ if (ret == 0) {
+ major = le16_to_cpu(ext_smart_log_ptr->ext_smart_maj);
+ minor = le16_to_cpu(ext_smart_log_ptr->ext_smart_min);
+
+ /* print the version returned from the log page */
+ printf("HyperScale Boot Version: %d.%d\n", major, minor);
+
+ } else {
+ fprintf(stderr, "ERROR : WDC : Unable to read Extended Smart/C0 Log Page data\n");
+ ret = -1;
+ }
+
+ if (data)
+ free(data);
+ } else {
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ }
+
+ nvme_free_tree(r);
+ close(fd);
+ return ret;
+}
+
static int wdc_enc_get_log(int argc, char **argv, struct command *command,
struct plugin *plugin)
{
@@ -9226,7 +10710,7 @@ static int wdc_enc_get_log(int argc, char **argv, struct command *command,
int xfer_size = 0;
int fd;
int len;
- int err;
+ int err = 0;
struct config {
char *file;
@@ -9247,7 +10731,7 @@ static int wdc_enc_get_log(int argc, char **argv, struct command *command,
OPT_END()
};
- err = fd = parse_and_open(argc, argv, desc, opts);
+ fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0) {
goto ret;
}
@@ -9402,9 +10886,9 @@ static int wdc_enc_submit_move_data(int fd, char *cmd, int len, int xfer_size, F
}
}
} while (more);
- free(buf);
}
+ free(buf);
return err;
}
diff --git a/plugins/wdc/wdc-nvme.h b/plugins/wdc/wdc-nvme.h
index da21692..c7b7f4c 100644
--- a/plugins/wdc/wdc-nvme.h
+++ b/plugins/wdc/wdc-nvme.h
@@ -1,10 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
#undef CMD_INC_FILE
#define CMD_INC_FILE plugins/wdc/wdc-nvme
#if !defined(WDC_NVME) || defined(CMD_HEADER_MULTI_READ)
#define WDC_NVME
-#define WDC_PLUGIN_VERSION "1.16.4"
+#define WDC_PLUGIN_VERSION "2.0.3"
#include "cmd.h"
PLUGIN(NAME("wdc", "Western Digital vendor specific extensions", WDC_PLUGIN_VERSION),
@@ -40,6 +41,10 @@ PLUGIN(NAME("wdc", "Western Digital vendor specific extensions", WDC_PLUGIN_VERS
ENTRY("get-error-recovery-log", "WDC Get Error Recovery Log Page", wdc_get_error_recovery_log)
ENTRY("get-dev-capabilities-log", "WDC Get Device Capabilities Log Page", wdc_get_dev_capabilities_log)
ENTRY("get-unsupported-reqs-log", "WDC Get Unsupported Requirements Log Page", wdc_get_unsupported_reqs_log)
+ ENTRY("cloud-boot-SSD-version", "WDC Get the Cloud Boot SSD Version", wdc_cloud_boot_SSD_version)
+ ENTRY("vs-cloud-log", "WDC Get the Cloud Log Page", wdc_vs_cloud_log)
+ ENTRY("vs-hw-rev-log", "WDC Get the Hardware Revision Log Page", wdc_vs_hw_rev_log)
+ ENTRY("vs-device-waf", "WDC Calculate Device Write Amplication Factor", wdc_vs_device_waf)
)
);
diff --git a/plugins/wdc/wdc-utils.c b/plugins/wdc/wdc-utils.c
index 52c427b..38e61ed 100644
--- a/plugins/wdc/wdc-utils.c
+++ b/plugins/wdc/wdc-utils.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2017-2018 Western Digital Corporation or its affiliates.
*
diff --git a/plugins/wdc/wdc-utils.h b/plugins/wdc/wdc-utils.h
index 04d4b83..83b208e 100644
--- a/plugins/wdc/wdc-utils.h
+++ b/plugins/wdc/wdc-utils.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2017-2018 Western Digital Corporation or its affiliates.
*
diff --git a/plugins/ymtc/ymtc-nvme.c b/plugins/ymtc/ymtc-nvme.c
index dd5f004..cfbf6a6 100644
--- a/plugins/ymtc/ymtc-nvme.c
+++ b/plugins/ymtc/ymtc-nvme.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
@@ -30,9 +31,21 @@ static int show_ymtc_smart_log(int fd, __u32 nsid, const char *devname,
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(fd, &ctrl);
- if (err)
+ 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],
@@ -51,17 +64,17 @@ static int show_ymtc_smart_log(int fd, __u32 nsid, const char *devname,
/* 02 SI_VD_WEARLEVELING_COUNT */
get_ymtc_smart_info(smart, SI_VD_WEARLEVELING_COUNT, nm, raw);
printf("wear_leveling : %3d%% min: %u, max: %u, avg: %u\n", *nm,
- *raw, *(raw+2), *(raw+4));
+ *(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%% %"PRIu64"\n", *nm, int48_to_long(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%% %"PRIu64"%%, cnt: %"PRIu64"\n", *nm,
- int48_to_long(raw), int48_to_long(raw+1));
+ 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));
@@ -74,15 +87,15 @@ static int show_ymtc_smart_log(int fd, __u32 nsid, const char *devname,
/* 15 SI_VD_TEMPT_SINCE_BORN */
get_ymtc_smart_info(smart, SI_VD_TEMPT_SINCE_BORN, nm, raw);
printf("tempt_since_born : %3d%% max: %u, min: %u, curr: %u\n", *nm,
- *raw, *(raw+2), *(raw+4));
+ *(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,
- *raw, *(raw+2), *(raw+4));
+ *(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, *raw,
- *(raw+2), *(raw+4));
+ 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));
@@ -91,7 +104,8 @@ static int show_ymtc_smart_log(int fd, __u32 nsid, const char *devname,
printf("read_fail : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw));
/* 20 SI_VD_THERMAL_THROTTLE_TIME */
get_ymtc_smart_info(smart, SI_VD_THERMAL_THROTTLE_TIME, nm, raw);
- printf("thermal_throttle_time : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw));
+ 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));
@@ -140,5 +154,6 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
if (err > 0)
nvme_show_status(err);
+ close(fd);
return err;
}
diff --git a/plugins/ymtc/ymtc-nvme.h b/plugins/ymtc/ymtc-nvme.h
index c1ebc11..df5d598 100644
--- a/plugins/ymtc/ymtc-nvme.h
+++ b/plugins/ymtc/ymtc-nvme.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#undef CMD_INC_FILE
#define CMD_INC_FILE plugins/ymtc/ymtc-nvme
diff --git a/plugins/ymtc/ymtc-utils.h b/plugins/ymtc/ymtc-utils.h
index 700c764..39f79cb 100644
--- a/plugins/ymtc/ymtc-utils.h
+++ b/plugins/ymtc/ymtc-utils.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef __YMTC_UTILS_H__
#define __YMTC_UTILS_H__
diff --git a/plugins/zns/zns.c b/plugins/zns/zns.c
index 56e53af..0b96346 100644
--- a/plugins/zns/zns.c
+++ b/plugins/zns/zns.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
@@ -102,13 +103,12 @@ static int list(int argc, char **argv, struct command *cmd,
nvme_root = nvme_scan(NULL);
if (nvme_root) {
err = print_zns_list(nvme_root);
+ nvme_free_tree(nvme_root);
} else {
fprintf(stderr, "Failed to scan nvme subsystems\n");
err = -errno;
}
- nvme_free_tree(nvme_root);
-
return err;
}
@@ -1018,9 +1018,9 @@ static int zone_append(int argc, char **argv, struct command *cmd, struct plugin
const char *fua = "force unit access";
const char *prinfo = "protection information action and checks field";
const char *piremap = "protection information remap (for type 1 PI)";
- const char *ref_tag = "reference tag (for end to end PI)";
- const char *lbat = "logical block application tag (for end to end PI)";
- const char *lbatm = "logical block application tag mask (for end to end PI)";
+ const char *ref_tag = "reference tag for end-to-end PI";
+ const char *lbat = "logical block application tag for end-to-end PI";
+ const char *lbatm = "logical block application tag mask for end-to-end PI";
const char *metadata_size = "size of metadata in bytes";
const char *data_size = "size of data in bytes";
const char *latency = "output latency statistics";
@@ -1044,7 +1044,7 @@ static int zone_append(int argc, char **argv, struct command *cmd, struct plugin
bool limited_retry;
bool fua;
__u32 namespace_id;
- __u32 ref_tag;
+ __u64 ref_tag;
__u16 lbat;
__u16 lbatm;
__u8 prinfo;
@@ -1063,7 +1063,7 @@ static int zone_append(int argc, char **argv, struct command *cmd, struct plugin
OPT_FILE("metadata", 'M', &cfg.metadata, metadata),
OPT_FLAG("limited-retry", 'l', &cfg.limited_retry, limited_retry),
OPT_FLAG("force-unit-access", 'f', &cfg.fua, fua),
- OPT_UINT("ref-tag", 'r', &cfg.ref_tag, ref_tag),
+ OPT_SUFFIX("ref-tag", 'r', &cfg.ref_tag, ref_tag),
OPT_SHRT("app-tag-mask", 'm', &cfg.lbatm, lbatm),
OPT_SHRT("app-tag", 'a', &cfg.lbat, lbat),
OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo),
@@ -1184,7 +1184,7 @@ static int zone_append(int argc, char **argv, struct command *cmd, struct plugin
.zslba = cfg.zslba,
.nlb = nblocks,
.control = control,
- .ilbrt = cfg.ref_tag,
+ .ilbrt_u64 = cfg.ref_tag,
.lbat = cfg.lbat,
.lbatm = cfg.lbatm,
.data_len = cfg.data_size,
diff --git a/plugins/zns/zns.h b/plugins/zns/zns.h
index 1bdd4d9..77bfdd6 100644
--- a/plugins/zns/zns.h
+++ b/plugins/zns/zns.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#undef CMD_INC_FILE
#define CMD_INC_FILE plugins/zns/zns