Annotation of embedaddon/smartmontools/os_darwin.cpp, revision 1.1.1.2

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
1.1.1.2 ! misho      14:  * (for example COPYING); if not, write to the Free Software Foundation,
        !            15:  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1.1       misho      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
1.1.1.2 ! misho      47: const char *os_XXXX_c_cvsid="$Id: os_darwin.cpp 3728 2012-12-13 17:57:50Z chrfranke $" \
1.1       misho      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>