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