4 * Home page of code is: http://smartmontools.sourceforge.net
6 * Copyright (C) 2004-6 Geoffrey Keating <geoffk@geoffk.org>
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)
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.
20 #include <mach/mach.h>
21 #include <mach/mach_error.h>
22 #include <mach/mach_init.h>
23 #include <IOKit/IOCFPlugIn.h>
24 #include <IOKit/IOKitLib.h>
25 #include <IOKit/IOReturn.h>
26 #include <IOKit/IOBSD.h>
27 #include <IOKit/storage/ata/IOATAStorageDefines.h>
28 #include <IOKit/storage/ata/ATASMARTLib.h>
29 #include <IOKit/storage/IOStorageDeviceCharacteristics.h>
30 #include <IOKit/storage/IOMedia.h>
31 #include <CoreFoundation/CoreFoundation.h>
33 // No, I don't know why there isn't a header for this.
34 #define kIOATABlockStorageDeviceClass "IOATABlockStorageDevice"
42 #include "os_darwin.h"
44 // Needed by '-V' option (CVS versioning) of smartd/smartctl
45 const char *os_XXXX_c_cvsid
="$Id: os_darwin.c,v 1.13 2006/04/12 14:54:28 ballen4705 Exp $" \
46 ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_DARWIN_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID
;
48 // Print examples for smartctl.
49 void print_smartctl_examples(){
50 printf("=================================================== SMARTCTL EXAMPLES =====\n\n");
52 " smartctl -a disk0 (Prints all SMART information)\n\n"
53 " smartctl -t long /dev/disk0 (Executes extended disk self-test)\n\n"
54 #ifdef HAVE_GETOPT_LONG
55 " smartctl --smart=on --saveauto=on /dev/rdisk0 (Enables SMART on first disk)\n\n"
56 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/disk0\n"
57 " (Prints Self-Test & Attribute errors)\n\n"
59 " smartctl -s on -S on /dev/rdisk0 (Enables SMART on first disk)\n\n"
60 " smartctl -A -l selftest -q errorsonly /dev/disk0\n"
61 " (Prints Self-Test & Attribute errors)\n\n"
63 " smartctl -a IOService:/MacRISC2PE/pci@f4000000/AppleMacRiscPCI/ata-6@D/AppleKauaiATA/ATADeviceNub@0/IOATABlockStorageDriver/IOATABlockStorageDevice\n"
64 " (You can use IOService: ...)\n\n"
65 " smartctl -c IODeviceTree:/pci@f4000000/ata-6@D/@0:0\n"
66 " (... Or IODeviceTree:)\n"
71 // tries to guess device type given the name (a path). See utility.h
73 int guess_device_type (const char* dev_name
) {
74 // Only ATA is supported right now, so that's what it'd better be.
75 dev_name
= dev_name
; // suppress unused warning.
76 return CONTROLLER_ATA
;
79 // makes a list of ATA or SCSI devices for the DEVICESCAN directive of
80 // smartd. Returns number N of devices, or -1 if out of
81 // memory. Allocates N+1 arrays: one of N pointers (devlist); the
82 // other N arrays each contain null-terminated character strings. In
83 // the case N==0, no arrays are allocated because the array of 0
84 // pointers has zero length, equivalent to calling malloc(0).
85 int make_device_names (char*** devlist
, const char* name
) {
93 if (strcmp (name
, "ATA") == 0)
94 cls
= kIOATABlockStorageDeviceClass
;
95 else // only ATA supported right now.
98 err
= IOServiceGetMatchingServices (kIOMasterPortDefault
,
99 IOServiceMatching (cls
),
101 if (err
!= kIOReturnSuccess
)
104 // Count the devices.
105 for (result
= 0; (device
= IOIteratorNext (i
)) != MACH_PORT_NULL
; result
++)
106 IOObjectRelease (device
);
108 // Create an array of service names.
110 *devlist
= Calloc (result
, sizeof (char *));
113 for (index
= 0; (device
= IOIteratorNext (i
)) != MACH_PORT_NULL
; index
++)
116 IORegistryEntryGetPath(device
, kIOServicePlane
, devName
);
117 IOObjectRelease (device
);
119 (*devlist
)[index
] = CustomStrDup (devName
, true, __LINE__
, __FILE__
);
120 if (! (*devlist
)[index
])
131 for (index
= 0; index
< result
; index
++)
132 if ((*devlist
)[index
])
133 FreeNonZero ((*devlist
)[index
], 0, __LINE__
, __FILE__
);
134 FreeNonZero (*devlist
, result
* sizeof (char *), __LINE__
, __FILE__
);
139 // Information that we keep about each device.
144 IOCFPlugInInterface
**plugin
;
145 IOATASMARTInterface
**smartIf
;
148 // Like open(). Return non-negative integer handle, only used by the
149 // functions below. type=="ATA" or "SCSI". The return value is
150 // an index into the devices[] array. If the device can't be opened,
151 // sets errno and returns -1.
152 // Acceptable device names are:
158 int deviceopen(const char *pathname
, char *type
){
163 if (strcmp (type
, "ATA") != 0)
169 // Find a free device number.
170 for (devnum
= 0; devnum
< sizeof (devices
) / sizeof (devices
[0]); devnum
++)
171 if (! devices
[devnum
].ioob
)
173 if (devnum
== sizeof (devices
) / sizeof (devices
[0]))
180 if (strncmp (pathname
, "/dev/rdisk", 10) == 0)
181 devname
= pathname
+ 6;
182 else if (strncmp (pathname
, "/dev/disk", 9) == 0)
183 devname
= pathname
+ 5;
184 else if (strncmp (pathname
, "disk", 4) == 0)
185 // allow user to just say 'disk0'
191 CFMutableDictionaryRef matcher
;
192 matcher
= IOBSDNameMatching (kIOMasterPortDefault
, 0, devname
);
193 disk
= IOServiceGetMatchingService (kIOMasterPortDefault
, matcher
);
197 disk
= IORegistryEntryFromPath (kIOMasterPortDefault
, pathname
);
206 // Find the ATA block storage driver that is the parent of this device
207 while (! IOObjectConformsTo (disk
, kIOATABlockStorageDeviceClass
))
210 io_object_t notdisk
= disk
;
212 err
= IORegistryEntryGetParentEntry (notdisk
, kIOServicePlane
, &disk
);
213 if (err
!= kIOReturnSuccess
|| ! disk
)
216 IOObjectRelease (notdisk
);
221 devices
[devnum
].ioob
= disk
;
224 CFDictionaryRef diskChars
= NULL
;
225 CFNumberRef diskFeatures
= NULL
;
228 // Determine whether the drive actually supports SMART.
229 if ((diskChars
= IORegistryEntryCreateCFProperty (disk
,
230 CFSTR (kIOPropertyDeviceCharacteristicsKey
),
232 kNilOptions
)) != NULL
233 && CFDictionaryGetValueIfPresent (diskChars
, CFSTR ("ATA Features"),
234 (const void **)&diskFeatures
)
235 && CFNumberGetValue (diskFeatures
, kCFNumberLongType
, &ataFeatures
)
236 && (ataFeatures
& kIOATAFeatureSMART
))
237 devices
[devnum
].hassmart
= true;
239 devices
[devnum
].hassmart
= false;
241 CFRelease (diskChars
);
247 devices
[devnum
].plugin
= NULL
;
248 devices
[devnum
].smartIf
= NULL
;
250 // Create an interface to the ATA SMART library.
251 if (devices
[devnum
].hassmart
252 && IOCreatePlugInInterfaceForService (disk
,
253 kIOATASMARTUserClientTypeID
,
254 kIOCFPlugInInterfaceID
,
255 &devices
[devnum
].plugin
,
256 &dummy
) == kIOReturnSuccess
)
257 (*devices
[devnum
].plugin
)->QueryInterface
258 (devices
[devnum
].plugin
,
259 CFUUIDGetUUIDBytes ( kIOATASMARTInterfaceID
),
260 (LPVOID
) &devices
[devnum
].smartIf
);
266 // Like close(). Acts only on integer handles returned by
267 // deviceopen() above.
268 int deviceclose(int fd
){
269 if (devices
[fd
].smartIf
)
270 (*devices
[fd
].smartIf
)->Release (devices
[fd
].smartIf
);
271 if (devices
[fd
].plugin
)
272 IODestroyPlugInInterface (devices
[fd
].plugin
);
273 IOObjectRelease (devices
[fd
].ioob
);
274 devices
[fd
].ioob
= MACH_PORT_NULL
;
278 // Interface to ATA devices. See os_linux.c for the cannonical example.
279 // DETAILED DESCRIPTION OF ARGUMENTS
280 // device: is the integer handle provided by deviceopen()
281 // command: defines the different operations, see atacmds.h
282 // select: additional input data IF NEEDED (which log, which type of
284 // data: location to write output data, IF NEEDED (1 or 512 bytes).
285 // Note: not all commands use all arguments.
286 // RETURN VALUES (for all commands BUT command==STATUS_CHECK)
287 // -1 if the command failed
288 // 0 if the command succeeded,
289 // RETURN VALUES if command==STATUS_CHECK
290 // -1 if the command failed OR the disk SMART status can't be determined
291 // 0 if the command succeeded and disk SMART status is "OK"
292 // 1 if the command succeeded and disk SMART status is "FAILING"
294 // Things that aren't available in the Darwin interfaces:
295 // - Tests other than short and extended (in particular, can't run
296 // an immediate offline test)
297 // - Captive-mode tests, aborting tests
298 // - ability to switch automatic offline testing on or off
300 // Note that some versions of Darwin, at least 7H63 and earlier,
301 // have a buggy library that treats the boolean value in
302 // SMARTEnableDisableOperations, SMARTEnableDisableAutosave, and
303 // SMARTExecuteOffLineImmediate as always being true.
304 int marvell_command_interface(int fd
, smart_command_set command
,
305 int select
, char *data
)
309 ata_command_interface(int fd
, smart_command_set command
,
310 int select
, char *data
)
312 IOATASMARTInterface
**ifp
= devices
[fd
].smartIf
;
313 IOATASMARTInterface
*smartIf
;
327 err
= smartIf
->SMARTReturnStatus (ifp
, &is_failing
);
328 if (err
== kIOReturnSuccess
&& is_failing
)
334 err
= smartIf
->SMARTEnableDisableOperations (ifp
, command
== ENABLE
);
337 err
= smartIf
->SMARTEnableDisableAutosave (ifp
, select
!= 0);
339 case IMMEDIATE_OFFLINE
:
340 if (select
!= SHORT_SELF_TEST
&& select
!= EXTEND_SELF_TEST
)
345 err
= smartIf
->SMARTExecuteOffLineImmediate (ifp
,
346 select
== EXTEND_SELF_TEST
);
349 err
= smartIf
->SMARTReadData (ifp
, (ATASMARTData
*)data
);
351 case READ_THRESHOLDS
:
352 err
= smartIf
->SMARTReadDataThresholds (ifp
,
353 (ATASMARTDataThresholds
*)data
);
356 err
= smartIf
->SMARTReadLogAtAddress (ifp
, select
, data
, 512);
359 err
= smartIf
->SMARTWriteLogAtAddress (ifp
, select
, data
, 512);
364 err
= smartIf
->GetATAIdentifyData (ifp
, data
, 512, &dummy
);
365 if (err
== kIOReturnSuccess
&& isbigendian())
368 /* The system has already byte-swapped, undo it. */
369 for (i
= 0; i
< 256; i
+=2)
374 case CHECK_POWER_MODE
:
375 // The information is right there in the device registry, but how
376 // to get to it portably?
381 if (err
== kIOReturnExclusiveAccess
)
383 return err
== kIOReturnSuccess
? 0 : -1;
386 // There's no special handling needed for hidden devices, the kernel
387 // must deal with them.
388 int escalade_command_interface(int fd
, int escalade_port
, int escalade_type
,
389 smart_command_set command
, int select
,
393 escalade_port
= escalade_port
;
394 escalade_type
= escalade_type
;
401 // Interface to SCSI devices. See os_linux.c
402 int do_scsi_cmnd_io(int fd
, struct scsi_cmnd_io
* iop
, int report
) {