]> git.proxmox.com Git - mirror_smartmontools-debian.git/blame - os_darwin.cpp
Updated changelog
[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
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>
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
2127e193 47const char *os_XXXX_c_cvsid="$Id: os_darwin.cpp,v 1.21 2008/06/12 21:46:31 ballen4705 Exp $" \
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.
75int 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
4d59bff9
GG
81// Determine whether 'dev' is a SMART-capable device.
82static 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
832b75ed
GG
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).
127int make_device_names (char*** devlist, const char* name) {
128 IOReturn err;
129 io_iterator_t i;
4d59bff9 130 io_object_t device = MACH_PORT_NULL;
832b75ed
GG
131 int result;
132 int index;
832b75ed 133
4d59bff9
GG
134 // We treat all devices as ATA so long as they support SMARTLib.
135 if (strcmp (name, "ATA") != 0)
832b75ed
GG
136 return 0;
137
4d59bff9
GG
138 err = IOServiceGetMatchingServices
139 (kIOMasterPortDefault, IOServiceMatching (kIOBlockStorageDeviceClass), &i);
832b75ed
GG
140 if (err != kIOReturnSuccess)
141 return -1;
142
143 // Count the devices.
4d59bff9
GG
144 result = 0;
145 while ((device = IOIteratorNext (i)) != MACH_PORT_NULL) {
146 if (is_smart_capable (device))
147 result++;
832b75ed 148 IOObjectRelease (device);
4d59bff9 149 }
832b75ed
GG
150
151 // Create an array of service names.
152 IOIteratorReset (i);
4d59bff9 153 *devlist = (char**)Calloc (result, sizeof (char *));
832b75ed
GG
154 if (! *devlist)
155 goto error;
4d59bff9
GG
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 }
832b75ed 169
832b75ed 170 IOObjectRelease (i);
832b75ed
GG
171 return result;
172
173 error:
4d59bff9
GG
174 if (device != MACH_PORT_NULL)
175 IOObjectRelease (device);
832b75ed
GG
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
189static struct {
190 io_object_t ioob;
832b75ed
GG
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:*
205int 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
4d59bff9
GG
253 // Find a SMART-capable driver which is a parent of this device.
254 while (! is_smart_capable (disk))
832b75ed
GG
255 {
256 IOReturn err;
4d59bff9 257 io_object_t prevdisk = disk;
832b75ed 258
4d59bff9
GG
259 // Find this device's parent and try again.
260 err = IORegistryEntryGetParentEntry (disk, kIOServicePlane, &disk);
832b75ed
GG
261 if (err != kIOReturnSuccess || ! disk)
262 {
263 errno = ENODEV;
4d59bff9 264 IOObjectRelease (prevdisk);
832b75ed
GG
265 return -1;
266 }
267 }
832b75ed 268
4d59bff9
GG
269 devices[devnum].ioob = disk;
270
832b75ed
GG
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.
4d59bff9
GG
278 if (IOCreatePlugInInterfaceForService (disk,
279 kIOATASMARTUserClientTypeID,
280 kIOCFPlugInInterfaceID,
281 &devices[devnum].plugin,
282 &dummy) == kIOReturnSuccess)
832b75ed
GG
283 (*devices[devnum].plugin)->QueryInterface
284 (devices[devnum].plugin,
285 CFUUIDGetUUIDBytes ( kIOATASMARTInterfaceID),
4d59bff9 286 (void **)&devices[devnum].smartIf);
832b75ed
GG
287 }
288
289 return devnum;
290}
291
292// Like close(). Acts only on integer handles returned by
293// deviceopen() above.
294int 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
4d59bff9 304// Interface to ATA devices. See os_linux.cpp for the cannonical example.
832b75ed
GG
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.
832b75ed
GG
330int
331ata_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;
a37e7145 337 int timeoutCount = 5;
832b75ed
GG
338
339 if (! ifp)
340 return -1;
341 smartIf = *ifp;
342
4d59bff9
GG
343 do {
344 switch (command)
832b75ed 345 {
4d59bff9
GG
346 case STATUS:
347 return 0;
348 case STATUS_CHECK:
832b75ed 349 {
4d59bff9
GG
350 Boolean is_failing;
351 err = smartIf->SMARTReturnStatus (ifp, &is_failing);
352 if (err == kIOReturnSuccess && is_failing)
353 return 1;
354 break;
832b75ed 355 }
4d59bff9
GG
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)
832b75ed 365 {
4d59bff9
GG
366 errno = EINVAL;
367 return -1;
832b75ed 368 }
4d59bff9
GG
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);
a37e7145
GG
389 if (err != kIOReturnSuccess && err != kIOReturnTimeout
390 && err != kIOReturnNotResponding)
391 printf ("identify failed: %#x\n", (unsigned) err);
4d59bff9
GG
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;
832b75ed 407 }
4d59bff9
GG
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. */
a37e7145
GG
414 if (err == kIOReturnTimeout || err == kIOReturnNotResponding)
415 sleep (1);
416 } while ((err == kIOReturnTimeout || err == kIOReturnNotResponding)
417 && timeoutCount-- > 0);
832b75ed
GG
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.
425int 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
2127e193
GI
438int 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
4d59bff9
GG
453int 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
463int 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
832b75ed
GG
472// Interface to SCSI devices. See os_linux.c
473int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report) {
4d59bff9
GG
474 fd = fd;
475 iop = iop;
476 report = report;
832b75ed
GG
477 return -ENOSYS;
478}