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>