]>
Commit | Line | Data |
---|---|---|
2127e193 GI |
1 | /* |
2 | * dev_legacy.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 "utility.h" |
21 | #include "atacmds.h" | |
22 | #include "scsicmds.h" | |
23 | #include "dev_interface.h" | |
24 | #include "dev_ata_cmd_set.h" | |
25 | ||
cfbba5b9 | 26 | #include <errno.h> |
2127e193 | 27 | |
cfbba5b9 GI |
28 | const char * dev_legacy_cpp_cvsid = "$Id: dev_legacy.cpp 3263 2011-02-20 18:32:56Z chrfranke $" |
29 | DEV_INTERFACE_H_CVSID; | |
2127e193 GI |
30 | |
31 | ///////////////////////////////////////////////////////////////////////////// | |
32 | ||
33 | // Legacy interface declarations (now commented out globally): | |
34 | ||
35 | // from utility.h: | |
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); | |
2127e193 GI |
40 | |
41 | // from atacmds.h: | |
42 | int ata_command_interface(int device, smart_command_set command, int select, char *data); | |
2127e193 GI |
43 | |
44 | // from scsicmds.h: | |
45 | int do_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report); | |
46 | ||
47 | // from smartctl.h: | |
48 | void print_smartctl_examples(); | |
49 | ||
50 | ///////////////////////////////////////////////////////////////////////////// | |
51 | ||
52 | namespace os { // No need to publish anything, name provided for Doxygen | |
53 | ||
54 | ///////////////////////////////////////////////////////////////////////////// | |
55 | /// Implement shared open/close routines with old functions. | |
56 | ||
57 | class legacy_smart_device | |
58 | : virtual public /*implements*/ smart_device | |
59 | { | |
60 | public: | |
61 | explicit legacy_smart_device(const char * mode) | |
62 | : smart_device(never_called), | |
63 | m_fd(-1), m_mode(mode) { } | |
64 | ||
65 | virtual ~legacy_smart_device() throw(); | |
66 | ||
67 | virtual bool is_open() const; | |
68 | ||
69 | virtual bool open(); | |
70 | ||
71 | virtual bool close(); | |
72 | ||
73 | protected: | |
74 | /// Return filedesc for derived classes. | |
75 | int get_fd() const | |
76 | { return m_fd; } | |
77 | ||
78 | private: | |
79 | int m_fd; ///< filedesc, -1 if not open. | |
80 | const char * m_mode; ///< Mode string for deviceopen(). | |
81 | }; | |
82 | ||
83 | ||
84 | legacy_smart_device::~legacy_smart_device() throw() | |
85 | { | |
86 | if (m_fd >= 0) | |
87 | ::deviceclose(m_fd); | |
88 | } | |
89 | ||
90 | bool legacy_smart_device::is_open() const | |
91 | { | |
92 | return (m_fd >= 0); | |
93 | } | |
94 | ||
95 | bool legacy_smart_device::open() | |
96 | { | |
cfbba5b9 | 97 | m_fd = ::deviceopen(get_dev_name(), const_cast<char*>(m_mode)); |
2127e193 GI |
98 | if (m_fd < 0) { |
99 | set_err((errno==ENOENT || errno==ENOTDIR) ? ENODEV : errno); | |
100 | return false; | |
101 | } | |
102 | return true; | |
103 | } | |
104 | ||
105 | bool legacy_smart_device::close() | |
106 | { | |
107 | int fd = m_fd; m_fd = -1; | |
108 | if (::deviceclose(fd) < 0) { | |
109 | set_err(errno); | |
110 | return false; | |
111 | } | |
112 | return true; | |
113 | } | |
114 | ||
115 | ///////////////////////////////////////////////////////////////////////////// | |
116 | /// Implement standard ATA support with old functions | |
117 | ||
118 | class legacy_ata_device | |
119 | : public /*implements*/ ata_device_with_command_set, | |
120 | public /*extends*/ legacy_smart_device | |
121 | { | |
122 | public: | |
123 | legacy_ata_device(smart_interface * intf, const char * dev_name, const char * req_type); | |
124 | ||
2127e193 GI |
125 | protected: |
126 | virtual int ata_command_interface(smart_command_set command, int select, char * data); | |
127 | }; | |
128 | ||
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") | |
132 | { | |
133 | } | |
134 | ||
135 | int legacy_ata_device::ata_command_interface(smart_command_set command, int select, char * data) | |
136 | { | |
137 | return ::ata_command_interface(get_fd(), command, select, data); | |
138 | } | |
139 | ||
2127e193 GI |
140 | |
141 | ///////////////////////////////////////////////////////////////////////////// | |
142 | /// Implement standard SCSI support with old functions | |
143 | ||
144 | class legacy_scsi_device | |
145 | : public /*implements*/ scsi_device, | |
146 | public /*extends*/ legacy_smart_device | |
147 | { | |
148 | public: | |
149 | legacy_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type); | |
150 | ||
151 | virtual smart_device * autodetect_open(); | |
152 | ||
153 | virtual bool scsi_pass_through(scsi_cmnd_io * iop); | |
154 | }; | |
155 | ||
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") | |
160 | { | |
161 | } | |
162 | ||
163 | bool legacy_scsi_device::scsi_pass_through(scsi_cmnd_io * iop) | |
164 | { | |
cfbba5b9 | 165 | int status = ::do_scsi_cmnd_io(get_fd(), iop, scsi_debugmode); |
2127e193 GI |
166 | if (status < 0) { |
167 | set_err(-status); | |
168 | return false; | |
169 | } | |
170 | return true; | |
171 | } | |
172 | ||
173 | ||
174 | ///////////////////////////////////////////////////////////////////////////// | |
175 | /// SCSI open with autodetection support | |
176 | ||
177 | smart_device * legacy_scsi_device::autodetect_open() | |
178 | { | |
179 | // Open device | |
180 | if (!open()) | |
181 | return this; | |
182 | ||
183 | // No Autodetection if device type was specified by user | |
184 | if (*get_req_type()) | |
185 | return this; | |
186 | ||
187 | // The code below is based on smartd.cpp:SCSIFilterKnown() | |
188 | ||
189 | // Get INQUIRY | |
190 | unsigned char req_buff[64] = {0, }; | |
191 | int req_len = 36; | |
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 | |
195 | req_len = 64; | |
196 | if (scsiStdInquiry(this, req_buff, req_len)) { | |
197 | // device doesn't like INQUIRY commands | |
198 | close(); | |
199 | set_err(EIO, "INQUIRY failed"); | |
200 | return this; | |
201 | } | |
202 | } | |
203 | ||
204 | int avail_len = req_buff[4] + 5; | |
205 | int len = (avail_len < req_len ? avail_len : req_len); | |
206 | if (len < 36) | |
bed94269 | 207 | return this; |
2127e193 GI |
208 | |
209 | // Use INQUIRY to detect type | |
bed94269 | 210 | |
bed94269 GI |
211 | // SAT or USB ? |
212 | { | |
213 | smart_device * newdev = smi()->autodetect_sat_device(this, req_buff, len); | |
2127e193 GI |
214 | if (newdev) |
215 | // NOTE: 'this' is now owned by '*newdev' | |
216 | return newdev; | |
217 | } | |
2127e193 GI |
218 | |
219 | // Nothing special found | |
220 | return this; | |
221 | } | |
222 | ||
223 | ||
224 | ///////////////////////////////////////////////////////////////////////////// | |
225 | /// Implement platform interface with old functions. | |
226 | ||
227 | class legacy_smart_interface | |
228 | : public /*implements*/ smart_interface | |
229 | { | |
230 | public: | |
54965743 | 231 | virtual std::string get_app_examples(const char * appname); |
2127e193 GI |
232 | |
233 | virtual bool scan_smart_devices(smart_device_list & devlist, const char * type, | |
234 | const char * pattern = 0); | |
235 | ||
236 | protected: | |
237 | virtual ata_device * get_ata_device(const char * name, const char * type); | |
238 | ||
239 | virtual scsi_device * get_scsi_device(const char * name, const char * type); | |
240 | ||
241 | virtual smart_device * autodetect_smart_device(const char * name); | |
2127e193 GI |
242 | }; |
243 | ||
244 | ||
245 | ////////////////////////////////////////////////////////////////////// | |
246 | ||
54965743 | 247 | std::string legacy_smart_interface::get_app_examples(const char * appname) |
2127e193 GI |
248 | { |
249 | if (!strcmp(appname, "smartctl")) | |
250 | ::print_smartctl_examples(); // this prints to stdout ... | |
54965743 | 251 | return ""; // ... so don't print again. |
2127e193 GI |
252 | } |
253 | ||
254 | ata_device * legacy_smart_interface::get_ata_device(const char * name, const char * type) | |
255 | { | |
256 | return new legacy_ata_device(this, name, type); | |
257 | } | |
258 | ||
259 | scsi_device * legacy_smart_interface::get_scsi_device(const char * name, const char * type) | |
260 | { | |
261 | return new legacy_scsi_device(this, name, type); | |
262 | } | |
263 | ||
264 | ||
265 | smart_device * legacy_smart_interface::autodetect_smart_device(const char * name) | |
266 | { | |
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, ""); | |
270 | } | |
271 | // TODO: Test autodetect device here | |
272 | return 0; | |
273 | } | |
274 | ||
275 | ||
276 | static void free_devnames(char * * devnames, int numdevs) | |
277 | { | |
cfbba5b9 | 278 | static const char version[] = "$Id: dev_legacy.cpp 3263 2011-02-20 18:32:56Z chrfranke $"; |
2127e193 GI |
279 | for (int i = 0; i < numdevs; i++) |
280 | FreeNonZero(devnames[i], -1,__LINE__, version); | |
281 | FreeNonZero(devnames, (sizeof (char*) * numdevs),__LINE__, version); | |
282 | } | |
283 | ||
284 | bool legacy_smart_interface::scan_smart_devices(smart_device_list & devlist, | |
285 | const char * type, const char * pattern /*= 0*/) | |
286 | { | |
287 | if (pattern) { | |
288 | set_err(EINVAL, "DEVICESCAN with pattern not implemented yet"); | |
289 | return false; | |
290 | } | |
291 | ||
292 | // Make namelists | |
293 | char * * atanames = 0; int numata = 0; | |
294 | if (!type || !strcmp(type, "ata")) { | |
295 | numata = ::make_device_names(&atanames, "ATA"); | |
296 | if (numata < 0) { | |
297 | set_err(ENOMEM); | |
298 | return false; | |
299 | } | |
300 | } | |
301 | ||
302 | char * * scsinames = 0; int numscsi = 0; | |
303 | if (!type || !strcmp(type, "scsi")) { | |
304 | numscsi = ::make_device_names(&scsinames, "SCSI"); | |
305 | if (numscsi < 0) { | |
306 | free_devnames(atanames, numata); | |
307 | set_err(ENOMEM); | |
308 | return false; | |
309 | } | |
310 | } | |
311 | ||
312 | // Add to devlist | |
313 | int i; | |
cfbba5b9 | 314 | if (!type) |
2127e193 GI |
315 | type=""; |
316 | for (i = 0; i < numata; i++) { | |
317 | ata_device * atadev = get_ata_device(atanames[i], type); | |
318 | if (atadev) | |
bed94269 | 319 | devlist.push_back(atadev); |
2127e193 GI |
320 | } |
321 | free_devnames(atanames, numata); | |
322 | ||
323 | for (i = 0; i < numscsi; i++) { | |
324 | scsi_device * scsidev = get_scsi_device(scsinames[i], type); | |
325 | if (scsidev) | |
bed94269 | 326 | devlist.push_back(scsidev); |
2127e193 GI |
327 | } |
328 | free_devnames(scsinames, numscsi); | |
329 | return true; | |
330 | } | |
331 | ||
2127e193 GI |
332 | } // namespace |
333 | ||
334 | ||
335 | ///////////////////////////////////////////////////////////////////////////// | |
336 | /// Initialize platform interface and register with smi() | |
337 | ||
338 | void smart_interface::init() | |
339 | { | |
340 | static os::legacy_smart_interface the_interface; | |
341 | smart_interface::set(&the_interface); | |
342 | } |