Improve SSD attribute parsing logic for Kingston drives
This commit is contained in:
80
disk.py
80
disk.py
@@ -37,8 +37,6 @@ def parse_smart_data(data, device_node, rotation):
|
|||||||
if model == 'Unknown': model = data.get('model_number', 'Unknown')
|
if model == 'Unknown': model = data.get('model_number', 'Unknown')
|
||||||
serial = data.get('serial_number', 'Unknown')
|
serial = data.get('serial_number', 'Unknown')
|
||||||
size_bytes = data.get('user_capacity', {}).get('bytes', 0)
|
size_bytes = data.get('user_capacity', {}).get('bytes', 0)
|
||||||
|
|
||||||
# Get Logical Sector Size for LBA calculations (default to 512)
|
|
||||||
sector_size = data.get('logical_block_size', 512)
|
sector_size = data.get('logical_block_size', 512)
|
||||||
|
|
||||||
# --- 2. TYPE DETECTION ---
|
# --- 2. TYPE DETECTION ---
|
||||||
@@ -57,7 +55,7 @@ def parse_smart_data(data, device_node, rotation):
|
|||||||
spare = "N/A"
|
spare = "N/A"
|
||||||
temp = "N/A"
|
temp = "N/A"
|
||||||
errors = 0
|
errors = 0
|
||||||
total_bytes_written = 0
|
max_total_bytes = 0 # We will store the highest calculated write value here
|
||||||
|
|
||||||
# Temperature
|
# Temperature
|
||||||
temp_data = data.get('temperature', {}).get('current')
|
temp_data = data.get('temperature', {}).get('current')
|
||||||
@@ -74,53 +72,73 @@ def parse_smart_data(data, device_node, rotation):
|
|||||||
errors = nvme_log.get('media_errors', 0)
|
errors = nvme_log.get('media_errors', 0)
|
||||||
|
|
||||||
duw = nvme_log.get('data_units_written', 0)
|
duw = nvme_log.get('data_units_written', 0)
|
||||||
if duw: total_bytes_written = duw * 1000 * 512
|
if duw: max_total_bytes = duw * 1000 * 512
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# --- SATA/HDD LOGIC ---
|
# --- SATA/HDD LOGIC ---
|
||||||
attributes = data.get('ata_smart_attributes', {}).get('table', [])
|
attributes = data.get('ata_smart_attributes', {}).get('table', [])
|
||||||
|
|
||||||
writes_32mib_candidates = []
|
|
||||||
lba_written_val = 0
|
|
||||||
|
|
||||||
for attr in attributes:
|
for attr in attributes:
|
||||||
id_ = attr.get('id')
|
id_ = attr.get('id')
|
||||||
# 'value' is the Normalized value (0-100 usually)
|
|
||||||
norm_val = attr.get('value', 0)
|
norm_val = attr.get('value', 0)
|
||||||
# 'raw.value' is the Raw count
|
|
||||||
raw_val = attr.get('raw', {}).get('value', 0)
|
raw_val = attr.get('raw', {}).get('value', 0)
|
||||||
|
name = attr.get('name', '').lower()
|
||||||
|
|
||||||
# Standard Metrics
|
# Standard Metrics
|
||||||
if id_ == 9: hours = raw_val
|
if id_ == 9: hours = raw_val
|
||||||
if id_ == 194 and temp == "N/A": temp = f"{raw_val}C"
|
if id_ == 194 and temp == "N/A": temp = f"{raw_val}C"
|
||||||
if id_ in [5, 197]: errors += raw_val
|
if id_ in [5, 197]: errors += raw_val
|
||||||
|
|
||||||
# --- SATA SSD SPARE / LIFE LOGIC ---
|
# --- SPARE / LIFE REMAINING LOGIC ---
|
||||||
# We prioritize explicit percentage attributes.
|
# We check ID 231 (SSD_Life_Left) explicitly as requested.
|
||||||
# 202: Percent_Lifetime_Remain
|
# We only use ID 233 if the name implies "wear" or "life", NOT "writes".
|
||||||
# 233: Media_Wearout_Indicator (Intel/Others)
|
|
||||||
# 232: Available_Reservd_Space
|
|
||||||
# 231: SSD_Life_Left
|
|
||||||
# 169: Remaining_Lifetime_Perc
|
|
||||||
if disk_type == "SSD":
|
if disk_type == "SSD":
|
||||||
if id_ in [169, 202, 231, 232, 233]:
|
is_life_attr = False
|
||||||
# For these IDs, the Normalized Value is the percentage remaining
|
|
||||||
if norm_val is not None:
|
|
||||||
spare = f"{norm_val}%"
|
|
||||||
|
|
||||||
# --- SATA WRITE CALCULATION ---
|
# ID 231: SSD_Life_Left (Normalized value is %)
|
||||||
if id_ in [225, 241, 243]:
|
if id_ == 231: is_life_attr = True
|
||||||
writes_32mib_candidates.append(raw_val)
|
|
||||||
if id_ == 246:
|
|
||||||
lba_written_val = raw_val
|
|
||||||
|
|
||||||
# Finalize Writes
|
# ID 202: Percent_Lifetime_Remain
|
||||||
if writes_32mib_candidates:
|
if id_ == 202: is_life_attr = True
|
||||||
total_bytes_written = max(writes_32mib_candidates) * 32 * 1024 * 1024
|
|
||||||
elif lba_written_val > 0:
|
|
||||||
total_bytes_written = lba_written_val * sector_size
|
|
||||||
|
|
||||||
written_str = get_size(total_bytes_written) if total_bytes_written > 0 else "N/A"
|
# ID 169, 232: Common Life/Reserve attributes
|
||||||
|
if id_ in [169, 232]: is_life_attr = True
|
||||||
|
|
||||||
|
# ID 233: Only if name is NOT "writes" (Avoids collision with Flash_Writes_GiB)
|
||||||
|
if id_ == 233 and 'write' not in name: is_life_attr = True
|
||||||
|
|
||||||
|
if is_life_attr and norm_val is not None:
|
||||||
|
spare = f"{norm_val}%"
|
||||||
|
|
||||||
|
# --- DATA WRITTEN LOGIC ---
|
||||||
|
# We calculate bytes for this attribute based on its Name or ID
|
||||||
|
# and keep it if it's higher than what we've seen so far.
|
||||||
|
current_calc_bytes = 0
|
||||||
|
|
||||||
|
# Case A: Explicit "GiB" in name (e.g., "Flash_Writes_GiB")
|
||||||
|
if 'gib' in name:
|
||||||
|
current_calc_bytes = raw_val * 1024 * 1024 * 1024
|
||||||
|
|
||||||
|
# Case B: Explicit "32MiB" in name (e.g., "Host_Writes_32MiB")
|
||||||
|
elif '32mib' in name:
|
||||||
|
current_calc_bytes = raw_val * 32 * 1024 * 1024
|
||||||
|
|
||||||
|
# Case C: Explicit "LBA" in name (e.g., "Total_LBAs_Written")
|
||||||
|
elif 'lba' in name:
|
||||||
|
current_calc_bytes = raw_val * sector_size
|
||||||
|
|
||||||
|
# Case D: Fallback by ID if name is generic or empty
|
||||||
|
elif id_ in [225, 241, 243] and current_calc_bytes == 0:
|
||||||
|
# Default Assumption: 32MiB for these IDs unless name said GiB
|
||||||
|
current_calc_bytes = raw_val * 32 * 1024 * 1024
|
||||||
|
elif id_ == 246 and current_calc_bytes == 0:
|
||||||
|
current_calc_bytes = raw_val * sector_size
|
||||||
|
|
||||||
|
# Compare and Store Max
|
||||||
|
if current_calc_bytes > max_total_bytes:
|
||||||
|
max_total_bytes = current_calc_bytes
|
||||||
|
|
||||||
|
written_str = get_size(max_total_bytes) if max_total_bytes > 0 else "N/A"
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"Device": device_node,
|
"Device": device_node,
|
||||||
|
|||||||
Reference in New Issue
Block a user