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

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