|
smartmontools SVN Rev 3317
Utility to control and monitor storage systems with "S.M.A.R.T."
|
00001 /* 00002 * dev_interface.cpp 00003 * 00004 * Home page of code is: http://smartmontools.sourceforge.net 00005 * 00006 * Copyright (C) 2008-13 Christian Franke <smartmontools-support@lists.sourceforge.net> 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2, or (at your option) 00011 * any later version. 00012 * 00013 * You should have received a copy of the GNU General Public License 00014 * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. 00015 * 00016 */ 00017 00018 #include "config.h" 00019 #include "int64.h" 00020 #include "dev_interface.h" 00021 #include "dev_tunnelled.h" 00022 #include "atacmds.h" // ATA_SMART_CMD/STATUS 00023 #include "utility.h" 00024 00025 #include <errno.h> 00026 #include <stdarg.h> 00027 #include <stdexcept> 00028 00029 #if defined(HAVE_GETTIMEOFDAY) 00030 #include <sys/time.h> 00031 #elif defined(HAVE_FTIME) 00032 #include <sys/timeb.h> 00033 #endif 00034 00035 const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp 3741 2013-01-02 17:06:54Z chrfranke $" 00036 DEV_INTERFACE_H_CVSID; 00037 00038 ///////////////////////////////////////////////////////////////////////////// 00039 // smart_device 00040 00041 smart_device::smart_device(smart_interface * intf, const char * dev_name, 00042 const char * dev_type, const char * req_type) 00043 : m_intf(intf), m_info(dev_name, dev_type, req_type), 00044 m_ata_ptr(0), m_scsi_ptr(0) 00045 { 00046 } 00047 00048 smart_device::smart_device(do_not_use_in_implementation_classes) 00049 : m_intf(0), m_ata_ptr(0), m_scsi_ptr(0) 00050 { 00051 throw std::logic_error("smart_device: wrong constructor called in implementation class"); 00052 } 00053 00054 smart_device::~smart_device() throw() 00055 { 00056 } 00057 00058 bool smart_device::is_syscall_unsup() const 00059 { 00060 if (get_errno() == ENOSYS) 00061 return true; 00062 #ifdef ENOTSUP 00063 if (get_errno() == ENOTSUP) 00064 return true; 00065 #endif 00066 return false; 00067 } 00068 00069 bool smart_device::set_err(int no, const char * msg, ...) 00070 { 00071 if (!msg) 00072 return set_err(no); 00073 m_err.no = no; 00074 va_list ap; va_start(ap, msg); 00075 m_err.msg = vstrprintf(msg, ap); 00076 va_end(ap); 00077 return false; 00078 } 00079 00080 bool smart_device::set_err(int no) 00081 { 00082 return smi()->set_err_var(&m_err, no); 00083 } 00084 00085 smart_device * smart_device::autodetect_open() 00086 { 00087 open(); 00088 return this; 00089 } 00090 00091 bool smart_device::owns(const smart_device * /*dev*/) const 00092 { 00093 return false; 00094 } 00095 00096 void smart_device::release(const smart_device * /*dev*/) 00097 { 00098 } 00099 00100 00101 ///////////////////////////////////////////////////////////////////////////// 00102 // ata_device 00103 00104 ata_in_regs_48bit::ata_in_regs_48bit() 00105 : features_16(features, prev.features), 00106 sector_count_16(sector_count, prev.sector_count), 00107 lba_low_16(lba_low, prev.lba_low), 00108 lba_mid_16(lba_mid, prev.lba_mid), 00109 lba_high_16(lba_high, prev.lba_high), 00110 lba_48( lba_low, lba_mid, lba_high, 00111 prev.lba_low, prev.lba_mid, prev.lba_high) 00112 { 00113 } 00114 00115 ata_out_regs_48bit::ata_out_regs_48bit() 00116 : sector_count_16(sector_count, prev.sector_count), 00117 lba_low_16(lba_low, prev.lba_low), 00118 lba_mid_16(lba_mid, prev.lba_mid), 00119 lba_high_16(lba_high, prev.lba_high), 00120 lba_48( lba_low, lba_mid, lba_high, 00121 prev.lba_low, prev.lba_mid, prev.lba_high) 00122 { 00123 } 00124 00125 ata_cmd_in::ata_cmd_in() 00126 : direction(no_data), 00127 buffer(0), 00128 size(0) 00129 { 00130 } 00131 00132 ata_cmd_out::ata_cmd_out() 00133 { 00134 } 00135 00136 bool ata_device::ata_pass_through(const ata_cmd_in & in) 00137 { 00138 ata_cmd_out dummy; 00139 return ata_pass_through(in, dummy); 00140 } 00141 00142 bool ata_device::ata_cmd_is_supported(const ata_cmd_in & in, 00143 unsigned flags, const char * type /* = 0 */) 00144 { 00145 // Check DATA IN/OUT 00146 switch (in.direction) { 00147 case ata_cmd_in::no_data: break; 00148 case ata_cmd_in::data_in: break; 00149 case ata_cmd_in::data_out: break; 00150 default: 00151 return set_err(EINVAL, "Invalid data direction %d", (int)in.direction); 00152 } 00153 00154 // Check buffer size 00155 if (in.direction == ata_cmd_in::no_data) { 00156 if (in.size) 00157 return set_err(EINVAL, "Buffer size %u > 0 for NO DATA command", in.size); 00158 } 00159 else { 00160 if (!in.buffer) 00161 return set_err(EINVAL, "Buffer not set for DATA IN/OUT command"); 00162 unsigned count = (in.in_regs.prev.sector_count<<16)|in.in_regs.sector_count; 00163 // TODO: Add check for sector count == 0 00164 if (count * 512 != in.size) 00165 return set_err(EINVAL, "Sector count %u does not match buffer size %u", count, in.size); 00166 } 00167 00168 // Check features 00169 const char * errmsg = 0; 00170 if (in.direction == ata_cmd_in::data_out && !(flags & supports_data_out)) 00171 errmsg = "DATA OUT ATA commands not implemented"; 00172 else if ( in.out_needed.is_set() && !(flags & supports_output_regs) 00173 && !( in.in_regs.command == ATA_SMART_CMD 00174 && in.in_regs.features == ATA_SMART_STATUS 00175 && (flags & supports_smart_status))) 00176 errmsg = "Read of ATA output registers not implemented"; 00177 else if (!(in.size == 0 || in.size == 512) && !(flags & supports_multi_sector)) 00178 errmsg = "Multi-sector ATA commands not implemented"; 00179 else if (in.in_regs.is_48bit_cmd() && !(flags & (supports_48bit_hi_null|supports_48bit))) 00180 errmsg = "48-bit ATA commands not implemented"; 00181 else if (in.in_regs.is_real_48bit_cmd() && !(flags & supports_48bit)) 00182 errmsg = "48-bit ATA commands not fully implemented"; 00183 00184 if (errmsg) 00185 return set_err(ENOSYS, "%s%s%s%s", errmsg, 00186 (type ? " [" : ""), (type ? type : ""), (type ? "]" : "")); 00187 00188 return true; 00189 } 00190 00191 bool ata_device::ata_identify_is_cached() const 00192 { 00193 return false; 00194 } 00195 00196 00197 ///////////////////////////////////////////////////////////////////////////// 00198 // tunnelled_device_base 00199 00200 tunnelled_device_base::tunnelled_device_base(smart_device * tunnel_dev) 00201 : smart_device(never_called), 00202 m_tunnel_base_dev(tunnel_dev) 00203 { 00204 } 00205 00206 tunnelled_device_base::~tunnelled_device_base() throw() 00207 { 00208 delete m_tunnel_base_dev; 00209 } 00210 00211 bool tunnelled_device_base::is_open() const 00212 { 00213 return (m_tunnel_base_dev && m_tunnel_base_dev->is_open()); 00214 } 00215 00216 bool tunnelled_device_base::open() 00217 { 00218 if (!m_tunnel_base_dev) 00219 return set_err(ENOSYS); 00220 if (!m_tunnel_base_dev->open()) 00221 return set_err(m_tunnel_base_dev->get_err()); 00222 return true; 00223 } 00224 00225 bool tunnelled_device_base::close() 00226 { 00227 if (!m_tunnel_base_dev) 00228 return true; 00229 if (!m_tunnel_base_dev->close()) 00230 return set_err(m_tunnel_base_dev->get_err()); 00231 return true; 00232 } 00233 00234 bool tunnelled_device_base::owns(const smart_device * dev) const 00235 { 00236 return (m_tunnel_base_dev && (m_tunnel_base_dev == dev)); 00237 } 00238 00239 void tunnelled_device_base::release(const smart_device * dev) 00240 { 00241 if (m_tunnel_base_dev == dev) 00242 m_tunnel_base_dev = 0; 00243 } 00244 00245 00246 ///////////////////////////////////////////////////////////////////////////// 00247 // smart_interface 00248 00249 // Pointer to (usually singleton) interface object returned by ::smi() 00250 smart_interface * smart_interface::s_instance; 00251 00252 std::string smart_interface::get_os_version_str() 00253 { 00254 return SMARTMONTOOLS_BUILD_HOST; 00255 } 00256 00257 std::string smart_interface::get_valid_dev_types_str() 00258 { 00259 // default 00260 std::string s = 00261 "ata, scsi, sat[,auto][,N][+TYPE], usbcypress[,X], usbjmicron[,p][,x][,N], usbsunplus"; 00262 // append custom 00263 std::string s2 = get_valid_custom_dev_types_str(); 00264 if (!s2.empty()) { 00265 s += ", "; s += s2; 00266 } 00267 return s; 00268 } 00269 00270 std::string smart_interface::get_app_examples(const char * /*appname*/) 00271 { 00272 return ""; 00273 } 00274 00275 int64_t smart_interface::get_timer_usec() 00276 { 00277 #if defined(HAVE_GETTIMEOFDAY) 00278 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) 00279 { 00280 static bool have_clock_monotonic = true; 00281 if (have_clock_monotonic) { 00282 struct timespec ts; 00283 if (!clock_gettime(CLOCK_MONOTONIC, &ts)) 00284 return ts.tv_sec * 1000000LL + ts.tv_nsec/1000; 00285 have_clock_monotonic = false; 00286 } 00287 } 00288 #endif 00289 { 00290 struct timeval tv; 00291 gettimeofday(&tv, 0); 00292 return tv.tv_sec * 1000000LL + tv.tv_usec; 00293 } 00294 #elif defined(HAVE_FTIME) 00295 { 00296 struct timeb tb; 00297 ftime(&tb); 00298 return tb.time * 1000000LL + tb.millitm * 1000; 00299 } 00300 #else 00301 return -1; 00302 #endif 00303 } 00304 00305 bool smart_interface::disable_system_auto_standby(bool /*disable*/) 00306 { 00307 return set_err(ENOSYS); 00308 } 00309 00310 bool smart_interface::set_err(int no, const char * msg, ...) 00311 { 00312 if (!msg) 00313 return set_err(no); 00314 m_err.no = no; 00315 va_list ap; va_start(ap, msg); 00316 m_err.msg = vstrprintf(msg, ap); 00317 va_end(ap); 00318 return false; 00319 } 00320 00321 bool smart_interface::set_err(int no) 00322 { 00323 return set_err_var(&m_err, no); 00324 } 00325 00326 bool smart_interface::set_err_var(smart_device::error_info * err, int no) 00327 { 00328 err->no = no; 00329 err->msg = get_msg_for_errno(no); 00330 if (err->msg.empty() && no != 0) 00331 err->msg = strprintf("Unknown error %d", no); 00332 return false; 00333 } 00334 00335 const char * smart_interface::get_msg_for_errno(int no) 00336 { 00337 return strerror(no); 00338 } 00339 00340 00341 ///////////////////////////////////////////////////////////////////////////// 00342 // Default device factory 00343 00344 smart_device * smart_interface::get_smart_device(const char * name, const char * type) 00345 { 00346 clear_err(); 00347 00348 // Call platform specific autodetection if no device type specified 00349 smart_device * dev; 00350 if (!type || !*type) { 00351 dev = autodetect_smart_device(name); 00352 if (!dev && !get_errno()) 00353 set_err(EINVAL, "Unable to detect device type"); 00354 return dev; 00355 } 00356 00357 // First check for platform specific device types 00358 dev = get_custom_smart_device(name, type); 00359 if (dev || get_errno()) 00360 return dev; 00361 00362 if (!strcmp(type, "ata")) 00363 dev = get_ata_device(name, type); 00364 else if (!strcmp(type, "scsi")) 00365 dev = get_scsi_device(name, type); 00366 00367 else if ( ((!strncmp(type, "sat", 3) && (!type[3] || strchr(",+", type[3]))) 00368 || (!strncmp(type, "usb", 3)))) { 00369 // Split "sat...+base..." -> ("sat...", "base...") 00370 unsigned satlen = strcspn(type, "+"); 00371 std::string sattype(type, satlen); 00372 const char * basetype = (type[satlen] ? type+satlen+1 : ""); 00373 // Recurse to allocate base device, default is standard SCSI 00374 if (!*basetype) 00375 basetype = "scsi"; 00376 smart_device_auto_ptr basedev( get_smart_device(name, basetype) ); 00377 if (!basedev) { 00378 set_err(EINVAL, "Type '%s+...': %s", sattype.c_str(), get_errmsg()); 00379 return 0; 00380 } 00381 // Result must be SCSI 00382 if (!basedev->is_scsi()) { 00383 set_err(EINVAL, "Type '%s+...': Device type '%s' is not SCSI", sattype.c_str(), basetype); 00384 return 0; 00385 } 00386 // Attach SAT tunnel 00387 ata_device * satdev = get_sat_device(sattype.c_str(), basedev->to_scsi()); 00388 if (!satdev) 00389 return 0; 00390 basedev.release(); 00391 return satdev; 00392 } 00393 00394 else { 00395 set_err(EINVAL, "Unknown device type '%s'", type); 00396 return 0; 00397 } 00398 if (!dev && !get_errno()) 00399 set_err(EINVAL, "Not a device of type '%s'", type); 00400 return dev; 00401 } 00402 00403 smart_device * smart_interface::get_custom_smart_device(const char * /*name*/, const char * /*type*/) 00404 { 00405 return 0; 00406 } 00407 00408 std::string smart_interface::get_valid_custom_dev_types_str() 00409 { 00410 return ""; 00411 }
1.7.4