File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / smartmontools / dev_interface.cpp
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 16:32:16 2012 UTC (12 years, 4 months ago) by misho
Branches: smartmontools, elwix, MAIN
CVS tags: v5_42, HEAD
smartmontools

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

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