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>