smartmontools  SVN Rev 4335
Utility to control and monitor storage systems with "S.M.A.R.T."
dev_interface.cpp
Go to the documentation of this file.
1 /*
2  * dev_interface.cpp
3  *
4  * Home page of code is: http://www.smartmontools.org
5  *
6  * Copyright (C) 2008-16 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 "atacmds.h" // ATA_SMART_CMD/STATUS
23 #include "utility.h"
24 
25 #include <errno.h>
26 #include <stdarg.h>
27 #include <stdexcept>
28 
29 #if defined(HAVE_GETTIMEOFDAY)
30 #include <sys/time.h>
31 #elif defined(HAVE_FTIME)
32 #include <sys/timeb.h>
33 #endif
34 
35 const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp 4283 2016-04-10 12:55:59Z chrfranke $"
37 
38 /////////////////////////////////////////////////////////////////////////////
39 // smart_device
40 
42 
43 smart_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),
46  m_ata_ptr(0), m_scsi_ptr(0), m_nvme_ptr(0)
47 {
48  s_num_objects++;
49 }
50 
52 : m_intf(0), m_ata_ptr(0), m_scsi_ptr(0), m_nvme_ptr(0)
53 {
54  throw std::logic_error("smart_device: wrong constructor called in implementation class");
55 }
56 
58 {
59  s_num_objects--;
60 }
61 
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 
73 bool 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 
85 {
86  return smi()->set_err_var(&m_err, no);
87 }
88 
90 {
91  open();
92  return this;
93 }
94 
96 {
97  return false;
98 }
99 
100 bool smart_device::owns(const smart_device * /*dev*/) const
101 {
102  return false;
103 }
104 
105 void smart_device::release(const smart_device * /*dev*/)
106 {
107 }
108 
109 
110 /////////////////////////////////////////////////////////////////////////////
111 // ata_device
112 
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),
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)
121 {
122 }
123 
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),
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)
131 {
132 }
133 
135 : direction(no_data),
136  buffer(0),
137  size(0)
138 {
139 }
140 
142 {
143 }
144 
146 {
147  ata_cmd_out dummy;
148  return ata_pass_through(in, dummy);
149 }
150 
152  unsigned flags, const char * type /* = 0 */)
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
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
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 
197  return true;
198 }
199 
201 {
202  return false;
203 }
204 
205 
206 /////////////////////////////////////////////////////////////////////////////
207 // nvme_device
208 
209 bool 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 
220 /////////////////////////////////////////////////////////////////////////////
221 // tunnelled_device_base
222 
224 : smart_device(never_called),
225  m_tunnel_base_dev(tunnel_dev)
226 {
227 }
228 
230 {
231  delete m_tunnel_base_dev;
232 }
233 
235 {
237 }
238 
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 
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 
258 {
259  return (m_tunnel_base_dev && (m_tunnel_base_dev == dev));
260 }
261 
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()
274 
276 {
277  return SMARTMONTOOLS_BUILD_HOST;
278 }
279 
281 {
282  // default
283  std::string s =
284  "ata, scsi, nvme[,NSID], sat[,auto][,N][+TYPE], "
285  "usbcypress[,X], usbjmicron[,p][,x][,N], usbprolific, usbsunplus";
286  // append custom
287  std::string s2 = get_valid_custom_dev_types_str();
288  if (!s2.empty()) {
289  s += ", "; s += s2;
290  }
291  return s;
292 }
293 
294 std::string smart_interface::get_app_examples(const char * /*appname*/)
295 {
296  return "";
297 }
298 
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 
330 {
331  return set_err(ENOSYS);
332 }
333 
334 bool smart_interface::set_err(int no, const char * msg, ...)
335 {
336  if (!msg)
337  return set_err(no);
338  m_err.no = no;
339  va_list ap; va_start(ap, msg);
340  m_err.msg = vstrprintf(msg, ap);
341  va_end(ap);
342  return false;
343 }
344 
346 {
347  return set_err_var(&m_err, no);
348 }
349 
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);
356  return false;
357 }
358 
360 {
361  return strerror(no);
362 }
363 
364 
365 /////////////////////////////////////////////////////////////////////////////
366 // Default device factory
367 
368 smart_device * smart_interface::get_smart_device(const char * name, const char * type)
369 {
370  clear_err();
371 
372  // Call platform specific autodetection if no device type specified
373  smart_device * dev;
374  if (!type || !*type) {
375  dev = autodetect_smart_device(name);
376  if (!dev && !get_errno())
377  set_err(EINVAL, "Unable to detect device type");
378  return dev;
379  }
380 
381  // First check for platform specific device types
382  dev = get_custom_smart_device(name, type);
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 
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 
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";
411  smart_device_auto_ptr basedev( get_smart_device(name, basetype) );
412  if (!basedev) {
413  set_err(EINVAL, "Type '%s+...': %s", sattype.c_str(), get_errmsg());
414  return 0;
415  }
416  // Result must be SCSI
417  if (!basedev->is_scsi()) {
418  set_err(EINVAL, "Type '%s+...': Device type '%s' is not SCSI", sattype.c_str(), basetype);
419  return 0;
420  }
421  // Attach SAT tunnel
422  return get_sat_device(sattype.c_str(), basedev.release()->to_scsi());
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 
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 
453 nvme_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 
459 smart_device * smart_interface::get_custom_smart_device(const char * /*name*/, const char * /*type*/)
460 {
461  return 0;
462 }
463 
465 {
466  return "";
467 }
virtual int64_t get_timer_usec()
Get microseconds since some unspecified starting point.
Error (number,message) pair.
Definition: dev_interface.h:59
int get_errno() const
Get last error number.
virtual void release(const smart_device *dev)
Release ownership of other device.
u16 s[6]
Definition: megaraid.h:97
ata_out_regs_flags out_needed
True if output register value needed.
const char * get_errmsg() const
Get last error message.
virtual std::string get_valid_dev_types_str()
Return valid args for device type option/directive.
u32 size
Definition: megaraid.h:79
std::string msg
Error message.
Definition: dev_interface.h:68
virtual ata_device * get_sat_device(const char *type, scsi_device *scsidev)
Return ATA->SCSI filter for a SAT or USB 'type'.
Definition: scsiata.cpp:1487
do_not_use_in_implementation_classes
Dummy enum for dummy constructor.
Definition: dev_interface.h:79
ata_in_regs prev
"previous content"
#define ATA_SMART_CMD
Definition: atacmds.h:75
smart_device::error_info m_err
tunnelled_device_base(smart_device *tunnel_dev)
int get_errno() const
Get last error number.
virtual void release(const smart_device *dev)
Release ownership of other device.
virtual bool open()=0
Open device, return false on error.
bool str_starts_with(const char *str, const char *prefix)
Definition: utility.h:57
void clear_err()
Clear last error info.
bool set_nvme_err(nvme_cmd_out &out, unsigned status, const char *msg=0)
Set last error number and message if pass-through returns NVMe error status.
Smart pointer class for device pointers.
virtual bool is_powered_down()
Early test if device is powered up or down.
virtual const char * get_msg_for_errno(int no)
Convert error number into message, used by set_err(no).
virtual std::string get_valid_custom_dev_types_str()
Return valid 'type' args accepted by above.
virtual bool close()=0
Close device, return false on error.
u32 count
Definition: megaraid.h:80
#define ENOTSUP
Definition: os_linux.cpp:100
u16 flags
Definition: megaraid.h:93
void * buffer
Pointer to data buffer.
NVMe pass through output parameters.
#define DEV_INTERFACE_H_CVSID
Definition: dev_interface.h:21
bool is_real_48bit_cmd() const
Return true if 48-bit command with any nonzero high byte.
virtual smart_device * get_smart_device(const char *name, const char *type)
Return device object for device 'name' with some 'type'.
bool ata_cmd_is_supported(const ata_cmd_in &in, unsigned flags, const char *type=0)
Check command input parameters.
ata_in_regs_48bit in_regs
Input registers.
virtual ata_device * get_ata_device(const char *name, const char *type)=0
Return standard ATA device.
List of devices for DEVICESCAN.
enum ata_cmd_in::@27 direction
I/O direction.
device_type * release()
Return the pointer and release ownership.
bool set_err_var(smart_device::error_info *err, int no)
Set last error number and default message to any error_info.
virtual bool is_open() const =0
Return true if device is open.
The platform interface abstraction.
virtual bool ata_pass_through(const ata_cmd_in &in, ata_cmd_out &out)=0
ATA pass through.
std::vector< std::string > smart_devtype_list
List of types for DEVICESCAN.
NVMe device access.
bool status_valid
true if status is valid
error_info m_err
long long int64_t
Definition: int64.h:51
static smart_interface * s_instance
Pointer to the interface object.
virtual bool open()
Open device, return false on error.
virtual smart_device * autodetect_smart_device(const char *name)=0
Autodetect device if no device type specified.
virtual nvme_device * get_nvme_device(const char *name, const char *type, unsigned nsid)
Return standard NVMe device.
virtual smart_device * get_custom_smart_device(const char *name, const char *type)
Return device for platform specific 'type'.
virtual std::string get_app_examples(const char *appname)
Return example string for program 'appname'.
std::string vstrprintf(const char *fmt, va_list ap)
Definition: utility.cpp:742
ptr_t buffer
Definition: megaraid.h:89
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
bool is_set() const
Return true if any flag is set.
virtual bool owns(const smart_device *dev) const
Return true if other device is owned by this device.
unsigned size
Size of buffer.
virtual ~tunnelled_device_base()
ata_register features
bool is_48bit_cmd() const
Return true if 48-bit command.
virtual bool scan_smart_devices(smart_device_list &devlist, const char *type, const char *pattern=0)=0
Fill 'devlist' with devices of some 'type' with device names specified by some optional 'pattern'...
Base class for all devices.
Definition: dev_interface.h:39
int no
Error number.
Definition: dev_interface.h:67
ata_register sector_count
virtual bool disable_system_auto_standby(bool disable)
Disable/Enable system auto standby/sleep mode.
smart_device * m_tunnel_base_dev
Definition: dev_tunnelled.h:50
virtual scsi_device * get_scsi_device(const char *name, const char *type)=0
Return standard SCSI device.
ata_register command
virtual bool close()
Close device, return false on error.
virtual smart_device * autodetect_open()
Open device with autodetection support.
ATA pass through input parameters.
std::string strprintf(const char *fmt,...)
Definition: utility.cpp:750
const char * dev_interface_cpp_cvsid
virtual ~smart_device()
void append(smart_device_list &devlist)
smart_interface * smi()
Get interface which produced this object.
const error_info & get_err() const
Get last error info struct.
unsigned short status
Status Field (DW3 31:17)
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
virtual bool is_open() const
Return true if device is open.
virtual bool ata_identify_is_cached() const
Return true if OS caches ATA identify sector.
virtual bool is_syscall_unsup() const
Return true if last error indicates an unsupported system call.
ATA pass through output parameters.
smart_device(smart_interface *intf, const char *dev_name, const char *dev_type, const char *req_type)
Constructor to init interface and device info.
virtual bool owns(const smart_device *dev) const
Return true if other device is owned by this device.
static int s_num_objects
virtual std::string get_os_version_str()
Return info string about build host and/or OS version.
#define ATA_SMART_STATUS
Definition: atacmds.h:105