]>
Commit | Line | Data |
---|---|---|
2127e193 GI |
1 | /* |
2 | * dev_legacy.cpp | |
3 | * | |
4 | * Home page of code is: http://smartmontools.sourceforge.net | |
5 | * | |
e9583e0c | 6 | * Copyright (C) 2008-10 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" | |
20 | #include "extern.h" | |
21 | #include "utility.h" | |
22 | #include "atacmds.h" | |
23 | #include "scsicmds.h" | |
24 | #include "dev_interface.h" | |
25 | #include "dev_ata_cmd_set.h" | |
26 | ||
e9583e0c | 27 | const char * dev_legacy_cpp_cvsid = "$Id: dev_legacy.cpp 3098 2010-04-30 17:35:35Z chrfranke $" |
2127e193 GI |
28 | DEV_INTERFACE_H_CVSID; |
29 | ||
30 | extern smartmonctrl * con; // con->reportscsiioctl | |
31 | ||
32 | ///////////////////////////////////////////////////////////////////////////// | |
33 | ||
34 | // Legacy interface declarations (now commented out globally): | |
35 | ||
36 | // from utility.h: | |
37 | int guess_device_type(const char * dev_name); | |
38 | int make_device_names (char ***devlist, const char* name); | |
39 | int deviceopen(const char *pathname, char *type); | |
40 | int deviceclose(int fd); | |
41 | #ifdef HAVE_GET_OS_VERSION_STR | |
42 | const char * get_os_version_str(void); | |
43 | #endif | |
44 | ||
45 | // from atacmds.h: | |
46 | int ata_command_interface(int device, smart_command_set command, int select, char *data); | |
47 | int escalade_command_interface(int fd, int escalade_port, int escalade_type, smart_command_set command, int select, char *data); | |
48 | int marvell_command_interface(int device, smart_command_set command, int select, char *data); | |
49 | int highpoint_command_interface(int device, smart_command_set command, int select, char *data); | |
50 | int areca_command_interface(int fd, int disknum, smart_command_set command, int select, char *data); | |
51 | #ifdef HAVE_ATA_IDENTIFY_IS_CACHED | |
52 | int ata_identify_is_cached(int fd); | |
53 | #endif | |
54 | ||
55 | // from scsicmds.h: | |
56 | int do_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report); | |
57 | ||
58 | // from smartctl.h: | |
59 | void print_smartctl_examples(); | |
60 | ||
61 | ///////////////////////////////////////////////////////////////////////////// | |
62 | ||
63 | namespace os { // No need to publish anything, name provided for Doxygen | |
64 | ||
65 | ///////////////////////////////////////////////////////////////////////////// | |
66 | /// Implement shared open/close routines with old functions. | |
67 | ||
68 | class legacy_smart_device | |
69 | : virtual public /*implements*/ smart_device | |
70 | { | |
71 | public: | |
72 | explicit legacy_smart_device(const char * mode) | |
73 | : smart_device(never_called), | |
74 | m_fd(-1), m_mode(mode) { } | |
75 | ||
76 | virtual ~legacy_smart_device() throw(); | |
77 | ||
78 | virtual bool is_open() const; | |
79 | ||
80 | virtual bool open(); | |
81 | ||
82 | virtual bool close(); | |
83 | ||
84 | protected: | |
85 | /// Return filedesc for derived classes. | |
86 | int get_fd() const | |
87 | { return m_fd; } | |
88 | ||
89 | private: | |
90 | int m_fd; ///< filedesc, -1 if not open. | |
91 | const char * m_mode; ///< Mode string for deviceopen(). | |
92 | }; | |
93 | ||
94 | ||
95 | legacy_smart_device::~legacy_smart_device() throw() | |
96 | { | |
97 | if (m_fd >= 0) | |
98 | ::deviceclose(m_fd); | |
99 | } | |
100 | ||
101 | bool legacy_smart_device::is_open() const | |
102 | { | |
103 | return (m_fd >= 0); | |
104 | } | |
105 | ||
106 | bool legacy_smart_device::open() | |
107 | { | |
108 | m_fd = ::deviceopen(get_dev_name(), (char*)m_mode); | |
109 | if (m_fd < 0) { | |
110 | set_err((errno==ENOENT || errno==ENOTDIR) ? ENODEV : errno); | |
111 | return false; | |
112 | } | |
113 | return true; | |
114 | } | |
115 | ||
116 | bool legacy_smart_device::close() | |
117 | { | |
118 | int fd = m_fd; m_fd = -1; | |
119 | if (::deviceclose(fd) < 0) { | |
120 | set_err(errno); | |
121 | return false; | |
122 | } | |
123 | return true; | |
124 | } | |
125 | ||
126 | ///////////////////////////////////////////////////////////////////////////// | |
127 | /// Implement standard ATA support with old functions | |
128 | ||
129 | class legacy_ata_device | |
130 | : public /*implements*/ ata_device_with_command_set, | |
131 | public /*extends*/ legacy_smart_device | |
132 | { | |
133 | public: | |
134 | legacy_ata_device(smart_interface * intf, const char * dev_name, const char * req_type); | |
135 | ||
136 | #ifdef HAVE_ATA_IDENTIFY_IS_CACHED | |
137 | virtual bool ata_identify_is_cached() const; | |
138 | #endif | |
139 | ||
140 | protected: | |
141 | virtual int ata_command_interface(smart_command_set command, int select, char * data); | |
142 | }; | |
143 | ||
144 | legacy_ata_device::legacy_ata_device(smart_interface * intf, const char * dev_name, const char * req_type) | |
145 | : smart_device(intf, dev_name, "ata", req_type), | |
146 | legacy_smart_device("ATA") | |
147 | { | |
148 | } | |
149 | ||
150 | int legacy_ata_device::ata_command_interface(smart_command_set command, int select, char * data) | |
151 | { | |
152 | return ::ata_command_interface(get_fd(), command, select, data); | |
153 | } | |
154 | ||
155 | #ifdef HAVE_ATA_IDENTIFY_IS_CACHED | |
156 | bool legacy_ata_device::ata_identify_is_cached() const | |
157 | { | |
158 | return !!::ata_identify_is_cached(get_fd()); | |
159 | } | |
160 | #endif | |
161 | ||
162 | ||
163 | ///////////////////////////////////////////////////////////////////////////// | |
164 | /// Implement AMCC/3ware RAID support with old functions | |
165 | ||
166 | class legacy_escalade_device | |
167 | : public /*implements*/ ata_device_with_command_set, | |
168 | public /*extends*/ legacy_smart_device | |
169 | { | |
170 | public: | |
171 | legacy_escalade_device(smart_interface * intf, const char * dev_name, | |
172 | int escalade_type, int disknum); | |
173 | ||
174 | protected: | |
175 | virtual int ata_command_interface(smart_command_set command, int select, char * data); | |
176 | ||
177 | private: | |
178 | int m_escalade_type; ///< Type string for escalade_command_interface(). | |
179 | int m_disknum; ///< Disk number. | |
180 | }; | |
181 | ||
182 | legacy_escalade_device::legacy_escalade_device(smart_interface * intf, const char * dev_name, | |
183 | int escalade_type, int disknum) | |
184 | : smart_device(intf, dev_name, "3ware", "3ware"), | |
185 | legacy_smart_device( | |
186 | escalade_type==CONTROLLER_3WARE_9000_CHAR ? "ATA_3WARE_9000" : | |
187 | escalade_type==CONTROLLER_3WARE_678K_CHAR ? "ATA_3WARE_678K" : | |
188 | /* CONTROLLER_3WARE_678K */ "ATA" ), | |
189 | m_escalade_type(escalade_type), m_disknum(disknum) | |
190 | { | |
191 | set_info().info_name = strprintf("%s [3ware_disk_%02d]", dev_name, disknum); | |
192 | } | |
193 | ||
194 | int legacy_escalade_device::ata_command_interface(smart_command_set command, int select, char * data) | |
195 | { | |
196 | return ::escalade_command_interface(get_fd(), m_disknum, m_escalade_type, command, select, data); | |
197 | } | |
198 | ||
199 | ||
200 | ///////////////////////////////////////////////////////////////////////////// | |
201 | /// Implement Areca RAID support with old functions | |
202 | ||
203 | class legacy_areca_device | |
204 | : public /*implements*/ ata_device_with_command_set, | |
205 | public /*extends*/ legacy_smart_device | |
206 | { | |
207 | public: | |
208 | legacy_areca_device(smart_interface * intf, const char * dev_name, int disknum); | |
209 | ||
210 | protected: | |
211 | virtual int ata_command_interface(smart_command_set command, int select, char * data); | |
212 | ||
213 | private: | |
214 | int m_disknum; ///< Disk number. | |
215 | }; | |
216 | ||
217 | legacy_areca_device::legacy_areca_device(smart_interface * intf, const char * dev_name, int disknum) | |
218 | : smart_device(intf, dev_name, "areca", "areca"), | |
219 | legacy_smart_device("ATA_ARECA"), | |
220 | m_disknum(disknum) | |
221 | { | |
222 | set_info().info_name = strprintf("%s [areca_%02d]", dev_name, disknum); | |
223 | } | |
224 | ||
225 | int legacy_areca_device::ata_command_interface(smart_command_set command, int select, char * data) | |
226 | { | |
227 | return ::areca_command_interface(get_fd(), m_disknum, command, select, data); | |
228 | } | |
229 | ||
230 | ||
231 | ///////////////////////////////////////////////////////////////////////////// | |
232 | /// Implement Marvell support with old functions | |
233 | ||
234 | class legacy_marvell_device | |
235 | : public /*implements*/ ata_device_with_command_set, | |
236 | public /*extends*/ legacy_smart_device | |
237 | { | |
238 | public: | |
239 | legacy_marvell_device(smart_interface * intf, const char * dev_name, const char * req_type); | |
240 | ||
241 | protected: | |
242 | virtual int ata_command_interface(smart_command_set command, int select, char * data); | |
243 | }; | |
244 | ||
245 | ||
246 | legacy_marvell_device::legacy_marvell_device(smart_interface * intf, | |
247 | const char * dev_name, const char * req_type) | |
248 | : smart_device(intf, dev_name, "marvell", req_type), | |
249 | legacy_smart_device("ATA") | |
250 | { | |
251 | } | |
252 | ||
253 | int legacy_marvell_device::ata_command_interface(smart_command_set command, int select, char * data) | |
254 | { | |
255 | return ::marvell_command_interface(get_fd(), command, select, data); | |
256 | } | |
257 | ||
258 | ||
259 | ///////////////////////////////////////////////////////////////////////////// | |
260 | /// Implement Highpoint RAID support with old functions | |
261 | ||
262 | class legacy_highpoint_device | |
263 | : public /*implements*/ ata_device_with_command_set, | |
264 | public /*extends*/ legacy_smart_device | |
265 | { | |
266 | public: | |
267 | legacy_highpoint_device(smart_interface * intf, const char * dev_name, | |
268 | unsigned char controller, unsigned char channel, unsigned char port); | |
269 | ||
270 | protected: | |
271 | virtual int ata_command_interface(smart_command_set command, int select, char * data); | |
272 | ||
273 | private: | |
274 | unsigned char m_hpt_data[3]; ///< controller/channel/port | |
275 | }; | |
276 | ||
277 | ||
278 | legacy_highpoint_device::legacy_highpoint_device(smart_interface * intf, const char * dev_name, | |
279 | unsigned char controller, unsigned char channel, unsigned char port) | |
280 | : smart_device(intf, dev_name, "hpt", "hpt"), | |
281 | legacy_smart_device("ATA") | |
282 | { | |
283 | m_hpt_data[0] = controller; m_hpt_data[1] = channel; m_hpt_data[2] = port; | |
284 | set_info().info_name = strprintf("%s [hpt_disk_%u/%u/%u]", dev_name, m_hpt_data[0], m_hpt_data[1], m_hpt_data[2]); | |
285 | } | |
286 | ||
287 | int legacy_highpoint_device::ata_command_interface(smart_command_set command, int select, char * data) | |
288 | { | |
289 | unsigned char old_hpt_data[3]; | |
290 | memcpy(old_hpt_data, con->hpt_data, 3); | |
291 | memcpy(con->hpt_data, m_hpt_data, 3); | |
292 | int status = ::highpoint_command_interface(get_fd(), command, select, data); | |
293 | memcpy(con->hpt_data, old_hpt_data, 3); | |
294 | return status; | |
295 | } | |
296 | ||
297 | ||
298 | ///////////////////////////////////////////////////////////////////////////// | |
299 | /// Implement standard SCSI support with old functions | |
300 | ||
301 | class legacy_scsi_device | |
302 | : public /*implements*/ scsi_device, | |
303 | public /*extends*/ legacy_smart_device | |
304 | { | |
305 | public: | |
306 | legacy_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type); | |
307 | ||
308 | virtual smart_device * autodetect_open(); | |
309 | ||
310 | virtual bool scsi_pass_through(scsi_cmnd_io * iop); | |
311 | }; | |
312 | ||
313 | legacy_scsi_device::legacy_scsi_device(smart_interface * intf, | |
314 | const char * dev_name, const char * req_type) | |
315 | : smart_device(intf, dev_name, "scsi", req_type), | |
316 | legacy_smart_device("SCSI") | |
317 | { | |
318 | } | |
319 | ||
320 | bool legacy_scsi_device::scsi_pass_through(scsi_cmnd_io * iop) | |
321 | { | |
322 | unsigned char oldtype = con->controller_type, oldport = con->controller_port; | |
323 | con->controller_type = CONTROLLER_SCSI; con->controller_port = 0; | |
324 | int status = ::do_scsi_cmnd_io(get_fd(), iop, con->reportscsiioctl); | |
325 | con->controller_type = oldtype; con->controller_port = oldport; | |
326 | if (status < 0) { | |
327 | set_err(-status); | |
328 | return false; | |
329 | } | |
330 | return true; | |
331 | } | |
332 | ||
333 | ||
334 | ///////////////////////////////////////////////////////////////////////////// | |
335 | /// Implement CCISS RAID support with old functions | |
336 | ||
337 | class legacy_cciss_device | |
338 | : public /*implements*/ scsi_device, | |
339 | public /*extends*/ legacy_smart_device | |
340 | { | |
341 | public: | |
342 | legacy_cciss_device(smart_interface * intf, const char * name, unsigned char disknum); | |
343 | ||
344 | virtual bool scsi_pass_through(scsi_cmnd_io * iop); | |
345 | ||
346 | private: | |
347 | unsigned char m_disknum; ///< Disk number. | |
348 | }; | |
349 | ||
350 | ||
351 | legacy_cciss_device::legacy_cciss_device(smart_interface * intf, | |
352 | const char * dev_name, unsigned char disknum) | |
353 | : smart_device(intf, dev_name, "cciss", "cciss"), | |
354 | legacy_smart_device("SCSI"), | |
355 | m_disknum(disknum) | |
356 | { | |
357 | set_info().info_name = strprintf("%s [cciss_disk_%02d]", dev_name, disknum); | |
358 | } | |
359 | ||
360 | bool legacy_cciss_device::scsi_pass_through(scsi_cmnd_io * iop) | |
361 | { | |
362 | // See os_linux.cpp | |
363 | unsigned char oldtype = con->controller_type, oldport = con->controller_port; | |
364 | con->controller_type = CONTROLLER_CCISS; con->controller_port = m_disknum+1; | |
365 | int status = ::do_scsi_cmnd_io(get_fd(), iop, con->reportscsiioctl); | |
366 | con->controller_type = oldtype; con->controller_port = oldport; | |
367 | if (status < 0) { | |
368 | set_err(-status); | |
369 | return false; | |
370 | } | |
371 | return true; | |
372 | } | |
373 | ||
374 | ||
375 | ///////////////////////////////////////////////////////////////////////////// | |
376 | /// SCSI open with autodetection support | |
377 | ||
378 | smart_device * legacy_scsi_device::autodetect_open() | |
379 | { | |
380 | // Open device | |
381 | if (!open()) | |
382 | return this; | |
383 | ||
384 | // No Autodetection if device type was specified by user | |
385 | if (*get_req_type()) | |
386 | return this; | |
387 | ||
388 | // The code below is based on smartd.cpp:SCSIFilterKnown() | |
389 | ||
390 | // Get INQUIRY | |
391 | unsigned char req_buff[64] = {0, }; | |
392 | int req_len = 36; | |
393 | if (scsiStdInquiry(this, req_buff, req_len)) { | |
394 | // Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices | |
395 | // watch this spot ... other devices could lock up here | |
396 | req_len = 64; | |
397 | if (scsiStdInquiry(this, req_buff, req_len)) { | |
398 | // device doesn't like INQUIRY commands | |
399 | close(); | |
400 | set_err(EIO, "INQUIRY failed"); | |
401 | return this; | |
402 | } | |
403 | } | |
404 | ||
405 | int avail_len = req_buff[4] + 5; | |
406 | int len = (avail_len < req_len ? avail_len : req_len); | |
407 | if (len < 36) | |
bed94269 | 408 | return this; |
2127e193 GI |
409 | |
410 | // Use INQUIRY to detect type | |
bed94269 GI |
411 | |
412 | // 3ware ? | |
413 | if (!memcmp(req_buff + 8, "3ware", 5) || !memcmp(req_buff + 8, "AMCC", 4)) { | |
414 | close(); | |
2127e193 | 415 | #if defined(_WIN32) || defined(__CYGWIN__) |
bed94269 | 416 | set_err(EINVAL, "AMCC/3ware controller, please try changing device to %s,N", get_dev_name()); |
2127e193 | 417 | #else |
bed94269 GI |
418 | set_err(EINVAL, "AMCC/3ware controller, please try adding '-d 3ware,N',\n" |
419 | "you may need to replace %s with /dev/twaN or /dev/tweN", get_dev_name()); | |
2127e193 | 420 | #endif |
bed94269 GI |
421 | return this; |
422 | } | |
2127e193 | 423 | |
bed94269 GI |
424 | // Marvell ? |
425 | if (len >= 42 && !memcmp(req_buff + 36, "MVSATA", 6)) { // TODO: Linux-specific? | |
426 | //pout("Device %s: using '-d marvell' for ATA disk with Marvell driver\n", get_dev_name()); | |
427 | close(); | |
428 | smart_device_auto_ptr newdev( | |
429 | new legacy_marvell_device(smi(), get_dev_name(), get_req_type()), | |
430 | this | |
431 | ); | |
432 | newdev->open(); // TODO: Can possibly pass open fd | |
433 | delete this; | |
434 | return newdev.release(); | |
435 | } | |
2127e193 | 436 | |
bed94269 GI |
437 | // SAT or USB ? |
438 | { | |
439 | smart_device * newdev = smi()->autodetect_sat_device(this, req_buff, len); | |
2127e193 GI |
440 | if (newdev) |
441 | // NOTE: 'this' is now owned by '*newdev' | |
442 | return newdev; | |
443 | } | |
2127e193 GI |
444 | |
445 | // Nothing special found | |
446 | return this; | |
447 | } | |
448 | ||
449 | ||
450 | ///////////////////////////////////////////////////////////////////////////// | |
451 | /// Implement platform interface with old functions. | |
452 | ||
453 | class legacy_smart_interface | |
454 | : public /*implements*/ smart_interface | |
455 | { | |
456 | public: | |
457 | #ifdef HAVE_GET_OS_VERSION_STR | |
54965743 | 458 | virtual std::string get_os_version_str(); |
2127e193 GI |
459 | #endif |
460 | ||
54965743 | 461 | virtual std::string get_app_examples(const char * appname); |
2127e193 GI |
462 | |
463 | virtual bool scan_smart_devices(smart_device_list & devlist, const char * type, | |
464 | const char * pattern = 0); | |
465 | ||
466 | protected: | |
467 | virtual ata_device * get_ata_device(const char * name, const char * type); | |
468 | ||
469 | virtual scsi_device * get_scsi_device(const char * name, const char * type); | |
470 | ||
471 | virtual smart_device * autodetect_smart_device(const char * name); | |
472 | ||
473 | virtual smart_device * get_custom_smart_device(const char * name, const char * type); | |
474 | ||
54965743 | 475 | virtual std::string get_valid_custom_dev_types_str(); |
2127e193 GI |
476 | }; |
477 | ||
478 | ||
479 | ////////////////////////////////////////////////////////////////////// | |
480 | ||
481 | #ifdef HAVE_GET_OS_VERSION_STR | |
54965743 | 482 | std::string legacy_smart_interface::get_os_version_str() |
2127e193 GI |
483 | { |
484 | return ::get_os_version_str(); | |
485 | } | |
486 | #endif | |
487 | ||
54965743 | 488 | std::string legacy_smart_interface::get_app_examples(const char * appname) |
2127e193 GI |
489 | { |
490 | if (!strcmp(appname, "smartctl")) | |
491 | ::print_smartctl_examples(); // this prints to stdout ... | |
54965743 | 492 | return ""; // ... so don't print again. |
2127e193 GI |
493 | } |
494 | ||
495 | ata_device * legacy_smart_interface::get_ata_device(const char * name, const char * type) | |
496 | { | |
497 | return new legacy_ata_device(this, name, type); | |
498 | } | |
499 | ||
500 | scsi_device * legacy_smart_interface::get_scsi_device(const char * name, const char * type) | |
501 | { | |
502 | return new legacy_scsi_device(this, name, type); | |
503 | } | |
504 | ||
505 | ||
506 | smart_device * legacy_smart_interface::autodetect_smart_device(const char * name) | |
507 | { | |
508 | switch (::guess_device_type(name)) { | |
509 | case CONTROLLER_ATA : return new legacy_ata_device(this, name, ""); | |
510 | case CONTROLLER_SCSI: return new legacy_scsi_device(this, name, ""); | |
511 | } | |
512 | // TODO: Test autodetect device here | |
513 | return 0; | |
514 | } | |
515 | ||
516 | ||
517 | static void free_devnames(char * * devnames, int numdevs) | |
518 | { | |
e9583e0c | 519 | static const char version[] = "$Id: dev_legacy.cpp 3098 2010-04-30 17:35:35Z chrfranke $"; |
2127e193 GI |
520 | for (int i = 0; i < numdevs; i++) |
521 | FreeNonZero(devnames[i], -1,__LINE__, version); | |
522 | FreeNonZero(devnames, (sizeof (char*) * numdevs),__LINE__, version); | |
523 | } | |
524 | ||
525 | bool legacy_smart_interface::scan_smart_devices(smart_device_list & devlist, | |
526 | const char * type, const char * pattern /*= 0*/) | |
527 | { | |
528 | if (pattern) { | |
529 | set_err(EINVAL, "DEVICESCAN with pattern not implemented yet"); | |
530 | return false; | |
531 | } | |
532 | ||
533 | // Make namelists | |
534 | char * * atanames = 0; int numata = 0; | |
535 | if (!type || !strcmp(type, "ata")) { | |
536 | numata = ::make_device_names(&atanames, "ATA"); | |
537 | if (numata < 0) { | |
538 | set_err(ENOMEM); | |
539 | return false; | |
540 | } | |
541 | } | |
542 | ||
543 | char * * scsinames = 0; int numscsi = 0; | |
544 | if (!type || !strcmp(type, "scsi")) { | |
545 | numscsi = ::make_device_names(&scsinames, "SCSI"); | |
546 | if (numscsi < 0) { | |
547 | free_devnames(atanames, numata); | |
548 | set_err(ENOMEM); | |
549 | return false; | |
550 | } | |
551 | } | |
552 | ||
553 | // Add to devlist | |
554 | int i; | |
555 | if (type==NULL) | |
556 | type=""; | |
557 | for (i = 0; i < numata; i++) { | |
558 | ata_device * atadev = get_ata_device(atanames[i], type); | |
559 | if (atadev) | |
bed94269 | 560 | devlist.push_back(atadev); |
2127e193 GI |
561 | } |
562 | free_devnames(atanames, numata); | |
563 | ||
564 | for (i = 0; i < numscsi; i++) { | |
565 | scsi_device * scsidev = get_scsi_device(scsinames[i], type); | |
566 | if (scsidev) | |
bed94269 | 567 | devlist.push_back(scsidev); |
2127e193 GI |
568 | } |
569 | free_devnames(scsinames, numscsi); | |
570 | return true; | |
571 | } | |
572 | ||
573 | ||
574 | smart_device * legacy_smart_interface::get_custom_smart_device(const char * name, const char * type) | |
575 | { | |
576 | // Marvell ? | |
577 | if (!strcmp(type, "marvell")) | |
578 | return new legacy_marvell_device(this, name, type); | |
579 | ||
580 | // 3Ware ? | |
581 | int disknum = -1, n1 = -1, n2 = -1; | |
582 | if (sscanf(type, "3ware,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) { | |
583 | if (n2 != (int)strlen(type)) { | |
584 | set_err(EINVAL, "Option -d 3ware,N requires N to be a non-negative integer"); | |
585 | return 0; | |
586 | } | |
587 | if (!(0 <= disknum && disknum <= 127)) { | |
588 | set_err(EINVAL, "Option -d 3ware,N (N=%d) must have 0 <= N <= 127", disknum); | |
589 | return 0; | |
590 | } | |
591 | int contr = ::guess_device_type(name); | |
592 | if (contr != CONTROLLER_3WARE_9000_CHAR && contr != CONTROLLER_3WARE_678K_CHAR) | |
593 | contr = CONTROLLER_3WARE_678K; | |
594 | return new legacy_escalade_device(this, name, contr, disknum); | |
595 | } | |
596 | ||
597 | // Areca? | |
598 | disknum = n1 = n2 = -1; | |
599 | if (sscanf(type, "areca,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) { | |
600 | if (n2 != (int)strlen(type)) { | |
601 | set_err(EINVAL, "Option -d areca,N requires N to be a non-negative integer"); | |
602 | return 0; | |
603 | } | |
604 | if (!(1 <= disknum && disknum <= 24)) { | |
605 | set_err(EINVAL, "Option -d areca,N (N=%d) must have 1 <= N <= 24", disknum); | |
606 | return 0; | |
607 | } | |
608 | return new legacy_areca_device(this, name, disknum); | |
609 | } | |
610 | ||
611 | // Highpoint ? | |
612 | int controller = -1, channel = -1; disknum = 1; | |
613 | n1 = n2 = -1; int n3 = -1; | |
614 | if (sscanf(type, "hpt,%n%d/%d%n/%d%n", &n1, &controller, &channel, &n2, &disknum, &n3) >= 2 || n1 == 4) { | |
615 | int len = strlen(type); | |
616 | if (!(n2 == len || n3 == len)) { | |
617 | set_err(EINVAL, "Option '-d hpt,L/M/N' supports 2-3 items"); | |
618 | return 0; | |
619 | } | |
620 | if (!(1 <= controller && controller <= 8)) { | |
621 | set_err(EINVAL, "Option '-d hpt,L/M/N' invalid controller id L supplied"); | |
622 | return 0; | |
623 | } | |
624 | if (!(1 <= channel && channel <= 8)) { | |
625 | set_err(EINVAL, "Option '-d hpt,L/M/N' invalid channel number M supplied"); | |
626 | return 0; | |
627 | } | |
628 | if (!(1 <= disknum && disknum <= 15)) { | |
629 | set_err(EINVAL, "Option '-d hpt,L/M/N' invalid pmport number N supplied"); | |
630 | return 0; | |
631 | } | |
632 | return new legacy_highpoint_device(this, name, controller, channel, disknum); | |
633 | } | |
634 | ||
635 | // CCISS ? | |
636 | disknum = n1 = n2 = -1; | |
637 | if (sscanf(type, "cciss,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) { | |
638 | if (n2 != (int)strlen(type)) { | |
639 | set_err(EINVAL, "Option -d cciss,N requires N to be a non-negative integer"); | |
640 | return 0; | |
641 | } | |
e9583e0c GI |
642 | if (!(0 <= disknum && disknum <= 127)) { |
643 | set_err(EINVAL, "Option -d cciss,N (N=%d) must have 0 <= N <= 127", disknum); | |
2127e193 GI |
644 | return 0; |
645 | } | |
646 | return new legacy_cciss_device(this, name, disknum); | |
647 | } | |
648 | ||
649 | return 0; | |
650 | } | |
651 | ||
54965743 | 652 | std::string legacy_smart_interface::get_valid_custom_dev_types_str() |
2127e193 GI |
653 | { |
654 | return "marvell, areca,N, 3ware,N, hpt,L/M/N, cciss,N"; | |
655 | } | |
656 | ||
657 | } // namespace | |
658 | ||
659 | ||
660 | ///////////////////////////////////////////////////////////////////////////// | |
661 | /// Initialize platform interface and register with smi() | |
662 | ||
663 | void smart_interface::init() | |
664 | { | |
665 | static os::legacy_smart_interface the_interface; | |
666 | smart_interface::set(&the_interface); | |
667 | } |