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

1.1       misho       1: /*
                      2:  * dev_interface.cpp
                      3:  *
                      4:  * Home page of code is: http://smartmontools.sourceforge.net
                      5:  *
1.1.1.2 ! misho       6:  * Copyright (C) 2008-12 Christian Franke <smartmontools-support@lists.sourceforge.net>
1.1       misho       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: 
1.1.1.2 ! misho      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 3554 2012-06-01 20:11:46Z chrfranke $"
1.1       misho      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: 
1.1.1.2 ! misho      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: 
1.1       misho      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: {
1.1.1.2 ! misho      81:   return smi()->set_err_var(&m_err, no);
1.1       misho      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 =
1.1.1.2 ! misho     249:     "ata, scsi, sat[,auto][,N][+TYPE], usbcypress[,X], usbjmicron[,x][,N], usbsunplus";
1.1       misho     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: 
1.1.1.2 ! misho     263: int64_t smart_interface::get_timer_usec()
1.1       misho     264: {
1.1.1.2 ! misho     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;
1.1       misho     287:   }
1.1.1.2 ! misho     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);
1.1       misho     302:   m_err.no = no;
                    303:   va_list ap; va_start(ap, msg);
                    304:   m_err.msg = vstrprintf(msg, ap);
                    305:   va_end(ap);
1.1.1.2 ! misho     306:   return false;
1.1       misho     307: }
                    308: 
1.1.1.2 ! misho     309: bool smart_interface::set_err(int no)
1.1       misho     310: {
1.1.1.2 ! misho     311:   return set_err_var(&m_err, no);
1.1       misho     312: }
                    313: 
1.1.1.2 ! misho     314: bool smart_interface::set_err_var(smart_device::error_info * err, int no)
1.1       misho     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);
1.1.1.2 ! misho     320:   return false;
1.1       misho     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>