smartmontools  SVN Rev 4556
Utility to control and monitor storage systems with "S.M.A.R.T."
os_darwin.cpp
Go to the documentation of this file.
1 /*
2  * os_darwin.cpp
3  *
4  * Home page of code is: http://www.smartmontools.org
5  *
6  * Copyright (C) 2004-8 Geoffrey Keating <geoffk@geoffk.org>
7  * Copyright (C) 2014 Alex Samorukov <samm@os2.kiev.ua>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2, or (at your option)
12  * any later version.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with smartmontools. If not, see <http://www.gnu.org/licenses/>.
16  *
17  */
18 
19 #include <stdbool.h>
20 #include <errno.h>
21 #include <unistd.h>
22 #include <mach/mach.h>
23 #include <mach/mach_error.h>
24 #include <mach/mach_init.h>
25 #include <sys/utsname.h>
26 #include <IOKit/IOCFPlugIn.h>
27 #include <IOKit/IOKitLib.h>
28 #include <IOKit/IOReturn.h>
29 #include <IOKit/IOBSD.h>
30 #include <IOKit/storage/IOBlockStorageDevice.h>
31 #include <IOKit/storage/IOStorageDeviceCharacteristics.h>
32 #include <IOKit/storage/IOMedia.h>
33 #include <IOKit/storage/ata/IOATAStorageDefines.h>
34 #include <IOKit/storage/ata/ATASMARTLib.h>
35 #include <CoreFoundation/CoreFoundation.h>
36 
37 #include "config.h"
38 #include "int64.h"
39 #include "atacmds.h"
40 #include "scsicmds.h"
41 #include "nvmecmds.h"
42 #include "utility.h"
43 #include "os_darwin.h"
44 #include "dev_interface.h"
45 
46 #define ARGUSED(x) ((void)(x))
47 // Needed by '-V' option (CVS versioning) of smartd/smartctl
48 const char *os_darwin_cpp_cvsid="$Id: os_darwin.cpp 4552 2017-10-11 10:11:35Z samm2 $" \
50 
51 // examples for smartctl
52 static const char smartctl_examples[] =
53  "=================================================== SMARTCTL EXAMPLES =====\n\n"
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 
71 
72 // Information that we keep about each device.
73 
74 static struct {
75  io_object_t ioob;
76  IOCFPlugInInterface **plugin;
77  IOATASMARTInterface **smartIf; // ATA devices
79 } devices[20];
80 
81 const char * dev_darwin_cpp_cvsid = "$Id: os_darwin.cpp 4552 2017-10-11 10:11:35Z samm2 $"
83 
84 /////////////////////////////////////////////////////////////////////////////
85 
86 namespace os { // No need to publish anything, name provided for Doxygen
87 
88 /////////////////////////////////////////////////////////////////////////////
89 /// Implement shared open/close routines with old functions.
90 
92 : virtual public /*implements*/ smart_device
93 {
94 public:
95  explicit darwin_smart_device(const char * mode)
97  m_fd(-1), m_mode(mode) { }
98 
99  virtual ~darwin_smart_device() throw();
100 
101  virtual bool is_open() const;
102 
103  virtual bool open();
104 
105  virtual bool close();
106 
107 protected:
108  /// Return filedesc for derived classes.
109  int get_fd() const
110  { return m_fd; }
111 
112 private:
113  int m_fd; ///< filedesc, -1 if not open.
114  const char * m_mode; ///< Mode string for deviceopen().
115 };
116 
117 
119 {
120  if (m_fd >= 0)
122 }
123 
125 {
126  return (m_fd >= 0);
127 }
128 
129 // Determine whether 'dev' is a SMART-capable device.
130 static bool is_smart_capable (io_object_t dev, const char * type) {
131  CFTypeRef smartCapableKey = NULL;
132  CFDictionaryRef diskChars;
133 
134  // If the device has kIOPropertySMARTCapableKey, then it's capable,
135  // no matter what it looks like.
136  if (!strcmp("ATA", type)) {
137  smartCapableKey = IORegistryEntryCreateCFProperty
138  (dev, CFSTR (kIOPropertySMARTCapableKey),
139  kCFAllocatorDefault, 0);
140  }
141 
142  else if (!strcmp("NVME", type)) {
143  smartCapableKey = IORegistryEntryCreateCFProperty
144  (dev, CFSTR (kIOPropertyNVMeSMARTCapableKey),
145  kCFAllocatorDefault, 0);
146  }
147 
148  if (smartCapableKey)
149  {
150  CFRelease (smartCapableKey);
151  return true;
152  }
153 
154  // If it's an kIOATABlockStorageDeviceClass then we're successful
155  // only if its ATA features indicate it supports SMART.
156  // This will be broken for NVMe, however it is not needed
157  if (IOObjectConformsTo (dev, kIOATABlockStorageDeviceClass)
158  && (diskChars = (CFDictionaryRef)IORegistryEntryCreateCFProperty
159  (dev, CFSTR (kIOPropertyDeviceCharacteristicsKey),
160  kCFAllocatorDefault, kNilOptions)) != NULL)
161  {
162  CFNumberRef diskFeatures = NULL;
163  UInt32 ataFeatures = 0;
164 
165  if (CFDictionaryGetValueIfPresent (diskChars, CFSTR ("ATA Features"),
166  (const void **)&diskFeatures))
167  CFNumberGetValue (diskFeatures, kCFNumberLongType,
168  &ataFeatures);
169  CFRelease (diskChars);
170  if (diskFeatures)
171  CFRelease (diskFeatures);
172 
173  return (ataFeatures & kIOATAFeatureSMART) != 0;
174  }
175  return false;
176 }
177 
179 {
180  // Acceptable device names are:
181  // /dev/disk*
182  // /dev/rdisk*
183  // disk*
184  // IOService:*
185  // IODeviceTree:*
186  size_t devnum;
187  const char *devname;
188  io_object_t disk;
189  const char *pathname = get_dev_name();
190  char *type = const_cast<char*>(m_mode);
191 
192  if (!(strcmp("ATA", type) || strcmp("NVME", type)))
193  {
194  set_err (EINVAL);
195  return false;
196  }
197 
198  // Find a free device number.
199  for (devnum = 0; devnum < sizeof (devices) / sizeof (devices[0]); devnum++)
200  if (! devices[devnum].ioob)
201  break;
202  if (devnum == sizeof (devices) / sizeof (devices[0]))
203  {
204  set_err (EMFILE);
205  return false;
206  }
207 
208  devname = NULL;
209  if (strncmp (pathname, "/dev/rdisk", 10) == 0)
210  devname = pathname + 6;
211  else if (strncmp (pathname, "/dev/disk", 9) == 0)
212  devname = pathname + 5;
213  else if (strncmp (pathname, "disk", 4) == 0)
214  // allow user to just say 'disk0'
215  devname = pathname;
216 
217  // Find the device. This part should be the same for the NVMe and ATA
218  if (devname)
219  {
220  CFMutableDictionaryRef matcher;
221  matcher = IOBSDNameMatching (kIOMasterPortDefault, 0, devname);
222  disk = IOServiceGetMatchingService (kIOMasterPortDefault, matcher);
223  }
224  else
225  {
226  disk = IORegistryEntryFromPath (kIOMasterPortDefault, pathname);
227  }
228  if (! disk)
229  {
230  set_err(ENOENT);
231  return false;
232  }
233  // Find a SMART-capable driver which is a parent of this device.
234  while (! is_smart_capable (disk, type))
235  {
236  IOReturn err;
237  io_object_t prevdisk = disk;
238 
239  // Find this device's parent and try again.
240  err = IORegistryEntryGetParentEntry (disk, kIOServicePlane, &disk);
241  if (err != kIOReturnSuccess || ! disk)
242  {
243  set_err(ENODEV);
244  IOObjectRelease (prevdisk);
245  return false;
246  }
247  }
248 
249  devices[devnum].ioob = disk;
250 
251  {
252  SInt32 dummy;
253 
254  devices[devnum].plugin = NULL;
255  devices[devnum].smartIf = NULL;
256  devices[devnum].smartIfNVMe = NULL;
257 
258  CFUUIDRef pluginType = NULL;
259  CFUUIDRef smartInterfaceId = NULL;
260  void ** SMARTptr = NULL;
261 
262  if (!strcmp("ATA", type)) {
263  pluginType = kIOATASMARTUserClientTypeID;
264  smartInterfaceId = kIOATASMARTInterfaceID;
265  SMARTptr = (void **)&devices[devnum].smartIf;
266  }
267  else if (!strcmp("NVME", type)) {
268  pluginType = kIONVMeSMARTUserClientTypeID;
269  smartInterfaceId = kIONVMeSMARTInterfaceID;
270  SMARTptr = (void **)&devices[devnum].smartIfNVMe;
271  }
272 
273  // Create an interface to the ATA SMART library.
274  if (IOCreatePlugInInterfaceForService (disk,
275  pluginType,
276  kIOCFPlugInInterfaceID,
277  &devices[devnum].plugin,
278  &dummy) == kIOReturnSuccess)
279  (*devices[devnum].plugin)->QueryInterface
280  (devices[devnum].plugin,
281  CFUUIDGetUUIDBytes ( smartInterfaceId),
282  SMARTptr);
283  else
284  return set_err(ENOSYS, "IOCreatePlugInInterfaceForService failed");
285  }
286 
287 
288  m_fd = devnum;
289  if (m_fd < 0) {
290  set_err((errno==ENOENT || errno==ENOTDIR) ? ENODEV : errno);
291  return false;
292  }
293  return true;
294 }
295 
297 {
298  int fd = m_fd; m_fd = -1;
299  if (devices[fd].smartIf)
300  (*devices[fd].smartIf)->Release (devices[fd].smartIf);
301  if (devices[fd].smartIfNVMe)
302  (*devices[fd].smartIfNVMe)->Release (devices[fd].smartIfNVMe);
303  if (devices[fd].plugin)
304  IODestroyPlugInInterface (devices[fd].plugin);
305  IOObjectRelease (devices[fd].ioob);
306  devices[fd].ioob = MACH_PORT_NULL;
307  return true;
308 }
309 
310 // makes a list of ATA or SCSI devices for the DEVICESCAN directive of
311 // smartd. Returns number N of devices, or -1 if out of
312 // memory. Allocates N+1 arrays: one of N pointers (devlist); the
313 // other N arrays each contain null-terminated character strings. In
314 // the case N==0, no arrays are allocated because the array of 0
315 // pointers has zero length, equivalent to calling malloc(0).
316 static int make_device_names (char*** devlist, const char* name) {
317  IOReturn err;
318  io_iterator_t i;
319  io_object_t device = MACH_PORT_NULL;
320  int result;
321  int index;
322 
323  if (!(strcmp("ATA", name) || strcmp("NVME", name))) {
324  return 0;
325  }
326 
327  err = IOServiceGetMatchingServices
328  (kIOMasterPortDefault, IOServiceMatching (kIOBlockStorageDeviceClass), &i);
329  if (err != kIOReturnSuccess)
330  return -1;
331 
332  // Count the devices.
333  result = 0;
334  while ((device = IOIteratorNext (i)) != MACH_PORT_NULL) {
335  if (is_smart_capable (device, name))
336  result++;
337  IOObjectRelease (device);
338  }
339 
340  // Create an array of service names.
341  IOIteratorReset (i);
342  if (! result)
343  goto error;
344  *devlist = (char**)calloc (result, sizeof (char *));
345  index = 0;
346  while ((device = IOIteratorNext (i)) != MACH_PORT_NULL) {
347  if (is_smart_capable (device, name))
348  {
349  io_string_t devName;
350  IORegistryEntryGetPath(device, kIOServicePlane, devName);
351  (*devlist)[index] = strdup (devName);
352  if (! (*devlist)[index])
353  goto error;
354  index++;
355  }
356  IOObjectRelease (device);
357  }
358 
359  IOObjectRelease (i);
360  return result;
361 
362  error:
363  if (device != MACH_PORT_NULL)
364  IOObjectRelease (device);
365  IOObjectRelease (i);
366  if (*devlist)
367  {
368  for (index = 0; index < result; index++)
369  if ((*devlist)[index])
370  free ((*devlist)[index]);
371  free (*devlist);
372  }
373  if(!result) // no devs found
374  return 0;
375 
376  return -1;
377 }
378 
379 /////////////////////////////////////////////////////////////////////////////
380 /// Implement standard ATA support
381 
383 : public /*implements*/ ata_device,
384  public /*extends*/ darwin_smart_device
385 {
386 public:
387  darwin_ata_device(smart_interface * intf, const char * dev_name, const char * req_type);
388  virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
389 
390 protected:
391  // virtual int ata_command_interface(smart_command_set command, int select, char * data);
392 };
393 
394 darwin_ata_device::darwin_ata_device(smart_interface * intf, const char * dev_name, const char * req_type)
395 : smart_device(intf, dev_name, "ata", req_type),
396  darwin_smart_device("ATA")
397 {
398 }
399 
401 {
402  if (!ata_cmd_is_ok(in,
403  true, // data_out_support
404  true, // multi_sector_support
405  false) // not supported by API
406  )
407  return false;
408 
409  int select = 0;
410  char * data = (char *)in.buffer;
411  int fd = get_fd();
412  IOATASMARTInterface **ifp = devices[fd].smartIf;
413  IOATASMARTInterface *smartIf;
414  IOReturn err;
415  int timeoutCount = 5;
416  int rc = 0;
417 
418  if (! ifp)
419  return -1;
420  smartIf = *ifp;
421  clear_err(); errno = 0;
422  do {
423  switch (in.in_regs.command) {
424  case ATA_IDENTIFY_DEVICE:
425  {
426  UInt32 dummy;
427  err = smartIf->GetATAIdentifyData (ifp, data, 512, &dummy);
428  if (err != kIOReturnSuccess && err != kIOReturnTimeout
429  && err != kIOReturnNotResponding)
430  printf ("identify failed: %#x\n", (unsigned) rc);
431  if (err == kIOReturnSuccess && isbigendian())
432  {
433  int i;
434  /* The system has already byte-swapped, undo it. */
435  for (i = 0; i < 256; i+=2)
436  swap2 (data + i);
437  }
438  }
439  break;
442  errno = ENOTSUP;
443  err = -1;
444  break;
445  case ATA_SMART_CMD:
446  switch (in.in_regs.features) {
448  err = smartIf->SMARTReadData (ifp, (ATASMARTData *)data);
449  break;
451  err = smartIf->SMARTReadDataThresholds (ifp,
452  (ATASMARTDataThresholds *)data);
453  break;
455  err = smartIf->SMARTReadLogAtAddress (ifp, in.in_regs.lba_low, data, 512 * in.in_regs.sector_count);
456  break;
458  err = smartIf->SMARTWriteLogAtAddress (ifp, in.in_regs.lba_low, data, 512 * in.in_regs.sector_count);
459  break;
460  case ATA_SMART_ENABLE:
461  case ATA_SMART_DISABLE:
462  err = smartIf->SMARTEnableDisableOperations (ifp, in.in_regs.features == ATA_SMART_ENABLE);
463  break;
464  case ATA_SMART_STATUS:
465  if (in.out_needed.lba_high) // statuscheck
466  {
467  Boolean is_failing;
468  err = smartIf->SMARTReturnStatus (ifp, &is_failing);
469  if (err == kIOReturnSuccess && is_failing) {
470  err = -1; // thresholds exceeded condition
471  out.out_regs.lba_high = 0x2c; out.out_regs.lba_mid = 0xf4;
472  }
473  else
474  out.out_regs.lba_high = 0xc2; out.out_regs.lba_mid = 0x4f;
475  break;
476  }
477  else err = 0;
478  break;
479  case ATA_SMART_AUTOSAVE:
480  err = smartIf->SMARTEnableDisableAutosave (ifp,
481  (in.in_regs.sector_count == 241 ? true : false));
482  break;
484  select = in.in_regs.lba_low;
485  if (select != SHORT_SELF_TEST && select != EXTEND_SELF_TEST)
486  {
487  errno = EINVAL;
488  return set_err(ENOSYS, "Unsupported SMART self-test mode");
489  }
490  err = smartIf->SMARTExecuteOffLineImmediate (ifp,
491  select == EXTEND_SELF_TEST);
492  break;
494  return set_err(ENOSYS, "SMART command not supported");
495  default:
496  return set_err(ENOSYS, "Unknown SMART command");
497  }
498  break;
499  default:
500  return set_err(ENOSYS, "Non-SMART commands not implemented");
501  }
502  } while ((err == kIOReturnTimeout || err == kIOReturnNotResponding)
503  && timeoutCount-- > 0);
504  if (err == kIOReturnExclusiveAccess)
505  errno = EBUSY;
506  rc = err == kIOReturnSuccess ? 0 : -1;
507  if (rc < 0) {
508  if (!get_errno())
509  set_err(errno);
510  return false;
511  }
512  return true;
513 }
514 
515 /////////////////////////////////////////////////////////////////////////////
516 /// Implement platform interface
517 
519 : public /*implements*/ smart_interface
520 {
521 public:
522  virtual std::string get_os_version_str();
523 
524  virtual std::string get_app_examples(const char * appname);
525 
526  virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
527  const char * pattern = 0);
528 
529 protected:
530  virtual ata_device * get_ata_device(const char * name, const char * type);
531 
532  virtual scsi_device * get_scsi_device(const char * name, const char * type);
533 
534  virtual nvme_device * get_nvme_device(const char * name, const char * type,
535  unsigned nsid);
536 
537  virtual smart_device * autodetect_smart_device(const char * name);
538 
539 };
540 
541 /////////////////////////////////////////////////////////////////////////////
542 /// NVMe support
543 
545 : public /*implements*/ nvme_device,
546  public /*extends*/ darwin_smart_device
547 {
548 public:
549  darwin_nvme_device(smart_interface * intf, const char * dev_name,
550  const char * req_type, unsigned nsid);
551 
552  virtual bool nvme_pass_through(const nvme_cmd_in & in, nvme_cmd_out & out);
553 };
554 
556  const char * req_type, unsigned nsid)
557 : smart_device(intf, dev_name, "nvme", req_type),
558  nvme_device(nsid),
559  darwin_smart_device("NVME")
560 {
561 }
562 
564 {
565  ARGUSED(out);
566  int fd = get_fd();
567  IONVMeSMARTInterface **ifp = devices[fd].smartIfNVMe;
569  IOReturn err = 0;
570  unsigned int page = in.cdw10 & 0xff;
571 
572  if (! ifp)
573  return -1;
574  smartIfNVMe = *ifp;
575  // currently only GetIdentifyData and SMARTReadData are supported
576  switch (in.opcode) {
578  err = smartIfNVMe->GetIdentifyData(ifp, (struct nvme_id_ctrl *) in.buffer, in.nsid); // FIXME
579  break;
581  if(page == 0x02)
582  err = smartIfNVMe->SMARTReadData(ifp, (struct nvme_smart_log *) in.buffer);
583  else /* GetLogPage() is not working yet */
584  return set_err(ENOSYS, "NVMe admin command:0x%02x/page:0x%02x is not supported",
585  in.opcode, page);
586  break;
587  default:
588  return set_err(ENOSYS, "NVMe admin command 0x%02x is not supported", in.opcode);
589  }
590  return true;
591 }
592 //////////////////////////////////////////////////////////////////////
593 
595 {
596  // now we are just getting darwin runtime version, to get OSX version more things needs to be done, see
597  // http://stackoverflow.com/questions/11072804/how-do-i-determine-the-os-version-at-runtime-in-os-x-or-ios-without-using-gesta
598  struct utsname osname;
599  uname(&osname);
600  return strprintf("%s %s %s", osname.sysname, osname.release, osname.machine);
601 }
602 
603 std::string darwin_smart_interface::get_app_examples(const char * appname)
604 {
605  if (!strcmp(appname, "smartctl"))
606  return smartctl_examples;
607  return ""; // ... so don't print again.
608 }
609 
610 ata_device * darwin_smart_interface::get_ata_device(const char * name, const char * type)
611 {
612  return new darwin_ata_device(this, name, type);
613 }
614 
616 {
617  return 0; // scsi devices are not supported [yet]
618 }
619 
620 nvme_device * darwin_smart_interface::get_nvme_device(const char * name, const char * type,
621  unsigned nsid)
622 {
623  return new darwin_nvme_device(this, name, type, nsid);
624 }
625 
627 { // TODO - refactor as a function
628  // Acceptable device names are:
629  // /dev/disk*
630  // /dev/rdisk*
631  // disk*
632  // IOService:*
633  // IODeviceTree:*
634  const char *devname = NULL;
635  io_object_t disk;
636 
637  if (strncmp (name, "/dev/rdisk", 10) == 0)
638  devname = name + 6;
639  else if (strncmp (name, "/dev/disk", 9) == 0)
640  devname = name + 5;
641  else if (strncmp (name, "disk", 4) == 0)
642  // allow user to just say 'disk0'
643  devname = name;
644  // Find the device. This part should be the same for the NVMe and ATA
645  if (devname) {
646  CFMutableDictionaryRef matcher;
647  matcher = IOBSDNameMatching (kIOMasterPortDefault, 0, devname);
648  disk = IOServiceGetMatchingService (kIOMasterPortDefault, matcher);
649  }
650  else {
651  disk = IORegistryEntryFromPath (kIOMasterPortDefault, name);
652  }
653  if (! disk) {
654  return 0;
655  }
656  io_registry_entry_t tmpdisk=disk;
657 
658 
659  while (! is_smart_capable (tmpdisk, "ATA"))
660  {
661  IOReturn err;
662  io_object_t prevdisk = tmpdisk;
663 
664  // Find this device's parent and try again.
665  err = IORegistryEntryGetParentEntry (tmpdisk, kIOServicePlane, &tmpdisk);
666  if (err != kIOReturnSuccess || ! tmpdisk)
667  {
668  IOObjectRelease (prevdisk);
669  break;
670  }
671  }
672  if (tmpdisk)
673  return new darwin_ata_device(this, name, "");
674  tmpdisk=disk;
675  while (! is_smart_capable (tmpdisk, "NVME"))
676  {
677  IOReturn err;
678  io_object_t prevdisk = tmpdisk;
679 
680  // Find this device's parent and try again.
681  err = IORegistryEntryGetParentEntry (tmpdisk, kIOServicePlane, &tmpdisk);
682  if (err != kIOReturnSuccess || ! tmpdisk)
683  {
684  IOObjectRelease (prevdisk);
685  break;
686  }
687  }
688  if (tmpdisk)
689  return new darwin_nvme_device(this, name, "", 0);
690 
691  // try ATA as a last option, for compatibility
692  return new darwin_ata_device(this, name, "");
693 }
694 
695 static void free_devnames(char * * devnames, int numdevs)
696 {
697  for (int i = 0; i < numdevs; i++)
698  free(devnames[i]);
699  free(devnames);
700 }
701 
703  const char * type, const char * pattern /*= 0*/)
704 {
705  if (pattern) {
706  set_err(EINVAL, "DEVICESCAN with pattern not implemented yet");
707  return false;
708  }
709 
710  // Make namelists
711  char * * atanames = 0; int numata = 0;
712  if (!type || !strcmp(type, "ata")) {
713  numata = make_device_names(&atanames, "ATA");
714  if (numata < 0) {
715  set_err(ENOMEM);
716  return false;
717  }
718  }
719  char * * nvmenames = 0; int numnvme = 0;
720  if (
721 #ifdef WITH_NVME_DEVICESCAN // TODO: Remove when NVMe support is no longer EXPERIMENTAL
722  !type ||
723 #else
724  type &&
725 #endif
726  !strcmp(type, "nvme")) {
727  numnvme = make_device_names(&nvmenames, "NVME");
728  if (numnvme < 0) {
729  set_err(ENOMEM);
730  return false;
731  }
732  }
733 
734  // Add to devlist
735  int i;
736  if (!type)
737  type="";
738  for (i = 0; i < numata; i++) {
739  ata_device * atadev = get_ata_device(atanames[i], type);
740  if (atadev)
741  devlist.push_back(atadev);
742  }
743  free_devnames(atanames, numata);
744 
745  for (i = 0; i < numnvme; i++) {
746  nvme_device * nvmedev = get_nvme_device(nvmenames[i], type, 0); // default nsid
747  if (nvmedev)
748  devlist.push_back(nvmedev);
749  }
750  free_devnames(nvmenames, numnvme);
751 
752  return true;
753 }
754 
755 } // namespace
756 
757 
758 /////////////////////////////////////////////////////////////////////////////
759 /// Initialize platform interface and register with smi()
760 
762 {
763  static os::darwin_smart_interface the_interface;
764  smart_interface::set(&the_interface);
765 }
virtual bool close()
Close device, return false on error.
Definition: os_darwin.cpp:296
virtual scsi_device * get_scsi_device(const char *name, const char *type)
Return standard SCSI device.
Definition: os_darwin.cpp:615
#define ATA_SMART_READ_LOG_SECTOR
Definition: atacmds.h:105
#define ATA_SMART_WRITE_LOG_SECTOR
Definition: atacmds.h:106
bool isbigendian()
Definition: utility.h:104
#define ATACMDS_H_CVSID
Definition: atacmds.h:28
ata_out_regs_flags out_needed
True if output register value needed.
IONVMeSMARTInterface ** smartIfNVMe
Definition: os_darwin.cpp:78
virtual smart_device * autodetect_smart_device(const char *name)
Autodetect device if no device type specified.
Definition: os_darwin.cpp:626
static struct @44 devices[20]
int m_fd
filedesc, -1 if not open.
Definition: os_darwin.cpp:113
#define ATA_SMART_CMD
Definition: atacmds.h:75
#define kIONVMeSMARTUserClientTypeID
Definition: os_darwin.h:41
int get_errno() const
Get last error number.
virtual ata_device * get_ata_device(const char *name, const char *type)
Return standard ATA device.
Definition: os_darwin.cpp:610
virtual bool ata_pass_through(const ata_cmd_in &in, ata_cmd_out &out)
ATA pass through.
Definition: os_darwin.cpp:400
virtual ~darwin_smart_device()
Definition: os_darwin.cpp:118
const char * m_mode
Mode string for deviceopen().
Definition: os_darwin.cpp:114
Implement platform interface.
Definition: os_darwin.cpp:518
virtual bool is_open() const
Return true if device is open.
Definition: os_darwin.cpp:124
static void free_devnames(char **devnames, int numdevs)
Definition: dev_legacy.cpp:276
#define ATA_SMART_DISABLE
Definition: atacmds.h:109
NVMe pass through input parameters.
#define ATA_SMART_AUTOSAVE
Definition: atacmds.h:102
virtual bool scan_smart_devices(smart_device_list &devlist, const char *type, const char *pattern=0)
Fill 'devlist' with devices of some 'type' with device names specified by some optional 'pattern'...
Definition: os_darwin.cpp:702
#define EXTEND_SELF_TEST
Definition: atacmds.h:118
#define ENOTSUP
Definition: os_linux.cpp:101
virtual nvme_device * get_nvme_device(const char *name, const char *type, unsigned nsid)
Return standard NVMe device.
Definition: os_darwin.cpp:620
void * buffer
Pointer to data buffer.
NVMe pass through output parameters.
Implement standard ATA support.
Definition: os_darwin.cpp:382
void push_back(smart_device *dev)
#define ATA_IDENTIFY_DEVICE
Definition: atacmds.h:72
ata_register lba_mid
#define DEV_INTERFACE_H_CVSID
Definition: dev_interface.h:21
#define INT64_H_CVSID
Definition: int64.h:23
#define ATA_IDENTIFY_PACKET_DEVICE
Definition: atacmds.h:73
uint32_t nsid
#define SCSICMDS_H_CVSID
Definition: scsicmds.h:33
ata_in_regs_48bit in_regs
Input registers.
ata_out_regs_48bit out_regs
Output registers.
ptr_t data
Definition: megaraid.h:94
Implement shared open/close routines with old functions.
Definition: os_darwin.cpp:91
List of devices for DEVICESCAN.
virtual std::string get_os_version_str()
Return info string about build host and/or OS version.
Definition: os_darwin.cpp:594
#define ATA_CHECK_POWER_MODE
Definition: atacmds.h:71
static void init()
Initialize platform interface and register with smi().
Definition: dev_legacy.cpp:341
The platform interface abstraction.
IOATASMARTInterface ** smartIf
Definition: os_darwin.cpp:77
NVMe device access.
darwin_smart_device(const char *mode)
Definition: os_darwin.cpp:95
static void set(smart_interface *intf)
Set interface to use, must be called from init().
void * buffer
Pointer to data buffer.
NVMe support.
Definition: os_darwin.cpp:544
IOCFPlugInInterface ** plugin
Definition: os_darwin.cpp:76
static const char smartctl_examples[]
Definition: os_darwin.cpp:52
unsigned char opcode
Opcode (CDW0 07:00)
static bool is_smart_capable(io_object_t dev, const char *type)
Definition: os_darwin.cpp:130
virtual bool nvme_pass_through(const nvme_cmd_in &in, nvme_cmd_out &out)
NVMe pass through.
Definition: os_darwin.cpp:563
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
darwin_nvme_device(smart_interface *intf, const char *dev_name, const char *req_type, unsigned nsid)
Definition: os_darwin.cpp:555
const char * os_darwin_cpp_cvsid
Definition: os_darwin.cpp:48
#define ATA_SMART_READ_VALUES
Definition: atacmds.h:100
ata_register lba_low
#define kIOPropertyNVMeSMARTCapableKey
Definition: os_darwin.h:38
SCSI device access.
unsigned nsid
Namespace ID.
ata_register features
#define ATA_SMART_AUTO_OFFLINE
Definition: atacmds.h:113
#define OS_DARWIN_H_CVSID
Definition: os_darwin.h:27
#define kIOPropertySMARTCapableKey
Definition: os_darwin.h:34
bool ata_cmd_is_ok(const ata_cmd_in &in, bool data_out_support=false, bool multi_sector_support=false, bool ata_48bit_support=false)
Check command input parameters (old version).
io_object_t ioob
Definition: os_darwin.cpp:75
static int make_device_names(char ***devlist, const char *name)
Definition: os_darwin.cpp:316
#define ATA_SMART_READ_THRESHOLDS
Definition: atacmds.h:101
Base class for all devices.
Definition: dev_interface.h:39
ATA device access.
ata_register sector_count
#define SHORT_SELF_TEST
Definition: atacmds.h:117
const char * dev_darwin_cpp_cvsid
Definition: os_darwin.cpp:81
#define ATA_SMART_IMMEDIATE_OFFLINE
Definition: atacmds.h:104
virtual std::string get_app_examples(const char *appname)
Return example string for program 'appname'.
Definition: os_darwin.cpp:603
virtual bool open()
Open device, return false on error.
Definition: os_darwin.cpp:178
#define kIOATABlockStorageDeviceClass
Definition: os_darwin.h:29
ata_register command
ATA pass through input parameters.
unsigned cdw10
#define ATA_SMART_ENABLE
Definition: atacmds.h:108
void swap2(char *location)
Definition: atacmds.cpp:314
darwin_ata_device(smart_interface *intf, const char *dev_name, const char *req_type)
Definition: os_darwin.cpp:394
std::string strprintf(const char *fmt,...)
Definition: utility.cpp:750
IOReturn(* SMARTReadData)(void *interface, struct nvme_smart_log *NVMeSMARTData)
Definition: os_darwin.h:59
ata_register lba_high
void clear_err()
Clear last error info.
#define kIONVMeSMARTInterfaceID
Definition: os_darwin.h:46
const char * get_dev_name() const
Get device (path)name.
IOReturn(* GetIdentifyData)(void *interface, struct nvme_id_ctrl *NVMeIdentifyControllerStruct, unsigned int ns)
Definition: os_darwin.h:63
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
ATA pass through output parameters.
int get_fd() const
Return filedesc for derived classes.
Definition: os_darwin.cpp:109
#define ARGUSED(x)
Definition: os_darwin.cpp:46
#define UTILITY_H_CVSID
Definition: utility.h:28
#define ATA_SMART_STATUS
Definition: atacmds.h:110