]> git.proxmox.com Git - mirror_smartmontools-debian.git/blame - os_darwin.cpp
Imported Upstream version 6.1+svn3812
[mirror_smartmontools-debian.git] / os_darwin.cpp
CommitLineData
832b75ed
GG
1/*
2 * os_darwin.c
3 *
4 * Home page of code is: http://smartmontools.sourceforge.net
5 *
34ad0c5f 6 * Copyright (C) 2004-8 Geoffrey Keating <geoffk@geoffk.org>
832b75ed
GG
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
ee38a438
GI
14 * (for example COPYING); if not, write to the Free Software Foundation,
15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
832b75ed
GG
16 */
17
18#include <stdbool.h>
19#include <errno.h>
a37e7145 20#include <unistd.h>
832b75ed
GG
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>
4d59bff9 28#include <IOKit/storage/IOBlockStorageDevice.h>
832b75ed
GG
29#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
30#include <IOKit/storage/IOMedia.h>
4d59bff9
GG
31#include <IOKit/storage/ata/IOATAStorageDefines.h>
32#include <IOKit/storage/ata/ATASMARTLib.h>
832b75ed
GG
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
ee38a438 47const char *os_XXXX_c_cvsid="$Id: os_darwin.cpp 3805 2013-03-29 19:54:18Z chrfranke $" \
832b75ed
GG
48ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_DARWIN_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
49
50// Print examples for smartctl.
51void 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.
ee38a438 75int guess_device_type (const char * /* dev_name */) {
832b75ed 76 // Only ATA is supported right now, so that's what it'd better be.
832b75ed
GG
77 return CONTROLLER_ATA;
78}
79
4d59bff9
GG
80// Determine whether 'dev' is a SMART-capable device.
81static 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
832b75ed
GG
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).
126int make_device_names (char*** devlist, const char* name) {
127 IOReturn err;
128 io_iterator_t i;
4d59bff9 129 io_object_t device = MACH_PORT_NULL;
832b75ed
GG
130 int result;
131 int index;
832b75ed 132
4d59bff9
GG
133 // We treat all devices as ATA so long as they support SMARTLib.
134 if (strcmp (name, "ATA") != 0)
832b75ed
GG
135 return 0;
136
4d59bff9
GG
137 err = IOServiceGetMatchingServices
138 (kIOMasterPortDefault, IOServiceMatching (kIOBlockStorageDeviceClass), &i);
832b75ed
GG
139 if (err != kIOReturnSuccess)
140 return -1;
141
142 // Count the devices.
4d59bff9
GG
143 result = 0;
144 while ((device = IOIteratorNext (i)) != MACH_PORT_NULL) {
145 if (is_smart_capable (device))
146 result++;
832b75ed 147 IOObjectRelease (device);
4d59bff9 148 }
832b75ed
GG
149
150 // Create an array of service names.
151 IOIteratorReset (i);
4d59bff9 152 *devlist = (char**)Calloc (result, sizeof (char *));
832b75ed
GG
153 if (! *devlist)
154 goto error;
4d59bff9
GG
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 }
832b75ed 168
832b75ed 169 IOObjectRelease (i);
832b75ed
GG
170 return result;
171
172 error:
4d59bff9
GG
173 if (device != MACH_PORT_NULL)
174 IOObjectRelease (device);
832b75ed
GG
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
188static struct {
189 io_object_t ioob;
832b75ed
GG
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:*
204int 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
4d59bff9
GG
252 // Find a SMART-capable driver which is a parent of this device.
253 while (! is_smart_capable (disk))
832b75ed
GG
254 {
255 IOReturn err;
4d59bff9 256 io_object_t prevdisk = disk;
832b75ed 257
4d59bff9
GG
258 // Find this device's parent and try again.
259 err = IORegistryEntryGetParentEntry (disk, kIOServicePlane, &disk);
832b75ed
GG
260 if (err != kIOReturnSuccess || ! disk)
261 {
262 errno = ENODEV;
4d59bff9 263 IOObjectRelease (prevdisk);
832b75ed
GG
264 return -1;
265 }
266 }
832b75ed 267
4d59bff9
GG
268 devices[devnum].ioob = disk;
269
832b75ed
GG
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.
4d59bff9
GG
277 if (IOCreatePlugInInterfaceForService (disk,
278 kIOATASMARTUserClientTypeID,
279 kIOCFPlugInInterfaceID,
280 &devices[devnum].plugin,
281 &dummy) == kIOReturnSuccess)
832b75ed
GG
282 (*devices[devnum].plugin)->QueryInterface
283 (devices[devnum].plugin,
284 CFUUIDGetUUIDBytes ( kIOATASMARTInterfaceID),
4d59bff9 285 (void **)&devices[devnum].smartIf);
832b75ed
GG
286 }
287
288 return devnum;
289}
290
291// Like close(). Acts only on integer handles returned by
292// deviceopen() above.
293int 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
4d59bff9 303// Interface to ATA devices. See os_linux.cpp for the cannonical example.
832b75ed
GG
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.
832b75ed
GG
329int
330ata_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;
a37e7145 336 int timeoutCount = 5;
832b75ed
GG
337
338 if (! ifp)
339 return -1;
340 smartIf = *ifp;
341
4d59bff9
GG
342 do {
343 switch (command)
832b75ed 344 {
4d59bff9
GG
345 case STATUS:
346 return 0;
347 case STATUS_CHECK:
832b75ed 348 {
4d59bff9
GG
349 Boolean is_failing;
350 err = smartIf->SMARTReturnStatus (ifp, &is_failing);
351 if (err == kIOReturnSuccess && is_failing)
352 return 1;
353 break;
832b75ed 354 }
4d59bff9
GG
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)
832b75ed 364 {
4d59bff9
GG
365 errno = EINVAL;
366 return -1;
832b75ed 367 }
4d59bff9
GG
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);
a37e7145
GG
388 if (err != kIOReturnSuccess && err != kIOReturnTimeout
389 && err != kIOReturnNotResponding)
390 printf ("identify failed: %#x\n", (unsigned) err);
4d59bff9
GG
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;
832b75ed 406 }
4d59bff9
GG
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. */
a37e7145
GG
413 if (err == kIOReturnTimeout || err == kIOReturnNotResponding)
414 sleep (1);
415 } while ((err == kIOReturnTimeout || err == kIOReturnNotResponding)
416 && timeoutCount-- > 0);
832b75ed
GG
417 if (err == kIOReturnExclusiveAccess)
418 errno = EBUSY;
419 return err == kIOReturnSuccess ? 0 : -1;
420}
421
832b75ed 422// Interface to SCSI devices. See os_linux.c
ee38a438 423int do_scsi_cmnd_io(int /* fd */, struct scsi_cmnd_io * /* iop */, int /* report */) {
832b75ed
GG
424 return -ENOSYS;
425}