diff --git a/scripts/wk/hw/diags.py b/scripts/wk/hw/diags.py index 7b7cb755..7dc44870 100644 --- a/scripts/wk/hw/diags.py +++ b/scripts/wk/hw/diags.py @@ -118,7 +118,13 @@ class State(): for dev in self.disks: disk_smart_status_check(dev, mid_run=True) for test in dev.tests: - if test.failed and 'Attributes' not in test.name: + if test.failed: + # Skip acceptable failure states + if 'Attributes' in test.name: + continue + if 'Self-Test' in test.name and 'TimedOut' in test.status: + continue + # Disable remaining tests dev.disable_disk_tests() break diff --git a/scripts/wk/hw/smart.py b/scripts/wk/hw/smart.py index d9f47f7a..ebce3dbf 100644 --- a/scripts/wk/hw/smart.py +++ b/scripts/wk/hw/smart.py @@ -231,6 +231,28 @@ def get_smart_self_test_details(dev) -> dict[Any, Any]: return details +def get_smart_self_test_last_result(dev) -> str: + """Get last SMART self-test result, returns str.""" + result = 'Unknown' + + # Parse SMART data + data = dev.raw_smartctl.get('ata_smart_self_test_log', {}).get('standard', {}).get('table', []) + if not data: + # No results found + return result + + # Build result string + result = ( + f'Power-on hours: {data.get("lifetime_hours", "?")}' + f', Type: {data.get("type", {}).get("string", "?")}' + f', Passed: {data.get("status", {}).get("passed", "?")}' + f', Result: {data.get("status", {}).get("string", "?")}' + ) + + # Done + return result + + def monitor_smart_self_test(test_obj, header_str, log_path) -> bool: """Monitor SMART self-test status and update test_obj, returns bool.""" started = False @@ -262,6 +284,10 @@ def monitor_smart_self_test(test_obj, header_str, log_path) -> bool: if _i * 5 >= SMART_SELF_TEST_START_TIMEOUT_IN_SECONDS: # Test didn't start within limit, stop waiting abort_self_test(test_obj.dev) + result = get_smart_self_test_last_result(test_obj.dev) + if result == 'Unknown': + result = 'SMART self-test failed to start' + test_obj.dev.add_note(result) test_obj.failed = True test_obj.set_status('TimedOut') break @@ -290,7 +316,7 @@ def run_self_test(test_obj, log_path) -> None: run_smart_self_test(test_obj, log_path) -def run_smart_self_test(test_obj, log_path) -> bool: +def run_smart_self_test(test_obj, log_path) -> None: """Run SMART self-test and check if it passed, returns bool. NOTE: An exception will be raised if the disk lacks SMART support. @@ -352,7 +378,10 @@ def run_smart_self_test(test_obj, log_path) -> bool: test_obj.failed = test_obj.failed or not test_obj.passed # Set status - if test_obj.failed and test_obj.status != 'TimedOut': + if test_obj.status == 'TimedOut': + # Preserve TimedOut status + pass + elif test_obj.failed: test_obj.set_status('Failed') elif test_obj.passed: test_obj.set_status('Passed')