Annotation of embedaddon/smartmontools/dev_interface.cpp, revision 1.1.1.1
1.1 misho 1: /*
2: * dev_interface.cpp
3: *
4: * Home page of code is: http://smartmontools.sourceforge.net
5: *
6: * Copyright (C) 2008-11 Christian Franke <smartmontools-support@lists.sourceforge.net>
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:
28: const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp 3256 2011-02-08 22:13:41Z chrfranke $"
29: DEV_INTERFACE_H_CVSID;
30:
31: /////////////////////////////////////////////////////////////////////////////
32: // smart_device
33:
34: smart_device::smart_device(smart_interface * intf, const char * dev_name,
35: const char * dev_type, const char * req_type)
36: : m_intf(intf), m_info(dev_name, dev_type, req_type),
37: m_ata_ptr(0), m_scsi_ptr(0)
38: {
39: }
40:
41: smart_device::smart_device(do_not_use_in_implementation_classes)
42: : m_intf(0), m_ata_ptr(0), m_scsi_ptr(0)
43: {
44: throw std::logic_error("smart_device: wrong constructor called in implementation class");
45: }
46:
47: smart_device::~smart_device() throw()
48: {
49: }
50:
51: bool smart_device::set_err(int no, const char * msg, ...)
52: {
53: if (!msg)
54: return set_err(no);
55: m_err.no = no;
56: va_list ap; va_start(ap, msg);
57: m_err.msg = vstrprintf(msg, ap);
58: va_end(ap);
59: return false;
60: }
61:
62: bool smart_device::set_err(int no)
63: {
64: smi()->set_err_var(&m_err, no);
65: return false;
66: }
67:
68: smart_device * smart_device::autodetect_open()
69: {
70: open();
71: return this;
72: }
73:
74: bool smart_device::owns(const smart_device * /*dev*/) const
75: {
76: return false;
77: }
78:
79: void smart_device::release(const smart_device * /*dev*/)
80: {
81: }
82:
83:
84: /////////////////////////////////////////////////////////////////////////////
85: // ata_device
86:
87: ata_in_regs_48bit::ata_in_regs_48bit()
88: : features_16(features, prev.features),
89: sector_count_16(sector_count, prev.sector_count),
90: lba_low_16(lba_low, prev.lba_low),
91: lba_mid_16(lba_mid, prev.lba_mid),
92: lba_high_16(lba_high, prev.lba_high),
93: lba_48( lba_low, lba_mid, lba_high,
94: prev.lba_low, prev.lba_mid, prev.lba_high)
95: {
96: }
97:
98: ata_out_regs_48bit::ata_out_regs_48bit()
99: : sector_count_16(sector_count, prev.sector_count),
100: lba_low_16(lba_low, prev.lba_low),
101: lba_mid_16(lba_mid, prev.lba_mid),
102: lba_high_16(lba_high, prev.lba_high),
103: lba_48( lba_low, lba_mid, lba_high,
104: prev.lba_low, prev.lba_mid, prev.lba_high)
105: {
106: }
107:
108: ata_cmd_in::ata_cmd_in()
109: : direction(no_data),
110: buffer(0),
111: size(0)
112: {
113: }
114:
115: ata_cmd_out::ata_cmd_out()
116: {
117: }
118:
119: bool ata_device::ata_pass_through(const ata_cmd_in & in)
120: {
121: ata_cmd_out dummy;
122: return ata_pass_through(in, dummy);
123: }
124:
125: bool ata_device::ata_cmd_is_ok(const ata_cmd_in & in,
126: bool data_out_support /*= false*/,
127: bool multi_sector_support /*= false*/,
128: bool ata_48bit_support /*= false*/)
129: {
130: // Check DATA IN/OUT
131: switch (in.direction) {
132: case ata_cmd_in::no_data: break;
133: case ata_cmd_in::data_in: break;
134: case ata_cmd_in::data_out: break;
135: default:
136: return set_err(EINVAL, "Invalid data direction %d", (int)in.direction);
137: }
138:
139: // Check buffer size
140: if (in.direction == ata_cmd_in::no_data) {
141: if (in.size)
142: return set_err(EINVAL, "Buffer size %u > 0 for NO DATA command", in.size);
143: }
144: else {
145: if (!in.buffer)
146: return set_err(EINVAL, "Buffer not set for DATA IN/OUT command");
147: unsigned count = (in.in_regs.prev.sector_count<<16)|in.in_regs.sector_count;
148: // TODO: Add check for sector count == 0
149: if (count * 512 != in.size)
150: return set_err(EINVAL, "Sector count %u does not match buffer size %u", count, in.size);
151: }
152:
153: // Check features
154: if (in.direction == ata_cmd_in::data_out && !data_out_support)
155: return set_err(ENOSYS, "DATA OUT ATA commands not supported");
156: if (!(in.size == 0 || in.size == 512) && !multi_sector_support)
157: return set_err(ENOSYS, "Multi-sector ATA commands not supported");
158: if (in.in_regs.is_48bit_cmd() && !ata_48bit_support)
159: return set_err(ENOSYS, "48-bit ATA commands not supported");
160: return true;
161: }
162:
163: bool ata_device::ata_identify_is_cached() const
164: {
165: return false;
166: }
167:
168:
169: /////////////////////////////////////////////////////////////////////////////
170: // tunnelled_device_base
171:
172: tunnelled_device_base::tunnelled_device_base(smart_device * tunnel_dev)
173: : smart_device(never_called),
174: m_tunnel_base_dev(tunnel_dev)
175: {
176: }
177:
178: tunnelled_device_base::~tunnelled_device_base() throw()
179: {
180: delete m_tunnel_base_dev;
181: }
182:
183: bool tunnelled_device_base::is_open() const
184: {
185: return (m_tunnel_base_dev && m_tunnel_base_dev->is_open());
186: }
187:
188: bool tunnelled_device_base::open()
189: {
190: if (!m_tunnel_base_dev)
191: return set_err(ENOSYS);
192: if (!m_tunnel_base_dev->open())
193: return set_err(m_tunnel_base_dev->get_err());
194: return true;
195: }
196:
197: bool tunnelled_device_base::close()
198: {
199: if (!m_tunnel_base_dev)
200: return true;
201: if (!m_tunnel_base_dev->close())
202: return set_err(m_tunnel_base_dev->get_err());
203: return true;
204: }
205:
206: bool tunnelled_device_base::owns(const smart_device * dev) const
207: {
208: return (m_tunnel_base_dev && (m_tunnel_base_dev == dev));
209: }
210:
211: void tunnelled_device_base::release(const smart_device * dev)
212: {
213: if (m_tunnel_base_dev == dev)
214: m_tunnel_base_dev = 0;
215: }
216:
217:
218: /////////////////////////////////////////////////////////////////////////////
219: // smart_interface
220:
221: // Pointer to (usually singleton) interface object returned by ::smi()
222: smart_interface * smart_interface::s_instance;
223:
224: std::string smart_interface::get_os_version_str()
225: {
226: return SMARTMONTOOLS_BUILD_HOST;
227: }
228:
229: std::string smart_interface::get_valid_dev_types_str()
230: {
231: // default
232: std::string s =
233: "ata, scsi, sat[,N][+TYPE], usbcypress[,X], usbjmicron[,x][,N], usbsunplus";
234: // append custom
235: std::string s2 = get_valid_custom_dev_types_str();
236: if (!s2.empty()) {
237: s += ", "; s += s2;
238: }
239: return s;
240: }
241:
242: std::string smart_interface::get_app_examples(const char * /*appname*/)
243: {
244: return "";
245: }
246:
247: void smart_interface::set_err(int no, const char * msg, ...)
248: {
249: if (!msg) {
250: set_err(no); return;
251: }
252: m_err.no = no;
253: va_list ap; va_start(ap, msg);
254: m_err.msg = vstrprintf(msg, ap);
255: va_end(ap);
256: }
257:
258: void smart_interface::set_err(int no)
259: {
260: set_err_var(&m_err, no);
261: }
262:
263: void smart_interface::set_err_var(smart_device::error_info * err, int no)
264: {
265: err->no = no;
266: err->msg = get_msg_for_errno(no);
267: if (err->msg.empty() && no != 0)
268: err->msg = strprintf("Unknown error %d", no);
269: }
270:
271: const char * smart_interface::get_msg_for_errno(int no)
272: {
273: return strerror(no);
274: }
275:
276:
277: /////////////////////////////////////////////////////////////////////////////
278: // Default device factory
279:
280: smart_device * smart_interface::get_smart_device(const char * name, const char * type)
281: {
282: clear_err();
283:
284: // Call platform specific autodetection if no device type specified
285: smart_device * dev;
286: if (!type || !*type) {
287: dev = autodetect_smart_device(name);
288: if (!dev && !get_errno())
289: set_err(EINVAL, "Unable to detect device type");
290: return dev;
291: }
292:
293: // First check for platform specific device types
294: dev = get_custom_smart_device(name, type);
295: if (dev || get_errno())
296: return dev;
297:
298: if (!strcmp(type, "ata"))
299: dev = get_ata_device(name, type);
300: else if (!strcmp(type, "scsi"))
301: dev = get_scsi_device(name, type);
302:
303: else if ( ((!strncmp(type, "sat", 3) && (!type[3] || strchr(",+", type[3])))
304: || (!strncmp(type, "usb", 3)))) {
305: // Split "sat...+base..." -> ("sat...", "base...")
306: unsigned satlen = strcspn(type, "+");
307: std::string sattype(type, satlen);
308: const char * basetype = (type[satlen] ? type+satlen+1 : "");
309: // Recurse to allocate base device, default is standard SCSI
310: if (!*basetype)
311: basetype = "scsi";
312: smart_device_auto_ptr basedev( get_smart_device(name, basetype) );
313: if (!basedev) {
314: set_err(EINVAL, "Type '%s+...': %s", sattype.c_str(), get_errmsg());
315: return 0;
316: }
317: // Result must be SCSI
318: if (!basedev->is_scsi()) {
319: set_err(EINVAL, "Type '%s+...': Device type '%s' is not SCSI", sattype.c_str(), basetype);
320: return 0;
321: }
322: // Attach SAT tunnel
323: ata_device * satdev = get_sat_device(sattype.c_str(), basedev->to_scsi());
324: if (!satdev)
325: return 0;
326: basedev.release();
327: return satdev;
328: }
329:
330: else {
331: set_err(EINVAL, "Unknown device type '%s'", type);
332: return 0;
333: }
334: if (!dev && !get_errno())
335: set_err(EINVAL, "Not a device of type '%s'", type);
336: return dev;
337: }
338:
339: smart_device * smart_interface::get_custom_smart_device(const char * /*name*/, const char * /*type*/)
340: {
341: return 0;
342: }
343:
344: std::string smart_interface::get_valid_custom_dev_types_str()
345: {
346: return "";
347: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>