]> git.proxmox.com Git - mirror_smartmontools-debian.git/blob - dev_interface.cpp
Imported Upstream version 5.42+svn3521
[mirror_smartmontools-debian.git] / dev_interface.cpp
1 /*
2 * dev_interface.cpp
3 *
4 * Home page of code is: http://smartmontools.sourceforge.net
5 *
6 * Copyright (C) 2008-12 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 "utility.h"
23
24 #include <errno.h>
25 #include <stdarg.h>
26 #include <stdexcept>
27
28 const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp 3519 2012-03-06 20:01:44Z chrfranke $"
29 DEV_INTERFACE_H_CVSID;
30
31 /////////////////////////////////////////////////////////////////////////////
32 // smart_device
33
34 smart_device::smart_device(smart_interface * intf, const char * dev_name,
35 const char * dev_type, const char * req_type)
36 : m_intf(intf), m_info(dev_name, dev_type, req_type),
37 m_ata_ptr(0), m_scsi_ptr(0)
38 {
39 }
40
41 smart_device::smart_device(do_not_use_in_implementation_classes)
42 : m_intf(0), m_ata_ptr(0), m_scsi_ptr(0)
43 {
44 throw std::logic_error("smart_device: wrong constructor called in implementation class");
45 }
46
47 smart_device::~smart_device() throw()
48 {
49 }
50
51 bool smart_device::set_err(int no, const char * msg, ...)
52 {
53 if (!msg)
54 return set_err(no);
55 m_err.no = no;
56 va_list ap; va_start(ap, msg);
57 m_err.msg = vstrprintf(msg, ap);
58 va_end(ap);
59 return false;
60 }
61
62 bool smart_device::set_err(int no)
63 {
64 return smi()->set_err_var(&m_err, no);
65 }
66
67 smart_device * smart_device::autodetect_open()
68 {
69 open();
70 return this;
71 }
72
73 bool smart_device::owns(const smart_device * /*dev*/) const
74 {
75 return false;
76 }
77
78 void smart_device::release(const smart_device * /*dev*/)
79 {
80 }
81
82
83 /////////////////////////////////////////////////////////////////////////////
84 // ata_device
85
86 ata_in_regs_48bit::ata_in_regs_48bit()
87 : features_16(features, prev.features),
88 sector_count_16(sector_count, prev.sector_count),
89 lba_low_16(lba_low, prev.lba_low),
90 lba_mid_16(lba_mid, prev.lba_mid),
91 lba_high_16(lba_high, prev.lba_high),
92 lba_48( lba_low, lba_mid, lba_high,
93 prev.lba_low, prev.lba_mid, prev.lba_high)
94 {
95 }
96
97 ata_out_regs_48bit::ata_out_regs_48bit()
98 : sector_count_16(sector_count, prev.sector_count),
99 lba_low_16(lba_low, prev.lba_low),
100 lba_mid_16(lba_mid, prev.lba_mid),
101 lba_high_16(lba_high, prev.lba_high),
102 lba_48( lba_low, lba_mid, lba_high,
103 prev.lba_low, prev.lba_mid, prev.lba_high)
104 {
105 }
106
107 ata_cmd_in::ata_cmd_in()
108 : direction(no_data),
109 buffer(0),
110 size(0)
111 {
112 }
113
114 ata_cmd_out::ata_cmd_out()
115 {
116 }
117
118 bool ata_device::ata_pass_through(const ata_cmd_in & in)
119 {
120 ata_cmd_out dummy;
121 return ata_pass_through(in, dummy);
122 }
123
124 bool ata_device::ata_cmd_is_ok(const ata_cmd_in & in,
125 bool data_out_support /*= false*/,
126 bool multi_sector_support /*= false*/,
127 bool ata_48bit_support /*= false*/)
128 {
129 // Check DATA IN/OUT
130 switch (in.direction) {
131 case ata_cmd_in::no_data: break;
132 case ata_cmd_in::data_in: break;
133 case ata_cmd_in::data_out: break;
134 default:
135 return set_err(EINVAL, "Invalid data direction %d", (int)in.direction);
136 }
137
138 // Check buffer size
139 if (in.direction == ata_cmd_in::no_data) {
140 if (in.size)
141 return set_err(EINVAL, "Buffer size %u > 0 for NO DATA command", in.size);
142 }
143 else {
144 if (!in.buffer)
145 return set_err(EINVAL, "Buffer not set for DATA IN/OUT command");
146 unsigned count = (in.in_regs.prev.sector_count<<16)|in.in_regs.sector_count;
147 // TODO: Add check for sector count == 0
148 if (count * 512 != in.size)
149 return set_err(EINVAL, "Sector count %u does not match buffer size %u", count, in.size);
150 }
151
152 // Check features
153 if (in.direction == ata_cmd_in::data_out && !data_out_support)
154 return set_err(ENOSYS, "DATA OUT ATA commands not supported");
155 if (!(in.size == 0 || in.size == 512) && !multi_sector_support)
156 return set_err(ENOSYS, "Multi-sector ATA commands not supported");
157 if (in.in_regs.is_48bit_cmd() && !ata_48bit_support)
158 return set_err(ENOSYS, "48-bit ATA commands not supported");
159 return true;
160 }
161
162 bool ata_device::ata_identify_is_cached() const
163 {
164 return false;
165 }
166
167
168 /////////////////////////////////////////////////////////////////////////////
169 // tunnelled_device_base
170
171 tunnelled_device_base::tunnelled_device_base(smart_device * tunnel_dev)
172 : smart_device(never_called),
173 m_tunnel_base_dev(tunnel_dev)
174 {
175 }
176
177 tunnelled_device_base::~tunnelled_device_base() throw()
178 {
179 delete m_tunnel_base_dev;
180 }
181
182 bool tunnelled_device_base::is_open() const
183 {
184 return (m_tunnel_base_dev && m_tunnel_base_dev->is_open());
185 }
186
187 bool tunnelled_device_base::open()
188 {
189 if (!m_tunnel_base_dev)
190 return set_err(ENOSYS);
191 if (!m_tunnel_base_dev->open())
192 return set_err(m_tunnel_base_dev->get_err());
193 return true;
194 }
195
196 bool tunnelled_device_base::close()
197 {
198 if (!m_tunnel_base_dev)
199 return true;
200 if (!m_tunnel_base_dev->close())
201 return set_err(m_tunnel_base_dev->get_err());
202 return true;
203 }
204
205 bool tunnelled_device_base::owns(const smart_device * dev) const
206 {
207 return (m_tunnel_base_dev && (m_tunnel_base_dev == dev));
208 }
209
210 void tunnelled_device_base::release(const smart_device * dev)
211 {
212 if (m_tunnel_base_dev == dev)
213 m_tunnel_base_dev = 0;
214 }
215
216
217 /////////////////////////////////////////////////////////////////////////////
218 // smart_interface
219
220 // Pointer to (usually singleton) interface object returned by ::smi()
221 smart_interface * smart_interface::s_instance;
222
223 std::string smart_interface::get_os_version_str()
224 {
225 return SMARTMONTOOLS_BUILD_HOST;
226 }
227
228 std::string smart_interface::get_valid_dev_types_str()
229 {
230 // default
231 std::string s =
232 "ata, scsi, sat[,auto][,N][+TYPE], usbcypress[,X], usbjmicron[,x][,N], usbsunplus";
233 // append custom
234 std::string s2 = get_valid_custom_dev_types_str();
235 if (!s2.empty()) {
236 s += ", "; s += s2;
237 }
238 return s;
239 }
240
241 std::string smart_interface::get_app_examples(const char * /*appname*/)
242 {
243 return "";
244 }
245
246 bool smart_interface::disable_system_auto_standby(bool /*disable*/)
247 {
248 return set_err(ENOSYS);
249 }
250
251 bool smart_interface::set_err(int no, const char * msg, ...)
252 {
253 if (!msg)
254 return set_err(no);
255 m_err.no = no;
256 va_list ap; va_start(ap, msg);
257 m_err.msg = vstrprintf(msg, ap);
258 va_end(ap);
259 return false;
260 }
261
262 bool smart_interface::set_err(int no)
263 {
264 return set_err_var(&m_err, no);
265 }
266
267 bool smart_interface::set_err_var(smart_device::error_info * err, int no)
268 {
269 err->no = no;
270 err->msg = get_msg_for_errno(no);
271 if (err->msg.empty() && no != 0)
272 err->msg = strprintf("Unknown error %d", no);
273 return false;
274 }
275
276 const char * smart_interface::get_msg_for_errno(int no)
277 {
278 return strerror(no);
279 }
280
281
282 /////////////////////////////////////////////////////////////////////////////
283 // Default device factory
284
285 smart_device * smart_interface::get_smart_device(const char * name, const char * type)
286 {
287 clear_err();
288
289 // Call platform specific autodetection if no device type specified
290 smart_device * dev;
291 if (!type || !*type) {
292 dev = autodetect_smart_device(name);
293 if (!dev && !get_errno())
294 set_err(EINVAL, "Unable to detect device type");
295 return dev;
296 }
297
298 // First check for platform specific device types
299 dev = get_custom_smart_device(name, type);
300 if (dev || get_errno())
301 return dev;
302
303 if (!strcmp(type, "ata"))
304 dev = get_ata_device(name, type);
305 else if (!strcmp(type, "scsi"))
306 dev = get_scsi_device(name, type);
307
308 else if ( ((!strncmp(type, "sat", 3) && (!type[3] || strchr(",+", type[3])))
309 || (!strncmp(type, "usb", 3)))) {
310 // Split "sat...+base..." -> ("sat...", "base...")
311 unsigned satlen = strcspn(type, "+");
312 std::string sattype(type, satlen);
313 const char * basetype = (type[satlen] ? type+satlen+1 : "");
314 // Recurse to allocate base device, default is standard SCSI
315 if (!*basetype)
316 basetype = "scsi";
317 smart_device_auto_ptr basedev( get_smart_device(name, basetype) );
318 if (!basedev) {
319 set_err(EINVAL, "Type '%s+...': %s", sattype.c_str(), get_errmsg());
320 return 0;
321 }
322 // Result must be SCSI
323 if (!basedev->is_scsi()) {
324 set_err(EINVAL, "Type '%s+...': Device type '%s' is not SCSI", sattype.c_str(), basetype);
325 return 0;
326 }
327 // Attach SAT tunnel
328 ata_device * satdev = get_sat_device(sattype.c_str(), basedev->to_scsi());
329 if (!satdev)
330 return 0;
331 basedev.release();
332 return satdev;
333 }
334
335 else {
336 set_err(EINVAL, "Unknown device type '%s'", type);
337 return 0;
338 }
339 if (!dev && !get_errno())
340 set_err(EINVAL, "Not a device of type '%s'", type);
341 return dev;
342 }
343
344 smart_device * smart_interface::get_custom_smart_device(const char * /*name*/, const char * /*type*/)
345 {
346 return 0;
347 }
348
349 std::string smart_interface::get_valid_custom_dev_types_str()
350 {
351 return "";
352 }