]> git.proxmox.com Git - mirror_smartmontools-debian.git/blob - os_darwin.cpp
Imported Upstream version 6.1+svn3812
[mirror_smartmontools-debian.git] / os_darwin.cpp
1 /*
2 * os_darwin.c
3 *
4 * Home page of code is: http://smartmontools.sourceforge.net
5 *
6 * Copyright (C) 2004-8 Geoffrey Keating <geoffk@geoffk.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * You should have received a copy of the GNU General Public License
14 * (for example COPYING); if not, write to the Free Software Foundation,
15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18 #include <stdbool.h>
19 #include <errno.h>
20 #include <unistd.h>
21 #include <mach/mach.h>
22 #include <mach/mach_error.h>
23 #include <mach/mach_init.h>
24 #include <IOKit/IOCFPlugIn.h>
25 #include <IOKit/IOKitLib.h>
26 #include <IOKit/IOReturn.h>
27 #include <IOKit/IOBSD.h>
28 #include <IOKit/storage/IOBlockStorageDevice.h>
29 #include <IOKit/storage/IOStorageDeviceCharacteristics.h>
30 #include <IOKit/storage/IOMedia.h>
31 #include <IOKit/storage/ata/IOATAStorageDefines.h>
32 #include <IOKit/storage/ata/ATASMARTLib.h>
33 #include <CoreFoundation/CoreFoundation.h>
34
35 // No, I don't know why there isn't a header for this.
36 #define kIOATABlockStorageDeviceClass "IOATABlockStorageDevice"
37
38 #include "config.h"
39 #include "int64.h"
40 #include "atacmds.h"
41 #include "scsicmds.h"
42 #include "utility.h"
43
44 #include "os_darwin.h"
45
46 // Needed by '-V' option (CVS versioning) of smartd/smartctl
47 const char *os_XXXX_c_cvsid="$Id: os_darwin.cpp 3805 2013-03-29 19:54:18Z chrfranke $" \
48 ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_DARWIN_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
49
50 // Print examples for smartctl.
51 void print_smartctl_examples(){
52 printf("=================================================== SMARTCTL EXAMPLES =====\n\n");
53 printf(
54 " smartctl -a disk0 (Prints all SMART information)\n\n"
55 " smartctl -t long /dev/disk0 (Executes extended disk self-test)\n\n"
56 #ifdef HAVE_GETOPT_LONG
57 " smartctl --smart=on --saveauto=on /dev/rdisk0 (Enables SMART on first disk)\n\n"
58 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/disk0\n"
59 " (Prints Self-Test & Attribute errors)\n\n"
60 #else
61 " smartctl -s on -S on /dev/rdisk0 (Enables SMART on first disk)\n\n"
62 " smartctl -A -l selftest -q errorsonly /dev/disk0\n"
63 " (Prints Self-Test & Attribute errors)\n\n"
64 #endif
65 " smartctl -a IOService:/MacRISC2PE/pci@f4000000/AppleMacRiscPCI/ata-6@D/AppleKauaiATA/ATADeviceNub@0/IOATABlockStorageDriver/IOATABlockStorageDevice\n"
66 " (You can use IOService: ...)\n\n"
67 " smartctl -c IODeviceTree:/pci@f4000000/ata-6@D/@0:0\n"
68 " (... Or IODeviceTree:)\n"
69 );
70 return;
71 }
72
73 // tries to guess device type given the name (a path). See utility.h
74 // for return values.
75 int guess_device_type (const char * /* dev_name */) {
76 // Only ATA is supported right now, so that's what it'd better be.
77 return CONTROLLER_ATA;
78 }
79
80 // Determine whether 'dev' is a SMART-capable device.
81 static bool is_smart_capable (io_object_t dev) {
82 CFTypeRef smartCapableKey;
83 CFDictionaryRef diskChars;
84
85 // If the device has kIOPropertySMARTCapableKey, then it's capable,
86 // no matter what it looks like.
87 smartCapableKey = IORegistryEntryCreateCFProperty
88 (dev, CFSTR (kIOPropertySMARTCapableKey),
89 kCFAllocatorDefault, 0);
90 if (smartCapableKey)
91 {
92 CFRelease (smartCapableKey);
93 return true;
94 }
95
96 // If it's an kIOATABlockStorageDeviceClass then we're successful
97 // only if its ATA features indicate it supports SMART.
98 if (IOObjectConformsTo (dev, kIOATABlockStorageDeviceClass)
99 && (diskChars = (CFDictionaryRef)IORegistryEntryCreateCFProperty
100 (dev, CFSTR (kIOPropertyDeviceCharacteristicsKey),
101 kCFAllocatorDefault, kNilOptions)) != NULL)
102 {
103 CFNumberRef diskFeatures = NULL;
104 UInt32 ataFeatures = 0;
105
106 if (CFDictionaryGetValueIfPresent (diskChars, CFSTR ("ATA Features"),
107 (const void **)&diskFeatures))
108 CFNumberGetValue (diskFeatures, kCFNumberLongType,
109 &ataFeatures);
110 CFRelease (diskChars);
111 if (diskFeatures)
112 CFRelease (diskFeatures);
113
114 return (ataFeatures & kIOATAFeatureSMART) != 0;
115 }
116 return false;
117 }
118
119
120 // makes a list of ATA or SCSI devices for the DEVICESCAN directive of
121 // smartd. Returns number N of devices, or -1 if out of
122 // memory. Allocates N+1 arrays: one of N pointers (devlist); the
123 // other N arrays each contain null-terminated character strings. In
124 // the case N==0, no arrays are allocated because the array of 0
125 // pointers has zero length, equivalent to calling malloc(0).
126 int make_device_names (char*** devlist, const char* name) {
127 IOReturn err;
128 io_iterator_t i;
129 io_object_t device = MACH_PORT_NULL;
130 int result;
131 int index;
132
133 // We treat all devices as ATA so long as they support SMARTLib.
134 if (strcmp (name, "ATA") != 0)
135 return 0;
136
137 err = IOServiceGetMatchingServices
138 (kIOMasterPortDefault, IOServiceMatching (kIOBlockStorageDeviceClass), &i);
139 if (err != kIOReturnSuccess)
140 return -1;
141
142 // Count the devices.
143 result = 0;
144 while ((device = IOIteratorNext (i)) != MACH_PORT_NULL) {
145 if (is_smart_capable (device))
146 result++;
147 IOObjectRelease (device);
148 }
149
150 // Create an array of service names.
151 IOIteratorReset (i);
152 *devlist = (char**)Calloc (result, sizeof (char *));
153 if (! *devlist)
154 goto error;
155 index = 0;
156 while ((device = IOIteratorNext (i)) != MACH_PORT_NULL) {
157 if (is_smart_capable (device))
158 {
159 io_string_t devName;
160 IORegistryEntryGetPath(device, kIOServicePlane, devName);
161 (*devlist)[index] = CustomStrDup (devName, true, __LINE__, __FILE__);
162 if (! (*devlist)[index])
163 goto error;
164 index++;
165 }
166 IOObjectRelease (device);
167 }
168
169 IOObjectRelease (i);
170 return result;
171
172 error:
173 if (device != MACH_PORT_NULL)
174 IOObjectRelease (device);
175 IOObjectRelease (i);
176 if (*devlist)
177 {
178 for (index = 0; index < result; index++)
179 if ((*devlist)[index])
180 FreeNonZero ((*devlist)[index], 0, __LINE__, __FILE__);
181 FreeNonZero (*devlist, result * sizeof (char *), __LINE__, __FILE__);
182 }
183 return -1;
184 }
185
186 // Information that we keep about each device.
187
188 static struct {
189 io_object_t ioob;
190 IOCFPlugInInterface **plugin;
191 IOATASMARTInterface **smartIf;
192 } devices[20];
193
194 // Like open(). Return non-negative integer handle, only used by the
195 // functions below. type=="ATA" or "SCSI". The return value is
196 // an index into the devices[] array. If the device can't be opened,
197 // sets errno and returns -1.
198 // Acceptable device names are:
199 // /dev/disk*
200 // /dev/rdisk*
201 // disk*
202 // IOService:*
203 // IODeviceTree:*
204 int deviceopen(const char *pathname, char *type){
205 size_t devnum;
206 const char *devname;
207 io_object_t disk;
208
209 if (strcmp (type, "ATA") != 0)
210 {
211 errno = EINVAL;
212 return -1;
213 }
214
215 // Find a free device number.
216 for (devnum = 0; devnum < sizeof (devices) / sizeof (devices[0]); devnum++)
217 if (! devices[devnum].ioob)
218 break;
219 if (devnum == sizeof (devices) / sizeof (devices[0]))
220 {
221 errno = EMFILE;
222 return -1;
223 }
224
225 devname = NULL;
226 if (strncmp (pathname, "/dev/rdisk", 10) == 0)
227 devname = pathname + 6;
228 else if (strncmp (pathname, "/dev/disk", 9) == 0)
229 devname = pathname + 5;
230 else if (strncmp (pathname, "disk", 4) == 0)
231 // allow user to just say 'disk0'
232 devname = pathname;
233
234 // Find the device.
235 if (devname)
236 {
237 CFMutableDictionaryRef matcher;
238 matcher = IOBSDNameMatching (kIOMasterPortDefault, 0, devname);
239 disk = IOServiceGetMatchingService (kIOMasterPortDefault, matcher);
240 }
241 else
242 {
243 disk = IORegistryEntryFromPath (kIOMasterPortDefault, pathname);
244 }
245
246 if (! disk)
247 {
248 errno = ENOENT;
249 return -1;
250 }
251
252 // Find a SMART-capable driver which is a parent of this device.
253 while (! is_smart_capable (disk))
254 {
255 IOReturn err;
256 io_object_t prevdisk = disk;
257
258 // Find this device's parent and try again.
259 err = IORegistryEntryGetParentEntry (disk, kIOServicePlane, &disk);
260 if (err != kIOReturnSuccess || ! disk)
261 {
262 errno = ENODEV;
263 IOObjectRelease (prevdisk);
264 return -1;
265 }
266 }
267
268 devices[devnum].ioob = disk;
269
270 {
271 SInt32 dummy;
272
273 devices[devnum].plugin = NULL;
274 devices[devnum].smartIf = NULL;
275
276 // Create an interface to the ATA SMART library.
277 if (IOCreatePlugInInterfaceForService (disk,
278 kIOATASMARTUserClientTypeID,
279 kIOCFPlugInInterfaceID,
280 &devices[devnum].plugin,
281 &dummy) == kIOReturnSuccess)
282 (*devices[devnum].plugin)->QueryInterface
283 (devices[devnum].plugin,
284 CFUUIDGetUUIDBytes ( kIOATASMARTInterfaceID),
285 (void **)&devices[devnum].smartIf);
286 }
287
288 return devnum;
289 }
290
291 // Like close(). Acts only on integer handles returned by
292 // deviceopen() above.
293 int deviceclose(int fd){
294 if (devices[fd].smartIf)
295 (*devices[fd].smartIf)->Release (devices[fd].smartIf);
296 if (devices[fd].plugin)
297 IODestroyPlugInInterface (devices[fd].plugin);
298 IOObjectRelease (devices[fd].ioob);
299 devices[fd].ioob = MACH_PORT_NULL;
300 return 0;
301 }
302
303 // Interface to ATA devices. See os_linux.cpp for the cannonical example.
304 // DETAILED DESCRIPTION OF ARGUMENTS
305 // device: is the integer handle provided by deviceopen()
306 // command: defines the different operations, see atacmds.h
307 // select: additional input data IF NEEDED (which log, which type of
308 // self-test).
309 // data: location to write output data, IF NEEDED (1 or 512 bytes).
310 // Note: not all commands use all arguments.
311 // RETURN VALUES (for all commands BUT command==STATUS_CHECK)
312 // -1 if the command failed
313 // 0 if the command succeeded,
314 // RETURN VALUES if command==STATUS_CHECK
315 // -1 if the command failed OR the disk SMART status can't be determined
316 // 0 if the command succeeded and disk SMART status is "OK"
317 // 1 if the command succeeded and disk SMART status is "FAILING"
318
319 // Things that aren't available in the Darwin interfaces:
320 // - Tests other than short and extended (in particular, can't run
321 // an immediate offline test)
322 // - Captive-mode tests, aborting tests
323 // - ability to switch automatic offline testing on or off
324
325 // Note that some versions of Darwin, at least 7H63 and earlier,
326 // have a buggy library that treats the boolean value in
327 // SMARTEnableDisableOperations, SMARTEnableDisableAutosave, and
328 // SMARTExecuteOffLineImmediate as always being true.
329 int
330 ata_command_interface(int fd, smart_command_set command,
331 int select, char *data)
332 {
333 IOATASMARTInterface **ifp = devices[fd].smartIf;
334 IOATASMARTInterface *smartIf;
335 IOReturn err;
336 int timeoutCount = 5;
337
338 if (! ifp)
339 return -1;
340 smartIf = *ifp;
341
342 do {
343 switch (command)
344 {
345 case STATUS:
346 return 0;
347 case STATUS_CHECK:
348 {
349 Boolean is_failing;
350 err = smartIf->SMARTReturnStatus (ifp, &is_failing);
351 if (err == kIOReturnSuccess && is_failing)
352 return 1;
353 break;
354 }
355 case ENABLE:
356 case DISABLE:
357 err = smartIf->SMARTEnableDisableOperations (ifp, command == ENABLE);
358 break;
359 case AUTOSAVE:
360 err = smartIf->SMARTEnableDisableAutosave (ifp, select != 0);
361 break;
362 case IMMEDIATE_OFFLINE:
363 if (select != SHORT_SELF_TEST && select != EXTEND_SELF_TEST)
364 {
365 errno = EINVAL;
366 return -1;
367 }
368 err = smartIf->SMARTExecuteOffLineImmediate (ifp,
369 select == EXTEND_SELF_TEST);
370 break;
371 case READ_VALUES:
372 err = smartIf->SMARTReadData (ifp, (ATASMARTData *)data);
373 break;
374 case READ_THRESHOLDS:
375 err = smartIf->SMARTReadDataThresholds (ifp,
376 (ATASMARTDataThresholds *)data);
377 break;
378 case READ_LOG:
379 err = smartIf->SMARTReadLogAtAddress (ifp, select, data, 512);
380 break;
381 case WRITE_LOG:
382 err = smartIf->SMARTWriteLogAtAddress (ifp, select, data, 512);
383 break;
384 case IDENTIFY:
385 {
386 UInt32 dummy;
387 err = smartIf->GetATAIdentifyData (ifp, data, 512, &dummy);
388 if (err != kIOReturnSuccess && err != kIOReturnTimeout
389 && err != kIOReturnNotResponding)
390 printf ("identify failed: %#x\n", (unsigned) err);
391 if (err == kIOReturnSuccess && isbigendian())
392 {
393 int i;
394 /* The system has already byte-swapped, undo it. */
395 for (i = 0; i < 256; i+=2)
396 swap2 (data + i);
397 }
398 }
399 break;
400 case CHECK_POWER_MODE:
401 // The information is right there in the device registry, but how
402 // to get to it portably?
403 default:
404 errno = ENOTSUP;
405 return -1;
406 }
407 /* This bit is a bit strange. Apparently, when the drive is spun
408 down, the intended behaviour of these calls is that they fail,
409 return kIOReturnTimeout and then power the drive up. So if
410 you get a timeout, you have to try again to get the actual
411 command run, but the drive is already powering up so you can't
412 use this for CHECK_POWER_MODE. */
413 if (err == kIOReturnTimeout || err == kIOReturnNotResponding)
414 sleep (1);
415 } while ((err == kIOReturnTimeout || err == kIOReturnNotResponding)
416 && timeoutCount-- > 0);
417 if (err == kIOReturnExclusiveAccess)
418 errno = EBUSY;
419 return err == kIOReturnSuccess ? 0 : -1;
420 }
421
422 // Interface to SCSI devices. See os_linux.c
423 int do_scsi_cmnd_io(int /* fd */, struct scsi_cmnd_io * /* iop */, int /* report */) {
424 return -ENOSYS;
425 }