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