File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / smartmontools / dev_interface.h
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:36:45 2012 UTC (11 years, 8 months ago) by misho
Branches: smartmontools, elwix, MAIN
CVS tags: v5_43, HEAD
smartmontools

    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.2 2012/10/09 09:36:45 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:   /// Check command input parameters.
  510:   /// Calls set_err(...) accordingly.
  511:   bool ata_cmd_is_ok(const ata_cmd_in & in,
  512:     bool data_out_support = false,
  513:     bool multi_sector_support = false,
  514:     bool ata_48bit_support = false);
  515: 
  516:   /// Hide/unhide ATA interface.
  517:   void hide_ata(bool hide = true)
  518:     { m_ata_ptr = (!hide ? this : 0); }
  519: 
  520:   /// Default constructor, registers device as ATA.
  521:   ata_device()
  522:     : smart_device(never_called)
  523:     { hide_ata(false); }
  524: };
  525: 
  526: 
  527: /////////////////////////////////////////////////////////////////////////////
  528: // SCSI specific interface
  529: 
  530: struct scsi_cmnd_io;
  531: 
  532: /// SCSI device access
  533: class scsi_device
  534: : virtual public /*extends*/ smart_device
  535: {
  536: public:
  537:   /// SCSI pass through.
  538:   /// Returns false on error.
  539:   virtual bool scsi_pass_through(scsi_cmnd_io * iop) = 0;
  540: 
  541: protected:
  542:   /// Hide/unhide SCSI interface.
  543:   void hide_scsi(bool hide = true)
  544:     { m_scsi_ptr = (!hide ? this : 0); }
  545: 
  546:   /// Default constructor, registers device as SCSI.
  547:   scsi_device()
  548:     : smart_device(never_called)
  549:     { hide_scsi(false); }
  550: };
  551: 
  552: 
  553: /////////////////////////////////////////////////////////////////////////////
  554: /// Smart pointer class for device pointers
  555: 
  556: template <class Dev>
  557: class any_device_auto_ptr
  558: {
  559: public:
  560:   typedef Dev device_type;
  561: 
  562:   /// Construct from optional pointer to device
  563:   /// and optional pointer to base device.
  564:   explicit any_device_auto_ptr(device_type * dev = 0,
  565:                                smart_device * base_dev = 0)
  566:     : m_dev(dev), m_base_dev(base_dev) { }
  567: 
  568:   /// Destructor deletes device object.
  569:   ~any_device_auto_ptr() throw()
  570:     { reset(); }
  571: 
  572:   /// Assign a new pointer.
  573:   /// Throws if a pointer is already assigned.
  574:   void operator=(device_type * dev)
  575:     {
  576:       if (m_dev)
  577:         fail();
  578:       m_dev = dev;
  579:     }
  580: 
  581:   /// Delete device object and clear the pointer.
  582:   void reset()
  583:     {
  584:       if (m_dev) {
  585:         if (m_base_dev && m_dev->owns(m_base_dev))
  586:           m_dev->release(m_base_dev);
  587:         delete m_dev;
  588:         m_dev = 0;
  589:       }
  590:     }
  591: 
  592:   /// Return the pointer and release ownership.
  593:   device_type * release()
  594:     {
  595:       device_type * dev = m_dev;
  596:       m_dev = 0;
  597:       return dev;
  598:     }
  599: 
  600:   /// Replace the pointer.
  601:   /// Used to call dev->autodetect_open().
  602:   void replace(device_type * dev)
  603:     { m_dev = dev; }
  604: 
  605:   /// Return the pointer.
  606:   device_type * get() const
  607:     { return m_dev; }
  608: 
  609:   /// Pointer dereferencing.
  610:   device_type & operator*() const
  611:     { return *m_dev; }
  612: 
  613:   /// Pointer dereferencing.
  614:   device_type * operator->() const
  615:     { return m_dev; }
  616: 
  617:   /// For (ptr != 0) check.
  618:   operator bool() const
  619:     { return !!m_dev; }
  620: 
  621:   /// For (ptr == 0) check.
  622:   bool operator !() const
  623:     { return !m_dev; }
  624: 
  625: private:
  626:   device_type * m_dev;
  627:   smart_device * m_base_dev;
  628: 
  629:   void fail() const
  630:     { throw std::logic_error("any_device_auto_ptr: wrong usage"); }
  631: 
  632:   // Prevent copy/assignment
  633:   any_device_auto_ptr(const any_device_auto_ptr<Dev> &);
  634:   void operator=(const any_device_auto_ptr<Dev> &);
  635: };
  636: 
  637: typedef any_device_auto_ptr<smart_device> smart_device_auto_ptr;
  638: typedef any_device_auto_ptr<ata_device>   ata_device_auto_ptr;
  639: typedef any_device_auto_ptr<scsi_device>  scsi_device_auto_ptr;
  640: 
  641: 
  642: /////////////////////////////////////////////////////////////////////////////
  643: // smart_device_list
  644: 
  645: /// List of devices for DEVICESCAN
  646: class smart_device_list
  647: {
  648: // Construction
  649: public:
  650:   smart_device_list()
  651:     { }
  652: 
  653:   ~smart_device_list() throw()
  654:     {
  655:       for (unsigned i = 0; i < m_list.size(); i++)
  656:         delete m_list[i];
  657:     }
  658: 
  659: // Attributes
  660:   unsigned size() const
  661:     { return m_list.size(); }
  662: 
  663: // Operations
  664:   void clear()
  665:     {
  666:       for (unsigned i = 0; i < m_list.size(); i++)
  667:         delete m_list[i];
  668:       m_list.clear();
  669:     }
  670: 
  671: 
  672:   void push_back(smart_device * dev)
  673:     { m_list.push_back(dev); }
  674: 
  675:   void push_back(smart_device_auto_ptr & dev)
  676:     {
  677:       m_list.push_back(dev.get());
  678:       dev.release();
  679:     }
  680: 
  681:   smart_device * at(unsigned i)
  682:     { return m_list.at(i); }
  683: 
  684:   const smart_device * at(unsigned i) const
  685:     { return m_list.at(i); }
  686: 
  687:   smart_device * release(unsigned i)
  688:     {
  689:       smart_device * dev = m_list.at(i);
  690:       m_list[i] = 0;
  691:       return dev;
  692:     }
  693: 
  694: // Implementation
  695: private:
  696:   std::vector<smart_device *> m_list;
  697: 
  698:   // Prevent copy/assigment
  699:   smart_device_list(const smart_device_list &);
  700:   void operator=(const smart_device_list &);
  701: };
  702: 
  703: 
  704: /////////////////////////////////////////////////////////////////////////////
  705: // smart_interface
  706: 
  707: /// The platform interface abstraction
  708: class smart_interface
  709: {
  710: public:
  711:   /// Initialize platform interface and register with smi().
  712:   /// Must be implemented by platform module and register interface with set()
  713:   static void init();
  714: 
  715:   smart_interface()
  716:     { }
  717: 
  718:   virtual ~smart_interface() throw()
  719:     { }
  720: 
  721:   /// Return info string about build host and/or OS version.
  722:   /// Default implementation returns SMARTMONTOOLS_BUILD_HOST.
  723:   virtual std::string get_os_version_str();
  724: 
  725:   /// Return valid args for device type option/directive.
  726:   /// Default implementation returns "ata, scsi, sat, usb*..."
  727:   /// concatenated with result from get_valid_custom_dev_types_str().
  728:   virtual std::string get_valid_dev_types_str();
  729: 
  730:   /// Return example string for program 'appname'.
  731:   /// Default implementation returns empty string.
  732:   /// For the migration of print_smartctl_examples(),
  733:   /// function is allowed to print examples to stdout.
  734:   /// TODO: Remove this hack.
  735:   virtual std::string get_app_examples(const char * appname);
  736: 
  737:   /// Get microseconds since some unspecified starting point.
  738:   /// Used only for command duration measurements in debug outputs.
  739:   /// Returns -1 if unsupported.
  740:   /// Default implementation uses clock_gettime(), gettimeofday() or ftime().
  741:   virtual int64_t get_timer_usec();
  742: 
  743:   /// Disable/Enable system auto standby/sleep mode.
  744:   /// Return false if unsupported or if system is running
  745:   /// on battery.
  746:   /// Default implementation returns false.
  747:   virtual bool disable_system_auto_standby(bool disable);
  748: 
  749: 
  750:   ///////////////////////////////////////////////
  751:   // Last error information
  752: 
  753:   /// Get last error info struct.
  754:   const smart_device::error_info & get_err() const
  755:     { return m_err; }
  756:   /// Get last error number.
  757:   int get_errno() const
  758:     { return m_err.no; }
  759:   /// Get last error message.
  760:   const char * get_errmsg() const
  761:     { return m_err.msg.c_str(); }
  762: 
  763:   /// Set last error number and message.
  764:   /// Printf()-like formatting is supported.
  765:   /// Returns false always to allow use as a return expression.
  766:   bool set_err(int no, const char * msg, ...)
  767:     __attribute_format_printf(3, 4);
  768: 
  769:   /// Set last error info struct.
  770:   bool set_err(const smart_device::error_info & err)
  771:     { m_err = err; return false; }
  772: 
  773:   /// Clear last error info.
  774:   void clear_err()
  775:     { m_err.clear(); }
  776: 
  777:   /// Set last error number and default message.
  778:   /// Message is retrieved from get_msg_for_errno(no).
  779:   bool set_err(int no);
  780: 
  781:   /// Set last error number and default message to any error_info.
  782:   /// Used by set_err(no).
  783:   bool set_err_var(smart_device::error_info * err, int no);
  784: 
  785:   /// Convert error number into message, used by set_err(no).
  786:   /// Default implementation returns strerror(no).
  787:   virtual const char * get_msg_for_errno(int no);
  788: 
  789:   ///////////////////////////////////////////////////////////////////////////
  790:   // Device factory:
  791: 
  792:   /// Return device object for device 'name' with some 'type'.
  793:   /// 'type' is 0 if not specified by user.
  794:   /// Return 0 on error.
  795:   /// Default implementation selects between ata, scsi and custom device.
  796:   virtual smart_device * get_smart_device(const char * name, const char * type);
  797: 
  798:   /// Fill 'devlist' with devices of some 'type' with device names
  799:   /// specified by some optional 'pattern'.
  800:   /// Return false on error.
  801:   virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
  802:     const char * pattern = 0) = 0;
  803: 
  804: protected:
  805:   /// Return standard ATA device.
  806:   virtual ata_device * get_ata_device(const char * name, const char * type) = 0;
  807: 
  808:   /// Return standard SCSI device.
  809:   virtual scsi_device * get_scsi_device(const char * name, const char * type) = 0;
  810: 
  811:   /// Autodetect device if no device type specified.
  812:   virtual smart_device * autodetect_smart_device(const char * name) = 0;
  813: 
  814:   /// Return device for platform specific 'type'.
  815:   /// Default implementation returns 0.
  816:   virtual smart_device * get_custom_smart_device(const char * name, const char * type);
  817: 
  818:   /// Return valid 'type' args accepted by above.
  819:   /// This is called in get_valid_dev_types_str().
  820:   /// Default implementation returns empty string.
  821:   virtual std::string get_valid_custom_dev_types_str();
  822: 
  823:   /// Return ATA->SCSI filter for SAT or USB.
  824:   /// Override only if platform needs special handling.
  825:   virtual ata_device * get_sat_device(const char * type, scsi_device * scsidev);
  826:   //{ implemented in scsiata.cpp }
  827: 
  828: public:
  829:   /// Try to detect a SAT device behind a SCSI interface.
  830:   /// Inquiry data can be passed if available.
  831:   /// Return appropriate device if yes, otherwise 0.
  832:   /// Override only if platform needs special handling.
  833:   virtual ata_device * autodetect_sat_device(scsi_device * scsidev,
  834:     const unsigned char * inqdata, unsigned inqsize);
  835:   //{ implemented in scsiata.cpp }
  836: 
  837:   /// Get type name for USB device with known VENDOR:PRODUCT ID.
  838:   /// Return name if device known and supported, otherwise 0.
  839:   virtual const char * get_usb_dev_type_by_id(int vendor_id, int product_id,
  840:                                               int version = -1);
  841:   //{ implemented in scsiata.cpp }
  842: 
  843: protected:
  844:   /// Set interface to use, must be called from init().
  845:   static void set(smart_interface * intf)
  846:     { s_instance = intf; }
  847: 
  848: // Implementation
  849: private:
  850:   smart_device::error_info m_err;
  851: 
  852:   friend smart_interface * smi(); // below
  853:   static smart_interface * s_instance; ///< Pointer to the interface object.
  854: 
  855:   // Prevent copy/assigment
  856:   smart_interface(const smart_interface &);
  857:   void operator=(const smart_interface &);
  858: };
  859: 
  860: 
  861: /////////////////////////////////////////////////////////////////////////////
  862: // smi()
  863: 
  864: /// Global access to the (usually singleton) smart_interface
  865: inline smart_interface * smi()
  866:   { return smart_interface::s_instance; }
  867: 
  868: /////////////////////////////////////////////////////////////////////////////
  869: 
  870: #endif // DEV_INTERFACE_H

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