|
smartmontools SVN Rev 3317
Utility to control and monitor storage systems with "S.M.A.R.T."
|
00001 /* 00002 * os_darwin.c 00003 * 00004 * Home page of code is: http://smartmontools.sourceforge.net 00005 * 00006 * Copyright (C) 2004-8 Geoffrey Keating <geoffk@geoffk.org> 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2, or (at your option) 00011 * any later version. 00012 * 00013 * You should have received a copy of the GNU General Public License 00014 * (for example COPYING); if not, write to the Free Software Foundation, 00015 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00016 */ 00017 00018 #include <stdbool.h> 00019 #include <errno.h> 00020 #include <unistd.h> 00021 #include <mach/mach.h> 00022 #include <mach/mach_error.h> 00023 #include <mach/mach_init.h> 00024 #include <IOKit/IOCFPlugIn.h> 00025 #include <IOKit/IOKitLib.h> 00026 #include <IOKit/IOReturn.h> 00027 #include <IOKit/IOBSD.h> 00028 #include <IOKit/storage/IOBlockStorageDevice.h> 00029 #include <IOKit/storage/IOStorageDeviceCharacteristics.h> 00030 #include <IOKit/storage/IOMedia.h> 00031 #include <IOKit/storage/ata/IOATAStorageDefines.h> 00032 #include <IOKit/storage/ata/ATASMARTLib.h> 00033 #include <CoreFoundation/CoreFoundation.h> 00034 00035 // No, I don't know why there isn't a header for this. 00036 #define kIOATABlockStorageDeviceClass "IOATABlockStorageDevice" 00037 00038 #include "config.h" 00039 #include "int64.h" 00040 #include "atacmds.h" 00041 #include "scsicmds.h" 00042 #include "utility.h" 00043 00044 #include "os_darwin.h" 00045 00046 // Needed by '-V' option (CVS versioning) of smartd/smartctl 00047 const char *os_XXXX_c_cvsid="$Id: os_darwin.cpp 3805 2013-03-29 19:54:18Z chrfranke $" \ 00048 ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_DARWIN_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; 00049 00050 // Print examples for smartctl. 00051 void print_smartctl_examples(){ 00052 printf("=================================================== SMARTCTL EXAMPLES =====\n\n"); 00053 printf( 00054 " smartctl -a disk0 (Prints all SMART information)\n\n" 00055 " smartctl -t long /dev/disk0 (Executes extended disk self-test)\n\n" 00056 #ifdef HAVE_GETOPT_LONG 00057 " smartctl --smart=on --saveauto=on /dev/rdisk0 (Enables SMART on first disk)\n\n" 00058 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/disk0\n" 00059 " (Prints Self-Test & Attribute errors)\n\n" 00060 #else 00061 " smartctl -s on -S on /dev/rdisk0 (Enables SMART on first disk)\n\n" 00062 " smartctl -A -l selftest -q errorsonly /dev/disk0\n" 00063 " (Prints Self-Test & Attribute errors)\n\n" 00064 #endif 00065 " smartctl -a IOService:/MacRISC2PE/pci@f4000000/AppleMacRiscPCI/ata-6@D/AppleKauaiATA/ATADeviceNub@0/IOATABlockStorageDriver/IOATABlockStorageDevice\n" 00066 " (You can use IOService: ...)\n\n" 00067 " smartctl -c IODeviceTree:/pci@f4000000/ata-6@D/@0:0\n" 00068 " (... Or IODeviceTree:)\n" 00069 ); 00070 return; 00071 } 00072 00073 // tries to guess device type given the name (a path). See utility.h 00074 // for return values. 00075 int guess_device_type (const char * /* dev_name */) { 00076 // Only ATA is supported right now, so that's what it'd better be. 00077 return CONTROLLER_ATA; 00078 } 00079 00080 // Determine whether 'dev' is a SMART-capable device. 00081 static bool is_smart_capable (io_object_t dev) { 00082 CFTypeRef smartCapableKey; 00083 CFDictionaryRef diskChars; 00084 00085 // If the device has kIOPropertySMARTCapableKey, then it's capable, 00086 // no matter what it looks like. 00087 smartCapableKey = IORegistryEntryCreateCFProperty 00088 (dev, CFSTR (kIOPropertySMARTCapableKey), 00089 kCFAllocatorDefault, 0); 00090 if (smartCapableKey) 00091 { 00092 CFRelease (smartCapableKey); 00093 return true; 00094 } 00095 00096 // If it's an kIOATABlockStorageDeviceClass then we're successful 00097 // only if its ATA features indicate it supports SMART. 00098 if (IOObjectConformsTo (dev, kIOATABlockStorageDeviceClass) 00099 && (diskChars = (CFDictionaryRef)IORegistryEntryCreateCFProperty 00100 (dev, CFSTR (kIOPropertyDeviceCharacteristicsKey), 00101 kCFAllocatorDefault, kNilOptions)) != NULL) 00102 { 00103 CFNumberRef diskFeatures = NULL; 00104 UInt32 ataFeatures = 0; 00105 00106 if (CFDictionaryGetValueIfPresent (diskChars, CFSTR ("ATA Features"), 00107 (const void **)&diskFeatures)) 00108 CFNumberGetValue (diskFeatures, kCFNumberLongType, 00109 &ataFeatures); 00110 CFRelease (diskChars); 00111 if (diskFeatures) 00112 CFRelease (diskFeatures); 00113 00114 return (ataFeatures & kIOATAFeatureSMART) != 0; 00115 } 00116 return false; 00117 } 00118 00119 00120 // makes a list of ATA or SCSI devices for the DEVICESCAN directive of 00121 // smartd. Returns number N of devices, or -1 if out of 00122 // memory. Allocates N+1 arrays: one of N pointers (devlist); the 00123 // other N arrays each contain null-terminated character strings. In 00124 // the case N==0, no arrays are allocated because the array of 0 00125 // pointers has zero length, equivalent to calling malloc(0). 00126 int make_device_names (char*** devlist, const char* name) { 00127 IOReturn err; 00128 io_iterator_t i; 00129 io_object_t device = MACH_PORT_NULL; 00130 int result; 00131 int index; 00132 00133 // We treat all devices as ATA so long as they support SMARTLib. 00134 if (strcmp (name, "ATA") != 0) 00135 return 0; 00136 00137 err = IOServiceGetMatchingServices 00138 (kIOMasterPortDefault, IOServiceMatching (kIOBlockStorageDeviceClass), &i); 00139 if (err != kIOReturnSuccess) 00140 return -1; 00141 00142 // Count the devices. 00143 result = 0; 00144 while ((device = IOIteratorNext (i)) != MACH_PORT_NULL) { 00145 if (is_smart_capable (device)) 00146 result++; 00147 IOObjectRelease (device); 00148 } 00149 00150 // Create an array of service names. 00151 IOIteratorReset (i); 00152 *devlist = (char**)Calloc (result, sizeof (char *)); 00153 if (! *devlist) 00154 goto error; 00155 index = 0; 00156 while ((device = IOIteratorNext (i)) != MACH_PORT_NULL) { 00157 if (is_smart_capable (device)) 00158 { 00159 io_string_t devName; 00160 IORegistryEntryGetPath(device, kIOServicePlane, devName); 00161 (*devlist)[index] = CustomStrDup (devName, true, __LINE__, __FILE__); 00162 if (! (*devlist)[index]) 00163 goto error; 00164 index++; 00165 } 00166 IOObjectRelease (device); 00167 } 00168 00169 IOObjectRelease (i); 00170 return result; 00171 00172 error: 00173 if (device != MACH_PORT_NULL) 00174 IOObjectRelease (device); 00175 IOObjectRelease (i); 00176 if (*devlist) 00177 { 00178 for (index = 0; index < result; index++) 00179 if ((*devlist)[index]) 00180 FreeNonZero ((*devlist)[index], 0, __LINE__, __FILE__); 00181 FreeNonZero (*devlist, result * sizeof (char *), __LINE__, __FILE__); 00182 } 00183 return -1; 00184 } 00185 00186 // Information that we keep about each device. 00187 00188 static struct { 00189 io_object_t ioob; 00190 IOCFPlugInInterface **plugin; 00191 IOATASMARTInterface **smartIf; 00192 } devices[20]; 00193 00194 // Like open(). Return non-negative integer handle, only used by the 00195 // functions below. type=="ATA" or "SCSI". The return value is 00196 // an index into the devices[] array. If the device can't be opened, 00197 // sets errno and returns -1. 00198 // Acceptable device names are: 00199 // /dev/disk* 00200 // /dev/rdisk* 00201 // disk* 00202 // IOService:* 00203 // IODeviceTree:* 00204 int deviceopen(const char *pathname, char *type){ 00205 size_t devnum; 00206 const char *devname; 00207 io_object_t disk; 00208 00209 if (strcmp (type, "ATA") != 0) 00210 { 00211 errno = EINVAL; 00212 return -1; 00213 } 00214 00215 // Find a free device number. 00216 for (devnum = 0; devnum < sizeof (devices) / sizeof (devices[0]); devnum++) 00217 if (! devices[devnum].ioob) 00218 break; 00219 if (devnum == sizeof (devices) / sizeof (devices[0])) 00220 { 00221 errno = EMFILE; 00222 return -1; 00223 } 00224 00225 devname = NULL; 00226 if (strncmp (pathname, "/dev/rdisk", 10) == 0) 00227 devname = pathname + 6; 00228 else if (strncmp (pathname, "/dev/disk", 9) == 0) 00229 devname = pathname + 5; 00230 else if (strncmp (pathname, "disk", 4) == 0) 00231 // allow user to just say 'disk0' 00232 devname = pathname; 00233 00234 // Find the device. 00235 if (devname) 00236 { 00237 CFMutableDictionaryRef matcher; 00238 matcher = IOBSDNameMatching (kIOMasterPortDefault, 0, devname); 00239 disk = IOServiceGetMatchingService (kIOMasterPortDefault, matcher); 00240 } 00241 else 00242 { 00243 disk = IORegistryEntryFromPath (kIOMasterPortDefault, pathname); 00244 } 00245 00246 if (! disk) 00247 { 00248 errno = ENOENT; 00249 return -1; 00250 } 00251 00252 // Find a SMART-capable driver which is a parent of this device. 00253 while (! is_smart_capable (disk)) 00254 { 00255 IOReturn err; 00256 io_object_t prevdisk = disk; 00257 00258 // Find this device's parent and try again. 00259 err = IORegistryEntryGetParentEntry (disk, kIOServicePlane, &disk); 00260 if (err != kIOReturnSuccess || ! disk) 00261 { 00262 errno = ENODEV; 00263 IOObjectRelease (prevdisk); 00264 return -1; 00265 } 00266 } 00267 00268 devices[devnum].ioob = disk; 00269 00270 { 00271 SInt32 dummy; 00272 00273 devices[devnum].plugin = NULL; 00274 devices[devnum].smartIf = NULL; 00275 00276 // Create an interface to the ATA SMART library. 00277 if (IOCreatePlugInInterfaceForService (disk, 00278 kIOATASMARTUserClientTypeID, 00279 kIOCFPlugInInterfaceID, 00280 &devices[devnum].plugin, 00281 &dummy) == kIOReturnSuccess) 00282 (*devices[devnum].plugin)->QueryInterface 00283 (devices[devnum].plugin, 00284 CFUUIDGetUUIDBytes ( kIOATASMARTInterfaceID), 00285 (void **)&devices[devnum].smartIf); 00286 } 00287 00288 return devnum; 00289 } 00290 00291 // Like close(). Acts only on integer handles returned by 00292 // deviceopen() above. 00293 int deviceclose(int fd){ 00294 if (devices[fd].smartIf) 00295 (*devices[fd].smartIf)->Release (devices[fd].smartIf); 00296 if (devices[fd].plugin) 00297 IODestroyPlugInInterface (devices[fd].plugin); 00298 IOObjectRelease (devices[fd].ioob); 00299 devices[fd].ioob = MACH_PORT_NULL; 00300 return 0; 00301 } 00302 00303 // Interface to ATA devices. See os_linux.cpp for the cannonical example. 00304 // DETAILED DESCRIPTION OF ARGUMENTS 00305 // device: is the integer handle provided by deviceopen() 00306 // command: defines the different operations, see atacmds.h 00307 // select: additional input data IF NEEDED (which log, which type of 00308 // self-test). 00309 // data: location to write output data, IF NEEDED (1 or 512 bytes). 00310 // Note: not all commands use all arguments. 00311 // RETURN VALUES (for all commands BUT command==STATUS_CHECK) 00312 // -1 if the command failed 00313 // 0 if the command succeeded, 00314 // RETURN VALUES if command==STATUS_CHECK 00315 // -1 if the command failed OR the disk SMART status can't be determined 00316 // 0 if the command succeeded and disk SMART status is "OK" 00317 // 1 if the command succeeded and disk SMART status is "FAILING" 00318 00319 // Things that aren't available in the Darwin interfaces: 00320 // - Tests other than short and extended (in particular, can't run 00321 // an immediate offline test) 00322 // - Captive-mode tests, aborting tests 00323 // - ability to switch automatic offline testing on or off 00324 00325 // Note that some versions of Darwin, at least 7H63 and earlier, 00326 // have a buggy library that treats the boolean value in 00327 // SMARTEnableDisableOperations, SMARTEnableDisableAutosave, and 00328 // SMARTExecuteOffLineImmediate as always being true. 00329 int 00330 ata_command_interface(int fd, smart_command_set command, 00331 int select, char *data) 00332 { 00333 IOATASMARTInterface **ifp = devices[fd].smartIf; 00334 IOATASMARTInterface *smartIf; 00335 IOReturn err; 00336 int timeoutCount = 5; 00337 00338 if (! ifp) 00339 return -1; 00340 smartIf = *ifp; 00341 00342 do { 00343 switch (command) 00344 { 00345 case STATUS: 00346 return 0; 00347 case STATUS_CHECK: 00348 { 00349 Boolean is_failing; 00350 err = smartIf->SMARTReturnStatus (ifp, &is_failing); 00351 if (err == kIOReturnSuccess && is_failing) 00352 return 1; 00353 break; 00354 } 00355 case ENABLE: 00356 case DISABLE: 00357 err = smartIf->SMARTEnableDisableOperations (ifp, command == ENABLE); 00358 break; 00359 case AUTOSAVE: 00360 err = smartIf->SMARTEnableDisableAutosave (ifp, select != 0); 00361 break; 00362 case IMMEDIATE_OFFLINE: 00363 if (select != SHORT_SELF_TEST && select != EXTEND_SELF_TEST) 00364 { 00365 errno = EINVAL; 00366 return -1; 00367 } 00368 err = smartIf->SMARTExecuteOffLineImmediate (ifp, 00369 select == EXTEND_SELF_TEST); 00370 break; 00371 case READ_VALUES: 00372 err = smartIf->SMARTReadData (ifp, (ATASMARTData *)data); 00373 break; 00374 case READ_THRESHOLDS: 00375 err = smartIf->SMARTReadDataThresholds (ifp, 00376 (ATASMARTDataThresholds *)data); 00377 break; 00378 case READ_LOG: 00379 err = smartIf->SMARTReadLogAtAddress (ifp, select, data, 512); 00380 break; 00381 case WRITE_LOG: 00382 err = smartIf->SMARTWriteLogAtAddress (ifp, select, data, 512); 00383 break; 00384 case IDENTIFY: 00385 { 00386 UInt32 dummy; 00387 err = smartIf->GetATAIdentifyData (ifp, data, 512, &dummy); 00388 if (err != kIOReturnSuccess && err != kIOReturnTimeout 00389 && err != kIOReturnNotResponding) 00390 printf ("identify failed: %#x\n", (unsigned) err); 00391 if (err == kIOReturnSuccess && isbigendian()) 00392 { 00393 int i; 00394 /* The system has already byte-swapped, undo it. */ 00395 for (i = 0; i < 256; i+=2) 00396 swap2 (data + i); 00397 } 00398 } 00399 break; 00400 case CHECK_POWER_MODE: 00401 // The information is right there in the device registry, but how 00402 // to get to it portably? 00403 default: 00404 errno = ENOTSUP; 00405 return -1; 00406 } 00407 /* This bit is a bit strange. Apparently, when the drive is spun 00408 down, the intended behaviour of these calls is that they fail, 00409 return kIOReturnTimeout and then power the drive up. So if 00410 you get a timeout, you have to try again to get the actual 00411 command run, but the drive is already powering up so you can't 00412 use this for CHECK_POWER_MODE. */ 00413 if (err == kIOReturnTimeout || err == kIOReturnNotResponding) 00414 sleep (1); 00415 } while ((err == kIOReturnTimeout || err == kIOReturnNotResponding) 00416 && timeoutCount-- > 0); 00417 if (err == kIOReturnExclusiveAccess) 00418 errno = EBUSY; 00419 return err == kIOReturnSuccess ? 0 : -1; 00420 } 00421 00422 // Interface to SCSI devices. See os_linux.c 00423 int do_scsi_cmnd_io(int /* fd */, struct scsi_cmnd_io * /* iop */, int /* report */) { 00424 return -ENOSYS; 00425 }
1.7.4