smartmontools SVN Rev 3317
Utility to control and monitor storage systems with "S.M.A.R.T."
os_darwin.cpp
Go to the documentation of this file.
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 }