Skip to content

Commit

Permalink
WIP: SMART statistics
Browse files Browse the repository at this point in the history
  • Loading branch information
mdlayher committed Jul 13, 2016
1 parent 43a7a19 commit 8a4f7bb
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 0 deletions.
1 change: 1 addition & 0 deletions block.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type Device struct {
// system implementations.
type devicer interface {
Identify() ([512]byte, error)
ReadSMART() (*SMARTData, error)
Size() (uint64, error)

io.Closer
Expand Down
20 changes: 20 additions & 0 deletions block_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,26 @@ func (d *device) Size() (uint64, error) {
return size, err
}

const (
_HDIO_DRIVE_CMD = 0x031f
_WIN_SMART = 0xb0
_SMART_READ_VALUES = 0xd0
)

func (d *device) ReadSMART() (*SMARTData, error) {
b := [516]byte{}
b[0] = _WIN_SMART
b[2] = _SMART_READ_VALUES
b[3] = 1

_, err := d.ioctl(d.fd, _HDIO_DRIVE_CMD, uintptr(unsafe.Pointer(&b[0])))
if err != nil {
return nil, err
}

return parseSMARTData(b), nil
}

// Read implements io.Reader for a block device.
func (d *device) Read(b []byte) (int, error) {
return d.dev.Read(b)
Expand Down
94 changes: 94 additions & 0 deletions smart.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package block

import (
"encoding/binary"
"unsafe"
)

// nativeEndian is the native endian byte order for this machine, determined
// on package init.
var nativeEndian binary.ByteOrder

// Courtesy of golang.org/x/net/ipv4
func init() {
i := uint32(1)
b := (*[4]byte)(unsafe.Pointer(&i))
if b[0] == 1 {
nativeEndian = binary.LittleEndian
} else {
nativeEndian = binary.BigEndian
}
}

func parseSMARTData(raw [516]byte) *SMARTData {
sd := &SMARTData{}

// Skip 4 bytes ATA header
sd.Revision = nativeEndian.Uint16(raw[4:6])

i := 6
for c := 0; c < _NR_ATTRIBUTES; c++ {
sd.Values[c].ID = raw[i]
i++

sd.Values[c].Status = nativeEndian.Uint16(raw[i : i+2])
i += 2

sd.Values[c].Value = raw[i]
i++

copy(sd.Values[c].Vendor[:], raw[i:i+8])
i += 8
}

sd.OfflineStatus = raw[i]
i++

sd.Vendor1 = raw[i]
i++

sd.OfflineTimeout = nativeEndian.Uint16(raw[i : i+2])
i += 2

sd.Vendor2 = raw[i]
i++

sd.OfflineCapability = raw[i]
i++

sd.SMARTCapability = nativeEndian.Uint16(raw[i : i+2])
i += 2

copy(sd.Reserved[:], raw[i:i+16])
i += 16

copy(sd.Vendor[:], raw[i:i+125])
i += 125

sd.Checksum = raw[i]

return sd
}

type SMARTData struct {
Revision uint16
Values [_NR_ATTRIBUTES]Value
OfflineStatus uint8
Vendor1 uint8
OfflineTimeout uint16
Vendor2 uint8
OfflineCapability uint8
SMARTCapability uint16
Reserved [16]byte
Vendor [125]byte
Checksum uint8
}

const _NR_ATTRIBUTES = 30

type Value struct {
ID uint8
Status uint16
Value uint8
Vendor [8]byte
}

0 comments on commit 8a4f7bb

Please sign in to comment.