diff options
Diffstat (limited to '')
-rw-r--r-- | plugins/dera/dera-nvme.c | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/plugins/dera/dera-nvme.c b/plugins/dera/dera-nvme.c new file mode 100644 index 0000000..ca4b53d --- /dev/null +++ b/plugins/dera/dera-nvme.c @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <dirent.h> +#include <ctype.h> +#include <sys/stat.h> +#include <sys/time.h> + +#include "nvme.h" +#include "libnvme.h" +#include "plugin.h" +#include "linux/types.h" +#include "nvme-print.h" + +#define CREATE_CMD +#include "dera-nvme.h" + +static int char4_to_int(__u8 *data) +{ + int i; + int result = 0; + + for (i = 0; i < 4; i++) { + result = result << 8; + result += data[3 - i]; + } + return result; +} + +struct nvme_dera_smart_info_log +{ + __u8 quick_rebuild_cnt0[4]; + __u8 quick_rebuild_cnt1[4]; + __u8 full_rebuild_cnt0[4]; + __u8 full_rebuild_cnt1[4]; + __u8 raw_rebuild_cnt0[4]; + __u8 raw_rebuild_cnt1[4]; + __u8 cap_aged; + __u8 cap_aged_ratio; + __u8 cap_status; + __u8 cap_voltage[4]; + __u8 cap_charge_ctrl_en; + __u8 cap_charge_ctrl_val[2]; + __u8 cap_charge_max_thr[2]; + __u8 cap_charge_min_thr[2]; + __u8 dev_status; + __u8 dev_status_up; + __u8 nand_erase_err_cnt[4]; + __u8 nand_program_err_cnt[4]; + __u8 ddra_1bit_err[2]; + __u8 ddra_2bit_err[2]; + __u8 ddrb_1bit_err[2]; + __u8 ddrb_2bit_err[2]; + __u8 ddr_err_bit; + __u8 pcie_corr_err[2]; + __u8 pcie_uncorr_err[2]; + __u8 pcie_fatal_err[2]; + __u8 pcie_err_bit; + __u8 power_level; + __u8 current_power[2]; + __u8 nand_init_fail[2]; + __u8 fw_loader_version[8]; + __u8 uefi_driver_version[8]; + __u8 gpio0_err[2]; + __u8 gpio5_err[2]; + __u8 gpio_err_bit[2]; + __u8 rebuild_percent; + __u8 pcie_volt_status; + __u8 current_pcie_volt[2]; + __u8 init_pcie_volt_thr[2]; + __u8 rt_pcie_volt_thr[2]; + __u8 init_pcie_volt_low[2]; + __u8 rt_pcie_volt_low[2]; + __u8 temp_sensor_abnormal[2]; + __u8 nand_read_retry_fail_cnt[4]; + __u8 fw_slot_version[8]; + __u8 rsved[395]; +}; + +enum dera_device_status +{ + DEVICE_STATUS_READY = 0x00, + DEVICE_STATUS_QUICK_REBUILDING = 0x01, + DEVICE_STATUS_FULL_REBUILDING = 0x02, + DEVICE_STATUS_RAW_REBUILDING = 0x03, + DEVICE_STATUS_CARD_READ_ONLY = 0x04, + DEVICE_STATUS_FATAL_ERROR = 0x05, + DEVICE_STATUS_BUSY = 0x06, + DEVICE_STAUTS_LOW_LEVEL_FORMAT = 0x07, + DEVICE_STAUTS_FW_COMMITING = 0x08, + DEVICE_STAUTS__OVER_TEMPRATURE = 0x09, +}; + +static int nvme_dera_get_device_status(int fd, enum dera_device_status *result) +{ + int err = 0; + + struct nvme_passthru_cmd cmd = { + .opcode = 0xc0, + .addr = (__u64)(uintptr_t)NULL, + .data_len = 0, + .cdw10 = 0, + .cdw12 = 0x104, + }; + + err = nvme_submit_admin_passthru(fd, &cmd, NULL); + if (!err && result) + *result = cmd.result; + + return err; +} + +static int get_status(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + struct nvme_dera_smart_info_log log; + enum dera_device_status state = DEVICE_STATUS_FATAL_ERROR; + char *desc = "Get the Dera device status"; + struct nvme_dev *dev; + int err; + + OPT_ARGS(opts) = { + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + err = nvme_get_log_simple(dev_fd(dev), 0xc0, sizeof(log), &log); + if (err) + goto exit; + + static const char *dev_status[] = { + "Normal", + "Quick Rebuilding", + "Full Rebuilding", + "Raw Rebuilding", + "Card Read Only", + "Fatal Error", + "Busy", + "Low Level Format", + "Firmware Committing", + "Over Temperature" }; + + static const char *volt_status[] = { + "Normal", + "Initial Low", + "Runtime Low", + }; + + err = nvme_dera_get_device_status(dev_fd(dev), &state); + if (!err) { + if (state > 0 && state < 4) + printf("device_status : %s %d%% completed\n", dev_status[state], log.rebuild_percent); + else + printf("device_status : %s\n", dev_status[state]); + } else { + goto exit; + } + + printf("dev_status_up : %s\n", dev_status[log.dev_status_up]); + printf("cap_aged : %s\n", log.cap_aged == 1 ? "True" : "False"); + printf("cap_aged_ratio : %d%%\n", log.cap_aged_ratio < 100 ? log.cap_aged_ratio : 100); + printf("cap_status : %s\n", log.cap_status == 0 ? "Normal" : (log.cap_status == 1 ? "Warning" : "Critical")); + printf("cap_voltage : %d mV\n", char4_to_int(log.cap_voltage)); + printf("nand_erase_err_cnt : %d\n", char4_to_int(log.nand_erase_err_cnt)); + printf("nand_program_err_cnt : %d\n", char4_to_int(log.nand_program_err_cnt)); + printf("ddra_1bit_err : %d\n", log.ddra_1bit_err[1] << 8 | log.ddra_1bit_err[0]); + printf("ddra_2bit_err : %d\n", log.ddra_2bit_err[1] << 8 | log.ddra_2bit_err[0]); + printf("ddrb_1bit_err : %d\n", log.ddrb_1bit_err[1] << 8 | log.ddrb_1bit_err[0]); + printf("ddrb_2bit_err : %d\n", log.ddrb_2bit_err[1] << 8 | log.ddrb_2bit_err[0]); + printf("ddr_err_bit : %d\n", log.ddr_err_bit); + printf("pcie_corr_err : %d\n", log.pcie_corr_err[1] << 8 | log.pcie_corr_err[0]); + printf("pcie_uncorr_err : %d\n", log.pcie_uncorr_err[1] << 8 | log.pcie_uncorr_err[0]); + printf("pcie_fatal_err : %d\n", log.pcie_fatal_err[1] << 8 | log.pcie_fatal_err[0]); + printf("power_level : %d W\n", log.power_level); + printf("current_power : %d mW\n", log.current_power[1] << 8 | log.current_power[0]); + printf("nand_init_fail : %d\n", log.nand_init_fail[1] << 8 | log.nand_init_fail[0]); + 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 *)) + printf("pcie_volt_status : %s\n", volt_status[log.pcie_volt_status]); + else + printf("pcie_volt_status : Unknown\n"); + + printf("current_pcie_volt : %d mV\n", log.current_pcie_volt[1] << 8 | log.current_pcie_volt[0]); + printf("init_pcie_volt_low_cnt : %d\n", log.init_pcie_volt_low[1] << 8 | log.init_pcie_volt_low[0]); + printf("rt_pcie_volt_low_cnt : %d\n", log.rt_pcie_volt_low[1] << 8 | log.rt_pcie_volt_low[0]); + printf("temp_sensor_abnormal_cnt : %d\n", log.temp_sensor_abnormal[1] << 8 | log.temp_sensor_abnormal[0]); + printf("nand_read_retry_fail_cnt : %d\n", char4_to_int(log.nand_read_retry_fail_cnt)); + printf("fw_slot_version : %.*s\n", 8, log.fw_slot_version); + +exit: + if (err > 0) + nvme_show_status(err); + + dev_close(dev); + return err; +} + |