From 6594cddb65f59040408c12b5987ec6ea0d0f644c Mon Sep 17 00:00:00 2001 From: Alexander Shaduri Date: Thu, 2 May 2024 13:47:20 +0400 Subject: [PATCH] Refactored drive data fetch and parsing, and drive types. --- src/applib/ata_storage_property.h | 10 +- src/applib/ata_storage_property_descr.cpp | 592 +++++++++--------- src/applib/ata_storage_property_descr.h | 6 +- .../examples/example_storage_detector.cpp | 2 +- src/applib/selftest.cpp | 4 +- src/applib/smartctl_json_ata_parser.cpp | 19 +- src/applib/smartctl_json_basic_parser.cpp | 14 +- src/applib/smartctl_parser.cpp | 9 +- src/applib/smartctl_parser_types.h | 2 +- src/applib/smartctl_text_basic_parser.cpp | 9 +- src/applib/smartctl_version_parser.cpp | 20 + src/applib/smartctl_version_parser.h | 6 + src/applib/storage_detector.cpp | 2 +- src/applib/storage_detector_linux.cpp | 3 +- src/applib/storage_device.cpp | 459 +++++++++----- src/applib/storage_device.h | 74 ++- src/applib/storage_device_detected_type.cpp | 11 + src/applib/storage_device_detected_type.h | 69 ++ src/gsc_main_window.cpp | 4 +- src/gsc_main_window_iconview.h | 13 +- 20 files changed, 823 insertions(+), 505 deletions(-) create mode 100644 src/applib/storage_device_detected_type.cpp create mode 100644 src/applib/storage_device_detected_type.h diff --git a/src/applib/ata_storage_property.h b/src/applib/ata_storage_property.h index e989daa..3c4b795 100644 --- a/src/applib/ata_storage_property.h +++ b/src/applib/ata_storage_property.h @@ -48,11 +48,11 @@ class AtaStorageAttribute { public: /// Disk type the attribute may match - enum class DiskType { - Any, ///< Any disk type - Hdd, ///< HDD (rotational) only - Ssd ///< SSD only - }; +// enum class DiskType { +// Any, ///< Any disk type +// Hdd, ///< HDD (rotational) only +// Ssd ///< SSD only +// }; /// Attribute pre-failure / old-age type enum class AttributeType { diff --git a/src/applib/ata_storage_property_descr.cpp b/src/applib/ata_storage_property_descr.cpp index d0910c2..2a91a39 100644 --- a/src/applib/ata_storage_property_descr.cpp +++ b/src/applib/ata_storage_property_descr.cpp @@ -46,14 +46,14 @@ namespace { AttributeDescription() = default; /// Constructor - AttributeDescription(int32_t id_, AtaStorageAttribute::DiskType type, std::string reported_name_, + AttributeDescription(int32_t id_, std::optional type, std::string reported_name_, std::string displayable_name_, std::string generic_name_, std::string description_) - : id(id_), disk_type(type), reported_name(std::move(reported_name_)), displayable_name(std::move(displayable_name_)), + : id(id_), drive_type(type), reported_name(std::move(reported_name_)), displayable_name(std::move(displayable_name_)), generic_name(std::move(generic_name_)), description(std::move(description_)) { } int32_t id = -1; ///< e.g. 190 - AtaStorageAttribute::DiskType disk_type = AtaStorageAttribute::DiskType::Any; ///< HDD-only, SSD-only or universal attribute + std::optional drive_type; ///< HDD-only, SSD-only or universal attribute std::string reported_name; ///< e.g. Airflow_Temperature_Cel std::string displayable_name; ///< e.g. Airflow Temperature (C). This is a translatable string. std::string generic_name; ///< Generic name to be set on the property, e.g. "airflow_temperature". For lookups. @@ -100,52 +100,52 @@ namespace { add(4, "Start_Stop_Count", "Start / Stop Count", "", "Number of start/stop cycles of a spindle (Raw value). That is, number of drive spin-ups."); // Reallocated Sector Count (smartctl) - add(5, AtaStorageAttribute::DiskType::Hdd, "Reallocated_Sector_Ct", "Reallocated Sector Count", "attr_reallocated_sector_count", + add(5, StorageDeviceDetectedType::AtaHdd, "Reallocated_Sector_Ct", "Reallocated Sector Count", "attr_reallocated_sector_count", "Number of reallocated sectors (Raw value). Non-zero Raw value indicates a disk surface failure." "\n\n" + get_uncorrectable_text()); // SSD: Reallocated Sector Count (smartctl) - add(5, AtaStorageAttribute::DiskType::Ssd, "Reallocated_Sector_Ct", "Reallocated Sector Count", "attr_reallocated_sector_count", + add(5, StorageDeviceDetectedType::AtaSsd, "Reallocated_Sector_Ct", "Reallocated Sector Count", "attr_reallocated_sector_count", "Number of reallocated sectors (Raw value). High Raw value indicates an old age for an SSD."); // SandForce SSD: Retired_Block_Count (smartctl) - add(5, AtaStorageAttribute::DiskType::Ssd, "Retired_Block_Count", "Retired Block Rate", "attr_ssd_life_left", + add(5, StorageDeviceDetectedType::AtaSsd, "Retired_Block_Count", "Retired Block Rate", "attr_ssd_life_left", "Indicates estimated remaining life of the drive. Normalized value is (100-100*RBC/MRB) where RBC is the number of retired blocks " "and MRB is the minimum required blocks."); // Crucial/Micron SSD: Reallocate_NAND_Blk_Cnt (smartctl) - add(5, AtaStorageAttribute::DiskType::Ssd, "Reallocate_NAND_Blk_Cnt", "Reallocated NAND Block Count", "", + add(5, StorageDeviceDetectedType::AtaSsd, "Reallocate_NAND_Blk_Cnt", "Reallocated NAND Block Count", "", "Number of reallocated blocks (Raw value). High Raw value indicates an old age for an SSD."); // Micron SSD: Reallocate_NAND_Blk_Cnt (smartctl) - add(5, AtaStorageAttribute::DiskType::Ssd, "Reallocated_Block_Count", "Reallocated Block Count", "", + add(5, StorageDeviceDetectedType::AtaSsd, "Reallocated_Block_Count", "Reallocated Block Count", "", "Number of reallocated blocks (Raw value). High Raw value indicates an old age for an SSD."); // OCZ SSD (smartctl) - add(5, AtaStorageAttribute::DiskType::Ssd, "Runtime_Bad_Block", "Runtime Bad Block Count", "", + add(5, StorageDeviceDetectedType::AtaSsd, "Runtime_Bad_Block", "Runtime Bad Block Count", "", ""); // Innodisk SSD (smartctl) - add(5, AtaStorageAttribute::DiskType::Ssd, "Later_Bad_Block", "Later Bad Block", "", + add(5, StorageDeviceDetectedType::AtaSsd, "Later_Bad_Block", "Later Bad Block", "", ""); // Read Channel Margin (smartctl) - add(6, AtaStorageAttribute::DiskType::Hdd, "Read_Channel_Margin", "Read Channel Margin", "", + add(6, StorageDeviceDetectedType::AtaHdd, "Read_Channel_Margin", "Read Channel Margin", "", "Margin of a channel while reading data. The function of this attribute is not specified."); // Seek Error Rate (smartctl) - add(7, AtaStorageAttribute::DiskType::Hdd, "Seek_Error_Rate", "Seek Error Rate", "", + add(7, StorageDeviceDetectedType::AtaHdd, "Seek_Error_Rate", "Seek Error Rate", "", "Frequency of errors appearance while positioning. When a drive reads data, it positions heads in the needed place. " "If there is a failure in the mechanical positioning system, a seek error arises. More seek errors indicate worse condition " "of a disk surface and disk mechanical subsystem. The exact meaning of the Raw value is manufacturer-dependent."); // Seek Time Performance (smartctl) - add(8, AtaStorageAttribute::DiskType::Hdd, "Seek_Time_Performance", "Seek Time Performance", "", + add(8, StorageDeviceDetectedType::AtaHdd, "Seek_Time_Performance", "Seek Time Performance", "", "Average efficiency of seek operations of the magnetic heads. If this value is decreasing, it is a sign of problems in the hard disk drive mechanical subsystem."); // Power-On Hours (smartctl) (Maxtor may use minutes, Fujitsu may use seconds, some even temperature?) add(9, "Power_On_Hours", "Power-On Time", "", "Number of hours in power-on state. Raw value shows total count of hours (or minutes, or half-minutes, or seconds, depending on manufacturer) in power-on state."); // SandForce, Intel SSD: Power_On_Hours_and_Msec (smartctl) (description?) - add(9, AtaStorageAttribute::DiskType::Ssd, "Power_On_Hours_and_Msec"); + add(9, StorageDeviceDetectedType::AtaSsd, "Power_On_Hours_and_Msec"); // Smart Storage Systems SSD (smartctl) - add(9, AtaStorageAttribute::DiskType::Ssd, "Proprietary_9", "Internal Attribute", "", + add(9, StorageDeviceDetectedType::AtaSsd, "Proprietary_9", "Internal Attribute", "", "This attribute has been reserved by vendor as internal."); // Spin-up Retry Count (smartctl) - add(10, AtaStorageAttribute::DiskType::Hdd, "Spin_Retry_Count", "Spin-Up Retry Count", "attr_spin_up_retry_count", + add(10, StorageDeviceDetectedType::AtaHdd, "Spin_Retry_Count", "Spin-Up Retry Count", "attr_spin_up_retry_count", "Number of retries of spin start attempts (Raw value). An increase of this attribute value is a sign of problems in the hard disk mechanical subsystem."); // Calibration Retry Count (smartctl) - add(11, AtaStorageAttribute::DiskType::Hdd, "Calibration_Retry_Count", "Calibration Retry Count", "", + add(11, StorageDeviceDetectedType::AtaHdd, "Calibration_Retry_Count", "Calibration Retry Count", "", "Number of times recalibration was requested, under the condition that the first attempt was unsuccessful (Raw value). " "A decrease is a sign of problems in the hard disk mechanical subsystem."); // Power Cycle Count (smartctl) @@ -155,303 +155,303 @@ namespace { add(13, "Read_Soft_Error_Rate", "Soft Read Error Rate", "attr_soft_read_error_rate", "Uncorrected read errors reported to the operating system (Raw value). If the value is non-zero, you should back up your data."); // Sandforce SSD: Soft_Read_Error_Rate (smartctl) - add(13, AtaStorageAttribute::DiskType::Ssd, "Soft_Read_Error_Rate"); + add(13, StorageDeviceDetectedType::AtaSsd, "Soft_Read_Error_Rate"); // Maxtor: Average FHC (custom) (description?) - add(99, AtaStorageAttribute::DiskType::Hdd, "", "Average FHC (Flying Height Control)", "", + add(99, StorageDeviceDetectedType::AtaHdd, "", "Average FHC (Flying Height Control)", "", ""); // Sandforce SSD: Gigabytes_Erased (smartctl) (description?) - add(100, AtaStorageAttribute::DiskType::Ssd, "Gigabytes_Erased", "GiB Erased", "", + add(100, StorageDeviceDetectedType::AtaSsd, "Gigabytes_Erased", "GiB Erased", "", "Number of GiB erased."); // OCZ SSD (smartctl) - add(100, AtaStorageAttribute::DiskType::Ssd, "Total_Blocks_Erased", "Total Blocks Erased", "", + add(100, StorageDeviceDetectedType::AtaSsd, "Total_Blocks_Erased", "Total Blocks Erased", "", "Number of total blocks erased."); // STEC CF: (custom) - add(100, AtaStorageAttribute::DiskType::Ssd, "", "Erase / Program Cycles", "", // unused + add(100, StorageDeviceDetectedType::AtaSsd, "", "Erase / Program Cycles", "", // unused "Number of Erase / Program cycles of the entire drive."); // Maxtor: Maximum FHC (custom) (description?) - add(101, AtaStorageAttribute::DiskType::Hdd, "", "Maximum FHC (Flying Height Control)", "", + add(101, StorageDeviceDetectedType::AtaHdd, "", "Maximum FHC (Flying Height Control)", "", ""); // Unknown (source says Maxtor, but it's an SSD thing and Maxtor doesn't have them at this point). // add(101, "", "Translation Table Rebuild", "", // "Indicates power backup fault or internal error resulting in loss of system unit tables."); // STEC CF: Translation Table Rebuild (custom) - add(103, AtaStorageAttribute::DiskType::Ssd, "", "Translation Table Rebuild", "", + add(103, StorageDeviceDetectedType::AtaSsd, "", "Translation Table Rebuild", "", "Indicates power backup fault or internal error resulting in loss of system unit tables."); // Smart Storage Systems SSD (smartctl) (description?) - add(130, AtaStorageAttribute::DiskType::Ssd, "Minimum_Spares_All_Zs", "Minimum Spares All Zs", "", + add(130, StorageDeviceDetectedType::AtaSsd, "Minimum_Spares_All_Zs", "Minimum Spares All Zs", "", ""); // SiliconMotion SSDs (description?) (smartctl) - add(148, AtaStorageAttribute::DiskType::Ssd, "Total_SLC_Erase_Ct", "Total SLC Erase Count", "", + add(148, StorageDeviceDetectedType::AtaSsd, "Total_SLC_Erase_Ct", "Total SLC Erase Count", "", ""); // SiliconMotion SSDs (description?) (smartctl) - add(149, AtaStorageAttribute::DiskType::Ssd, "Max_SLC_Erase_Ct", "Maximum SLC Erase Count", "", + add(149, StorageDeviceDetectedType::AtaSsd, "Max_SLC_Erase_Ct", "Maximum SLC Erase Count", "", ""); // SiliconMotion SSDs (description?) (smartctl) - add(150, AtaStorageAttribute::DiskType::Ssd, "Min_SLC_Erase_Ct", "Minimum SLC Erase Count", "", + add(150, StorageDeviceDetectedType::AtaSsd, "Min_SLC_Erase_Ct", "Minimum SLC Erase Count", "", ""); // SiliconMotion SSDs (description?) (smartctl) - add(151, AtaStorageAttribute::DiskType::Ssd, "Average_SLC_Erase_Ct", "Average SLC Erase Count", "", + add(151, StorageDeviceDetectedType::AtaSsd, "Average_SLC_Erase_Ct", "Average SLC Erase Count", "", ""); // Apacer Flash (description?) (smartctl) - add(160, AtaStorageAttribute::DiskType::Ssd, "Initial_Bad_Block_Count", "Initial Bad Block Count", "", + add(160, StorageDeviceDetectedType::AtaSsd, "Initial_Bad_Block_Count", "Initial Bad Block Count", "", ""); // Samsung SSD, Intel SSD: Reported Uncorrectable (smartctl) - add(160, AtaStorageAttribute::DiskType::Ssd, "Uncorrectable_Error_Cnt", "Uncorrectable Error Count", "", + add(160, StorageDeviceDetectedType::AtaSsd, "Uncorrectable_Error_Cnt", "Uncorrectable Error Count", "", ""); // Apacer Flash (description?) (smartctl) - add(161, AtaStorageAttribute::DiskType::Ssd, "Bad_Block_Count", "Bad Block Count", "", + add(161, StorageDeviceDetectedType::AtaSsd, "Bad_Block_Count", "Bad Block Count", "", "Number of bad blocks. SSDs reallocate blocks as part of their normal operation, so low bad block counts are not critical for them."); // Innodisk (description?) (smartctl) - add(161, AtaStorageAttribute::DiskType::Ssd, "Number_of_Pure_Spare", "Number of Pure Spare", "", + add(161, StorageDeviceDetectedType::AtaSsd, "Number_of_Pure_Spare", "Number of Pure Spare", "", ""); // Innodisk CF (description?) (smartctl) - add(161, AtaStorageAttribute::DiskType::Ssd, "Valid_Spare_Block_Cnt", "Valid Spare Block Count", "", + add(161, StorageDeviceDetectedType::AtaSsd, "Valid_Spare_Block_Cnt", "Valid Spare Block Count", "", "Number of available spare blocks. Spare blocks are used when bad blocks develop."); // Apacer Flash (description?) (smartctl) - add(162, AtaStorageAttribute::DiskType::Ssd, "Spare_Block_Count", "Spare Block Count", "", + add(162, StorageDeviceDetectedType::AtaSsd, "Spare_Block_Count", "Spare Block Count", "", "Number of spare blocks which are used when bad blocks develop."); // Innodisk CF (smartctl) - add(162, AtaStorageAttribute::DiskType::Ssd, "Child_Pair_Count", "Child Pair Count", "", + add(162, StorageDeviceDetectedType::AtaSsd, "Child_Pair_Count", "Child Pair Count", "", ""); // Apacer Flash (description?) (smartctl) - add(163, AtaStorageAttribute::DiskType::Ssd, "Max_Erase_Count", "Maximum Erase Count", "", + add(163, StorageDeviceDetectedType::AtaSsd, "Max_Erase_Count", "Maximum Erase Count", "", "The maximum of individual erase counts of all the blocks."); // Innodisk SSD: (smartctl) - add(163, AtaStorageAttribute::DiskType::Ssd, "Initial_Bad_Block_Count", "Initial Bad Block Count", "", + add(163, StorageDeviceDetectedType::AtaSsd, "Initial_Bad_Block_Count", "Initial Bad Block Count", "", "Factory-determined number of initial bad blocks."); // Innodisk SSD: (smartctl) - add(163, AtaStorageAttribute::DiskType::Ssd, "Total_Bad_Block_Count", "Total Bad Block Count", "", + add(163, StorageDeviceDetectedType::AtaSsd, "Total_Bad_Block_Count", "Total Bad Block Count", "", "Number of bad blocks. SSDs reallocate blocks as part of their normal operation, so low bad block counts are not critical for them."); // Apacer Flash (description?) (smartctl) - add(164, AtaStorageAttribute::DiskType::Ssd, "Average_Erase_Count", "Average Erase Count", "", + add(164, StorageDeviceDetectedType::AtaSsd, "Average_Erase_Count", "Average Erase Count", "", ""); // Innodisk SSD (description?) (smartctl) - add(164, AtaStorageAttribute::DiskType::Ssd, "Total_Erase_Count", "Total Erase Count", "", + add(164, StorageDeviceDetectedType::AtaSsd, "Total_Erase_Count", "Total Erase Count", "", ""); // Apacer Flash (description?) (smartctl) - add(165, AtaStorageAttribute::DiskType::Ssd, "Average_Erase_Count", "Average Erase Count", "", + add(165, StorageDeviceDetectedType::AtaSsd, "Average_Erase_Count", "Average Erase Count", "", ""); // Innodisk SSD (description?) (smartctl) - add(165, AtaStorageAttribute::DiskType::Ssd, "Max_Erase_Count", "Maximum Erase Count", "", + add(165, StorageDeviceDetectedType::AtaSsd, "Max_Erase_Count", "Maximum Erase Count", "", ""); // Sandisk SSD (description?) (smartctl) - add(165, AtaStorageAttribute::DiskType::Ssd, "Total_Write/Erase_Count", "Total Write / Erase Count", "", + add(165, StorageDeviceDetectedType::AtaSsd, "Total_Write/Erase_Count", "Total Write / Erase Count", "", ""); // Apacer Flash (description?) (smartctl) - add(166, AtaStorageAttribute::DiskType::Ssd, "Later_Bad_Block_Count", "Later Bad Block Count", "", + add(166, StorageDeviceDetectedType::AtaSsd, "Later_Bad_Block_Count", "Later Bad Block Count", "", ""); // Innodisk SSD (description?) (smartctl) - add(166, AtaStorageAttribute::DiskType::Ssd, "Min_Erase_Count", "Minimum Erase Count", "", + add(166, StorageDeviceDetectedType::AtaSsd, "Min_Erase_Count", "Minimum Erase Count", "", ""); // Sandisk SSD (description?) (smartctl) - add(166, AtaStorageAttribute::DiskType::Ssd, "Min_W/E_Cycle", "Minimum Write / Erase Cycles", "", + add(166, StorageDeviceDetectedType::AtaSsd, "Min_W/E_Cycle", "Minimum Write / Erase Cycles", "", ""); // Apacer Flash, OCZ (description?) (smartctl) - add(167, AtaStorageAttribute::DiskType::Ssd, "SSD_Protect_Mode", "SSD Protect Mode", "", + add(167, StorageDeviceDetectedType::AtaSsd, "SSD_Protect_Mode", "SSD Protect Mode", "", ""); // Innodisk SSD (description?) (smartctl) - add(167, AtaStorageAttribute::DiskType::Ssd, "Average_Erase_Count", "Average Erase Count", "", + add(167, StorageDeviceDetectedType::AtaSsd, "Average_Erase_Count", "Average Erase Count", "", ""); // Sandisk SSD (description?) (smartctl) - add(167, AtaStorageAttribute::DiskType::Ssd, "Min_Bad_Block/Die", "Minimum Bad Block / Die", "", + add(167, StorageDeviceDetectedType::AtaSsd, "Min_Bad_Block/Die", "Minimum Bad Block / Die", "", ""); // Apacer Flash (description?) (smartctl) - add(168, AtaStorageAttribute::DiskType::Ssd, "SATA_PHY_Err_Ct", "SATA Physical Error Count", "", + add(168, StorageDeviceDetectedType::AtaSsd, "SATA_PHY_Err_Ct", "SATA Physical Error Count", "", ""); // Various SSDs: (smartctl) (description?) - add(168, AtaStorageAttribute::DiskType::Ssd, "SATA_Phy_Error_Count", "SATA Physical Error Count", "", + add(168, StorageDeviceDetectedType::AtaSsd, "SATA_Phy_Error_Count", "SATA Physical Error Count", "", ""); // Innodisk SSDs: (smartctl) (description?) - add(168, AtaStorageAttribute::DiskType::Ssd, "Max_Erase_Count_of_Spec", "Maximum Erase Count per Specification", "", + add(168, StorageDeviceDetectedType::AtaSsd, "Max_Erase_Count_of_Spec", "Maximum Erase Count per Specification", "", ""); // Sandisk SSD (description?) (smartctl) - add(168, AtaStorageAttribute::DiskType::Ssd, "Maximum_Erase_Cycle", "Maximum Erase Cycles", "", + add(168, StorageDeviceDetectedType::AtaSsd, "Maximum_Erase_Cycle", "Maximum Erase Cycles", "", ""); // Toshiba SSDs: (smartctl) (description?) - add(169, AtaStorageAttribute::DiskType::Ssd, "Bad_Block_Count", "Bad Block Count", "", + add(169, StorageDeviceDetectedType::AtaSsd, "Bad_Block_Count", "Bad Block Count", "", "Number of bad blocks. SSDs reallocate blocks as part of their normal operation, so low bad block counts are not critical for them."); // Sandisk SSD (description?) (smartctl) - add(169, AtaStorageAttribute::DiskType::Ssd, "Total_Bad_Blocks", "Total Bad Blocks", "", + add(169, StorageDeviceDetectedType::AtaSsd, "Total_Bad_Blocks", "Total Bad Blocks", "", "Number of bad blocks. SSDs reallocate blocks as part of their normal operation, so low bad block counts are not critical for them."); // Innodisk SSDs: (smartctl) (description?) - add(169, AtaStorageAttribute::DiskType::Ssd, "Remaining_Lifetime_Perc", "Remaining Lifetime %", "attr_ssd_life_left", + add(169, StorageDeviceDetectedType::AtaSsd, "Remaining_Lifetime_Perc", "Remaining Lifetime %", "attr_ssd_life_left", "Remaining drive life in % (usually by erase count)."); // Intel SSD, STEC CF: Reserved Block Count (smartctl) - add(170, AtaStorageAttribute::DiskType::Ssd, "Reserve_Block_Count", "Reserved Block Count", "", + add(170, StorageDeviceDetectedType::AtaSsd, "Reserve_Block_Count", "Reserved Block Count", "", "Number of reserved (spare) blocks for bad block handling."); // Micron SSD: Reserved Block Count (smartctl) - add(170, AtaStorageAttribute::DiskType::Ssd, "Reserved_Block_Count", "Reserved Block Count", "", + add(170, StorageDeviceDetectedType::AtaSsd, "Reserved_Block_Count", "Reserved Block Count", "", "Number of reserved (spare) blocks for bad block handling."); // Crucial / Marvell SSD: Grown Failing Block Count (smartctl) (description?) - add(170, AtaStorageAttribute::DiskType::Ssd, "Grown_Failing_Block_Ct", "Grown Failing Block Count", "", + add(170, StorageDeviceDetectedType::AtaSsd, "Grown_Failing_Block_Ct", "Grown Failing Block Count", "", ""); // Intel SSD: (smartctl) (description?) - add(170, AtaStorageAttribute::DiskType::Ssd, "Available_Reservd_Space", "Available Reserved Space", "", + add(170, StorageDeviceDetectedType::AtaSsd, "Available_Reservd_Space", "Available Reserved Space", "", ""); // Various SSDs: (smartctl) (description?) - add(170, AtaStorageAttribute::DiskType::Ssd, "Bad_Block_Count", "Bad Block Count", "", + add(170, StorageDeviceDetectedType::AtaSsd, "Bad_Block_Count", "Bad Block Count", "", "Number of bad blocks. SSDs reallocate blocks as part of their normal operation, so low bad block counts are not critical for them."); // Kingston SSDs: (smartctl) (description?) - add(170, AtaStorageAttribute::DiskType::Ssd, "Bad_Blk_Ct_Erl/Lat", "Bad Block Early / Later", "", + add(170, StorageDeviceDetectedType::AtaSsd, "Bad_Blk_Ct_Erl/Lat", "Bad Block Early / Later", "", ""); // Samsung SSDs: (smartctl) (description?) - add(170, AtaStorageAttribute::DiskType::Ssd, "Unused_Rsvd_Blk_Ct_Chip", "Unused Reserved Block Count (Chip)", "", + add(170, StorageDeviceDetectedType::AtaSsd, "Unused_Rsvd_Blk_Ct_Chip", "Unused Reserved Block Count (Chip)", "", ""); // Innodisk Flash (description?) (smartctl) - add(170, AtaStorageAttribute::DiskType::Ssd, "Spare_Block_Count", "Spare Block Count", "", + add(170, StorageDeviceDetectedType::AtaSsd, "Spare_Block_Count", "Spare Block Count", "", "Number of spare blocks which are used in case bad blocks develop."); // Intel SSD, Sandforce SSD, STEC CF, Crucial / Marvell SSD: Program Fail Count (smartctl) - add(171, AtaStorageAttribute::DiskType::Ssd, "Program_Fail_Count", "Program Fail Count", "", + add(171, StorageDeviceDetectedType::AtaSsd, "Program_Fail_Count", "Program Fail Count", "", "Number of flash program (write) failures. High values may indicate old drive age or other problems."); // Samsung SSDs: (smartctl) (description?) - add(171, AtaStorageAttribute::DiskType::Ssd, "Program_Fail_Count_Chip", "Program Fail Count (Chip)", "", + add(171, StorageDeviceDetectedType::AtaSsd, "Program_Fail_Count_Chip", "Program Fail Count (Chip)", "", ""); // OCZ SSD (smartctl) - add(171, AtaStorageAttribute::DiskType::Ssd, "Avail_OP_Block_Count", "Available OP Block Count", "", + add(171, StorageDeviceDetectedType::AtaSsd, "Avail_OP_Block_Count", "Available OP Block Count", "", ""); // Intel SSD, Sandforce SSD, STEC CF, Crucial / Marvell SSD: Erase Fail Count (smartctl) - add(172, AtaStorageAttribute::DiskType::Ssd, "Erase_Fail_Count", "Erase Fail Count", "", + add(172, StorageDeviceDetectedType::AtaSsd, "Erase_Fail_Count", "Erase Fail Count", "", "Number of flash erase command failures. High values may indicate old drive age or other problems."); // Various SSDs (smartctl) (description?) - add(173, AtaStorageAttribute::DiskType::Ssd, "Erase_Count", "Erase Count", "", + add(173, StorageDeviceDetectedType::AtaSsd, "Erase_Count", "Erase Count", "", ""); // Samsung SSDs (smartctl) (description?) - add(173, AtaStorageAttribute::DiskType::Ssd, "Erase_Fail_Count_Chip", "Erase Fail Count (Chip)", "", + add(173, StorageDeviceDetectedType::AtaSsd, "Erase_Fail_Count_Chip", "Erase Fail Count (Chip)", "", ""); // Kingston SSDs (smartctl) (description?) - add(173, AtaStorageAttribute::DiskType::Ssd, "MaxAvgErase_Ct", "Maximum / Average Erase Count", "", + add(173, StorageDeviceDetectedType::AtaSsd, "MaxAvgErase_Ct", "Maximum / Average Erase Count", "", ""); // Crucial/Micron SSDs (smartctl) (description?) - add(173, AtaStorageAttribute::DiskType::Ssd, "Ave_Block-Erase_Count", "Average Block-Erase Count", "", + add(173, StorageDeviceDetectedType::AtaSsd, "Ave_Block-Erase_Count", "Average Block-Erase Count", "", ""); // STEC CF, Crucial / Marvell SSD: Wear Leveling Count (smartctl) (description?) - add(173, AtaStorageAttribute::DiskType::Ssd, "Wear_Leveling_Count", "Wear Leveling Count", "", + add(173, StorageDeviceDetectedType::AtaSsd, "Wear_Leveling_Count", "Wear Leveling Count", "", "Indicates the difference between the most worn block and the least worn block."); // Same as above, old smartctl - add(173, AtaStorageAttribute::DiskType::Ssd, "Wear_Levelling_Count", "Wear Leveling Count", "", + add(173, StorageDeviceDetectedType::AtaSsd, "Wear_Levelling_Count", "Wear Leveling Count", "", "Indicates the difference between the most worn block and the least worn block."); // Sandisk SSDs (smartctl) (description?) - add(173, AtaStorageAttribute::DiskType::Ssd, "Avg_Write/Erase_Count", "Average Write / Erase Count", "", + add(173, StorageDeviceDetectedType::AtaSsd, "Avg_Write/Erase_Count", "Average Write / Erase Count", "", ""); // Intel SSD, Sandforce SSD, Crucial / Marvell SSD: Unexpected Power Loss (smartctl) - add(174, AtaStorageAttribute::DiskType::Ssd, "Unexpect_Power_Loss_Ct", "Unexpected Power Loss Count", "", + add(174, StorageDeviceDetectedType::AtaSsd, "Unexpect_Power_Loss_Ct", "Unexpected Power Loss Count", "", "Number of unexpected power loss events."); // OCZ SSD (smartctl) - add(174, AtaStorageAttribute::DiskType::Ssd, "Pwr_Cycle_Ct_Unplanned", "Unexpected Power Loss Count", "", + add(174, StorageDeviceDetectedType::AtaSsd, "Pwr_Cycle_Ct_Unplanned", "Unexpected Power Loss Count", "", "Number of unexpected power loss events."); // Apple SSD (smartctl) - add(174, AtaStorageAttribute::DiskType::Ssd, "Host_Reads_MiB", "Host Read (MiB)", "", + add(174, StorageDeviceDetectedType::AtaSsd, "Host_Reads_MiB", "Host Read (MiB)", "", "Total number of sectors read by the host system. The Raw value is increased by 1 for every MiB read by the host."); // Program_Fail_Count_Chip (smartctl) - add(175, AtaStorageAttribute::DiskType::Ssd, "Program_Fail_Count_Chip", "Program Fail Count (Chip)", "", + add(175, StorageDeviceDetectedType::AtaSsd, "Program_Fail_Count_Chip", "Program Fail Count (Chip)", "", "Number of flash program (write) failures. High values may indicate old drive age or other problems."); // Various SSDs: Bad_Cluster_Table_Count (smartctl) (description?) - add(175, AtaStorageAttribute::DiskType::Ssd, "Bad_Cluster_Table_Count", "Bad Cluster Table Count", "", + add(175, StorageDeviceDetectedType::AtaSsd, "Bad_Cluster_Table_Count", "Bad Cluster Table Count", "", ""); // Intel SSD (smartctl) (description?) - add(175, AtaStorageAttribute::DiskType::Ssd, "Power_Loss_Cap_Test", "Power Loss Capacitor Test", "", + add(175, StorageDeviceDetectedType::AtaSsd, "Power_Loss_Cap_Test", "Power Loss Capacitor Test", "", ""); // Intel SSD (smartctl) (description?) - add(175, AtaStorageAttribute::DiskType::Ssd, "Host_Writes_MiB", "Host Written (MiB)", "", + add(175, StorageDeviceDetectedType::AtaSsd, "Host_Writes_MiB", "Host Written (MiB)", "", "Total number of sectors written by the host system. The Raw value is increased by 1 for every MiB written by the host."); // Erase_Fail_Count_Chip (smartctl) - add(176, AtaStorageAttribute::DiskType::Ssd, "Erase_Fail_Count_Chip", "Erase Fail Count (Chip)", "", + add(176, StorageDeviceDetectedType::AtaSsd, "Erase_Fail_Count_Chip", "Erase Fail Count (Chip)", "", "Number of flash erase command failures. High values may indicate old drive age or other problems."); // Innodisk SSD (smartctl) (description?) - add(176, AtaStorageAttribute::DiskType::Ssd, "Uncorr_RECORD_Count", "Uncorrected RECORD Count", "", + add(176, StorageDeviceDetectedType::AtaSsd, "Uncorr_RECORD_Count", "Uncorrected RECORD Count", "", ""); // Innodisk SSD (smartctl) (description?) - add(176, AtaStorageAttribute::DiskType::Ssd, "RANGE_RECORD_Count", "RANGE RECORD Count", "", + add(176, StorageDeviceDetectedType::AtaSsd, "RANGE_RECORD_Count", "RANGE RECORD Count", "", ""); // Wear_Leveling_Count (smartctl) (same as Wear_Range_Delta?) - add(177, AtaStorageAttribute::DiskType::Ssd, "Wear_Leveling_Count", "Wear Leveling Count", "", + add(177, StorageDeviceDetectedType::AtaSsd, "Wear_Leveling_Count", "Wear Leveling Count", "", "Indicates the difference (in percent) between the most worn block and the least worn block."); // Sandforce SSD: Wear_Range_Delta (smartctl) - add(177, AtaStorageAttribute::DiskType::Ssd, "Wear_Range_Delta", "Wear Range Delta", "", + add(177, StorageDeviceDetectedType::AtaSsd, "Wear_Range_Delta", "Wear Range Delta", "", "Indicates the difference (in percent) between the most worn block and the least worn block."); // Used_Rsvd_Blk_Cnt_Chip (smartctl) - add(178, AtaStorageAttribute::DiskType::Ssd, "Used_Rsvd_Blk_Cnt_Chip", "Used Reserved Block Count (Chip)", "", + add(178, StorageDeviceDetectedType::AtaSsd, "Used_Rsvd_Blk_Cnt_Chip", "Used Reserved Block Count (Chip)", "", "Number of a chip's used reserved blocks. High values may indicate old drive age or other problems."); // Innodisk SSD (smartctl) - add(178, AtaStorageAttribute::DiskType::Ssd, "Runtime_Invalid_Blk_Cnt", "Runtime Invalid Block Count", "", + add(178, StorageDeviceDetectedType::AtaSsd, "Runtime_Invalid_Blk_Cnt", "Runtime Invalid Block Count", "", ""); // Used_Rsvd_Blk_Cnt_Tot (smartctl) (description?) - add(179, AtaStorageAttribute::DiskType::Ssd, "Used_Rsvd_Blk_Cnt_Tot", "Used Reserved Block Count (Total)", "", + add(179, StorageDeviceDetectedType::AtaSsd, "Used_Rsvd_Blk_Cnt_Tot", "Used Reserved Block Count (Total)", "", "Number of used reserved blocks. High values may indicate old drive age or other problems."); // Unused_Rsvd_Blk_Cnt_Tot (smartctl) - add(180, AtaStorageAttribute::DiskType::Ssd, "Unused_Rsvd_Blk_Cnt_Tot", "Unused Reserved Block Count (Total)", "", + add(180, StorageDeviceDetectedType::AtaSsd, "Unused_Rsvd_Blk_Cnt_Tot", "Unused Reserved Block Count (Total)", "", "Number of unused reserved blocks. High values may indicate old drive age or other problems."); // Crucial / Micron SSDs (smartctl) (description?) - add(180, AtaStorageAttribute::DiskType::Ssd, "Unused_Reserve_NAND_Blk", "Unused Reserved NAND Blocks", "", + add(180, StorageDeviceDetectedType::AtaSsd, "Unused_Reserve_NAND_Blk", "Unused Reserved NAND Blocks", "", ""); // Program_Fail_Cnt_Total (smartctl) add(181, "Program_Fail_Cnt_Total", "Program Fail Count", "", "Number of flash program (write) failures. High values may indicate old drive age or other problems."); // Sandforce SSD: Program_Fail_Count (smartctl) (Sandforce says it's identical to 171) - add(181, AtaStorageAttribute::DiskType::Ssd, "Program_Fail_Count"); + add(181, StorageDeviceDetectedType::AtaSsd, "Program_Fail_Count"); // Crucial / Marvell SSD (smartctl) (description?) - add(181, AtaStorageAttribute::DiskType::Ssd, "Non4k_Aligned_Access", "Non-4k Aligned Access", "", + add(181, StorageDeviceDetectedType::AtaSsd, "Non4k_Aligned_Access", "Non-4k Aligned Access", "", ""); // Erase_Fail_Count_Total (smartctl) (description?) - add(182, AtaStorageAttribute::DiskType::Ssd, "Erase_Fail_Count_Total", "Erase Fail Count", "", + add(182, StorageDeviceDetectedType::AtaSsd, "Erase_Fail_Count_Total", "Erase Fail Count", "", "Number of flash erase command failures. High values may indicate old drive age or other problems."); // Sandforce SSD: Erase_Fail_Count (smartctl) (Sandforce says it's identical to 172) - add(182, AtaStorageAttribute::DiskType::Ssd, "Erase_Fail_Count"); + add(182, StorageDeviceDetectedType::AtaSsd, "Erase_Fail_Count"); // Runtime_Bad_Block (smartctl) (description?) add(183, "Runtime_Bad_Block", "Runtime Bad Blocks", "", ""); // Samsung, WD, Crucial / Marvell SSD: SATA Downshift Error Count (smartctl) (description?) - add(183, AtaStorageAttribute::DiskType::Any, "SATA_Iface_Downshift", "SATA Downshift Error Count", "", + add(183, "SATA_Iface_Downshift", "SATA Downshift Error Count", "", ""); // Crucial / Marvell SSD: SATA Downshift Error Count (smartctl) (description?) - add(183, AtaStorageAttribute::DiskType::Any, "SATA_Interfac_Downshift", "SATA Downshift Error Count", "", + add(183, "SATA_Interfac_Downshift", "SATA Downshift Error Count", "", ""); // Intel SSD, Ubtek SSD (smartctl) (description?) - add(183, AtaStorageAttribute::DiskType::Ssd, "SATA_Downshift_Count", "SATA Downshift Error Count", "", + add(183, StorageDeviceDetectedType::AtaSsd, "SATA_Downshift_Count", "SATA Downshift Error Count", "", ""); // End to End Error (smartctl) (description?) add(184, "End-to-End_Error", "End to End Error", "", "Indicates discrepancy of data between the host and the drive cache."); // Sandforce SSD: IO_Error_Detect_Code_Ct (smartctl) - add(184, AtaStorageAttribute::DiskType::Ssd, "IO_Error_Detect_Code_Ct", "Input/Output ECC Error Count", "", + add(184, StorageDeviceDetectedType::AtaSsd, "IO_Error_Detect_Code_Ct", "Input/Output ECC Error Count", "", ""); // OCZ SSD (smartctl) - add(184, AtaStorageAttribute::DiskType::Ssd, "Factory_Bad_Block_Count", "Factory Bad Block Count", "", + add(184, StorageDeviceDetectedType::AtaSsd, "Factory_Bad_Block_Count", "Factory Bad Block Count", "", ""); // Indilinx Barefoot SSD: IO_Error_Detect_Code_Ct (smartctl) - add(184, AtaStorageAttribute::DiskType::Ssd, "Initial_Bad_Block_Count", "Initial Bad Block Count", "", + add(184, StorageDeviceDetectedType::AtaSsd, "Initial_Bad_Block_Count", "Initial Bad Block Count", "", "Factory-determined number of initial bad blocks."); // Crucial / Micron SSD (smartctl) - add(184, AtaStorageAttribute::DiskType::Ssd, "Error_Correction_Count", "Error Correction Count", "", + add(184, StorageDeviceDetectedType::AtaSsd, "Error_Correction_Count", "Error Correction Count", "", ""); // WD: Head Stability (custom) - add(185, AtaStorageAttribute::DiskType::Hdd, "", "Head Stability", "", + add(185, StorageDeviceDetectedType::AtaHdd, "", "Head Stability", "", ""); // WD: Induced Op-Vibration Detection (custom) - add(185, AtaStorageAttribute::DiskType::Hdd, "", "Induced Op-Vibration Detection", "", // unused + add(185, StorageDeviceDetectedType::AtaHdd, "", "Induced Op-Vibration Detection", "", // unused ""); // Reported Uncorrectable (smartctl) add(187, "Reported_Uncorrect", "Reported Uncorrectable", "", "Number of errors that could not be recovered using hardware ECC (Error-Correcting Code)."); // Innodisk SSD: Reported Uncorrectable (smartctl) - add(187, AtaStorageAttribute::DiskType::Ssd, "Uncorrectable_Error_Cnt"); + add(187, StorageDeviceDetectedType::AtaSsd, "Uncorrectable_Error_Cnt"); // OCZ SSD (smartctl) - add(187, AtaStorageAttribute::DiskType::Ssd, "Total_Unc_NAND_Reads", "Total Uncorrectable NAND Reads", "", + add(187, StorageDeviceDetectedType::AtaSsd, "Total_Unc_NAND_Reads", "Total Uncorrectable NAND Reads", "", ""); // Command Timeout (smartctl) add(188, "Command_Timeout", "Command Timeout", "", "Number of aborted operations due to drive timeout. High values may indicate problems with cabling or power supply."); // Micron SSD (smartctl) - add(188, AtaStorageAttribute::DiskType::Ssd, "Command_Timeouts", "Command Timeout", "", + add(188, StorageDeviceDetectedType::AtaSsd, "Command_Timeouts", "Command Timeout", "", "Number of aborted operations due to drive timeout. High values may indicate problems with cabling or power supply."); // High Fly Writes (smartctl) - add(189, AtaStorageAttribute::DiskType::Hdd, "High_Fly_Writes", "High Fly Writes", "", + add(189, StorageDeviceDetectedType::AtaHdd, "High_Fly_Writes", "High Fly Writes", "", "Some drives can detect when a recording head is flying outside its normal operating range. " "If an unsafe fly height condition is encountered, the write process is stopped, and the information " "is rewritten or reallocated to a safe region of the drive. This attribute indicates the count of " "these errors detected over the lifetime of the drive."); // Crucial / Marvell SSD (smartctl) - add(189, AtaStorageAttribute::DiskType::Ssd, "Factory_Bad_Block_Ct", "Factory Bad Block Count", "", + add(189, StorageDeviceDetectedType::AtaSsd, "Factory_Bad_Block_Ct", "Factory Bad Block Count", "", "Factory-determined number of initial bad blocks."); // Various SSD (smartctl) add(189, "Airflow_Temperature_Cel", "Airflow Temperature", "", @@ -469,38 +469,38 @@ namespace { add(190, "Temperature_Case", "Case Temperature (Celsius)", "", "Drive case temperature. The Raw value shows built-in heat sensor registrations (in Celsius)."); // G-sense error rate (smartctl) (same as 221?) - add(191, AtaStorageAttribute::DiskType::Hdd, "G-Sense_Error_Rate", "G-Sense Error Rate", "", + add(191, StorageDeviceDetectedType::AtaHdd, "G-Sense_Error_Rate", "G-Sense Error Rate", "", "Number of errors caused by externally-induced shock and vibration (Raw value). May indicate incorrect installation."); // Power-Off Retract Cycle (smartctl) - add(192, AtaStorageAttribute::DiskType::Hdd, "Power-Off_Retract_Count", "Head Retract Cycle Count", "", + add(192, StorageDeviceDetectedType::AtaHdd, "Power-Off_Retract_Count", "Head Retract Cycle Count", "", "Number of times the heads were loaded off the media (during power-offs or emergency conditions)."); // Intel SSD: Unsafe_Shutdown_Count (smartctl) - add(192, AtaStorageAttribute::DiskType::Ssd, "Unsafe_Shutdown_Count", "Unsafe Shutdown Count", "", + add(192, StorageDeviceDetectedType::AtaSsd, "Unsafe_Shutdown_Count", "Unsafe Shutdown Count", "", "Raw value indicates the number of unsafe (unclean) shutdown events over the drive lifetime. " "An unsafe shutdown occurs whenever the device is powered off without " "STANDBY IMMEDIATE being the last command."); // Various SSDs (smartctl) - add(192, AtaStorageAttribute::DiskType::Ssd, "Unexpect_Power_Loss_Ct", "Unexpected Power Loss Count", "", + add(192, StorageDeviceDetectedType::AtaSsd, "Unexpect_Power_Loss_Ct", "Unexpected Power Loss Count", "", "Number of unexpected power loss events."); // Fujitsu: Emergency Retract Cycle Count (smartctl) - add(192, AtaStorageAttribute::DiskType::Hdd, "Emerg_Retract_Cycle_Ct", "Emergency Retract Cycle Count", "", + add(192, StorageDeviceDetectedType::AtaHdd, "Emerg_Retract_Cycle_Ct", "Emergency Retract Cycle Count", "", "Number of times the heads were loaded off the media during emergency conditions."); // Load/Unload Cycle (smartctl) - add(193, AtaStorageAttribute::DiskType::Hdd, "Load_Cycle_Count", "Load / Unload Cycle", "", + add(193, StorageDeviceDetectedType::AtaHdd, "Load_Cycle_Count", "Load / Unload Cycle", "", "Number of load / unload cycles into Landing Zone position."); // Temperature Celsius (smartctl) (same as 231). This is the most common one. Some Samsungs: 10xTemp. add(194, "Temperature_Celsius", "Temperature (Celsius)", "attr_temperature_celsius", "Drive temperature. The Raw value shows built-in heat sensor registrations (in Celsius). " "Increases in average drive temperature often signal spindle motor problems (unless the increases are caused by environmental factors)."); // Samsung SSD: Temperature Celsius (smartctl) (not sure about the value) - add(194, AtaStorageAttribute::DiskType::Ssd, "Airflow_Temperature", "Airflow Temperature (Celsius)", "attr_temperature_celsius", + add(194, StorageDeviceDetectedType::AtaSsd, "Airflow_Temperature", "Airflow Temperature (Celsius)", "attr_temperature_celsius", "Drive temperature (Celsius)"); // Temperature Celsius x 10 (smartctl) add(194, "Temperature_Celsius_x10", "Temperature (Celsius) x 10", "attr_temperature_celsius_x10", "Drive temperature. The Raw value shows built-in heat sensor registrations (in Celsius * 10). " "Increases in average drive temperature often signal spindle motor problems (unless the increases are caused by environmental factors)."); // Smart Storage Systems SSD (smartctl) - add(194, AtaStorageAttribute::DiskType::Ssd, "Proprietary_194", "Internal Attribute", "", + add(194, StorageDeviceDetectedType::AtaSsd, "Proprietary_194", "Internal Attribute", "", "This attribute has been reserved by vendor as internal."); // Intel SSD (smartctl) add(194, "Temperature_Internal", "Internal Temperature (Celsius)", "attr_temperature_celsius", @@ -509,32 +509,32 @@ namespace { add(195, "Hardware_ECC_Recovered", "Hardware ECC Recovered", "", "Number of ECC on the fly errors (Raw value). Users are advised to ignore this attribute."); // Fujitsu: ECC_On_The_Fly_Count (smartctl) - add(195, AtaStorageAttribute::DiskType::Hdd, "ECC_On_The_Fly_Count"); + add(195, StorageDeviceDetectedType::AtaHdd, "ECC_On_The_Fly_Count"); // Sandforce SSD: ECC_Uncorr_Error_Count (smartctl) (description?) - add(195, AtaStorageAttribute::DiskType::Ssd, "ECC_Uncorr_Error_Count", "Uncorrected ECC Error Count", "", + add(195, StorageDeviceDetectedType::AtaSsd, "ECC_Uncorr_Error_Count", "Uncorrected ECC Error Count", "", "Number of uncorrectable errors (UECC)."); // Samsung SSD (smartctl) (description?) - add(195, AtaStorageAttribute::DiskType::Ssd, "ECC_Rate", "Uncorrected ECC Error Rate", "", + add(195, StorageDeviceDetectedType::AtaSsd, "ECC_Rate", "Uncorrected ECC Error Rate", "", ""); // OCZ SSD (smartctl) - add(195, AtaStorageAttribute::DiskType::Ssd, "Total_Prog_Failures", "Total Program Failures", "", + add(195, StorageDeviceDetectedType::AtaSsd, "Total_Prog_Failures", "Total Program Failures", "", ""); // Indilinx Barefoot SSD: Program_Failure_Blk_Ct (smartctl) (description?) - add(195, AtaStorageAttribute::DiskType::Ssd, "Program_Failure_Blk_Ct", "Program Failure Block Count", "", + add(195, StorageDeviceDetectedType::AtaSsd, "Program_Failure_Blk_Ct", "Program Failure Block Count", "", "Number of flash program (write) failures."); // Micron SSD (smartctl) - add(195, AtaStorageAttribute::DiskType::Ssd, "Cumulativ_Corrected_ECC", "Cumulative Corrected ECC Error Count", "", + add(195, StorageDeviceDetectedType::AtaSsd, "Cumulativ_Corrected_ECC", "Cumulative Corrected ECC Error Count", "", ""); // Reallocation Event Count (smartctl) - add(196, AtaStorageAttribute::DiskType::Any, "Reallocated_Event_Count", "Reallocation Event Count", "attr_reallocation_event_count", + add(196, std::nullopt, "Reallocated_Event_Count", "Reallocation Event Count", "attr_reallocation_event_count", "Number of reallocation (remap) operations. Raw value should show the total number of attempts " "(both successful and unsuccessful) to reallocate sectors. An increase in Raw value indicates a disk surface failure." "\n\n" + get_uncorrectable_text()); // Indilinx Barefoot SSD: Erase_Failure_Blk_Ct (smartctl) (description?) - add(196, AtaStorageAttribute::DiskType::Ssd, "Erase_Failure_Blk_Ct", "Erase Failure Block Count", "", + add(196, StorageDeviceDetectedType::AtaSsd, "Erase_Failure_Blk_Ct", "Erase Failure Block Count", "", "Number of flash erase failures."); // OCZ SSD (smartctl) - add(196, AtaStorageAttribute::DiskType::Ssd, "Total_Erase_Failures", "Total Erase Failures", "", + add(196, StorageDeviceDetectedType::AtaSsd, "Total_Erase_Failures", "Total Erase Failures", "", ""); // Current Pending Sector Count (smartctl) add(197, "Current_Pending_Sector", "Current Pending Sector Count", "attr_current_pending_sector_count", @@ -543,7 +543,7 @@ namespace { "An increase in Raw value indicates a disk surface failure." "\n\n" + get_uncorrectable_text()); // Indilinx Barefoot SSD: Read_Failure_Blk_Ct (smartctl) (description?) - add(197, AtaStorageAttribute::DiskType::Ssd, "Read_Failure_Blk_Ct", "Read Failure Block Count", "", + add(197, StorageDeviceDetectedType::AtaSsd, "Read_Failure_Blk_Ct", "Read Failure Block Count", "", "Number of blocks that failed to be read."); // Samsung: Total_Pending_Sectors (smartctl). From smartctl man page: // unlike Current_Pending_Sector, this won't decrease on reallocation. @@ -552,7 +552,7 @@ namespace { "An increase in Raw value indicates a disk surface failure." "\n\n" + get_uncorrectable_text()); // OCZ SSD (smartctl) - add(197, AtaStorageAttribute::DiskType::Ssd, "Total_Unc_Read_Failures", "Total Uncorrectable Read Failures", "", + add(197, StorageDeviceDetectedType::AtaSsd, "Total_Unc_Read_Failures", "Total Uncorrectable Read Failures", "", ""); // Offline Uncorrectable (smartctl) add(198, "Offline_Uncorrectable", "Offline Uncorrectable", "attr_offline_uncorrectable", @@ -568,17 +568,17 @@ namespace { "An increase in Raw value indicates a disk surface failure." "\n\n" + get_uncorrectable_text()); // Sandforce SSD: Uncorrectable_Sector_Ct (smartctl) (same description?) - add(198, AtaStorageAttribute::DiskType::Ssd, "Uncorrectable_Sector_Ct"); + add(198, StorageDeviceDetectedType::AtaSsd, "Uncorrectable_Sector_Ct"); // Indilinx Barefoot SSD: Read_Sectors_Tot_Ct (smartctl) (description?) - add(198, AtaStorageAttribute::DiskType::Ssd, "Read_Sectors_Tot_Ct", "Total Read Sectors", "", + add(198, StorageDeviceDetectedType::AtaSsd, "Read_Sectors_Tot_Ct", "Total Read Sectors", "", "Total count of read sectors."); // OCZ SSD - add(198, AtaStorageAttribute::DiskType::Ssd, "Host_Reads_GiB", "Host Read (GiB)", "", + add(198, StorageDeviceDetectedType::AtaSsd, "Host_Reads_GiB", "Host Read (GiB)", "", "Total number of sectors read by the host system. The Raw value is increased by 1 for every GiB read by the host."); // Fujitsu: Offline_Scan_UNC_SectCt (smartctl) - add(198, AtaStorageAttribute::DiskType::Hdd, "Offline_Scan_UNC_SectCt"); + add(198, StorageDeviceDetectedType::AtaHdd, "Offline_Scan_UNC_SectCt"); // Fujitsu version of Offline Uncorrectable (smartctl) (old, not in current smartctl) - add(198, AtaStorageAttribute::DiskType::Hdd, "Off-line_Scan_UNC_Sector_Ct"); + add(198, StorageDeviceDetectedType::AtaHdd, "Off-line_Scan_UNC_Sector_Ct"); // UDMA CRC Error Count (smartctl) add(199, "UDMA_CRC_Error_Count", "UDMA CRC Error Count", "", "Number of errors in data transfer via the interface cable in UDMA mode, as determined by ICRC " @@ -593,464 +593,464 @@ namespace { add(199, "CRC_Error_Count", "CRC Error Count", "", "Number of errors in data transfer via the interface cable (Raw value)."); // Indilinx Barefoot SSD: Write_Sectors_Tot_Ct (smartctl) (description?) - add(199, AtaStorageAttribute::DiskType::Ssd, "Write_Sectors_Tot_Ct", "Total Written Sectors", "", + add(199, StorageDeviceDetectedType::AtaSsd, "Write_Sectors_Tot_Ct", "Total Written Sectors", "", "Total count of written sectors."); // OCZ SSD - add(198, AtaStorageAttribute::DiskType::Ssd, "Host_Writes_GiB", "Host Written (GiB)", "", + add(198, StorageDeviceDetectedType::AtaSsd, "Host_Writes_GiB", "Host Written (GiB)", "", "Total number of sectors written by the host system. The Raw value is increased by 1 for every GiB written by the host."); // WD: Multi-Zone Error Rate (smartctl). (maybe head flying height too (?)) - add(200, AtaStorageAttribute::DiskType::Hdd, "Multi_Zone_Error_Rate", "Multi Zone Error Rate", "", + add(200, StorageDeviceDetectedType::AtaHdd, "Multi_Zone_Error_Rate", "Multi Zone Error Rate", "", "Number of errors found when writing to sectors (Raw value). The higher the value, the worse the disk surface condition and/or mechanical subsystem is."); // Fujitsu: Write Error Rate (smartctl) - add(200, AtaStorageAttribute::DiskType::Hdd, "Write_Error_Count", "Write Error Count", "", + add(200, StorageDeviceDetectedType::AtaHdd, "Write_Error_Count", "Write Error Count", "", "Number of errors found when writing to sectors (Raw value). The higher the value, the worse the disk surface condition and/or mechanical subsystem is."); // Indilinx Barefoot SSD: Read_Commands_Tot_Ct (smartctl) (description?) - add(200, AtaStorageAttribute::DiskType::Ssd, "Read_Commands_Tot_Ct", "Total Read Commands Issued", "", + add(200, StorageDeviceDetectedType::AtaSsd, "Read_Commands_Tot_Ct", "Total Read Commands Issued", "", "Total count of read commands issued."); // Soft Read Error Rate (smartctl) (description?) - add(201, AtaStorageAttribute::DiskType::Hdd, "Soft_Read_Error_Rate", "Soft Read Error Rate", "attr_soft_read_error_rate", + add(201, StorageDeviceDetectedType::AtaHdd, "Soft_Read_Error_Rate", "Soft Read Error Rate", "attr_soft_read_error_rate", "Uncorrected read errors reported to the operating system (Raw value). If the value is non-zero, you should back up your data."); // Sandforce SSD: Unc_Soft_Read_Err_Rate (smartctl) - add(201, AtaStorageAttribute::DiskType::Ssd, "Unc_Soft_Read_Err_Rate"); + add(201, StorageDeviceDetectedType::AtaSsd, "Unc_Soft_Read_Err_Rate"); // Samsung SSD: (smartctl) (description?) - add(201, AtaStorageAttribute::DiskType::Ssd, "Supercap_Status", "Supercapacitor Health", "", + add(201, StorageDeviceDetectedType::AtaSsd, "Supercap_Status", "Supercapacitor Health", "", ""); // Maxtor: Off Track Errors (custom) -// add(201, AtaStorageAttribute::DiskType::Hdd, "", "Off Track Errors", "", // unused +// add(201, StorageDeviceDetectedType::AtaHdd, "", "Off Track Errors", "", // unused // ""); // Fujitsu: Detected TA Count (smartctl) (description?) - add(201, AtaStorageAttribute::DiskType::Hdd, "Detected_TA_Count", "Torque Amplification Count", "", + add(201, StorageDeviceDetectedType::AtaHdd, "Detected_TA_Count", "Torque Amplification Count", "", "Number of attempts to compensate for platter speed variations."); // Indilinx Barefoot SSD: Write_Commands_Tot_Ct (smartctl) (description?) - add(201, AtaStorageAttribute::DiskType::Ssd, "Write_Commands_Tot_Ct", "Total Write Commands Issued", "", + add(201, StorageDeviceDetectedType::AtaSsd, "Write_Commands_Tot_Ct", "Total Write Commands Issued", "", "Total count of write commands issued."); // WD: Data Address Mark Errors (smartctl) - add(202, AtaStorageAttribute::DiskType::Hdd, "Data_Address_Mark_Errs", "Data Address Mark Errors", "", + add(202, StorageDeviceDetectedType::AtaHdd, "Data_Address_Mark_Errs", "Data Address Mark Errors", "", "Frequency of the Data Address Mark errors."); // Fujitsu: TA Increase Count (same as 227?) - add(202, AtaStorageAttribute::DiskType::Hdd, "TA_Increase_Count", "TA Increase Count", "", + add(202, StorageDeviceDetectedType::AtaHdd, "TA_Increase_Count", "TA Increase Count", "", "Number of attempts to compensate for platter speed variations."); // Indilinx Barefoot SSD: Error_Bits_Flash_Tot_Ct (smartctl) (description?) - add(202, AtaStorageAttribute::DiskType::Ssd, "Error_Bits_Flash_Tot_Ct", "Total Count of Error Bits", "", + add(202, StorageDeviceDetectedType::AtaSsd, "Error_Bits_Flash_Tot_Ct", "Total Count of Error Bits", "", ""); // Crucial / Marvell SSD: Percent_Lifetime_Used (smartctl) (description?) - add(202, AtaStorageAttribute::DiskType::Ssd, "Percent_Lifetime_Used", "Rated Life Used (%)", "attr_ssd_life_used", + add(202, StorageDeviceDetectedType::AtaSsd, "Percent_Lifetime_Used", "Rated Life Used (%)", "attr_ssd_life_used", "Used drive life in %."); // Samsung SSD: (smartctl) (description?) - add(202, AtaStorageAttribute::DiskType::Ssd, "Exception_Mode_Status", "Exception Mode Status", "", + add(202, StorageDeviceDetectedType::AtaSsd, "Exception_Mode_Status", "Exception Mode Status", "", ""); // OCZ SSD (smartctl) (description?) - add(202, AtaStorageAttribute::DiskType::Ssd, "Total_Read_Bits_Corr_Ct", "Total Read Bits Corrected", "", + add(202, StorageDeviceDetectedType::AtaSsd, "Total_Read_Bits_Corr_Ct", "Total Read Bits Corrected", "", ""); // Micron SSD (smartctl) (description?) - add(202, AtaStorageAttribute::DiskType::Ssd, "Percent_Lifetime_Remain", "Remaining Lifetime (%)", "attr_ssd_life_left", + add(202, StorageDeviceDetectedType::AtaSsd, "Percent_Lifetime_Remain", "Remaining Lifetime (%)", "attr_ssd_life_left", "Remaining drive life in %."); // Run Out Cancel (smartctl). (description?) add(203, "Run_Out_Cancel", "Run Out Cancel", "", "Number of ECC errors."); // Maxtor: ECC Errors (smartctl) (description?) - add(203, AtaStorageAttribute::DiskType::Hdd, "Corr_Read_Errors_Tot_Ct", "ECC Errors", "", + add(203, StorageDeviceDetectedType::AtaHdd, "Corr_Read_Errors_Tot_Ct", "ECC Errors", "", "Number of ECC errors."); // Indilinx Barefoot SSD: Corr_Read_Errors_Tot_Ct (smartctl) (description?) - add(203, AtaStorageAttribute::DiskType::Ssd, "Corr_Read_Errors_Tot_Ct", "Total Corrected Read Errors", "", + add(203, StorageDeviceDetectedType::AtaSsd, "Corr_Read_Errors_Tot_Ct", "Total Corrected Read Errors", "", "Total cound of read sectors with correctable errors."); // Maxtor: Soft ECC Correction (smartctl) - add(204, AtaStorageAttribute::DiskType::Hdd, "Soft_ECC_Correction", "Soft ECC Correction", "", + add(204, StorageDeviceDetectedType::AtaHdd, "Soft_ECC_Correction", "Soft ECC Correction", "", "Number of errors corrected by software ECC (Error-Correcting Code)."); // Fujitsu: Shock_Count_Write_Opern (smartctl) (description?) - add(204, AtaStorageAttribute::DiskType::Hdd, "Shock_Count_Write_Opern", "Shock Count During Write Operation", "", + add(204, StorageDeviceDetectedType::AtaHdd, "Shock_Count_Write_Opern", "Shock Count During Write Operation", "", ""); // Sandforce SSD: Soft_ECC_Correct_Rate (smartctl) (description?) - add(204, AtaStorageAttribute::DiskType::Ssd, "Soft_ECC_Correct_Rate", "Soft ECC Correction Rate", "", + add(204, StorageDeviceDetectedType::AtaSsd, "Soft_ECC_Correct_Rate", "Soft ECC Correction Rate", "", ""); // Indilinx Barefoot SSD: Bad_Block_Full_Flag (smartctl) (description?) - add(204, AtaStorageAttribute::DiskType::Ssd, "Bad_Block_Full_Flag", "Bad Block Area Is Full", "", + add(204, StorageDeviceDetectedType::AtaSsd, "Bad_Block_Full_Flag", "Bad Block Area Is Full", "", "Indicates whether the bad block (reserved) area is full or not."); // Thermal Asperity Rate (TAR) (smartctl) add(205, "Thermal_Asperity_Rate", "Thermal Asperity Rate", "", "Number of problems caused by high temperature."); // Fujitsu: Shock_Rate_Write_Opern (smartctl) (description?) - add(205, AtaStorageAttribute::DiskType::Hdd, "Shock_Rate_Write_Opern", "Shock Rate During Write Operation", "", + add(205, StorageDeviceDetectedType::AtaHdd, "Shock_Rate_Write_Opern", "Shock Rate During Write Operation", "", ""); // Indilinx Barefoot SSD: Max_PE_Count_Spec (smartctl) (description?) - add(205, AtaStorageAttribute::DiskType::Ssd, "Max_PE_Count_Spec", "Maximum Program-Erase Count Specification", "", + add(205, StorageDeviceDetectedType::AtaSsd, "Max_PE_Count_Spec", "Maximum Program-Erase Count Specification", "", "Maximum Program / Erase cycle count as per specification."); // OCZ SSD (smartctl) - add(205, AtaStorageAttribute::DiskType::Ssd, "Max_Rated_PE_Count", "Maximum Rated Program-Erase Count", "", + add(205, StorageDeviceDetectedType::AtaSsd, "Max_Rated_PE_Count", "Maximum Rated Program-Erase Count", "", "Maximum Program / Erase cycle count as per specification."); // Flying Height (smartctl) - add(206, AtaStorageAttribute::DiskType::Hdd, "Flying_Height", "Head Flying Height", "", + add(206, StorageDeviceDetectedType::AtaHdd, "Flying_Height", "Head Flying Height", "", "The height of the disk heads above the disk surface. A downward trend will often predict a head crash, " "while high values may cause read / write errors."); // Indilinx Barefoot SSD, OCZ SSD: Min_Erase_Count (smartctl) (description?) - add(206, AtaStorageAttribute::DiskType::Ssd, "Min_Erase_Count", "Minimum Erase Count", "", + add(206, StorageDeviceDetectedType::AtaSsd, "Min_Erase_Count", "Minimum Erase Count", "", "The minimum of individual erase counts of all the blocks."); // Crucial / Marvell SSD: Write_Error_Rate (smartctl) (description?) - add(206, AtaStorageAttribute::DiskType::Ssd, "Write_Error_Rate", "Write Error Rate", "", + add(206, StorageDeviceDetectedType::AtaSsd, "Write_Error_Rate", "Write Error Rate", "", ""); // Spin High Current (smartctl) - add(207, AtaStorageAttribute::DiskType::Hdd, "Spin_High_Current", "Spin High Current", "", + add(207, StorageDeviceDetectedType::AtaHdd, "Spin_High_Current", "Spin High Current", "", "Amount of high current needed or used to spin up the drive."); // Indilinx Barefoot SSD, OCZ SSD: Max_Erase_Count (smartctl) (description?) - add(207, AtaStorageAttribute::DiskType::Ssd, "Max_Erase_Count", "Maximum Erase Count", "", + add(207, StorageDeviceDetectedType::AtaSsd, "Max_Erase_Count", "Maximum Erase Count", "", ""); // Spin Buzz (smartctl) - add(208, AtaStorageAttribute::DiskType::Hdd, "Spin_Buzz", "Spin Buzz", "", + add(208, StorageDeviceDetectedType::AtaHdd, "Spin_Buzz", "Spin Buzz", "", "Number of buzz routines (retries because of low current) to spin up the drive."); // Indilinx Barefoot SSD, OCZ SSD: Average_Erase_Count (smartctl) (description?) - add(208, AtaStorageAttribute::DiskType::Ssd, "Average_Erase_Count", "Average Erase Count", "", + add(208, StorageDeviceDetectedType::AtaSsd, "Average_Erase_Count", "Average Erase Count", "", "The average of individual erase counts of all the blocks."); // Offline Seek Performance (smartctl) (description?) - add(209, AtaStorageAttribute::DiskType::Hdd, "Offline_Seek_Performnce", "Offline Seek Performance", "", + add(209, StorageDeviceDetectedType::AtaHdd, "Offline_Seek_Performnce", "Offline Seek Performance", "", "Seek performance during Offline Data Collection operations."); // Indilinx Barefoot SSD, OCZ SSD: Remaining_Lifetime_Perc (smartctl) (description?) - add(209, AtaStorageAttribute::DiskType::Ssd, "Remaining_Lifetime_Perc", "Remaining Lifetime (%)", "attr_ssd_life_left", + add(209, StorageDeviceDetectedType::AtaSsd, "Remaining_Lifetime_Perc", "Remaining Lifetime (%)", "attr_ssd_life_left", "Remaining drive life in % (usually by erase count)."); // Vibration During Write (custom). wikipedia says 211, but it's wrong. (description?) - add(210, AtaStorageAttribute::DiskType::Hdd, "", "Vibration During Write", "", + add(210, StorageDeviceDetectedType::AtaHdd, "", "Vibration During Write", "", "Vibration encountered during write operations."); // OCZ SSD (smartctl) - add(210, AtaStorageAttribute::DiskType::Ssd, "SATA_CRC_Error_Count", "SATA CRC Error Count", "", + add(210, StorageDeviceDetectedType::AtaSsd, "SATA_CRC_Error_Count", "SATA CRC Error Count", "", ""); // Indilinx Barefoot SSD: Indilinx_Internal (smartctl) (description?) - add(210, AtaStorageAttribute::DiskType::Ssd, "Indilinx_Internal", "Internal Attribute", "", + add(210, StorageDeviceDetectedType::AtaSsd, "Indilinx_Internal", "Internal Attribute", "", "This attribute has been reserved by vendor as internal."); // Crucial / Micron SSD (smartctl) - add(210, AtaStorageAttribute::DiskType::Ssd, "Success_RAIN_Recov_Cnt", "Success RAIN Recovered Count", "", + add(210, StorageDeviceDetectedType::AtaSsd, "Success_RAIN_Recov_Cnt", "Success RAIN Recovered Count", "", ""); // Vibration During Read (description?) - add(211, AtaStorageAttribute::DiskType::Hdd, "", "Vibration During Read", "", + add(211, StorageDeviceDetectedType::AtaHdd, "", "Vibration During Read", "", "Vibration encountered during read operations."); // Indilinx Barefoot SSD (smartctl) (description?) - add(211, AtaStorageAttribute::DiskType::Ssd, "SATA_Error_Ct_CRC", "SATA CRC Error Count", "", + add(211, StorageDeviceDetectedType::AtaSsd, "SATA_Error_Ct_CRC", "SATA CRC Error Count", "", "Number of errors in data transfer via the SATA interface cable"); // OCZ SSD (smartctl) (description?) - add(211, AtaStorageAttribute::DiskType::Ssd, "SATA_UNC_Count", "SATA Uncorrectable Error Count", "", + add(211, StorageDeviceDetectedType::AtaSsd, "SATA_UNC_Count", "SATA Uncorrectable Error Count", "", "Number of errors in data transfer via the SATA interface cable"); // Shock During Write (custom) (description?) - add(212, AtaStorageAttribute::DiskType::Hdd, "", "Shock During Write", "", + add(212, StorageDeviceDetectedType::AtaHdd, "", "Shock During Write", "", "Shock encountered during write operations"); // Indilinx Barefoot SSD: SATA_Error_Ct_Handshake (smartctl) (description?) - add(212, AtaStorageAttribute::DiskType::Ssd, "SATA_Error_Ct_Handshake", "SATA Handshake Error Count", "", + add(212, StorageDeviceDetectedType::AtaSsd, "SATA_Error_Ct_Handshake", "SATA Handshake Error Count", "", "Number of errors occurring during SATA handshake."); // OCZ SSD (smartctl) (description?) - add(212, AtaStorageAttribute::DiskType::Ssd, "Pages_Requiring_Rd_Rtry", "Pages Requiring Read Retry", "", + add(212, StorageDeviceDetectedType::AtaSsd, "Pages_Requiring_Rd_Rtry", "Pages Requiring Read Retry", "", ""); // OCZ SSD (smartctl) (description?) - add(212, AtaStorageAttribute::DiskType::Ssd, "NAND_Reads_with_Retry", "Number of NAND Reads with Retry", "", + add(212, StorageDeviceDetectedType::AtaSsd, "NAND_Reads_with_Retry", "Number of NAND Reads with Retry", "", ""); // Sandisk SSDs: (smartctl) (description?) - add(212, AtaStorageAttribute::DiskType::Ssd, "SATA_PHY_Error", "SATA Physical Error Count", "", + add(212, StorageDeviceDetectedType::AtaSsd, "SATA_PHY_Error", "SATA Physical Error Count", "", ""); // Indilinx Barefoot SSD: Indilinx_Internal (smartctl) (description?) - add(213, AtaStorageAttribute::DiskType::Ssd, "Indilinx_Internal", "Internal Attribute", "", + add(213, StorageDeviceDetectedType::AtaSsd, "Indilinx_Internal", "Internal Attribute", "", "This attribute has been reserved by vendor as internal."); // OCZ SSD (smartctl) (description?) - add(213, AtaStorageAttribute::DiskType::Ssd, "Simple_Rd_Rtry_Attempts", "Simple Read Retry Attempts", "", + add(213, StorageDeviceDetectedType::AtaSsd, "Simple_Rd_Rtry_Attempts", "Simple Read Retry Attempts", "", ""); // OCZ SSD (smartctl) (description?) - add(213, AtaStorageAttribute::DiskType::Ssd, "Snmple_Retry_Attempts", "Simple Retry Attempts", "", + add(213, StorageDeviceDetectedType::AtaSsd, "Snmple_Retry_Attempts", "Simple Retry Attempts", "", ""); // OCZ SSD (smartctl) (description?) - add(213, AtaStorageAttribute::DiskType::Ssd, "Simple_Retry_Attempts", "Simple Retry Attempts", "", + add(213, StorageDeviceDetectedType::AtaSsd, "Simple_Retry_Attempts", "Simple Retry Attempts", "", ""); // OCZ SSD (smartctl) (description?) - add(213, AtaStorageAttribute::DiskType::Ssd, "Adaptv_Rd_Rtry_Attempts", "Adaptive Read Retry Attempts", "", + add(213, StorageDeviceDetectedType::AtaSsd, "Adaptv_Rd_Rtry_Attempts", "Adaptive Read Retry Attempts", "", ""); // OCZ SSD (smartctl) (description?) - add(214, AtaStorageAttribute::DiskType::Ssd, "Adaptive_Retry_Attempts", "Adaptive Retry Attempts", "", + add(214, StorageDeviceDetectedType::AtaSsd, "Adaptive_Retry_Attempts", "Adaptive Retry Attempts", "", ""); // Kingston SSD (smartctl) - add(218, AtaStorageAttribute::DiskType::Ssd, "CRC_Error_Count", "CRC Error Count", "", + add(218, StorageDeviceDetectedType::AtaSsd, "CRC_Error_Count", "CRC Error Count", "", ""); // Disk Shift (smartctl) // Note: There's also smartctl shortcut option "-v 220,temp" (possibly for Temperature Celsius), // but it's not used anywhere, so we ignore it. - add(220, AtaStorageAttribute::DiskType::Hdd, "Disk_Shift", "Disk Shift", "", + add(220, StorageDeviceDetectedType::AtaHdd, "Disk_Shift", "Disk Shift", "", "Shift of disks towards spindle. Shift of disks is possible as a result of a strong shock or a fall, high temperature, or some other reasons."); // G-sense error rate (smartctl) - add(221, AtaStorageAttribute::DiskType::Hdd, "G-Sense_Error_Rate", "G-Sense Error Rate", "", + add(221, StorageDeviceDetectedType::AtaHdd, "G-Sense_Error_Rate", "G-Sense Error Rate", "", "Number of errors resulting from externally-induced shock and vibration (Raw value). May indicate incorrect installation."); // OCZ SSD (smartctl) (description?) - add(213, AtaStorageAttribute::DiskType::Ssd, "Int_Data_Path_Prot_Unc", "Internal Data Path Protection Uncorrectable", "", + add(213, StorageDeviceDetectedType::AtaSsd, "Int_Data_Path_Prot_Unc", "Internal Data Path Protection Uncorrectable", "", ""); // Loaded Hours (smartctl) - add(222, AtaStorageAttribute::DiskType::Hdd, "Loaded_Hours", "Loaded Hours", "", + add(222, StorageDeviceDetectedType::AtaHdd, "Loaded_Hours", "Loaded Hours", "", "Number of hours spent operating under load (movement of magnetic head armature) (Raw value)"); // OCZ SSD (smartctl) (description?) - add(222, AtaStorageAttribute::DiskType::Ssd, "RAID_Recovery_Count", "RAID Recovery Count", "", + add(222, StorageDeviceDetectedType::AtaSsd, "RAID_Recovery_Count", "RAID Recovery Count", "", ""); // Load/Unload Retry Count (smartctl) (description?) - add(223, AtaStorageAttribute::DiskType::Hdd, "Load_Retry_Count", "Load / Unload Retry Count", "", + add(223, StorageDeviceDetectedType::AtaHdd, "Load_Retry_Count", "Load / Unload Retry Count", "", "Number of times the head armature entered / left the data zone."); // Load Friction (smartctl) - add(224, AtaStorageAttribute::DiskType::Hdd, "Load_Friction", "Load Friction", "", + add(224, StorageDeviceDetectedType::AtaHdd, "Load_Friction", "Load Friction", "", "Resistance caused by friction in mechanical parts while operating. An increase of Raw value may mean that there is " "a problem with the mechanical subsystem of the drive."); // OCZ SSD (smartctl) (description?) - add(224, AtaStorageAttribute::DiskType::Ssd, "In_Warranty", "In Warranty", "", + add(224, StorageDeviceDetectedType::AtaSsd, "In_Warranty", "In Warranty", "", ""); // Load/Unload Cycle Count (smartctl) (description?) - add(225, AtaStorageAttribute::DiskType::Hdd, "Load_Cycle_Count", "Load / Unload Cycle Count", "", + add(225, StorageDeviceDetectedType::AtaHdd, "Load_Cycle_Count", "Load / Unload Cycle Count", "", "Total number of load cycles."); // Intel SSD: Host_Writes_32MiB (smartctl) (description?) - add(225, AtaStorageAttribute::DiskType::Ssd, "Host_Writes_32MiB", "Host Written (32 MiB)", "", + add(225, StorageDeviceDetectedType::AtaSsd, "Host_Writes_32MiB", "Host Written (32 MiB)", "", "Total number of sectors written by the host system. The Raw value is increased by 1 for every 32 MiB written by the host."); // OCZ SSD (smartctl) (description?) - add(225, AtaStorageAttribute::DiskType::Ssd, "DAS_Polarity", "DAS Polarity", "", + add(225, StorageDeviceDetectedType::AtaSsd, "DAS_Polarity", "DAS Polarity", "", ""); // Innodisk SSDs: (smartctl) (description?) - add(225, AtaStorageAttribute::DiskType::Ssd, "Data_Log_Write_Count", "Data Log Write Count", "", + add(225, StorageDeviceDetectedType::AtaSsd, "Data_Log_Write_Count", "Data Log Write Count", "", ""); // Load-in Time (smartctl) - add(226, AtaStorageAttribute::DiskType::Hdd, "Load-in_Time", "Load-in Time", "", + add(226, StorageDeviceDetectedType::AtaHdd, "Load-in_Time", "Load-in Time", "", "Total time of loading on the magnetic heads actuator. Indicates total time in which the drive was under load " "(on the assumption that the magnetic heads were in operating mode and out of the parking area)."); // Intel SSD: Intel_Internal (smartctl) - add(226, AtaStorageAttribute::DiskType::Ssd, "Intel_Internal", "Internal Attribute", "", + add(226, StorageDeviceDetectedType::AtaSsd, "Intel_Internal", "Internal Attribute", "", "This attribute has been reserved by vendor as internal."); // Intel SSD: Workld_Media_Wear_Indic (smartctl) - add(226, AtaStorageAttribute::DiskType::Ssd, "Workld_Media_Wear_Indic", "Timed Workload Media Wear", "", + add(226, StorageDeviceDetectedType::AtaSsd, "Workld_Media_Wear_Indic", "Timed Workload Media Wear", "", "Timed workload media wear indicator (percent*1024)"); // OCZ SSD (smartctl) (description?) - add(226, AtaStorageAttribute::DiskType::Ssd, "Partial_Pfail", "Partial Program Fail", "", + add(226, StorageDeviceDetectedType::AtaSsd, "Partial_Pfail", "Partial Program Fail", "", ""); // Torque Amplification Count (aka TA) (smartctl) - add(227, AtaStorageAttribute::DiskType::Hdd, "Torq-amp_Count", "Torque Amplification Count", "", + add(227, StorageDeviceDetectedType::AtaHdd, "Torq-amp_Count", "Torque Amplification Count", "", "Number of attempts to compensate for platter speed variations."); // Intel SSD: Intel_Internal (smartctl) - add(227, AtaStorageAttribute::DiskType::Ssd, "Intel_Internal", "Internal Attribute", "", + add(227, StorageDeviceDetectedType::AtaSsd, "Intel_Internal", "Internal Attribute", "", "This attribute has been reserved by vendor as internal."); // Intel SSD: Workld_Host_Reads_Perc (smartctl) - add(227, AtaStorageAttribute::DiskType::Ssd, "Workld_Host_Reads_Perc", "Timed Workload Host Reads %", "", + add(227, StorageDeviceDetectedType::AtaSsd, "Workld_Host_Reads_Perc", "Timed Workload Host Reads %", "", ""); // Power-Off Retract Count (smartctl) add(228, "Power-off_Retract_Count", "Power-Off Retract Count", "", "Number of times the magnetic armature was retracted automatically as a result of power loss."); // Intel SSD: Intel_Internal (smartctl) - add(228, AtaStorageAttribute::DiskType::Ssd, "Intel_Internal", "Internal Attribute", "", + add(228, StorageDeviceDetectedType::AtaSsd, "Intel_Internal", "Internal Attribute", "", "This attribute has been reserved by vendor as internal."); // Intel SSD: Workload_Minutes (smartctl) - add(228, AtaStorageAttribute::DiskType::Ssd, "Workload_Minutes", "Workload (Minutes)", "", + add(228, StorageDeviceDetectedType::AtaSsd, "Workload_Minutes", "Workload (Minutes)", "", ""); // Transcend SSD: Halt_System_ID (smartctl) (description?) - add(229, AtaStorageAttribute::DiskType::Ssd, "Halt_System_ID", "Halt System ID", "", + add(229, StorageDeviceDetectedType::AtaSsd, "Halt_System_ID", "Halt System ID", "", "Halt system ID and flash ID"); // InnoDisk SSD (smartctl) - add(229, AtaStorageAttribute::DiskType::Ssd, "Flash_ID", "Flash ID", "", + add(229, StorageDeviceDetectedType::AtaSsd, "Flash_ID", "Flash ID", "", "Flash ID"); // IBM: GMR Head Amplitude (smartctl) - add(230, AtaStorageAttribute::DiskType::Hdd, "Head_Amplitude", "GMR Head Amplitude", "", + add(230, StorageDeviceDetectedType::AtaHdd, "Head_Amplitude", "GMR Head Amplitude", "", "Amplitude of heads trembling (GMR-head) in running mode."); // Sandforce SSD: Life_Curve_Status (smartctl) (description?) - add(230, AtaStorageAttribute::DiskType::Ssd, "Life_Curve_Status", "Life Curve Status", "", + add(230, StorageDeviceDetectedType::AtaSsd, "Life_Curve_Status", "Life Curve Status", "", "Current state of drive operation based upon the Life Curve."); // OCZ SSD (smartctl) (description?) - add(230, AtaStorageAttribute::DiskType::Ssd, "SuperCap_Charge_Status", "Super-Capacitor Charge Status", "", + add(230, StorageDeviceDetectedType::AtaSsd, "SuperCap_Charge_Status", "Super-Capacitor Charge Status", "", "0 means not charged, 1 - fully charged, 2 - unknown."); // OCZ SSD (smartctl) (description?) - add(230, AtaStorageAttribute::DiskType::Ssd, "Write_Throttling", "Write Throttling", "", + add(230, StorageDeviceDetectedType::AtaSsd, "Write_Throttling", "Write Throttling", "", ""); // Sandisk SSD (smartctl) (description?) - add(230, AtaStorageAttribute::DiskType::Ssd, "Perc_Write/Erase_Count", "Write / Erase Count (%)", "", + add(230, StorageDeviceDetectedType::AtaSsd, "Perc_Write/Erase_Count", "Write / Erase Count (%)", "", ""); // Temperature (Some drives) (smartctl) add(231, "Temperature_Celsius", "Temperature", "attr_temperature_celsius", "Drive temperature. The Raw value shows built-in heat sensor registrations (in Celsius). " "Increases in average drive temperature often signal spindle motor problems (unless the increases are caused by environmental factors)."); // Sandforce SSD: SSD_Life_Left - add(231, AtaStorageAttribute::DiskType::Ssd, "SSD_Life_Left", "SSD Life Left", "attr_ssd_life_left", + add(231, StorageDeviceDetectedType::AtaSsd, "SSD_Life_Left", "SSD Life Left", "attr_ssd_life_left", "A measure of drive's estimated life left. A Normalized value of 100 indicates a new drive. " "10 means there are reserved blocks left but Program / Erase cycles have been used. " "0 means insufficient reserved blocks, drive may be in read-only mode to allow recovery of the data."); // Intel SSD: Available_Reservd_Space (smartctl) (description?) - add(232, AtaStorageAttribute::DiskType::Ssd, "Available_Reservd_Space", "Available reserved space", "", + add(232, StorageDeviceDetectedType::AtaSsd, "Available_Reservd_Space", "Available reserved space", "", "Number of reserved blocks remaining. The Normalized value indicates percentage, with 100 meaning new and 10 meaning the drive being close to its end of life."); // Transcend SSD: Firmware_Version_information (smartctl) (description?) - add(232, AtaStorageAttribute::DiskType::Ssd, "Firmware_Version_Info", "Firmware Version Information", "", + add(232, StorageDeviceDetectedType::AtaSsd, "Firmware_Version_Info", "Firmware Version Information", "", "Firmware version information (year, month, day, channels, banks)."); // Same as Firmware_Version_Info, but in older smartctl versions. - add(232, AtaStorageAttribute::DiskType::Ssd, "Firmware_Version_information", "Firmware Version Information", "", + add(232, StorageDeviceDetectedType::AtaSsd, "Firmware_Version_information", "Firmware Version Information", "", "Firmware version information (year, month, day, channels, banks)."); // OCZ SSD (description?) (smartctl) - add(232, AtaStorageAttribute::DiskType::Ssd, "Lifetime_Writes", "Lifetime_Writes", "", + add(232, StorageDeviceDetectedType::AtaSsd, "Lifetime_Writes", "Lifetime_Writes", "", ""); // Kingston SSD (description?) (smartctl) - add(232, AtaStorageAttribute::DiskType::Ssd, "Flash_Writes_GiB", "Flash Written (GiB)", "", + add(232, StorageDeviceDetectedType::AtaSsd, "Flash_Writes_GiB", "Flash Written (GiB)", "", ""); // Innodisk SSD (description?) (smartctl) - add(232, AtaStorageAttribute::DiskType::Ssd, "Spares_Remaining_Perc", "Spare Blocks Remaining (%)", "attr_ssd_life_left", + add(232, StorageDeviceDetectedType::AtaSsd, "Spares_Remaining_Perc", "Spare Blocks Remaining (%)", "attr_ssd_life_left", "Percentage of spare blocks remaining. Spare blocks are used when bad blocks develop."); // Innodisk SSD (description?) (smartctl) - add(232, AtaStorageAttribute::DiskType::Ssd, "Perc_Avail_Resrvd_Space", "Available Reserved Space (%)", "attr_ssd_life_left", + add(232, StorageDeviceDetectedType::AtaSsd, "Perc_Avail_Resrvd_Space", "Available Reserved Space (%)", "attr_ssd_life_left", "Percentage of spare blocks remaining. Spare blocks are used when bad blocks develop."); // Intel SSD: Media_Wearout_Indicator (smartctl) (description?) - add(233, AtaStorageAttribute::DiskType::Ssd, "Media_Wearout_Indicator", "Media Wear Out Indicator", "attr_ssd_life_left", + add(233, StorageDeviceDetectedType::AtaSsd, "Media_Wearout_Indicator", "Media Wear Out Indicator", "attr_ssd_life_left", "Number of cycles the NAND media has experienced. The Normalized value decreases linearly from 100 to 1 as the average erase cycle " "count increases from 0 to the maximum rated cycles."); // OCZ SSD - add(233, AtaStorageAttribute::DiskType::Ssd, "Remaining_Lifetime_Perc", "Remaining Lifetime %", "attr_ssd_life_left", + add(233, StorageDeviceDetectedType::AtaSsd, "Remaining_Lifetime_Perc", "Remaining Lifetime %", "attr_ssd_life_left", "Remaining drive life in % (usually by erase count)."); // Sandforce SSD: SandForce_Internal (smartctl) (description?) - add(233, AtaStorageAttribute::DiskType::Ssd, "SandForce_Internal", "Internal Attribute", "", + add(233, StorageDeviceDetectedType::AtaSsd, "SandForce_Internal", "Internal Attribute", "", "This attribute has been reserved by vendor as internal."); // Transcend SSD: ECC_Fail_Record (smartctl) (description?) - add(233, AtaStorageAttribute::DiskType::Ssd, "ECC_Fail_Record", "ECC Failure Record", "", + add(233, StorageDeviceDetectedType::AtaSsd, "ECC_Fail_Record", "ECC Failure Record", "", "Indicates rate of ECC (error-correcting code) failures."); // Innodisk SSD (smartctl) (description?) - add(233, AtaStorageAttribute::DiskType::Ssd, "Flash_Writes_32MiB", "Flash Written (32MiB)", "", + add(233, StorageDeviceDetectedType::AtaSsd, "Flash_Writes_32MiB", "Flash Written (32MiB)", "", ""); // Innodisk SSD (smartctl) (description?) - add(233, AtaStorageAttribute::DiskType::Ssd, "Total_NAND_Writes_GiB", "Total NAND Written (GiB)", "", + add(233, StorageDeviceDetectedType::AtaSsd, "Total_NAND_Writes_GiB", "Total NAND Written (GiB)", "", ""); // Sandforce SSD: SandForce_Internal (smartctl) (description?) - add(234, AtaStorageAttribute::DiskType::Ssd, "SandForce_Internal", "Internal Attribute", "", + add(234, StorageDeviceDetectedType::AtaSsd, "SandForce_Internal", "Internal Attribute", "", "This attribute has been reserved by vendor as internal."); // Intel SSD (smartctl) - add(234, AtaStorageAttribute::DiskType::Ssd, "Thermal_Throttle", "Thermal Throttle", "", + add(234, StorageDeviceDetectedType::AtaSsd, "Thermal_Throttle", "Thermal Throttle", "", ""); // Transcend SSD: Erase_Count_Avg (smartctl) (description?) - add(234, AtaStorageAttribute::DiskType::Ssd, "Erase_Count_Avg/Max", "Erase Count Average / Maximum", "", + add(234, StorageDeviceDetectedType::AtaSsd, "Erase_Count_Avg/Max", "Erase Count Average / Maximum", "", ""); // Innodisk SSD (smartctl) (description?) - add(234, AtaStorageAttribute::DiskType::Ssd, "Flash_Reads_32MiB", "Flash Read (32MiB)", "", + add(234, StorageDeviceDetectedType::AtaSsd, "Flash_Reads_32MiB", "Flash Read (32MiB)", "", ""); // Sandisk SSD (smartctl) (description / name?) - add(234, AtaStorageAttribute::DiskType::Ssd, "Perc_Write/Erase_Ct_BC", "Write / Erase Count BC (%)", "", + add(234, StorageDeviceDetectedType::AtaSsd, "Perc_Write/Erase_Ct_BC", "Write / Erase Count BC (%)", "", ""); // Sandforce SSD: SuperCap_Health (smartctl) (description?) - add(235, AtaStorageAttribute::DiskType::Ssd, "SuperCap_Health", "Supercapacitor Health", "", + add(235, StorageDeviceDetectedType::AtaSsd, "SuperCap_Health", "Supercapacitor Health", "", ""); // Transcend SSD: Block_Count_Good/System (smartctl) (description?) - add(235, AtaStorageAttribute::DiskType::Ssd, "Block_Count_Good/System", "Good / System Free Block Count", "", + add(235, StorageDeviceDetectedType::AtaSsd, "Block_Count_Good/System", "Good / System Free Block Count", "", "Good block count and system free block count."); // InnoDisk SSD (smartctl). (description / name?) - add(235, AtaStorageAttribute::DiskType::Ssd, "Later_Bad_Block", "Later Bad Block", "", + add(235, StorageDeviceDetectedType::AtaSsd, "Later_Bad_Block", "Later Bad Block", "", ""); // InnoDisk SSD (smartctl). (description / name?) - add(235, AtaStorageAttribute::DiskType::Ssd, "Later_Bad_Blk_Inf_R/W/E", "Later Bad Block Read / Write / Erase", "", + add(235, StorageDeviceDetectedType::AtaSsd, "Later_Bad_Blk_Inf_R/W/E", "Later Bad Block Read / Write / Erase", "", ""); // Samsung SSD (smartctl). (description / name?) - add(235, AtaStorageAttribute::DiskType::Ssd, "POR_Recovery_Count", "POR Recovery Count", "", + add(235, StorageDeviceDetectedType::AtaSsd, "POR_Recovery_Count", "POR Recovery Count", "", ""); // InnoDisk SSD (smartctl). (description / name?) - add(236, AtaStorageAttribute::DiskType::Ssd, "Unstable_Power_Count", "Unstable Power Count", "", + add(236, StorageDeviceDetectedType::AtaSsd, "Unstable_Power_Count", "Unstable Power Count", "", ""); // Head Flying Hours (smartctl) - add(240, AtaStorageAttribute::DiskType::Hdd, "Head_Flying_Hours", "Head Flying Hours", "", + add(240, StorageDeviceDetectedType::AtaHdd, "Head_Flying_Hours", "Head Flying Hours", "", "Time spent on head is positioning."); // Fujitsu: Transfer_Error_Rate (smartctl) (description?) - add(240, AtaStorageAttribute::DiskType::Hdd, "Transfer_Error_Rate", "Transfer Error Rate", "", + add(240, StorageDeviceDetectedType::AtaHdd, "Transfer_Error_Rate", "Transfer Error Rate", "", ""); // InnoDisk SSD (smartctl). (description / name?) - add(240, AtaStorageAttribute::DiskType::Ssd, "Write_Head", "Write Head", "", + add(240, StorageDeviceDetectedType::AtaSsd, "Write_Head", "Write Head", "", ""); // Total_LBAs_Written (smartctl) (description?) add(241, "Total_LBAs_Written", "Total LBAs Written", "", "Logical blocks written during lifetime."); // Sandforce SSD: Lifetime_Writes_GiB (smartctl) (maybe in 64GiB increments?) - add(241, AtaStorageAttribute::DiskType::Ssd, "Lifetime_Writes_GiB", "Total GiB Written", "", + add(241, StorageDeviceDetectedType::AtaSsd, "Lifetime_Writes_GiB", "Total GiB Written", "", "Total GiB written during lifetime."); // Intel SSD: Host_Writes_32MiB (smartctl) (description?) - add(241, AtaStorageAttribute::DiskType::Ssd, "Host_Writes_32MiB", "Host Written (32 MiB)", "", + add(241, StorageDeviceDetectedType::AtaSsd, "Host_Writes_32MiB", "Host Written (32 MiB)", "", "Total number of sectors written by the host system. The Raw value is increased by 1 for every 32 MiB written by the host."); // OCZ SSD (smartctl) - add(241, AtaStorageAttribute::DiskType::Ssd, "Host_Writes_GiB", "Host Written (GiB)", "", + add(241, StorageDeviceDetectedType::AtaSsd, "Host_Writes_GiB", "Host Written (GiB)", "", "Total number of sectors written by the host system. The Raw value is increased by 1 for every GiB written by the host."); // Sandisk SSD (smartctl) - add(241, AtaStorageAttribute::DiskType::Ssd, "Total_Writes_GiB", "Total Written (GiB)", "", + add(241, StorageDeviceDetectedType::AtaSsd, "Total_Writes_GiB", "Total Written (GiB)", "", "Total GiB written."); // Toshiba SSD (smartctl) - add(241, AtaStorageAttribute::DiskType::Ssd, "Host_Writes", "Host Written", "", + add(241, StorageDeviceDetectedType::AtaSsd, "Host_Writes", "Host Written", "", "Total number of sectors written by the host system."); // Total_LBAs_Read (smartctl) (description?) add(242, "Total_LBAs_Read", "Total LBAs Read", "", "Logical blocks read during lifetime."); // Sandforce SSD: Lifetime_Writes_GiB (smartctl) (maybe in 64GiB increments?) - add(242, AtaStorageAttribute::DiskType::Ssd, "Lifetime_Reads_GiB", "Total GiB Read", "", + add(242, StorageDeviceDetectedType::AtaSsd, "Lifetime_Reads_GiB", "Total GiB Read", "", "Total GiB read during lifetime."); // Intel SSD: Host_Reads_32MiB (smartctl) (description?) - add(242, AtaStorageAttribute::DiskType::Ssd, "Host_Reads_32MiB", "Host Read (32 MiB)", "", + add(242, StorageDeviceDetectedType::AtaSsd, "Host_Reads_32MiB", "Host Read (32 MiB)", "", "Total number of sectors read by the host system. The Raw value is increased by 1 for every 32 MiB read by the host."); // OCZ SSD (smartctl) - add(242, AtaStorageAttribute::DiskType::Ssd, "Host_Reads_GiB", "Host Read (GiB)", "", + add(242, StorageDeviceDetectedType::AtaSsd, "Host_Reads_GiB", "Host Read (GiB)", "", "Total number of sectors read by the host system. The Raw value is increased by 1 for every GiB read by the host."); // Marvell SSD (smartctl) - add(242, AtaStorageAttribute::DiskType::Ssd, "Host_Reads", "Host Read", "", + add(242, StorageDeviceDetectedType::AtaSsd, "Host_Reads", "Host Read", "", ""); // Sandisk SSD (smartctl) - add(241, AtaStorageAttribute::DiskType::Ssd, "Total_Reads_GiB", "Total Read (GiB)", "", + add(241, StorageDeviceDetectedType::AtaSsd, "Total_Reads_GiB", "Total Read (GiB)", "", "Total GiB read."); // Intel SSD: (smartctl) (description?) - add(243, AtaStorageAttribute::DiskType::Ssd, "NAND_Writes_32MiB", "NAND Written (32MiB)", "", + add(243, StorageDeviceDetectedType::AtaSsd, "NAND_Writes_32MiB", "NAND Written (32MiB)", "", ""); // Samsung SSD (smartctl). (description / name?) - add(243, AtaStorageAttribute::DiskType::Ssd, "SATA_Downshift_Ct", "SATA Downshift Count", "", + add(243, StorageDeviceDetectedType::AtaSsd, "SATA_Downshift_Ct", "SATA Downshift Count", "", ""); // Kingston SSDs (description?) (smartctl) - add(244, AtaStorageAttribute::DiskType::Ssd, "Average_Erase_Count", "Average Erase Count", "", + add(244, StorageDeviceDetectedType::AtaSsd, "Average_Erase_Count", "Average Erase Count", "", "The average of individual erase counts of all the blocks"); // Samsung SSDs (description?) (smartctl) - add(244, AtaStorageAttribute::DiskType::Ssd, "Thermal_Throttle_St", "Thermal Throttle Status", "", + add(244, StorageDeviceDetectedType::AtaSsd, "Thermal_Throttle_St", "Thermal Throttle Status", "", ""); // Sandisk SSDs (description?) (smartctl) - add(244, AtaStorageAttribute::DiskType::Ssd, "Thermal_Throttle", "Thermal Throttle Status", "", + add(244, StorageDeviceDetectedType::AtaSsd, "Thermal_Throttle", "Thermal Throttle Status", "", ""); // Kingston SSDs (smartctl) - add(245, AtaStorageAttribute::DiskType::Ssd, "Max_Erase_Count", "Maximum Erase Count", "", + add(245, StorageDeviceDetectedType::AtaSsd, "Max_Erase_Count", "Maximum Erase Count", "", "The maximum of individual erase counts of all the blocks."); // Innodisk SSD (smartctl) (description?) - add(245, AtaStorageAttribute::DiskType::Ssd, "Flash_Writes_32MiB", "Flash Written (32MiB)", "", + add(245, StorageDeviceDetectedType::AtaSsd, "Flash_Writes_32MiB", "Flash Written (32MiB)", "", ""); // Samsung SSD (smartctl) (description?) - add(245, AtaStorageAttribute::DiskType::Ssd, "Timed_Workld_Media_Wear", "Timed Workload Media Wear", "", + add(245, StorageDeviceDetectedType::AtaSsd, "Timed_Workld_Media_Wear", "Timed Workload Media Wear", "", ""); // SiliconMotion SSD (smartctl) (description?) - add(245, AtaStorageAttribute::DiskType::Ssd, "TLC_Writes_32MiB", "TLC Written (32MiB)", "", + add(245, StorageDeviceDetectedType::AtaSsd, "TLC_Writes_32MiB", "TLC Written (32MiB)", "", "Total number of sectors written to TLC. The Raw value is increased by 1 for every 32 MiB written by the host."); // Crucial / Micron SSD (smartctl) - add(246, AtaStorageAttribute::DiskType::Ssd, "Total_Host_Sector_Write", "Total Host Sectors Written", "", + add(246, StorageDeviceDetectedType::AtaSsd, "Total_Host_Sector_Write", "Total Host Sectors Written", "", "Total number of sectors written by the host system."); // Kingston SSDs (description?) (smartctl) - add(246, AtaStorageAttribute::DiskType::Ssd, "Total_Erase_Count", "Total Erase Count", "", + add(246, StorageDeviceDetectedType::AtaSsd, "Total_Erase_Count", "Total Erase Count", "", ""); // Samsung SSD (smartctl) (description?) - add(246, AtaStorageAttribute::DiskType::Ssd, "Timed_Workld_RdWr_Ratio", "Timed Workload Read/Write Ratio", "", + add(246, StorageDeviceDetectedType::AtaSsd, "Timed_Workld_RdWr_Ratio", "Timed Workload Read/Write Ratio", "", ""); // SiliconMotion SSD (smartctl) (description?) - add(246, AtaStorageAttribute::DiskType::Ssd, "SLC_Writes_32MiB", "SLC Written (32MiB)", "", + add(246, StorageDeviceDetectedType::AtaSsd, "SLC_Writes_32MiB", "SLC Written (32MiB)", "", "Total number of sectors written to SLC. The Raw value is increased by 1 for every 32 MiB written by the host."); // Crucial / Micron SSD (smartctl) - add(247, AtaStorageAttribute::DiskType::Ssd, "Host_Program_Page_Count", "Host Program Page Count", "", + add(247, StorageDeviceDetectedType::AtaSsd, "Host_Program_Page_Count", "Host Program Page Count", "", ""); // Samsung SSD (smartctl) - add(247, AtaStorageAttribute::DiskType::Ssd, "Timed_Workld_Timer", "Timed Workload Timer", "", + add(247, StorageDeviceDetectedType::AtaSsd, "Timed_Workld_Timer", "Timed Workload Timer", "", ""); // SiliconMotion SSD (smartctl) (description?) - add(247, AtaStorageAttribute::DiskType::Ssd, "Raid_Recoverty_Ct", "RAID Recovery Count", "", + add(247, StorageDeviceDetectedType::AtaSsd, "Raid_Recoverty_Ct", "RAID Recovery Count", "", ""); - add(248, AtaStorageAttribute::DiskType::Ssd, "Bckgnd_Program_Page_Cnt", "Background Program Page Count", "", + add(248, StorageDeviceDetectedType::AtaSsd, "Bckgnd_Program_Page_Cnt", "Background Program Page Count", "", ""); // Intel SSD: NAND_Writes_1GiB (smartctl) (description?) - add(249, AtaStorageAttribute::DiskType::Ssd, "NAND_Writes_1GiB", "NAND Written (1GiB)", "", + add(249, StorageDeviceDetectedType::AtaSsd, "NAND_Writes_1GiB", "NAND Written (1GiB)", "", ""); // OCZ SSD: Total_NAND_Prog_Ct_GiB (smartctl) (description?) - add(249, AtaStorageAttribute::DiskType::Ssd, "Total_NAND_Prog_Ct_GiB", "Total NAND Written (1GiB)", "", + add(249, StorageDeviceDetectedType::AtaSsd, "Total_NAND_Prog_Ct_GiB", "Total NAND Written (1GiB)", "", ""); // Read Error Retry Rate (smartctl) (description?) add(250, "Read_Error_Retry_Rate", "Read Error Retry Rate", "", "Number of errors found while reading."); // Samsung SSD: (smartctl) (description?) - add(183, AtaStorageAttribute::DiskType::Any, "SATA_Iface_Downshift", "SATA Downshift Error Count", "", + add(183, std::nullopt, "SATA_Iface_Downshift", "SATA Downshift Error Count", "", ""); // OCZ SSD (smartctl) (description?) - add(251, AtaStorageAttribute::DiskType::Ssd, "Total_NAND_Read_Ct_GiB", "Total NAND Read (1GiB)", "", + add(251, StorageDeviceDetectedType::AtaSsd, "Total_NAND_Read_Ct_GiB", "Total NAND Read (1GiB)", "", ""); // Samsung SSD: (smartctl) (description?) - add(251, AtaStorageAttribute::DiskType::Any, "NAND_Writes", "NAND Write Count", "", + add(251, std::nullopt, "NAND_Writes", "NAND Write Count", "", ""); // Free Fall Protection (smartctl) (seagate laptop drives) - add(254, AtaStorageAttribute::DiskType::Hdd, "Free_Fall_Sensor", "Free Fall Protection", "", + add(254, StorageDeviceDetectedType::AtaHdd, "Free_Fall_Sensor", "Free Fall Protection", "", "Number of free fall events detected by accelerometer sensor."); } @@ -1066,7 +1066,7 @@ namespace { void add(int32_t id, std::string reported_name, std::string displayable_name, std::string generic_name, std::string description) { - add(AttributeDescription(id, AtaStorageAttribute::DiskType::Any, + add(AttributeDescription(id, std::nullopt, std::move(reported_name), std::move(displayable_name), std::move(generic_name), std::move(description))); } @@ -1079,12 +1079,12 @@ namespace { // DBG_ASSERT(iter != id_db.end() && !iter->second.empty()); // if (iter != id_db.end() || iter->second.empty()) { // AttributeDescription attr = iter->second.front(); -// add(AttributeDescription(id, AtaStorageAttribute::DiskType::Any, reported_name, attr.displayable_name, attr.generic_name, attr.description)); +// add(AttributeDescription(id, std::nullopt, reported_name, attr.displayable_name, attr.generic_name, attr.description)); // } // } /// Add an attribute description to the attribute database - void add(int32_t id, AtaStorageAttribute::DiskType type, std::string reported_name, std::string displayable_name, + void add(int32_t id, std::optional type, std::string reported_name, std::string displayable_name, std::string generic_name, std::string description) { add(AttributeDescription(id, type, std::move(reported_name), std::move(displayable_name), std::move(generic_name), std::move(description))); @@ -1093,7 +1093,7 @@ namespace { /// Add a previously added description to the attribute database under a /// different smartctl name (fill the other members from the previous attribute). - void add(int32_t id, AtaStorageAttribute::DiskType type, std::string reported_name) + void add(int32_t id, std::optional type, std::string reported_name) { auto iter = id_db.find(id); DBG_ASSERT(iter != id_db.end() && !iter->second.empty()); @@ -1106,7 +1106,7 @@ namespace { /// Find the description by smartctl name or id, merging them if they're partial. - [[nodiscard]] AttributeDescription find(const std::string& reported_name, int32_t id, AtaStorageAttribute::DiskType type) const + [[nodiscard]] AttributeDescription find(const std::string& reported_name, int32_t id, std::optional type) const { // search by ID first auto id_iter = id_db.find(id); @@ -1120,7 +1120,7 @@ namespace { std::vector type_matched; for (const auto& attr_iter : id_iter->second) { - if (attr_iter.disk_type == type || attr_iter.disk_type == AtaStorageAttribute::DiskType::Any || type == AtaStorageAttribute::DiskType::Any) { + if (!attr_iter.drive_type.has_value() || !type.has_value() || attr_iter.drive_type == type) { type_matched.push_back(attr_iter); } } @@ -1428,9 +1428,9 @@ namespace { /// Find a property's attribute in the attribute database and fill the property /// with all the readable information we can gather. - inline void auto_set_attr(AtaStorageProperty& p, AtaStorageAttribute::DiskType disk_type) + inline void auto_set_attr(AtaStorageProperty& p, StorageDeviceDetectedType drive_type) { - AttributeDescription attr = get_attribute_db().find(p.reported_name, p.get_value().id, disk_type); + AttributeDescription attr = get_attribute_db().find(p.reported_name, p.get_value().id, drive_type); std::string humanized_reported_name; std::string ssd_hdd_str; @@ -1560,7 +1560,7 @@ namespace { -bool ata_storage_property_autoset_description(AtaStorageProperty& p, AtaStorageAttribute::DiskType disk_type) +bool ata_storage_property_autoset_description(AtaStorageProperty& p, StorageDeviceDetectedType device_type) { bool found = false; @@ -1581,8 +1581,8 @@ bool ata_storage_property_autoset_description(AtaStorageProperty& p, AtaStorageA || auto_set(p, "user_capacity/bytes", "User-serviceable drive capacity as reported to an operating system") || auto_set(p, "in_smartctl_database", "Whether the device is in smartctl database or not. " "If it is, additional information may be provided; otherwise, Raw values of some attributes may be incorrectly formatted.") - || auto_set(p, "_custom/smart_supported", "Whether the device supports SMART. If not, then only very limited information will be available.") - || auto_set(p, "_custom/smart_enabled", "Whether the device has SMART enabled. If not, most of the reported values will be incorrect.") + || auto_set(p, "smart_support/available", "Whether the device supports SMART. If not, then only very limited information will be available.") + || auto_set(p, "smart_support/enabled", "Whether the device has SMART enabled. If not, most of the reported values will be incorrect.") || auto_set(p, "ata_aam/enabled", "Automatic Acoustic Management (AAM) feature") || auto_set(p, "ata_aam/level", "Automatic Acoustic Management (AAM) level") || auto_set(p, "ata_apm/enabled", "Automatic Power Management (APM) feature") @@ -1621,7 +1621,7 @@ bool ata_storage_property_autoset_description(AtaStorageProperty& p, AtaStorageA case AtaStorageProperty::Section::Attributes: found = auto_set(p, "ata_smart_attributes/revision", p.displayable_name.c_str()); if (!found) { - auto_set_attr(p, disk_type); + auto_set_attr(p, device_type); found = true; // true, because auto_set_attr() may set "Unknown attribute", which is still "found". } break; @@ -1636,7 +1636,7 @@ bool ata_storage_property_autoset_description(AtaStorageProperty& p, AtaStorageA "(e.g., command invalid, not implemented, etc.)."); // || auto_set(p, "error_log_unsupported", "This device does not support error logging."); // the property text already says that if (p.is_value_type()) { - for (size_t i = 0; i < p.get_value().reported_types.size(); ++i) { + for (std::size_t i = 0; i < p.get_value().reported_types.size(); ++i) { p.set_description(AtaStorageErrorBlock::format_readable_error_types( p.get_value().reported_types)); found = true; @@ -1689,11 +1689,11 @@ WarningLevel ata_storage_property_autoset_warning(AtaStorageProperty& p) } else { switch (p.section) { case AtaStorageProperty::Section::Info: - if (name_match(p, "_custom/smart_supported") && !p.get_value()) { + if (name_match(p, "smart_support/available") && !p.get_value()) { w = WarningLevel::Notice; reason = "SMART is not supported. You won't be able to read any SMART information from this drive."; - } else if (name_match(p, "_custom/smart_enabled") && !p.get_value()) { + } else if (name_match(p, "smart_support/enabled") && !p.get_value()) { w = WarningLevel::Notice; reason = "SMART is disabled. You should enable it to read any SMART information from this drive. " "Additionally, some drives do not log useful data with SMART disabled, so it's advisable to keep it always enabled."; @@ -1983,10 +1983,10 @@ WarningLevel ata_storage_property_autoset_warning(AtaStorageProperty& p) StoragePropertyRepository StoragePropertyProcessor::process_properties( - StoragePropertyRepository properties, AtaStorageAttribute::DiskType disk_type) + StoragePropertyRepository properties, StorageDeviceDetectedType device_type) { for (auto& p : properties.get_properties_ref()) { - ata_storage_property_autoset_description(p, disk_type); + ata_storage_property_autoset_description(p, device_type); ata_storage_property_autoset_warning(p); storage_property_autoset_warning_descr(p); // append warning to description } diff --git a/src/applib/ata_storage_property_descr.h b/src/applib/ata_storage_property_descr.h index 054579d..ccdc92a 100644 --- a/src/applib/ata_storage_property_descr.h +++ b/src/applib/ata_storage_property_descr.h @@ -13,6 +13,10 @@ Copyright: #define ATA_STORAGE_PROPERTY_DESCR_H #include "storage_property_repository.h" +#include "storage_device_detected_type.h" + + + class StoragePropertyProcessor { @@ -20,7 +24,7 @@ class StoragePropertyProcessor { /// Set descriptions, warnings, etc. on properties, and return them. static StoragePropertyRepository process_properties(StoragePropertyRepository properties, - AtaStorageAttribute::DiskType disk_type); + StorageDeviceDetectedType device_type); }; diff --git a/src/applib/examples/example_storage_detector.cpp b/src/applib/examples/example_storage_detector.cpp index c7ed725..bb7df4b 100644 --- a/src/applib/examples/example_storage_detector.cpp +++ b/src/applib/examples/example_storage_detector.cpp @@ -43,7 +43,7 @@ int main() } else { for (const auto& drive : drives) { std::cerr << drive->get_device_with_type() << - " (" << StorageDevice::get_type_storable_name(drive->get_detected_type()) << ")\n"; + " (" << StorageDeviceDetectedTypeExt::get_storable_name(drive->get_detected_type()) << ")\n"; } } return EXIT_SUCCESS; diff --git a/src/applib/selftest.cpp b/src/applib/selftest.cpp index 17907c4..69bed3c 100644 --- a/src/applib/selftest.cpp +++ b/src/applib/selftest.cpp @@ -257,7 +257,6 @@ hz::ExpectedVoid SelfTest::update(const std::shared_ptrget_is_hdd() ? AtaStorageAttribute::DiskType::Hdd : AtaStorageAttribute::DiskType::Ssd; auto parser = SmartctlParser::create(SmartctlParserType::Ata, SmartctlVersionParser::get_default_format(SmartctlParserType::Ata)); DBG_ASSERT_RETURN(parser, hz::Unexpected(SelfTestError::ParseError, _("Cannot create parser."))); @@ -266,7 +265,8 @@ hz::ExpectedVoid SelfTest::update(const std::shared_ptrget_property_repository(), disk_type); + auto property_repo = StoragePropertyProcessor::process_properties( + parser->get_property_repository(), drive_->get_detected_type()); // Note: Since the self-test log is sometimes late // and in undetermined order (sorting by hours is too rough), diff --git a/src/applib/smartctl_json_ata_parser.cpp b/src/applib/smartctl_json_ata_parser.cpp index 5cbb08b..d6e07fc 100644 --- a/src/applib/smartctl_json_ata_parser.cpp +++ b/src/applib/smartctl_json_ata_parser.cpp @@ -82,9 +82,6 @@ smartctl/version/_merged Looks like "7.2" smartctl/version/_merged_full Looks like "smartctl 7.2 2020-12-30 r5155", formed from "/smartctl" subkeys. - -_custom/smart_enabled - Not present in json? */ @@ -285,11 +282,19 @@ hz::ExpectedVoid SmartctlJsonAtaParser::parse_section_info( } }, - {"rotation_rate", _("Rotation Rate"), - custom_string_formatter([](int64_t value) + {"rotation_rate", _("Rotation Rate"), // (S)ATA, used to detect HDD vs SSD + [](const nlohmann::json& root_node, const std::string& key, const std::string& displayable_name) + -> hz::ExpectedValue { - return std::format("{} RPM", value); - }) + if (auto jval = get_node_data(root_node, key); jval) { + AtaStorageProperty p; + p.set_name(key, key, displayable_name); + p.readable_value = std::format("{} RPM", jval.value()); + p.value = jval.value(); + return p; + } + return hz::Unexpected(SmartctlParserError::KeyNotFound, std::format("Error getting key {} from JSON data.", key)); + } }, {"form_factor/name", _("Form Factor"), string_formatter()}, diff --git a/src/applib/smartctl_json_basic_parser.cpp b/src/applib/smartctl_json_basic_parser.cpp index dc8e05f..e33ebf7 100644 --- a/src/applib/smartctl_json_basic_parser.cpp +++ b/src/applib/smartctl_json_basic_parser.cpp @@ -186,10 +186,18 @@ hz::ExpectedVoid SmartctlJsonBasicParser::parse_section_bas {"local_time/asctime", _("Scanned on"), string_formatter()}, {"rotation_rate", _("Rotation Rate"), // (S)ATA, used to detect HDD vs SSD - custom_string_formatter([](int64_t value) + [](const nlohmann::json& root_node, const std::string& key, const std::string& displayable_name) + -> hz::ExpectedValue { - return std::format("{} RPM", value); - }) + if (auto jval = get_node_data(root_node, key); jval) { + AtaStorageProperty p; + p.set_name(key, key, displayable_name); + p.readable_value = std::format("{} RPM", jval.value()); + p.value = jval.value(); + return p; + } + return hz::Unexpected(SmartctlParserError::KeyNotFound, std::format("Error getting key {} from JSON data.", key)); + } }, {"form_factor/name", _("Form Factor"), string_formatter()}, diff --git a/src/applib/smartctl_parser.cpp b/src/applib/smartctl_parser.cpp index 28a97ef..e85fea0 100644 --- a/src/applib/smartctl_parser.cpp +++ b/src/applib/smartctl_parser.cpp @@ -45,7 +45,14 @@ std::unique_ptr SmartctlParser::create(SmartctlParserType type, } break; case SmartctlParserType::Nvme: - // TODO + switch(format) { + case SmartctlOutputFormat::Json: +// return std::make_unique(); + break; + case SmartctlOutputFormat::Text: + // nothing + break; + } break; } return nullptr; diff --git a/src/applib/smartctl_parser_types.h b/src/applib/smartctl_parser_types.h index bccefd6..c0a3769 100644 --- a/src/applib/smartctl_parser_types.h +++ b/src/applib/smartctl_parser_types.h @@ -62,7 +62,7 @@ struct SmartctlParserPreferenceTypeExt : public hz::EnumHelper< SmartctlParserPreferenceType, SmartctlParserPreferenceTypeExt, - Glib::ustring> + Glib::ustring> { static constexpr inline SmartctlParserPreferenceType default_value = SmartctlParserPreferenceType::Auto; diff --git a/src/applib/smartctl_text_basic_parser.cpp b/src/applib/smartctl_text_basic_parser.cpp index b536cc0..2ee1456 100644 --- a/src/applib/smartctl_text_basic_parser.cpp +++ b/src/applib/smartctl_text_basic_parser.cpp @@ -30,6 +30,7 @@ Copyright: #include "smartctl_parser_types.h" #include "smartctl_version_parser.h" #include "smartctl_text_parser_helper.h" +#include "storage_device.h" @@ -77,9 +78,9 @@ hz::ExpectedVoid SmartctlTextBasicParser::parse(std::string if (app_pcre_match("/this device: CD\\/DVD/mi", output) || app_pcre_match("/^Device type:\\s+CD\\/DVD/mi", output)) { AtaStorageProperty p; - p.set_name("Drive type", "_custom/disk_type", "Drive Type"); + p.set_name("Drive type", "_custom/parser_detected_drive_type", "Parser-Detected Drive Type"); p.reported_value = "CD/DVD"; - p.value = p.reported_value; // TODO canonicalize + p.value = StorageDeviceDetectedTypeExt::get_storable_name(StorageDeviceDetectedType::CdDvd); p.section = AtaStorageProperty::Section::Info; // add to info section add_property(p); @@ -88,9 +89,9 @@ hz::ExpectedVoid SmartctlTextBasicParser::parse(std::string // Product: Raid 5 Volume } else if (app_pcre_match("/Product:[ \\t]*Raid/mi", output)) { AtaStorageProperty p; - p.set_name("Drive type", "_custom/disk_type", "Drive Type"); + p.set_name("Drive type", "_custom/parser_detected_drive_type", "Parser-Detected Drive Type"); p.reported_value = "RAID"; - p.value = p.reported_value; // TODO canonicalize + p.value = StorageDeviceDetectedTypeExt::get_storable_name(StorageDeviceDetectedType::UnsupportedRaid); p.section = AtaStorageProperty::Section::Info; // add to info section add_property(p); diff --git a/src/applib/smartctl_version_parser.cpp b/src/applib/smartctl_version_parser.cpp index b35acce..af88db4 100644 --- a/src/applib/smartctl_version_parser.cpp +++ b/src/applib/smartctl_version_parser.cpp @@ -83,6 +83,26 @@ SmartctlOutputFormat SmartctlVersionParser::get_default_format(SmartctlParserTyp +SmartctlParserType SmartctlVersionParser::get_default_parser_type(StorageDeviceDetectedType detected_type) +{ + switch (detected_type) { + case StorageDeviceDetectedType::Unknown: + case StorageDeviceDetectedType::NeedsExplicitType: + case StorageDeviceDetectedType::BasicScsi: + case StorageDeviceDetectedType::CdDvd: + case StorageDeviceDetectedType::UnsupportedRaid: + break; + case StorageDeviceDetectedType::AtaAny: + case StorageDeviceDetectedType::AtaHdd: + case StorageDeviceDetectedType::AtaSsd: + return SmartctlParserType::Ata; + case StorageDeviceDetectedType::Nvme: + return SmartctlParserType::Nvme; + } + return SmartctlParserType::Basic; +} + + /// @} diff --git a/src/applib/smartctl_version_parser.h b/src/applib/smartctl_version_parser.h index 93ef054..644a431 100644 --- a/src/applib/smartctl_version_parser.h +++ b/src/applib/smartctl_version_parser.h @@ -18,6 +18,9 @@ Copyright: #include #include "smartctl_parser_types.h" +#include "ata_storage_property_descr.h" + + @@ -47,6 +50,9 @@ class SmartctlVersionParser { /// Get default output format for a parser type. static SmartctlOutputFormat get_default_format(SmartctlParserType parser_type); + /// Get default output format for a parser type. + static SmartctlParserType get_default_parser_type(StorageDeviceDetectedType detected_type); + private: diff --git a/src/applib/storage_detector.cpp b/src/applib/storage_detector.cpp index 29e3f9d..728aed9 100644 --- a/src/applib/storage_detector.cpp +++ b/src/applib/storage_detector.cpp @@ -129,7 +129,7 @@ hz::ExpectedVoid StorageDetector::fetch_basic_data(std::ve debug_out_dump("app", "Device information for " << drive->get_device() << " (type: \"" << drive->get_type_argument() << "\"):\n" << "\tModel: " << drive->get_model_name() << "\n" - << "\tDetected type: " << StorageDevice::get_type_storable_name(drive->get_detected_type()) << "\n" + << "\tDetected type: " << StorageDeviceDetectedTypeExt::get_displayable_name(drive->get_detected_type()) << "\n" << "\tSMART status: " << StorageDevice::get_status_displayable_name(drive->get_smart_status()) << "\n" ); diff --git a/src/applib/storage_detector_linux.cpp b/src/applib/storage_detector_linux.cpp index f65d8ad..6460b18 100644 --- a/src/applib/storage_detector_linux.cpp +++ b/src/applib/storage_detector_linux.cpp @@ -682,7 +682,8 @@ inline hz::ExpectedVoid detect_drives_linux_adaptec( // Note: Not sure about this, have to check with real SAS drives if (app_pcre_match("/Device Read Identity Failed/mi", output)) { // "-d sat" didn't work, default back to smartctl's "-d scsi" - drive->clear_fetched(); + drive->clear_parse_results(); + drive->clear_outputs(); drive->set_type_argument(""); fetch_status = drive->fetch_basic_data_and_parse(smartctl_ex); } diff --git a/src/applib/storage_device.cpp b/src/applib/storage_device.cpp index 8c972e4..54dce32 100644 --- a/src/applib/storage_device.cpp +++ b/src/applib/storage_device.cpp @@ -9,48 +9,43 @@ Copyright: /// \weakgroup applib /// @{ +#include "storage_device.h" + #include "local_glibmm.h" +#include +#include +#include +#include #include +#include +#include +#include #include "rconfig/rconfig.h" #include "hz/string_algo.h" // string_trim_copy, string_any_to_unix_copy #include "hz/fs.h" #include "hz/format_unit.h" // hz::format_date +#include "hz/error_container.h" #include "app_pcrecpp.h" -#include "storage_device.h" -#include "smartctl_text_ata_parser.h" +#include "smartctl_parser_types.h" +#include "storage_device_detected_type.h" #include "storage_settings.h" #include "smartctl_executor.h" #include "smartctl_version_parser.h" -//#include "smartctl_text_parser_helper.h" #include "ata_storage_property_descr.h" - - - -std::string StorageDevice::get_type_storable_name(DetectedType type) -{ - static const std::unordered_map m { - {DetectedType::Unknown, "unknown"}, - {DetectedType::NeedsExplicitType, "invalid"}, - {DetectedType::CdDvd, "cd/dvd"}, - {DetectedType::Raid, "raid"}, - }; - if (auto iter = m.find(type); iter != m.end()) { - return iter->second; - } - return "[internal_error]"; -} +//#include "smartctl_text_parser_helper.h" +//#include "ata_storage_property_descr.h" std::string StorageDevice::get_status_displayable_name(Status status) { static const std::unordered_map m { - {Status::Enabled, C_("status", "Enabled")}, - {Status::Disabled, C_("status", "Disabled")}, + {Status::Enabled, C_("status", "Enabled")}, + {Status::Disabled, C_("status", "Disabled")}, {Status::Unsupported, C_("status", "Unsupported")}, - {Status::Unknown, C_("status", "Unknown")}, + {Status::Unknown, C_("status", "Unknown")}, }; if (auto iter = m.find(status); iter != m.end()) { return iter->second; @@ -78,15 +73,20 @@ StorageDevice::StorageDevice(std::string dev, std::string type_arg) -void StorageDevice::clear_fetched(bool including_outputs) +void StorageDevice::clear_outputs() { - if (including_outputs) { - basic_output_.clear(); - full_output_.clear(); - } + basic_output_.clear(); + full_output_.clear(); +} + + +void StorageDevice::clear_parse_results() +{ parse_status_ = ParseStatus::None; - test_is_active_ = false; // not sure +// test_is_active_ = false; // not sure + + property_repository_.clear(); smart_supported_.reset(); smart_enabled_.reset(); @@ -95,8 +95,6 @@ void StorageDevice::clear_fetched(bool including_outputs) family_name_.reset(); size_.reset(); health_property_.reset(); - - property_repository_.clear(); } @@ -108,7 +106,9 @@ hz::ExpectedVoid StorageDevice::fetch_basic_data_and_parse( return hz::Unexpected(StorageDeviceError::TestRunning, _("A test is currently being performed on this drive.")); } - this->clear_fetched(); // clear everything fetched before, including outputs + // Clear everything fetched before, including outputs + this->clear_parse_results(); + this->clear_outputs(); // We don't use "--all" - it may cause really screwed up the output (tests, etc.). // This looks just like "--info" only on non-smart devices. @@ -125,10 +125,14 @@ hz::ExpectedVoid StorageDevice::fetch_basic_data_and_parse( // This means that the old SCSI identify command isn't executed by default, // and there is no information about the device manufacturer/etc. in the output. // We detect this and set the device type to scsi to at least have _some_ info. + + // Note: This match works even with JSON (the text output is included in --json=o). if ((execute_status || execute_status.error().data() == StorageDeviceError::ExecutionError) - && get_detected_type() == DetectedType::NeedsExplicitType && get_type_argument().empty()) { + && get_detected_type() == StorageDeviceDetectedType::NeedsExplicitType + && get_type_argument().empty() ) { debug_out_info("app", "The device seems to be of different type than auto-detected, trying again with scsi.\n"); this->set_type_argument("scsi"); + this->set_detected_type(StorageDeviceDetectedType::BasicScsi); return this->fetch_basic_data_and_parse(smartctl_ex); // try again with scsi } @@ -142,73 +146,44 @@ hz::ExpectedVoid StorageDevice::fetch_basic_data_and_parse( // } // Set some properties too - they are needed for e.g. AODC status, etc. - return this->parse_basic_data(true); + return this->parse_basic_data(); } -hz::ExpectedVoid StorageDevice::parse_basic_data(bool do_set_properties, bool emit_signal) +hz::ExpectedVoid StorageDevice::parse_basic_data() { - this->clear_fetched(false); // clear everything fetched before, except outputs + // Clear everything fetched before, except outputs and type + this->clear_parse_results(); - AtaStorageAttribute::DiskType disk_type = AtaStorageAttribute::DiskType::Any; - - // Try the basic parser first. If it succeeds, use the specialized parser. + // Parse using Basic parser. This supports all drive types. auto basic_parser = SmartctlParser::create(SmartctlParserType::Basic, SmartctlOutputFormat::Json); DBG_ASSERT_RETURN(basic_parser, hz::Unexpected(StorageDeviceError::ParseError, _("Cannot create parser"))); + // This also detects the drive type and adds it to "_custom/parser_detected_drive_type" property. auto parse_status = basic_parser->parse(this->get_basic_output()); if (!parse_status) { return hz::Unexpected(StorageDeviceError::ParseError, std::vformat(_("Cannot parse smartctl output: {}"), std::make_format_args(parse_status.error().message()))); } + // See if we can narrow down the drive type from what was detected + // by StorageDetector and "_custom/parser_detected_drive_type" property set by Basic parser. auto basic_property_repo = basic_parser->get_property_repository(); - auto drive_type_prop = basic_property_repo.lookup_property("_custom/drive_type"); - if (!drive_type_prop.empty()) { - const auto& drive_type = drive_type_prop.get_value(); - if (drive_type == "CD/DVD") { - debug_out_dump("app", "Drive " << get_device_with_type() << " seems to be a CD/DVD device.\n"); - this->set_detected_type(DetectedType::CdDvd); - } else if (drive_type == "RAID") { - debug_out_dump("app", "Drive " << get_device_with_type() << " seems to be a RAID volume/controller.\n"); - this->set_detected_type(DetectedType::Raid); - } - } + // Make detected type more exact. + detect_drive_type_from_properties(basic_property_repo); - { - auto rpm_prop = basic_property_repo.lookup_property("rotation_rate"); - if (!rpm_prop.empty()) { - auto rpm = rpm_prop.get_value(); - this->hdd_ = rpm > 0; - } - if (hdd_.has_value()) { - disk_type = hdd_.value() ? AtaStorageAttribute::DiskType::Hdd : AtaStorageAttribute::DiskType::Ssd; - } - } + // A model field (and its aliases) is a good indication whether there was any data or not + set_parse_status(model_name_.has_value() ? ParseStatus::Basic : ParseStatus::None); - if (auto prop = basic_property_repo.lookup_property("smart_support/available"); !prop.empty()) { - smart_supported_ = prop.get_value(); - } - if (auto prop = basic_property_repo.lookup_property("smart_support/enabled"); !prop.empty()) { - smart_enabled_ = prop.get_value(); - } - if (auto prop = basic_property_repo.lookup_property("model_name"); !prop.empty()) { - model_name_ = prop.get_value(); - } - if (auto prop = basic_property_repo.lookup_property("model_family"); !prop.empty()) { - family_name_ = prop.get_value(); - } - if (auto prop = basic_property_repo.lookup_property("serial_number"); !prop.empty()) { - serial_number_ = prop.get_value(); - } - if (auto prop = basic_property_repo.lookup_property("user_capacity/bytes/_short"); !prop.empty()) { - size_ = prop.readable_value; - } else if (auto prop2 = basic_property_repo.lookup_property("user_capacity/bytes"); !prop.empty()) { - size_ = prop2.readable_value; - } + // Add property descriptions and set to the drive. + this->set_property_repository(StoragePropertyProcessor::process_properties(basic_property_repo, get_detected_type())); + debug_out_dump("app", "Drive " << get_device_with_type() << " set to be " + << StorageDeviceDetectedTypeExt::get_displayable_name(get_detected_type()) << " device.\n"); + + read_common_properties(); // Try to parse the properties. ignore its errors - we already got what we came for. // Note that this may try to parse data the second time (it may already have @@ -222,15 +197,8 @@ hz::ExpectedVoid StorageDevice::parse_basic_data(bool do_set // StoragePropertyProcessor::process_properties(parser->get_property_repository(), disk_type)); // copy to our drive, overwriting old data // } // } - if (do_set_properties) { - this->set_property_repository(StoragePropertyProcessor::process_properties(basic_property_repo, disk_type)); - } - // A model field (and its aliases) is a good indication whether there was any data or not - set_parse_status(model_name_.has_value() ? ParseStatus::Basic : ParseStatus::None); - - if (emit_signal) - signal_changed().emit(this); // notify listeners + signal_changed().emit(this); // notify listeners return {}; } @@ -244,71 +212,109 @@ hz::ExpectedVoid StorageDevice::fetch_full_data_and_parse( return hz::Unexpected(StorageDeviceError::TestRunning, _("A test is currently being performed on this drive.")); } - this->clear_fetched(); // clear everything fetched before, including outputs + // Drive type must be already set at this point, using fetch_basic_data_and_parse(). + DBG_ASSERT(this->get_detected_type() != StorageDeviceDetectedType::Unknown); + + // Clear everything fetched before, including outputs + this->clear_parse_results(); + this->clear_outputs(); + + // Execute smartctl. + + // Instead of -x, we use all the individual options -x encompasses, so that + // an addition to default -x output won't affect us. + std::string command_options; + + // Type was detected by Basic parser + switch (this->get_detected_type()) { + case StorageDeviceDetectedType::Unknown: + case StorageDeviceDetectedType::NeedsExplicitType: + DBG_ASSERT(0); + break; + case StorageDeviceDetectedType::AtaAny: + case StorageDeviceDetectedType::AtaHdd: + case StorageDeviceDetectedType::AtaSsd: + command_options = "--health --info --get=all --capabilities --attributes --format=brief --log=xerror,50,error --log=xselftest,50,selftest --log=selective --log=directory --log=scttemp --log=scterc --log=devstat --log=sataphy"; + break; + case StorageDeviceDetectedType::Nvme: + command_options = "--health --info --get=all --capabilities --attributes --format=brief --log=xerror,50,error --log=xselftest,50,selftest --log=selective --log=directory --log=scttemp --log=scterc --log=devstat --log=sataphy"; + break; + case StorageDeviceDetectedType::BasicScsi: + case StorageDeviceDetectedType::CdDvd: + case StorageDeviceDetectedType::UnsupportedRaid: + // SCSI equivalent of -x: + command_options = "--health --info --attributes --log=error --log=selftest --log=background --log=sasphy"; + break; + } + + auto parser_type = SmartctlVersionParser::get_default_parser_type(this->get_detected_type()); + auto parser_format = SmartctlVersionParser::get_default_format(parser_type); + if (parser_format == SmartctlOutputFormat::Json) { + // --json flags: o means include original output (just in case). + command_options += " --json=o"; + } std::string output; - hz::ExpectedVoid execute_status; - - // instead of -x, we use all the individual options -x encompasses, so that - // an addition to default -x output won't affect us. - if (this->get_type_argument() == "scsi") { // not sure about correctness... FIXME probably fails with RAID/scsi - const auto default_parser_type = SmartctlVersionParser::get_default_format(SmartctlParserType::Basic); - // This doesn't do much yet, but just in case... - // SCSI equivalent of -x: - std::string command_options = "--health --info --attributes --log=error --log=selftest --log=background --log=sasphy"; - if (default_parser_type == SmartctlOutputFormat::Json) { - // --json flags: o means include original output (just in case). - command_options += " --json=o"; - } - - execute_status = execute_device_smartctl(command_options, smartctl_ex, output); - - } else { - const auto default_parser_type = SmartctlVersionParser::get_default_format(SmartctlParserType::Ata); - // ATA equivalent of -x. - std::string command_options = "--health --info --get=all --capabilities --attributes --format=brief --log=xerror,50,error --log=xselftest,50,selftest --log=selective --log=directory --log=scttemp --log=scterc --log=devstat --log=sataphy"; - if (default_parser_type == SmartctlOutputFormat::Json) { - // --json flags: o means include original output (just in case). - command_options += " --json=o"; - } - - execute_status = execute_device_smartctl(command_options, smartctl_ex, output, true); // set type to invalid if needed - } + auto execute_status = execute_device_smartctl(command_options, smartctl_ex, output); +// if (this->get_type_argument() == "scsi") { // not sure about correctness... FIXME probably fails with RAID/scsi +// const auto default_parser_type = SmartctlVersionParser::get_default_format(SmartctlParserType::Basic); +// // This doesn't do much yet, but just in case... +// // SCSI equivalent of -x: +// std::string command_options = "--health --info --attributes --log=error --log=selftest --log=background --log=sasphy"; +// if (default_parser_type == SmartctlOutputFormat::Json) { +// // --json flags: o means include original output (just in case). +// command_options += " --json=o"; +// } +// +// execute_status = execute_device_smartctl(command_options, smartctl_ex, output); +// +// } else { +// const auto default_parser_type = SmartctlVersionParser::get_default_format(SmartctlParserType::Ata); +// // ATA equivalent of -x. +// std::string command_options = "--health --info --get=all --capabilities --attributes --format=brief --log=xerror,50,error --log=xselftest,50,selftest --log=selective --log=directory --log=scttemp --log=scterc --log=devstat --log=sataphy"; +// if (default_parser_type == SmartctlOutputFormat::Json) { +// // --json flags: o means include original output (just in case). +// command_options += " --json=o"; +// } +// +// execute_status = execute_device_smartctl(command_options, smartctl_ex, output, true); // set type to invalid if needed +// } // See notes above (in fetch_basic_data_and_parse()). - if ((execute_status || execute_status.error().data() == StorageDeviceError::ExecutionError) - && get_detected_type() == DetectedType::NeedsExplicitType && get_type_argument().empty()) { - debug_out_info("app", "The device seems to be of different type than auto-detected, trying again with scsi.\n"); - this->set_type_argument("scsi"); - return this->fetch_full_data_and_parse(smartctl_ex); // try again with scsi - } - + // No need to do this: if the basic data was fetched, the type is already set. +// if ((execute_status || execute_status.error().data() == StorageDeviceError::ExecutionError) +// && get_detected_type() == DetectedType::NeedsExplicitType && get_type_argument().empty()) { +// debug_out_info("app", "The device seems to be of different type than auto-detected, trying again with scsi.\n"); +// this->set_type_argument("scsi"); +// return this->fetch_full_data_and_parse(smartctl_ex); // try again with scsi +// } // Since the type error leads to "command line didn't parse" error here, // we do this after the scsi stuff. + + if (!execute_status) return execute_status; this->full_output_ = output; - return this->try_parse_data(); + return this->parse_full_data(parser_type, parser_format); } - +/* hz::ExpectedVoid StorageDevice::try_parse_data() { - this->clear_fetched(false); // clear everything fetched before, except outputs - - AtaStorageAttribute::DiskType disk_type = AtaStorageAttribute::DiskType::Any; - if (hdd_.has_value()) { - disk_type = hdd_.value() ? AtaStorageAttribute::DiskType::Hdd : AtaStorageAttribute::DiskType::Ssd; - } + this->clear_fetched(false); // clear everything fetched before, except outputs and disk type auto parser_format = SmartctlParser::detect_output_format(this->full_output_); - if (!parser_format.has_value()) { return hz::Unexpected(StorageDeviceError::ParseError, parser_format.error().message()); } +// auto basic_parser = SmartctlParser::create(SmartctlParserType::Basic, parser_format.value()); +// if (!basic_parser) { +// return hz::Unexpected(StorageDeviceError::ParseError, _("Cannot create parser")); +// } + // TODO Choose format according to device type SmartctlParserType parser_type = SmartctlParserType::Ata; @@ -355,6 +361,113 @@ hz::ExpectedVoid StorageDevice::try_parse_data() return {}; // return ok if at least the info was ok. } +*/ + + + +hz::ExpectedVoid StorageDevice::parse_full_data(SmartctlParserType parser_type, SmartctlOutputFormat format) +{ + // Clear everything fetched before, except outputs and disk type + clear_parse_results(); + + auto parser = SmartctlParser::create(parser_type, format); + DBG_ASSERT_RETURN(parser, hz::Unexpected(StorageDeviceError::ParseError, _("Cannot create parser"))); + + const auto parse_status = parser->parse(this->full_output_); + if (parse_status.has_value()) { + set_parse_status(parser_type == SmartctlParserType::Basic ? ParseStatus::Basic : ParseStatus::Full); + + // Detect drive type based on parsed properties + detect_drive_type_from_properties(parser->get_property_repository()); + + // Set the full properties, overwriting old data. + set_property_repository(StoragePropertyProcessor::process_properties(parser->get_property_repository(), get_detected_type())); + + // Read common properties from the repository. + read_common_properties(); + + signal_changed().emit(this); // notify listeners + + return {}; + } + + return hz::Unexpected(StorageDeviceError::ParseError, + std::vformat(_("Cannot parse smartctl output: {}"), std::make_format_args(parse_status.error().message()))); +} + + + +hz::ExpectedVoid StorageDevice::parse_any_data_for_virtual() +{ + // Clear everything fetched before, except outputs and disk type + this->clear_parse_results(); + + auto parser_format = SmartctlParser::detect_output_format(this->full_output_); + if (!parser_format.has_value()) { + return hz::Unexpected(StorageDeviceError::ParseError, parser_format.error().message()); + } + + auto basic_parser = SmartctlParser::create(SmartctlParserType::Basic, parser_format.value()); + if (!basic_parser) { + return hz::Unexpected(StorageDeviceError::ParseError, _("Cannot create parser")); + } + + // This will add some properties and emit signal_changed(). + auto basic_parse_status = this->parse_basic_data(); + if (!basic_parse_status) { + return hz::Unexpected(StorageDeviceError::ParseError, + std::vformat(_("Cannot parse smartctl output: {}"), std::make_format_args(basic_parse_status.error().message()))); + } + + auto basic_property_repo = basic_parser->get_property_repository(); + + // Make detected type more exact. + detect_drive_type_from_properties(basic_property_repo); + + // Set properties from the basic parser. + set_property_repository(StoragePropertyProcessor::process_properties(basic_property_repo, get_detected_type())); + + // Read common properties from the repository. + read_common_properties(); + + + // Try to parse with a specialized parser based on drive type + auto parser_type = SmartctlVersionParser::get_default_parser_type(this->get_detected_type()); + + if (parser_type != SmartctlParserType::Basic) { + // Try specialized parser + auto parser = SmartctlParser::create(parser_type, parser_format.value()); + DBG_ASSERT_RETURN(parser, hz::Unexpected(StorageDeviceError::ParseError, _("Cannot create parser."))); + + const auto parse_status = parser->parse(this->full_output_); + if (parse_status.has_value()) { + // Call this after parse_basic_data(), since it sets parse status to "info". + set_parse_status(StorageDevice::ParseStatus::Full); + + // set the full properties. + // copy to our drive, overwriting old data. + set_property_repository(StoragePropertyProcessor::process_properties(parser->get_property_repository(), get_detected_type())); + } + } + + if (get_parse_status() != ParseStatus::Full) { + // Only basic data available + set_parse_status(ParseStatus::Basic); + set_property_repository(StoragePropertyProcessor::process_properties(basic_parser->get_property_repository(), get_detected_type())); + } + + signal_changed().emit(this); // notify listeners + + // Don't show any GUI warnings on parse failure - it may just be an unsupported + // drive (e.g. usb flash disk). Plus, it may flood the string. The data will be + // parsed again in Info window, and we show the warnings there. +// debug_out_warn("app", DBG_FUNC_MSG << "Cannot parse smartctl output.\n"); + + // proper parsing failed. try to at least extract info section +// this->basic_output_ = this->full_output_; // complete output here. sometimes it's only the info section + + return {}; +} @@ -443,6 +556,71 @@ A mandatory SMART command failed: exiting. To continue, add one or more '-T perm +void StorageDevice::read_common_properties() +{ + if (auto prop = property_repository_.lookup_property("smart_support/available"); !prop.empty()) { + smart_supported_ = prop.get_value(); + } + if (auto prop = property_repository_.lookup_property("smart_support/enabled"); !prop.empty()) { + smart_enabled_ = prop.get_value(); + } + if (auto prop = property_repository_.lookup_property("model_name"); !prop.empty()) { + model_name_ = prop.get_value(); + } + if (auto prop = property_repository_.lookup_property("model_family"); !prop.empty()) { + family_name_ = prop.get_value(); + } + if (auto prop = property_repository_.lookup_property("serial_number"); !prop.empty()) { + serial_number_ = prop.get_value(); + } + if (auto prop = property_repository_.lookup_property("user_capacity/bytes/_short"); !prop.empty()) { + size_ = prop.readable_value; + } else if (auto prop2 = property_repository_.lookup_property("user_capacity/bytes"); !prop.empty()) { + size_ = prop2.readable_value; + } +} + + + +void StorageDevice::detect_drive_type_from_properties(const StoragePropertyRepository& property_repo) +{ + auto drive_type_prop = property_repo.lookup_property("_custom/parser_detected_drive_type"); + if (!drive_type_prop.empty()) { + const auto& drive_type_storable_str = drive_type_prop.get_value(); + set_detected_type(StorageDeviceDetectedTypeExt::get_by_storable_name(drive_type_storable_str, StorageDeviceDetectedType::BasicScsi)); + } + + switch (get_detected_type()) { + case StorageDeviceDetectedType::Unknown: + set_detected_type(StorageDeviceDetectedType::BasicScsi); // fall back to basic scsi parser + break; + case StorageDeviceDetectedType::AtaAny: + // Find out if it's SSD or HDD + { + auto rpm_prop = property_repo.lookup_property("rotation_rate"); + if (rpm_prop.empty() || rpm_prop.get_value() == 0) { + set_detected_type(StorageDeviceDetectedType::AtaSsd); + } else { + set_detected_type(StorageDeviceDetectedType::AtaHdd); + } + break; + } + case StorageDeviceDetectedType::AtaHdd: + case StorageDeviceDetectedType::AtaSsd: + case StorageDeviceDetectedType::Nvme: + case StorageDeviceDetectedType::BasicScsi: + case StorageDeviceDetectedType::CdDvd: + case StorageDeviceDetectedType::UnsupportedRaid: + // leave as is + break; + case StorageDeviceDetectedType::NeedsExplicitType: + DBG_ASSERT(0); + break; + } +} + + + StorageDevice::Status StorageDevice::get_smart_status() const { Status status = Status::Unsupported; @@ -580,14 +758,14 @@ std::string StorageDevice::get_device_with_type() const -void StorageDevice::set_detected_type(DetectedType t) +void StorageDevice::set_detected_type(StorageDeviceDetectedType t) { detected_type_ = t; } -StorageDevice::DetectedType StorageDevice::get_detected_type() const +StorageDeviceDetectedType StorageDevice::get_detected_type() const { return detected_type_; } @@ -700,13 +878,6 @@ std::string StorageDevice::get_serial_number() const -bool StorageDevice::get_is_hdd() const -{ - return hdd_.has_value() && hdd_.value(); -} - - - void StorageDevice::set_info_output(std::string s) { basic_output_ = std::move(s); @@ -824,7 +995,7 @@ hz::ExpectedVoid StorageDevice::execute_device_smartctl(cons return hz::Unexpected(StorageDeviceError::CannotExecuteOnVirtual, _("Cannot execute smartctl on a virtual device.")); } - std::string device = get_device(); + const std::string device = get_device(); auto smartctl_status = execute_smartctl(device, this->get_device_options(), command_options, smartctl_ex, smartctl_output); @@ -836,9 +1007,11 @@ hz::ExpectedVoid StorageDevice::execute_device_smartctl(cons // This means that the old SCSI identify command isn't executed by default, // and there is no information about the device manufacturer/etc. in the output. // We detect this and set the device type to scsi to at least have _some_ info. - if (check_type && this->get_detected_type() == DetectedType::Unknown + + // Note: This match works even with JSON (the text output is included in --json=o). + if (check_type && this->get_detected_type() == StorageDeviceDetectedType::Unknown && app_pcre_match("/specify device type with the -d option/mi", smartctl_output)) { - this->set_detected_type(DetectedType::NeedsExplicitType); + this->set_detected_type(StorageDeviceDetectedType::NeedsExplicitType); } return hz::Unexpected(StorageDeviceError::ExecutionError, smartctl_status.error().message()); diff --git a/src/applib/storage_device.h b/src/applib/storage_device.h index 58ca3a9..c4d9d53 100644 --- a/src/applib/storage_device.h +++ b/src/applib/storage_device.h @@ -23,6 +23,10 @@ Copyright: #include "smartctl_text_ata_parser.h" // prop_list_t #include "smartctl_executor.h" #include "storage_property_repository.h" +#include "storage_device_detected_type.h" + + + class StorageDevice; @@ -47,20 +51,6 @@ enum class StorageDeviceError { class StorageDevice { public: - /// These may be used to force smartctl to a special type, as well as - /// to display the correct icon - enum class DetectedType { - Unknown, // Unknown. Will be autodetected by smartctl. - Invalid, // This is set by smartctl executor if it detects invalid type (but not if it's scsi). - CdDvd, // CD/DVD/Blu-Ray. Unsupported by smartctl, only basic info is given. - Raid, // RAID controller or volume. Unsupported by smartctl, only basic info is given. - }; - - - /// This gives a string which can be displayed in outputs - [[nodiscard]] static std::string get_type_storable_name(DetectedType type); - - /// Statuses of various states enum class Status { Enabled, ///< SMART, AODC @@ -75,8 +65,8 @@ class StorageDevice { /// Statuses of various parse states enum class ParseStatus { - Full, ///< Fully parsed - Basic, ///< Only info section available + Full, ///< Parsed with specialized parser + Basic, ///< Only info section available, parsed with Basic parser None, ///< No data }; @@ -88,8 +78,12 @@ class StorageDevice { StorageDevice(std::string dev, std::string type_arg); - // clear everything fetched before. - void clear_fetched(bool including_outputs = true); + /// Clear fetched smartctl outputs + void clear_outputs(); + + /// Clear common properties previously imported from repository. + void clear_parse_results(); + /// Calls "smartctl -i -H -c" (info section, health, capabilities), then parse_basic_data(). /// Called during drive detection. @@ -99,14 +93,20 @@ class StorageDevice { /// Detects type, smart support, smart status (on / off). /// Note: this will clear all previous properties! - [[nodiscard]] hz::ExpectedVoid parse_basic_data(bool do_set_properties = true, bool emit_signal = true); + [[nodiscard]] hz::ExpectedVoid parse_basic_data(); /// Execute smartctl --all / -x (all sections), get output, parse it (basic data too), fill properties. [[nodiscard]] hz::ExpectedVoid fetch_full_data_and_parse(const std::shared_ptr& smartctl_ex); /// Parse full info. If failed, try to parse it as basic info. - [[nodiscard]] hz::ExpectedVoid try_parse_data(); +// [[nodiscard]] hz::ExpectedVoid try_parse_data(); + + /// Parse full info. + [[nodiscard]] hz::ExpectedVoid parse_full_data(SmartctlParserType parser_type, SmartctlOutputFormat format); + + /// Try to detect the data type and parse it. This is used when loading virtual drives. + [[nodiscard]] hz::ExpectedVoid parse_any_data_for_virtual(); /// Get the "fully parsed" flag [[nodiscard]] ParseStatus get_parse_status() const; @@ -119,6 +119,13 @@ class StorageDevice { [[nodiscard]] hz::ExpectedVoid set_aodc_enabled(bool b, const std::shared_ptr& smartctl_ex); + /// Read common properties (smart supported, smart enabled, etc.) from the repository. + void read_common_properties(); + + /// Detect drive type based on parsed properties. + void detect_drive_type_from_properties(const StoragePropertyRepository& property_repo); + + /// Get SMART status [[nodiscard]] Status get_smart_status() const; @@ -144,10 +151,10 @@ class StorageDevice { /// Set detected type - void set_detected_type(DetectedType t); + void set_detected_type(StorageDeviceDetectedType t); /// Get detected type - [[nodiscard]] DetectedType get_detected_type() const; + [[nodiscard]] StorageDeviceDetectedType get_detected_type() const; /// Set argument for "-d" smartctl parameter @@ -200,9 +207,6 @@ class StorageDevice { /// \return empty string if not found [[nodiscard]] std::string get_serial_number() const; - /// Check whether this drive is a rotational HDD. - [[nodiscard]] bool get_is_hdd() const; - /// Set "info" output to parse void set_info_output(std::string s); @@ -260,9 +264,6 @@ class StorageDevice { private: - std::string basic_output_; ///< "smartctl --info" output - std::string full_output_; ///< "smartctl --all" or "-x" output - std::string device_; ///< e.g. /dev/sda or pd0. empty if virtual. std::string type_arg_; ///< Device type (for -d smartctl parameter), as specified when adding the device. std::string extra_args_; ///< Extra parameters for smartctl, as specified when adding the device. @@ -273,14 +274,21 @@ class StorageDevice { hz::fs::path virtual_file_; ///< A file (smartctl data) the virtual device was loaded from bool is_manually_added_ = false; ///< StorageDevice doesn't use it, but it's useful for its users. - ParseStatus parse_status_ = ParseStatus::None; ///< "Fully parsed" flag - /// Sort of a "lock". If true, the device is not allowed to perform any commands /// except "-l selftest" and maybe "--capabilities" and "--info" (not sure). bool test_is_active_ = false; - // Note: These are detected through info output - DetectedType detected_type_ = DetectedType::Unknown; ///< e.g. type_unknown + // Outputs + std::string basic_output_; ///< "smartctl --info" output + std::string full_output_; ///< "smartctl --all" or "-x" output + + StorageDeviceDetectedType detected_type_ = StorageDeviceDetectedType::Unknown; ///< Detected by basic parser + + ParseStatus parse_status_ = ParseStatus::None; ///< "Fully parsed" flag + + StoragePropertyRepository property_repository_; ///< Parsed data properties + + // Common properties std::optional smart_supported_; ///< SMART support status std::optional smart_enabled_; ///< SMART enabled status mutable std::optional aodc_status_; ///< Cached aodc status. @@ -288,10 +296,8 @@ class StorageDevice { std::optional family_name_; ///< Family name std::optional serial_number_; ///< Serial number std::optional size_; ///< Formatted size - std::optional hdd_; ///< Whether it's a rotational drive (HDD) or something else (SSD, flash, etc.) mutable std::optional health_property_; ///< Cached health property. - StoragePropertyRepository property_repository_; ///< Parsed data properties /// Emitted whenever new information is available sigc::signal signal_changed_; diff --git a/src/applib/storage_device_detected_type.cpp b/src/applib/storage_device_detected_type.cpp new file mode 100644 index 0000000..4bfd3bb --- /dev/null +++ b/src/applib/storage_device_detected_type.cpp @@ -0,0 +1,11 @@ + + + +/* + ***************************************************************************** + License: GNU General Public License v3.0 only + Copyright: + (C) 2024 Alexander Shaduri + ***************************************************************************** + */ +#include "storage_device_detected_type.h" diff --git a/src/applib/storage_device_detected_type.h b/src/applib/storage_device_detected_type.h new file mode 100644 index 0000000..dc39dab --- /dev/null +++ b/src/applib/storage_device_detected_type.h @@ -0,0 +1,69 @@ +/****************************************************************************** +License: GNU General Public License v3.0 only +Copyright: + (C) 2008 - 2021 Alexander Shaduri +******************************************************************************/ +/// \file +/// \author Alexander Shaduri +/// \ingroup applib +/// \weakgroup applib +/// @{ +#ifndef STORAGE_DEVICE_DETECTED_TYPE_H +#define STORAGE_DEVICE_DETECTED_TYPE_H + +#include "local_glibmm.h" + +#include "hz/enum_helper.h" + + +/// These may be used to force smartctl to a special type, as well as +/// to display the correct icon +enum class StorageDeviceDetectedType { + Unknown, ///< Unknown, default state. + NeedsExplicitType, ///< This is set by smartctl executor if it detects the need for -d option. + AtaAny, ///< Any ATA device (HDD or SSD), before it is detected whether it's HDD or SSD. + AtaHdd, ///< ATA HDD + AtaSsd, ///< ATA SSD + Nvme, ///< NVMe device (SSD) + BasicScsi, ///< Basic SCSI device (no smart data). Usually flash drives, etc. + CdDvd, ///< CD/DVD/Blu-Ray. Blu-ray is not always detected. + UnsupportedRaid, ///< RAID controller or volume. Unsupported by smartctl, only basic info is given. +}; + + + +/// Helper structure for enum-related functions +struct StorageDeviceDetectedTypeExt + : public hz::EnumHelper< + StorageDeviceDetectedType, + StorageDeviceDetectedTypeExt, + Glib::ustring> +{ + static constexpr inline StorageDeviceDetectedType default_value = StorageDeviceDetectedType::Unknown; + + static std::unordered_map> build_enum_map() + { + return { + {StorageDeviceDetectedType::Unknown, {"unknown", _("Unknown")}}, + {StorageDeviceDetectedType::NeedsExplicitType, {"needs_explicit_type", _("Needs Explicit Type")}}, + {StorageDeviceDetectedType::AtaAny, {"ata_any", _("ATA Device (HDD or SSD)")}}, + {StorageDeviceDetectedType::AtaHdd, {"ata_hdd", _("ATA HDD")}}, + {StorageDeviceDetectedType::AtaSsd, {"ata_ssd", _("ATA SSD")}}, + {StorageDeviceDetectedType::Nvme, {"nvme", _("NVMe Device")}}, + {StorageDeviceDetectedType::BasicScsi, {"basic_scsi", _("Basic SCSI Device")}}, + {StorageDeviceDetectedType::CdDvd, {"cd_dvd", _("CD/DVD/Blu-Ray")}}, + {StorageDeviceDetectedType::UnsupportedRaid, {"unsupported_raid", _("Unsupported RAID Controller or Volume")}}, + }; + } + +}; + + + + + + + +#endif + +/// @} diff --git a/src/gsc_main_window.cpp b/src/gsc_main_window.cpp index 5ff64aa..dde8b4e 100644 --- a/src/gsc_main_window.cpp +++ b/src/gsc_main_window.cpp @@ -13,6 +13,7 @@ Copyright: #include #include #include +#include #include "hz/string_algo.h" // string_split #include "hz/string_num.h" @@ -1162,7 +1163,8 @@ bool GscMainWindow::add_virtual_drive(const std::string& file) drive->set_full_output(output); drive->set_info_output(output); // info can be parsed from full output string too. - auto parse_error = drive->try_parse_data(); // this will set the type and add the properties + // this will set the type and add the properties + auto parse_error = drive->parse_any_data_for_virtual(); if (!parse_error) { gui_show_error_dialog(_("Cannot interpret SMART data"), parse_error.error().message(), this); return false; diff --git a/src/gsc_main_window_iconview.h b/src/gsc_main_window_iconview.h index 0fcda50..d4dcbba 100644 --- a/src/gsc_main_window_iconview.h +++ b/src/gsc_main_window_iconview.h @@ -347,12 +347,17 @@ class GscMainWindowIconView : public Gtk::IconView { Glib::RefPtr icon; switch(drive->get_detected_type()) { - case StorageDevice::DetectedType::CdDvd: + case StorageDeviceDetectedType::CdDvd: icon = cddvd_icon; break; - case StorageDevice::DetectedType::Unknown: // standard HD icon - case StorageDevice::DetectedType::NeedsExplicitType: - case StorageDevice::DetectedType::Raid: // TODO a separate icon for this + case StorageDeviceDetectedType::Unknown: // standard HD icon + case StorageDeviceDetectedType::NeedsExplicitType: + case StorageDeviceDetectedType::AtaAny: + case StorageDeviceDetectedType::AtaHdd: + case StorageDeviceDetectedType::AtaSsd: + case StorageDeviceDetectedType::Nvme: + case StorageDeviceDetectedType::BasicScsi: + case StorageDeviceDetectedType::UnsupportedRaid: // TODO a separate icon icon = hd_icon; break; }