File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / smartmontools / dev_interface.h
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 01:17:35 2013 UTC (10 years, 11 months ago) by misho
Branches: smartmontools, elwix, MAIN
CVS tags: v6_2, v6_1p0, v6_1, HEAD
6.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>