Annotation of embedaddon/smartmontools/dev_interface.cpp, revision 1.1.1.1

1.1       misho       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 3256 2011-02-08 22:13:41Z chrfranke $"
                     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>