Report more NVME SMART attributes

This commit is contained in:
Andrea Mazzoleni 2026-02-26 12:53:55 +01:00
parent 18279f7346
commit ed15ad23a4
2 changed files with 49 additions and 5 deletions

View file

@ -434,7 +434,10 @@ int randomize(void* ptr, size_t size);
#define SMART_LOAD_CYCLE_COUNT 193
#define SMART_TEMPERATURE_CELSIUS 194
#define SMART_FLAGS 256 /**< Flags returned by smartctl. */
/**
* Flags returned by smartctl via exit code
*/
#define SMART_FLAGS 256
/*
* Counts command, transport, or controller-level errors reported by the device.
@ -467,6 +470,22 @@ int randomize(void* ptr, size_t size);
*/
#define SMART_COUNT 260
/**
* NVME custom SMART attributes
*
* The numbers are just arbitrary to put them in unused space
*/
#define SMART_NVME_CRITICAL_WARNING 100
#define SMART_NVME_AVAILABLE_SPARE 101
#define SMART_NVME_DATA_UNITS_READ 102
#define SMART_NVME_DATA_UNITS_WRITTEN 103
#define SMART_NVME_HOST_READ_COMMANDS 104
#define SMART_NVME_HOST_WRITE_COMMANDS 105
#define SMART_NVME_CONTROLLER_BUSY_TIME 106
#define SMART_NVME_UNSAFE_SHUTDOWNS 107
#define SMART_NVME_WARNING_COMP_TEMPERATURE_TIME 108
#define SMART_NVME_CRITICAL_COMP_TEMPERATURE_TIME 109
/**
* Info attributes.
*/
@ -478,8 +497,10 @@ int randomize(void* ptr, size_t size);
*/
#define INFO_COUNT 2
#define SMART_IGNORE_MAX 4 /**< Max number of ignored smart attributes */
/**
* Max number of ignored smart attributes
*/
#define SMART_IGNORE_MAX 4
/**
* Flags returned by smartctl.
@ -546,7 +567,7 @@ struct devinfo_struct {
struct devinfo_struct* parent; /**< Pointer at the parent if any. */
struct devinfo_struct* split; /**< Pointer at first split if any. */
struct smart_attr smart[SMART_COUNT]; /**< All smart values. */
uint64_t info[INFO_COUNT]; /**< Info attributes. */
uint64_t info[INFO_COUNT]; /**< Informational attributes not related to SMART telemetry. */
uint64_t access_stat; /**< Access stat info. */
char serial[SMART_MAX]; /**< Serial number. */
char family[SMART_MAX]; /**< Family. */

View file

@ -2130,7 +2130,30 @@ int smartctl_attribute(FILE* f, const char* file, const char* name, struct smart
pathcpy(smart[SMART_POWER_ON_HOURS].name, sizeof(smart[SMART_POWER_ON_HOURS].name), "Power_On_Hours");
} else if (scomma(s, "Power Cycles:", &smart[SMART_POWER_CYCLE_COUNT].raw) == 1) {
pathcpy(smart[SMART_POWER_CYCLE_COUNT].name, sizeof(smart[SMART_POWER_CYCLE_COUNT].name), "Power_Cycles");
/* Attributes */
/* map specific attributes to UNUSED SMART attr */
} else if (sscanf(s, "Critical Warning: %" SCNx64, &smart[SMART_NVME_CRITICAL_WARNING].raw) == 1) {
pathcpy(smart[SMART_NVME_CRITICAL_WARNING].name, sizeof(smart[SMART_NVME_CRITICAL_WARNING].name), "Critical_Warning");
} else if (sscanf(s, "Available Spare: %" SCNu64 "%%", &smart[SMART_NVME_AVAILABLE_SPARE].raw) == 1) {
pathcpy(smart[SMART_NVME_AVAILABLE_SPARE].name, sizeof(smart[SMART_NVME_AVAILABLE_SPARE].name), "Available_Spare");
} else if (scomma(s, "Data Units Read:", &smart[SMART_NVME_DATA_UNITS_READ].raw) == 1) {
pathcpy(smart[SMART_NVME_DATA_UNITS_READ].name, sizeof(smart[SMART_NVME_DATA_UNITS_READ].name), "Data_Units_Read");
} else if (scomma(s, "Data Units Written:", &smart[SMART_NVME_DATA_UNITS_WRITTEN].raw) == 1) {
pathcpy(smart[SMART_NVME_DATA_UNITS_WRITTEN].name, sizeof(smart[SMART_NVME_DATA_UNITS_WRITTEN].name), "Data_Units_Written");
} else if (scomma(s, "Host Read Commands:", &smart[SMART_NVME_HOST_READ_COMMANDS].raw) == 1) {
pathcpy(smart[SMART_NVME_HOST_READ_COMMANDS].name, sizeof(smart[SMART_NVME_HOST_READ_COMMANDS].name), "Host_Read_Commands");
} else if (scomma(s, "Host Write Commands:", &smart[SMART_NVME_HOST_WRITE_COMMANDS].raw) == 1) {
pathcpy(smart[SMART_NVME_HOST_WRITE_COMMANDS].name, sizeof(smart[SMART_NVME_HOST_WRITE_COMMANDS].name), "Host_Write_Commands");
} else if (scomma(s, "Controller Busy Time:", &smart[SMART_NVME_CONTROLLER_BUSY_TIME].raw) == 1) {
pathcpy(smart[SMART_NVME_CONTROLLER_BUSY_TIME].name, sizeof(smart[SMART_NVME_CONTROLLER_BUSY_TIME].name), "Controller_Busy_Time");
} else if (scomma(s, "Unsafe Shutdowns:", &smart[SMART_NVME_UNSAFE_SHUTDOWNS].raw) == 1) {
pathcpy(smart[SMART_NVME_UNSAFE_SHUTDOWNS].name, sizeof(smart[SMART_NVME_UNSAFE_SHUTDOWNS].name), "Unsafe_Shutdowns");
/* smartctl doesn't print this with command, but %d */
} else if (scomma(s, "Warning Comp. Temperature Time:", &smart[SMART_NVME_WARNING_COMP_TEMPERATURE_TIME].raw) == 1) {
pathcpy(smart[SMART_NVME_WARNING_COMP_TEMPERATURE_TIME].name, sizeof(smart[SMART_NVME_WARNING_COMP_TEMPERATURE_TIME].name), "Warning_Comp_Temperature_Time");
/* smartctl doesn't print this with command, but %d */
} else if (scomma(s, "Critical Comp. Temperature Time:", &smart[SMART_NVME_CRITICAL_COMP_TEMPERATURE_TIME].raw) == 1) {
pathcpy(smart[SMART_NVME_CRITICAL_COMP_TEMPERATURE_TIME].name, sizeof(smart[SMART_NVME_CRITICAL_COMP_TEMPERATURE_TIME].name), "Critical_Comp_Temperature_Time");
/* ATA Attributes table */
} else if (smatch(s, "ID#") == 0) {
inside = 1;
} else if (inside) {