]> git.proxmox.com Git - mirror_smartmontools-debian.git/blame - dev_interface.cpp
Closes #831504
[mirror_smartmontools-debian.git] / dev_interface.cpp
CommitLineData
2127e193
GI
1/*
2 * dev_interface.cpp
3 *
a86ec89e 4 * Home page of code is: http://www.smartmontools.org
2127e193 5 *
a86ec89e 6 * Copyright (C) 2008-16 Christian Franke <smartmontools-support@lists.sourceforge.net>
2127e193
GI
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"
2127e193
GI
20#include "dev_interface.h"
21#include "dev_tunnelled.h"
ee38a438 22#include "atacmds.h" // ATA_SMART_CMD/STATUS
2127e193
GI
23#include "utility.h"
24
cfbba5b9
GI
25#include <errno.h>
26#include <stdarg.h>
2127e193
GI
27#include <stdexcept>
28
e165493d
GI
29#if defined(HAVE_GETTIMEOFDAY)
30#include <sys/time.h>
31#elif defined(HAVE_FTIME)
32#include <sys/timeb.h>
33#endif
34
a86ec89e 35const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp 4283 2016-04-10 12:55:59Z chrfranke $"
2127e193
GI
36 DEV_INTERFACE_H_CVSID;
37
38/////////////////////////////////////////////////////////////////////////////
39// smart_device
40
a86ec89e
GI
41int smart_device::s_num_objects = 0;
42
2127e193
GI
43smart_device::smart_device(smart_interface * intf, const char * dev_name,
44 const char * dev_type, const char * req_type)
45: m_intf(intf), m_info(dev_name, dev_type, req_type),
a86ec89e 46 m_ata_ptr(0), m_scsi_ptr(0), m_nvme_ptr(0)
2127e193 47{
a86ec89e 48 s_num_objects++;
2127e193
GI
49}
50
51smart_device::smart_device(do_not_use_in_implementation_classes)
a86ec89e 52: m_intf(0), m_ata_ptr(0), m_scsi_ptr(0), m_nvme_ptr(0)
2127e193
GI
53{
54 throw std::logic_error("smart_device: wrong constructor called in implementation class");
55}
56
57smart_device::~smart_device() throw()
58{
a86ec89e 59 s_num_objects--;
2127e193
GI
60}
61
f4e463df
GI
62bool smart_device::is_syscall_unsup() const
63{
64 if (get_errno() == ENOSYS)
65 return true;
66#ifdef ENOTSUP
67 if (get_errno() == ENOTSUP)
68 return true;
69#endif
70 return false;
71}
72
2127e193
GI
73bool smart_device::set_err(int no, const char * msg, ...)
74{
75 if (!msg)
76 return set_err(no);
77 m_err.no = no;
78 va_list ap; va_start(ap, msg);
79 m_err.msg = vstrprintf(msg, ap);
80 va_end(ap);
81 return false;
82}
83
84bool smart_device::set_err(int no)
85{
d008864d 86 return smi()->set_err_var(&m_err, no);
2127e193
GI
87}
88
89smart_device * smart_device::autodetect_open()
90{
91 open();
92 return this;
93}
94
a86ec89e
GI
95bool smart_device::is_powered_down()
96{
97 return false;
98}
99
2127e193
GI
100bool smart_device::owns(const smart_device * /*dev*/) const
101{
102 return false;
103}
104
105void smart_device::release(const smart_device * /*dev*/)
106{
107}
108
109
110/////////////////////////////////////////////////////////////////////////////
111// ata_device
112
113ata_in_regs_48bit::ata_in_regs_48bit()
114: features_16(features, prev.features),
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),
a23d5117
GI
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)
2127e193
GI
121{
122}
123
124ata_out_regs_48bit::ata_out_regs_48bit()
125: sector_count_16(sector_count, prev.sector_count),
126 lba_low_16(lba_low, prev.lba_low),
127 lba_mid_16(lba_mid, prev.lba_mid),
a23d5117
GI
128 lba_high_16(lba_high, prev.lba_high),
129 lba_48( lba_low, lba_mid, lba_high,
130 prev.lba_low, prev.lba_mid, prev.lba_high)
2127e193
GI
131{
132}
133
134ata_cmd_in::ata_cmd_in()
135: direction(no_data),
136 buffer(0),
137 size(0)
138{
139}
140
141ata_cmd_out::ata_cmd_out()
142{
143}
144
145bool ata_device::ata_pass_through(const ata_cmd_in & in)
146{
147 ata_cmd_out dummy;
148 return ata_pass_through(in, dummy);
149}
150
ee38a438
GI
151bool ata_device::ata_cmd_is_supported(const ata_cmd_in & in,
152 unsigned flags, const char * type /* = 0 */)
2127e193
GI
153{
154 // Check DATA IN/OUT
155 switch (in.direction) {
156 case ata_cmd_in::no_data: break;
157 case ata_cmd_in::data_in: break;
158 case ata_cmd_in::data_out: break;
159 default:
160 return set_err(EINVAL, "Invalid data direction %d", (int)in.direction);
161 }
162
163 // Check buffer size
164 if (in.direction == ata_cmd_in::no_data) {
165 if (in.size)
166 return set_err(EINVAL, "Buffer size %u > 0 for NO DATA command", in.size);
167 }
168 else {
169 if (!in.buffer)
170 return set_err(EINVAL, "Buffer not set for DATA IN/OUT command");
171 unsigned count = (in.in_regs.prev.sector_count<<16)|in.in_regs.sector_count;
172 // TODO: Add check for sector count == 0
173 if (count * 512 != in.size)
174 return set_err(EINVAL, "Sector count %u does not match buffer size %u", count, in.size);
175 }
176
177 // Check features
ee38a438
GI
178 const char * errmsg = 0;
179 if (in.direction == ata_cmd_in::data_out && !(flags & supports_data_out))
180 errmsg = "DATA OUT ATA commands not implemented";
181 else if ( in.out_needed.is_set() && !(flags & supports_output_regs)
182 && !( in.in_regs.command == ATA_SMART_CMD
183 && in.in_regs.features == ATA_SMART_STATUS
184 && (flags & supports_smart_status)))
185 errmsg = "Read of ATA output registers not implemented";
186 else if (!(in.size == 0 || in.size == 512) && !(flags & supports_multi_sector))
187 errmsg = "Multi-sector ATA commands not implemented";
188 else if (in.in_regs.is_48bit_cmd() && !(flags & (supports_48bit_hi_null|supports_48bit)))
189 errmsg = "48-bit ATA commands not implemented";
190 else if (in.in_regs.is_real_48bit_cmd() && !(flags & supports_48bit))
191 errmsg = "48-bit ATA commands not fully implemented";
192
193 if (errmsg)
194 return set_err(ENOSYS, "%s%s%s%s", errmsg,
195 (type ? " [" : ""), (type ? type : ""), (type ? "]" : ""));
196
2127e193
GI
197 return true;
198}
199
200bool ata_device::ata_identify_is_cached() const
201{
202 return false;
203}
204
205
a86ec89e
GI
206/////////////////////////////////////////////////////////////////////////////
207// nvme_device
208
209bool nvme_device::set_nvme_err(nvme_cmd_out & out, unsigned status, const char * msg /* = 0 */)
210{
211 if (!status)
212 throw std::logic_error("nvme_device: set_nvme_err() called with status=0");
213
214 out.status = status;
215 out.status_valid = true;
216 return set_err(EIO, "%sNVMe Status 0x%02x", (msg ? msg : ""), status);
217}
218
219
2127e193
GI
220/////////////////////////////////////////////////////////////////////////////
221// tunnelled_device_base
222
223tunnelled_device_base::tunnelled_device_base(smart_device * tunnel_dev)
224: smart_device(never_called),
225 m_tunnel_base_dev(tunnel_dev)
226{
227}
228
229tunnelled_device_base::~tunnelled_device_base() throw()
230{
231 delete m_tunnel_base_dev;
232}
233
234bool tunnelled_device_base::is_open() const
235{
236 return (m_tunnel_base_dev && m_tunnel_base_dev->is_open());
237}
238
239bool tunnelled_device_base::open()
240{
241 if (!m_tunnel_base_dev)
242 return set_err(ENOSYS);
243 if (!m_tunnel_base_dev->open())
244 return set_err(m_tunnel_base_dev->get_err());
245 return true;
246}
247
248bool tunnelled_device_base::close()
249{
250 if (!m_tunnel_base_dev)
251 return true;
252 if (!m_tunnel_base_dev->close())
253 return set_err(m_tunnel_base_dev->get_err());
254 return true;
255}
256
257bool tunnelled_device_base::owns(const smart_device * dev) const
258{
259 return (m_tunnel_base_dev && (m_tunnel_base_dev == dev));
260}
261
262void tunnelled_device_base::release(const smart_device * dev)
263{
264 if (m_tunnel_base_dev == dev)
265 m_tunnel_base_dev = 0;
266}
267
268
269/////////////////////////////////////////////////////////////////////////////
270// smart_interface
271
272// Pointer to (usually singleton) interface object returned by ::smi()
273smart_interface * smart_interface::s_instance;
274
54965743 275std::string smart_interface::get_os_version_str()
2127e193
GI
276{
277 return SMARTMONTOOLS_BUILD_HOST;
278}
279
54965743 280std::string smart_interface::get_valid_dev_types_str()
2127e193 281{
2127e193 282 // default
54965743 283 std::string s =
a86ec89e
GI
284 "ata, scsi, nvme[,NSID], sat[,auto][,N][+TYPE], "
285 "usbcypress[,X], usbjmicron[,p][,x][,N], usbprolific, usbsunplus";
2127e193 286 // append custom
54965743
GI
287 std::string s2 = get_valid_custom_dev_types_str();
288 if (!s2.empty()) {
289 s += ", "; s += s2;
290 }
291 return s;
2127e193
GI
292}
293
54965743 294std::string smart_interface::get_app_examples(const char * /*appname*/)
2127e193 295{
54965743 296 return "";
2127e193
GI
297}
298
e165493d
GI
299int64_t smart_interface::get_timer_usec()
300{
301#if defined(HAVE_GETTIMEOFDAY)
302 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
303 {
304 static bool have_clock_monotonic = true;
305 if (have_clock_monotonic) {
306 struct timespec ts;
307 if (!clock_gettime(CLOCK_MONOTONIC, &ts))
308 return ts.tv_sec * 1000000LL + ts.tv_nsec/1000;
309 have_clock_monotonic = false;
310 }
311 }
312 #endif
313 {
314 struct timeval tv;
315 gettimeofday(&tv, 0);
316 return tv.tv_sec * 1000000LL + tv.tv_usec;
317 }
318#elif defined(HAVE_FTIME)
319 {
320 struct timeb tb;
321 ftime(&tb);
322 return tb.time * 1000000LL + tb.millitm * 1000;
323 }
324#else
325 return -1;
326#endif
327}
328
d008864d 329bool smart_interface::disable_system_auto_standby(bool /*disable*/)
2127e193 330{
d008864d
GI
331 return set_err(ENOSYS);
332}
333
334bool smart_interface::set_err(int no, const char * msg, ...)
335{
336 if (!msg)
337 return set_err(no);
2127e193
GI
338 m_err.no = no;
339 va_list ap; va_start(ap, msg);
340 m_err.msg = vstrprintf(msg, ap);
341 va_end(ap);
d008864d 342 return false;
2127e193
GI
343}
344
d008864d 345bool smart_interface::set_err(int no)
2127e193 346{
d008864d 347 return set_err_var(&m_err, no);
2127e193
GI
348}
349
d008864d 350bool smart_interface::set_err_var(smart_device::error_info * err, int no)
2127e193
GI
351{
352 err->no = no;
353 err->msg = get_msg_for_errno(no);
354 if (err->msg.empty() && no != 0)
355 err->msg = strprintf("Unknown error %d", no);
d008864d 356 return false;
2127e193
GI
357}
358
359const char * smart_interface::get_msg_for_errno(int no)
360{
361 return strerror(no);
362}
363
364
365/////////////////////////////////////////////////////////////////////////////
366// Default device factory
367
368smart_device * smart_interface::get_smart_device(const char * name, const char * type)
369{
370 clear_err();
cfbba5b9
GI
371
372 // Call platform specific autodetection if no device type specified
373 smart_device * dev;
2127e193 374 if (!type || !*type) {
cfbba5b9 375 dev = autodetect_smart_device(name);
2127e193
GI
376 if (!dev && !get_errno())
377 set_err(EINVAL, "Unable to detect device type");
378 return dev;
379 }
380
cfbba5b9
GI
381 // First check for platform specific device types
382 dev = get_custom_smart_device(name, type);
2127e193
GI
383 if (dev || get_errno())
384 return dev;
385
386 if (!strcmp(type, "ata"))
387 dev = get_ata_device(name, type);
388 else if (!strcmp(type, "scsi"))
389 dev = get_scsi_device(name, type);
390
a86ec89e
GI
391 else if (str_starts_with(type, "nvme")) {
392 int n1 = -1, n2 = -1, len = strlen(type);
393 unsigned nsid = 0; // invalid namespace id -> use default
394 sscanf(type, "nvme%n,0x%x%n", &n1, &nsid, &n2);
395 if (!(n1 == len || n2 == len)) {
396 set_err(EINVAL, "Invalid NVMe namespace id in '%s'", type);
397 return 0;
398 }
399 dev = get_nvme_device(name, type, nsid);
400 }
401
2127e193
GI
402 else if ( ((!strncmp(type, "sat", 3) && (!type[3] || strchr(",+", type[3])))
403 || (!strncmp(type, "usb", 3)))) {
404 // Split "sat...+base..." -> ("sat...", "base...")
405 unsigned satlen = strcspn(type, "+");
406 std::string sattype(type, satlen);
407 const char * basetype = (type[satlen] ? type+satlen+1 : "");
408 // Recurse to allocate base device, default is standard SCSI
409 if (!*basetype)
410 basetype = "scsi";
bed94269
GI
411 smart_device_auto_ptr basedev( get_smart_device(name, basetype) );
412 if (!basedev) {
2127e193
GI
413 set_err(EINVAL, "Type '%s+...': %s", sattype.c_str(), get_errmsg());
414 return 0;
415 }
416 // Result must be SCSI
bed94269 417 if (!basedev->is_scsi()) {
2127e193
GI
418 set_err(EINVAL, "Type '%s+...': Device type '%s' is not SCSI", sattype.c_str(), basetype);
419 return 0;
420 }
421 // Attach SAT tunnel
a86ec89e 422 return get_sat_device(sattype.c_str(), basedev.release()->to_scsi());
2127e193
GI
423 }
424
425 else {
426 set_err(EINVAL, "Unknown device type '%s'", type);
427 return 0;
428 }
429 if (!dev && !get_errno())
430 set_err(EINVAL, "Not a device of type '%s'", type);
431 return dev;
432}
433
a86ec89e
GI
434bool smart_interface::scan_smart_devices(smart_device_list & devlist,
435 const smart_devtype_list & types, const char * pattern /* = 0 */)
436{
437 unsigned n = types.size();
438 if (n == 0)
439 return scan_smart_devices(devlist, (const char *)0, pattern);
440 if (n == 1)
441 return scan_smart_devices(devlist, types.front().c_str(), pattern);
442
443 for (unsigned i = 0; i < n; i++) {
444 smart_device_list tmplist;
445 if (!scan_smart_devices(tmplist, types[i].c_str(), pattern))
446 return false;
447 devlist.append(tmplist);
448 }
449
450 return true;
451}
452
453nvme_device * smart_interface::get_nvme_device(const char * /*name*/, const char * /*type*/, unsigned /*nsid*/)
454{
455 set_err(ENOSYS, "NVMe devices are not supported in this version of smartmontools");
456 return 0;
457}
458
2127e193
GI
459smart_device * smart_interface::get_custom_smart_device(const char * /*name*/, const char * /*type*/)
460{
461 return 0;
462}
463
54965743 464std::string smart_interface::get_valid_custom_dev_types_str()
2127e193 465{
54965743 466 return "";
2127e193 467}