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