Annotation of embedaddon/smartmontools/os_darwin.cpp, revision 1.1.1.1
1.1 misho 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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>