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