4 * Home page of code is: http://www.smartmontools.org
6 * Copyright (C) 2008-16 Christian Franke
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)
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/>.
23 #include "dev_interface.h"
24 #include "dev_ata_cmd_set.h"
28 const char * dev_legacy_cpp_cvsid
= "$Id: dev_legacy.cpp 4431 2017-08-08 19:38:15Z chrfranke $"
29 DEV_INTERFACE_H_CVSID
;
31 /////////////////////////////////////////////////////////////////////////////
33 // Legacy interface declarations (now commented out globally):
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
);
42 int ata_command_interface(int device
, smart_command_set command
, int select
, char *data
);
45 int do_scsi_cmnd_io(int dev_fd
, struct scsi_cmnd_io
* iop
, int report
);
48 void print_smartctl_examples();
50 /////////////////////////////////////////////////////////////////////////////
52 namespace os
{ // No need to publish anything, name provided for Doxygen
54 /////////////////////////////////////////////////////////////////////////////
55 /// Implement shared open/close routines with old functions.
57 class legacy_smart_device
58 : virtual public /*implements*/ smart_device
61 explicit legacy_smart_device(const char * mode
)
62 : smart_device(never_called
),
63 m_fd(-1), m_mode(mode
) { }
65 virtual ~legacy_smart_device() throw();
67 virtual bool is_open() const;
74 /// Return filedesc for derived classes.
79 int m_fd
; ///< filedesc, -1 if not open.
80 const char * m_mode
; ///< Mode string for deviceopen().
84 legacy_smart_device::~legacy_smart_device() throw()
90 bool legacy_smart_device::is_open() const
95 bool legacy_smart_device::open()
97 m_fd
= ::deviceopen(get_dev_name(), const_cast<char*>(m_mode
));
99 set_err((errno
==ENOENT
|| errno
==ENOTDIR
) ? ENODEV
: errno
);
105 bool legacy_smart_device::close()
107 int fd
= m_fd
; m_fd
= -1;
108 if (::deviceclose(fd
) < 0) {
115 /////////////////////////////////////////////////////////////////////////////
116 /// Implement standard ATA support with old functions
118 class legacy_ata_device
119 : public /*implements*/ ata_device_with_command_set
,
120 public /*extends*/ legacy_smart_device
123 legacy_ata_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
);
126 virtual int ata_command_interface(smart_command_set command
, int select
, char * data
);
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")
135 int legacy_ata_device::ata_command_interface(smart_command_set command
, int select
, char * data
)
137 return ::ata_command_interface(get_fd(), command
, select
, data
);
141 /////////////////////////////////////////////////////////////////////////////
142 /// Implement standard SCSI support with old functions
144 class legacy_scsi_device
145 : public /*implements*/ scsi_device
,
146 public /*extends*/ legacy_smart_device
149 legacy_scsi_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
);
151 virtual smart_device
* autodetect_open();
153 virtual bool scsi_pass_through(scsi_cmnd_io
* iop
);
156 legacy_scsi_device::legacy_scsi_device(smart_interface
* intf
,
157 const char * dev_name
, const char * req_type
)
158 : smart_device(intf
, dev_name
, "scsi", req_type
),
159 legacy_smart_device("SCSI")
163 bool legacy_scsi_device::scsi_pass_through(scsi_cmnd_io
* iop
)
165 int status
= ::do_scsi_cmnd_io(get_fd(), iop
, scsi_debugmode
);
174 /////////////////////////////////////////////////////////////////////////////
175 /// SCSI open with autodetection support
177 smart_device
* legacy_scsi_device::autodetect_open()
183 // No Autodetection if device type was specified by user
187 // The code below is based on smartd.cpp:SCSIFilterKnown()
190 unsigned char req_buff
[64] = {0, };
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
196 if (scsiStdInquiry(this, req_buff
, req_len
)) {
197 // device doesn't like INQUIRY commands
199 set_err(EIO
, "INQUIRY failed");
204 int avail_len
= req_buff
[4] + 5;
205 int len
= (avail_len
< req_len
? avail_len
: req_len
);
209 // Use INQUIRY to detect type
213 smart_device
* newdev
= smi()->autodetect_sat_device(this, req_buff
, len
);
215 // NOTE: 'this' is now owned by '*newdev'
219 // Nothing special found
224 /////////////////////////////////////////////////////////////////////////////
225 /// Implement platform interface with old functions.
227 class legacy_smart_interface
228 : public /*implements*/ smart_interface
231 virtual std::string
get_app_examples(const char * appname
);
233 virtual bool scan_smart_devices(smart_device_list
& devlist
, const char * type
,
234 const char * pattern
= 0);
237 virtual ata_device
* get_ata_device(const char * name
, const char * type
);
239 virtual scsi_device
* get_scsi_device(const char * name
, const char * type
);
241 virtual smart_device
* autodetect_smart_device(const char * name
);
245 //////////////////////////////////////////////////////////////////////
247 std::string
legacy_smart_interface::get_app_examples(const char * appname
)
249 if (!strcmp(appname
, "smartctl"))
250 ::print_smartctl_examples(); // this prints to stdout ...
251 return ""; // ... so don't print again.
254 ata_device
* legacy_smart_interface::get_ata_device(const char * name
, const char * type
)
256 return new legacy_ata_device(this, name
, type
);
259 scsi_device
* legacy_smart_interface::get_scsi_device(const char * name
, const char * type
)
261 return new legacy_scsi_device(this, name
, type
);
265 smart_device
* legacy_smart_interface::autodetect_smart_device(const char * name
)
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
, "");
271 // TODO: Test autodetect device here
276 static void free_devnames(char * * devnames
, int numdevs
)
280 for (int i
= 0; i
< numdevs
; i
++) {
287 bool legacy_smart_interface::scan_smart_devices(smart_device_list
& devlist
,
288 const char * type
, const char * pattern
/*= 0*/)
291 set_err(EINVAL
, "DEVICESCAN with pattern not implemented yet");
296 char * * atanames
= 0; int numata
= 0;
297 if (!type
|| !strcmp(type
, "ata")) {
298 numata
= ::make_device_names(&atanames
, "ATA");
305 char * * scsinames
= 0; int numscsi
= 0;
306 if (!type
|| !strcmp(type
, "scsi")) {
307 numscsi
= ::make_device_names(&scsinames
, "SCSI");
309 free_devnames(atanames
, numata
);
319 for (i
= 0; i
< numata
; i
++) {
320 ata_device
* atadev
= get_ata_device(atanames
[i
], type
);
322 devlist
.push_back(atadev
);
324 free_devnames(atanames
, numata
);
326 for (i
= 0; i
< numscsi
; i
++) {
327 scsi_device
* scsidev
= get_scsi_device(scsinames
[i
], type
);
329 devlist
.push_back(scsidev
);
331 free_devnames(scsinames
, numscsi
);
338 /////////////////////////////////////////////////////////////////////////////
339 /// Initialize platform interface and register with smi()
341 void smart_interface::init()
343 static os::legacy_smart_interface the_interface
;
344 smart_interface::set(&the_interface
);