-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathnvme_darwin.cpp
101 lines (81 loc) · 2.82 KB
/
nvme_darwin.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// SPDX-License-Identifier: MIT
#include "nvme_darwin.h"
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/storage/nvme/NVMeSMARTLibExternal.h>
#include <stdlib.h>
struct smart_nvme_darwin {
IONVMeSMARTInterface **smartIfNVMe;
IOCFPlugInInterface **plugin;
io_object_t disk;
};
static 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, void **ptr) {
// see also https://gist.github.com/AlanQuatermain/250538
SInt32 score = 0;
int res = EINVAL;
IONVMeSMARTInterface **smartIfNVMe;
IOCFPlugInInterface **plugin;
struct smart_nvme_darwin *nvme;
CFMutableDictionaryRef matcher = IOBSDNameMatching(kIOMainPortDefault, 0, path);
io_object_t disk = IOServiceGetMatchingService(kIOMainPortDefault, 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;
}
res = IOCreatePlugInInterfaceForService(disk, kIONVMeSMARTUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, &score);
if (res != kIOReturnSuccess)
goto exit2;
res = (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIONVMeSMARTInterfaceID), (void **)&smartIfNVMe);
if (res != S_OK)
goto exit3;
*ptr = malloc(sizeof(struct smart_nvme_darwin));
nvme = (struct smart_nvme_darwin *)*ptr;
if (!nvme)
goto exit4;
nvme->disk = disk;
nvme->plugin = plugin;
nvme->smartIfNVMe = smartIfNVMe;
return 0;
exit4:
(*smartIfNVMe)->Release(smartIfNVMe);
exit3:
IODestroyPlugInInterface(plugin);
exit2:
IOObjectRelease(disk);
exit1:
return res;
}
unsigned int smart_nvme_identify_darwin(void *ptr, void *buffer, unsigned int nsid) {
struct smart_nvme_darwin *nvme = (struct smart_nvme_darwin *)ptr;
return (*nvme->smartIfNVMe)->GetIdentifyData(nvme->smartIfNVMe, buffer, nsid);
}
unsigned int smart_nvme_readsmart_darwin(void *ptr, void *buffer) {
struct smart_nvme_darwin *nvme = (struct smart_nvme_darwin *)ptr;
return (*nvme->smartIfNVMe)->SMARTReadData(nvme->smartIfNVMe, (struct NVMeSMARTData *)buffer);
}
void smart_nvme_close_darwin(void *ptr) {
struct smart_nvme_darwin *nvme = (struct smart_nvme_darwin *)ptr;
(*nvme->smartIfNVMe)->Release(nvme->smartIfNVMe);
IODestroyPlugInInterface(nvme->plugin);
IOObjectRelease(nvme->disk);
free(nvme);
}