4 * Home page of code is: http://smartmontools.sourceforge.net
6 * Copyright (C) 2008 Christian Franke <smartmontools-support@lists.sourceforge.net>
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/>.
22 #include "dev_interface.h"
23 #include "dev_tunnelled.h"
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
;
31 /////////////////////////////////////////////////////////////////////////////
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)
41 smart_device::smart_device(do_not_use_in_implementation_classes
)
42 : m_intf(0), m_ata_ptr(0), m_scsi_ptr(0)
44 throw std::logic_error("smart_device: wrong constructor called in implementation class");
47 smart_device::~smart_device() throw()
51 bool smart_device::set_err(int no
, const char * msg
, ...)
56 va_list ap
; va_start(ap
, msg
);
57 m_err
.msg
= vstrprintf(msg
, ap
);
62 bool smart_device::set_err(int no
)
64 smi()->set_err_var(&m_err
, no
);
68 smart_device
* smart_device::autodetect_open()
74 bool smart_device::owns(const smart_device
* /*dev*/) const
79 void smart_device::release(const smart_device
* /*dev*/)
84 /////////////////////////////////////////////////////////////////////////////
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
)
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
)
104 ata_cmd_in::ata_cmd_in()
105 : direction(no_data
),
111 ata_cmd_out::ata_cmd_out()
115 bool ata_device::ata_pass_through(const ata_cmd_in
& in
)
118 return ata_pass_through(in
, dummy
);
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*/)
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;
132 return set_err(EINVAL
, "Invalid data direction %d", (int)in
.direction
);
136 if (in
.direction
== ata_cmd_in::no_data
) {
138 return set_err(EINVAL
, "Buffer size %u > 0 for NO DATA command", in
.size
);
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
);
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");
159 bool ata_device::ata_identify_is_cached() const
165 /////////////////////////////////////////////////////////////////////////////
166 // tunnelled_device_base
168 tunnelled_device_base::tunnelled_device_base(smart_device
* tunnel_dev
)
169 : smart_device(never_called
),
170 m_tunnel_base_dev(tunnel_dev
)
174 tunnelled_device_base::~tunnelled_device_base() throw()
176 delete m_tunnel_base_dev
;
179 bool tunnelled_device_base::is_open() const
181 return (m_tunnel_base_dev
&& m_tunnel_base_dev
->is_open());
184 bool tunnelled_device_base::open()
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());
193 bool tunnelled_device_base::close()
195 if (!m_tunnel_base_dev
)
197 if (!m_tunnel_base_dev
->close())
198 return set_err(m_tunnel_base_dev
->get_err());
202 bool tunnelled_device_base::owns(const smart_device
* dev
) const
204 return (m_tunnel_base_dev
&& (m_tunnel_base_dev
== dev
));
207 void tunnelled_device_base::release(const smart_device
* dev
)
209 if (m_tunnel_base_dev
== dev
)
210 m_tunnel_base_dev
= 0;
214 /////////////////////////////////////////////////////////////////////////////
217 // Pointer to (usually singleton) interface object returned by ::smi()
218 smart_interface
* smart_interface::s_instance
;
220 const char * smart_interface::get_os_version_str()
222 return SMARTMONTOOLS_BUILD_HOST
;
225 const char * smart_interface::get_valid_dev_types_str()
227 static std::string buf
;
231 buf
= "ata, scsi, sat[,N][+TYPE]";
233 const char * add
= get_valid_custom_dev_types_str();
236 buf
+= ", "; buf
+= add
;
240 const char * smart_interface::get_app_examples(const char * /*appname*/)
245 void smart_interface::set_err(int no
, const char * msg
, ...)
251 va_list ap
; va_start(ap
, msg
);
252 m_err
.msg
= vstrprintf(msg
, ap
);
256 void smart_interface::set_err(int no
)
258 set_err_var(&m_err
, no
);
261 void smart_interface::set_err_var(smart_device::error_info
* err
, int no
)
264 err
->msg
= get_msg_for_errno(no
);
265 if (err
->msg
.empty() && no
!= 0)
266 err
->msg
= strprintf("Unknown error %d", no
);
269 const char * smart_interface::get_msg_for_errno(int no
)
275 /////////////////////////////////////////////////////////////////////////////
276 // Default device factory
278 smart_device
* smart_interface::get_smart_device(const char * name
, const char * type
)
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");
288 smart_device
* dev
= get_custom_smart_device(name
, type
);
289 if (dev
|| get_errno())
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
);
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
306 dev
= get_smart_device(name
, basetype
);
308 set_err(EINVAL
, "Type '%s+...': %s", sattype
.c_str(), get_errmsg());
311 // Result must be SCSI
312 if (!dev
->is_scsi()) {
314 set_err(EINVAL
, "Type '%s+...': Device type '%s' is not SCSI", sattype
.c_str(), basetype
);
319 ata_device
* satdev
= get_sat_device(sattype
.c_str(), dev
->to_scsi());
332 set_err(EINVAL
, "Unknown device type '%s'", type
);
335 if (!dev
&& !get_errno())
336 set_err(EINVAL
, "Not a device of type '%s'", type
);
340 smart_device
* smart_interface::get_custom_smart_device(const char * /*name*/, const char * /*type*/)
345 const char * smart_interface::get_valid_custom_dev_types_str()