]> git.proxmox.com Git - mirror_smartmontools-debian.git/blob - os_win32.cpp
a0f6c4e70d14c3b0de95eef4a1904f53d1cbb459
[mirror_smartmontools-debian.git] / os_win32.cpp
1 /*
2 * os_win32.cpp
3 *
4 * Home page of code is: http://smartmontools.sourceforge.net
5 *
6 * Copyright (C) 2004-9 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 "extern.h"
22 extern smartmonctrl * con; // con->permissive,reportataioctl
23 #include "scsicmds.h"
24 #include "utility.h"
25
26 #include "dev_interface.h"
27 #include "dev_ata_cmd_set.h"
28
29 #include <errno.h>
30
31 #ifdef _DEBUG
32 #include <assert.h>
33 #else
34 #undef assert
35 #define assert(x) /**/
36 #endif
37
38 #define WIN32_LEAN_AND_MEAN
39 #include <windows.h>
40 #include <stddef.h> // offsetof()
41 #include <io.h> // access()
42
43 // Macro to check constants at compile time using a dummy typedef
44 #define ASSERT_CONST(c, n) \
45 typedef char assert_const_##c[((c) == (n)) ? 1 : -1]
46 #define ASSERT_SIZEOF(t, n) \
47 typedef char assert_sizeof_##t[(sizeof(t) == (n)) ? 1 : -1]
48
49
50 // Needed by '-V' option (CVS versioning) of smartd/smartctl
51 const char *os_XXXX_c_cvsid="$Id: os_win32.cpp 2915 2009-09-18 21:17:37Z chrfranke $"
52 ATACMDS_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
53
54
55 /////////////////////////////////////////////////////////////////////////////
56
57 namespace os_win32 { // no need to publish anything, name provided for Doxygen
58
59 #ifdef _MSC_VER
60 #pragma warning(disable:4250)
61 #endif
62
63 class win_smart_device
64 : virtual public /*implements*/ smart_device
65 {
66 public:
67 win_smart_device()
68 : smart_device(never_called),
69 m_fh(INVALID_HANDLE_VALUE)
70 { }
71
72 virtual ~win_smart_device() throw();
73
74 virtual bool is_open() const;
75
76 virtual bool close();
77
78 protected:
79 /// Set handle for open() in derived classes.
80 void set_fh(HANDLE fh)
81 { m_fh = fh; }
82
83 /// Return handle for derived classes.
84 HANDLE get_fh() const
85 { return m_fh; }
86
87 private:
88 HANDLE m_fh; ///< File handle
89 };
90
91
92 /////////////////////////////////////////////////////////////////////////////
93
94 class win_ata_device
95 : public /*implements*/ ata_device,
96 public /*extends*/ win_smart_device
97 {
98 public:
99 win_ata_device(smart_interface * intf, const char * dev_name, const char * req_type);
100
101 virtual ~win_ata_device() throw();
102
103 virtual bool open();
104
105 virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
106
107 virtual bool ata_identify_is_cached() const;
108
109 private:
110 bool open(int phydrive, int logdrive, const char * options, int port);
111
112 std::string m_options;
113 bool m_usr_options; // options set by user?
114 bool m_admin; // open with admin access?
115 int m_drive, m_port;
116 int m_smartver_state;
117 };
118
119
120 /////////////////////////////////////////////////////////////////////////////
121
122 class win_scsi_device
123 : public /*implements*/ scsi_device,
124 virtual public /*extends*/ win_smart_device
125 {
126 public:
127 win_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type);
128
129 virtual bool open();
130
131 virtual bool scsi_pass_through(scsi_cmnd_io * iop);
132
133 private:
134 bool open(int pd_num, int ld_num, int tape_num, int sub_addr);
135 };
136
137
138 /////////////////////////////////////////////////////////////////////////////
139
140 class win_aspi_device
141 : public /*implements*/ scsi_device
142 {
143 public:
144 win_aspi_device(smart_interface * intf, const char * dev_name, const char * req_type);
145
146 virtual bool is_open() const;
147
148 virtual bool open();
149
150 virtual bool close();
151
152 virtual bool scsi_pass_through(scsi_cmnd_io * iop);
153
154 private:
155 int m_adapter;
156 unsigned char m_id;
157 };
158
159
160 //////////////////////////////////////////////////////////////////////
161
162 class win_tw_cli_device
163 : public /*implements*/ ata_device_with_command_set
164 {
165 public:
166 win_tw_cli_device(smart_interface * intf, const char * dev_name, const char * req_type);
167
168 virtual bool is_open() const;
169
170 virtual bool open();
171
172 virtual bool close();
173
174 protected:
175 virtual int ata_command_interface(smart_command_set command, int select, char * data);
176
177 private:
178 bool m_ident_valid, m_smart_valid;
179 ata_identify_device m_ident_buf;
180 ata_smart_values m_smart_buf;
181 };
182
183
184 //////////////////////////////////////////////////////////////////////
185 // Platform specific interfaces
186
187 // Common to all windows flavors
188 class win_smart_interface
189 : public /*implements part of*/ smart_interface
190 {
191 public:
192 virtual std::string get_os_version_str();
193
194 virtual std::string get_app_examples(const char * appname);
195
196 virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
197 const char * pattern = 0);
198
199 protected:
200 virtual ata_device * get_ata_device(const char * name, const char * type);
201
202 //virtual scsi_device * get_scsi_device(const char * name, const char * type);
203
204 virtual smart_device * autodetect_smart_device(const char * name);
205
206 virtual bool ata_scan(smart_device_list & devlist) = 0;
207
208 virtual bool scsi_scan(smart_device_list & devlist) = 0;
209 };
210
211 // Win9x/ME reduced functionality
212 class win9x_smart_interface
213 : public /*extends*/ win_smart_interface
214 {
215 protected:
216 virtual scsi_device * get_scsi_device(const char * name, const char * type);
217
218 virtual bool ata_scan(smart_device_list & devlist);
219
220 virtual bool scsi_scan(smart_device_list & devlist);
221 };
222
223 // WinNT,2000,XP,...
224 class winnt_smart_interface
225 : public /*extends*/ win_smart_interface
226 {
227 protected:
228 virtual scsi_device * get_scsi_device(const char * name, const char * type);
229
230 virtual smart_device * autodetect_smart_device(const char * name);
231
232 virtual bool ata_scan(smart_device_list & devlist);
233
234 virtual bool scsi_scan(smart_device_list & devlist);
235 };
236
237
238 //////////////////////////////////////////////////////////////////////
239
240 // Running on Win9x/ME ?
241 static inline bool is_win9x()
242 {
243 return !!(GetVersion() & 0x80000000);
244 }
245
246 // Running on 64-bit Windows as 32-bit app ?
247 static bool is_wow64()
248 {
249 HMODULE hk = GetModuleHandleA("kernel32");
250 if (!hk)
251 return false;
252 BOOL (WINAPI * IsWow64Process_p)(HANDLE, PBOOL) =
253 (BOOL (WINAPI *)(HANDLE, PBOOL))GetProcAddress(hk, "IsWow64Process");
254 if (!IsWow64Process_p)
255 return false;
256 BOOL w64 = FALSE;
257 if (!IsWow64Process_p(GetCurrentProcess(), &w64))
258 return false;
259 return !!w64;
260 }
261
262 // Return info string about build host and OS version
263 std::string win_smart_interface::get_os_version_str()
264 {
265 char vstr[sizeof(SMARTMONTOOLS_BUILD_HOST)-1+sizeof("-2003r2(64)-sp2.1")+13]
266 = SMARTMONTOOLS_BUILD_HOST;
267 if (vstr[1] < '6')
268 vstr[1] = '6';
269 char * const vptr = vstr+sizeof(SMARTMONTOOLS_BUILD_HOST)-1;
270 const int vlen = sizeof(vstr)-sizeof(SMARTMONTOOLS_BUILD_HOST);
271 assert(vptr == vstr+strlen(vstr) && vptr+vlen+1 == vstr+sizeof(vstr));
272
273 OSVERSIONINFOEXA vi; memset(&vi, 0, sizeof(vi));
274 vi.dwOSVersionInfoSize = sizeof(vi);
275 if (!GetVersionExA((OSVERSIONINFOA *)&vi)) {
276 memset(&vi, 0, sizeof(vi));
277 vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
278 if (!GetVersionExA((OSVERSIONINFOA *)&vi))
279 return vstr;
280 }
281
282 if (vi.dwPlatformId > 0xff || vi.dwMajorVersion > 0xff || vi.dwMinorVersion > 0xff)
283 return vstr;
284
285 const char * w;
286 switch (vi.dwPlatformId << 16 | vi.dwMajorVersion << 8 | vi.dwMinorVersion) {
287 case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400| 0:
288 w = (vi.szCSDVersion[1] == 'B' ||
289 vi.szCSDVersion[1] == 'C' ? "95-osr2" : "95"); break;
290 case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400|10:
291 w = (vi.szCSDVersion[1] == 'A' ? "98se" : "98"); break;
292 case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400|90: w = "me"; break;
293 //case VER_PLATFORM_WIN32_NT <<16|0x0300|51: w = "nt3.51"; break;
294 case VER_PLATFORM_WIN32_NT <<16|0x0400| 0: w = "nt4"; break;
295 case VER_PLATFORM_WIN32_NT <<16|0x0500| 0: w = "2000"; break;
296 case VER_PLATFORM_WIN32_NT <<16|0x0500| 1:
297 w = (!GetSystemMetrics(87/*SM_MEDIACENTER*/) ? "xp"
298 : "xp-mc"); break;
299 case VER_PLATFORM_WIN32_NT <<16|0x0500| 2:
300 w = (!GetSystemMetrics(89/*SM_SERVERR2*/) ? "2003"
301 : "2003r2"); break;
302 case VER_PLATFORM_WIN32_NT <<16|0x0600| 0:
303 w = (vi.wProductType == VER_NT_WORKSTATION ? "vista"
304 : "2008" ); break;
305 case VER_PLATFORM_WIN32_NT <<16|0x0600| 1:
306 w = (vi.wProductType == VER_NT_WORKSTATION ? "win7"
307 : "2008r2"); break;
308 default: w = 0; break;
309 }
310
311 const char * w64 = (is_wow64() ? "(64)" : "");
312 if (!w)
313 snprintf(vptr, vlen, "-%s%lu.%lu%s",
314 (vi.dwPlatformId==VER_PLATFORM_WIN32_NT ? "nt" : "9x"),
315 vi.dwMajorVersion, vi.dwMinorVersion, w64);
316 else if (vi.wServicePackMinor)
317 snprintf(vptr, vlen, "-%s%s-sp%u.%u", w, w64, vi.wServicePackMajor, vi.wServicePackMinor);
318 else if (vi.wServicePackMajor)
319 snprintf(vptr, vlen, "-%s%s-sp%u", w, w64, vi.wServicePackMajor);
320 else
321 snprintf(vptr, vlen, "-%s%s", w, w64);
322 return vstr;
323 }
324
325 // Return value for device detection functions
326 enum win_dev_type { DEV_UNKNOWN = 0, DEV_ATA, DEV_SCSI, DEV_USB };
327
328 static win_dev_type get_phy_drive_type(int drive);
329 static win_dev_type get_log_drive_type(int drive);
330 static bool get_usb_id(int drive, unsigned short & vendor_id,
331 unsigned short & product_id);
332
333 static const char * ata_get_def_options(void);
334
335
336 static int is_permissive()
337 {
338 if (!con->permissive) {
339 pout("To continue, add one or more '-T permissive' options.\n");
340 return 0;
341 }
342 con->permissive--;
343 return 1;
344 }
345
346 // return number for drive letter, -1 on error
347 // "[A-Za-z]:([/\\][.]?)?" => 0-25
348 // Accepts trailing '"' to fix broken "X:\" parameter passing from .bat files
349 static int drive_letter(const char * s)
350 {
351 return ( (('A' <= s[0] && s[0] <= 'Z') || ('a' <= s[0] && s[0] <= 'z'))
352 && s[1] == ':'
353 && (!s[2] || ( strchr("/\\\"", s[2])
354 && (!s[3] || (s[3] == '.' && !s[4]))) ) ?
355 (s[0] & 0x1f) - 1 : -1);
356 }
357
358 // Skip trailing "/dev/", do not allow "/dev/X:"
359 static const char * skipdev(const char * s)
360 {
361 return (!strncmp(s, "/dev/", 5) && drive_letter(s+5) < 0 ? s+5 : s);
362 }
363
364 ata_device * win_smart_interface::get_ata_device(const char * name, const char * type)
365 {
366 const char * testname = skipdev(name);
367 if (!strncmp(testname, "tw_cli", 6))
368 return new win_tw_cli_device(this, name, type);
369 return new win_ata_device(this, name, type);
370 }
371
372 scsi_device * win9x_smart_interface::get_scsi_device(const char * name, const char * type)
373 {
374 return new win_aspi_device(this, name, type);
375 }
376
377 scsi_device * winnt_smart_interface::get_scsi_device(const char * name, const char * type)
378 {
379 const char * testname = skipdev(name);
380 if (!strncmp(testname, "scsi", 4))
381 return new win_aspi_device(this, name, type);
382 return new win_scsi_device(this, name, type);
383 }
384
385 static win_dev_type get_dev_type(const char * name, int & phydrive)
386 {
387 phydrive = -1;
388 name = skipdev(name);
389 if (!strncmp(name, "st", 2))
390 return DEV_SCSI;
391 if (!strncmp(name, "nst", 3))
392 return DEV_SCSI;
393 if (!strncmp(name, "tape", 4))
394 return DEV_SCSI;
395
396 int logdrive = drive_letter(name);
397 if (logdrive >= 0) {
398 win_dev_type type = get_log_drive_type(logdrive);
399 return (type != DEV_UNKNOWN ? type : DEV_SCSI);
400 }
401
402 char drive[1+1] = "";
403 if (sscanf(name, "sd%1[a-z]", drive) == 1) {
404 phydrive = drive[0] - 'a';
405 return get_phy_drive_type(phydrive);
406 }
407
408 phydrive = -1;
409 if (sscanf(name, "pd%d", &phydrive) == 1 && phydrive >= 0)
410 return get_phy_drive_type(phydrive);
411 return DEV_UNKNOWN;
412 }
413
414 smart_device * win_smart_interface::autodetect_smart_device(const char * name)
415 {
416 const char * testname = skipdev(name);
417 if (!strncmp(testname, "hd", 2))
418 return new win_ata_device(this, name, "");
419 if (!strncmp(testname, "scsi", 4))
420 return new win_aspi_device(this, name, "");
421 if (!strncmp(testname, "tw_cli", 6))
422 return new win_tw_cli_device(this, name, "");
423 return 0;
424 }
425
426 smart_device * winnt_smart_interface::autodetect_smart_device(const char * name)
427 {
428 smart_device * dev = win_smart_interface::autodetect_smart_device(name);
429 if (dev)
430 return dev;
431
432 int phydrive = -1;
433 win_dev_type type = get_dev_type(name, phydrive);
434
435 if (type == DEV_ATA)
436 return new win_ata_device(this, name, "");
437 if (type == DEV_SCSI)
438 return new win_scsi_device(this, name, "");
439
440 if (type == DEV_USB) {
441 // Get USB bridge ID
442 unsigned short vendor_id = 0, product_id = 0;
443 if (!(phydrive >= 0 && get_usb_id(phydrive, vendor_id, product_id))) {
444 set_err(EINVAL, "Unable to read USB device ID");
445 return 0;
446 }
447 // Get type name for this ID
448 const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id);
449 if (!usbtype)
450 return 0;
451 // Return SAT/USB device for this type
452 return get_sat_device(usbtype, new win_scsi_device(this, name, ""));
453 }
454
455 return 0;
456 }
457
458
459 // makes a list of ATA or SCSI devices for the DEVICESCAN directive
460 bool win_smart_interface::scan_smart_devices(smart_device_list & devlist,
461 const char * type, const char * pattern /* = 0*/)
462 {
463 if (pattern) {
464 set_err(EINVAL, "DEVICESCAN with pattern not implemented yet");
465 return false;
466 }
467
468 if (!type || !strcmp(type, "ata")) {
469 if (!ata_scan(devlist))
470 return false;
471 }
472
473 if (!type || !strcmp(type, "scsi")) {
474 if (!scsi_scan(devlist))
475 return false;
476 }
477 return true;
478 }
479
480
481 // get examples for smartctl
482 std::string win_smart_interface::get_app_examples(const char * appname)
483 {
484 if (strcmp(appname, "smartctl"))
485 return "";
486 return "=================================================== SMARTCTL EXAMPLES =====\n\n"
487 " smartctl -a /dev/hda (Prints all SMART information)\n\n"
488 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/hda\n"
489 " (Enables SMART on first disk)\n\n"
490 " smartctl -t long /dev/hda (Executes extended disk self-test)\n\n"
491 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/hda\n"
492 " (Prints Self-Test & Attribute errors)\n"
493 " smartctl -a /dev/scsi21\n"
494 " (Prints all information for SCSI disk on ASPI adapter 2, ID 1)\n"
495 " smartctl -a /dev/sda\n"
496 " (Prints all information for SCSI disk on PhysicalDrive 0)\n"
497 " smartctl -a /dev/pd3\n"
498 " (Prints all information for SCSI disk on PhysicalDrive 3)\n"
499 " smartctl -a /dev/tape1\n"
500 " (Prints all information for SCSI tape on Tape 1)\n"
501 " smartctl -A /dev/hdb,3\n"
502 " (Prints Attributes for physical drive 3 on 3ware 9000 RAID)\n"
503 " smartctl -A /dev/tw_cli/c0/p1\n"
504 " (Prints Attributes for 3ware controller 0, port 1 using tw_cli)\n"
505 "\n"
506 " ATA SMART access methods and ordering may be specified by modifiers\n"
507 " following the device name: /dev/hdX:[saicm], where\n"
508 " 's': SMART_* IOCTLs, 'a': IOCTL_ATA_PASS_THROUGH,\n"
509 " 'i': IOCTL_IDE_PASS_THROUGH, 'c': ATA via IOCTL_SCSI_PASS_THROUGH,\n"
510 " 'f': IOCTL_STORAGE_*, 'm': IOCTL_SCSI_MINIPORT_*.\n"
511 + strprintf(
512 " The default on this system is /dev/sdX:%s\n", ata_get_def_options()
513 );
514 }
515
516
517 /////////////////////////////////////////////////////////////////////////////
518 // ATA Interface
519 /////////////////////////////////////////////////////////////////////////////
520
521 // SMART_* IOCTLs, also known as DFP_* (Disk Fault Protection)
522
523 #define FILE_READ_ACCESS 0x0001
524 #define FILE_WRITE_ACCESS 0x0002
525 #define METHOD_BUFFERED 0
526 #define CTL_CODE(DeviceType, Function, Method, Access) (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
527
528 #define FILE_DEVICE_DISK 7
529 #define IOCTL_DISK_BASE FILE_DEVICE_DISK
530
531 #define SMART_GET_VERSION \
532 CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS)
533
534 #define SMART_SEND_DRIVE_COMMAND \
535 CTL_CODE(IOCTL_DISK_BASE, 0x0021, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
536
537 #define SMART_RCV_DRIVE_DATA \
538 CTL_CODE(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
539
540 ASSERT_CONST(SMART_GET_VERSION , 0x074080);
541 ASSERT_CONST(SMART_SEND_DRIVE_COMMAND, 0x07c084);
542 ASSERT_CONST(SMART_RCV_DRIVE_DATA , 0x07c088);
543
544 #define SMART_CYL_LOW 0x4F
545 #define SMART_CYL_HI 0xC2
546
547
548 #pragma pack(1)
549
550 typedef struct _GETVERSIONOUTPARAMS {
551 UCHAR bVersion;
552 UCHAR bRevision;
553 UCHAR bReserved;
554 UCHAR bIDEDeviceMap;
555 ULONG fCapabilities;
556 ULONG dwReserved[4];
557 } GETVERSIONOUTPARAMS, *PGETVERSIONOUTPARAMS, *LPGETVERSIONOUTPARAMS;
558
559 ASSERT_SIZEOF(GETVERSIONOUTPARAMS, 24);
560
561
562 #define SMART_VENDOR_3WARE 0x13C1 // identifies 3ware specific parameters
563
564 typedef struct _GETVERSIONINPARAMS_EX {
565 BYTE bVersion;
566 BYTE bRevision;
567 BYTE bReserved;
568 BYTE bIDEDeviceMap;
569 DWORD fCapabilities;
570 DWORD dwDeviceMapEx; // 3ware specific: RAID drive bit map
571 WORD wIdentifier; // Vendor specific identifier
572 WORD wControllerId; // 3ware specific: Controller ID (0,1,...)
573 ULONG dwReserved[2];
574 } GETVERSIONINPARAMS_EX, *PGETVERSIONINPARAMS_EX, *LPGETVERSIONINPARAMS_EX;
575
576 ASSERT_SIZEOF(GETVERSIONINPARAMS_EX, sizeof(GETVERSIONOUTPARAMS));
577
578
579 typedef struct _IDEREGS {
580 UCHAR bFeaturesReg;
581 UCHAR bSectorCountReg;
582 UCHAR bSectorNumberReg;
583 UCHAR bCylLowReg;
584 UCHAR bCylHighReg;
585 UCHAR bDriveHeadReg;
586 UCHAR bCommandReg;
587 UCHAR bReserved;
588 } IDEREGS, *PIDEREGS, *LPIDEREGS;
589
590 typedef struct _SENDCMDINPARAMS {
591 ULONG cBufferSize;
592 IDEREGS irDriveRegs;
593 UCHAR bDriveNumber;
594 UCHAR bReserved[3];
595 ULONG dwReserved[4];
596 UCHAR bBuffer[1];
597 } SENDCMDINPARAMS, *PSENDCMDINPARAMS, *LPSENDCMDINPARAMS;
598
599 ASSERT_SIZEOF(SENDCMDINPARAMS, 32+1);
600
601 typedef struct _SENDCMDINPARAMS_EX {
602 DWORD cBufferSize;
603 IDEREGS irDriveRegs;
604 BYTE bDriveNumber;
605 BYTE bPortNumber; // 3ware specific: port number
606 WORD wIdentifier; // Vendor specific identifier
607 DWORD dwReserved[4];
608 BYTE bBuffer[1];
609 } SENDCMDINPARAMS_EX, *PSENDCMDINPARAMS_EX, *LPSENDCMDINPARAMS_EX;
610
611 ASSERT_SIZEOF(SENDCMDINPARAMS_EX, sizeof(SENDCMDINPARAMS));
612
613
614 /* DRIVERSTATUS.bDriverError constants (just for info, not used)
615 #define SMART_NO_ERROR 0
616 #define SMART_IDE_ERROR 1
617 #define SMART_INVALID_FLAG 2
618 #define SMART_INVALID_COMMAND 3
619 #define SMART_INVALID_BUFFER 4
620 #define SMART_INVALID_DRIVE 5
621 #define SMART_INVALID_IOCTL 6
622 #define SMART_ERROR_NO_MEM 7
623 #define SMART_INVALID_REGISTER 8
624 #define SMART_NOT_SUPPORTED 9
625 #define SMART_NO_IDE_DEVICE 10
626 */
627
628 typedef struct _DRIVERSTATUS {
629 UCHAR bDriverError;
630 UCHAR bIDEError;
631 UCHAR bReserved[2];
632 ULONG dwReserved[2];
633 } DRIVERSTATUS, *PDRIVERSTATUS, *LPDRIVERSTATUS;
634
635 typedef struct _SENDCMDOUTPARAMS {
636 ULONG cBufferSize;
637 DRIVERSTATUS DriverStatus;
638 UCHAR bBuffer[1];
639 } SENDCMDOUTPARAMS, *PSENDCMDOUTPARAMS, *LPSENDCMDOUTPARAMS;
640
641 ASSERT_SIZEOF(SENDCMDOUTPARAMS, 16+1);
642
643 #pragma pack()
644
645
646 /////////////////////////////////////////////////////////////////////////////
647
648 static void print_ide_regs(const IDEREGS * r, int out)
649 {
650 pout("%s=0x%02x,%s=0x%02x, SC=0x%02x, SN=0x%02x, CL=0x%02x, CH=0x%02x, SEL=0x%02x\n",
651 (out?"STS":"CMD"), r->bCommandReg, (out?"ERR":" FR"), r->bFeaturesReg,
652 r->bSectorCountReg, r->bSectorNumberReg, r->bCylLowReg, r->bCylHighReg, r->bDriveHeadReg);
653 }
654
655 static void print_ide_regs_io(const IDEREGS * ri, const IDEREGS * ro)
656 {
657 pout(" Input : "); print_ide_regs(ri, 0);
658 if (ro) {
659 pout(" Output: "); print_ide_regs(ro, 1);
660 }
661 }
662
663 /////////////////////////////////////////////////////////////////////////////
664
665 // call SMART_GET_VERSION, return device map or -1 on error
666
667 static int smart_get_version(HANDLE hdevice, GETVERSIONINPARAMS_EX * ata_version_ex = 0)
668 {
669 GETVERSIONOUTPARAMS vers; memset(&vers, 0, sizeof(vers));
670 const GETVERSIONINPARAMS_EX & vers_ex = (const GETVERSIONINPARAMS_EX &)vers;
671 DWORD num_out;
672
673 if (!DeviceIoControl(hdevice, SMART_GET_VERSION,
674 NULL, 0, &vers, sizeof(vers), &num_out, NULL)) {
675 if (con->reportataioctl)
676 pout(" SMART_GET_VERSION failed, Error=%ld\n", GetLastError());
677 errno = ENOSYS;
678 return -1;
679 }
680 assert(num_out == sizeof(GETVERSIONOUTPARAMS));
681
682 if (con->reportataioctl > 1) {
683 pout(" SMART_GET_VERSION suceeded, bytes returned: %lu\n"
684 " Vers = %d.%d, Caps = 0x%lx, DeviceMap = 0x%02x\n",
685 num_out, vers.bVersion, vers.bRevision,
686 vers.fCapabilities, vers.bIDEDeviceMap);
687 if (vers_ex.wIdentifier == SMART_VENDOR_3WARE)
688 pout(" Identifier = %04x(3WARE), ControllerId=%u, DeviceMapEx = 0x%08lx\n",
689 vers_ex.wIdentifier, vers_ex.wControllerId, vers_ex.dwDeviceMapEx);
690 }
691
692 if (ata_version_ex)
693 *ata_version_ex = vers_ex;
694
695 // TODO: Check vers.fCapabilities here?
696 return vers.bIDEDeviceMap;
697 }
698
699
700 // call SMART_* ioctl
701
702 static int smart_ioctl(HANDLE hdevice, int drive, IDEREGS * regs, char * data, unsigned datasize, int port)
703 {
704 SENDCMDINPARAMS inpar;
705 SENDCMDINPARAMS_EX & inpar_ex = (SENDCMDINPARAMS_EX &)inpar;
706
707 unsigned char outbuf[sizeof(SENDCMDOUTPARAMS)-1 + 512];
708 const SENDCMDOUTPARAMS * outpar;
709 DWORD code, num_out;
710 unsigned int size_out;
711 const char * name;
712
713 memset(&inpar, 0, sizeof(inpar));
714 inpar.irDriveRegs = *regs;
715 // drive is set to 0-3 on Win9x only
716 inpar.irDriveRegs.bDriveHeadReg = 0xA0 | ((drive & 1) << 4);
717 inpar.bDriveNumber = drive;
718
719 if (port >= 0) {
720 // Set RAID port
721 inpar_ex.wIdentifier = SMART_VENDOR_3WARE;
722 inpar_ex.bPortNumber = port;
723 }
724
725 if (datasize == 512) {
726 code = SMART_RCV_DRIVE_DATA; name = "SMART_RCV_DRIVE_DATA";
727 inpar.cBufferSize = size_out = 512;
728 }
729 else if (datasize == 0) {
730 code = SMART_SEND_DRIVE_COMMAND; name = "SMART_SEND_DRIVE_COMMAND";
731 if (regs->bFeaturesReg == ATA_SMART_STATUS)
732 size_out = sizeof(IDEREGS); // ioctl returns new IDEREGS as data
733 // Note: cBufferSize must be 0 on Win9x
734 else
735 size_out = 0;
736 }
737 else {
738 errno = EINVAL;
739 return -1;
740 }
741
742 memset(&outbuf, 0, sizeof(outbuf));
743
744 if (!DeviceIoControl(hdevice, code, &inpar, sizeof(SENDCMDINPARAMS)-1,
745 outbuf, sizeof(SENDCMDOUTPARAMS)-1 + size_out, &num_out, NULL)) {
746 // CAUTION: DO NOT change "regs" Parameter in this case, see ata_command_interface()
747 long err = GetLastError();
748 if (con->reportataioctl && (err != ERROR_INVALID_PARAMETER || con->reportataioctl > 1)) {
749 pout(" %s failed, Error=%ld\n", name, err);
750 print_ide_regs_io(regs, NULL);
751 }
752 errno = ( err == ERROR_INVALID_FUNCTION/*9x*/
753 || err == ERROR_INVALID_PARAMETER/*NT/2K/XP*/
754 || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
755 return -1;
756 }
757 // NOTE: On Win9x, inpar.irDriveRegs now contains the returned regs
758
759 outpar = (const SENDCMDOUTPARAMS *)outbuf;
760
761 if (outpar->DriverStatus.bDriverError) {
762 if (con->reportataioctl) {
763 pout(" %s failed, DriverError=0x%02x, IDEError=0x%02x\n", name,
764 outpar->DriverStatus.bDriverError, outpar->DriverStatus.bIDEError);
765 print_ide_regs_io(regs, NULL);
766 }
767 errno = (!outpar->DriverStatus.bIDEError ? ENOSYS : EIO);
768 return -1;
769 }
770
771 if (con->reportataioctl > 1) {
772 pout(" %s suceeded, bytes returned: %lu (buffer %lu)\n", name,
773 num_out, outpar->cBufferSize);
774 print_ide_regs_io(regs, (regs->bFeaturesReg == ATA_SMART_STATUS ?
775 (const IDEREGS *)(outpar->bBuffer) : NULL));
776 }
777
778 if (datasize)
779 memcpy(data, outpar->bBuffer, 512);
780 else if (regs->bFeaturesReg == ATA_SMART_STATUS) {
781 if (nonempty(const_cast<unsigned char *>(outpar->bBuffer), sizeof(IDEREGS)))
782 *regs = *(const IDEREGS *)(outpar->bBuffer);
783 else { // Workaround for driver not returning regs
784 if (con->reportataioctl)
785 pout(" WARNING: driver does not return ATA registers in output buffer!\n");
786 *regs = inpar.irDriveRegs;
787 }
788 }
789
790 return 0;
791 }
792
793
794 /////////////////////////////////////////////////////////////////////////////
795
796 // IDE PASS THROUGH (2000, XP, undocumented)
797 //
798 // Based on WinATA.cpp, 2002 c't/Matthias Withopf
799 // ftp://ftp.heise.de/pub/ct/listings/0207-218.zip
800
801 #define FILE_DEVICE_CONTROLLER 4
802 #define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER
803
804 #define IOCTL_IDE_PASS_THROUGH \
805 CTL_CODE(IOCTL_SCSI_BASE, 0x040A, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
806
807 ASSERT_CONST(IOCTL_IDE_PASS_THROUGH, 0x04d028);
808
809 #pragma pack(1)
810
811 typedef struct {
812 IDEREGS IdeReg;
813 ULONG DataBufferSize;
814 UCHAR DataBuffer[1];
815 } ATA_PASS_THROUGH;
816
817 ASSERT_SIZEOF(ATA_PASS_THROUGH, 12+1);
818
819 #pragma pack()
820
821
822 /////////////////////////////////////////////////////////////////////////////
823
824 static int ide_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize)
825 {
826 if (datasize > 512) {
827 errno = EINVAL;
828 return -1;
829 }
830 unsigned int size = sizeof(ATA_PASS_THROUGH)-1 + datasize;
831 ATA_PASS_THROUGH * buf = (ATA_PASS_THROUGH *)VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
832 DWORD num_out;
833 const unsigned char magic = 0xcf;
834
835 if (!buf) {
836 errno = ENOMEM;
837 return -1;
838 }
839
840 buf->IdeReg = *regs;
841 buf->DataBufferSize = datasize;
842 if (datasize)
843 buf->DataBuffer[0] = magic;
844
845 if (!DeviceIoControl(hdevice, IOCTL_IDE_PASS_THROUGH,
846 buf, size, buf, size, &num_out, NULL)) {
847 long err = GetLastError();
848 if (con->reportataioctl) {
849 pout(" IOCTL_IDE_PASS_THROUGH failed, Error=%ld\n", err);
850 print_ide_regs_io(regs, NULL);
851 }
852 VirtualFree(buf, 0, MEM_RELEASE);
853 errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
854 return -1;
855 }
856
857 // Check ATA status
858 if (buf->IdeReg.bCommandReg/*Status*/ & 0x01) {
859 if (con->reportataioctl) {
860 pout(" IOCTL_IDE_PASS_THROUGH command failed:\n");
861 print_ide_regs_io(regs, &buf->IdeReg);
862 }
863 VirtualFree(buf, 0, MEM_RELEASE);
864 errno = EIO;
865 return -1;
866 }
867
868 // Check and copy data
869 if (datasize) {
870 if ( num_out != size
871 || (buf->DataBuffer[0] == magic && !nonempty(buf->DataBuffer+1, datasize-1))) {
872 if (con->reportataioctl) {
873 pout(" IOCTL_IDE_PASS_THROUGH output data missing (%lu, %lu)\n",
874 num_out, buf->DataBufferSize);
875 print_ide_regs_io(regs, &buf->IdeReg);
876 }
877 VirtualFree(buf, 0, MEM_RELEASE);
878 errno = EIO;
879 return -1;
880 }
881 memcpy(data, buf->DataBuffer, datasize);
882 }
883
884 if (con->reportataioctl > 1) {
885 pout(" IOCTL_IDE_PASS_THROUGH suceeded, bytes returned: %lu (buffer %lu)\n",
886 num_out, buf->DataBufferSize);
887 print_ide_regs_io(regs, &buf->IdeReg);
888 }
889 *regs = buf->IdeReg;
890
891 // Caution: VirtualFree() fails if parameter "dwSize" is nonzero
892 VirtualFree(buf, 0, MEM_RELEASE);
893 return 0;
894 }
895
896
897 /////////////////////////////////////////////////////////////////////////////
898
899 // ATA PASS THROUGH (Win2003, XP SP2)
900
901 #define IOCTL_ATA_PASS_THROUGH \
902 CTL_CODE(IOCTL_SCSI_BASE, 0x040B, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
903
904 ASSERT_CONST(IOCTL_ATA_PASS_THROUGH, 0x04d02c);
905
906 typedef struct _ATA_PASS_THROUGH_EX {
907 USHORT Length;
908 USHORT AtaFlags;
909 UCHAR PathId;
910 UCHAR TargetId;
911 UCHAR Lun;
912 UCHAR ReservedAsUchar;
913 ULONG DataTransferLength;
914 ULONG TimeOutValue;
915 ULONG ReservedAsUlong;
916 ULONG/*_PTR*/ DataBufferOffset;
917 UCHAR PreviousTaskFile[8];
918 UCHAR CurrentTaskFile[8];
919 } ATA_PASS_THROUGH_EX, *PATA_PASS_THROUGH_EX;
920
921 ASSERT_SIZEOF(ATA_PASS_THROUGH_EX, 40);
922
923 #define ATA_FLAGS_DRDY_REQUIRED 0x01
924 #define ATA_FLAGS_DATA_IN 0x02
925 #define ATA_FLAGS_DATA_OUT 0x04
926 #define ATA_FLAGS_48BIT_COMMAND 0x08
927 #define ATA_FLAGS_USE_DMA 0x10
928 #define ATA_FLAGS_NO_MULTIPLE 0x20 // Vista
929
930
931 /////////////////////////////////////////////////////////////////////////////
932
933 // Warning:
934 // IOCTL_ATA_PASS_THROUGH[_DIRECT] can only handle one interrupt/DRQ data
935 // transfer per command. Therefore, multi-sector transfers are only supported
936 // for the READ/WRITE MULTIPLE [EXT] commands. Other commands like READ/WRITE SECTORS
937 // or READ/WRITE LOG EXT work only with single sector transfers.
938 // The latter are supported on Vista (only) through new ATA_FLAGS_NO_MULTIPLE.
939 // See:
940 // http://social.msdn.microsoft.com/Forums/en-US/storageplatformata/thread/eb408507-f221-455b-9bbb-d1069b29c4da
941
942 static int ata_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, IDEREGS * prev_regs, char * data, int datasize)
943 {
944 const int max_sectors = 32; // TODO: Allocate dynamic buffer
945
946 typedef struct {
947 ATA_PASS_THROUGH_EX apt;
948 ULONG Filler;
949 UCHAR ucDataBuf[max_sectors * 512];
950 } ATA_PASS_THROUGH_EX_WITH_BUFFERS;
951
952 const unsigned char magic = 0xcf;
953
954 ATA_PASS_THROUGH_EX_WITH_BUFFERS ab; memset(&ab, 0, sizeof(ab));
955 ab.apt.Length = sizeof(ATA_PASS_THROUGH_EX);
956 //ab.apt.PathId = 0;
957 //ab.apt.TargetId = 0;
958 //ab.apt.Lun = 0;
959 ab.apt.TimeOutValue = 10;
960 unsigned size = offsetof(ATA_PASS_THROUGH_EX_WITH_BUFFERS, ucDataBuf);
961 ab.apt.DataBufferOffset = size;
962
963 if (datasize > 0) {
964 if (datasize > (int)sizeof(ab.ucDataBuf)) {
965 errno = EINVAL;
966 return -1;
967 }
968 ab.apt.AtaFlags = ATA_FLAGS_DATA_IN;
969 ab.apt.DataTransferLength = datasize;
970 size += datasize;
971 ab.ucDataBuf[0] = magic;
972 }
973 else if (datasize < 0) {
974 if (-datasize > (int)sizeof(ab.ucDataBuf)) {
975 errno = EINVAL;
976 return -1;
977 }
978 ab.apt.AtaFlags = ATA_FLAGS_DATA_OUT;
979 ab.apt.DataTransferLength = -datasize;
980 size += -datasize;
981 memcpy(ab.ucDataBuf, data, -datasize);
982 }
983 else {
984 assert(ab.apt.AtaFlags == 0);
985 assert(ab.apt.DataTransferLength == 0);
986 }
987
988 assert(sizeof(ab.apt.CurrentTaskFile) == sizeof(IDEREGS));
989 IDEREGS * ctfregs = (IDEREGS *)ab.apt.CurrentTaskFile;
990 IDEREGS * ptfregs = (IDEREGS *)ab.apt.PreviousTaskFile;
991 *ctfregs = *regs;
992
993 if (prev_regs) {
994 *ptfregs = *prev_regs;
995 ab.apt.AtaFlags |= ATA_FLAGS_48BIT_COMMAND;
996 }
997
998 DWORD num_out;
999 if (!DeviceIoControl(hdevice, IOCTL_ATA_PASS_THROUGH,
1000 &ab, size, &ab, size, &num_out, NULL)) {
1001 long err = GetLastError();
1002 if (con->reportataioctl) {
1003 pout(" IOCTL_ATA_PASS_THROUGH failed, Error=%ld\n", err);
1004 print_ide_regs_io(regs, NULL);
1005 }
1006 errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
1007 return -1;
1008 }
1009
1010 // Check ATA status
1011 if (ctfregs->bCommandReg/*Status*/ & (0x01/*Err*/|0x08/*DRQ*/)) {
1012 if (con->reportataioctl) {
1013 pout(" IOCTL_ATA_PASS_THROUGH command failed:\n");
1014 print_ide_regs_io(regs, ctfregs);
1015 }
1016 errno = EIO;
1017 return -1;
1018 }
1019
1020 // Check and copy data
1021 if (datasize > 0) {
1022 if ( num_out != size
1023 || (ab.ucDataBuf[0] == magic && !nonempty(ab.ucDataBuf+1, datasize-1))) {
1024 if (con->reportataioctl) {
1025 pout(" IOCTL_ATA_PASS_THROUGH output data missing (%lu)\n", num_out);
1026 print_ide_regs_io(regs, ctfregs);
1027 }
1028 errno = EIO;
1029 return -1;
1030 }
1031 memcpy(data, ab.ucDataBuf, datasize);
1032 }
1033
1034 if (con->reportataioctl > 1) {
1035 pout(" IOCTL_ATA_PASS_THROUGH suceeded, bytes returned: %lu\n", num_out);
1036 print_ide_regs_io(regs, ctfregs);
1037 }
1038 *regs = *ctfregs;
1039 if (prev_regs)
1040 *prev_regs = *ptfregs;
1041
1042 return 0;
1043 }
1044
1045
1046 /////////////////////////////////////////////////////////////////////////////
1047
1048 // ATA PASS THROUGH via SCSI PASS THROUGH (WinNT4 only)
1049
1050 #define IOCTL_SCSI_PASS_THROUGH \
1051 CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
1052
1053 ASSERT_CONST(IOCTL_SCSI_PASS_THROUGH, 0x04d004);
1054
1055 #define SCSI_IOCTL_DATA_OUT 0
1056 #define SCSI_IOCTL_DATA_IN 1
1057 #define SCSI_IOCTL_DATA_UNSPECIFIED 2
1058 // undocumented SCSI opcode to for ATA passthrough
1059 #define SCSIOP_ATA_PASSTHROUGH 0xCC
1060
1061 typedef struct _SCSI_PASS_THROUGH {
1062 USHORT Length;
1063 UCHAR ScsiStatus;
1064 UCHAR PathId;
1065 UCHAR TargetId;
1066 UCHAR Lun;
1067 UCHAR CdbLength;
1068 UCHAR SenseInfoLength;
1069 UCHAR DataIn;
1070 ULONG DataTransferLength;
1071 ULONG TimeOutValue;
1072 ULONG/*_PTR*/ DataBufferOffset;
1073 ULONG SenseInfoOffset;
1074 UCHAR Cdb[16];
1075 } SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;
1076
1077 ASSERT_SIZEOF(SCSI_PASS_THROUGH, 44);
1078
1079
1080 /////////////////////////////////////////////////////////////////////////////
1081
1082 static int ata_via_scsi_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize)
1083 {
1084 typedef struct {
1085 SCSI_PASS_THROUGH spt;
1086 ULONG Filler;
1087 UCHAR ucSenseBuf[32];
1088 UCHAR ucDataBuf[512];
1089 } SCSI_PASS_THROUGH_WITH_BUFFERS;
1090
1091 SCSI_PASS_THROUGH_WITH_BUFFERS sb;
1092 IDEREGS * cdbregs;
1093 unsigned int size;
1094 DWORD num_out;
1095 const unsigned char magic = 0xcf;
1096
1097 memset(&sb, 0, sizeof(sb));
1098 sb.spt.Length = sizeof(SCSI_PASS_THROUGH);
1099 //sb.spt.PathId = 0;
1100 sb.spt.TargetId = 1;
1101 //sb.spt.Lun = 0;
1102 sb.spt.CdbLength = 10; sb.spt.SenseInfoLength = 24;
1103 sb.spt.TimeOutValue = 10;
1104 sb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf);
1105 size = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf);
1106 sb.spt.DataBufferOffset = size;
1107
1108 if (datasize) {
1109 if (datasize > sizeof(sb.ucDataBuf)) {
1110 errno = EINVAL;
1111 return -1;
1112 }
1113 sb.spt.DataIn = SCSI_IOCTL_DATA_IN;
1114 sb.spt.DataTransferLength = datasize;
1115 size += datasize;
1116 sb.ucDataBuf[0] = magic;
1117 }
1118 else {
1119 sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
1120 //sb.spt.DataTransferLength = 0;
1121 }
1122
1123 // Use pseudo SCSI command followed by registers
1124 sb.spt.Cdb[0] = SCSIOP_ATA_PASSTHROUGH;
1125 cdbregs = (IDEREGS *)(sb.spt.Cdb+2);
1126 *cdbregs = *regs;
1127
1128 if (!DeviceIoControl(hdevice, IOCTL_SCSI_PASS_THROUGH,
1129 &sb, size, &sb, size, &num_out, NULL)) {
1130 long err = GetLastError();
1131 if (con->reportataioctl)
1132 pout(" ATA via IOCTL_SCSI_PASS_THROUGH failed, Error=%ld\n", err);
1133 errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
1134 return -1;
1135 }
1136
1137 // Cannot check ATA status, because command does not return IDEREGS
1138
1139 // Check and copy data
1140 if (datasize) {
1141 if ( num_out != size
1142 || (sb.ucDataBuf[0] == magic && !nonempty(sb.ucDataBuf+1, datasize-1))) {
1143 if (con->reportataioctl) {
1144 pout(" ATA via IOCTL_SCSI_PASS_THROUGH output data missing (%lu)\n", num_out);
1145 print_ide_regs_io(regs, NULL);
1146 }
1147 errno = EIO;
1148 return -1;
1149 }
1150 memcpy(data, sb.ucDataBuf, datasize);
1151 }
1152
1153 if (con->reportataioctl > 1) {
1154 pout(" ATA via IOCTL_SCSI_PASS_THROUGH suceeded, bytes returned: %lu\n", num_out);
1155 print_ide_regs_io(regs, NULL);
1156 }
1157 return 0;
1158 }
1159
1160
1161 /////////////////////////////////////////////////////////////////////////////
1162
1163 // SMART IOCTL via SCSI MINIPORT ioctl
1164
1165 // This function is handled by ATAPI port driver (atapi.sys) or by SCSI
1166 // miniport driver (via SCSI port driver scsiport.sys).
1167 // It can be used to skip the missing or broken handling of some SMART
1168 // command codes (e.g. READ_LOG) in the disk class driver (disk.sys)
1169
1170 #define IOCTL_SCSI_MINIPORT \
1171 CTL_CODE(IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
1172
1173 ASSERT_CONST(IOCTL_SCSI_MINIPORT, 0x04d008);
1174
1175 typedef struct _SRB_IO_CONTROL {
1176 ULONG HeaderLength;
1177 UCHAR Signature[8];
1178 ULONG Timeout;
1179 ULONG ControlCode;
1180 ULONG ReturnCode;
1181 ULONG Length;
1182 } SRB_IO_CONTROL, *PSRB_IO_CONTROL;
1183
1184 ASSERT_SIZEOF(SRB_IO_CONTROL, 28);
1185
1186 #define FILE_DEVICE_SCSI 0x001b
1187
1188 #define IOCTL_SCSI_MINIPORT_SMART_VERSION ((FILE_DEVICE_SCSI << 16) + 0x0500)
1189 #define IOCTL_SCSI_MINIPORT_IDENTIFY ((FILE_DEVICE_SCSI << 16) + 0x0501)
1190 #define IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS ((FILE_DEVICE_SCSI << 16) + 0x0502)
1191 #define IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS ((FILE_DEVICE_SCSI << 16) + 0x0503)
1192 #define IOCTL_SCSI_MINIPORT_ENABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0504)
1193 #define IOCTL_SCSI_MINIPORT_DISABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0505)
1194 #define IOCTL_SCSI_MINIPORT_RETURN_STATUS ((FILE_DEVICE_SCSI << 16) + 0x0506)
1195 #define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE ((FILE_DEVICE_SCSI << 16) + 0x0507)
1196 #define IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES ((FILE_DEVICE_SCSI << 16) + 0x0508)
1197 #define IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS ((FILE_DEVICE_SCSI << 16) + 0x0509)
1198 #define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE ((FILE_DEVICE_SCSI << 16) + 0x050a)
1199 #define IOCTL_SCSI_MINIPORT_READ_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050b)
1200 #define IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050c)
1201
1202 /////////////////////////////////////////////////////////////////////////////
1203
1204 static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, int datasize)
1205 {
1206 // Select code
1207 DWORD code = 0; const char * name = 0;
1208 if (regs->bCommandReg == ATA_IDENTIFY_DEVICE) {
1209 code = IOCTL_SCSI_MINIPORT_IDENTIFY; name = "IDENTIFY";
1210 }
1211 else if (regs->bCommandReg == ATA_SMART_CMD) switch (regs->bFeaturesReg) {
1212 case ATA_SMART_READ_VALUES:
1213 code = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS; name = "READ_SMART_ATTRIBS"; break;
1214 case ATA_SMART_READ_THRESHOLDS:
1215 code = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS; name = "READ_SMART_THRESHOLDS"; break;
1216 case ATA_SMART_ENABLE:
1217 code = IOCTL_SCSI_MINIPORT_ENABLE_SMART; name = "ENABLE_SMART"; break;
1218 case ATA_SMART_DISABLE:
1219 code = IOCTL_SCSI_MINIPORT_DISABLE_SMART; name = "DISABLE_SMART"; break;
1220 case ATA_SMART_STATUS:
1221 code = IOCTL_SCSI_MINIPORT_RETURN_STATUS; name = "RETURN_STATUS"; break;
1222 case ATA_SMART_AUTOSAVE:
1223 code = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE; name = "ENABLE_DISABLE_AUTOSAVE"; break;
1224 //case ATA_SMART_SAVE: // obsolete since ATA-6, not used by smartmontools
1225 // code = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES; name = "SAVE_ATTRIBUTE_VALUES"; break;
1226 case ATA_SMART_IMMEDIATE_OFFLINE:
1227 code = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS; name = "EXECUTE_OFFLINE_DIAGS"; break;
1228 case ATA_SMART_AUTO_OFFLINE:
1229 code = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE; name = "ENABLE_DISABLE_AUTO_OFFLINE"; break;
1230 case ATA_SMART_READ_LOG_SECTOR:
1231 code = IOCTL_SCSI_MINIPORT_READ_SMART_LOG; name = "READ_SMART_LOG"; break;
1232 case ATA_SMART_WRITE_LOG_SECTOR:
1233 code = IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG; name = "WRITE_SMART_LOG"; break;
1234 }
1235 if (!code) {
1236 errno = ENOSYS;
1237 return -1;
1238 }
1239
1240 // Set SRB
1241 struct {
1242 SRB_IO_CONTROL srbc;
1243 union {
1244 SENDCMDINPARAMS in;
1245 SENDCMDOUTPARAMS out;
1246 } params;
1247 char space[512-1];
1248 } sb;
1249 ASSERT_SIZEOF(sb, sizeof(SRB_IO_CONTROL)+sizeof(SENDCMDINPARAMS)-1+512);
1250 memset(&sb, 0, sizeof(sb));
1251
1252 unsigned size;
1253 if (datasize > 0) {
1254 if (datasize > (int)sizeof(sb.space)+1) {
1255 errno = EINVAL;
1256 return -1;
1257 }
1258 size = datasize;
1259 }
1260 else if (datasize < 0) {
1261 if (-datasize > (int)sizeof(sb.space)+1) {
1262 errno = EINVAL;
1263 return -1;
1264 }
1265 size = -datasize;
1266 memcpy(sb.params.in.bBuffer, data, size);
1267 }
1268 else if (code == IOCTL_SCSI_MINIPORT_RETURN_STATUS)
1269 size = sizeof(IDEREGS);
1270 else
1271 size = 0;
1272 sb.srbc.HeaderLength = sizeof(SRB_IO_CONTROL);
1273 memcpy(sb.srbc.Signature, "SCSIDISK", 8); // atapi.sys
1274 sb.srbc.Timeout = 60; // seconds
1275 sb.srbc.ControlCode = code;
1276 //sb.srbc.ReturnCode = 0;
1277 sb.srbc.Length = sizeof(SENDCMDINPARAMS)-1 + size;
1278 sb.params.in.irDriveRegs = *regs;
1279 sb.params.in.cBufferSize = size;
1280
1281 // Call miniport ioctl
1282 size += sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)-1;
1283 DWORD num_out;
1284 if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
1285 &sb, size, &sb, size, &num_out, NULL)) {
1286 long err = GetLastError();
1287 if (con->reportataioctl) {
1288 pout(" IOCTL_SCSI_MINIPORT_%s failed, Error=%ld\n", name, err);
1289 print_ide_regs_io(regs, NULL);
1290 }
1291 errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
1292 return -1;
1293 }
1294
1295 // Check result
1296 if (sb.srbc.ReturnCode) {
1297 if (con->reportataioctl) {
1298 pout(" IOCTL_SCSI_MINIPORT_%s failed, ReturnCode=0x%08lx\n", name, sb.srbc.ReturnCode);
1299 print_ide_regs_io(regs, NULL);
1300 }
1301 errno = EIO;
1302 return -1;
1303 }
1304
1305 if (sb.params.out.DriverStatus.bDriverError) {
1306 if (con->reportataioctl) {
1307 pout(" IOCTL_SCSI_MINIPORT_%s failed, DriverError=0x%02x, IDEError=0x%02x\n", name,
1308 sb.params.out.DriverStatus.bDriverError, sb.params.out.DriverStatus.bIDEError);
1309 print_ide_regs_io(regs, NULL);
1310 }
1311 errno = (!sb.params.out.DriverStatus.bIDEError ? ENOSYS : EIO);
1312 return -1;
1313 }
1314
1315 if (con->reportataioctl > 1) {
1316 pout(" IOCTL_SCSI_MINIPORT_%s suceeded, bytes returned: %lu (buffer %lu)\n", name,
1317 num_out, sb.params.out.cBufferSize);
1318 print_ide_regs_io(regs, (code == IOCTL_SCSI_MINIPORT_RETURN_STATUS ?
1319 (const IDEREGS *)(sb.params.out.bBuffer) : 0));
1320 }
1321
1322 if (datasize > 0)
1323 memcpy(data, sb.params.out.bBuffer, datasize);
1324 else if (datasize == 0 && code == IOCTL_SCSI_MINIPORT_RETURN_STATUS)
1325 *regs = *(const IDEREGS *)(sb.params.out.bBuffer);
1326
1327 return 0;
1328 }
1329
1330
1331 /////////////////////////////////////////////////////////////////////////////
1332
1333 // ATA PASS THROUGH via 3ware specific SCSI MINIPORT ioctl
1334
1335 static int ata_via_3ware_miniport_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, int datasize, int port)
1336 {
1337 struct {
1338 SRB_IO_CONTROL srbc;
1339 IDEREGS regs;
1340 UCHAR buffer[512];
1341 } sb;
1342 ASSERT_SIZEOF(sb, sizeof(SRB_IO_CONTROL)+sizeof(IDEREGS)+512);
1343
1344 if (!(0 <= datasize && datasize <= (int)sizeof(sb.buffer) && port >= 0)) {
1345 errno = EINVAL;
1346 return -1;
1347 }
1348 memset(&sb, 0, sizeof(sb));
1349 strcpy((char *)sb.srbc.Signature, "<3ware>");
1350 sb.srbc.HeaderLength = sizeof(SRB_IO_CONTROL);
1351 sb.srbc.Timeout = 60; // seconds
1352 sb.srbc.ControlCode = 0xA0000000;
1353 sb.srbc.ReturnCode = 0;
1354 sb.srbc.Length = sizeof(IDEREGS) + (datasize > 0 ? datasize : 1);
1355 sb.regs = *regs;
1356 sb.regs.bReserved = port;
1357
1358 DWORD num_out;
1359 if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
1360 &sb, sizeof(sb), &sb, sizeof(sb), &num_out, NULL)) {
1361 long err = GetLastError();
1362 if (con->reportataioctl) {
1363 pout(" ATA via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err);
1364 print_ide_regs_io(regs, NULL);
1365 }
1366 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
1367 return -1;
1368 }
1369
1370 if (sb.srbc.ReturnCode) {
1371 if (con->reportataioctl) {
1372 pout(" ATA via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08lx\n", sb.srbc.ReturnCode);
1373 print_ide_regs_io(regs, NULL);
1374 }
1375 errno = EIO;
1376 return -1;
1377 }
1378
1379 // Copy data
1380 if (datasize > 0)
1381 memcpy(data, sb.buffer, datasize);
1382
1383 if (con->reportataioctl > 1) {
1384 pout(" ATA via IOCTL_SCSI_MINIPORT suceeded, bytes returned: %lu\n", num_out);
1385 print_ide_regs_io(regs, &sb.regs);
1386 }
1387 *regs = sb.regs;
1388
1389 return 0;
1390 }
1391
1392
1393 /////////////////////////////////////////////////////////////////////////////
1394
1395 // 3ware specific call to update the devicemap returned by SMART_GET_VERSION.
1396 // 3DM/CLI "Rescan Controller" function does not to always update it.
1397
1398 static int update_3ware_devicemap_ioctl(HANDLE hdevice)
1399 {
1400 SRB_IO_CONTROL srbc;
1401 memset(&srbc, 0, sizeof(srbc));
1402 strcpy((char *)srbc.Signature, "<3ware>");
1403 srbc.HeaderLength = sizeof(SRB_IO_CONTROL);
1404 srbc.Timeout = 60; // seconds
1405 srbc.ControlCode = 0xCC010014;
1406 srbc.ReturnCode = 0;
1407 srbc.Length = 0;
1408
1409 DWORD num_out;
1410 if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
1411 &srbc, sizeof(srbc), &srbc, sizeof(srbc), &num_out, NULL)) {
1412 long err = GetLastError();
1413 if (con->reportataioctl)
1414 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err);
1415 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
1416 return -1;
1417 }
1418 if (srbc.ReturnCode) {
1419 if (con->reportataioctl)
1420 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08lx\n", srbc.ReturnCode);
1421 errno = EIO;
1422 return -1;
1423 }
1424 if (con->reportataioctl > 1)
1425 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT suceeded\n");
1426 return 0;
1427 }
1428
1429
1430
1431 /////////////////////////////////////////////////////////////////////////////
1432
1433 // Routines for pseudo device /dev/tw_cli/*
1434 // Parses output of 3ware "tw_cli /cx/py show all" or 3DM SMART data window
1435
1436
1437 // Get clipboard data
1438
1439 static int get_clipboard(char * data, int datasize)
1440 {
1441 if (!OpenClipboard(NULL))
1442 return -1;
1443 HANDLE h = GetClipboardData(CF_TEXT);
1444 if (!h) {
1445 CloseClipboard();
1446 return 0;
1447 }
1448 const void * p = GlobalLock(h);
1449 int n = GlobalSize(h);
1450 if (n > datasize)
1451 n = datasize;
1452 memcpy(data, p, n);
1453 GlobalFree(h);
1454 CloseClipboard();
1455 return n;
1456 }
1457
1458
1459 // Run a command, write stdout to dataout
1460 // TODO: Combine with daemon_win32.cpp:daemon_spawn()
1461
1462 static int run_cmd(const char * cmd, char * dataout, int outsize)
1463 {
1464 // Create stdout pipe
1465 SECURITY_ATTRIBUTES sa = {sizeof(sa), 0, TRUE};
1466 HANDLE pipe_out_w, h;
1467 if (!CreatePipe(&h, &pipe_out_w, &sa/*inherit*/, outsize))
1468 return -1;
1469 HANDLE self = GetCurrentProcess();
1470 HANDLE pipe_out_r;
1471 if (!DuplicateHandle(self, h, self, &pipe_out_r,
1472 GENERIC_READ, FALSE/*!inherit*/, DUPLICATE_CLOSE_SOURCE)) {
1473 CloseHandle(pipe_out_w);
1474 return -1;
1475 }
1476 HANDLE pipe_err_w;
1477 if (!DuplicateHandle(self, pipe_out_w, self, &pipe_err_w,
1478 0, TRUE/*inherit*/, DUPLICATE_SAME_ACCESS)) {
1479 CloseHandle(pipe_out_r); CloseHandle(pipe_out_w);
1480 return -1;
1481 }
1482
1483 // Create process
1484 STARTUPINFO si; memset(&si, 0, sizeof(si)); si.cb = sizeof(si);
1485 si.hStdInput = INVALID_HANDLE_VALUE;
1486 si.hStdOutput = pipe_out_w; si.hStdError = pipe_err_w;
1487 si.dwFlags = STARTF_USESTDHANDLES;
1488 PROCESS_INFORMATION pi;
1489 if (!CreateProcess(
1490 NULL, const_cast<char *>(cmd),
1491 NULL, NULL, TRUE/*inherit*/,
1492 CREATE_NO_WINDOW/*do not create a new console window*/,
1493 NULL, NULL, &si, &pi)) {
1494 CloseHandle(pipe_err_w); CloseHandle(pipe_out_r); CloseHandle(pipe_out_w);
1495 return -1;
1496 }
1497 CloseHandle(pi.hThread);
1498 CloseHandle(pipe_err_w); CloseHandle(pipe_out_w);
1499
1500 // Copy stdout to output buffer
1501 int i = 0;
1502 while (i < outsize) {
1503 DWORD num_read;
1504 if (!ReadFile(pipe_out_r, dataout+i, outsize-i, &num_read, NULL) || num_read == 0)
1505 break;
1506 i += num_read;
1507 }
1508 CloseHandle(pipe_out_r);
1509 // Wait for process
1510 WaitForSingleObject(pi.hProcess, INFINITE);
1511 CloseHandle(pi.hProcess);
1512 return i;
1513 }
1514
1515
1516 static const char * findstr(const char * str, const char * sub)
1517 {
1518 const char * s = strstr(str, sub);
1519 return (s ? s+strlen(sub) : "");
1520 }
1521
1522
1523 static void copy_swapped(unsigned char * dest, const char * src, int destsize)
1524 {
1525 int srclen = strcspn(src, "\r\n");
1526 int i;
1527 for (i = 0; i < destsize-1 && i < srclen-1; i+=2) {
1528 dest[i] = src[i+1]; dest[i+1] = src[i];
1529 }
1530 if (i < destsize-1 && i < srclen)
1531 dest[i+1] = src[i];
1532 }
1533
1534
1535 // TODO: This is OS independent
1536
1537 win_tw_cli_device::win_tw_cli_device(smart_interface * intf, const char * dev_name, const char * req_type)
1538 : smart_device(intf, dev_name, "tw_cli", req_type),
1539 m_ident_valid(false), m_smart_valid(false)
1540 {
1541 memset(&m_ident_buf, 0, sizeof(m_ident_buf));
1542 memset(&m_smart_buf, 0, sizeof(m_smart_buf));
1543 }
1544
1545
1546 bool win_tw_cli_device::is_open() const
1547 {
1548 return (m_ident_valid || m_smart_valid);
1549 }
1550
1551
1552 bool win_tw_cli_device::open()
1553 {
1554 m_ident_valid = m_smart_valid = false;
1555 const char * name = skipdev(get_dev_name());
1556 // Read tw_cli or 3DM browser output into buffer
1557 char buffer[4096];
1558 int size = -1, n1 = -1, n2 = -1;
1559 if (!strcmp(name, "tw_cli/clip")) { // read clipboard
1560 size = get_clipboard(buffer, sizeof(buffer));
1561 }
1562 else if (!strcmp(name, "tw_cli/stdin")) { // read stdin
1563 size = fread(buffer, 1, sizeof(buffer), stdin);
1564 }
1565 else if (sscanf(name, "tw_cli/%nc%*u/p%*u%n", &n1, &n2) >= 0 && n2 == (int)strlen(name)) {
1566 // tw_cli/cx/py => read output from "tw_cli /cx/py show all"
1567 char cmd[100];
1568 snprintf(cmd, sizeof(cmd), "tw_cli /%s show all", name+n1);
1569 if (con->reportataioctl > 1)
1570 pout("%s: Run: \"%s\"\n", name, cmd);
1571 size = run_cmd(cmd, buffer, sizeof(buffer));
1572 }
1573 else {
1574 return set_err(EINVAL);
1575 }
1576
1577 if (con->reportataioctl > 1)
1578 pout("%s: Read %d bytes\n", name, size);
1579 if (size <= 0)
1580 return set_err(ENOENT);
1581 if (size >= (int)sizeof(buffer))
1582 return set_err(EIO);
1583
1584 buffer[size] = 0;
1585 if (con->reportataioctl > 1)
1586 pout("[\n%.100s%s\n]\n", buffer, (size>100?"...":""));
1587
1588 // Fake identify sector
1589 ASSERT_SIZEOF(ata_identify_device, 512);
1590 ata_identify_device * id = &m_ident_buf;
1591 memset(id, 0, sizeof(*id));
1592 copy_swapped(id->model , findstr(buffer, " Model = " ), sizeof(id->model));
1593 copy_swapped(id->fw_rev , findstr(buffer, " Firmware Version = "), sizeof(id->fw_rev));
1594 copy_swapped(id->serial_no, findstr(buffer, " Serial = " ), sizeof(id->serial_no));
1595 unsigned long nblocks = 0; // "Capacity = N.N GB (N Blocks)"
1596 sscanf(findstr(buffer, "Capacity = "), "%*[^(\r\n](%lu", &nblocks);
1597 if (nblocks) {
1598 id->words047_079[49-47] = 0x0200; // size valid
1599 id->words047_079[60-47] = (unsigned short)(nblocks ); // secs_16
1600 id->words047_079[61-47] = (unsigned short)(nblocks>>16); // secs_32
1601 }
1602 id->major_rev_num = 0x1<<3; // ATA-3
1603 id->command_set_1 = 0x0001; id->command_set_2 = 0x4000; // SMART supported, words 82,83 valid
1604 id->cfs_enable_1 = 0x0001; id->csf_default = 0x4000; // SMART enabled, words 85,87 valid
1605
1606 // Parse smart data hex dump
1607 const char * s = findstr(buffer, "Drive Smart Data:");
1608 if (!*s) {
1609 s = findstr(buffer, "S.M.A.R.T. (Controller"); // from 3DM browser window
1610 if (*s) {
1611 const char * s1 = findstr(s, "<td class"); // html version
1612 if (*s1)
1613 s = s1;
1614 s += strcspn(s, "\r\n");
1615 }
1616 else
1617 s = buffer; // try raw hex dump without header
1618 }
1619 unsigned char * sd = (unsigned char *)&m_smart_buf;
1620 int i = 0;
1621 for (;;) {
1622 unsigned x = ~0; int n = -1;
1623 if (!(sscanf(s, "%x %n", &x, &n) == 1 && !(x & ~0xff)))
1624 break;
1625 sd[i] = (unsigned char)x;
1626 if (!(++i < 512 && n > 0))
1627 break;
1628 s += n;
1629 if (*s == '<') // "<br>"
1630 s += strcspn(s, "\r\n");
1631 }
1632 if (i < 512) {
1633 if (!id->model[1]) {
1634 // No useful data found
1635 char * err = strstr(buffer, "Error:");
1636 if (!err)
1637 err = strstr(buffer, "error :");
1638 if (err && (err = strchr(err, ':'))) {
1639 // Show tw_cli error message
1640 err++;
1641 err[strcspn(err, "\r\n")] = 0;
1642 return set_err(EIO, err);
1643 }
1644 return set_err(EIO);
1645 }
1646 sd = 0;
1647 }
1648
1649 m_ident_valid = true;
1650 m_smart_valid = !!sd;
1651 return true;
1652 }
1653
1654
1655 bool win_tw_cli_device::close()
1656 {
1657 m_ident_valid = m_smart_valid = false;
1658 return true;
1659 }
1660
1661
1662 int win_tw_cli_device::ata_command_interface(smart_command_set command, int /*select*/, char * data)
1663 {
1664 switch (command) {
1665 case IDENTIFY:
1666 if (!m_ident_valid)
1667 break;
1668 memcpy(data, &m_ident_buf, 512);
1669 return 0;
1670 case READ_VALUES:
1671 if (!m_smart_valid)
1672 break;
1673 memcpy(data, &m_smart_buf, 512);
1674 return 0;
1675 case READ_THRESHOLDS:
1676 if (!m_smart_valid)
1677 break;
1678 // Fake zero thresholds
1679 {
1680 const ata_smart_values * sv = &m_smart_buf;
1681 ata_smart_thresholds_pvt * tr = (ata_smart_thresholds_pvt *)data;
1682 memset(tr, 0, 512);
1683 // TODO: Indicate missing thresholds in ataprint.cpp:PrintSmartAttribWithThres()
1684 // (ATA_SMART_READ_THRESHOLDS is marked obsolete since ATA-5)
1685 for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++)
1686 tr->chksum -= tr->thres_entries[i].id = sv->vendor_attributes[i].id;
1687 }
1688 return 0;
1689 case ENABLE:
1690 case STATUS:
1691 case STATUS_CHECK: // Fake "good" SMART status
1692 return 0;
1693 default:
1694 break;
1695 }
1696 // Arrive here for all unsupported commands
1697 set_err(ENOSYS);
1698 return -1;
1699 }
1700
1701
1702 /////////////////////////////////////////////////////////////////////////////
1703
1704 // IOCTL_STORAGE_QUERY_PROPERTY
1705
1706 #define FILE_DEVICE_MASS_STORAGE 0x0000002d
1707 #define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE
1708 #define FILE_ANY_ACCESS 0
1709
1710 #define IOCTL_STORAGE_QUERY_PROPERTY \
1711 CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)
1712
1713 typedef enum _STORAGE_BUS_TYPE {
1714 BusTypeUnknown = 0x00,
1715 BusTypeScsi = 0x01,
1716 BusTypeAtapi = 0x02,
1717 BusTypeAta = 0x03,
1718 BusType1394 = 0x04,
1719 BusTypeSsa = 0x05,
1720 BusTypeFibre = 0x06,
1721 BusTypeUsb = 0x07,
1722 BusTypeRAID = 0x08,
1723 BusTypeiScsi = 0x09,
1724 BusTypeSas = 0x0A,
1725 BusTypeSata = 0x0B,
1726 BusTypeSd = 0x0C,
1727 BusTypeMmc = 0x0D,
1728 BusTypeMax = 0x0E,
1729 BusTypeMaxReserved = 0x7F
1730 } STORAGE_BUS_TYPE, *PSTORAGE_BUS_TYPE;
1731
1732 typedef struct _STORAGE_DEVICE_DESCRIPTOR {
1733 ULONG Version;
1734 ULONG Size;
1735 UCHAR DeviceType;
1736 UCHAR DeviceTypeModifier;
1737 BOOLEAN RemovableMedia;
1738 BOOLEAN CommandQueueing;
1739 ULONG VendorIdOffset;
1740 ULONG ProductIdOffset;
1741 ULONG ProductRevisionOffset;
1742 ULONG SerialNumberOffset;
1743 STORAGE_BUS_TYPE BusType;
1744 ULONG RawPropertiesLength;
1745 UCHAR RawDeviceProperties[1];
1746 } STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR;
1747
1748 typedef enum _STORAGE_QUERY_TYPE {
1749 PropertyStandardQuery = 0,
1750 PropertyExistsQuery,
1751 PropertyMaskQuery,
1752 PropertyQueryMaxDefined
1753 } STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE;
1754
1755 typedef enum _STORAGE_PROPERTY_ID {
1756 StorageDeviceProperty = 0,
1757 StorageAdapterProperty,
1758 StorageDeviceIdProperty,
1759 StorageDeviceUniqueIdProperty,
1760 StorageDeviceWriteCacheProperty,
1761 StorageMiniportProperty,
1762 StorageAccessAlignmentProperty
1763 } STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID;
1764
1765 typedef struct _STORAGE_PROPERTY_QUERY {
1766 STORAGE_PROPERTY_ID PropertyId;
1767 STORAGE_QUERY_TYPE QueryType;
1768 UCHAR AdditionalParameters[1];
1769 } STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY;
1770
1771
1772 /////////////////////////////////////////////////////////////////////////////
1773
1774 union STORAGE_DEVICE_DESCRIPTOR_DATA {
1775 STORAGE_DEVICE_DESCRIPTOR desc;
1776 char raw[256];
1777 };
1778
1779 // Get STORAGE_DEVICE_DESCRIPTOR_DATA for device.
1780 // (This works without admin rights)
1781
1782 static int storage_query_property_ioctl(HANDLE hdevice, STORAGE_DEVICE_DESCRIPTOR_DATA * data)
1783 {
1784 STORAGE_PROPERTY_QUERY query = {StorageDeviceProperty, PropertyStandardQuery, {0} };
1785 memset(data, 0, sizeof(*data));
1786
1787 DWORD num_out;
1788 if (!DeviceIoControl(hdevice, IOCTL_STORAGE_QUERY_PROPERTY,
1789 &query, sizeof(query), data, sizeof(*data), &num_out, NULL)) {
1790 if (con->reportataioctl > 1 || con->reportscsiioctl > 1)
1791 pout(" IOCTL_STORAGE_QUERY_PROPERTY failed, Error=%ld\n", GetLastError());
1792 errno = ENOSYS;
1793 return -1;
1794 }
1795
1796 if (con->reportataioctl > 1 || con->reportscsiioctl > 1) {
1797 pout(" IOCTL_STORAGE_QUERY_PROPERTY returns:\n"
1798 " Vendor: \"%s\"\n"
1799 " Product: \"%s\"\n"
1800 " Revision: \"%s\"\n"
1801 " Removable: %s\n"
1802 " BusType: 0x%02x\n",
1803 (data->desc.VendorIdOffset ? data->raw+data->desc.VendorIdOffset : ""),
1804 (data->desc.ProductIdOffset ? data->raw+data->desc.ProductIdOffset : ""),
1805 (data->desc.ProductRevisionOffset ? data->raw+data->desc.ProductRevisionOffset : ""),
1806 (data->desc.RemovableMedia? "Yes":"No"), data->desc.BusType
1807 );
1808 }
1809 return 0;
1810 }
1811
1812
1813 /////////////////////////////////////////////////////////////////////////////
1814
1815 // IOCTL_STORAGE_PREDICT_FAILURE
1816
1817 #define IOCTL_STORAGE_PREDICT_FAILURE \
1818 CTL_CODE(IOCTL_STORAGE_BASE, 0x0440, METHOD_BUFFERED, FILE_ANY_ACCESS)
1819
1820 typedef struct _STORAGE_PREDICT_FAILURE {
1821 ULONG PredictFailure;
1822 UCHAR VendorSpecific[512];
1823 } STORAGE_PREDICT_FAILURE, *PSTORAGE_PREDICT_FAILURE;
1824
1825 ASSERT_SIZEOF(STORAGE_PREDICT_FAILURE, 4+512);
1826
1827
1828 /////////////////////////////////////////////////////////////////////////////
1829
1830
1831 // Call IOCTL_STORAGE_PREDICT_FAILURE, return PredictFailure value
1832 // or -1 on error, opionally return VendorSpecific data.
1833 // (This works without admin rights)
1834
1835 static int storage_predict_failure_ioctl(HANDLE hdevice, char * data = 0)
1836 {
1837 STORAGE_PREDICT_FAILURE pred;
1838 memset(&pred, 0, sizeof(pred));
1839
1840 DWORD num_out;
1841 if (!DeviceIoControl(hdevice, IOCTL_STORAGE_PREDICT_FAILURE,
1842 0, 0, &pred, sizeof(pred), &num_out, NULL)) {
1843 if (con->reportataioctl > 1)
1844 pout(" IOCTL_STORAGE_PREDICT_FAILURE failed, Error=%ld\n", GetLastError());
1845 errno = ENOSYS;
1846 return -1;
1847 }
1848
1849 if (con->reportataioctl > 1) {
1850 pout(" IOCTL_STORAGE_PREDICT_FAILURE returns:\n"
1851 " PredictFailure: 0x%08lx\n"
1852 " VendorSpecific: 0x%02x,0x%02x,0x%02x,...,0x%02x\n",
1853 pred.PredictFailure,
1854 pred.VendorSpecific[0], pred.VendorSpecific[1], pred.VendorSpecific[2],
1855 pred.VendorSpecific[sizeof(pred.VendorSpecific)-1]
1856 );
1857 }
1858 if (data)
1859 memcpy(data, pred.VendorSpecific, sizeof(pred.VendorSpecific));
1860 return (!pred.PredictFailure ? 0 : 1);
1861 }
1862
1863
1864 /////////////////////////////////////////////////////////////////////////////
1865
1866 // get DEV_* for open handle
1867 static win_dev_type get_controller_type(HANDLE hdevice, bool admin, GETVERSIONINPARAMS_EX * ata_version_ex)
1868 {
1869 // Try SMART_GET_VERSION first to detect ATA SMART support
1870 // for drivers reporting BusTypeScsi (3ware)
1871 if (admin && smart_get_version(hdevice, ata_version_ex) >= 0)
1872 return DEV_ATA;
1873
1874 // Get BusType from device descriptor
1875 STORAGE_DEVICE_DESCRIPTOR_DATA data;
1876 if (storage_query_property_ioctl(hdevice, &data))
1877 return DEV_UNKNOWN;
1878
1879 switch (data.desc.BusType) {
1880 case BusTypeAta:
1881 case BusTypeSata:
1882 if (ata_version_ex)
1883 memset(ata_version_ex, 0, sizeof(*ata_version_ex));
1884 return DEV_ATA;
1885 case BusTypeScsi:
1886 case BusTypeiScsi:
1887 case BusTypeSas:
1888 return DEV_SCSI;
1889 case BusTypeUsb:
1890 return DEV_USB;
1891 default:
1892 return DEV_UNKNOWN;
1893 }
1894 /*NOTREACHED*/
1895 }
1896
1897 // get DEV_* for device path
1898 static win_dev_type get_controller_type(const char * path, GETVERSIONINPARAMS_EX * ata_version_ex = 0)
1899 {
1900 bool admin = true;
1901 HANDLE h = CreateFileA(path, GENERIC_READ|GENERIC_WRITE,
1902 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
1903 if (h == INVALID_HANDLE_VALUE) {
1904 admin = false;
1905 h = CreateFileA(path, 0,
1906 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
1907 if (h == INVALID_HANDLE_VALUE)
1908 return DEV_UNKNOWN;
1909 }
1910 if (con->reportataioctl > 1 || con->reportscsiioctl > 1)
1911 pout(" %s: successfully opened%s\n", path, (!admin ? " (without admin rights)" :""));
1912 win_dev_type type = get_controller_type(h, admin, ata_version_ex);
1913 CloseHandle(h);
1914 return type;
1915 }
1916
1917 // get DEV_* for physical drive number
1918 static win_dev_type get_phy_drive_type(int drive, GETVERSIONINPARAMS_EX * ata_version_ex)
1919 {
1920 char path[30];
1921 snprintf(path, sizeof(path)-1, "\\\\.\\PhysicalDrive%d", drive);
1922 return get_controller_type(path, ata_version_ex);
1923 }
1924
1925 static win_dev_type get_phy_drive_type(int drive)
1926 {
1927 return get_phy_drive_type(drive, 0);
1928 }
1929
1930 // get DEV_* for logical drive number
1931 static win_dev_type get_log_drive_type(int drive)
1932 {
1933 char path[30];
1934 snprintf(path, sizeof(path)-1, "\\\\.\\%c:", 'A'+drive);
1935 return get_controller_type(path);
1936 }
1937
1938 // Build IDENTIFY information from STORAGE_DEVICE_DESCRIPTOR
1939 static int get_identify_from_device_property(HANDLE hdevice, ata_identify_device * id)
1940 {
1941 STORAGE_DEVICE_DESCRIPTOR_DATA data;
1942 if (storage_query_property_ioctl(hdevice, &data))
1943 return -1;
1944
1945 memset(id, 0, sizeof(*id));
1946 if (data.desc.ProductIdOffset)
1947 copy_swapped(id->model, data.raw+data.desc.ProductIdOffset, sizeof(id->model));
1948 if (data.desc.ProductRevisionOffset)
1949 copy_swapped(id->fw_rev, data.raw+data.desc.ProductRevisionOffset, sizeof(id->fw_rev));
1950 id->major_rev_num = 0x1<<3; // ATA-3
1951 id->command_set_1 = 0x0001; id->command_set_2 = 0x4000; // SMART supported, words 82,83 valid
1952 id->cfs_enable_1 = 0x0001; id->csf_default = 0x4000; // SMART enabled, words 85,87 valid
1953 return 0;
1954 }
1955
1956
1957 /////////////////////////////////////////////////////////////////////////////
1958 // USB ID detection using WMI
1959
1960 // Run a command, split stdout into lines.
1961 // Return number of lines read, -1 on error.
1962 static int run_cmd(std::vector<std::string> & lines, const char * cmd, ...)
1963 {
1964 lines.clear();
1965
1966 va_list ap; va_start(ap, cmd);
1967 std::string cmdline = vstrprintf(cmd, ap);
1968 va_end(ap);
1969
1970 if (con->reportscsiioctl > 1)
1971 pout("Run: \"%s\"\n", cmdline.c_str());
1972
1973 char buffer[16*1024];
1974 int size = run_cmd(cmdline.c_str(), buffer, sizeof(buffer));
1975
1976 if (con->reportscsiioctl > 1)
1977 pout("Read %d bytes\n", size);
1978 if (!(0 < size && size < (int)sizeof(buffer)-1))
1979 return -1;
1980
1981 buffer[size] = 0;
1982
1983 for (int i = 0; buffer[i]; ) {
1984 int len = strcspn(buffer+i, "\r\n");
1985 lines.push_back(std::string(buffer+i, len));
1986 i += len;
1987 i += strspn(buffer+i, "\r\n");
1988 }
1989 if (con->reportscsiioctl > 1) {
1990 for (unsigned i = 0; i < lines.size(); i++)
1991 printf("'%s'\n", lines[i].c_str());
1992 }
1993 return lines.size();
1994 }
1995
1996 // Quote string for WMI
1997 static std::string wmi_quote(const char * s, int len)
1998 {
1999 std::string r;
2000 for (int i = 0; i < len; i++) {
2001 char c = s[i];
2002 if (c == '\\')
2003 r += '\\';
2004 r += c;
2005 }
2006 return r;
2007 }
2008
2009 // Get USB ID for a physical drive number
2010 static bool get_usb_id(int drive, unsigned short & vendor_id, unsigned short & product_id)
2011 {
2012 // Get device name
2013 std::vector<std::string> result;
2014 if (run_cmd(result,
2015 "wmic PATH Win32_DiskDrive WHERE DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\" GET Model",
2016 drive) != 2)
2017 return false;
2018
2019 std::string name = result[1];
2020
2021 // Get USB_CONTROLLER -> DEVICE associations
2022 std::vector<std::string> assoc;
2023 int n = run_cmd(assoc, "wmic PATH Win32_USBControllerDevice GET Antecedent,Dependent");
2024 if (n < 2)
2025 return false;
2026
2027 regular_expression regex("^([^ ]+) .*Win32_PnPEntity.DeviceID=\"(USBSTOR\\\\[^\"]*)\" *$",
2028 REG_EXTENDED);
2029 if (regex.empty()) // TODO: throw in constructor?
2030 return false;
2031
2032 int usbstoridx = -1;
2033 std::string usbcontr;
2034 for (int i = 2; i < n; i++) {
2035 // Find next 'USB_CONTROLLER USBSTORAGE_DEVICE' pair
2036 regmatch_t match[3];
2037 const char * s = assoc[i].c_str();
2038 if (!regex.execute(s, 3, match))
2039 continue;
2040
2041 // USBSTOR device found, compare Name
2042 if (run_cmd(result,
2043 "wmic PATH Win32_PnPEntity WHERE DeviceID=\"%s\" GET Name",
2044 wmi_quote(s + match[2].rm_so, match[2].rm_eo - match[2].rm_so).c_str()
2045 ) != 2)
2046 continue;
2047 if (result[1] != name)
2048 continue;
2049
2050 // Name must be uniqe
2051 if (usbstoridx >= 0)
2052 return false;
2053
2054 usbstoridx = i;
2055 usbcontr.assign(s + match[1].rm_so, match[1].rm_eo - match[1].rm_so);
2056 }
2057
2058 // Found ?
2059 if (usbstoridx <= 0)
2060 return false;
2061
2062 // The entry preceding USBSTOR should be the USB bridge device
2063 regex.compile("^([^ ]+) .*Win32_PnPEntity.DeviceID=\"USB\\\\VID_(....&PID_....)[^\"]*\" *$",
2064 REG_EXTENDED);
2065 if (regex.empty())
2066 return false;
2067 regmatch_t match[3];
2068 const char * s = assoc[usbstoridx-1].c_str();
2069 if (!regex.execute(s, 3, match))
2070 return false;
2071
2072 // Both devices must be associated to same controller
2073 if (usbcontr != std::string(s + match[1].rm_so, match[1].rm_eo - match[1].rm_so))
2074 return false;
2075
2076 // Parse USB ID
2077 int nc = -1;
2078 if (!(sscanf(s + match[2].rm_so, "%4hx&PID_%4hx%n",
2079 &vendor_id, &product_id, &nc) == 2 && nc == 4+5+4))
2080 return false;
2081
2082 if (con->reportscsiioctl > 1)
2083 pout("USB ID = 0x%04x:0x%04x\n", vendor_id, product_id);
2084 return true;
2085 }
2086
2087
2088 /////////////////////////////////////////////////////////////////////////////
2089
2090 // Call GetDevicePowerState() if available (Win98/ME/2000/XP/2003)
2091 // returns: 1=active, 0=standby, -1=error
2092 // (This would also work for SCSI drives)
2093
2094 static int get_device_power_state(HANDLE hdevice)
2095 {
2096 static HINSTANCE h_kernel_dll = 0;
2097 #ifdef __CYGWIN__
2098 static DWORD kernel_dll_pid = 0;
2099 #endif
2100 static BOOL (WINAPI * GetDevicePowerState_p)(HANDLE, BOOL *) = 0;
2101
2102 BOOL state = TRUE;
2103
2104 if (!GetDevicePowerState_p
2105 #ifdef __CYGWIN__
2106 || kernel_dll_pid != GetCurrentProcessId() // detect fork()
2107 #endif
2108 ) {
2109 if (h_kernel_dll == INVALID_HANDLE_VALUE) {
2110 errno = ENOSYS;
2111 return -1;
2112 }
2113 if (!(h_kernel_dll = LoadLibraryA("KERNEL32.DLL"))) {
2114 pout("Cannot load KERNEL32.DLL, Error=%ld\n", GetLastError());
2115 h_kernel_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
2116 errno = ENOSYS;
2117 return -1;
2118 }
2119 if (!(GetDevicePowerState_p = (BOOL (WINAPI *)(HANDLE, BOOL *))
2120 GetProcAddress(h_kernel_dll, "GetDevicePowerState"))) {
2121 if (con->reportataioctl)
2122 pout(" GetDevicePowerState() not found, Error=%ld\n", GetLastError());
2123 FreeLibrary(h_kernel_dll);
2124 h_kernel_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
2125 errno = ENOSYS;
2126 return -1;
2127 }
2128 #ifdef __CYGWIN__
2129 kernel_dll_pid = GetCurrentProcessId();
2130 #endif
2131 }
2132
2133 if (!GetDevicePowerState_p(hdevice, &state)) {
2134 long err = GetLastError();
2135 if (con->reportataioctl)
2136 pout(" GetDevicePowerState() failed, Error=%ld\n", err);
2137 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
2138 // TODO: This may not work as expected on transient errors,
2139 // because smartd interprets -1 as SLEEP mode regardless of errno.
2140 return -1;
2141 }
2142
2143 if (con->reportataioctl > 1)
2144 pout(" GetDevicePowerState() succeeded, state=%d\n", state);
2145 return state;
2146 }
2147
2148
2149 /////////////////////////////////////////////////////////////////////////////
2150
2151 // Print SMARTVSD error message, return errno
2152
2153 static int smartvsd_error()
2154 {
2155 char path[MAX_PATH];
2156 unsigned len;
2157 if (!(5 <= (len = GetSystemDirectoryA(path, MAX_PATH)) && len < MAX_PATH/2))
2158 return ENOENT;
2159 // SMARTVSD.VXD present?
2160 strcpy(path+len, "\\IOSUBSYS\\SMARTVSD.VXD");
2161 if (!access(path, 0)) {
2162 // Yes, standard IDE driver used?
2163 HANDLE h;
2164 if ( (h = CreateFileA("\\\\.\\ESDI_506",
2165 GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
2166 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE
2167 && GetLastError() == ERROR_FILE_NOT_FOUND ) {
2168 pout("Standard IDE driver ESDI_506.PDR not used, or no IDE/ATA drives present.\n");
2169 return ENOENT;
2170 }
2171 else {
2172 if (h != INVALID_HANDLE_VALUE) // should not happen
2173 CloseHandle(h);
2174 pout("SMART driver SMARTVSD.VXD is installed, but not loaded.\n");
2175 return ENOSYS;
2176 }
2177 }
2178 else {
2179 strcpy(path+len, "\\SMARTVSD.VXD");
2180 if (!access(path, 0)) {
2181 // Some Windows versions install SMARTVSD.VXD in SYSTEM directory
2182 // (http://support.microsoft.com/kb/265854/en-us).
2183 path[len] = 0;
2184 pout("SMART driver is not properly installed,\n"
2185 " move SMARTVSD.VXD from \"%s\" to \"%s\\IOSUBSYS\"\n"
2186 " and reboot Windows.\n", path, path);
2187 }
2188 else {
2189 // Some Windows versions do not provide SMARTVSD.VXD
2190 // (http://support.microsoft.com/kb/199886/en-us).
2191 path[len] = 0;
2192 pout("SMARTVSD.VXD is missing in folder \"%s\\IOSUBSYS\".\n", path);
2193 }
2194 return ENOSYS;
2195 }
2196 }
2197
2198
2199 // Get default ATA device options
2200
2201 static const char * ata_get_def_options()
2202 {
2203 DWORD ver = GetVersion();
2204 if ((ver & 0x80000000) || (ver & 0xff) < 4) // Win9x/ME
2205 return "s"; // SMART_* only
2206 else if ((ver & 0xff) == 4) // WinNT4
2207 return "sc"; // SMART_*, SCSI_PASS_THROUGH
2208 else // WinXP, 2003, Vista
2209 return "pasifm"; // GetDevicePowerState(), ATA_, SMART_*, IDE_PASS_THROUGH,
2210 // STORAGE_*, SCSI_MINIPORT_*
2211 }
2212
2213
2214 // Common routines for devices with HANDLEs
2215
2216 win_smart_device::~win_smart_device() throw()
2217 {
2218 if (m_fh != INVALID_HANDLE_VALUE)
2219 ::CloseHandle(m_fh);
2220 }
2221
2222 bool win_smart_device::is_open() const
2223 {
2224 return (m_fh != INVALID_HANDLE_VALUE);
2225 }
2226
2227 bool win_smart_device::close()
2228 {
2229 if (m_fh == INVALID_HANDLE_VALUE)
2230 return true;
2231 BOOL rc = ::CloseHandle(m_fh);
2232 m_fh = INVALID_HANDLE_VALUE;
2233 return !!rc;
2234 }
2235
2236 // ATA
2237
2238 win_ata_device::win_ata_device(smart_interface * intf, const char * dev_name, const char * req_type)
2239 : smart_device(intf, dev_name, "ata", req_type),
2240 m_usr_options(false),
2241 m_admin(false),
2242 m_drive(0),
2243 m_port(-1),
2244 m_smartver_state(0)
2245 {
2246 }
2247
2248 win_ata_device::~win_ata_device() throw()
2249 {
2250 }
2251
2252
2253 // Open ATA device
2254
2255 bool win_ata_device::open()
2256 {
2257 const char * name = skipdev(get_dev_name()); int len = strlen(name);
2258 // [sh]d[a-z](:[saicmfp]+)? => Physical drive 0-25, with options
2259 char drive[1+1] = "", options[8+1] = ""; int n1 = -1, n2 = -1;
2260 if ( sscanf(name, "%*[sh]d%1[a-z]%n:%7[saicmfp]%n", drive, &n1, options, &n2) >= 1
2261 && ((n1 == len && !options[0]) || n2 == len) ) {
2262 return open(drive[0] - 'a', -1, options, -1);
2263 }
2264 // [sh]d[a-z],N(:[saicmfp3]+)? => Physical drive 0-25, RAID port N, with options
2265 drive[0] = 0; options[0] = 0; n1 = -1; n2 = -1;
2266 unsigned port = ~0;
2267 if ( sscanf(name, "%*[sh]d%1[a-z],%u%n:%8[saicmfp3]%n", drive, &port, &n1, options, &n2) >= 2
2268 && port < 32 && ((n1 == len && !options[0]) || n2 == len) ) {
2269 return open(drive[0] - 'a', -1, options, port);
2270 }
2271 // pd<m>,N => Physical drive <m>, RAID port N
2272 int phydrive = -1; port = ~0; n1 = -1; n2 = -1;
2273 if ( sscanf(name, "pd%d%n,%u%n", &phydrive, &n1, &port, &n2) >= 1
2274 && phydrive >= 0 && ((n1 == len && (int)port < 0) || (n2 == len && port < 32))) {
2275 return open(phydrive, -1, "", (int)port);
2276 }
2277 // [a-zA-Z]: => Physical drive behind logical drive 0-25
2278 int logdrive = drive_letter(name);
2279 if (logdrive >= 0) {
2280 return open(-1, logdrive, "", -1);
2281 }
2282
2283 return set_err(EINVAL);
2284 }
2285
2286
2287 bool win_ata_device::open(int phydrive, int logdrive, const char * options, int port)
2288 {
2289 // path depends on Windows Version
2290 bool win9x = is_win9x(); // TODO: Member variable
2291 char devpath[30];
2292 if (win9x && 0 <= phydrive && phydrive <= 7)
2293 // Use patched "smartvse.vxd" for drives 4-7, see INSTALL file for details
2294 strcpy(devpath, (phydrive <= 3 ? "\\\\.\\SMARTVSD" : "\\\\.\\SMARTVSE"));
2295 else if (!win9x && 0 <= phydrive && phydrive <= 255)
2296 snprintf(devpath, sizeof(devpath)-1, "\\\\.\\PhysicalDrive%d", phydrive);
2297 else if (!win9x && 0 <= logdrive && logdrive <= 'Z'-'A')
2298 snprintf(devpath, sizeof(devpath)-1, "\\\\.\\%c:", 'A'+logdrive);
2299 else
2300 return set_err(ENOENT);
2301
2302 // Open device
2303 HANDLE h = INVALID_HANDLE_VALUE;
2304 if (win9x || !(*options && !options[strspn(options, "fp")])) {
2305 // Open with admin rights
2306 m_admin = true;
2307 h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,
2308 FILE_SHARE_READ|FILE_SHARE_WRITE,
2309 NULL, OPEN_EXISTING, 0, 0);
2310 }
2311 if (!win9x && h == INVALID_HANDLE_VALUE) {
2312 // Open without admin rights
2313 m_admin = false;
2314 h = CreateFileA(devpath, 0,
2315 FILE_SHARE_READ|FILE_SHARE_WRITE,
2316 NULL, OPEN_EXISTING, 0, 0);
2317 }
2318 if (h == INVALID_HANDLE_VALUE) {
2319 long err = GetLastError();
2320 pout("Cannot open device %s, Error=%ld\n", devpath, err);
2321 if (err == ERROR_FILE_NOT_FOUND)
2322 set_err((win9x && phydrive <= 3 ? smartvsd_error() : ENOENT), "%s: not found", devpath);
2323 else if (err == ERROR_ACCESS_DENIED)
2324 set_err(EACCES, "%s: access denied", devpath);
2325 else
2326 set_err(EIO, "%s: Error=%ld", devpath, err);
2327 return false;
2328 }
2329 set_fh(h);
2330
2331 if (con->reportataioctl > 1)
2332 pout("%s: successfully opened%s\n", devpath, (!m_admin ? " (without admin rights)" :""));
2333
2334 m_usr_options = false;
2335 if (*options) {
2336 // Save user options
2337 m_options = options; m_usr_options = true;
2338 }
2339 else if (port >= 0)
2340 // RAID: SMART_* and SCSI_MINIPORT
2341 m_options = "s3";
2342 else {
2343 // Set default options according to Windows version
2344 static const char * def_options = ata_get_def_options();
2345 m_options = def_options;
2346 }
2347
2348 // NT4/2000/XP: SMART_GET_VERSION may spin up disk, so delay until first real SMART_* call
2349 m_drive = 0; m_port = port;
2350 if (!win9x && port < 0)
2351 return true;
2352
2353 // Win9X/ME: Get drive map
2354 // RAID: Get port map
2355 GETVERSIONINPARAMS_EX vers_ex;
2356 int devmap = smart_get_version(h, (port >= 0 ? &vers_ex : 0));
2357
2358 unsigned long portmap = 0;
2359 if (port >= 0 && devmap >= 0) {
2360 // 3ware RAID: check vendor id
2361 if (vers_ex.wIdentifier != SMART_VENDOR_3WARE) {
2362 pout("SMART_GET_VERSION returns unknown Identifier = %04x\n"
2363 "This is no 3ware 9000 controller or driver has no SMART support.\n",
2364 vers_ex.wIdentifier);
2365 devmap = -1;
2366 }
2367 else
2368 portmap = vers_ex.dwDeviceMapEx;
2369 }
2370 if (devmap < 0) {
2371 pout("%s: ATA driver has no SMART support\n", devpath);
2372 if (!is_permissive()) {
2373 close();
2374 return set_err(ENOSYS);
2375 }
2376 devmap = 0x0f;
2377 }
2378 m_smartver_state = 1;
2379
2380 if (port >= 0) {
2381 // 3ware RAID: update devicemap first
2382
2383 if (!update_3ware_devicemap_ioctl(h)) {
2384 if ( smart_get_version(h, &vers_ex) >= 0
2385 && vers_ex.wIdentifier == SMART_VENDOR_3WARE )
2386 portmap = vers_ex.dwDeviceMapEx;
2387 }
2388 // Check port existence
2389 if (!(portmap & (1L << port))) {
2390 if (!is_permissive()) {
2391 close();
2392 return set_err(ENOENT, "%s: Port %d is empty or does not exist", devpath, port);
2393 }
2394 }
2395 return true;
2396 }
2397
2398 // Win9x/ME: Check device presence & type
2399 if (((devmap >> (phydrive & 0x3)) & 0x11) != 0x01) {
2400 unsigned char atapi = (devmap >> (phydrive & 0x3)) & 0x10;
2401 // Win9x drive existence check may not work as expected
2402 // The atapi.sys driver incorrectly fills in the bIDEDeviceMap with 0x01
2403 // (The related KB Article Q196120 is no longer available)
2404 if (!is_permissive()) {
2405 close();
2406 return set_err((atapi ? ENOSYS : ENOENT), "%s: Drive %d %s (IDEDeviceMap=0x%02x)",
2407 devpath, phydrive, (atapi?"is an ATAPI device":"does not exist"), devmap);
2408 }
2409 }
2410 // Drive number must be passed to ioctl
2411 m_drive = (phydrive & 0x3);
2412 return true;
2413 }
2414
2415
2416 // Scan for ATA drives on Win9x/ME
2417
2418 bool win9x_smart_interface::ata_scan(smart_device_list & devlist)
2419 {
2420 // Open device
2421 const char devpath[] = "\\\\.\\SMARTVSD";
2422 HANDLE h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,
2423 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
2424 if (h == INVALID_HANDLE_VALUE) {
2425 if (con->reportataioctl > 1)
2426 pout(" %s: Open failed, Error=%ld\n", devpath, GetLastError());
2427 return true; // SMARTVSD.VXD missing or no ATA devices
2428 }
2429
2430 // Get drive map
2431 int devmap = smart_get_version(h);
2432 CloseHandle(h);
2433 if (devmap < 0)
2434 return true; // Should not happen
2435
2436 // Check ATA device presence, remove ATAPI devices
2437 devmap = (devmap & 0xf) & ~((devmap >> 4) & 0xf);
2438 char name[20];
2439 for (int i = 0; i < 4; i++) {
2440 if (!(devmap & (1 << i)))
2441 continue;
2442 sprintf(name, "/dev/hd%c", 'a'+i);
2443 devlist.add( new win_ata_device(this, name, "ata") );
2444 }
2445 return true;
2446 }
2447
2448
2449 // Scan for ATA drives
2450
2451 bool winnt_smart_interface::ata_scan(smart_device_list & devlist)
2452 {
2453 const int max_raid = 2;
2454 bool raid_seen[max_raid] = {false, false};
2455
2456 char name[20];
2457 for (int i = 0; i <= 9; i++) {
2458 GETVERSIONINPARAMS_EX vers_ex;
2459 if (get_phy_drive_type(i, &vers_ex) != DEV_ATA)
2460 continue;
2461
2462 // Interpret RAID drive map if present
2463 if (vers_ex.wIdentifier == SMART_VENDOR_3WARE) {
2464 // Skip if more than 2 controllers or logical drive from this controller already seen
2465 if (vers_ex.wControllerId >= max_raid || raid_seen[vers_ex.wControllerId])
2466 continue;
2467 raid_seen[vers_ex.wControllerId] = true;
2468 // Add physical drives
2469 for (int pi = 0; pi < 32; pi++) {
2470 if (vers_ex.dwDeviceMapEx & (1L << pi)) {
2471 sprintf(name, "/dev/sd%c,%u", 'a'+i, pi);
2472 devlist.add( new win_ata_device(this, name, "ata") );
2473 }
2474 }
2475 continue;
2476 }
2477
2478 // Driver supports SMART_GET_VERSION or STORAGE_QUERY_PROPERTY returns ATA/SATA
2479 sprintf(name, "/dev/sd%c", 'a'+i);
2480 devlist.add( new win_ata_device(this, name, "ata") );
2481 }
2482
2483 return true;
2484 }
2485
2486
2487 /////////////////////////////////////////////////////////////////////////////
2488
2489 // Interface to ATA devices
2490 bool win_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
2491 {
2492 // No multi-sector support for now, see above
2493 // warning about IOCTL_ATA_PASS_THROUGH
2494 if (!ata_cmd_is_ok(in,
2495 true, // data_out_support
2496 false, // !multi_sector_support
2497 true) // ata_48bit_support
2498 )
2499 return false;
2500
2501 // Determine ioctl functions valid for this ATA cmd
2502 const char * valid_options = 0;
2503
2504 switch (in.in_regs.command) {
2505 case ATA_IDENTIFY_DEVICE:
2506 case ATA_IDENTIFY_PACKET_DEVICE:
2507 // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
2508 // and SCSI_MINIPORT_* if requested by user
2509 valid_options = (m_usr_options ? "saicmf" : "saicf");
2510 break;
2511
2512 case ATA_CHECK_POWER_MODE:
2513 // Try GetDevicePowerState() first, ATA/IDE_PASS_THROUGH may spin up disk
2514 valid_options = "pai3";
2515 break;
2516
2517 case ATA_SMART_CMD:
2518 switch (in.in_regs.features) {
2519 case ATA_SMART_READ_VALUES:
2520 case ATA_SMART_READ_THRESHOLDS:
2521 case ATA_SMART_AUTOSAVE:
2522 case ATA_SMART_ENABLE:
2523 case ATA_SMART_DISABLE:
2524 case ATA_SMART_AUTO_OFFLINE:
2525 // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
2526 // and SCSI_MINIPORT_* if requested by user
2527 valid_options = (m_usr_options ? "saicmf" : "saicf");
2528 break;
2529
2530 case ATA_SMART_IMMEDIATE_OFFLINE:
2531 // SMART_SEND_DRIVE_COMMAND supports ABORT_SELF_TEST only on Win9x/ME
2532 valid_options = (m_usr_options || in.in_regs.lba_low != 127/*ABORT*/ || is_win9x() ?
2533 "saicm3" : "aicm3");
2534 break;
2535
2536 case ATA_SMART_READ_LOG_SECTOR:
2537 // SMART_RCV_DRIVE_DATA supports this only on Win9x/ME
2538 // Try SCSI_MINIPORT also to skip buggy class driver
2539 // SMART functions do not support multi sector I/O.
2540 if (in.size == 512)
2541 valid_options = (m_usr_options || is_win9x() ? "saicm3" : "aicm3");
2542 else
2543 valid_options = "a";
2544 break;
2545
2546 case ATA_SMART_WRITE_LOG_SECTOR:
2547 // ATA_PASS_THROUGH, SCSI_MINIPORT, others don't support DATA_OUT
2548 // but SCSI_MINIPORT_* only if requested by user and single sector.
2549 valid_options = (in.size == 512 && m_usr_options ? "am" : "a");
2550 break;
2551
2552 case ATA_SMART_STATUS:
2553 // May require lba_mid,lba_high register return
2554 if (in.out_needed.is_set())
2555 valid_options = (m_usr_options ? "saimf" : "saif");
2556 else
2557 valid_options = (m_usr_options ? "saicmf" : "saicf");
2558 break;
2559
2560 default:
2561 // Unknown SMART command, handle below
2562 break;
2563 }
2564 break;
2565
2566 default:
2567 // Other ATA command, handle below
2568 break;
2569 }
2570
2571 if (!valid_options) {
2572 // No special ATA command found above, select a generic pass through ioctl.
2573 if (!( in.direction == ata_cmd_in::no_data
2574 || (in.direction == ata_cmd_in::data_in && in.size == 512))
2575 || in.in_regs.is_48bit_cmd() )
2576 // DATA_OUT, more than one sector, 48-bit command: ATA_PASS_THROUGH only
2577 valid_options = "a";
2578 else if (in.out_needed.is_set())
2579 // Need output registers: ATA/IDE_PASS_THROUGH
2580 valid_options = "ai";
2581 else
2582 valid_options = "aic";
2583 }
2584
2585 if (!m_admin) {
2586 // Restrict to IOCTL_STORAGE_*
2587 if (strchr(valid_options, 'f'))
2588 valid_options = "f";
2589 else if (strchr(valid_options, 'p'))
2590 valid_options = "p";
2591 else
2592 return set_err(ENOSYS, "Function requires admin rights");
2593 }
2594
2595 // Set IDEREGS
2596 IDEREGS regs, prev_regs;
2597 {
2598 const ata_in_regs & lo = in.in_regs;
2599 regs.bFeaturesReg = lo.features;
2600 regs.bSectorCountReg = lo.sector_count;
2601 regs.bSectorNumberReg = lo.lba_low;
2602 regs.bCylLowReg = lo.lba_mid;
2603 regs.bCylHighReg = lo.lba_high;
2604 regs.bDriveHeadReg = lo.device;
2605 regs.bCommandReg = lo.command;
2606 regs.bReserved = 0;
2607 }
2608 if (in.in_regs.is_48bit_cmd()) {
2609 const ata_in_regs & hi = in.in_regs.prev;
2610 prev_regs.bFeaturesReg = hi.features;
2611 prev_regs.bSectorCountReg = hi.sector_count;
2612 prev_regs.bSectorNumberReg = hi.lba_low;
2613 prev_regs.bCylLowReg = hi.lba_mid;
2614 prev_regs.bCylHighReg = hi.lba_high;
2615 prev_regs.bDriveHeadReg = hi.device;
2616 prev_regs.bCommandReg = hi.command;
2617 prev_regs.bReserved = 0;
2618 }
2619
2620 // Set data direction
2621 int datasize = 0;
2622 char * data = 0;
2623 switch (in.direction) {
2624 case ata_cmd_in::no_data:
2625 break;
2626 case ata_cmd_in::data_in:
2627 datasize = (int)in.size;
2628 data = (char *)in.buffer;
2629 break;
2630 case ata_cmd_in::data_out:
2631 datasize = -(int)in.size;
2632 data = (char *)in.buffer;
2633 break;
2634 default:
2635 return set_err(EINVAL, "win_ata_device::ata_pass_through: invalid direction=%d",
2636 (int)in.direction);
2637 }
2638
2639
2640 // Try all valid ioctls in the order specified in m_options
2641 bool powered_up = false;
2642 bool out_regs_set = false;
2643 const char * options = m_options.c_str();
2644
2645 for (int i = 0; ; i++) {
2646 char opt = options[i];
2647
2648 if (!opt) {
2649 if (in.in_regs.command == ATA_CHECK_POWER_MODE && powered_up) {
2650 // Power up reported by GetDevicePowerState() and no ioctl available
2651 // to detect the actual mode of the drive => simulate ATA result ACTIVE/IDLE.
2652 regs.bSectorCountReg = 0xff;
2653 out_regs_set = true;
2654 break;
2655 }
2656 // No IOCTL found
2657 return set_err(ENOSYS);
2658 }
2659 if (!strchr(valid_options, opt))
2660 // Invalid for this command
2661 continue;
2662
2663 errno = 0;
2664 assert( datasize == 0 || datasize == 512
2665 || (datasize == -512 && strchr("am", opt))
2666 || (datasize > 512 && opt == 'a'));
2667 int rc;
2668 switch (opt) {
2669 default: assert(0);
2670 case 's':
2671 // call SMART_GET_VERSION once for each drive
2672 if (m_smartver_state > 1) {
2673 rc = -1; errno = ENOSYS;
2674 break;
2675 }
2676 if (!m_smartver_state) {
2677 assert(m_port == -1);
2678 if (smart_get_version(get_fh()) < 0) {
2679 if (!con->permissive) {
2680 m_smartver_state = 2;
2681 rc = -1; errno = ENOSYS;
2682 break;
2683 }
2684 con->permissive--;
2685 }
2686 m_smartver_state = 1;
2687 }
2688 rc = smart_ioctl(get_fh(), m_drive, &regs, data, datasize, m_port);
2689 out_regs_set = (in.in_regs.features == ATA_SMART_STATUS);
2690 break;
2691 case 'm':
2692 rc = ata_via_scsi_miniport_smart_ioctl(get_fh(), &regs, data, datasize);
2693 break;
2694 case 'a':
2695 rc = ata_pass_through_ioctl(get_fh(), &regs,
2696 (in.in_regs.is_48bit_cmd() ? &prev_regs : 0),
2697 data, datasize);
2698 out_regs_set = true;
2699 break;
2700 case 'i':
2701 rc = ide_pass_through_ioctl(get_fh(), &regs, data, datasize);
2702 out_regs_set = true;
2703 break;
2704 case 'c':
2705 rc = ata_via_scsi_pass_through_ioctl(get_fh(), &regs, data, datasize);
2706 break;
2707 case 'f':
2708 if (in.in_regs.command == ATA_IDENTIFY_DEVICE) {
2709 rc = get_identify_from_device_property(get_fh(), (ata_identify_device *)data);
2710 }
2711 else if (in.in_regs.command == ATA_SMART_CMD) switch (in.in_regs.features) {
2712 case ATA_SMART_READ_VALUES:
2713 rc = storage_predict_failure_ioctl(get_fh(), data);
2714 if (rc > 0)
2715 rc = 0;
2716 break;
2717 case ATA_SMART_READ_THRESHOLDS:
2718 {
2719 ata_smart_values sv;
2720 rc = storage_predict_failure_ioctl(get_fh(), (char *)&sv);
2721 if (rc < 0)
2722 break;
2723 rc = 0;
2724 // Fake zero thresholds
2725 ata_smart_thresholds_pvt * tr = (ata_smart_thresholds_pvt *)data;
2726 memset(tr, 0, 512);
2727 for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++)
2728 tr->chksum -= tr->thres_entries[i].id = sv.vendor_attributes[i].id;
2729 }
2730 break;
2731 case ATA_SMART_ENABLE:
2732 rc = 0;
2733 break;
2734 case ATA_SMART_STATUS:
2735 rc = storage_predict_failure_ioctl(get_fh());
2736 if (rc >= 0) {
2737 if (rc > 0) {
2738 regs.bCylHighReg = 0x2c; regs.bCylLowReg = 0xf4;
2739 rc = 0;
2740 }
2741 out_regs_set = true;
2742 }
2743 break;
2744 default:
2745 errno = ENOSYS; rc = -1;
2746 }
2747 else {
2748 errno = ENOSYS; rc = -1;
2749 }
2750 break;
2751 case '3':
2752 rc = ata_via_3ware_miniport_ioctl(get_fh(), &regs, data, datasize, m_port);
2753 out_regs_set = true;
2754 break;
2755 case 'p':
2756 assert(in.in_regs.command == ATA_CHECK_POWER_MODE && in.size == 0);
2757 rc = get_device_power_state(get_fh());
2758 if (rc == 0) {
2759 // Power down reported by GetDevicePowerState(), using a passthrough ioctl would
2760 // spin up the drive => simulate ATA result STANDBY.
2761 regs.bSectorCountReg = 0x00;
2762 out_regs_set = true;
2763 }
2764 else if (rc > 0) {
2765 // Power up reported by GetDevicePowerState(), but this reflects the actual mode
2766 // only if it is selected by the device driver => try a passthrough ioctl to get the
2767 // actual mode, if none available simulate ACTIVE/IDLE.
2768 powered_up = true;
2769 rc = -1; errno = ENOSYS;
2770 }
2771 break;
2772 }
2773
2774 if (!rc)
2775 // Working ioctl found
2776 break;
2777
2778 if (errno != ENOSYS)
2779 // Abort on I/O error
2780 return set_err(errno);
2781
2782 out_regs_set = false;
2783 // CAUTION: *_ioctl() MUST NOT change "regs" Parameter in the ENOSYS case
2784 }
2785
2786 // Return IDEREGS if set
2787 if (out_regs_set) {
2788 ata_out_regs & lo = out.out_regs;
2789 lo.error = regs.bFeaturesReg;
2790 lo.sector_count = regs.bSectorCountReg;
2791 lo.lba_low = regs.bSectorNumberReg;
2792 lo.lba_mid = regs.bCylLowReg;
2793 lo.lba_high = regs.bCylHighReg;
2794 lo.device = regs.bDriveHeadReg;
2795 lo.status = regs.bCommandReg;
2796 if (in.in_regs.is_48bit_cmd()) {
2797 ata_out_regs & hi = out.out_regs.prev;
2798 hi.sector_count = prev_regs.bSectorCountReg;
2799 hi.lba_low = prev_regs.bSectorNumberReg;
2800 hi.lba_mid = prev_regs.bCylLowReg;
2801 hi.lba_high = prev_regs.bCylHighReg;
2802 }
2803 }
2804 return true;
2805 }
2806
2807 // Return true if OS caches the ATA identify sector
2808 bool win_ata_device::ata_identify_is_cached() const
2809 {
2810 // Not RAID and WinNT4/2000/XP => true, RAID or Win9x/ME => false
2811 // TODO: Set according to ioctl used.
2812 return (m_port < 0 && !is_win9x());
2813 }
2814
2815
2816 /////////////////////////////////////////////////////////////////////////////
2817 // ASPI Interface (for SCSI devices)
2818 /////////////////////////////////////////////////////////////////////////////
2819
2820 #pragma pack(1)
2821
2822 #define ASPI_SENSE_SIZE 18
2823
2824 // ASPI SCSI Request block header
2825
2826 typedef struct {
2827 unsigned char cmd; // 00: Command code
2828 unsigned char status; // 01: ASPI status
2829 unsigned char adapter; // 02: Host adapter number
2830 unsigned char flags; // 03: Request flags
2831 unsigned char reserved[4]; // 04: 0
2832 } ASPI_SRB_HEAD;
2833
2834 // SRB for host adapter inquiry
2835
2836 typedef struct {
2837 ASPI_SRB_HEAD h; // 00: Header
2838 unsigned char adapters; // 08: Number of adapters
2839 unsigned char target_id; // 09: Target ID ?
2840 char manager_id[16]; // 10: SCSI manager ID
2841 char adapter_id[16]; // 26: Host adapter ID
2842 unsigned char parameters[16]; // 42: Host adapter unique parmameters
2843 } ASPI_SRB_INQUIRY;
2844
2845 // SRB for get device type
2846
2847 typedef struct {
2848 ASPI_SRB_HEAD h; // 00: Header
2849 unsigned char target_id; // 08: Target ID
2850 unsigned char lun; // 09: LUN
2851 unsigned char devtype; // 10: Device type
2852 unsigned char reserved; // 11: Reserved
2853 } ASPI_SRB_DEVTYPE;
2854
2855 // SRB for SCSI I/O
2856
2857 typedef struct {
2858 ASPI_SRB_HEAD h; // 00: Header
2859 unsigned char target_id; // 08: Target ID
2860 unsigned char lun; // 09: LUN
2861 unsigned char reserved[2]; // 10: Reserved
2862 unsigned long data_size; // 12: Data alloc. lenght
2863 void * data_addr; // 16: Data buffer pointer
2864 unsigned char sense_size; // 20: Sense alloc. length
2865 unsigned char cdb_size; // 21: CDB length
2866 unsigned char host_status; // 22: Host status
2867 unsigned char target_status; // 23: Target status
2868 void * event_handle; // 24: Event handle
2869 unsigned char workspace[20]; // 28: ASPI workspace
2870 unsigned char cdb[16+ASPI_SENSE_SIZE];
2871 } ASPI_SRB_IO;
2872
2873 // Macro to retrieve start of sense information
2874 #define ASPI_SRB_SENSE(srb,cdbsz) ((srb)->cdb + 16)
2875
2876 // SRB union
2877
2878 typedef union {
2879 ASPI_SRB_HEAD h; // Common header
2880 ASPI_SRB_INQUIRY q; // Inquiry
2881 ASPI_SRB_DEVTYPE t; // Device type
2882 ASPI_SRB_IO i; // I/O
2883 } ASPI_SRB;
2884
2885 #pragma pack()
2886
2887 // ASPI commands
2888 #define ASPI_CMD_ADAPTER_INQUIRE 0x00
2889 #define ASPI_CMD_GET_DEVICE_TYPE 0x01
2890 #define ASPI_CMD_EXECUTE_IO 0x02
2891 #define ASPI_CMD_ABORT_IO 0x03
2892
2893 // Request flags
2894 #define ASPI_REQFLAG_DIR_TO_HOST 0x08
2895 #define ASPI_REQFLAG_DIR_TO_TARGET 0x10
2896 #define ASPI_REQFLAG_DIR_NO_XFER 0x18
2897 #define ASPI_REQFLAG_EVENT_NOTIFY 0x40
2898
2899 // ASPI status
2900 #define ASPI_STATUS_IN_PROGRESS 0x00
2901 #define ASPI_STATUS_NO_ERROR 0x01
2902 #define ASPI_STATUS_ABORTED 0x02
2903 #define ASPI_STATUS_ABORT_ERR 0x03
2904 #define ASPI_STATUS_ERROR 0x04
2905 #define ASPI_STATUS_INVALID_COMMAND 0x80
2906 #define ASPI_STATUS_INVALID_ADAPTER 0x81
2907 #define ASPI_STATUS_INVALID_TARGET 0x82
2908 #define ASPI_STATUS_NO_ADAPTERS 0xE8
2909
2910 // Adapter (host) status
2911 #define ASPI_HSTATUS_NO_ERROR 0x00
2912 #define ASPI_HSTATUS_SELECTION_TIMEOUT 0x11
2913 #define ASPI_HSTATUS_DATA_OVERRUN 0x12
2914 #define ASPI_HSTATUS_BUS_FREE 0x13
2915 #define ASPI_HSTATUS_BUS_PHASE_ERROR 0x14
2916 #define ASPI_HSTATUS_BAD_SGLIST 0x1A
2917
2918 // Target status
2919 #define ASPI_TSTATUS_NO_ERROR 0x00
2920 #define ASPI_TSTATUS_CHECK_CONDITION 0x02
2921 #define ASPI_TSTATUS_BUSY 0x08
2922 #define ASPI_TSTATUS_RESERV_CONFLICT 0x18
2923
2924
2925 static HINSTANCE h_aspi_dll; // DLL handle
2926 static UINT (* aspi_entry)(ASPI_SRB * srb); // ASPI entrypoint
2927 static unsigned num_aspi_adapters;
2928
2929 #ifdef __CYGWIN__
2930 // h_aspi_dll+aspi_entry is not inherited by Cygwin's fork()
2931 static DWORD aspi_dll_pid; // PID of DLL owner to detect fork()
2932 #define aspi_entry_valid() (aspi_entry && (aspi_dll_pid == GetCurrentProcessId()))
2933 #else
2934 #define aspi_entry_valid() (!!aspi_entry)
2935 #endif
2936
2937
2938 static int aspi_call(ASPI_SRB * srb)
2939 {
2940 int i;
2941 aspi_entry(srb);
2942 i = 0;
2943 while (((volatile ASPI_SRB *)srb)->h.status == ASPI_STATUS_IN_PROGRESS) {
2944 if (++i > 100/*10sek*/) {
2945 pout("ASPI Adapter %u: Timed out\n", srb->h.adapter);
2946 aspi_entry = 0;
2947 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
2948 errno = EIO;
2949 return -1;
2950 }
2951 if (con->reportscsiioctl > 1)
2952 pout("ASPI Adapter %u: Waiting (%d) ...\n", srb->h.adapter, i);
2953 Sleep(100);
2954 }
2955 return 0;
2956 }
2957
2958
2959 // Get ASPI entrypoint from wnaspi32.dll
2960
2961 static FARPROC aspi_get_address(const char * name, int verbose)
2962 {
2963 FARPROC addr;
2964 assert(h_aspi_dll && h_aspi_dll != INVALID_HANDLE_VALUE);
2965
2966 if (!(addr = GetProcAddress(h_aspi_dll, name))) {
2967 if (verbose)
2968 pout("Missing %s() in WNASPI32.DLL\n", name);
2969 aspi_entry = 0;
2970 FreeLibrary(h_aspi_dll);
2971 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
2972 errno = ENOSYS;
2973 return 0;
2974 }
2975 return addr;
2976 }
2977
2978
2979 static int aspi_open_dll(int verbose)
2980 {
2981 UINT (*aspi_info)(void);
2982 UINT info, rc;
2983
2984 assert(!aspi_entry_valid());
2985
2986 // Check structure layout
2987 assert(sizeof(ASPI_SRB_HEAD) == 8);
2988 assert(sizeof(ASPI_SRB_INQUIRY) == 58);
2989 assert(sizeof(ASPI_SRB_DEVTYPE) == 12);
2990 assert(sizeof(ASPI_SRB_IO) == 64+ASPI_SENSE_SIZE);
2991 assert(offsetof(ASPI_SRB,h.cmd) == 0);
2992 assert(offsetof(ASPI_SRB,h.flags) == 3);
2993 assert(offsetof(ASPI_SRB_IO,lun) == 9);
2994 assert(offsetof(ASPI_SRB_IO,data_addr) == 16);
2995 assert(offsetof(ASPI_SRB_IO,workspace) == 28);
2996 assert(offsetof(ASPI_SRB_IO,cdb) == 48);
2997
2998 if (h_aspi_dll == INVALID_HANDLE_VALUE) {
2999 // do not retry
3000 errno = ENOENT;
3001 return -1;
3002 }
3003
3004 // Load ASPI DLL
3005 if (!(h_aspi_dll = LoadLibraryA("WNASPI32.DLL"))) {
3006 if (verbose)
3007 pout("Cannot load WNASPI32.DLL, Error=%ld\n", GetLastError());
3008 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
3009 errno = ENOENT;
3010 return -1;
3011 }
3012 if (con->reportscsiioctl > 1) {
3013 // Print full path of WNASPI32.DLL
3014 char path[MAX_PATH];
3015 if (!GetModuleFileName(h_aspi_dll, path, sizeof(path)))
3016 strcpy(path, "*unknown*");
3017 pout("Using ASPI interface \"%s\"\n", path);
3018 }
3019
3020 // Get ASPI entrypoints
3021 if (!(aspi_info = (UINT (*)(void))aspi_get_address("GetASPI32SupportInfo", verbose)))
3022 return -1;
3023 if (!(aspi_entry = (UINT (*)(ASPI_SRB *))aspi_get_address("SendASPI32Command", verbose)))
3024 return -1;
3025
3026 // Init ASPI manager and get number of adapters
3027 info = (aspi_info)();
3028 if (con->reportscsiioctl > 1)
3029 pout("GetASPI32SupportInfo() returns 0x%04x\n", info);
3030 rc = (info >> 8) & 0xff;
3031 if (rc == ASPI_STATUS_NO_ADAPTERS) {
3032 num_aspi_adapters = 0;
3033 }
3034 else if (rc == ASPI_STATUS_NO_ERROR) {
3035 num_aspi_adapters = info & 0xff;
3036 }
3037 else {
3038 if (verbose)
3039 pout("Got strange 0x%04x from GetASPI32SupportInfo()\n", info);
3040 aspi_entry = 0;
3041 FreeLibrary(h_aspi_dll);
3042 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
3043 errno = ENOENT;
3044 return -1;
3045 }
3046
3047 if (con->reportscsiioctl)
3048 pout("%u ASPI Adapter%s detected\n",num_aspi_adapters, (num_aspi_adapters!=1?"s":""));
3049
3050 #ifdef __CYGWIN__
3051 // save PID to detect fork() in aspi_entry_valid()
3052 aspi_dll_pid = GetCurrentProcessId();
3053 #endif
3054 assert(aspi_entry_valid());
3055 return 0;
3056 }
3057
3058
3059 static int aspi_io_call(ASPI_SRB * srb, unsigned timeout)
3060 {
3061 HANDLE event;
3062 // Create event
3063 if (!(event = CreateEventA(NULL, FALSE, FALSE, NULL))) {
3064 pout("CreateEvent(): Error=%ld\n", GetLastError()); return -EIO;
3065 }
3066 srb->i.event_handle = event;
3067 srb->h.flags |= ASPI_REQFLAG_EVENT_NOTIFY;
3068 // Start ASPI request
3069 aspi_entry(srb);
3070 if (((volatile ASPI_SRB *)srb)->h.status == ASPI_STATUS_IN_PROGRESS) {
3071 // Wait for event
3072 DWORD rc = WaitForSingleObject(event, timeout*1000L);
3073 if (rc != WAIT_OBJECT_0) {
3074 if (rc == WAIT_TIMEOUT) {
3075 pout("ASPI Adapter %u, ID %u: Timed out after %u seconds\n",
3076 srb->h.adapter, srb->i.target_id, timeout);
3077 }
3078 else {
3079 pout("WaitForSingleObject(%lx) = 0x%lx,%ld, Error=%ld\n",
3080 (unsigned long)event, rc, rc, GetLastError());
3081 }
3082 // TODO: ASPI_ABORT_IO command
3083 aspi_entry = 0;
3084 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
3085 return -EIO;
3086 }
3087 }
3088 CloseHandle(event);
3089 return 0;
3090 }
3091
3092
3093 win_aspi_device::win_aspi_device(smart_interface * intf,
3094 const char * dev_name, const char * req_type)
3095 : smart_device(intf, dev_name, "scsi", req_type),
3096 m_adapter(-1), m_id(0)
3097 {
3098 }
3099
3100 bool win_aspi_device::is_open() const
3101 {
3102 return (m_adapter >= 0);
3103 }
3104
3105 bool win_aspi_device::open()
3106 {
3107 // scsi[0-9][0-f] => ASPI Adapter 0-9, ID 0-15, LUN 0
3108 unsigned adapter = ~0, id = ~0; int n1 = -1;
3109 const char * name = skipdev(get_dev_name());
3110 if (!(sscanf(name,"scsi%1u%1x%n", &adapter, &id, &n1) == 2 && n1 == (int)strlen(name)
3111 && adapter <= 9 && id < 16))
3112 return set_err(EINVAL);
3113
3114 if (!aspi_entry_valid()) {
3115 if (aspi_open_dll(1/*verbose*/))
3116 return set_err(ENOENT);
3117 }
3118
3119 // Adapter OK?
3120 if (adapter >= num_aspi_adapters) {
3121 pout("ASPI Adapter %u does not exist (%u Adapter%s detected).\n",
3122 adapter, num_aspi_adapters, (num_aspi_adapters!=1?"s":""));
3123 if (!is_permissive())
3124 return set_err(ENOENT);
3125 }
3126
3127 // Device present ?
3128 ASPI_SRB srb;
3129 memset(&srb, 0, sizeof(srb));
3130 srb.h.cmd = ASPI_CMD_GET_DEVICE_TYPE;
3131 srb.h.adapter = adapter; srb.i.target_id = id;
3132 if (aspi_call(&srb))
3133 return set_err(EIO);
3134 if (srb.h.status != ASPI_STATUS_NO_ERROR) {
3135 pout("ASPI Adapter %u, ID %u: No such device (Status=0x%02x)\n", adapter, id, srb.h.status);
3136 if (!is_permissive())
3137 return set_err(srb.h.status == ASPI_STATUS_INVALID_TARGET ? ENOENT : EIO);
3138 }
3139 else if (con->reportscsiioctl)
3140 pout("ASPI Adapter %u, ID %u: Device Type=0x%02x\n", adapter, id, srb.t.devtype);
3141
3142 m_adapter = (int)adapter; m_id = (unsigned char)id;
3143 return true;
3144 }
3145
3146
3147 bool win_aspi_device::close()
3148 {
3149 // No FreeLibrary(h_aspi_dll) to prevent problems with ASPI threads
3150 return true;
3151 }
3152
3153
3154 // Scan for ASPI drives
3155
3156 bool win9x_smart_interface::scsi_scan(smart_device_list & devlist)
3157 {
3158 if (!aspi_entry_valid()) {
3159 if (aspi_open_dll(con->reportscsiioctl/*default is quiet*/))
3160 return true;
3161 }
3162
3163 for (unsigned ad = 0; ad < num_aspi_adapters; ad++) {
3164 ASPI_SRB srb;
3165
3166 if (ad > 9) {
3167 if (con->reportscsiioctl)
3168 pout(" ASPI Adapter %u: Ignored\n", ad);
3169 continue;
3170 }
3171
3172 // Get adapter name
3173 memset(&srb, 0, sizeof(srb));
3174 srb.h.cmd = ASPI_CMD_ADAPTER_INQUIRE;
3175 srb.h.adapter = ad;
3176 if (aspi_call(&srb))
3177 break;
3178
3179 if (srb.h.status != ASPI_STATUS_NO_ERROR) {
3180 if (con->reportscsiioctl)
3181 pout(" ASPI Adapter %u: Status=0x%02x\n", ad, srb.h.status);
3182 continue;
3183 }
3184
3185 if (con->reportscsiioctl) {
3186 for (int i = 1; i < 16 && srb.q.adapter_id[i]; i++)
3187 if (!(' ' <= srb.q.adapter_id[i] && srb.q.adapter_id[i] <= '~'))
3188 srb.q.adapter_id[i] = '?';
3189 pout(" ASPI Adapter %u (\"%.16s\"):\n", ad, srb.q.adapter_id);
3190 }
3191
3192 bool ignore = !strnicmp(srb.q.adapter_id, "3ware", 5);
3193
3194 for (unsigned id = 0; id <= 7; id++) {
3195 // Get device type
3196 memset(&srb, 0, sizeof(srb));
3197 srb.h.cmd = ASPI_CMD_GET_DEVICE_TYPE;
3198 srb.h.adapter = ad; srb.i.target_id = id;
3199 if (aspi_call(&srb))
3200 return 0;
3201 if (srb.h.status != ASPI_STATUS_NO_ERROR) {
3202 if (con->reportscsiioctl > 1)
3203 pout(" ID %u: No such device (Status=0x%02x)\n", id, srb.h.status);
3204 continue;
3205 }
3206
3207 if (!ignore && srb.t.devtype == 0x00/*HDD*/) {
3208 if (con->reportscsiioctl)
3209 pout(" ID %u: Device Type=0x%02x\n", id, srb.t.devtype);
3210 char name[20];
3211 sprintf(name, "/dev/scsi%u%u", ad, id);
3212 devlist.add( new win_aspi_device(this, name, "scsi") );
3213 }
3214 else if (con->reportscsiioctl)
3215 pout(" ID %u: Device Type=0x%02x (ignored)\n", id, srb.t.devtype);
3216 }
3217 }
3218 return true;
3219 }
3220
3221
3222 // Interface to ASPI SCSI devices
3223 bool win_aspi_device::scsi_pass_through(scsi_cmnd_io * iop)
3224 {
3225 int report = con->reportscsiioctl; // TODO
3226
3227 if (m_adapter < 0) {
3228 set_err(EBADF);
3229 return false;
3230 }
3231
3232 if (!aspi_entry_valid()) {
3233 set_err(EBADF);
3234 return false;
3235 }
3236
3237 if (!(iop->cmnd_len == 6 || iop->cmnd_len == 10 || iop->cmnd_len == 12 || iop->cmnd_len == 16)) {
3238 set_err(EINVAL, "bad CDB length");
3239 return false;
3240 }
3241
3242 if (report > 0) {
3243 // From os_linux.c
3244 int k, j;
3245 const unsigned char * ucp = iop->cmnd;
3246 const char * np;
3247 char buff[256];
3248 const int sz = (int)sizeof(buff);
3249
3250 np = scsi_get_opcode_name(ucp[0]);
3251 j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
3252 for (k = 0; k < (int)iop->cmnd_len; ++k)
3253 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);
3254 if ((report > 1) &&
3255 (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
3256 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
3257
3258 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing "
3259 "data, len=%d%s:\n", (int)iop->dxfer_len,
3260 (trunc ? " [only first 256 bytes shown]" : ""));
3261 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
3262 }
3263 else
3264 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
3265 pout(buff);
3266 }
3267
3268 ASPI_SRB srb;
3269 memset(&srb, 0, sizeof(srb));
3270 srb.h.cmd = ASPI_CMD_EXECUTE_IO;
3271 srb.h.adapter = m_adapter;
3272 srb.i.target_id = m_id;
3273 //srb.i.lun = 0;
3274 srb.i.sense_size = ASPI_SENSE_SIZE;
3275 srb.i.cdb_size = iop->cmnd_len;
3276 memcpy(srb.i.cdb, iop->cmnd, iop->cmnd_len);
3277
3278 switch (iop->dxfer_dir) {
3279 case DXFER_NONE:
3280 srb.h.flags = ASPI_REQFLAG_DIR_NO_XFER;
3281 break;
3282 case DXFER_FROM_DEVICE:
3283 srb.h.flags = ASPI_REQFLAG_DIR_TO_HOST;
3284 srb.i.data_size = iop->dxfer_len;
3285 srb.i.data_addr = iop->dxferp;
3286 break;
3287 case DXFER_TO_DEVICE:
3288 srb.h.flags = ASPI_REQFLAG_DIR_TO_TARGET;
3289 srb.i.data_size = iop->dxfer_len;
3290 srb.i.data_addr = iop->dxferp;
3291 break;
3292 default:
3293 set_err(EINVAL, "bad dxfer_dir");
3294 return false;
3295 }
3296
3297 iop->resp_sense_len = 0;
3298 iop->scsi_status = 0;
3299 iop->resid = 0;
3300
3301 if (aspi_io_call(&srb, (iop->timeout ? iop->timeout : 60))) {
3302 // Timeout
3303 set_err(EIO, "ASPI Timeout"); return false;
3304 }
3305
3306 if (srb.h.status != ASPI_STATUS_NO_ERROR) {
3307 if ( srb.h.status == ASPI_STATUS_ERROR
3308 && srb.i.host_status == ASPI_HSTATUS_NO_ERROR
3309 && srb.i.target_status == ASPI_TSTATUS_CHECK_CONDITION) {
3310 // Sense valid
3311 const unsigned char * sense = ASPI_SRB_SENSE(&srb.i, iop->cmnd_len);
3312 int len = (ASPI_SENSE_SIZE < iop->max_sense_len ? ASPI_SENSE_SIZE : iop->max_sense_len);
3313 iop->scsi_status = SCSI_STATUS_CHECK_CONDITION;
3314 if (len > 0 && iop->sensep) {
3315 memcpy(iop->sensep, sense, len);
3316 iop->resp_sense_len = len;
3317 if (report > 1) {
3318 pout(" >>> Sense buffer, len=%d:\n", (int)len);
3319 dStrHex(iop->sensep, len , 1);
3320 }
3321 }
3322 if (report) {
3323 pout(" sense_key=%x asc=%x ascq=%x\n",
3324 sense[2] & 0xf, sense[12], sense[13]);
3325 }
3326 return true;
3327 }
3328 else {
3329 if (report)
3330 pout(" ASPI call failed, (0x%02x,0x%02x,0x%02x)\n", srb.h.status, srb.i.host_status, srb.i.target_status);
3331 set_err(EIO);
3332 return false;
3333 }
3334 }
3335
3336 if (report > 0)
3337 pout(" OK\n");
3338
3339 if (iop->dxfer_dir == DXFER_FROM_DEVICE && report > 1) {
3340 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
3341 pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
3342 (trunc ? " [only first 256 bytes shown]" : ""));
3343 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
3344 }
3345
3346 return true;
3347 }
3348
3349
3350 /////////////////////////////////////////////////////////////////////////////
3351 // SPT Interface (for SCSI devices and ATA devices behind SATLs)
3352 // Only supported in NT and later
3353 /////////////////////////////////////////////////////////////////////////////
3354
3355 win_scsi_device::win_scsi_device(smart_interface * intf,
3356 const char * dev_name, const char * req_type)
3357 : smart_device(intf, dev_name, "scsi", req_type)
3358 {
3359 }
3360
3361 bool win_scsi_device::open()
3362 {
3363 const char * name = skipdev(get_dev_name()); int len = strlen(name);
3364 // sd[a-z],N => Physical drive 0-26, RAID port N
3365 char drive[1+1] = ""; int sub_addr = -1; int n1 = -1; int n2 = -1;
3366 if ( sscanf(name, "sd%1[a-z]%n,%d%n", drive, &n1, &sub_addr, &n2) >= 1
3367 && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0)) ) {
3368 return open(drive[0] - 'a', -1, -1, sub_addr);
3369 }
3370 // pd<m>,N => Physical drive <m>, RAID port N
3371 int pd_num = -1; sub_addr = -1; n1 = -1; n2 = -1;
3372 if ( sscanf(name, "pd%d%n,%d%n", &pd_num, &n1, &sub_addr, &n2) >= 1
3373 && pd_num >= 0 && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0))) {
3374 return open(pd_num, -1, -1, sub_addr);
3375 }
3376 // [a-zA-Z]: => Physical drive behind logical drive 0-25
3377 int logdrive = drive_letter(name);
3378 if (logdrive >= 0) {
3379 return open(-1, logdrive, -1, -1);
3380 }
3381 // n?st<m> => tape drive <m> (same names used in Cygwin's /dev emulation)
3382 int tape_num = -1; n1 = -1;
3383 if (sscanf(name, "st%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) {
3384 return open(-1, -1, tape_num, -1);
3385 }
3386 tape_num = -1; n1 = -1;
3387 if (sscanf(name, "nst%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) {
3388 return open(-1, -1, tape_num, -1);
3389 }
3390 // tape<m> => tape drive <m>
3391 tape_num = -1; n1 = -1;
3392 if (sscanf(name, "tape%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) {
3393 return open(-1, -1, tape_num, -1);
3394 }
3395
3396 return set_err(EINVAL);
3397 }
3398
3399 bool win_scsi_device::open(int pd_num, int ld_num, int tape_num, int /*sub_addr*/)
3400 {
3401 char b[128];
3402 b[sizeof(b) - 1] = '\0';
3403 if (pd_num >= 0)
3404 snprintf(b, sizeof(b) - 1, "\\\\.\\PhysicalDrive%d", pd_num);
3405 else if (ld_num >= 0)
3406 snprintf(b, sizeof(b) - 1, "\\\\.\\%c:", 'A' + ld_num);
3407 else if (tape_num >= 0)
3408 snprintf(b, sizeof(b) - 1, "\\\\.\\TAPE%d", tape_num);
3409 else {
3410 set_err(EINVAL);
3411 return false;
3412 }
3413
3414 // Open device
3415 HANDLE h = CreateFileA(b, GENERIC_READ|GENERIC_WRITE,
3416 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
3417 OPEN_EXISTING, 0, 0);
3418 if (h == INVALID_HANDLE_VALUE) {
3419 set_err(ENODEV, "%s: Open failed, Error=%ld", b, GetLastError());
3420 return false;
3421 }
3422 set_fh(h);
3423 return true;
3424 }
3425
3426
3427 bool winnt_smart_interface::scsi_scan(smart_device_list & devlist)
3428 {
3429 char name[20];
3430 for (int i = 0; i <= 9; i++) {
3431 if (get_phy_drive_type(i) != DEV_SCSI)
3432 continue;
3433 // STORAGE_QUERY_PROPERTY returned SCSI/SAS/...
3434 sprintf(name, "/dev/sd%c", 'a'+i);
3435 devlist.add( new win_scsi_device(this, name, "scsi") );
3436 }
3437 return true;
3438 }
3439
3440
3441 #define IOCTL_SCSI_PASS_THROUGH_DIRECT \
3442 CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
3443
3444 typedef struct _SCSI_PASS_THROUGH_DIRECT {
3445 USHORT Length;
3446 UCHAR ScsiStatus;
3447 UCHAR PathId;
3448 UCHAR TargetId;
3449 UCHAR Lun;
3450 UCHAR CdbLength;
3451 UCHAR SenseInfoLength;
3452 UCHAR DataIn;
3453 ULONG DataTransferLength;
3454 ULONG TimeOutValue;
3455 PVOID DataBuffer;
3456 ULONG SenseInfoOffset;
3457 UCHAR Cdb[16];
3458 } SCSI_PASS_THROUGH_DIRECT;
3459
3460 typedef struct {
3461 SCSI_PASS_THROUGH_DIRECT spt;
3462 ULONG Filler;
3463 UCHAR ucSenseBuf[64];
3464 } SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
3465
3466
3467 // Issue command via IOCTL_SCSI_PASS_THROUGH instead of *_DIRECT.
3468 // Used if DataTransferLength not supported by *_DIRECT.
3469 static long scsi_pass_through_indirect(HANDLE h,
3470 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER * sbd)
3471 {
3472 struct SCSI_PASS_THROUGH_WITH_BUFFERS {
3473 SCSI_PASS_THROUGH spt;
3474 ULONG Filler;
3475 UCHAR ucSenseBuf[sizeof(sbd->ucSenseBuf)];
3476 UCHAR ucDataBuf[512];
3477 };
3478
3479 SCSI_PASS_THROUGH_WITH_BUFFERS sb;
3480 memset(&sb, 0, sizeof(sb));
3481
3482 // DATA_OUT not implemented yet
3483 if (!( sbd->spt.DataIn == SCSI_IOCTL_DATA_IN
3484 && sbd->spt.DataTransferLength <= sizeof(sb.ucDataBuf)))
3485 return ERROR_INVALID_PARAMETER;
3486
3487 sb.spt.Length = sizeof(sb.spt);
3488 sb.spt.CdbLength = sbd->spt.CdbLength;
3489 memcpy(sb.spt.Cdb, sbd->spt.Cdb, sizeof(sb.spt.Cdb));
3490 sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf);
3491 sb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf);
3492 sb.spt.DataIn = sbd->spt.DataIn;
3493 sb.spt.DataTransferLength = sbd->spt.DataTransferLength;
3494 sb.spt.DataBufferOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf);
3495 sb.spt.TimeOutValue = sbd->spt.TimeOutValue;
3496
3497 DWORD num_out;
3498 if (!DeviceIoControl(h, IOCTL_SCSI_PASS_THROUGH,
3499 &sb, sizeof(sb), &sb, sizeof(sb), &num_out, 0))
3500 return GetLastError();
3501
3502 sbd->spt.ScsiStatus = sb.spt.ScsiStatus;
3503 if (sb.spt.ScsiStatus & SCSI_STATUS_CHECK_CONDITION)
3504 memcpy(sbd->ucSenseBuf, sb.ucSenseBuf, sizeof(sbd->ucSenseBuf));
3505
3506 sbd->spt.DataTransferLength = sb.spt.DataTransferLength;
3507 if (sbd->spt.DataIn == SCSI_IOCTL_DATA_IN && sb.spt.DataTransferLength > 0)
3508 memcpy(sbd->spt.DataBuffer, sb.ucDataBuf, sb.spt.DataTransferLength);
3509 return 0;
3510 }
3511
3512
3513 // Interface to SPT SCSI devices. See scsicmds.h and os_linux.c
3514 bool win_scsi_device::scsi_pass_through(struct scsi_cmnd_io * iop)
3515 {
3516 int report = con->reportscsiioctl; // TODO
3517
3518 if (report > 0) {
3519 int k, j;
3520 const unsigned char * ucp = iop->cmnd;
3521 const char * np;
3522 char buff[256];
3523 const int sz = (int)sizeof(buff);
3524
3525 np = scsi_get_opcode_name(ucp[0]);
3526 j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
3527 for (k = 0; k < (int)iop->cmnd_len; ++k)
3528 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);
3529 if ((report > 1) &&
3530 (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
3531 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
3532
3533 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing "
3534 "data, len=%d%s:\n", (int)iop->dxfer_len,
3535 (trunc ? " [only first 256 bytes shown]" : ""));
3536 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
3537 }
3538 else
3539 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
3540 pout(buff);
3541 }
3542
3543 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb;
3544 if (iop->cmnd_len > (int)sizeof(sb.spt.Cdb)) {
3545 set_err(EINVAL, "cmnd_len too large");
3546 return false;
3547 }
3548
3549 memset(&sb, 0, sizeof(sb));
3550 sb.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
3551 sb.spt.CdbLength = iop->cmnd_len;
3552 memcpy(sb.spt.Cdb, iop->cmnd, iop->cmnd_len);
3553 sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf);
3554 sb.spt.SenseInfoOffset =
3555 offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
3556 sb.spt.TimeOutValue = (iop->timeout ? iop->timeout : 60);
3557
3558 bool direct = true;
3559 switch (iop->dxfer_dir) {
3560 case DXFER_NONE:
3561 sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
3562 break;
3563 case DXFER_FROM_DEVICE:
3564 sb.spt.DataIn = SCSI_IOCTL_DATA_IN;
3565 sb.spt.DataTransferLength = iop->dxfer_len;
3566 sb.spt.DataBuffer = iop->dxferp;
3567 // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte
3568 // transfers (needed for SMART STATUS check of JMicron USB briges)
3569 if (sb.spt.DataTransferLength == 1)
3570 direct = false;
3571 break;
3572 case DXFER_TO_DEVICE:
3573 sb.spt.DataIn = SCSI_IOCTL_DATA_OUT;
3574 sb.spt.DataTransferLength = iop->dxfer_len;
3575 sb.spt.DataBuffer = iop->dxferp;
3576 break;
3577 default:
3578 set_err(EINVAL, "bad dxfer_dir");
3579 return false;
3580 }
3581
3582 long err = 0;
3583 if (direct) {
3584 DWORD num_out;
3585 if (!DeviceIoControl(get_fh(), IOCTL_SCSI_PASS_THROUGH_DIRECT,
3586 &sb, sizeof(sb), &sb, sizeof(sb), &num_out, 0))
3587 err = GetLastError();
3588 }
3589 else
3590 err = scsi_pass_through_indirect(get_fh(), &sb);
3591
3592 if (err)
3593 return set_err((err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO),
3594 "IOCTL_SCSI_PASS_THROUGH%s failed, Error=%ld",
3595 (direct ? "_DIRECT" : ""), err);
3596
3597 iop->scsi_status = sb.spt.ScsiStatus;
3598 if (SCSI_STATUS_CHECK_CONDITION & iop->scsi_status) {
3599 int slen = sb.ucSenseBuf[7] + 8;
3600
3601 if (slen > (int)sizeof(sb.ucSenseBuf))
3602 slen = sizeof(sb.ucSenseBuf);
3603 if (slen > (int)iop->max_sense_len)
3604 slen = iop->max_sense_len;
3605 memcpy(iop->sensep, sb.ucSenseBuf, slen);
3606 iop->resp_sense_len = slen;
3607 if (report) {
3608 if ((iop->sensep[0] & 0x7f) > 0x71)
3609 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
3610 iop->scsi_status, iop->sensep[1] & 0xf,
3611 iop->sensep[2], iop->sensep[3]);
3612 else
3613 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
3614 iop->scsi_status, iop->sensep[2] & 0xf,
3615 iop->sensep[12], iop->sensep[13]);
3616 }
3617 } else
3618 iop->resp_sense_len = 0;
3619
3620 if ((iop->dxfer_len > 0) && (sb.spt.DataTransferLength > 0))
3621 iop->resid = iop->dxfer_len - sb.spt.DataTransferLength;
3622 else
3623 iop->resid = 0;
3624
3625 if ((iop->dxfer_dir == DXFER_FROM_DEVICE) && (report > 1)) {
3626 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
3627 pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
3628 (trunc ? " [only first 256 bytes shown]" : ""));
3629 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
3630 }
3631 return true;
3632 }
3633
3634
3635 //////////////////////////////////////////////////////////////////////////////////////////////////
3636
3637
3638 } // namespace
3639
3640 /////////////////////////////////////////////////////////////////////////////
3641
3642 // Initialize platform interface and register with smi()
3643 void smart_interface::init()
3644 {
3645 // Select interface for Windows flavor
3646 if (os_win32::is_win9x()) {
3647 static os_win32::win9x_smart_interface the_win9x_interface;
3648 smart_interface::set(&the_win9x_interface);
3649 }
3650 else {
3651 static os_win32::winnt_smart_interface the_winnt_interface;
3652 smart_interface::set(&the_winnt_interface);
3653 }
3654 }
3655