]> git.proxmox.com Git - mirror_smartmontools-debian.git/blob - os_darwin.cpp
Updated changelog
[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
15 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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,v 1.21 2008/06/12 21:46:31 ballen4705 Exp $" \
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 dev_name = dev_name; // suppress unused warning.
78 return CONTROLLER_ATA;
79 }
80
81 // Determine whether 'dev' is a SMART-capable device.
82 static bool is_smart_capable (io_object_t dev) {
83 CFTypeRef smartCapableKey;
84 CFDictionaryRef diskChars;
85
86 // If the device has kIOPropertySMARTCapableKey, then it's capable,
87 // no matter what it looks like.
88 smartCapableKey = IORegistryEntryCreateCFProperty
89 (dev, CFSTR (kIOPropertySMARTCapableKey),
90 kCFAllocatorDefault, 0);
91 if (smartCapableKey)
92 {
93 CFRelease (smartCapableKey);
94 return true;
95 }
96
97 // If it's an kIOATABlockStorageDeviceClass then we're successful
98 // only if its ATA features indicate it supports SMART.
99 if (IOObjectConformsTo (dev, kIOATABlockStorageDeviceClass)
100 && (diskChars = (CFDictionaryRef)IORegistryEntryCreateCFProperty
101 (dev, CFSTR (kIOPropertyDeviceCharacteristicsKey),
102 kCFAllocatorDefault, kNilOptions)) != NULL)
103 {
104 CFNumberRef diskFeatures = NULL;
105 UInt32 ataFeatures = 0;
106
107 if (CFDictionaryGetValueIfPresent (diskChars, CFSTR ("ATA Features"),
108 (const void **)&diskFeatures))
109 CFNumberGetValue (diskFeatures, kCFNumberLongType,
110 &ataFeatures);
111 CFRelease (diskChars);
112 if (diskFeatures)
113 CFRelease (diskFeatures);
114
115 return (ataFeatures & kIOATAFeatureSMART) != 0;
116 }
117 return false;
118 }
119
120
121 // makes a list of ATA or SCSI devices for the DEVICESCAN directive of
122 // smartd. Returns number N of devices, or -1 if out of
123 // memory. Allocates N+1 arrays: one of N pointers (devlist); the
124 // other N arrays each contain null-terminated character strings. In
125 // the case N==0, no arrays are allocated because the array of 0
126 // pointers has zero length, equivalent to calling malloc(0).
127 int make_device_names (char*** devlist, const char* name) {
128 IOReturn err;
129 io_iterator_t i;
130 io_object_t device = MACH_PORT_NULL;
131 int result;
132 int index;
133
134 // We treat all devices as ATA so long as they support SMARTLib.
135 if (strcmp (name, "ATA") != 0)
136 return 0;
137
138 err = IOServiceGetMatchingServices
139 (kIOMasterPortDefault, IOServiceMatching (kIOBlockStorageDeviceClass), &i);
140 if (err != kIOReturnSuccess)
141 return -1;
142
143 // Count the devices.
144 result = 0;
145 while ((device = IOIteratorNext (i)) != MACH_PORT_NULL) {
146 if (is_smart_capable (device))
147 result++;
148 IOObjectRelease (device);
149 }
150
151 // Create an array of service names.
152 IOIteratorReset (i);
153 *devlist = (char**)Calloc (result, sizeof (char *));
154 if (! *devlist)
155 goto error;
156 index = 0;
157 while ((device = IOIteratorNext (i)) != MACH_PORT_NULL) {
158 if (is_smart_capable (device))
159 {
160 io_string_t devName;
161 IORegistryEntryGetPath(device, kIOServicePlane, devName);
162 (*devlist)[index] = CustomStrDup (devName, true, __LINE__, __FILE__);
163 if (! (*devlist)[index])
164 goto error;
165 index++;
166 }
167 IOObjectRelease (device);
168 }
169
170 IOObjectRelease (i);
171 return result;
172
173 error:
174 if (device != MACH_PORT_NULL)
175 IOObjectRelease (device);
176 IOObjectRelease (i);
177 if (*devlist)
178 {
179 for (index = 0; index < result; index++)
180 if ((*devlist)[index])
181 FreeNonZero ((*devlist)[index], 0, __LINE__, __FILE__);
182 FreeNonZero (*devlist, result * sizeof (char *), __LINE__, __FILE__);
183 }
184 return -1;
185 }
186
187 // Information that we keep about each device.
188
189 static struct {
190 io_object_t ioob;
191 IOCFPlugInInterface **plugin;
192 IOATASMARTInterface **smartIf;
193 } devices[20];
194
195 // Like open(). Return non-negative integer handle, only used by the
196 // functions below. type=="ATA" or "SCSI". The return value is
197 // an index into the devices[] array. If the device can't be opened,
198 // sets errno and returns -1.
199 // Acceptable device names are:
200 // /dev/disk*
201 // /dev/rdisk*
202 // disk*
203 // IOService:*
204 // IODeviceTree:*
205 int deviceopen(const char *pathname, char *type){
206 size_t devnum;
207 const char *devname;
208 io_object_t disk;
209
210 if (strcmp (type, "ATA") != 0)
211 {
212 errno = EINVAL;
213 return -1;
214 }
215
216 // Find a free device number.
217 for (devnum = 0; devnum < sizeof (devices) / sizeof (devices[0]); devnum++)
218 if (! devices[devnum].ioob)
219 break;
220 if (devnum == sizeof (devices) / sizeof (devices[0]))
221 {
222 errno = EMFILE;
223 return -1;
224 }
225
226 devname = NULL;
227 if (strncmp (pathname, "/dev/rdisk", 10) == 0)
228 devname = pathname + 6;
229 else if (strncmp (pathname, "/dev/disk", 9) == 0)
230 devname = pathname + 5;
231 else if (strncmp (pathname, "disk", 4) == 0)
232 // allow user to just say 'disk0'
233 devname = pathname;
234
235 // Find the device.
236 if (devname)
237 {
238 CFMutableDictionaryRef matcher;
239 matcher = IOBSDNameMatching (kIOMasterPortDefault, 0, devname);
240 disk = IOServiceGetMatchingService (kIOMasterPortDefault, matcher);
241 }
242 else
243 {
244 disk = IORegistryEntryFromPath (kIOMasterPortDefault, pathname);
245 }
246
247 if (! disk)
248 {
249 errno = ENOENT;
250 return -1;
251 }
252
253 // Find a SMART-capable driver which is a parent of this device.
254 while (! is_smart_capable (disk))
255 {
256 IOReturn err;
257 io_object_t prevdisk = disk;
258
259 // Find this device's parent and try again.
260 err = IORegistryEntryGetParentEntry (disk, kIOServicePlane, &disk);
261 if (err != kIOReturnSuccess || ! disk)
262 {
263 errno = ENODEV;
264 IOObjectRelease (prevdisk);
265 return -1;
266 }
267 }
268
269 devices[devnum].ioob = disk;
270
271 {
272 SInt32 dummy;
273
274 devices[devnum].plugin = NULL;
275 devices[devnum].smartIf = NULL;
276
277 // Create an interface to the ATA SMART library.
278 if (IOCreatePlugInInterfaceForService (disk,
279 kIOATASMARTUserClientTypeID,
280 kIOCFPlugInInterfaceID,
281 &devices[devnum].plugin,
282 &dummy) == kIOReturnSuccess)
283 (*devices[devnum].plugin)->QueryInterface
284 (devices[devnum].plugin,
285 CFUUIDGetUUIDBytes ( kIOATASMARTInterfaceID),
286 (void **)&devices[devnum].smartIf);
287 }
288
289 return devnum;
290 }
291
292 // Like close(). Acts only on integer handles returned by
293 // deviceopen() above.
294 int deviceclose(int fd){
295 if (devices[fd].smartIf)
296 (*devices[fd].smartIf)->Release (devices[fd].smartIf);
297 if (devices[fd].plugin)
298 IODestroyPlugInInterface (devices[fd].plugin);
299 IOObjectRelease (devices[fd].ioob);
300 devices[fd].ioob = MACH_PORT_NULL;
301 return 0;
302 }
303
304 // Interface to ATA devices. See os_linux.cpp for the cannonical example.
305 // DETAILED DESCRIPTION OF ARGUMENTS
306 // device: is the integer handle provided by deviceopen()
307 // command: defines the different operations, see atacmds.h
308 // select: additional input data IF NEEDED (which log, which type of
309 // self-test).
310 // data: location to write output data, IF NEEDED (1 or 512 bytes).
311 // Note: not all commands use all arguments.
312 // RETURN VALUES (for all commands BUT command==STATUS_CHECK)
313 // -1 if the command failed
314 // 0 if the command succeeded,
315 // RETURN VALUES if command==STATUS_CHECK
316 // -1 if the command failed OR the disk SMART status can't be determined
317 // 0 if the command succeeded and disk SMART status is "OK"
318 // 1 if the command succeeded and disk SMART status is "FAILING"
319
320 // Things that aren't available in the Darwin interfaces:
321 // - Tests other than short and extended (in particular, can't run
322 // an immediate offline test)
323 // - Captive-mode tests, aborting tests
324 // - ability to switch automatic offline testing on or off
325
326 // Note that some versions of Darwin, at least 7H63 and earlier,
327 // have a buggy library that treats the boolean value in
328 // SMARTEnableDisableOperations, SMARTEnableDisableAutosave, and
329 // SMARTExecuteOffLineImmediate as always being true.
330 int
331 ata_command_interface(int fd, smart_command_set command,
332 int select, char *data)
333 {
334 IOATASMARTInterface **ifp = devices[fd].smartIf;
335 IOATASMARTInterface *smartIf;
336 IOReturn err;
337 int timeoutCount = 5;
338
339 if (! ifp)
340 return -1;
341 smartIf = *ifp;
342
343 do {
344 switch (command)
345 {
346 case STATUS:
347 return 0;
348 case STATUS_CHECK:
349 {
350 Boolean is_failing;
351 err = smartIf->SMARTReturnStatus (ifp, &is_failing);
352 if (err == kIOReturnSuccess && is_failing)
353 return 1;
354 break;
355 }
356 case ENABLE:
357 case DISABLE:
358 err = smartIf->SMARTEnableDisableOperations (ifp, command == ENABLE);
359 break;
360 case AUTOSAVE:
361 err = smartIf->SMARTEnableDisableAutosave (ifp, select != 0);
362 break;
363 case IMMEDIATE_OFFLINE:
364 if (select != SHORT_SELF_TEST && select != EXTEND_SELF_TEST)
365 {
366 errno = EINVAL;
367 return -1;
368 }
369 err = smartIf->SMARTExecuteOffLineImmediate (ifp,
370 select == EXTEND_SELF_TEST);
371 break;
372 case READ_VALUES:
373 err = smartIf->SMARTReadData (ifp, (ATASMARTData *)data);
374 break;
375 case READ_THRESHOLDS:
376 err = smartIf->SMARTReadDataThresholds (ifp,
377 (ATASMARTDataThresholds *)data);
378 break;
379 case READ_LOG:
380 err = smartIf->SMARTReadLogAtAddress (ifp, select, data, 512);
381 break;
382 case WRITE_LOG:
383 err = smartIf->SMARTWriteLogAtAddress (ifp, select, data, 512);
384 break;
385 case IDENTIFY:
386 {
387 UInt32 dummy;
388 err = smartIf->GetATAIdentifyData (ifp, data, 512, &dummy);
389 if (err != kIOReturnSuccess && err != kIOReturnTimeout
390 && err != kIOReturnNotResponding)
391 printf ("identify failed: %#x\n", (unsigned) err);
392 if (err == kIOReturnSuccess && isbigendian())
393 {
394 int i;
395 /* The system has already byte-swapped, undo it. */
396 for (i = 0; i < 256; i+=2)
397 swap2 (data + i);
398 }
399 }
400 break;
401 case CHECK_POWER_MODE:
402 // The information is right there in the device registry, but how
403 // to get to it portably?
404 default:
405 errno = ENOTSUP;
406 return -1;
407 }
408 /* This bit is a bit strange. Apparently, when the drive is spun
409 down, the intended behaviour of these calls is that they fail,
410 return kIOReturnTimeout and then power the drive up. So if
411 you get a timeout, you have to try again to get the actual
412 command run, but the drive is already powering up so you can't
413 use this for CHECK_POWER_MODE. */
414 if (err == kIOReturnTimeout || err == kIOReturnNotResponding)
415 sleep (1);
416 } while ((err == kIOReturnTimeout || err == kIOReturnNotResponding)
417 && timeoutCount-- > 0);
418 if (err == kIOReturnExclusiveAccess)
419 errno = EBUSY;
420 return err == kIOReturnSuccess ? 0 : -1;
421 }
422
423 // There's no special handling needed for hidden devices, the kernel
424 // must deal with them.
425 int escalade_command_interface(int fd, int escalade_port, int escalade_type,
426 smart_command_set command, int select,
427 char *data)
428 {
429 fd = fd;
430 escalade_port = escalade_port;
431 escalade_type = escalade_type;
432 command = command;
433 select = select;
434 data = data;
435 return -1;
436 }
437
438 int areca_command_interface(int fd, int escalade_port,
439 smart_command_set command, int select,
440 char *data)
441 {
442 fd = fd;
443 escalade_port = escalade_port;
444 command = command;
445 select = select;
446 data = data;
447 return -1;
448 }
449
450
451
452
453 int marvell_command_interface(int fd, smart_command_set command,
454 int select, char *data)
455 {
456 fd = fd;
457 command = command;
458 select = select;
459 data = data;
460 return -1;
461 }
462
463 int highpoint_command_interface(int fd, smart_command_set command, int select, char *data)
464 {
465 fd = fd;
466 command = command;
467 select = select;
468 data = data;
469 return -1;
470 }
471
472 // Interface to SCSI devices. See os_linux.c
473 int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report) {
474 fd = fd;
475 iop = iop;
476 report = report;
477 return -ENOSYS;
478 }