File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / smartmontools / dev_interface.cpp
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, 10 months ago) by misho
Branches: smartmontools, elwix, MAIN
CVS tags: v6_2, v6_1p0, v6_1, HEAD
6.1

    1: /*
    2:  * dev_interface.cpp
    3:  *
    4:  * Home page of code is: http://smartmontools.sourceforge.net
    5:  *
    6:  * Copyright (C) 2008-13 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: #include "config.h"
   19: #include "int64.h"
   20: #include "dev_interface.h"
   21: #include "dev_tunnelled.h"
   22: #include "atacmds.h" // ATA_SMART_CMD/STATUS
   23: #include "utility.h"
   24: 
   25: #include <errno.h>
   26: #include <stdarg.h>
   27: #include <stdexcept>
   28: 
   29: #if defined(HAVE_GETTIMEOFDAY)
   30: #include <sys/time.h>
   31: #elif defined(HAVE_FTIME)
   32: #include <sys/timeb.h>
   33: #endif
   34: 
   35: const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp,v 1.1.1.3 2013/07/22 01:17:35 misho Exp $"
   36:   DEV_INTERFACE_H_CVSID;
   37: 
   38: /////////////////////////////////////////////////////////////////////////////
   39: // smart_device
   40: 
   41: smart_device::smart_device(smart_interface * intf, const char * dev_name,
   42:     const char * dev_type, const char * req_type)
   43: : m_intf(intf), m_info(dev_name, dev_type, req_type),
   44:   m_ata_ptr(0), m_scsi_ptr(0)
   45: {
   46: }
   47: 
   48: smart_device::smart_device(do_not_use_in_implementation_classes)
   49: : m_intf(0), m_ata_ptr(0), m_scsi_ptr(0)
   50: {
   51:   throw std::logic_error("smart_device: wrong constructor called in implementation class");
   52: }
   53: 
   54: smart_device::~smart_device() throw()
   55: {
   56: }
   57: 
   58: bool smart_device::is_syscall_unsup() const
   59: {
   60:   if (get_errno() == ENOSYS)
   61:     return true;
   62: #ifdef ENOTSUP
   63:   if (get_errno() == ENOTSUP)
   64:     return true;
   65: #endif
   66:   return false;
   67: }
   68: 
   69: bool smart_device::set_err(int no, const char * msg, ...)
   70: {
   71:   if (!msg)
   72:     return set_err(no);
   73:   m_err.no = no;
   74:   va_list ap; va_start(ap, msg);
   75:   m_err.msg = vstrprintf(msg, ap);
   76:   va_end(ap);
   77:   return false;
   78: }
   79: 
   80: bool smart_device::set_err(int no)
   81: {
   82:   return smi()->set_err_var(&m_err, no);
   83: }
   84: 
   85: smart_device * smart_device::autodetect_open()
   86: {
   87:   open();
   88:   return this;
   89: }
   90: 
   91: bool smart_device::owns(const smart_device * /*dev*/) const
   92: {
   93:   return false;
   94: }
   95: 
   96: void smart_device::release(const smart_device * /*dev*/)
   97: {
   98: }
   99: 
  100: 
  101: /////////////////////////////////////////////////////////////////////////////
  102: // ata_device
  103: 
  104: ata_in_regs_48bit::ata_in_regs_48bit()
  105: : features_16(features, prev.features),
  106:   sector_count_16(sector_count, prev.sector_count),
  107:   lba_low_16(lba_low, prev.lba_low),
  108:   lba_mid_16(lba_mid, prev.lba_mid),
  109:   lba_high_16(lba_high, prev.lba_high),
  110:   lba_48(     lba_low,      lba_mid,      lba_high,
  111:          prev.lba_low, prev.lba_mid, prev.lba_high)
  112: {
  113: }
  114: 
  115: ata_out_regs_48bit::ata_out_regs_48bit()
  116: : sector_count_16(sector_count, prev.sector_count),
  117:   lba_low_16(lba_low, prev.lba_low),
  118:   lba_mid_16(lba_mid, prev.lba_mid),
  119:   lba_high_16(lba_high, prev.lba_high),
  120:   lba_48(     lba_low,      lba_mid,      lba_high,
  121:          prev.lba_low, prev.lba_mid, prev.lba_high)
  122: {
  123: }
  124: 
  125: ata_cmd_in::ata_cmd_in()
  126: : direction(no_data),
  127:   buffer(0),
  128:   size(0)
  129: {
  130: }
  131: 
  132: ata_cmd_out::ata_cmd_out()
  133: {
  134: }
  135: 
  136: bool ata_device::ata_pass_through(const ata_cmd_in & in)
  137: {
  138:   ata_cmd_out dummy;
  139:   return ata_pass_through(in, dummy);
  140: }
  141: 
  142: bool ata_device::ata_cmd_is_supported(const ata_cmd_in & in,
  143:   unsigned flags, const char * type /* = 0 */)
  144: {
  145:   // Check DATA IN/OUT
  146:   switch (in.direction) {
  147:     case ata_cmd_in::no_data:  break;
  148:     case ata_cmd_in::data_in:  break;
  149:     case ata_cmd_in::data_out: break;
  150:     default:
  151:       return set_err(EINVAL, "Invalid data direction %d", (int)in.direction);
  152:   }
  153: 
  154:   // Check buffer size
  155:   if (in.direction == ata_cmd_in::no_data) {
  156:     if (in.size)
  157:       return set_err(EINVAL, "Buffer size %u > 0 for NO DATA command", in.size);
  158:   }
  159:   else {
  160:     if (!in.buffer)
  161:       return set_err(EINVAL, "Buffer not set for DATA IN/OUT command");
  162:     unsigned count = (in.in_regs.prev.sector_count<<16)|in.in_regs.sector_count;
  163:     // TODO: Add check for sector count == 0
  164:     if (count * 512 != in.size)
  165:       return set_err(EINVAL, "Sector count %u does not match buffer size %u", count, in.size);
  166:   }
  167: 
  168:   // Check features
  169:   const char * errmsg = 0;
  170:   if (in.direction == ata_cmd_in::data_out && !(flags & supports_data_out))
  171:     errmsg = "DATA OUT ATA commands not implemented";
  172:   else if (   in.out_needed.is_set() && !(flags & supports_output_regs)
  173:            && !(   in.in_regs.command == ATA_SMART_CMD
  174:                 && in.in_regs.features == ATA_SMART_STATUS
  175:                 && (flags & supports_smart_status)))
  176:     errmsg = "Read of ATA output registers not implemented";
  177:   else if (!(in.size == 0 || in.size == 512) && !(flags & supports_multi_sector))
  178:     errmsg = "Multi-sector ATA commands not implemented";
  179:   else if (in.in_regs.is_48bit_cmd() && !(flags & (supports_48bit_hi_null|supports_48bit)))
  180:     errmsg = "48-bit ATA commands not implemented";
  181:   else if (in.in_regs.is_real_48bit_cmd() && !(flags & supports_48bit))
  182:     errmsg = "48-bit ATA commands not fully implemented";
  183: 
  184:   if (errmsg)
  185:     return set_err(ENOSYS, "%s%s%s%s", errmsg,
  186:                    (type ? " [" : ""), (type ? type : ""), (type ? "]" : ""));
  187: 
  188:   return true;
  189: }
  190: 
  191: bool ata_device::ata_identify_is_cached() const
  192: {
  193:   return false;
  194: }
  195: 
  196: 
  197: /////////////////////////////////////////////////////////////////////////////
  198: // tunnelled_device_base
  199: 
  200: tunnelled_device_base::tunnelled_device_base(smart_device * tunnel_dev)
  201: : smart_device(never_called),
  202:   m_tunnel_base_dev(tunnel_dev)
  203: {
  204: }
  205: 
  206: tunnelled_device_base::~tunnelled_device_base() throw()
  207: {
  208:   delete m_tunnel_base_dev;
  209: }
  210: 
  211: bool tunnelled_device_base::is_open() const
  212: {
  213:   return (m_tunnel_base_dev && m_tunnel_base_dev->is_open());
  214: }
  215: 
  216: bool tunnelled_device_base::open()
  217: {
  218:   if (!m_tunnel_base_dev)
  219:     return set_err(ENOSYS);
  220:   if (!m_tunnel_base_dev->open())
  221:     return set_err(m_tunnel_base_dev->get_err());
  222:   return true;
  223: }
  224: 
  225: bool tunnelled_device_base::close()
  226: {
  227:   if (!m_tunnel_base_dev)
  228:     return true;
  229:   if (!m_tunnel_base_dev->close())
  230:     return set_err(m_tunnel_base_dev->get_err());
  231:   return true;
  232: }
  233: 
  234: bool tunnelled_device_base::owns(const smart_device * dev) const
  235: {
  236:   return (m_tunnel_base_dev && (m_tunnel_base_dev == dev));
  237: }
  238: 
  239: void tunnelled_device_base::release(const smart_device * dev)
  240: {
  241:   if (m_tunnel_base_dev == dev)
  242:     m_tunnel_base_dev = 0;
  243: }
  244: 
  245: 
  246: /////////////////////////////////////////////////////////////////////////////
  247: // smart_interface
  248: 
  249: // Pointer to (usually singleton) interface object returned by ::smi()
  250: smart_interface * smart_interface::s_instance;
  251: 
  252: std::string smart_interface::get_os_version_str()
  253: {
  254:   return SMARTMONTOOLS_BUILD_HOST;
  255: }
  256: 
  257: std::string smart_interface::get_valid_dev_types_str()
  258: {
  259:   // default
  260:   std::string s =
  261:     "ata, scsi, sat[,auto][,N][+TYPE], usbcypress[,X], usbjmicron[,p][,x][,N], usbsunplus";
  262:   // append custom
  263:   std::string s2 = get_valid_custom_dev_types_str();
  264:   if (!s2.empty()) {
  265:     s += ", "; s += s2;
  266:   }
  267:   return s;
  268: }
  269: 
  270: std::string smart_interface::get_app_examples(const char * /*appname*/)
  271: {
  272:   return "";
  273: }
  274: 
  275: int64_t smart_interface::get_timer_usec()
  276: {
  277: #if defined(HAVE_GETTIMEOFDAY)
  278:  #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
  279:   {
  280:     static bool have_clock_monotonic = true;
  281:     if (have_clock_monotonic) {
  282:       struct timespec ts;
  283:       if (!clock_gettime(CLOCK_MONOTONIC, &ts))
  284:         return ts.tv_sec * 1000000LL + ts.tv_nsec/1000;
  285:       have_clock_monotonic = false;
  286:     }
  287:   }
  288:  #endif
  289:   {
  290:     struct timeval tv;
  291:     gettimeofday(&tv, 0);
  292:     return tv.tv_sec * 1000000LL + tv.tv_usec;
  293:   }
  294: #elif defined(HAVE_FTIME)
  295:   {
  296:     struct timeb tb;
  297:     ftime(&tb);
  298:     return tb.time * 1000000LL + tb.millitm * 1000;
  299:   }
  300: #else
  301:   return -1;
  302: #endif
  303: }
  304: 
  305: bool smart_interface::disable_system_auto_standby(bool /*disable*/)
  306: {
  307:   return set_err(ENOSYS);
  308: }
  309: 
  310: bool smart_interface::set_err(int no, const char * msg, ...)
  311: {
  312:   if (!msg)
  313:     return set_err(no);
  314:   m_err.no = no;
  315:   va_list ap; va_start(ap, msg);
  316:   m_err.msg = vstrprintf(msg, ap);
  317:   va_end(ap);
  318:   return false;
  319: }
  320: 
  321: bool smart_interface::set_err(int no)
  322: {
  323:   return set_err_var(&m_err, no);
  324: }
  325: 
  326: bool smart_interface::set_err_var(smart_device::error_info * err, int no)
  327: {
  328:   err->no = no;
  329:   err->msg = get_msg_for_errno(no);
  330:   if (err->msg.empty() && no != 0)
  331:     err->msg = strprintf("Unknown error %d", no);
  332:   return false;
  333: }
  334: 
  335: const char * smart_interface::get_msg_for_errno(int no)
  336: {
  337:   return strerror(no);
  338: }
  339: 
  340: 
  341: /////////////////////////////////////////////////////////////////////////////
  342: // Default device factory
  343: 
  344: smart_device * smart_interface::get_smart_device(const char * name, const char * type)
  345: {
  346:   clear_err();
  347: 
  348:   // Call platform specific autodetection if no device type specified
  349:   smart_device * dev;
  350:   if (!type || !*type) {
  351:     dev = autodetect_smart_device(name);
  352:     if (!dev && !get_errno())
  353:       set_err(EINVAL, "Unable to detect device type");
  354:     return dev;
  355:   }
  356: 
  357:   // First check for platform specific device types
  358:   dev = get_custom_smart_device(name, type);
  359:   if (dev || get_errno())
  360:     return dev;
  361: 
  362:   if (!strcmp(type, "ata"))
  363:     dev = get_ata_device(name, type);
  364:   else if (!strcmp(type, "scsi"))
  365:     dev = get_scsi_device(name, type);
  366: 
  367:   else if (  ((!strncmp(type, "sat", 3) && (!type[3] || strchr(",+", type[3])))
  368:            || (!strncmp(type, "usb", 3)))) {
  369:     // Split "sat...+base..." -> ("sat...", "base...")
  370:     unsigned satlen = strcspn(type, "+");
  371:     std::string sattype(type, satlen);
  372:     const char * basetype = (type[satlen] ? type+satlen+1 : "");
  373:     // Recurse to allocate base device, default is standard SCSI
  374:     if (!*basetype)
  375:       basetype = "scsi";
  376:     smart_device_auto_ptr basedev( get_smart_device(name, basetype) );
  377:     if (!basedev) {
  378:       set_err(EINVAL, "Type '%s+...': %s", sattype.c_str(), get_errmsg());
  379:       return 0;
  380:     }
  381:     // Result must be SCSI
  382:     if (!basedev->is_scsi()) {
  383:       set_err(EINVAL, "Type '%s+...': Device type '%s' is not SCSI", sattype.c_str(), basetype);
  384:       return 0;
  385:     }
  386:     // Attach SAT tunnel
  387:     ata_device * satdev = get_sat_device(sattype.c_str(), basedev->to_scsi());
  388:     if (!satdev)
  389:       return 0;
  390:     basedev.release();
  391:     return satdev;
  392:   }
  393: 
  394:   else {
  395:     set_err(EINVAL, "Unknown device type '%s'", type);
  396:     return 0;
  397:   }
  398:   if (!dev && !get_errno())
  399:     set_err(EINVAL, "Not a device of type '%s'", type);
  400:   return dev;
  401: }
  402: 
  403: smart_device * smart_interface::get_custom_smart_device(const char * /*name*/, const char * /*type*/)
  404: {
  405:   return 0;
  406: }
  407: 
  408: std::string smart_interface::get_valid_custom_dev_types_str()
  409: {
  410:   return "";
  411: }

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