]> git.proxmox.com Git - mirror_smartmontools-debian.git/blob - dev_interface.cpp
Updated changelog
[mirror_smartmontools-debian.git] / dev_interface.cpp
1 /*
2 * dev_interface.cpp
3 *
4 * Home page of code is: http://smartmontools.sourceforge.net
5 *
6 * Copyright (C) 2008-12 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 #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 3524 2012-03-21 22:19:31Z chrfranke $"
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
57 bool smart_device::set_err(int no, const char * msg, ...)
58 {
59 if (!msg)
60 return set_err(no);
61 m_err.no = no;
62 va_list ap; va_start(ap, msg);
63 m_err.msg = vstrprintf(msg, ap);
64 va_end(ap);
65 return false;
66 }
67
68 bool smart_device::set_err(int no)
69 {
70 return smi()->set_err_var(&m_err, no);
71 }
72
73 smart_device * smart_device::autodetect_open()
74 {
75 open();
76 return this;
77 }
78
79 bool smart_device::owns(const smart_device * /*dev*/) const
80 {
81 return false;
82 }
83
84 void smart_device::release(const smart_device * /*dev*/)
85 {
86 }
87
88
89 /////////////////////////////////////////////////////////////////////////////
90 // ata_device
91
92 ata_in_regs_48bit::ata_in_regs_48bit()
93 : features_16(features, prev.features),
94 sector_count_16(sector_count, prev.sector_count),
95 lba_low_16(lba_low, prev.lba_low),
96 lba_mid_16(lba_mid, prev.lba_mid),
97 lba_high_16(lba_high, prev.lba_high),
98 lba_48( lba_low, lba_mid, lba_high,
99 prev.lba_low, prev.lba_mid, prev.lba_high)
100 {
101 }
102
103 ata_out_regs_48bit::ata_out_regs_48bit()
104 : sector_count_16(sector_count, prev.sector_count),
105 lba_low_16(lba_low, prev.lba_low),
106 lba_mid_16(lba_mid, prev.lba_mid),
107 lba_high_16(lba_high, prev.lba_high),
108 lba_48( lba_low, lba_mid, lba_high,
109 prev.lba_low, prev.lba_mid, prev.lba_high)
110 {
111 }
112
113 ata_cmd_in::ata_cmd_in()
114 : direction(no_data),
115 buffer(0),
116 size(0)
117 {
118 }
119
120 ata_cmd_out::ata_cmd_out()
121 {
122 }
123
124 bool ata_device::ata_pass_through(const ata_cmd_in & in)
125 {
126 ata_cmd_out dummy;
127 return ata_pass_through(in, dummy);
128 }
129
130 bool ata_device::ata_cmd_is_ok(const ata_cmd_in & in,
131 bool data_out_support /*= false*/,
132 bool multi_sector_support /*= false*/,
133 bool ata_48bit_support /*= false*/)
134 {
135 // Check DATA IN/OUT
136 switch (in.direction) {
137 case ata_cmd_in::no_data: break;
138 case ata_cmd_in::data_in: break;
139 case ata_cmd_in::data_out: break;
140 default:
141 return set_err(EINVAL, "Invalid data direction %d", (int)in.direction);
142 }
143
144 // Check buffer size
145 if (in.direction == ata_cmd_in::no_data) {
146 if (in.size)
147 return set_err(EINVAL, "Buffer size %u > 0 for NO DATA command", in.size);
148 }
149 else {
150 if (!in.buffer)
151 return set_err(EINVAL, "Buffer not set for DATA IN/OUT command");
152 unsigned count = (in.in_regs.prev.sector_count<<16)|in.in_regs.sector_count;
153 // TODO: Add check for sector count == 0
154 if (count * 512 != in.size)
155 return set_err(EINVAL, "Sector count %u does not match buffer size %u", count, in.size);
156 }
157
158 // Check features
159 if (in.direction == ata_cmd_in::data_out && !data_out_support)
160 return set_err(ENOSYS, "DATA OUT ATA commands not supported");
161 if (!(in.size == 0 || in.size == 512) && !multi_sector_support)
162 return set_err(ENOSYS, "Multi-sector ATA commands not supported");
163 if (in.in_regs.is_48bit_cmd() && !ata_48bit_support)
164 return set_err(ENOSYS, "48-bit ATA commands not supported");
165 return true;
166 }
167
168 bool ata_device::ata_identify_is_cached() const
169 {
170 return false;
171 }
172
173
174 /////////////////////////////////////////////////////////////////////////////
175 // tunnelled_device_base
176
177 tunnelled_device_base::tunnelled_device_base(smart_device * tunnel_dev)
178 : smart_device(never_called),
179 m_tunnel_base_dev(tunnel_dev)
180 {
181 }
182
183 tunnelled_device_base::~tunnelled_device_base() throw()
184 {
185 delete m_tunnel_base_dev;
186 }
187
188 bool tunnelled_device_base::is_open() const
189 {
190 return (m_tunnel_base_dev && m_tunnel_base_dev->is_open());
191 }
192
193 bool tunnelled_device_base::open()
194 {
195 if (!m_tunnel_base_dev)
196 return set_err(ENOSYS);
197 if (!m_tunnel_base_dev->open())
198 return set_err(m_tunnel_base_dev->get_err());
199 return true;
200 }
201
202 bool tunnelled_device_base::close()
203 {
204 if (!m_tunnel_base_dev)
205 return true;
206 if (!m_tunnel_base_dev->close())
207 return set_err(m_tunnel_base_dev->get_err());
208 return true;
209 }
210
211 bool tunnelled_device_base::owns(const smart_device * dev) const
212 {
213 return (m_tunnel_base_dev && (m_tunnel_base_dev == dev));
214 }
215
216 void tunnelled_device_base::release(const smart_device * dev)
217 {
218 if (m_tunnel_base_dev == dev)
219 m_tunnel_base_dev = 0;
220 }
221
222
223 /////////////////////////////////////////////////////////////////////////////
224 // smart_interface
225
226 // Pointer to (usually singleton) interface object returned by ::smi()
227 smart_interface * smart_interface::s_instance;
228
229 std::string smart_interface::get_os_version_str()
230 {
231 return SMARTMONTOOLS_BUILD_HOST;
232 }
233
234 std::string smart_interface::get_valid_dev_types_str()
235 {
236 // default
237 std::string s =
238 "ata, scsi, sat[,auto][,N][+TYPE], usbcypress[,X], usbjmicron[,x][,N], usbsunplus";
239 // append custom
240 std::string s2 = get_valid_custom_dev_types_str();
241 if (!s2.empty()) {
242 s += ", "; s += s2;
243 }
244 return s;
245 }
246
247 std::string smart_interface::get_app_examples(const char * /*appname*/)
248 {
249 return "";
250 }
251
252 int64_t smart_interface::get_timer_usec()
253 {
254 #if defined(HAVE_GETTIMEOFDAY)
255 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
256 {
257 static bool have_clock_monotonic = true;
258 if (have_clock_monotonic) {
259 struct timespec ts;
260 if (!clock_gettime(CLOCK_MONOTONIC, &ts))
261 return ts.tv_sec * 1000000LL + ts.tv_nsec/1000;
262 have_clock_monotonic = false;
263 }
264 }
265 #endif
266 {
267 struct timeval tv;
268 gettimeofday(&tv, 0);
269 return tv.tv_sec * 1000000LL + tv.tv_usec;
270 }
271 #elif defined(HAVE_FTIME)
272 {
273 struct timeb tb;
274 ftime(&tb);
275 return tb.time * 1000000LL + tb.millitm * 1000;
276 }
277 #else
278 return -1;
279 #endif
280 }
281
282 bool smart_interface::disable_system_auto_standby(bool /*disable*/)
283 {
284 return set_err(ENOSYS);
285 }
286
287 bool smart_interface::set_err(int no, const char * msg, ...)
288 {
289 if (!msg)
290 return set_err(no);
291 m_err.no = no;
292 va_list ap; va_start(ap, msg);
293 m_err.msg = vstrprintf(msg, ap);
294 va_end(ap);
295 return false;
296 }
297
298 bool smart_interface::set_err(int no)
299 {
300 return set_err_var(&m_err, no);
301 }
302
303 bool smart_interface::set_err_var(smart_device::error_info * err, int no)
304 {
305 err->no = no;
306 err->msg = get_msg_for_errno(no);
307 if (err->msg.empty() && no != 0)
308 err->msg = strprintf("Unknown error %d", no);
309 return false;
310 }
311
312 const char * smart_interface::get_msg_for_errno(int no)
313 {
314 return strerror(no);
315 }
316
317
318 /////////////////////////////////////////////////////////////////////////////
319 // Default device factory
320
321 smart_device * smart_interface::get_smart_device(const char * name, const char * type)
322 {
323 clear_err();
324
325 // Call platform specific autodetection if no device type specified
326 smart_device * dev;
327 if (!type || !*type) {
328 dev = autodetect_smart_device(name);
329 if (!dev && !get_errno())
330 set_err(EINVAL, "Unable to detect device type");
331 return dev;
332 }
333
334 // First check for platform specific device types
335 dev = get_custom_smart_device(name, type);
336 if (dev || get_errno())
337 return dev;
338
339 if (!strcmp(type, "ata"))
340 dev = get_ata_device(name, type);
341 else if (!strcmp(type, "scsi"))
342 dev = get_scsi_device(name, type);
343
344 else if ( ((!strncmp(type, "sat", 3) && (!type[3] || strchr(",+", type[3])))
345 || (!strncmp(type, "usb", 3)))) {
346 // Split "sat...+base..." -> ("sat...", "base...")
347 unsigned satlen = strcspn(type, "+");
348 std::string sattype(type, satlen);
349 const char * basetype = (type[satlen] ? type+satlen+1 : "");
350 // Recurse to allocate base device, default is standard SCSI
351 if (!*basetype)
352 basetype = "scsi";
353 smart_device_auto_ptr basedev( get_smart_device(name, basetype) );
354 if (!basedev) {
355 set_err(EINVAL, "Type '%s+...': %s", sattype.c_str(), get_errmsg());
356 return 0;
357 }
358 // Result must be SCSI
359 if (!basedev->is_scsi()) {
360 set_err(EINVAL, "Type '%s+...': Device type '%s' is not SCSI", sattype.c_str(), basetype);
361 return 0;
362 }
363 // Attach SAT tunnel
364 ata_device * satdev = get_sat_device(sattype.c_str(), basedev->to_scsi());
365 if (!satdev)
366 return 0;
367 basedev.release();
368 return satdev;
369 }
370
371 else {
372 set_err(EINVAL, "Unknown device type '%s'", type);
373 return 0;
374 }
375 if (!dev && !get_errno())
376 set_err(EINVAL, "Not a device of type '%s'", type);
377 return dev;
378 }
379
380 smart_device * smart_interface::get_custom_smart_device(const char * /*name*/, const char * /*type*/)
381 {
382 return 0;
383 }
384
385 std::string smart_interface::get_valid_custom_dev_types_str()
386 {
387 return "";
388 }