smartmontools  SVN Rev 4063
Utility to control and monitor storage systems with "S.M.A.R.T."
dev_legacy.cpp
Go to the documentation of this file.
1 /*
2  * dev_legacy.cpp
3  *
4  * Home page of code is: http://smartmontools.sourceforge.net
5  *
6  * Copyright (C) 2008-11 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 "utility.h"
21 #include "atacmds.h"
22 #include "scsicmds.h"
23 #include "dev_interface.h"
24 #include "dev_ata_cmd_set.h"
25 
26 #include <errno.h>
27 
28 const char * dev_legacy_cpp_cvsid = "$Id: dev_legacy.cpp 3263 2011-02-20 18:32:56Z chrfranke $"
30 
31 /////////////////////////////////////////////////////////////////////////////
32 
33 // Legacy interface declarations (now commented out globally):
34 
35 // from utility.h:
36 int guess_device_type(const char * dev_name);
37 int make_device_names (char ***devlist, const char* name);
38 int deviceopen(const char *pathname, char *type);
39 int deviceclose(int fd);
40 
41 // from atacmds.h:
42 int ata_command_interface(int device, smart_command_set command, int select, char *data);
43 
44 // from scsicmds.h:
45 int do_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report);
46 
47 // from smartctl.h:
49 
50 /////////////////////////////////////////////////////////////////////////////
51 
52 namespace os { // No need to publish anything, name provided for Doxygen
53 
54 /////////////////////////////////////////////////////////////////////////////
55 /// Implement shared open/close routines with old functions.
56 
58 : virtual public /*implements*/ smart_device
59 {
60 public:
61  explicit legacy_smart_device(const char * mode)
63  m_fd(-1), m_mode(mode) { }
64 
65  virtual ~legacy_smart_device() throw();
66 
67  virtual bool is_open() const;
68 
69  virtual bool open();
70 
71  virtual bool close();
72 
73 protected:
74  /// Return filedesc for derived classes.
75  int get_fd() const
76  { return m_fd; }
77 
78 private:
79  int m_fd; ///< filedesc, -1 if not open.
80  const char * m_mode; ///< Mode string for deviceopen().
81 };
82 
83 
85 {
86  if (m_fd >= 0)
88 }
89 
91 {
92  return (m_fd >= 0);
93 }
94 
96 {
97  m_fd = ::deviceopen(get_dev_name(), const_cast<char*>(m_mode));
98  if (m_fd < 0) {
99  set_err((errno==ENOENT || errno==ENOTDIR) ? ENODEV : errno);
100  return false;
101  }
102  return true;
103 }
104 
106 {
107  int fd = m_fd; m_fd = -1;
108  if (::deviceclose(fd) < 0) {
109  set_err(errno);
110  return false;
111  }
112  return true;
113 }
114 
115 /////////////////////////////////////////////////////////////////////////////
116 /// Implement standard ATA support with old functions
117 
119 : public /*implements*/ ata_device_with_command_set,
120  public /*extends*/ legacy_smart_device
121 {
122 public:
123  legacy_ata_device(smart_interface * intf, const char * dev_name, const char * req_type);
124 
125 protected:
126  virtual int ata_command_interface(smart_command_set command, int select, char * data);
127 };
128 
129 legacy_ata_device::legacy_ata_device(smart_interface * intf, const char * dev_name, const char * req_type)
130 : smart_device(intf, dev_name, "ata", req_type),
131  legacy_smart_device("ATA")
132 {
133 }
134 
136 {
137  return ::ata_command_interface(get_fd(), command, select, data);
138 }
139 
140 
141 /////////////////////////////////////////////////////////////////////////////
142 /// Implement standard SCSI support with old functions
143 
145 : public /*implements*/ scsi_device,
146  public /*extends*/ legacy_smart_device
147 {
148 public:
149  legacy_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type);
150 
151  virtual smart_device * autodetect_open();
152 
153  virtual bool scsi_pass_through(scsi_cmnd_io * iop);
154 };
155 
157  const char * dev_name, const char * req_type)
158 : smart_device(intf, dev_name, "scsi", req_type),
159  legacy_smart_device("SCSI")
160 {
161 }
162 
164 {
165  int status = ::do_scsi_cmnd_io(get_fd(), iop, scsi_debugmode);
166  if (status < 0) {
167  set_err(-status);
168  return false;
169  }
170  return true;
171 }
172 
173 
174 /////////////////////////////////////////////////////////////////////////////
175 /// SCSI open with autodetection support
176 
178 {
179  // Open device
180  if (!open())
181  return this;
182 
183  // No Autodetection if device type was specified by user
184  if (*get_req_type())
185  return this;
186 
187  // The code below is based on smartd.cpp:SCSIFilterKnown()
188 
189  // Get INQUIRY
190  unsigned char req_buff[64] = {0, };
191  int req_len = 36;
192  if (scsiStdInquiry(this, req_buff, req_len)) {
193  // Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices
194  // watch this spot ... other devices could lock up here
195  req_len = 64;
196  if (scsiStdInquiry(this, req_buff, req_len)) {
197  // device doesn't like INQUIRY commands
198  close();
199  set_err(EIO, "INQUIRY failed");
200  return this;
201  }
202  }
203 
204  int avail_len = req_buff[4] + 5;
205  int len = (avail_len < req_len ? avail_len : req_len);
206  if (len < 36)
207  return this;
208 
209  // Use INQUIRY to detect type
210 
211  // SAT or USB ?
212  {
213  smart_device * newdev = smi()->autodetect_sat_device(this, req_buff, len);
214  if (newdev)
215  // NOTE: 'this' is now owned by '*newdev'
216  return newdev;
217  }
218 
219  // Nothing special found
220  return this;
221 }
222 
223 
224 /////////////////////////////////////////////////////////////////////////////
225 /// Implement platform interface with old functions.
226 
228 : public /*implements*/ smart_interface
229 {
230 public:
231  virtual std::string get_app_examples(const char * appname);
232 
233  virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
234  const char * pattern = 0);
235 
236 protected:
237  virtual ata_device * get_ata_device(const char * name, const char * type);
238 
239  virtual scsi_device * get_scsi_device(const char * name, const char * type);
240 
241  virtual smart_device * autodetect_smart_device(const char * name);
242 };
243 
244 
245 //////////////////////////////////////////////////////////////////////
246 
247 std::string legacy_smart_interface::get_app_examples(const char * appname)
248 {
249  if (!strcmp(appname, "smartctl"))
250  ::print_smartctl_examples(); // this prints to stdout ...
251  return ""; // ... so don't print again.
252 }
253 
254 ata_device * legacy_smart_interface::get_ata_device(const char * name, const char * type)
255 {
256  return new legacy_ata_device(this, name, type);
257 }
258 
259 scsi_device * legacy_smart_interface::get_scsi_device(const char * name, const char * type)
260 {
261  return new legacy_scsi_device(this, name, type);
262 }
263 
264 
266 {
267  switch (::guess_device_type(name)) {
268  case CONTROLLER_ATA : return new legacy_ata_device(this, name, "");
269  case CONTROLLER_SCSI: return new legacy_scsi_device(this, name, "");
270  }
271  // TODO: Test autodetect device here
272  return 0;
273 }
274 
275 
276 static void free_devnames(char * * devnames, int numdevs)
277 {
278  static const char version[] = "$Id: dev_legacy.cpp 3263 2011-02-20 18:32:56Z chrfranke $";
279  for (int i = 0; i < numdevs; i++)
280  FreeNonZero(devnames[i], -1,__LINE__, version);
281  FreeNonZero(devnames, (sizeof (char*) * numdevs),__LINE__, version);
282 }
283 
285  const char * type, const char * pattern /*= 0*/)
286 {
287  if (pattern) {
288  set_err(EINVAL, "DEVICESCAN with pattern not implemented yet");
289  return false;
290  }
291 
292  // Make namelists
293  char * * atanames = 0; int numata = 0;
294  if (!type || !strcmp(type, "ata")) {
295  numata = ::make_device_names(&atanames, "ATA");
296  if (numata < 0) {
297  set_err(ENOMEM);
298  return false;
299  }
300  }
301 
302  char * * scsinames = 0; int numscsi = 0;
303  if (!type || !strcmp(type, "scsi")) {
304  numscsi = ::make_device_names(&scsinames, "SCSI");
305  if (numscsi < 0) {
306  free_devnames(atanames, numata);
307  set_err(ENOMEM);
308  return false;
309  }
310  }
311 
312  // Add to devlist
313  int i;
314  if (!type)
315  type="";
316  for (i = 0; i < numata; i++) {
317  ata_device * atadev = get_ata_device(atanames[i], type);
318  if (atadev)
319  devlist.push_back(atadev);
320  }
321  free_devnames(atanames, numata);
322 
323  for (i = 0; i < numscsi; i++) {
324  scsi_device * scsidev = get_scsi_device(scsinames[i], type);
325  if (scsidev)
326  devlist.push_back(scsidev);
327  }
328  free_devnames(scsinames, numscsi);
329  return true;
330 }
331 
332 } // namespace
333 
334 
335 /////////////////////////////////////////////////////////////////////////////
336 /// Initialize platform interface and register with smi()
337 
339 {
340  static os::legacy_smart_interface the_interface;
341  smart_interface::set(&the_interface);
342 }
virtual ata_device * autodetect_sat_device(scsi_device *scsidev, const unsigned char *inqdata, unsigned inqsize)
Try to detect a SAT device behind a SCSI interface.
Definition: scsiata.cpp:1542
virtual smart_device * autodetect_smart_device(const char *name)
Autodetect device if no device type specified.
Definition: dev_legacy.cpp:265
int deviceopen(const char *pathname, char *type)
Definition: os_netbsd.cpp:153
legacy_smart_device(const char *mode)
Definition: dev_legacy.cpp:61
const char * dev_legacy_cpp_cvsid
Definition: dev_legacy.cpp:28
virtual scsi_device * get_scsi_device(const char *name, const char *type)
Return standard SCSI device.
Definition: dev_legacy.cpp:259
static void free_devnames(char **devnames, int numdevs)
Definition: dev_legacy.cpp:276
Adapter class to implement new ATA pass through old interface.
virtual bool close()
Close device, return false on error.
Definition: dev_legacy.cpp:105
virtual bool is_open() const
Return true if device is open.
Definition: dev_legacy.cpp:90
void push_back(smart_device *dev)
#define DEV_INTERFACE_H_CVSID
Definition: dev_interface.h:21
ptr_t data
Definition: megaraid.h:94
List of devices for DEVICESCAN.
static void init()
Initialize platform interface and register with smi().
Definition: dev_legacy.cpp:338
The platform interface abstraction.
void print_smartctl_examples()
Definition: os_netbsd.cpp:410
Implement standard SCSI support with old functions.
Definition: dev_legacy.cpp:144
static void set(smart_interface *intf)
Set interface to use, must be called from init().
virtual smart_device * autodetect_open()
SCSI open with autodetection support.
Definition: dev_legacy.cpp:177
virtual ~legacy_smart_device()
Definition: dev_legacy.cpp:84
unsigned char scsi_debugmode
Definition: scsicmds.cpp:56
virtual int ata_command_interface(smart_command_set command, int select, char *data)
Old ATA interface called by ata_pass_through()
Definition: dev_legacy.cpp:135
const char * m_mode
Mode string for deviceopen().
Definition: dev_legacy.cpp:80
int make_device_names(char ***devlist, const char *name)
Definition: os_netbsd.cpp:142
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
SCSI device access.
int guess_device_type(const char *dev_name)
Definition: os_netbsd.cpp:67
virtual bool scan_smart_devices(smart_device_list &devlist, const char *type, const char *pattern=0)
Fill 'devlist' with devices of some 'type' with device names specified by some optional 'pattern'...
Definition: dev_legacy.cpp:284
smart_command_set
Definition: atacmds.h:48
static int make_device_names(char ***devlist, const char *name)
Definition: os_darwin.cpp:288
Base class for all devices.
Definition: dev_interface.h:38
ATA device access.
virtual ata_device * get_ata_device(const char *name, const char *type)
Return standard ATA device.
Definition: dev_legacy.cpp:254
Implement platform interface with old functions.
Definition: dev_legacy.cpp:227
virtual bool scsi_pass_through(scsi_cmnd_io *iop)
SCSI pass through.
Definition: dev_legacy.cpp:163
virtual bool open()
Open device, return false on error.
Definition: dev_legacy.cpp:95
legacy_ata_device(smart_interface *intf, const char *dev_name, const char *req_type)
Definition: dev_legacy.cpp:129
int scsiStdInquiry(scsi_device *device, UINT8 *pBuf, int bufLen)
Definition: scsicmds.cpp:780
int m_fd
filedesc, -1 if not open.
Definition: dev_legacy.cpp:79
int get_fd() const
Return filedesc for derived classes.
Definition: dev_legacy.cpp:75
virtual std::string get_app_examples(const char *appname)
Return example string for program 'appname'.
Definition: dev_legacy.cpp:247
smart_interface * smi()
Get interface which produced this object.
legacy_scsi_device(smart_interface *intf, const char *dev_name, const char *req_type)
Definition: dev_legacy.cpp:156
const char * get_dev_name() const
Get device (path)name.
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
const char * get_req_type() const
Get type requested by user, empty if none.
int ata_command_interface(int device, smart_command_set command, int select, char *data)
Definition: os_netbsd.cpp:173
int do_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io *iop, int report)
Definition: os_netbsd.cpp:341
Implement standard ATA support with old functions.
Definition: dev_legacy.cpp:118
Implement shared open/close routines with old functions.
Definition: dev_legacy.cpp:57
int deviceclose(int fd)
Definition: os_netbsd.cpp:167