-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implements #2
- Loading branch information
Anatol Pomazau
committed
Feb 18, 2022
1 parent
4d973e3
commit c3f5c6b
Showing
10 changed files
with
298 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package test | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"os/exec" | ||
"testing" | ||
|
||
"github.com/anatol/smart.go" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestNVMe(t *testing.T) { | ||
path := "disk0" | ||
|
||
out, err := exec.Command("smartctl", "-a", path).CombinedOutput() | ||
fmt.Println(string(out)) | ||
//require.NoError(t, err) it fails at macosx because of GetLogPage() | ||
|
||
dev, err := smart.OpenNVMe(path) | ||
require.NoError(t, err) | ||
defer dev.Close() | ||
|
||
c, ns, err := dev.Identify() | ||
require.NoError(t, err) | ||
|
||
require.Equal(t, 0x106b, int(c.VendorID)) | ||
require.Equal(t, 0x106b, int(c.Ssvid)) | ||
require.Contains(t, string(bytes.TrimSpace(c.ModelNumber[:])), "APPLE SSD") | ||
require.Equal(t, 1, int(c.Nn)) | ||
|
||
require.Len(t, ns, 1) | ||
require.Equal(t, 244276265, int(ns[0].Nsze)) | ||
|
||
sm, err := dev.ReadSMART() | ||
require.NoError(t, err) | ||
require.Less(t, uint16(300), sm.Temperature) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
#include "nvme_darwin.h" | ||
|
||
bool is_smart_capable(io_object_t dev) { | ||
CFTypeRef smartCapableKey = IORegistryEntryCreateCFProperty( | ||
dev, CFSTR(kIOPropertyNVMeSMARTCapableKey), kCFAllocatorDefault, 0); | ||
if (smartCapableKey) { | ||
CFRelease(smartCapableKey); | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
// *path is a string that has a format like "disk0". | ||
unsigned int smart_nvme_open_darwin(const char *path, smart_nvme_darwin *nvme) { | ||
// see also https://gist.github.com/AlanQuatermain/250538 | ||
SInt32 score = 0; | ||
IOReturn kr; | ||
HRESULT hr; | ||
|
||
CFMutableDictionaryRef matcher = | ||
IOBSDNameMatching(kIOMasterPortDefault, 0, path); | ||
io_object_t disk = IOServiceGetMatchingService(kIOMasterPortDefault, matcher); | ||
|
||
while (!is_smart_capable(disk)) { | ||
io_object_t prevdisk = disk; | ||
|
||
// Find this device's parent and try again. | ||
IOReturn err = IORegistryEntryGetParentEntry(disk, kIOServicePlane, &disk); | ||
if (err != kIOReturnSuccess || !disk) { | ||
IOObjectRelease(prevdisk); | ||
break; | ||
} | ||
} | ||
|
||
if (!disk) { | ||
printf("no disk found"); | ||
goto exit1; | ||
} | ||
|
||
nvme->disk = disk; | ||
|
||
kr = IOCreatePlugInInterfaceForService( | ||
nvme->disk, kIONVMeSMARTUserClientTypeID, kIOCFPlugInInterfaceID, | ||
&nvme->plugin, &score); | ||
|
||
if (kr != kIOReturnSuccess) | ||
goto exit2; | ||
|
||
hr = (*nvme->plugin) | ||
->QueryInterface(nvme->plugin, | ||
CFUUIDGetUUIDBytes(kIONVMeSMARTInterfaceID), | ||
(void **)&nvme->smartIfNVMe); | ||
if (hr != S_OK) | ||
goto exit3; | ||
|
||
return 0; | ||
|
||
exit3: | ||
IODestroyPlugInInterface(nvme->plugin); | ||
exit2: | ||
IOObjectRelease(nvme->disk); | ||
exit1: | ||
return -1; | ||
} | ||
|
||
unsigned int smart_nvme_identify_darwin(smart_nvme_darwin *nvme, void *buffer, | ||
unsigned int nsid) { | ||
IOReturn err = | ||
(*nvme->smartIfNVMe)->GetIdentifyData(nvme->smartIfNVMe, buffer, nsid); | ||
if (err) | ||
return ENOSYS; | ||
|
||
return 0; | ||
} | ||
|
||
unsigned int smart_nvme_readsmart_darwin(smart_nvme_darwin *nvme, | ||
void *buffer) { | ||
IOReturn err = | ||
(*nvme->smartIfNVMe) | ||
->SMARTReadData(nvme->smartIfNVMe, (struct NVMeSMARTData *)buffer); | ||
if (err) | ||
return ENOSYS; | ||
|
||
return 0; | ||
} | ||
|
||
void smart_nvme_close_darwin(smart_nvme_darwin *nvme) { | ||
(*nvme->smartIfNVMe)->Release(nvme->smartIfNVMe); | ||
IODestroyPlugInInterface(nvme->plugin); | ||
IOObjectRelease(nvme->disk); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package smart | ||
|
||
// #cgo darwin LDFLAGS: -framework IOKit -framework CoreFoundation | ||
// #include "nvme_darwin.h" | ||
import "C" | ||
|
||
import ( | ||
"bytes" | ||
"encoding/binary" | ||
"fmt" | ||
"unsafe" | ||
) | ||
|
||
type NVMeDevice struct { | ||
data C.smart_nvme_darwin | ||
} | ||
|
||
func OpenNVMe(name string) (*NVMeDevice, error) { | ||
dev := NVMeDevice{} | ||
|
||
if res := C.smart_nvme_open_darwin(C.CString(name), &dev.data); res != 0 { | ||
return nil, fmt.Errorf("open darwin device error: 0x%x", res) | ||
} | ||
|
||
return &dev, nil | ||
} | ||
|
||
func (d *NVMeDevice) Close() error { | ||
C.smart_nvme_close_darwin(&d.data) | ||
return nil | ||
} | ||
|
||
func (d *NVMeDevice) ReadSMART() (*NvmeSMARTLog, error) { | ||
buf := make([]byte, 512) | ||
if err := C.smart_nvme_readsmart_darwin(&d.data, unsafe.Pointer(&buf[0])); err != 0 { | ||
return nil, fmt.Errorf("smart_nvme_readsmart_darwin: %v", err) | ||
} | ||
var sl NvmeSMARTLog | ||
if err := binary.Read(bytes.NewBuffer(buf), binary.LittleEndian, &sl); err != nil { | ||
return nil, err | ||
} | ||
|
||
return &sl, nil | ||
} | ||
|
||
func (d *NVMeDevice) readControllerIdentifyData() (*NvmeIdentController, error) { | ||
buf := make([]byte, 4096) | ||
if err := C.smart_nvme_identify_darwin(&d.data, unsafe.Pointer(&buf[0]), 0); err != 0 { | ||
return nil, fmt.Errorf("smart_nvme_identify_darwin: %v", err) | ||
} | ||
var controller NvmeIdentController | ||
if err := binary.Read(bytes.NewBuffer(buf), binary.LittleEndian, &controller); err != nil { | ||
return nil, err | ||
} | ||
|
||
return &controller, nil | ||
} | ||
|
||
func (d *NVMeDevice) readNamespaceIdentifyData(nsid int) (*NvmeIdentNamespace, error) { | ||
var n NvmeIdentNamespace | ||
if err := C.smart_nvme_identify_darwin(&d.data, unsafe.Pointer(&n), C.uint(nsid)); err != 0 { | ||
return nil, fmt.Errorf("smart_nvme_identify_darwin: %X", err) | ||
} | ||
|
||
return &n, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
#include <CoreFoundation/CoreFoundation.h> | ||
#include <IOKit/IOCFPlugIn.h> | ||
#include <IOKit/IOKitLib.h> | ||
#include <IOKit/storage/nvme/NVMeSMARTLibExternal.h> | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
typedef struct smart_nvme_darwin { | ||
IONVMeSMARTInterface **smartIfNVMe; | ||
IOCFPlugInInterface **plugin; | ||
io_object_t disk; | ||
} smart_nvme_darwin; | ||
|
||
unsigned int smart_nvme_open_darwin(const char *path, smart_nvme_darwin *nvme); | ||
unsigned int smart_nvme_identify_darwin(smart_nvme_darwin *nvme, void *buffer, | ||
unsigned int nsid); | ||
unsigned int smart_nvme_readsmart_darwin(smart_nvme_darwin *nvme, void *buffer); | ||
void smart_nvme_close_darwin(smart_nvme_darwin *nvme); | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.