SMART: detect drives whose firmware rejects the self-test log (WD SN580) and hide the test buttons with an explanation
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
340232b724
commit
e9be94e32b
@@ -178,6 +178,8 @@ type Smart struct {
|
||||
NVMe *NVMeLog `json:"nvme,omitempty"`
|
||||
SelfTest string `json:"self_test,omitempty"`
|
||||
SelfTestPct int `json:"self_test_remaining,omitempty"`
|
||||
SelfTestOK bool `json:"self_test_supported"`
|
||||
SelfTestNote string `json:"self_test_note,omitempty"`
|
||||
Warnings []string `json:"warnings"`
|
||||
Error string `json:"error,omitempty"`
|
||||
FetchedAt int64 `json:"fetched_at"`
|
||||
@@ -381,6 +383,30 @@ func (m *Manager) Smart(ctx context.Context, dev string, force bool) Smart {
|
||||
s.Warnings = append(s.Warnings, "endurance "+strconv.Itoa(l.PercentageUsed)+"% used")
|
||||
}
|
||||
}
|
||||
// Can this drive run self-tests from here? ATA says so outright; NVMe drives prove it
|
||||
// by exposing the self-test log, and some (WD SN580 among them) advertise the command
|
||||
// but reject the log page, which makes the whole feature unusable.
|
||||
if d, ok := raw["ata_smart_data"].(map[string]any); ok {
|
||||
if caps, ok := d["capabilities"].(map[string]any); ok {
|
||||
s.SelfTestOK = caps["self_tests_supported"] == true
|
||||
if !s.SelfTestOK {
|
||||
s.SelfTestNote = "drive reports no self-test support"
|
||||
}
|
||||
}
|
||||
}
|
||||
if _, ok := raw["nvme_self_test_log"]; ok {
|
||||
s.SelfTestOK = true
|
||||
} else if s.NVMe != nil {
|
||||
s.SelfTestNote = "this drive's firmware doesn't expose the NVMe self-test log, so tests can't be run or read from here"
|
||||
}
|
||||
if msgs, ok := raw["smartctl"].(map[string]any); ok {
|
||||
for _, mm := range asList(msgs["messages"]) {
|
||||
if strings.Contains(asString(mm["string"]), "Self-test Log failed") {
|
||||
s.SelfTestOK = false
|
||||
s.SelfTestNote = "firmware rejects the self-test log page (" + asString(mm["string"]) + ")"
|
||||
}
|
||||
}
|
||||
}
|
||||
if d, ok := raw["ata_smart_data"].(map[string]any); ok {
|
||||
if st, ok := d["self_test"].(map[string]any); ok {
|
||||
if ss, ok := st["status"].(map[string]any); ok {
|
||||
@@ -438,6 +464,9 @@ func (m *Manager) SelfTest(ctx context.Context, dev, kind string) error {
|
||||
if !m.smartctl {
|
||||
return errors.New("smartctl is not installed")
|
||||
}
|
||||
if sm := m.Smart(ctx, dev, false); sm.Supported && !sm.SelfTestOK {
|
||||
return errors.New("self-tests aren't available on this drive: " + sm.SelfTestNote)
|
||||
}
|
||||
out, code, err := m.run(ctx, "smartctl", "-t", kind, "/dev/"+dev)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user