Annotation of embedaddon/smartmontools/dev_legacy.cpp, revision 1.1.1.1
1.1 misho 1: /*
2: * dev_legacy.cpp
3: *
4: * Home page of code is: http://smartmontools.sourceforge.net
5: *
6: * Copyright (C) 2008-11 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 "utility.h"
21: #include "atacmds.h"
22: #include "scsicmds.h"
23: #include "dev_interface.h"
24: #include "dev_ata_cmd_set.h"
25:
26: #include <errno.h>
27:
28: const char * dev_legacy_cpp_cvsid = "$Id: dev_legacy.cpp 3263 2011-02-20 18:32:56Z chrfranke $"
29: DEV_INTERFACE_H_CVSID;
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);
40:
41: // from atacmds.h:
42: int ata_command_interface(int device, smart_command_set command, int select, char *data);
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: {
97: m_fd = ::deviceopen(get_dev_name(), const_cast<char*>(m_mode));
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:
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:
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: {
165: int status = ::do_scsi_cmnd_io(get_fd(), iop, scsi_debugmode);
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)
207: return this;
208:
209: // Use INQUIRY to detect type
210:
211: // SAT or USB ?
212: {
213: smart_device * newdev = smi()->autodetect_sat_device(this, req_buff, len);
214: if (newdev)
215: // NOTE: 'this' is now owned by '*newdev'
216: return newdev;
217: }
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:
231: virtual std::string get_app_examples(const char * appname);
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);
242: };
243:
244:
245: //////////////////////////////////////////////////////////////////////
246:
247: std::string legacy_smart_interface::get_app_examples(const char * appname)
248: {
249: if (!strcmp(appname, "smartctl"))
250: ::print_smartctl_examples(); // this prints to stdout ...
251: return ""; // ... so don't print again.
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: {
278: static const char version[] = "$Id: dev_legacy.cpp 3263 2011-02-20 18:32:56Z chrfranke $";
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;
314: if (!type)
315: type="";
316: for (i = 0; i < numata; i++) {
317: ata_device * atadev = get_ata_device(atanames[i], type);
318: if (atadev)
319: devlist.push_back(atadev);
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)
326: devlist.push_back(scsidev);
327: }
328: free_devnames(scsinames, numscsi);
329: return true;
330: }
331:
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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>