-
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 88ccdb9
Showing
9 changed files
with
310 additions
and
48 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
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, 0x1b36, int(c.VendorID)) | ||
require.Equal(t, 0x1af4, int(c.Ssvid)) | ||
require.Equal(t, "smarttest", string(bytes.TrimSpace(c.SerialNumber[:]))) | ||
require.Equal(t, "QEMU NVMe Ctrl", string(bytes.TrimSpace(c.ModelNumber[:]))) | ||
require.Equal(t, 256, int(c.Nn)) | ||
|
||
require.Len(t, ns, 1) | ||
require.Equal(t, 0x14000, 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,77 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
#include "nvme_darwin.h" | ||
|
||
#define kIONVMeSMARTUserClientTypeID \ | ||
CFUUIDGetConstantUUIDWithBytes(NULL, 0xAA, 0x0F, 0xA6, 0xF9, 0xC2, 0xD6, \ | ||
0x45, 0x7F, 0xB1, 0x0B, 0x59, 0xA1, 0x32, \ | ||
0x53, 0x29, 0x2F) | ||
|
||
#define kIONVMeSMARTInterfaceID \ | ||
CFUUIDGetConstantUUIDWithBytes(NULL, 0xcc, 0xd1, 0xdb, 0x19, 0xfd, 0x9a, \ | ||
0x4d, 0xaf, 0xbf, 0x95, 0x12, 0x45, 0x4b, \ | ||
0x23, 0xa, 0xb6) | ||
|
||
// *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); | ||
nvme->disk = IOServiceGetMatchingService(kIOMasterPortDefault, matcher); | ||
|
||
kr = IOCreatePlugInInterfaceForService( | ||
nvme->disk, kIONVMeSMARTUserClientTypeID, kIOCFPlugInInterfaceID, | ||
&nvme->plugin, &score); | ||
|
||
printf("err=0x%x system=0x%x subsystem=0x%x code=0x%x\n", kr, | ||
err_get_system(kr), err_get_sub(kr), err_get_code(kr)); | ||
|
||
if (kr != kIOReturnSuccess) | ||
goto exit1; | ||
|
||
hr = (*nvme->plugin) | ||
->QueryInterface(nvme->plugin, | ||
CFUUIDGetUUIDBytes(kIONVMeSMARTInterfaceID), | ||
(void **)nvme->smartIfNVMe); | ||
if (hr != S_OK) | ||
goto exit2; | ||
|
||
return 0; | ||
|
||
exit2: | ||
IODestroyPlugInInterface(nvme->plugin); | ||
exit1: | ||
IOObjectRelease(nvme->disk); | ||
return -1; | ||
} | ||
|
||
unsigned int smart_nvme_identify_darwin(smart_nvme_darwin *nvme, void *buffer, | ||
unsigned int nsid) { | ||
IOReturn err = (*nvme->smartIfNVMe) | ||
->GetIdentifyData(nvme->smartIfNVMe, | ||
(struct nvme_id_ctrl *)buffer, nsid); | ||
if (err) | ||
return ENOSYS; | ||
|
||
return 0; | ||
} | ||
|
||
unsigned int smart_nvme_readlog_darwin(smart_nvme_darwin *nvme, void *buffer) { | ||
IOReturn err = | ||
(*nvme->smartIfNVMe) | ||
->SMARTReadData(nvme->smartIfNVMe, (struct nvme_smart_log *)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,56 @@ | ||
package smart | ||
|
||
// #cgo darwin LDFLAGS: -framework IOKit -framework CoreFoundation | ||
// #include "nvme_darwin.h" | ||
import "C" | ||
|
||
import ( | ||
"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) { | ||
var l NvmeSMARTLog | ||
if err := C.smart_nvme_readlog_darwin(&d.data, unsafe.Pointer(&l)); err != 0 { | ||
return nil, fmt.Errorf("smart_nvme_readlog_darwin: %v", err) | ||
} | ||
|
||
return &l, nil | ||
} | ||
|
||
func (d *NVMeDevice) readControllerIdentifyData() (*NvmeIdentController, error) { | ||
var c NvmeIdentController | ||
if err := C.smart_nvme_identify_darwin(&d.data, unsafe.Pointer(&c), 0); err != 0 { | ||
return nil, fmt.Errorf("smart_nvme_identify_darwin: %v", err) | ||
} | ||
|
||
return &c, 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,68 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
#include <CoreFoundation/CoreFoundation.h> | ||
#include <IOKit/IOCFPlugIn.h> | ||
#include <IOKit/IOKitLib.h> | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
// TODO: figure out what header contains IONVMeSMARTInterface declaration | ||
typedef struct IONVMeSMARTInterface { | ||
IUNKNOWN_C_GUTS; | ||
|
||
UInt16 version; | ||
UInt16 revision; | ||
|
||
// NVMe smart data, returns nvme_smart_log structure | ||
IOReturn (*SMARTReadData)(void *interface, | ||
void /* struct nvme_smart_log */ *NVMeSMARTData); | ||
|
||
// NVMe IdentifyData, returns nvme_id_ctrl per namespace | ||
IOReturn (*GetIdentifyData)( | ||
void *interface, | ||
void /* struct nvme_id_ctrl */ *NVMeIdentifyControllerStruct, | ||
unsigned int ns); | ||
UInt64 reserved0; | ||
UInt64 reserved1; | ||
|
||
// NumDWords Number of dwords for log page data, zero based. | ||
IOReturn (*GetLogPage)(void *interface, void *data, unsigned int logPageId, | ||
unsigned int numDWords); | ||
|
||
UInt64 reserved2; | ||
UInt64 reserved3; | ||
UInt64 reserved4; | ||
UInt64 reserved5; | ||
UInt64 reserved6; | ||
UInt64 reserved7; | ||
UInt64 reserved8; | ||
UInt64 reserved9; | ||
UInt64 reserved10; | ||
UInt64 reserved11; | ||
UInt64 reserved12; | ||
UInt64 reserved13; | ||
UInt64 reserved14; | ||
UInt64 reserved15; | ||
UInt64 reserved16; | ||
UInt64 reserved17; | ||
UInt64 reserved18; | ||
UInt64 reserved19; | ||
} IONVMeSMARTInterface; | ||
|
||
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_readlog_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.