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

1.1       misho       1: /*
                      2:  * dev_interface.cpp
                      3:  *
                      4:  * Home page of code is: http://smartmontools.sourceforge.net
                      5:  *
1.1.1.3 ! misho       6:  * Copyright (C) 2008-13 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"
1.1.1.3 ! misho      22: #include "atacmds.h" // ATA_SMART_CMD/STATUS
1.1       misho      23: #include "utility.h"
                     24: 
                     25: #include <errno.h>
                     26: #include <stdarg.h>
                     27: #include <stdexcept>
                     28: 
1.1.1.2   misho      29: #if defined(HAVE_GETTIMEOFDAY)
                     30: #include <sys/time.h>
                     31: #elif defined(HAVE_FTIME)
                     32: #include <sys/timeb.h>
                     33: #endif
                     34: 
1.1.1.3 ! misho      35: const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp 3741 2013-01-02 17:06:54Z chrfranke $"
1.1       misho      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: 
1.1.1.2   misho      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: 
1.1       misho      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: {
1.1.1.2   misho      82:   return smi()->set_err_var(&m_err, no);
1.1       misho      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: 
1.1.1.3 ! misho     142: bool ata_device::ata_cmd_is_supported(const ata_cmd_in & in,
        !           143:   unsigned flags, const char * type /* = 0 */)
1.1       misho     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
1.1.1.3 ! misho     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: 
1.1       misho     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 =
1.1.1.3 ! misho     261:     "ata, scsi, sat[,auto][,N][+TYPE], usbcypress[,X], usbjmicron[,p][,x][,N], usbsunplus";
1.1       misho     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: 
1.1.1.2   misho     275: int64_t smart_interface::get_timer_usec()
1.1       misho     276: {
1.1.1.2   misho     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;
1.1       misho     299:   }
1.1.1.2   misho     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);
1.1       misho     314:   m_err.no = no;
                    315:   va_list ap; va_start(ap, msg);
                    316:   m_err.msg = vstrprintf(msg, ap);
                    317:   va_end(ap);
1.1.1.2   misho     318:   return false;
1.1       misho     319: }
                    320: 
1.1.1.2   misho     321: bool smart_interface::set_err(int no)
1.1       misho     322: {
1.1.1.2   misho     323:   return set_err_var(&m_err, no);
1.1       misho     324: }
                    325: 
1.1.1.2   misho     326: bool smart_interface::set_err_var(smart_device::error_info * err, int no)
1.1       misho     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);
1.1.1.2   misho     332:   return false;
1.1       misho     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>