#include <err.h>
#include <string.h>
#include <sys/stddef.h>
#include <sys/sysmacros.h>
#include <sys/nvme/micron.h>
#include "nvmeadm.h"
#define MICRON_GEN_73XX 1
#define MICRON_GEN_74XX 2
#define MICRON_F_SMART(f) \
.nf_off = offsetof(micron_vul_ext_smart_t, mes_##f), \
.nf_len = sizeof (((micron_vul_ext_smart_t *)NULL)->mes_##f)
static const nvmeadm_field_bit_t micron_vul_ext_smart_wpr_bits[] = { {
.nfb_lowbit = 0, .nfb_hibit = 0,
.nfb_short = "dramue",
.nfb_desc = "DRAM Double Bit Error",
.nfb_type = NVMEADM_FT_STRMAP,
.nfb_strs = { "did not occur", "occurred" }
}, {
.nfb_lowbit = 1, .nfb_hibit = 1,
.nfb_short = "spare",
.nfb_desc = "Low Remaining Spare Block Count",
.nfb_type = NVMEADM_FT_STRMAP,
.nfb_strs = { "did not occur", "occurred" }
}, {
.nfb_lowbit = 2, .nfb_hibit = 2,
.nfb_short = "cap",
.nfb_desc = "Power Holdup Capacitor Failure",
.nfb_type = NVMEADM_FT_STRMAP,
.nfb_strs = { "did not occur", "occurred" }
}, {
.nfb_lowbit = 3, .nfb_hibit = 3,
.nfb_short = "nvram",
.nfb_desc = "NVRAM Checksum Failure",
.nfb_type = NVMEADM_FT_STRMAP,
.nfb_strs = { "did not occur", "occurred" }
}, {
.nfb_lowbit = 4, .nfb_hibit = 4,
.nfb_short = "daor",
.nfb_desc = "DRAM Address Out of Range",
.nfb_type = NVMEADM_FT_STRMAP,
.nfb_strs = { "did not occur", "occurred" }
}, {
.nfb_lowbit = 5, .nfb_hibit = 5,
.nfb_short = "temp",
.nfb_desc = "Overtemp Shutdown",
.nfb_type = NVMEADM_FT_STRMAP,
.nfb_strs = { "did not occur", "occurred" }
} };
static const nvmeadm_field_t micron_vul_ext_smart_fields[] = { {
MICRON_F_SMART(gbb),
.nf_short = "gbb",
.nf_desc = "Grown Bad Block Count",
.nf_type = NVMEADM_FT_HEX
}, {
MICRON_F_SMART(max_erase),
.nf_short = "mec",
.nf_desc = "Per-Block Max Erase Count",
.nf_type = NVMEADM_FT_HEX
}, {
MICRON_F_SMART(power_on),
.nf_short = "pon",
.nf_desc = "Power-on",
.nf_type = NVMEADM_FT_UNIT,
.nf_addend = { .nfa_unit = "min" }
}, {
MICRON_F_SMART(wp_reason),
.nf_short = "wpr",
.nf_desc = "Write Protect Reason",
NVMEADM_F_BITS(micron_vul_ext_smart_wpr_bits)
}, {
MICRON_F_SMART(cap),
.nf_short = "cap",
.nf_desc = "Device Capacity",
.nf_type = NVMEADM_FT_BYTES
}, {
MICRON_F_SMART(erase_count),
.nf_short = "tec",
.nf_desc = "Total Erase Count",
.nf_type = NVMEADM_FT_HEX
}, {
MICRON_F_SMART(use_rate),
.nf_short = "use",
.nf_desc = "Lifetime Use Rate",
.nf_type = NVMEADM_FT_HEX
}, {
MICRON_F_SMART(erase_fail),
.nf_short = "efc",
.nf_desc = "Erase Fail Count",
.nf_rev = MICRON_GEN_74XX,
.nf_type = NVMEADM_FT_HEX
}, {
MICRON_F_SMART(uecc),
.nf_short = "uecc",
.nf_desc = "Reported Uncorrectable ECC Errors",
.nf_rev = MICRON_GEN_74XX,
.nf_type = NVMEADM_FT_HEX
}, {
MICRON_F_SMART(prog_fail),
.nf_short = "pfc",
.nf_desc = "Program Fail Count",
.nf_rev = MICRON_GEN_74XX,
.nf_type = NVMEADM_FT_HEX
}, {
MICRON_F_SMART(read_bytes),
.nf_short = "read",
.nf_desc = "Total Bytes Read",
.nf_rev = MICRON_GEN_74XX,
.nf_type = NVMEADM_FT_BYTES
}, {
MICRON_F_SMART(write_bytes),
.nf_short = "write",
.nf_desc = "Total Bytes Written",
.nf_rev = MICRON_GEN_74XX,
.nf_type = NVMEADM_FT_BYTES
}, {
MICRON_F_SMART(trans_size),
.nf_short = "tus",
.nf_desc = "Translation Unit Size",
.nf_type = NVMEADM_FT_BYTES
}, {
MICRON_F_SMART(bs_total),
.nf_short = "tbs",
.nf_desc = "Total Block Stripe Count for User Data",
.nf_type = NVMEADM_FT_HEX
}, {
MICRON_F_SMART(bs_free),
.nf_short = "fbs",
.nf_desc = "Free Block Stripe Count for User Data",
.nf_type = NVMEADM_FT_HEX
}, {
MICRON_F_SMART(bs_cap),
.nf_short = "bss",
.nf_desc = "Block Stripe Size",
.nf_type = NVMEADM_FT_BYTES
}, {
MICRON_F_SMART(user_erase_min),
.nf_short = "ubemin",
.nf_desc = "Minimum User Block Erase Count",
.nf_type = NVMEADM_FT_HEX
}, {
MICRON_F_SMART(user_erase_avg),
.nf_short = "ubeavg",
.nf_desc = "Average User Block Erase Count",
.nf_type = NVMEADM_FT_HEX
}, {
MICRON_F_SMART(user_erase_max),
.nf_short = "ubemax",
.nf_desc = "Maximum User Block Erase Count",
.nf_type = NVMEADM_FT_HEX
} };
static uint32_t
micron_vul_ext_smart_getvers(const void *data, size_t len)
{
const uint8_t zero[16] = { 0 };
uint8_t ones[16];
if (len < sizeof (micron_vul_ext_smart_t)) {
errx(-1, "cannot parse revision information, found 0x%zx "
"bytes, need at least 0x%zx", len,
sizeof (micron_vul_ext_smart_t));
}
(void) memset(ones, 0xff, sizeof (ones));
const micron_vul_ext_smart_t *log = data;
if (memcmp(zero, log->mes_read_bytes, sizeof (zero)) == 0 &&
memcmp(zero, log->mes_write_bytes, sizeof (zero)) == 0) {
return (MICRON_GEN_73XX);
}
if (memcmp(ones, log->mes_read_bytes, sizeof (ones)) == 0 &&
memcmp(ones, log->mes_write_bytes, sizeof (ones)) == 0) {
return (MICRON_GEN_73XX);
}
return (MICRON_GEN_74XX);
}
const nvmeadm_log_field_info_t micron_vul_extsmart_field_info = {
.nlfi_log = "micron/extsmart",
.nlfi_fields = micron_vul_ext_smart_fields,
.nlfi_nfields = ARRAY_SIZE(micron_vul_ext_smart_fields),
.nlfi_min = sizeof (micron_vul_ext_smart_t),
.nlfi_getrev = micron_vul_ext_smart_getvers
};