smartmontools SVN Rev 5612
Utility to control and monitor storage systems with "S.M.A.R.T."
dev_interface.h
Go to the documentation of this file.
1/*
2 * dev_interface.h
3 *
4 * Home page of code is: https://www.smartmontools.org
5 *
6 * Copyright (C) 2008-22 Christian Franke
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11#ifndef DEV_INTERFACE_H
12#define DEV_INTERFACE_H
13
14#define DEV_INTERFACE_H_CVSID "$Id: dev_interface.h 5455 2023-02-12 05:13:17Z dpgilbert $\n"
15
16#include "utility.h"
17
18#include <stdexcept>
19#include <string>
20#include <vector>
21
22/////////////////////////////////////////////////////////////////////////////
23// Common functionality for all device types
24
25// Forward declarations
26class smart_interface;
27class ata_device;
28class scsi_device;
29class nvme_device;
30
31/// Base class for all devices
33{
34// Types
35public:
36 /// Device info strings
37 struct device_info {
39 { }
40 device_info(const char * d_name, const char * d_type, const char * r_type)
41 : dev_name(d_name), info_name(d_name),
42 dev_type(d_type), req_type(r_type)
43 { }
44
45 std::string dev_name; ///< Device (path)name
46 std::string info_name; ///< Informal name
47 std::string dev_type; ///< Actual device type
48 std::string req_type; ///< Device type requested by user, empty if none
49 };
50
51 /// Error (number,message) pair
52 struct error_info {
53 explicit error_info(int n = 0)
54 : no(n) { }
55 error_info(int n, const char * m)
56 : no(n), msg(m) { }
57 void clear()
58 { no = 0; msg.erase(); }
59
60 int no; ///< Error number
61 std::string msg; ///< Error message
62 };
63
64// Construction
65protected:
66 /// Constructor to init interface and device info.
67 /// Must be called in implementation classes.
68 smart_device(smart_interface * intf, const char * dev_name,
69 const char * dev_type, const char * req_type);
70
71 /// Dummy enum for dummy constructor.
73 /// Dummy constructor for abstract classes.
74 /// Must never be called in implementation classes.
76
77public:
78 virtual ~smart_device();
79
80// Attributes
81public:
82 ///////////////////////////////////////////////
83 // Dynamic downcasts to actual device flavor
84
85 /// Return true if ATA device
86 bool is_ata() const
87 { return !!m_ata_ptr; }
88 /// Return true if SCSI device
89 bool is_scsi() const
90 { return !!m_scsi_ptr; }
91 /// Return true if NVMe device
92 bool is_nvme() const
93 { return !!m_nvme_ptr; }
94
95 /// Downcast to ATA device.
97 { return m_ata_ptr; }
98 /// Downcast to ATA device (const).
99 const ata_device * to_ata() const
100 { return m_ata_ptr; }
101 /// Downcast to SCSI device.
103 { return m_scsi_ptr; }
104 /// Downcast to SCSI device (const).
105 const scsi_device * to_scsi() const
106 { return m_scsi_ptr; }
107 /// Downcast to NVMe device.
109 { return m_nvme_ptr; }
110 /// Downcast to NVMe device (const).
111 const nvme_device * to_nvme() const
112 { return m_nvme_ptr; }
113
114 ///////////////////////////////////////////////
115 // Device information
116
117 /// Get device info struct.
118 const device_info & get_info() const
119 { return m_info; }
120
121 /// Get device (path)name.
122 const char * get_dev_name() const
123 { return m_info.dev_name.c_str(); }
124 /// Get informal name.
125 const char * get_info_name() const
126 { return m_info.info_name.c_str(); }
127 /// Get device type.
128 const char * get_dev_type() const
129 { return m_info.dev_type.c_str(); }
130 /// Get type requested by user, empty if none.
131 const char * get_req_type() const
132 { return m_info.req_type.c_str(); }
133
134protected:
135 /// R/W access to device info struct.
137 { return m_info; }
138
139public:
140 ///////////////////////////////////////////////
141 // Last error information
142
143 /// Get last error info struct.
144 const error_info & get_err() const
145 { return m_err; }
146 /// Get last error number.
147 int get_errno() const
148 { return m_err.no; }
149 /// Get last error message.
150 const char * get_errmsg() const
151 { return m_err.msg.c_str(); }
152
153 /// Return true if last error indicates an unsupported system call.
154 /// Default implementation returns true on ENOSYS and ENOTSUP.
155 virtual bool is_syscall_unsup() const;
156
157 /// Set last error number and message.
158 /// Printf()-like formatting is supported.
159 /// Returns false always to allow use as a return expression.
160 bool set_err(int no, const char * msg, ...)
162
163 /// Set last error info struct.
164 bool set_err(const error_info & err)
165 { m_err = err; return false; }
166
167 /// Clear last error info.
169 { m_err.clear(); }
170
171 /// Set last error number and default message.
172 /// Message is retrieved from interface's get_msg_for_errno(no).
173 bool set_err(int no);
174
175 /// Get current number of allocated 'smart_device' objects.
176 static int get_num_objects()
177 { return s_num_objects; }
178
179// Operations
180public:
181 ///////////////////////////////////////////////
182 // Device open/close
183 // Must be implemented in derived class
184
185 /// Return true if device is open.
186 virtual bool is_open() const = 0;
187
188 /// Open device, return false on error.
189 virtual bool open() = 0;
190
191 /// Close device, return false on error.
192 virtual bool close() = 0;
193
194 /// Open device with autodetection support.
195 /// May return another device for further access.
196 /// In this case, the original pointer is no longer valid.
197 /// Default implementation calls 'open()' and returns 'this'.
198 virtual smart_device * autodetect_open();
199
200 ///////////////////////////////////////////////
201 // Support for checking power mode reported by operating system
202
203 /// Early test if device is powered up or down.
204 /// Can be used without calling 'open()' first!
205 /// Return true when device is powered down, false when
206 /// powered up. If this function is not implemented or
207 /// the mode cannot be determined, return false.
208 /// Default implementation returns false.
209 virtual bool is_powered_down();
210
211 ///////////////////////////////////////////////
212 // Support for tunnelled devices
213
214 /// Return true if other device is owned by this device.
215 /// Default implementation returns false.
216 virtual bool owns(const smart_device * dev) const;
217
218 /// Release ownership of other device.
219 /// Default implementation does nothing.
220 virtual void release(const smart_device * dev);
221
222protected:
223 /// Get interface which produced this object.
225 { return m_intf; }
226 /// Get interface which produced this object (const).
227 const smart_interface * smi() const
228 { return m_intf; }
229
230// Implementation
231private:
235
236 // Pointers for to_ata(), to_scsi(), to_nvme()
237 // set by ATA/SCSI/NVMe interface classes.
238 friend class ata_device;
240 friend class scsi_device;
242 friend class nvme_device;
244
245 // Number of objects.
246 static int s_num_objects;
247
248 // Prevent copy/assignment
250 void operator=(const smart_device &);
251};
252
253
254/////////////////////////////////////////////////////////////////////////////
255// ATA specific interface
256
257/// ATA register value and info whether it has ever been set
258// (Automatically set by first assignment)
260{
261public:
263 : m_val(0x00), m_is_set(false) { }
264
265 ata_register & operator=(unsigned char x)
266 { m_val = x; m_is_set = true; return * this; }
267
268 unsigned char val() const
269 { return m_val; }
270 operator unsigned char() const
271 { return m_val; }
272
273 bool is_set() const
274 { return m_is_set; }
275
276private:
277 unsigned char m_val; ///< Register value
278 bool m_is_set; ///< true if set
279};
280
281/// ATA Input registers (for 28-bit commands)
283{
284 // ATA-6/7 register names // ATA-3/4/5 // ATA-8
285 ata_register features; // features // features
286 ata_register sector_count; // sector count // count
287 ata_register lba_low; // sector number // ]
288 ata_register lba_mid; // cylinder low // ] lba
289 ata_register lba_high; // cylinder high // ]
290 ata_register device; // device/head // device
291 ata_register command; // command // command
292
293 /// Return true if any register is set
294 bool is_set() const
295 { return (features.is_set() || sector_count.is_set()
297 || device.is_set() || command.is_set()); }
298};
299
300/// ATA Output registers (for 28-bit commands)
302{
310
311 /// Return true if any register is set
312 bool is_set() const
313 { return (error.is_set() || sector_count.is_set()
315 || device.is_set() || status.is_set()); }
316};
317
318
319/// 16-bit alias to a 8-bit ATA register pair.
321{
322public:
324 : m_lo(lo), m_hi(hi) { }
325
326 ata_reg_alias_16 & operator=(unsigned short x)
327 { m_lo = (unsigned char) x;
328 m_hi = (unsigned char)(x >> 8);
329 return * this; }
330
331 unsigned short val() const
332 { return m_lo | (m_hi << 8); }
333 operator unsigned short() const
334 { return m_lo | (m_hi << 8); }
335
336private:
338
339 // References must not be copied.
342};
343
344
345/// 48-bit alias to six 8-bit ATA registers (for LBA).
347{
348public:
350 ata_register & hl, ata_register & hm, ata_register & hh)
351 : m_ll(ll), m_lm(lm), m_lh(lh),
352 m_hl(hl), m_hm(hm), m_hh(hh)
353 { }
354
356 {
357 m_ll = (unsigned char) x;
358 m_lm = (unsigned char)(x >> 8);
359 m_lh = (unsigned char)(x >> 16);
360 m_hl = (unsigned char)(x >> 24);
361 m_hm = (unsigned char)(x >> 32);
362 m_hh = (unsigned char)(x >> 40);
363 return * this;
364 }
365
366 uint64_t val() const
367 {
368 return ( (unsigned)m_ll
369 | ((unsigned)m_lm << 8)
370 | ((unsigned)m_lh << 16)
371 | ((unsigned)m_hl << 24)
372 | ((uint64_t)m_hm << 32)
373 | ((uint64_t)m_hh << 40));
374 }
375
376 operator uint64_t() const
377 { return val(); }
378
379private:
381 & m_hl, & m_hm, & m_hh;
382
383 // References must not be copied.
386};
387
388
389/// ATA Input registers for 48-bit commands
390// See section 4.14 of T13/1532D Volume 1 Revision 4b
391//
392// Uses ATA-6/7 method to specify 16-bit registers as
393// recent (low byte) and previous (high byte) content of
394// 8-bit registers.
395//
396// (ATA-8 ACS does not longer follow this scheme, it uses
397// abstract registers with sufficient size and leaves the
398// actual mapping to the transport layer.)
399//
401: public ata_in_regs // "most recently written" registers
402{
403 ata_in_regs prev; ///< "previous content"
404
405 // 16-bit aliases for above pair.
411
412 // 48-bit alias to all 8-bit LBA registers.
414
415 /// Return true if 48-bit command
416 bool is_48bit_cmd() const
417 { return prev.is_set(); }
418
419 /// Return true if 48-bit command with any nonzero high byte
420 bool is_real_48bit_cmd() const
421 { return ( prev.features || prev.sector_count
422 || prev.lba_low || prev.lba_mid || prev.lba_high); }
423
425};
426
427
428/// ATA Output registers for 48-bit commands
430: public ata_out_regs // read with HOB=0
431{
432 ata_out_regs prev; ///< read with HOB=1
433
434 // 16-bit aliases for above pair.
439
440 // 48-bit alias to all 8-bit LBA registers.
442
444};
445
446
447/// Flags for each ATA output register
449{
451
452 /// Return true if any flag is set.
453 bool is_set() const
454 { return ( error || sector_count || lba_low
455 || lba_mid || lba_high || device || status); }
456
457 /// Default constructor clears all flags.
459 : error(false), sector_count(false), lba_low(false), lba_mid(false),
460 lba_high(false), device(false), status(false) { }
461};
462
463
464/// ATA pass through input parameters
466{
467 ata_in_regs_48bit in_regs; ///< Input registers
468 ata_out_regs_flags out_needed; ///< True if output register value needed
469 enum { no_data = 0, data_in, data_out } direction; ///< I/O direction
470 void * buffer; ///< Pointer to data buffer
471 unsigned size; ///< Size of buffer
472
473 /// Prepare for 28-bit DATA IN command
474 void set_data_in(void * buf, unsigned nsectors)
475 {
476 buffer = buf;
477 in_regs.sector_count = nsectors;
479 size = nsectors * 512;
480 }
481
482 /// Prepare for 28-bit DATA OUT command
483 void set_data_out(const void * buf, unsigned nsectors)
484 {
485 buffer = const_cast<void *>(buf);
486 in_regs.sector_count = nsectors;
488 size = nsectors * 512;
489 }
490
491 /// Prepare for 48-bit DATA IN command
492 void set_data_in_48bit(void * buf, unsigned nsectors)
493 {
494 buffer = buf;
495 // Note: This also sets 'in_regs.is_48bit_cmd()'
496 in_regs.sector_count_16 = nsectors;
498 size = nsectors * 512;
499 }
500
501 ata_cmd_in();
502};
503
504/// ATA pass through output parameters
506{
507 ata_out_regs_48bit out_regs; ///< Output registers
508
509 ata_cmd_out();
510};
511
512/// ATA device access
514: virtual public /*extends*/ smart_device
515{
516public:
517 /// ATA pass through.
518 /// Return false on error.
519 /// Must be implemented in derived class.
520 virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) = 0;
521
522 /// ATA pass through without output registers.
523 /// Return false on error.
524 /// Calls ata_pass_through(in, dummy), cannot be reimplemented.
525 bool ata_pass_through(const ata_cmd_in & in);
526
527 /// Return true if OS caches ATA identify sector.
528 /// Default implementation returns false.
529 virtual bool ata_identify_is_cached() const;
530
531protected:
532 /// Flags for ata_cmd_is_supported().
533 enum {
534 supports_data_out = 0x01, // PIO DATA OUT
535 supports_smart_status = 0x02, // read output registers for SMART STATUS only
536 supports_output_regs = 0x04, // read output registers for all commands
537 supports_multi_sector = 0x08, // more than one sector (1 DRQ/sector variant)
538 supports_48bit_hi_null = 0x10, // 48-bit commands with null high bytes only
539 supports_48bit = 0x20, // all 48-bit commands
540 };
541
542 /// Check command input parameters.
543 /// Return false if required features are not implemented.
544 /// Calls set_err(...) accordingly.
545 bool ata_cmd_is_supported(const ata_cmd_in & in, unsigned flags,
546 const char * type = 0);
547
548 /// Check command input parameters (old version).
549 // TODO: Remove if no longer used.
550 bool ata_cmd_is_ok(const ata_cmd_in & in,
551 bool data_out_support = false,
552 bool multi_sector_support = false,
553 bool ata_48bit_support = false)
554 {
555 return ata_cmd_is_supported(in,
556 (data_out_support ? supports_data_out : 0) |
558 (multi_sector_support ? supports_multi_sector : 0) |
559 (ata_48bit_support ? supports_48bit : 0));
560 }
561
562 /// Hide/unhide ATA interface.
563 void hide_ata(bool hide = true)
564 { m_ata_ptr = (!hide ? this : 0); }
565
566 /// Default constructor, registers device as ATA.
569 { hide_ata(false); }
570};
571
572
573/////////////////////////////////////////////////////////////////////////////
574// SCSI specific interface
575
576struct scsi_cmnd_io;
577
579{
583};
584
585/// SCSI device access
587: virtual public /*extends*/ smart_device
588{
589public:
590 /// SCSI pass through.
591 /// Returns false on error.
592 virtual bool scsi_pass_through(scsi_cmnd_io * iop) = 0;
593
594 // Call scsi_pass_through and check sense.
596 const char * msg = "");
597
598 /// Always try READ CAPACITY(10) (rcap10) first but once we know
599 /// rcap16 is needed, use it instead.
601 { rcap16_first = true; }
602
603 bool use_rcap16() const
604 { return rcap16_first; }
605
607
608 bool is_spc4_or_higher() const { return spc4_or_above; }
609
610 bool query_cmd_support();
611
612 bool checked_cmd_support() const { return rsoc_queried; }
613
614 enum scsi_cmd_support cmd_support_level(uint8_t opcode, bool sa_valid,
615 uint16_t sa,
616 bool for_lsense_spc = false) const;
617
618protected:
619 /// Hide/unhide SCSI interface.
620 void hide_scsi(bool hide = true)
621 { m_scsi_ptr = (!hide ? this : 0); }
622
623 /// Default constructor, registers device as SCSI.
626 rcap16_first(false),
627 spc4_or_above(false),
628 rsoc_queried(false),
635 { hide_scsi(false); }
636
637private:
640
648};
649
650
651/////////////////////////////////////////////////////////////////////////////
652// NVMe specific interface
653
654/// NVMe pass through input parameters
656{
657 unsigned char opcode; ///< Opcode (CDW0 07:00)
658 unsigned nsid; ///< Namespace ID
659 unsigned cdw10, cdw11, cdw12, cdw13, cdw14, cdw15; ///< Cmd specific
660
661 void * buffer; ///< Pointer to data buffer
662 unsigned size; ///< Size of buffer
663
664 enum {
665 no_data = 0x0, data_out = 0x1, data_in = 0x2, data_io = 0x3
666 };
667
668 /// Get I/O direction from opcode
669 unsigned char direction() const
670 { return (opcode & 0x3); }
671
672 // Prepare for DATA IN command
673 void set_data_in(unsigned char op, void * buf, unsigned sz)
674 {
675 opcode = op;
676 if (direction() != data_in)
677 throw std::logic_error("invalid opcode for DATA IN");
678 buffer = buf;
679 size = sz;
680 }
681
683 : opcode(0), nsid(0),
684 cdw10(0), cdw11(0), cdw12(0), cdw13(0), cdw14(0), cdw15(0),
685 buffer(0), size(0)
686 { }
687};
688
689/// NVMe pass through output parameters
691{
692 unsigned result; ///< Command specific result (DW0)
693 unsigned short status; ///< Status Field (DW3 31:17)
694 bool status_valid; ///< true if status is valid
695
697 : result(0), status(0), status_valid(false)
698 { }
699};
700
701/// NVMe device access
703: virtual public /*extends*/ smart_device
704{
705public:
706 /// NVMe pass through.
707 /// Return false on error.
708 virtual bool nvme_pass_through(const nvme_cmd_in & in, nvme_cmd_out & out) = 0;
709
710 /// Get namespace id.
711 unsigned get_nsid() const
712 { return m_nsid; }
713
714protected:
715 /// Hide/unhide NVMe interface.
716 void hide_nvme(bool hide = true)
717 { m_nvme_ptr = (!hide ? this : 0); }
718
719 /// Constructor requires namespace ID, registers device as NVMe.
720 explicit nvme_device(unsigned nsid)
722 m_nsid(nsid)
723 { hide_nvme(false); }
724
725 /// Set namespace id.
726 /// Should be called in open() function if get_nsid() returns 0.
727 void set_nsid(unsigned nsid)
728 { m_nsid = nsid; }
729
730 /// Set last error number and message if pass-through returns NVMe error status.
731 /// Returns false always to allow use as a return expression.
732 bool set_nvme_err(nvme_cmd_out & out, unsigned status, const char * msg = 0);
733
734private:
735 unsigned m_nsid;
736};
737
738
739/////////////////////////////////////////////////////////////////////////////
740/// Smart pointer class for device pointers
741
742template <class Dev>
744{
745public:
746 typedef Dev device_type;
747
748 /// Construct from optional pointer to device
749 /// and optional pointer to base device.
751 smart_device * base_dev = 0)
752 : m_dev(dev), m_base_dev(base_dev) { }
753
754 /// Destructor deletes device object.
756 { reset(); }
757
758 /// Assign a new pointer.
759 /// Throws if a pointer is already assigned.
761 {
762 if (m_dev)
763 fail();
764 m_dev = dev;
765 }
766
767 /// Delete device object and clear the pointer.
768 void reset()
769 {
770 if (m_dev) {
771 if (m_base_dev && m_dev->owns(m_base_dev))
772 m_dev->release(m_base_dev);
773 delete m_dev;
774 m_dev = 0;
775 }
776 }
777
778 /// Return the pointer and release ownership.
780 {
781 device_type * dev = m_dev;
782 m_dev = 0;
783 return dev;
784 }
785
786 /// Replace the pointer.
787 /// Used to call dev->autodetect_open().
789 { m_dev = dev; }
790
791 /// Return the pointer.
792 device_type * get() const
793 { return m_dev; }
794
795 /// Pointer dereferencing.
797 { return *m_dev; }
798
799 /// Pointer dereferencing.
801 { return m_dev; }
802
803 /// For (ptr != 0) check.
804 operator bool() const
805 { return !!m_dev; }
806
807 /// For (ptr == 0) check.
808 bool operator !() const
809 { return !m_dev; }
810
811private:
814
815 void fail() const
816 { throw std::logic_error("any_device_auto_ptr: wrong usage"); }
817
818 // Prevent copy/assignment
821};
822
827
828
829/////////////////////////////////////////////////////////////////////////////
830// smart_device_list
831
832/// List of devices for DEVICESCAN
834{
835// Construction
836public:
838 { }
839
841 {
842 for (unsigned i = 0; i < m_list.size(); i++)
843 delete m_list[i];
844 }
845
846// Attributes
847 unsigned size() const
848 { return m_list.size(); }
849
850// Operations
851 void clear()
852 {
853 for (unsigned i = 0; i < m_list.size(); i++)
854 delete m_list[i];
855 m_list.clear();
856 }
857
858
860 { m_list.push_back(dev); }
861
863 {
864 m_list.push_back(dev.get());
865 dev.release();
866 }
867
868 smart_device * at(unsigned i)
869 { return m_list.at(i); }
870
871 const smart_device * at(unsigned i) const
872 { return m_list.at(i); }
873
874 smart_device * release(unsigned i)
875 {
876 smart_device * dev = m_list.at(i);
877 m_list[i] = 0;
878 return dev;
879 }
880
881 void append(smart_device_list & devlist)
882 {
883 for (unsigned i = 0; i < devlist.size(); i++) {
884 smart_device * dev = devlist.at(i);
885 if (!dev)
886 continue;
887 push_back(dev);
888 devlist.m_list.at(i) = 0;
889 }
890 }
891
892// Implementation
893private:
894 std::vector<smart_device *> m_list;
895
896 // Prevent copy/assignment
899};
900
901
902/// List of types for DEVICESCAN
903typedef std::vector<std::string> smart_devtype_list;
904
905
906/////////////////////////////////////////////////////////////////////////////
907// smart_interface
908
909/// The platform interface abstraction
911{
912public:
913 /// Initialize platform interface and register with smi().
914 /// Must be implemented by platform module and register interface with set()
915 static void init();
916
918 { }
919
921 { }
922
923 /// Return info string about build host and/or OS version.
924 /// Default implementation returns SMARTMONTOOLS_BUILD_HOST.
925 virtual std::string get_os_version_str();
926
927 /// Return valid args for device type option/directive.
928 /// Default implementation returns "ata, scsi, sat, usb*..."
929 /// concatenated with result from get_valid_custom_dev_types_str().
930 virtual std::string get_valid_dev_types_str();
931
932 /// Return example string for program 'appname'.
933 /// Default implementation returns empty string.
934 /// For the migration of print_smartctl_examples(),
935 /// function is allowed to print examples to stdout.
936 /// TODO: Remove this hack.
937 virtual std::string get_app_examples(const char * appname);
938
939 /// Disable/Enable system auto standby/sleep mode.
940 /// Return false if unsupported or if system is running
941 /// on battery.
942 /// Default implementation returns false.
943 virtual bool disable_system_auto_standby(bool disable);
944
945
946 ///////////////////////////////////////////////
947 // Last error information
948
949 /// Get last error info struct.
951 { return m_err; }
952 /// Get last error number.
953 int get_errno() const
954 { return m_err.no; }
955 /// Get last error message.
956 const char * get_errmsg() const
957 { return m_err.msg.c_str(); }
958
959 /// Set last error number and message.
960 /// Printf()-like formatting is supported.
961 /// Returns false always to allow use as a return expression.
962 bool set_err(int no, const char * msg, ...)
964
965 /// Set last error number and message.
966 /// Printf()-like formatting is supported.
967 /// Returns nullptr always to allow use as a return expression
968 /// of any pointer type.
969 // (Not using 'std::nullptr_t' because it requires <cstddef>)
970 decltype(nullptr) set_err_np(int no, const char * msg, ...)
972
973 /// Set last error info struct.
974 bool set_err(const smart_device::error_info & err)
975 { m_err = err; return false; }
976
977 /// Clear last error info.
979 { m_err.clear(); }
980
981 /// Set last error number and default message.
982 /// Message is retrieved from get_msg_for_errno(no).
983 bool set_err(int no);
984
985 /// Set last error number and default message to any error_info.
986 /// Used by set_err(no).
987 bool set_err_var(smart_device::error_info * err, int no);
988
989 /// Convert error number into message, used by set_err(no).
990 /// Default implementation returns strerror(no).
991 virtual const char * get_msg_for_errno(int no);
992
993 ///////////////////////////////////////////////////////////////////////////
994 // Device factory:
995
996 /// Return device object for device 'name' with some 'type'.
997 /// 'type' is 0 if not specified by user.
998 /// Return 0 on error.
999 /// Default implementation selects between ata, scsi and custom device.
1000 virtual smart_device * get_smart_device(const char * name, const char * type);
1001
1002 /// Fill 'devlist' with devices of some 'type' with device names
1003 /// specified by some optional 'pattern'.
1004 /// Use platform specific default if 'type' is empty or 0.
1005 /// Return false on error.
1006 /// Default implementation returns false;
1007 virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
1008 const char * pattern = 0);
1009
1010 /// Fill 'devlist' with devices of all 'types' with device names
1011 /// specified by some optional 'pattern'.
1012 /// Use platform specific default if 'types' is empty.
1013 /// Return false on error.
1014 /// Default implementation calls above function for all types
1015 /// and concatenates the results.
1016 virtual bool scan_smart_devices(smart_device_list & devlist,
1017 const smart_devtype_list & types, const char * pattern = 0);
1018
1019 /// Return unique device name which is (only) suitable for duplicate detection.
1020 /// Default implementation resolves symlinks on POSIX systems and appends
1021 /// " [type]" if is_raid_dev_type(type)' returns true.
1022 virtual std::string get_unique_dev_name(const char * name, const char * type) const;
1023
1024 /// Return true if the 'type' string contains a RAID drive number.
1025 /// Default implementation returns true if 'type' starts with '[^,]+,[0-9]'
1026 /// but not with 'sat,'.
1027 virtual bool is_raid_dev_type(const char * type) const;
1028
1029protected:
1030 /// Return standard ATA device.
1031 virtual ata_device * get_ata_device(const char * name, const char * type) = 0;
1032
1033 /// Return standard SCSI device.
1034 virtual scsi_device * get_scsi_device(const char * name, const char * type) = 0;
1035
1036 /// Return standard NVMe device.
1037 /// Default implementation returns 0.
1038 virtual nvme_device * get_nvme_device(const char * name, const char * type,
1039 unsigned nsid);
1040
1041 /// Autodetect device if no device type specified.
1042 virtual smart_device * autodetect_smart_device(const char * name) = 0;
1043
1044 /// Return device for platform specific 'type'.
1045 /// Default implementation returns 0.
1046 virtual smart_device * get_custom_smart_device(const char * name, const char * type);
1047
1048 /// Return valid 'type' args accepted by above.
1049 /// This is called in get_valid_dev_types_str().
1050 /// Default implementation returns empty string.
1051 virtual std::string get_valid_custom_dev_types_str();
1052
1053 /// Return ATA->SCSI of NVMe->SCSI filter for a SAT, SNT or USB 'type'.
1054 /// Uses get_sat_device and get_snt_device.
1055 /// Return 0 and delete 'scsidev' on error.
1056 virtual smart_device * get_scsi_passthrough_device(const char * type, scsi_device * scsidev);
1057
1058 /// Return ATA->SCSI filter for a SAT or USB 'type'.
1059 /// Device 'scsidev' is used for SCSI access.
1060 /// Return 0 and delete 'scsidev' on error.
1061 /// Override only if platform needs special handling.
1062 virtual ata_device * get_sat_device(const char * type, scsi_device * scsidev);
1063 //{ implemented in scsiata.cpp }
1064
1065 /// Return NVMe->SCSI filter for a SNT or USB 'type'.
1066 /// Device 'scsidev' is used for SCSI access.
1067 /// Return 0 and delete 'scsidev' on error.
1068 /// Override only if platform needs special handling.
1069 virtual nvme_device * get_snt_device(const char * type, scsi_device * scsidev);
1070 //{ implemented in scsinvme.cpp }
1071
1072 /// Return filter for Intelliprop controllers.
1073 virtual ata_device * get_intelliprop_device(const char * type, ata_device * atadev);
1074 //{ implemented in dev_intelliprop.cpp }
1075
1076 /// Return JMB93x->ATA filter.
1077 /// Device 'smartdev' is used for ATA or SCSI R/W access.
1078 /// Return 0 and delete 'scsidev' on error.
1079 /// Override only if platform needs special handling.
1080 virtual ata_device * get_jmb39x_device(const char * type, smart_device * smartdev);
1081 //{ implemented in dev_jmb39x_raid.cpp }
1082
1083public:
1084 /// Try to detect a SAT device behind a SCSI interface.
1085 /// Inquiry data can be passed if available.
1086 /// Return appropriate device if yes, otherwise 0.
1087 /// Override only if platform needs special handling.
1088 virtual ata_device * autodetect_sat_device(scsi_device * scsidev,
1089 const unsigned char * inqdata, unsigned inqsize);
1090 //{ implemented in scsiata.cpp }
1091
1092 /// Get type name for USB device with known VENDOR:PRODUCT ID.
1093 /// Return name if device known and supported, otherwise 0.
1094 virtual const char * get_usb_dev_type_by_id(int vendor_id, int product_id,
1095 int version = -1);
1096 //{ implemented in scsiata.cpp }
1097
1098protected:
1099 /// Set interface to use, must be called from init().
1100 static void set(smart_interface * intf)
1101 { s_instance = intf; }
1102
1103// Implementation
1104private:
1106
1107 friend smart_interface * smi(); // below
1108 static smart_interface * s_instance; ///< Pointer to the interface object.
1109
1110 // Prevent copy/assignment
1113};
1114
1115
1116/////////////////////////////////////////////////////////////////////////////
1117// smi()
1118
1119/// Global access to the (usually singleton) smart_interface
1121 { return smart_interface::s_instance; }
1122
1123/////////////////////////////////////////////////////////////////////////////
1124
1125#endif // DEV_INTERFACE_H
Smart pointer class for device pointers.
device_type * release()
Return the pointer and release ownership.
~any_device_auto_ptr()
Destructor deletes device object.
device_type * m_dev
void reset()
Delete device object and clear the pointer.
device_type * get() const
Return the pointer.
void replace(device_type *dev)
Replace the pointer.
void operator=(const any_device_auto_ptr< Dev > &)
void operator=(device_type *dev)
Assign a new pointer.
bool operator!() const
For (ptr == 0) check.
any_device_auto_ptr(device_type *dev=0, smart_device *base_dev=0)
Construct from optional pointer to device and optional pointer to base device.
device_type * operator->() const
Pointer dereferencing.
device_type & operator*() const
Pointer dereferencing.
smart_device * m_base_dev
any_device_auto_ptr(const any_device_auto_ptr< Dev > &)
ATA device access.
ata_device()
Default constructor, registers device as ATA.
@ supports_output_regs
@ supports_48bit_hi_null
@ supports_multi_sector
@ supports_smart_status
virtual bool ata_identify_is_cached() const
Return true if OS caches ATA identify sector.
bool ata_cmd_is_supported(const ata_cmd_in &in, unsigned flags, const char *type=0)
Check command input parameters.
void hide_ata(bool hide=true)
Hide/unhide ATA interface.
virtual bool ata_pass_through(const ata_cmd_in &in, ata_cmd_out &out)=0
ATA pass through.
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).
16-bit alias to a 8-bit ATA register pair.
ata_reg_alias_16(const ata_reg_alias_16 &)
ata_register & m_hi
ata_register & m_lo
unsigned short val() const
ata_reg_alias_16(ata_register &lo, ata_register &hi)
ata_reg_alias_16 & operator=(unsigned short x)
void operator=(const ata_reg_alias_16 &)
48-bit alias to six 8-bit ATA registers (for LBA).
ata_register & m_hh
ata_register & m_ll
ata_register & m_lm
uint64_t val() const
ata_reg_alias_48 & operator=(uint64_t x)
void operator=(const ata_reg_alias_48 &)
ata_reg_alias_48(ata_register &ll, ata_register &lm, ata_register &lh, ata_register &hl, ata_register &hm, ata_register &hh)
ata_reg_alias_48(const ata_reg_alias_48 &)
ata_register & m_hl
ata_register & m_lh
ata_register & m_hm
ATA register value and info whether it has ever been set.
unsigned char val() const
bool is_set() const
ata_register & operator=(unsigned char x)
bool m_is_set
true if set
unsigned char m_val
Register value.
NVMe device access.
unsigned get_nsid() const
Get namespace id.
unsigned m_nsid
nvme_device(unsigned nsid)
Constructor requires namespace ID, registers device as NVMe.
virtual bool nvme_pass_through(const nvme_cmd_in &in, nvme_cmd_out &out)=0
NVMe pass through.
bool set_nvme_err(nvme_cmd_out &out, unsigned status, const char *msg=0)
Set last error number and message if pass-through returns NVMe error status.
void hide_nvme(bool hide=true)
Hide/unhide NVMe interface.
void set_nsid(unsigned nsid)
Set namespace id.
SCSI device access.
scsi_cmd_support logsense_spc_sup
scsi_device()
Default constructor, registers device as SCSI.
bool spc4_or_above
bool is_spc4_or_higher() const
bool checked_cmd_support() const
scsi_cmd_support rdefect12_sup
void hide_scsi(bool hide=true)
Hide/unhide SCSI interface.
void set_rcap16_first()
Always try READ CAPACITY(10) (rcap10) first but once we know rcap16 is needed, use it instead.
bool query_cmd_support()
Definition: scsicmds.cpp:80
bool scsi_pass_through_and_check(scsi_cmnd_io *iop, const char *msg="")
scsi_cmd_support logsense_sup
scsi_cmd_support rsoc_sup
virtual bool scsi_pass_through(scsi_cmnd_io *iop)=0
SCSI pass through.
scsi_cmd_support rdefect10_sup
bool use_rcap16() const
scsi_cmd_support rcap16_sup
enum scsi_cmd_support cmd_support_level(uint8_t opcode, bool sa_valid, uint16_t sa, bool for_lsense_spc=false) const
Definition: scsicmds.cpp:172
void set_spc4_or_higher()
List of devices for DEVICESCAN.
const smart_device * at(unsigned i) const
unsigned size() const
smart_device * at(unsigned i)
void operator=(const smart_device_list &)
void push_back(smart_device *dev)
std::vector< smart_device * > m_list
void push_back(smart_device_auto_ptr &dev)
void append(smart_device_list &devlist)
smart_device_list(const smart_device_list &)
smart_device * release(unsigned i)
Base class for all devices.
Definition: dev_interface.h:33
bool is_scsi() const
Return true if SCSI device.
Definition: dev_interface.h:89
int get_errno() const
Get last error number.
const error_info & get_err() const
Get last error info struct.
error_info m_err
virtual void release(const smart_device *dev)
Release ownership of other device.
smart_device(const smart_device &)
scsi_device * m_scsi_ptr
virtual bool is_powered_down()
Early test if device is powered up or down.
bool is_nvme() const
Return true if NVMe device.
Definition: dev_interface.h:92
const device_info & get_info() const
Get device info struct.
const smart_interface * smi() const
Get interface which produced this object (const).
nvme_device * m_nvme_ptr
smart_interface * smi()
Get interface which produced this object.
const char * get_req_type() const
Get type requested by user, empty if none.
const ata_device * to_ata() const
Downcast to ATA device (const).
Definition: dev_interface.h:99
const scsi_device * to_scsi() const
Downcast to SCSI device (const).
void operator=(const smart_device &)
const nvme_device * to_nvme() const
Downcast to NVMe device (const).
const char * get_dev_type() const
Get device type.
const char * get_errmsg() const
Get last error message.
virtual bool close()=0
Close device, return false on error.
nvme_device * to_nvme()
Downcast to NVMe device.
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
device_info m_info
ata_device * to_ata()
Downcast to ATA device.
Definition: dev_interface.h:96
do_not_use_in_implementation_classes
Dummy enum for dummy constructor.
Definition: dev_interface.h:72
const char * get_info_name() const
Get informal name.
virtual smart_device * autodetect_open()
Open device with autodetection support.
scsi_device * to_scsi()
Downcast to SCSI device.
static int get_num_objects()
Get current number of allocated 'smart_device' objects.
virtual bool owns(const smart_device *dev) const
Return true if other device is owned by this device.
virtual bool is_syscall_unsup() const
Return true if last error indicates an unsupported system call.
virtual bool is_open() const =0
Return true if device is open.
bool is_ata() const
Return true if ATA device.
Definition: dev_interface.h:86
static int s_num_objects
ata_device * m_ata_ptr
device_info & set_info()
R/W access to device info struct.
const char * get_dev_name() const
Get device (path)name.
virtual bool open()=0
Open device, return false on error.
virtual ~smart_device()
void clear_err()
Clear last error info.
smart_interface * m_intf
The platform interface abstraction.
virtual std::string get_app_examples(const char *appname)
Return example string for program 'appname'.
smart_interface(const smart_interface &)
static void set(smart_interface *intf)
Set interface to use, must be called from init().
virtual const char * get_msg_for_errno(int no)
Convert error number into message, used by set_err(no).
void clear_err()
Clear last error info.
virtual nvme_device * get_snt_device(const char *type, scsi_device *scsidev)
Return NVMe->SCSI filter for a SNT or USB 'type'.
Definition: scsinvme.cpp:398
virtual const char * get_usb_dev_type_by_id(int vendor_id, int product_id, int version=-1)
Get type name for USB device with known VENDOR:PRODUCT ID.
Definition: scsiata.cpp:1518
static smart_interface * s_instance
Pointer to the interface object.
virtual ata_device * get_jmb39x_device(const char *type, smart_device *smartdev)
Return JMB93x->ATA filter.
virtual ata_device * get_sat_device(const char *type, scsi_device *scsidev)
Return ATA->SCSI filter for a SAT or USB 'type'.
Definition: scsiata.cpp:1405
virtual std::string get_unique_dev_name(const char *name, const char *type) const
Return unique device name which is (only) suitable for duplicate detection.
virtual smart_device * get_smart_device(const char *name, const char *type)
Return device object for device 'name' with some 'type'.
smart_device::error_info m_err
virtual ata_device * get_ata_device(const char *name, const char *type)=0
Return standard ATA device.
const char * get_errmsg() const
Get last error message.
virtual ata_device * get_intelliprop_device(const char *type, ata_device *atadev)
Return filter for Intelliprop controllers.
static void init()
Initialize platform interface and register with smi().
Definition: dev_legacy.cpp:334
bool decltype(nullptr) set_err_np(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
int get_errno() const
Get last error number.
virtual smart_device * get_custom_smart_device(const char *name, const char *type)
Return device for platform specific 'type'.
virtual std::string get_os_version_str()
Return info string about build host and/or OS version.
virtual std::string get_valid_custom_dev_types_str()
Return valid 'type' args accepted by above.
const smart_device::error_info & get_err() const
Get last error info struct.
void operator=(const smart_interface &)
virtual bool disable_system_auto_standby(bool disable)
Disable/Enable system auto standby/sleep mode.
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'.
virtual smart_device * autodetect_smart_device(const char *name)=0
Autodetect device if no device type specified.
virtual std::string get_valid_dev_types_str()
Return valid args for device type option/directive.
virtual scsi_device * get_scsi_device(const char *name, const char *type)=0
Return standard SCSI device.
friend smart_interface * smi()
Global access to the (usually singleton) smart_interface.
virtual smart_device * get_scsi_passthrough_device(const char *type, scsi_device *scsidev)
Return ATA->SCSI of NVMe->SCSI filter for a SAT, SNT or USB 'type'.
virtual nvme_device * get_nvme_device(const char *name, const char *type, unsigned nsid)
Return standard NVMe device.
virtual ~smart_interface()
virtual ata_device * autodetect_sat_device(scsi_device *scsidev, const unsigned char *inqdata, unsigned inqsize)
Try to detect a SAT device behind a SCSI interface.
Definition: scsiata.cpp:1486
bool set_err_var(smart_device::error_info *err, int no)
Set last error number and default message to any error_info.
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
virtual bool is_raid_dev_type(const char *type) const
Return true if the 'type' string contains a RAID drive number.
any_device_auto_ptr< scsi_device > scsi_device_auto_ptr
std::vector< std::string > smart_devtype_list
List of types for DEVICESCAN.
any_device_auto_ptr< smart_device > smart_device_auto_ptr
any_device_auto_ptr< nvme_device > nvme_device_auto_ptr
scsi_cmd_support
@ SC_SUPPORT
@ SC_SUPPORT_UNKNOWN
@ SC_NO_SUPPORT
smart_interface * smi()
Global access to the (usually singleton) smart_interface.
any_device_auto_ptr< ata_device > ata_device_auto_ptr
u16 flags
Definition: megaraid.h:14
uint8_t opcode
Definition: megaraid.h:0
uint32_t nsid
ATA pass through input parameters.
enum ata_cmd_in::@29 direction
I/O direction.
void set_data_out(const void *buf, unsigned nsectors)
Prepare for 28-bit DATA OUT command.
void * buffer
Pointer to data buffer.
void set_data_in_48bit(void *buf, unsigned nsectors)
Prepare for 48-bit DATA IN command.
ata_in_regs_48bit in_regs
Input registers.
unsigned size
Size of buffer.
ata_out_regs_flags out_needed
True if output register value needed.
void set_data_in(void *buf, unsigned nsectors)
Prepare for 28-bit DATA IN command.
ATA pass through output parameters.
ata_out_regs_48bit out_regs
Output registers.
ATA Input registers for 48-bit commands.
bool is_48bit_cmd() const
Return true if 48-bit command.
ata_reg_alias_16 lba_high_16
ata_reg_alias_16 sector_count_16
bool is_real_48bit_cmd() const
Return true if 48-bit command with any nonzero high byte.
ata_reg_alias_16 features_16
ata_in_regs prev
"previous content"
ata_reg_alias_16 lba_low_16
ata_reg_alias_48 lba_48
ata_reg_alias_16 lba_mid_16
ATA Input registers (for 28-bit commands)
bool is_set() const
Return true if any register is set.
ata_register device
ata_register lba_high
ata_register sector_count
ata_register lba_low
ata_register features
ata_register command
ata_register lba_mid
ATA Output registers for 48-bit commands.
ata_reg_alias_48 lba_48
ata_out_regs prev
read with HOB=1
ata_reg_alias_16 lba_mid_16
ata_reg_alias_16 sector_count_16
ata_reg_alias_16 lba_low_16
ata_reg_alias_16 lba_high_16
Flags for each ATA output register.
ata_out_regs_flags()
Default constructor clears all flags.
bool is_set() const
Return true if any flag is set.
ATA Output registers (for 28-bit commands)
ata_register sector_count
ata_register lba_low
ata_register lba_mid
ata_register error
ata_register lba_high
bool is_set() const
Return true if any register is set.
ata_register device
ata_register status
NVMe pass through input parameters.
unsigned char direction() const
Get I/O direction from opcode.
unsigned cdw10
unsigned cdw13
unsigned cdw11
unsigned char opcode
Opcode (CDW0 07:00)
unsigned size
Size of buffer.
unsigned cdw14
unsigned cdw15
Cmd specific.
unsigned nsid
Namespace ID.
unsigned cdw12
void set_data_in(unsigned char op, void *buf, unsigned sz)
void * buffer
Pointer to data buffer.
NVMe pass through output parameters.
bool status_valid
true if status is valid
unsigned short status
Status Field (DW3 31:17)
unsigned result
Command specific result (DW0)
Device info strings.
Definition: dev_interface.h:37
std::string req_type
Device type requested by user, empty if none.
Definition: dev_interface.h:48
std::string info_name
Informal name.
Definition: dev_interface.h:46
device_info(const char *d_name, const char *d_type, const char *r_type)
Definition: dev_interface.h:40
std::string dev_type
Actual device type.
Definition: dev_interface.h:47
std::string dev_name
Device (path)name.
Definition: dev_interface.h:45
Error (number,message) pair.
Definition: dev_interface.h:52
std::string msg
Error message.
Definition: dev_interface.h:61
error_info(int n, const char *m)
Definition: dev_interface.h:55
int no
Error number.
Definition: dev_interface.h:60
#define __attribute_format_printf(x, y)
Definition: utility.h:34