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