]> git.proxmox.com Git - mirror_smartmontools-debian.git/blob - os_darwin.c
add debian specific patches
[mirror_smartmontools-debian.git] / os_darwin.c
1 /*
2 * os_darwin.c
3 *
4 * Home page of code is: http://smartmontools.sourceforge.net
5 *
6 * Copyright (C) 2004-6 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 <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>
32
33 // No, I don't know why there isn't a header for this.
34 #define kIOATABlockStorageDeviceClass "IOATABlockStorageDevice"
35
36 #include "config.h"
37 #include "int64.h"
38 #include "atacmds.h"
39 #include "scsicmds.h"
40 #include "utility.h"
41
42 #include "os_darwin.h"
43
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;
47
48 // Print examples for smartctl.
49 void print_smartctl_examples(){
50 printf("=================================================== SMARTCTL EXAMPLES =====\n\n");
51 printf(
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"
58 #else
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"
62 #endif
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"
67 );
68 return;
69 }
70
71 // tries to guess device type given the name (a path). See utility.h
72 // for return values.
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;
77 }
78
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) {
86 IOReturn err;
87 io_iterator_t i;
88 io_object_t device;
89 int result;
90 int index;
91 const char * cls;
92
93 if (strcmp (name, "ATA") == 0)
94 cls = kIOATABlockStorageDeviceClass;
95 else // only ATA supported right now.
96 return 0;
97
98 err = IOServiceGetMatchingServices (kIOMasterPortDefault,
99 IOServiceMatching (cls),
100 &i);
101 if (err != kIOReturnSuccess)
102 return -1;
103
104 // Count the devices.
105 for (result = 0; (device = IOIteratorNext (i)) != MACH_PORT_NULL; result++)
106 IOObjectRelease (device);
107
108 // Create an array of service names.
109 IOIteratorReset (i);
110 *devlist = Calloc (result, sizeof (char *));
111 if (! *devlist)
112 goto error;
113 for (index = 0; (device = IOIteratorNext (i)) != MACH_PORT_NULL; index++)
114 {
115 io_string_t devName;
116 IORegistryEntryGetPath(device, kIOServicePlane, devName);
117 IOObjectRelease (device);
118
119 (*devlist)[index] = CustomStrDup (devName, true, __LINE__, __FILE__);
120 if (! (*devlist)[index])
121 goto error;
122 }
123 IOObjectRelease (i);
124
125 return result;
126
127 error:
128 IOObjectRelease (i);
129 if (*devlist)
130 {
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__);
135 }
136 return -1;
137 }
138
139 // Information that we keep about each device.
140
141 static struct {
142 io_object_t ioob;
143 bool hassmart;
144 IOCFPlugInInterface **plugin;
145 IOATASMARTInterface **smartIf;
146 } devices[20];
147
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:
153 // /dev/disk*
154 // /dev/rdisk*
155 // disk*
156 // IOService:*
157 // IODeviceTree:*
158 int deviceopen(const char *pathname, char *type){
159 size_t devnum;
160 const char *devname;
161 io_object_t disk;
162
163 if (strcmp (type, "ATA") != 0)
164 {
165 errno = EINVAL;
166 return -1;
167 }
168
169 // Find a free device number.
170 for (devnum = 0; devnum < sizeof (devices) / sizeof (devices[0]); devnum++)
171 if (! devices[devnum].ioob)
172 break;
173 if (devnum == sizeof (devices) / sizeof (devices[0]))
174 {
175 errno = EMFILE;
176 return -1;
177 }
178
179 devname = NULL;
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'
186 devname = pathname;
187
188 // Find the device.
189 if (devname)
190 {
191 CFMutableDictionaryRef matcher;
192 matcher = IOBSDNameMatching (kIOMasterPortDefault, 0, devname);
193 disk = IOServiceGetMatchingService (kIOMasterPortDefault, matcher);
194 }
195 else
196 {
197 disk = IORegistryEntryFromPath (kIOMasterPortDefault, pathname);
198 }
199
200 if (! disk)
201 {
202 errno = ENOENT;
203 return -1;
204 }
205
206 // Find the ATA block storage driver that is the parent of this device
207 while (! IOObjectConformsTo (disk, kIOATABlockStorageDeviceClass))
208 {
209 IOReturn err;
210 io_object_t notdisk = disk;
211
212 err = IORegistryEntryGetParentEntry (notdisk, kIOServicePlane, &disk);
213 if (err != kIOReturnSuccess || ! disk)
214 {
215 errno = ENODEV;
216 IOObjectRelease (notdisk);
217 return -1;
218 }
219 }
220
221 devices[devnum].ioob = disk;
222
223 {
224 CFDictionaryRef diskChars = NULL;
225 CFNumberRef diskFeatures = NULL;
226 UInt32 ataFeatures;
227
228 // Determine whether the drive actually supports SMART.
229 if ((diskChars = IORegistryEntryCreateCFProperty (disk,
230 CFSTR (kIOPropertyDeviceCharacteristicsKey),
231 kCFAllocatorDefault,
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;
238 else
239 devices[devnum].hassmart = false;
240 if (diskChars)
241 CFRelease (diskChars);
242 }
243
244 {
245 SInt32 dummy;
246
247 devices[devnum].plugin = NULL;
248 devices[devnum].smartIf = NULL;
249
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);
261 }
262
263 return devnum;
264 }
265
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;
275 return 0;
276 }
277
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
283 // self-test).
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"
293
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
299
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)
306 { return -1; }
307
308 int
309 ata_command_interface(int fd, smart_command_set command,
310 int select, char *data)
311 {
312 IOATASMARTInterface **ifp = devices[fd].smartIf;
313 IOATASMARTInterface *smartIf;
314 IOReturn err;
315
316 if (! ifp)
317 return -1;
318 smartIf = *ifp;
319
320 switch (command)
321 {
322 case STATUS:
323 return 0;
324 case STATUS_CHECK:
325 {
326 Boolean is_failing;
327 err = smartIf->SMARTReturnStatus (ifp, &is_failing);
328 if (err == kIOReturnSuccess && is_failing)
329 return 1;
330 break;
331 }
332 case ENABLE:
333 case DISABLE:
334 err = smartIf->SMARTEnableDisableOperations (ifp, command == ENABLE);
335 break;
336 case AUTOSAVE:
337 err = smartIf->SMARTEnableDisableAutosave (ifp, select != 0);
338 break;
339 case IMMEDIATE_OFFLINE:
340 if (select != SHORT_SELF_TEST && select != EXTEND_SELF_TEST)
341 {
342 errno = EINVAL;
343 return -1;
344 }
345 err = smartIf->SMARTExecuteOffLineImmediate (ifp,
346 select == EXTEND_SELF_TEST);
347 break;
348 case READ_VALUES:
349 err = smartIf->SMARTReadData (ifp, (ATASMARTData *)data);
350 break;
351 case READ_THRESHOLDS:
352 err = smartIf->SMARTReadDataThresholds (ifp,
353 (ATASMARTDataThresholds *)data);
354 break;
355 case READ_LOG:
356 err = smartIf->SMARTReadLogAtAddress (ifp, select, data, 512);
357 break;
358 case WRITE_LOG:
359 err = smartIf->SMARTWriteLogAtAddress (ifp, select, data, 512);
360 break;
361 case IDENTIFY:
362 {
363 UInt32 dummy;
364 err = smartIf->GetATAIdentifyData (ifp, data, 512, &dummy);
365 if (err == kIOReturnSuccess && isbigendian())
366 {
367 int i;
368 /* The system has already byte-swapped, undo it. */
369 for (i = 0; i < 256; i+=2)
370 swap2 (data + i);
371 }
372 }
373 break;
374 case CHECK_POWER_MODE:
375 // The information is right there in the device registry, but how
376 // to get to it portably?
377 default:
378 errno = ENOTSUP;
379 return -1;
380 }
381 if (err == kIOReturnExclusiveAccess)
382 errno = EBUSY;
383 return err == kIOReturnSuccess ? 0 : -1;
384 }
385
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,
390 char *data)
391 {
392 fd = fd;
393 escalade_port = escalade_port;
394 escalade_type = escalade_type;
395 command = command;
396 select = select;
397 data = data;
398 return -1;
399 }
400
401 // Interface to SCSI devices. See os_linux.c
402 int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report) {
403 return -ENOSYS;
404 }