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