File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / smartmontools / os_darwin.cpp
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 16:32:16 2012 UTC (12 years, 4 months ago) by misho
Branches: smartmontools, elwix, MAIN
CVS tags: v5_43, v5_42, HEAD
smartmontools

    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.1.1.1 2012/02/21 16:32:16 misho 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>