]> git.proxmox.com Git - mirror_smartmontools-debian.git/blob - os_win32.cpp
Imported Upstream version 5.39.1
[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 3050 2010-01-27 19:58:38Z 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, "Drive SMART Data:"); // tw_cli from 9.5.x
1610 if (!*s) {
1611 s = findstr(buffer, "S.M.A.R.T. (Controller"); // from 3DM browser window
1612 if (*s) {
1613 const char * s1 = findstr(s, "<td class"); // html version
1614 if (*s1)
1615 s = s1;
1616 s += strcspn(s, "\r\n");
1617 }
1618 else
1619 s = buffer; // try raw hex dump without header
1620 }
1621 unsigned char * sd = (unsigned char *)&m_smart_buf;
1622 int i = 0;
1623 for (;;) {
1624 unsigned x = ~0; int n = -1;
1625 if (!(sscanf(s, "%x %n", &x, &n) == 1 && !(x & ~0xff)))
1626 break;
1627 sd[i] = (unsigned char)x;
1628 if (!(++i < 512 && n > 0))
1629 break;
1630 s += n;
1631 if (*s == '<') // "<br>"
1632 s += strcspn(s, "\r\n");
1633 }
1634 if (i < 512) {
1635 if (!id->model[1]) {
1636 // No useful data found
1637 char * err = strstr(buffer, "Error:");
1638 if (!err)
1639 err = strstr(buffer, "error :");
1640 if (err && (err = strchr(err, ':'))) {
1641 // Show tw_cli error message
1642 err++;
1643 err[strcspn(err, "\r\n")] = 0;
1644 return set_err(EIO, err);
1645 }
1646 return set_err(EIO);
1647 }
1648 sd = 0;
1649 }
1650
1651 m_ident_valid = true;
1652 m_smart_valid = !!sd;
1653 return true;
1654 }
1655
1656
1657 bool win_tw_cli_device::close()
1658 {
1659 m_ident_valid = m_smart_valid = false;
1660 return true;
1661 }
1662
1663
1664 int win_tw_cli_device::ata_command_interface(smart_command_set command, int /*select*/, char * data)
1665 {
1666 switch (command) {
1667 case IDENTIFY:
1668 if (!m_ident_valid)
1669 break;
1670 memcpy(data, &m_ident_buf, 512);
1671 return 0;
1672 case READ_VALUES:
1673 if (!m_smart_valid)
1674 break;
1675 memcpy(data, &m_smart_buf, 512);
1676 return 0;
1677 case READ_THRESHOLDS:
1678 if (!m_smart_valid)
1679 break;
1680 // Fake zero thresholds
1681 {
1682 const ata_smart_values * sv = &m_smart_buf;
1683 ata_smart_thresholds_pvt * tr = (ata_smart_thresholds_pvt *)data;
1684 memset(tr, 0, 512);
1685 // TODO: Indicate missing thresholds in ataprint.cpp:PrintSmartAttribWithThres()
1686 // (ATA_SMART_READ_THRESHOLDS is marked obsolete since ATA-5)
1687 for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++)
1688 tr->chksum -= tr->thres_entries[i].id = sv->vendor_attributes[i].id;
1689 }
1690 return 0;
1691 case ENABLE:
1692 case STATUS:
1693 case STATUS_CHECK: // Fake "good" SMART status
1694 return 0;
1695 default:
1696 break;
1697 }
1698 // Arrive here for all unsupported commands
1699 set_err(ENOSYS);
1700 return -1;
1701 }
1702
1703
1704 /////////////////////////////////////////////////////////////////////////////
1705
1706 // IOCTL_STORAGE_QUERY_PROPERTY
1707
1708 #define FILE_DEVICE_MASS_STORAGE 0x0000002d
1709 #define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE
1710 #define FILE_ANY_ACCESS 0
1711
1712 #define IOCTL_STORAGE_QUERY_PROPERTY \
1713 CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)
1714
1715 typedef enum _STORAGE_BUS_TYPE {
1716 BusTypeUnknown = 0x00,
1717 BusTypeScsi = 0x01,
1718 BusTypeAtapi = 0x02,
1719 BusTypeAta = 0x03,
1720 BusType1394 = 0x04,
1721 BusTypeSsa = 0x05,
1722 BusTypeFibre = 0x06,
1723 BusTypeUsb = 0x07,
1724 BusTypeRAID = 0x08,
1725 BusTypeiScsi = 0x09,
1726 BusTypeSas = 0x0A,
1727 BusTypeSata = 0x0B,
1728 BusTypeSd = 0x0C,
1729 BusTypeMmc = 0x0D,
1730 BusTypeMax = 0x0E,
1731 BusTypeMaxReserved = 0x7F
1732 } STORAGE_BUS_TYPE, *PSTORAGE_BUS_TYPE;
1733
1734 typedef struct _STORAGE_DEVICE_DESCRIPTOR {
1735 ULONG Version;
1736 ULONG Size;
1737 UCHAR DeviceType;
1738 UCHAR DeviceTypeModifier;
1739 BOOLEAN RemovableMedia;
1740 BOOLEAN CommandQueueing;
1741 ULONG VendorIdOffset;
1742 ULONG ProductIdOffset;
1743 ULONG ProductRevisionOffset;
1744 ULONG SerialNumberOffset;
1745 STORAGE_BUS_TYPE BusType;
1746 ULONG RawPropertiesLength;
1747 UCHAR RawDeviceProperties[1];
1748 } STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR;
1749
1750 typedef enum _STORAGE_QUERY_TYPE {
1751 PropertyStandardQuery = 0,
1752 PropertyExistsQuery,
1753 PropertyMaskQuery,
1754 PropertyQueryMaxDefined
1755 } STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE;
1756
1757 typedef enum _STORAGE_PROPERTY_ID {
1758 StorageDeviceProperty = 0,
1759 StorageAdapterProperty,
1760 StorageDeviceIdProperty,
1761 StorageDeviceUniqueIdProperty,
1762 StorageDeviceWriteCacheProperty,
1763 StorageMiniportProperty,
1764 StorageAccessAlignmentProperty
1765 } STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID;
1766
1767 typedef struct _STORAGE_PROPERTY_QUERY {
1768 STORAGE_PROPERTY_ID PropertyId;
1769 STORAGE_QUERY_TYPE QueryType;
1770 UCHAR AdditionalParameters[1];
1771 } STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY;
1772
1773
1774 /////////////////////////////////////////////////////////////////////////////
1775
1776 union STORAGE_DEVICE_DESCRIPTOR_DATA {
1777 STORAGE_DEVICE_DESCRIPTOR desc;
1778 char raw[256];
1779 };
1780
1781 // Get STORAGE_DEVICE_DESCRIPTOR_DATA for device.
1782 // (This works without admin rights)
1783
1784 static int storage_query_property_ioctl(HANDLE hdevice, STORAGE_DEVICE_DESCRIPTOR_DATA * data)
1785 {
1786 STORAGE_PROPERTY_QUERY query = {StorageDeviceProperty, PropertyStandardQuery, {0} };
1787 memset(data, 0, sizeof(*data));
1788
1789 DWORD num_out;
1790 if (!DeviceIoControl(hdevice, IOCTL_STORAGE_QUERY_PROPERTY,
1791 &query, sizeof(query), data, sizeof(*data), &num_out, NULL)) {
1792 if (con->reportataioctl > 1 || con->reportscsiioctl > 1)
1793 pout(" IOCTL_STORAGE_QUERY_PROPERTY failed, Error=%ld\n", GetLastError());
1794 errno = ENOSYS;
1795 return -1;
1796 }
1797
1798 if (con->reportataioctl > 1 || con->reportscsiioctl > 1) {
1799 pout(" IOCTL_STORAGE_QUERY_PROPERTY returns:\n"
1800 " Vendor: \"%s\"\n"
1801 " Product: \"%s\"\n"
1802 " Revision: \"%s\"\n"
1803 " Removable: %s\n"
1804 " BusType: 0x%02x\n",
1805 (data->desc.VendorIdOffset ? data->raw+data->desc.VendorIdOffset : ""),
1806 (data->desc.ProductIdOffset ? data->raw+data->desc.ProductIdOffset : ""),
1807 (data->desc.ProductRevisionOffset ? data->raw+data->desc.ProductRevisionOffset : ""),
1808 (data->desc.RemovableMedia? "Yes":"No"), data->desc.BusType
1809 );
1810 }
1811 return 0;
1812 }
1813
1814
1815 /////////////////////////////////////////////////////////////////////////////
1816
1817 // IOCTL_STORAGE_PREDICT_FAILURE
1818
1819 #define IOCTL_STORAGE_PREDICT_FAILURE \
1820 CTL_CODE(IOCTL_STORAGE_BASE, 0x0440, METHOD_BUFFERED, FILE_ANY_ACCESS)
1821
1822 typedef struct _STORAGE_PREDICT_FAILURE {
1823 ULONG PredictFailure;
1824 UCHAR VendorSpecific[512];
1825 } STORAGE_PREDICT_FAILURE, *PSTORAGE_PREDICT_FAILURE;
1826
1827 ASSERT_SIZEOF(STORAGE_PREDICT_FAILURE, 4+512);
1828
1829
1830 /////////////////////////////////////////////////////////////////////////////
1831
1832
1833 // Call IOCTL_STORAGE_PREDICT_FAILURE, return PredictFailure value
1834 // or -1 on error, opionally return VendorSpecific data.
1835 // (This works without admin rights)
1836
1837 static int storage_predict_failure_ioctl(HANDLE hdevice, char * data = 0)
1838 {
1839 STORAGE_PREDICT_FAILURE pred;
1840 memset(&pred, 0, sizeof(pred));
1841
1842 DWORD num_out;
1843 if (!DeviceIoControl(hdevice, IOCTL_STORAGE_PREDICT_FAILURE,
1844 0, 0, &pred, sizeof(pred), &num_out, NULL)) {
1845 if (con->reportataioctl > 1)
1846 pout(" IOCTL_STORAGE_PREDICT_FAILURE failed, Error=%ld\n", GetLastError());
1847 errno = ENOSYS;
1848 return -1;
1849 }
1850
1851 if (con->reportataioctl > 1) {
1852 pout(" IOCTL_STORAGE_PREDICT_FAILURE returns:\n"
1853 " PredictFailure: 0x%08lx\n"
1854 " VendorSpecific: 0x%02x,0x%02x,0x%02x,...,0x%02x\n",
1855 pred.PredictFailure,
1856 pred.VendorSpecific[0], pred.VendorSpecific[1], pred.VendorSpecific[2],
1857 pred.VendorSpecific[sizeof(pred.VendorSpecific)-1]
1858 );
1859 }
1860 if (data)
1861 memcpy(data, pred.VendorSpecific, sizeof(pred.VendorSpecific));
1862 return (!pred.PredictFailure ? 0 : 1);
1863 }
1864
1865
1866 /////////////////////////////////////////////////////////////////////////////
1867
1868 // get DEV_* for open handle
1869 static win_dev_type get_controller_type(HANDLE hdevice, bool admin, GETVERSIONINPARAMS_EX * ata_version_ex)
1870 {
1871 // Try SMART_GET_VERSION first to detect ATA SMART support
1872 // for drivers reporting BusTypeScsi (3ware)
1873 if (admin && smart_get_version(hdevice, ata_version_ex) >= 0)
1874 return DEV_ATA;
1875
1876 // Get BusType from device descriptor
1877 STORAGE_DEVICE_DESCRIPTOR_DATA data;
1878 if (storage_query_property_ioctl(hdevice, &data))
1879 return DEV_UNKNOWN;
1880
1881 switch (data.desc.BusType) {
1882 case BusTypeAta:
1883 case BusTypeSata:
1884 if (ata_version_ex)
1885 memset(ata_version_ex, 0, sizeof(*ata_version_ex));
1886 return DEV_ATA;
1887 case BusTypeScsi:
1888 case BusTypeiScsi:
1889 case BusTypeSas:
1890 return DEV_SCSI;
1891 case BusTypeUsb:
1892 return DEV_USB;
1893 default:
1894 return DEV_UNKNOWN;
1895 }
1896 /*NOTREACHED*/
1897 }
1898
1899 // get DEV_* for device path
1900 static win_dev_type get_controller_type(const char * path, GETVERSIONINPARAMS_EX * ata_version_ex = 0)
1901 {
1902 bool admin = true;
1903 HANDLE h = CreateFileA(path, GENERIC_READ|GENERIC_WRITE,
1904 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
1905 if (h == INVALID_HANDLE_VALUE) {
1906 admin = false;
1907 h = CreateFileA(path, 0,
1908 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
1909 if (h == INVALID_HANDLE_VALUE)
1910 return DEV_UNKNOWN;
1911 }
1912 if (con->reportataioctl > 1 || con->reportscsiioctl > 1)
1913 pout(" %s: successfully opened%s\n", path, (!admin ? " (without admin rights)" :""));
1914 win_dev_type type = get_controller_type(h, admin, ata_version_ex);
1915 CloseHandle(h);
1916 return type;
1917 }
1918
1919 // get DEV_* for physical drive number
1920 static win_dev_type get_phy_drive_type(int drive, GETVERSIONINPARAMS_EX * ata_version_ex)
1921 {
1922 char path[30];
1923 snprintf(path, sizeof(path)-1, "\\\\.\\PhysicalDrive%d", drive);
1924 return get_controller_type(path, ata_version_ex);
1925 }
1926
1927 static win_dev_type get_phy_drive_type(int drive)
1928 {
1929 return get_phy_drive_type(drive, 0);
1930 }
1931
1932 // get DEV_* for logical drive number
1933 static win_dev_type get_log_drive_type(int drive)
1934 {
1935 char path[30];
1936 snprintf(path, sizeof(path)-1, "\\\\.\\%c:", 'A'+drive);
1937 return get_controller_type(path);
1938 }
1939
1940 // Build IDENTIFY information from STORAGE_DEVICE_DESCRIPTOR
1941 static int get_identify_from_device_property(HANDLE hdevice, ata_identify_device * id)
1942 {
1943 STORAGE_DEVICE_DESCRIPTOR_DATA data;
1944 if (storage_query_property_ioctl(hdevice, &data))
1945 return -1;
1946
1947 memset(id, 0, sizeof(*id));
1948 if (data.desc.ProductIdOffset)
1949 copy_swapped(id->model, data.raw+data.desc.ProductIdOffset, sizeof(id->model));
1950 if (data.desc.ProductRevisionOffset)
1951 copy_swapped(id->fw_rev, data.raw+data.desc.ProductRevisionOffset, sizeof(id->fw_rev));
1952 id->major_rev_num = 0x1<<3; // ATA-3
1953 id->command_set_1 = 0x0001; id->command_set_2 = 0x4000; // SMART supported, words 82,83 valid
1954 id->cfs_enable_1 = 0x0001; id->csf_default = 0x4000; // SMART enabled, words 85,87 valid
1955 return 0;
1956 }
1957
1958
1959 /////////////////////////////////////////////////////////////////////////////
1960 // USB ID detection using WMI
1961
1962 // Run a command, split stdout into lines.
1963 // Return number of lines read, -1 on error.
1964 static int run_cmd(std::vector<std::string> & lines, const char * cmd, ...)
1965 {
1966 lines.clear();
1967
1968 va_list ap; va_start(ap, cmd);
1969 std::string cmdline = vstrprintf(cmd, ap);
1970 va_end(ap);
1971
1972 if (con->reportscsiioctl > 1)
1973 pout("Run: \"%s\"\n", cmdline.c_str());
1974
1975 char buffer[16*1024];
1976 int size = run_cmd(cmdline.c_str(), buffer, sizeof(buffer));
1977
1978 if (con->reportscsiioctl > 1)
1979 pout("Read %d bytes\n", size);
1980 if (!(0 < size && size < (int)sizeof(buffer)-1))
1981 return -1;
1982
1983 buffer[size] = 0;
1984
1985 for (int i = 0; buffer[i]; ) {
1986 int len = strcspn(buffer+i, "\r\n");
1987 lines.push_back(std::string(buffer+i, len));
1988 i += len;
1989 i += strspn(buffer+i, "\r\n");
1990 }
1991 if (con->reportscsiioctl > 1) {
1992 for (unsigned i = 0; i < lines.size(); i++)
1993 printf("'%s'\n", lines[i].c_str());
1994 }
1995 return lines.size();
1996 }
1997
1998 // Quote string for WMI
1999 static std::string wmi_quote(const char * s, int len)
2000 {
2001 std::string r;
2002 for (int i = 0; i < len; i++) {
2003 char c = s[i];
2004 if (c == '\\')
2005 r += '\\';
2006 r += c;
2007 }
2008 return r;
2009 }
2010
2011 // Get USB ID for a physical drive number
2012 static bool get_usb_id(int drive, unsigned short & vendor_id, unsigned short & product_id)
2013 {
2014 // Get device name
2015 std::vector<std::string> result;
2016 if (run_cmd(result,
2017 "wmic PATH Win32_DiskDrive WHERE DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\" GET Model",
2018 drive) != 2)
2019 return false;
2020
2021 std::string name = result[1];
2022
2023 // Get USB_CONTROLLER -> DEVICE associations
2024 std::vector<std::string> assoc;
2025 int n = run_cmd(assoc, "wmic PATH Win32_USBControllerDevice GET Antecedent,Dependent");
2026 if (n < 2)
2027 return false;
2028
2029 regular_expression regex("^([^ ]+) .*Win32_PnPEntity.DeviceID=\"(USBSTOR\\\\[^\"]*)\" *$",
2030 REG_EXTENDED);
2031 if (regex.empty()) // TODO: throw in constructor?
2032 return false;
2033
2034 int usbstoridx = -1;
2035 std::string usbcontr;
2036 for (int i = 2; i < n; i++) {
2037 // Find next 'USB_CONTROLLER USBSTORAGE_DEVICE' pair
2038 regmatch_t match[3];
2039 const char * s = assoc[i].c_str();
2040 if (!regex.execute(s, 3, match))
2041 continue;
2042
2043 // USBSTOR device found, compare Name
2044 if (run_cmd(result,
2045 "wmic PATH Win32_PnPEntity WHERE DeviceID=\"%s\" GET Name",
2046 wmi_quote(s + match[2].rm_so, match[2].rm_eo - match[2].rm_so).c_str()
2047 ) != 2)
2048 continue;
2049 if (result[1] != name)
2050 continue;
2051
2052 // Name must be uniqe
2053 if (usbstoridx >= 0)
2054 return false;
2055
2056 usbstoridx = i;
2057 usbcontr.assign(s + match[1].rm_so, match[1].rm_eo - match[1].rm_so);
2058 }
2059
2060 // Found ?
2061 if (usbstoridx <= 0)
2062 return false;
2063
2064 // The entry preceding USBSTOR should be the USB bridge device
2065 regex.compile("^([^ ]+) .*Win32_PnPEntity.DeviceID=\"USB\\\\VID_(....&PID_....)[^\"]*\" *$",
2066 REG_EXTENDED);
2067 if (regex.empty())
2068 return false;
2069 regmatch_t match[3];
2070 const char * s = assoc[usbstoridx-1].c_str();
2071 if (!regex.execute(s, 3, match))
2072 return false;
2073
2074 // Both devices must be associated to same controller
2075 if (usbcontr != std::string(s + match[1].rm_so, match[1].rm_eo - match[1].rm_so))
2076 return false;
2077
2078 // Parse USB ID
2079 int nc = -1;
2080 if (!(sscanf(s + match[2].rm_so, "%4hx&PID_%4hx%n",
2081 &vendor_id, &product_id, &nc) == 2 && nc == 4+5+4))
2082 return false;
2083
2084 if (con->reportscsiioctl > 1)
2085 pout("USB ID = 0x%04x:0x%04x\n", vendor_id, product_id);
2086 return true;
2087 }
2088
2089
2090 /////////////////////////////////////////////////////////////////////////////
2091
2092 // Call GetDevicePowerState() if available (Win98/ME/2000/XP/2003)
2093 // returns: 1=active, 0=standby, -1=error
2094 // (This would also work for SCSI drives)
2095
2096 static int get_device_power_state(HANDLE hdevice)
2097 {
2098 static HINSTANCE h_kernel_dll = 0;
2099 #ifdef __CYGWIN__
2100 static DWORD kernel_dll_pid = 0;
2101 #endif
2102 static BOOL (WINAPI * GetDevicePowerState_p)(HANDLE, BOOL *) = 0;
2103
2104 BOOL state = TRUE;
2105
2106 if (!GetDevicePowerState_p
2107 #ifdef __CYGWIN__
2108 || kernel_dll_pid != GetCurrentProcessId() // detect fork()
2109 #endif
2110 ) {
2111 if (h_kernel_dll == INVALID_HANDLE_VALUE) {
2112 errno = ENOSYS;
2113 return -1;
2114 }
2115 if (!(h_kernel_dll = LoadLibraryA("KERNEL32.DLL"))) {
2116 pout("Cannot load KERNEL32.DLL, Error=%ld\n", GetLastError());
2117 h_kernel_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
2118 errno = ENOSYS;
2119 return -1;
2120 }
2121 if (!(GetDevicePowerState_p = (BOOL (WINAPI *)(HANDLE, BOOL *))
2122 GetProcAddress(h_kernel_dll, "GetDevicePowerState"))) {
2123 if (con->reportataioctl)
2124 pout(" GetDevicePowerState() not found, Error=%ld\n", GetLastError());
2125 FreeLibrary(h_kernel_dll);
2126 h_kernel_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
2127 errno = ENOSYS;
2128 return -1;
2129 }
2130 #ifdef __CYGWIN__
2131 kernel_dll_pid = GetCurrentProcessId();
2132 #endif
2133 }
2134
2135 if (!GetDevicePowerState_p(hdevice, &state)) {
2136 long err = GetLastError();
2137 if (con->reportataioctl)
2138 pout(" GetDevicePowerState() failed, Error=%ld\n", err);
2139 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
2140 // TODO: This may not work as expected on transient errors,
2141 // because smartd interprets -1 as SLEEP mode regardless of errno.
2142 return -1;
2143 }
2144
2145 if (con->reportataioctl > 1)
2146 pout(" GetDevicePowerState() succeeded, state=%d\n", state);
2147 return state;
2148 }
2149
2150
2151 /////////////////////////////////////////////////////////////////////////////
2152
2153 // Print SMARTVSD error message, return errno
2154
2155 static int smartvsd_error()
2156 {
2157 char path[MAX_PATH];
2158 unsigned len;
2159 if (!(5 <= (len = GetSystemDirectoryA(path, MAX_PATH)) && len < MAX_PATH/2))
2160 return ENOENT;
2161 // SMARTVSD.VXD present?
2162 strcpy(path+len, "\\IOSUBSYS\\SMARTVSD.VXD");
2163 if (!access(path, 0)) {
2164 // Yes, standard IDE driver used?
2165 HANDLE h;
2166 if ( (h = CreateFileA("\\\\.\\ESDI_506",
2167 GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
2168 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE
2169 && GetLastError() == ERROR_FILE_NOT_FOUND ) {
2170 pout("Standard IDE driver ESDI_506.PDR not used, or no IDE/ATA drives present.\n");
2171 return ENOENT;
2172 }
2173 else {
2174 if (h != INVALID_HANDLE_VALUE) // should not happen
2175 CloseHandle(h);
2176 pout("SMART driver SMARTVSD.VXD is installed, but not loaded.\n");
2177 return ENOSYS;
2178 }
2179 }
2180 else {
2181 strcpy(path+len, "\\SMARTVSD.VXD");
2182 if (!access(path, 0)) {
2183 // Some Windows versions install SMARTVSD.VXD in SYSTEM directory
2184 // (http://support.microsoft.com/kb/265854/en-us).
2185 path[len] = 0;
2186 pout("SMART driver is not properly installed,\n"
2187 " move SMARTVSD.VXD from \"%s\" to \"%s\\IOSUBSYS\"\n"
2188 " and reboot Windows.\n", path, path);
2189 }
2190 else {
2191 // Some Windows versions do not provide SMARTVSD.VXD
2192 // (http://support.microsoft.com/kb/199886/en-us).
2193 path[len] = 0;
2194 pout("SMARTVSD.VXD is missing in folder \"%s\\IOSUBSYS\".\n", path);
2195 }
2196 return ENOSYS;
2197 }
2198 }
2199
2200
2201 // Get default ATA device options
2202
2203 static const char * ata_get_def_options()
2204 {
2205 DWORD ver = GetVersion();
2206 if ((ver & 0x80000000) || (ver & 0xff) < 4) // Win9x/ME
2207 return "s"; // SMART_* only
2208 else if ((ver & 0xff) == 4) // WinNT4
2209 return "sc"; // SMART_*, SCSI_PASS_THROUGH
2210 else // WinXP, 2003, Vista
2211 return "pasifm"; // GetDevicePowerState(), ATA_, SMART_*, IDE_PASS_THROUGH,
2212 // STORAGE_*, SCSI_MINIPORT_*
2213 }
2214
2215
2216 // Common routines for devices with HANDLEs
2217
2218 win_smart_device::~win_smart_device() throw()
2219 {
2220 if (m_fh != INVALID_HANDLE_VALUE)
2221 ::CloseHandle(m_fh);
2222 }
2223
2224 bool win_smart_device::is_open() const
2225 {
2226 return (m_fh != INVALID_HANDLE_VALUE);
2227 }
2228
2229 bool win_smart_device::close()
2230 {
2231 if (m_fh == INVALID_HANDLE_VALUE)
2232 return true;
2233 BOOL rc = ::CloseHandle(m_fh);
2234 m_fh = INVALID_HANDLE_VALUE;
2235 return !!rc;
2236 }
2237
2238 // ATA
2239
2240 win_ata_device::win_ata_device(smart_interface * intf, const char * dev_name, const char * req_type)
2241 : smart_device(intf, dev_name, "ata", req_type),
2242 m_usr_options(false),
2243 m_admin(false),
2244 m_drive(0),
2245 m_port(-1),
2246 m_smartver_state(0)
2247 {
2248 }
2249
2250 win_ata_device::~win_ata_device() throw()
2251 {
2252 }
2253
2254
2255 // Open ATA device
2256
2257 bool win_ata_device::open()
2258 {
2259 const char * name = skipdev(get_dev_name()); int len = strlen(name);
2260 // [sh]d[a-z](:[saicmfp]+)? => Physical drive 0-25, with options
2261 char drive[1+1] = "", options[8+1] = ""; int n1 = -1, n2 = -1;
2262 if ( sscanf(name, "%*[sh]d%1[a-z]%n:%7[saicmfp]%n", drive, &n1, options, &n2) >= 1
2263 && ((n1 == len && !options[0]) || n2 == len) ) {
2264 return open(drive[0] - 'a', -1, options, -1);
2265 }
2266 // [sh]d[a-z],N(:[saicmfp3]+)? => Physical drive 0-25, RAID port N, with options
2267 drive[0] = 0; options[0] = 0; n1 = -1; n2 = -1;
2268 unsigned port = ~0;
2269 if ( sscanf(name, "%*[sh]d%1[a-z],%u%n:%8[saicmfp3]%n", drive, &port, &n1, options, &n2) >= 2
2270 && port < 32 && ((n1 == len && !options[0]) || n2 == len) ) {
2271 return open(drive[0] - 'a', -1, options, port);
2272 }
2273 // pd<m>,N => Physical drive <m>, RAID port N
2274 int phydrive = -1; port = ~0; n1 = -1; n2 = -1;
2275 if ( sscanf(name, "pd%d%n,%u%n", &phydrive, &n1, &port, &n2) >= 1
2276 && phydrive >= 0 && ((n1 == len && (int)port < 0) || (n2 == len && port < 32))) {
2277 return open(phydrive, -1, "", (int)port);
2278 }
2279 // [a-zA-Z]: => Physical drive behind logical drive 0-25
2280 int logdrive = drive_letter(name);
2281 if (logdrive >= 0) {
2282 return open(-1, logdrive, "", -1);
2283 }
2284
2285 return set_err(EINVAL);
2286 }
2287
2288
2289 bool win_ata_device::open(int phydrive, int logdrive, const char * options, int port)
2290 {
2291 // path depends on Windows Version
2292 bool win9x = is_win9x(); // TODO: Member variable
2293 char devpath[30];
2294 if (win9x && 0 <= phydrive && phydrive <= 7)
2295 // Use patched "smartvse.vxd" for drives 4-7, see INSTALL file for details
2296 strcpy(devpath, (phydrive <= 3 ? "\\\\.\\SMARTVSD" : "\\\\.\\SMARTVSE"));
2297 else if (!win9x && 0 <= phydrive && phydrive <= 255)
2298 snprintf(devpath, sizeof(devpath)-1, "\\\\.\\PhysicalDrive%d", phydrive);
2299 else if (!win9x && 0 <= logdrive && logdrive <= 'Z'-'A')
2300 snprintf(devpath, sizeof(devpath)-1, "\\\\.\\%c:", 'A'+logdrive);
2301 else
2302 return set_err(ENOENT);
2303
2304 // Open device
2305 HANDLE h = INVALID_HANDLE_VALUE;
2306 if (win9x || !(*options && !options[strspn(options, "fp")])) {
2307 // Open with admin rights
2308 m_admin = true;
2309 h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,
2310 FILE_SHARE_READ|FILE_SHARE_WRITE,
2311 NULL, OPEN_EXISTING, 0, 0);
2312 }
2313 if (!win9x && h == INVALID_HANDLE_VALUE) {
2314 // Open without admin rights
2315 m_admin = false;
2316 h = CreateFileA(devpath, 0,
2317 FILE_SHARE_READ|FILE_SHARE_WRITE,
2318 NULL, OPEN_EXISTING, 0, 0);
2319 }
2320 if (h == INVALID_HANDLE_VALUE) {
2321 long err = GetLastError();
2322 pout("Cannot open device %s, Error=%ld\n", devpath, err);
2323 if (err == ERROR_FILE_NOT_FOUND)
2324 set_err((win9x && phydrive <= 3 ? smartvsd_error() : ENOENT), "%s: not found", devpath);
2325 else if (err == ERROR_ACCESS_DENIED)
2326 set_err(EACCES, "%s: access denied", devpath);
2327 else
2328 set_err(EIO, "%s: Error=%ld", devpath, err);
2329 return false;
2330 }
2331 set_fh(h);
2332
2333 if (con->reportataioctl > 1)
2334 pout("%s: successfully opened%s\n", devpath, (!m_admin ? " (without admin rights)" :""));
2335
2336 m_usr_options = false;
2337 if (*options) {
2338 // Save user options
2339 m_options = options; m_usr_options = true;
2340 }
2341 else if (port >= 0)
2342 // RAID: SMART_* and SCSI_MINIPORT
2343 m_options = "s3";
2344 else {
2345 // Set default options according to Windows version
2346 static const char * def_options = ata_get_def_options();
2347 m_options = def_options;
2348 }
2349
2350 // NT4/2000/XP: SMART_GET_VERSION may spin up disk, so delay until first real SMART_* call
2351 m_drive = 0; m_port = port;
2352 if (!win9x && port < 0)
2353 return true;
2354
2355 // Win9X/ME: Get drive map
2356 // RAID: Get port map
2357 GETVERSIONINPARAMS_EX vers_ex;
2358 int devmap = smart_get_version(h, (port >= 0 ? &vers_ex : 0));
2359
2360 unsigned long portmap = 0;
2361 if (port >= 0 && devmap >= 0) {
2362 // 3ware RAID: check vendor id
2363 if (vers_ex.wIdentifier != SMART_VENDOR_3WARE) {
2364 pout("SMART_GET_VERSION returns unknown Identifier = %04x\n"
2365 "This is no 3ware 9000 controller or driver has no SMART support.\n",
2366 vers_ex.wIdentifier);
2367 devmap = -1;
2368 }
2369 else
2370 portmap = vers_ex.dwDeviceMapEx;
2371 }
2372 if (devmap < 0) {
2373 pout("%s: ATA driver has no SMART support\n", devpath);
2374 if (!is_permissive()) {
2375 close();
2376 return set_err(ENOSYS);
2377 }
2378 devmap = 0x0f;
2379 }
2380 m_smartver_state = 1;
2381
2382 if (port >= 0) {
2383 // 3ware RAID: update devicemap first
2384
2385 if (!update_3ware_devicemap_ioctl(h)) {
2386 if ( smart_get_version(h, &vers_ex) >= 0
2387 && vers_ex.wIdentifier == SMART_VENDOR_3WARE )
2388 portmap = vers_ex.dwDeviceMapEx;
2389 }
2390 // Check port existence
2391 if (!(portmap & (1L << port))) {
2392 if (!is_permissive()) {
2393 close();
2394 return set_err(ENOENT, "%s: Port %d is empty or does not exist", devpath, port);
2395 }
2396 }
2397 return true;
2398 }
2399
2400 // Win9x/ME: Check device presence & type
2401 if (((devmap >> (phydrive & 0x3)) & 0x11) != 0x01) {
2402 unsigned char atapi = (devmap >> (phydrive & 0x3)) & 0x10;
2403 // Win9x drive existence check may not work as expected
2404 // The atapi.sys driver incorrectly fills in the bIDEDeviceMap with 0x01
2405 // (The related KB Article Q196120 is no longer available)
2406 if (!is_permissive()) {
2407 close();
2408 return set_err((atapi ? ENOSYS : ENOENT), "%s: Drive %d %s (IDEDeviceMap=0x%02x)",
2409 devpath, phydrive, (atapi?"is an ATAPI device":"does not exist"), devmap);
2410 }
2411 }
2412 // Drive number must be passed to ioctl
2413 m_drive = (phydrive & 0x3);
2414 return true;
2415 }
2416
2417
2418 // Scan for ATA drives on Win9x/ME
2419
2420 bool win9x_smart_interface::ata_scan(smart_device_list & devlist)
2421 {
2422 // Open device
2423 const char devpath[] = "\\\\.\\SMARTVSD";
2424 HANDLE h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,
2425 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
2426 if (h == INVALID_HANDLE_VALUE) {
2427 if (con->reportataioctl > 1)
2428 pout(" %s: Open failed, Error=%ld\n", devpath, GetLastError());
2429 return true; // SMARTVSD.VXD missing or no ATA devices
2430 }
2431
2432 // Get drive map
2433 int devmap = smart_get_version(h);
2434 CloseHandle(h);
2435 if (devmap < 0)
2436 return true; // Should not happen
2437
2438 // Check ATA device presence, remove ATAPI devices
2439 devmap = (devmap & 0xf) & ~((devmap >> 4) & 0xf);
2440 char name[20];
2441 for (int i = 0; i < 4; i++) {
2442 if (!(devmap & (1 << i)))
2443 continue;
2444 sprintf(name, "/dev/hd%c", 'a'+i);
2445 devlist.push_back( new win_ata_device(this, name, "ata") );
2446 }
2447 return true;
2448 }
2449
2450
2451 // Scan for ATA drives
2452
2453 bool winnt_smart_interface::ata_scan(smart_device_list & devlist)
2454 {
2455 const int max_raid = 2;
2456 bool raid_seen[max_raid] = {false, false};
2457
2458 char name[20];
2459 for (int i = 0; i <= 9; i++) {
2460 GETVERSIONINPARAMS_EX vers_ex;
2461 if (get_phy_drive_type(i, &vers_ex) != DEV_ATA)
2462 continue;
2463
2464 // Interpret RAID drive map if present
2465 if (vers_ex.wIdentifier == SMART_VENDOR_3WARE) {
2466 // Skip if more than 2 controllers or logical drive from this controller already seen
2467 if (vers_ex.wControllerId >= max_raid || raid_seen[vers_ex.wControllerId])
2468 continue;
2469 raid_seen[vers_ex.wControllerId] = true;
2470 // Add physical drives
2471 for (int pi = 0; pi < 32; pi++) {
2472 if (vers_ex.dwDeviceMapEx & (1L << pi)) {
2473 sprintf(name, "/dev/sd%c,%u", 'a'+i, pi);
2474 devlist.push_back( new win_ata_device(this, name, "ata") );
2475 }
2476 }
2477 continue;
2478 }
2479
2480 // Driver supports SMART_GET_VERSION or STORAGE_QUERY_PROPERTY returns ATA/SATA
2481 sprintf(name, "/dev/sd%c", 'a'+i);
2482 devlist.push_back( new win_ata_device(this, name, "ata") );
2483 }
2484
2485 return true;
2486 }
2487
2488
2489 /////////////////////////////////////////////////////////////////////////////
2490
2491 // Interface to ATA devices
2492 bool win_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
2493 {
2494 // No multi-sector support for now, see above
2495 // warning about IOCTL_ATA_PASS_THROUGH
2496 if (!ata_cmd_is_ok(in,
2497 true, // data_out_support
2498 false, // !multi_sector_support
2499 true) // ata_48bit_support
2500 )
2501 return false;
2502
2503 // Determine ioctl functions valid for this ATA cmd
2504 const char * valid_options = 0;
2505
2506 switch (in.in_regs.command) {
2507 case ATA_IDENTIFY_DEVICE:
2508 case ATA_IDENTIFY_PACKET_DEVICE:
2509 // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
2510 // and SCSI_MINIPORT_* if requested by user
2511 valid_options = (m_usr_options ? "saicmf" : "saicf");
2512 break;
2513
2514 case ATA_CHECK_POWER_MODE:
2515 // Try GetDevicePowerState() first, ATA/IDE_PASS_THROUGH may spin up disk
2516 valid_options = "pai3";
2517 break;
2518
2519 case ATA_SMART_CMD:
2520 switch (in.in_regs.features) {
2521 case ATA_SMART_READ_VALUES:
2522 case ATA_SMART_READ_THRESHOLDS:
2523 case ATA_SMART_AUTOSAVE:
2524 case ATA_SMART_ENABLE:
2525 case ATA_SMART_DISABLE:
2526 case ATA_SMART_AUTO_OFFLINE:
2527 // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
2528 // and SCSI_MINIPORT_* if requested by user
2529 valid_options = (m_usr_options ? "saicmf" : "saicf");
2530 break;
2531
2532 case ATA_SMART_IMMEDIATE_OFFLINE:
2533 // SMART_SEND_DRIVE_COMMAND supports ABORT_SELF_TEST only on Win9x/ME
2534 valid_options = (m_usr_options || in.in_regs.lba_low != 127/*ABORT*/ || is_win9x() ?
2535 "saicm3" : "aicm3");
2536 break;
2537
2538 case ATA_SMART_READ_LOG_SECTOR:
2539 // SMART_RCV_DRIVE_DATA supports this only on Win9x/ME
2540 // Try SCSI_MINIPORT also to skip buggy class driver
2541 // SMART functions do not support multi sector I/O.
2542 if (in.size == 512)
2543 valid_options = (m_usr_options || is_win9x() ? "saicm3" : "aicm3");
2544 else
2545 valid_options = "a";
2546 break;
2547
2548 case ATA_SMART_WRITE_LOG_SECTOR:
2549 // ATA_PASS_THROUGH, SCSI_MINIPORT, others don't support DATA_OUT
2550 // but SCSI_MINIPORT_* only if requested by user and single sector.
2551 valid_options = (in.size == 512 && m_usr_options ? "am" : "a");
2552 break;
2553
2554 case ATA_SMART_STATUS:
2555 // May require lba_mid,lba_high register return
2556 if (in.out_needed.is_set())
2557 valid_options = (m_usr_options ? "saimf" : "saif");
2558 else
2559 valid_options = (m_usr_options ? "saicmf" : "saicf");
2560 break;
2561
2562 default:
2563 // Unknown SMART command, handle below
2564 break;
2565 }
2566 break;
2567
2568 default:
2569 // Other ATA command, handle below
2570 break;
2571 }
2572
2573 if (!valid_options) {
2574 // No special ATA command found above, select a generic pass through ioctl.
2575 if (!( in.direction == ata_cmd_in::no_data
2576 || (in.direction == ata_cmd_in::data_in && in.size == 512))
2577 || in.in_regs.is_48bit_cmd() )
2578 // DATA_OUT, more than one sector, 48-bit command: ATA_PASS_THROUGH only
2579 valid_options = "a";
2580 else if (in.out_needed.is_set())
2581 // Need output registers: ATA/IDE_PASS_THROUGH
2582 valid_options = "ai";
2583 else
2584 valid_options = "aic";
2585 }
2586
2587 if (!m_admin) {
2588 // Restrict to IOCTL_STORAGE_*
2589 if (strchr(valid_options, 'f'))
2590 valid_options = "f";
2591 else if (strchr(valid_options, 'p'))
2592 valid_options = "p";
2593 else
2594 return set_err(ENOSYS, "Function requires admin rights");
2595 }
2596
2597 // Set IDEREGS
2598 IDEREGS regs, prev_regs;
2599 {
2600 const ata_in_regs & lo = in.in_regs;
2601 regs.bFeaturesReg = lo.features;
2602 regs.bSectorCountReg = lo.sector_count;
2603 regs.bSectorNumberReg = lo.lba_low;
2604 regs.bCylLowReg = lo.lba_mid;
2605 regs.bCylHighReg = lo.lba_high;
2606 regs.bDriveHeadReg = lo.device;
2607 regs.bCommandReg = lo.command;
2608 regs.bReserved = 0;
2609 }
2610 if (in.in_regs.is_48bit_cmd()) {
2611 const ata_in_regs & hi = in.in_regs.prev;
2612 prev_regs.bFeaturesReg = hi.features;
2613 prev_regs.bSectorCountReg = hi.sector_count;
2614 prev_regs.bSectorNumberReg = hi.lba_low;
2615 prev_regs.bCylLowReg = hi.lba_mid;
2616 prev_regs.bCylHighReg = hi.lba_high;
2617 prev_regs.bDriveHeadReg = hi.device;
2618 prev_regs.bCommandReg = hi.command;
2619 prev_regs.bReserved = 0;
2620 }
2621
2622 // Set data direction
2623 int datasize = 0;
2624 char * data = 0;
2625 switch (in.direction) {
2626 case ata_cmd_in::no_data:
2627 break;
2628 case ata_cmd_in::data_in:
2629 datasize = (int)in.size;
2630 data = (char *)in.buffer;
2631 break;
2632 case ata_cmd_in::data_out:
2633 datasize = -(int)in.size;
2634 data = (char *)in.buffer;
2635 break;
2636 default:
2637 return set_err(EINVAL, "win_ata_device::ata_pass_through: invalid direction=%d",
2638 (int)in.direction);
2639 }
2640
2641
2642 // Try all valid ioctls in the order specified in m_options
2643 bool powered_up = false;
2644 bool out_regs_set = false;
2645 const char * options = m_options.c_str();
2646
2647 for (int i = 0; ; i++) {
2648 char opt = options[i];
2649
2650 if (!opt) {
2651 if (in.in_regs.command == ATA_CHECK_POWER_MODE && powered_up) {
2652 // Power up reported by GetDevicePowerState() and no ioctl available
2653 // to detect the actual mode of the drive => simulate ATA result ACTIVE/IDLE.
2654 regs.bSectorCountReg = 0xff;
2655 out_regs_set = true;
2656 break;
2657 }
2658 // No IOCTL found
2659 return set_err(ENOSYS);
2660 }
2661 if (!strchr(valid_options, opt))
2662 // Invalid for this command
2663 continue;
2664
2665 errno = 0;
2666 assert( datasize == 0 || datasize == 512
2667 || (datasize == -512 && strchr("am", opt))
2668 || (datasize > 512 && opt == 'a'));
2669 int rc;
2670 switch (opt) {
2671 default: assert(0);
2672 case 's':
2673 // call SMART_GET_VERSION once for each drive
2674 if (m_smartver_state > 1) {
2675 rc = -1; errno = ENOSYS;
2676 break;
2677 }
2678 if (!m_smartver_state) {
2679 assert(m_port == -1);
2680 if (smart_get_version(get_fh()) < 0) {
2681 if (!con->permissive) {
2682 m_smartver_state = 2;
2683 rc = -1; errno = ENOSYS;
2684 break;
2685 }
2686 con->permissive--;
2687 }
2688 m_smartver_state = 1;
2689 }
2690 rc = smart_ioctl(get_fh(), m_drive, &regs, data, datasize, m_port);
2691 out_regs_set = (in.in_regs.features == ATA_SMART_STATUS);
2692 break;
2693 case 'm':
2694 rc = ata_via_scsi_miniport_smart_ioctl(get_fh(), &regs, data, datasize);
2695 break;
2696 case 'a':
2697 rc = ata_pass_through_ioctl(get_fh(), &regs,
2698 (in.in_regs.is_48bit_cmd() ? &prev_regs : 0),
2699 data, datasize);
2700 out_regs_set = true;
2701 break;
2702 case 'i':
2703 rc = ide_pass_through_ioctl(get_fh(), &regs, data, datasize);
2704 out_regs_set = true;
2705 break;
2706 case 'c':
2707 rc = ata_via_scsi_pass_through_ioctl(get_fh(), &regs, data, datasize);
2708 break;
2709 case 'f':
2710 if (in.in_regs.command == ATA_IDENTIFY_DEVICE) {
2711 rc = get_identify_from_device_property(get_fh(), (ata_identify_device *)data);
2712 }
2713 else if (in.in_regs.command == ATA_SMART_CMD) switch (in.in_regs.features) {
2714 case ATA_SMART_READ_VALUES:
2715 rc = storage_predict_failure_ioctl(get_fh(), data);
2716 if (rc > 0)
2717 rc = 0;
2718 break;
2719 case ATA_SMART_READ_THRESHOLDS:
2720 {
2721 ata_smart_values sv;
2722 rc = storage_predict_failure_ioctl(get_fh(), (char *)&sv);
2723 if (rc < 0)
2724 break;
2725 rc = 0;
2726 // Fake zero thresholds
2727 ata_smart_thresholds_pvt * tr = (ata_smart_thresholds_pvt *)data;
2728 memset(tr, 0, 512);
2729 for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++)
2730 tr->chksum -= tr->thres_entries[i].id = sv.vendor_attributes[i].id;
2731 }
2732 break;
2733 case ATA_SMART_ENABLE:
2734 rc = 0;
2735 break;
2736 case ATA_SMART_STATUS:
2737 rc = storage_predict_failure_ioctl(get_fh());
2738 if (rc >= 0) {
2739 if (rc > 0) {
2740 regs.bCylHighReg = 0x2c; regs.bCylLowReg = 0xf4;
2741 rc = 0;
2742 }
2743 out_regs_set = true;
2744 }
2745 break;
2746 default:
2747 errno = ENOSYS; rc = -1;
2748 }
2749 else {
2750 errno = ENOSYS; rc = -1;
2751 }
2752 break;
2753 case '3':
2754 rc = ata_via_3ware_miniport_ioctl(get_fh(), &regs, data, datasize, m_port);
2755 out_regs_set = true;
2756 break;
2757 case 'p':
2758 assert(in.in_regs.command == ATA_CHECK_POWER_MODE && in.size == 0);
2759 rc = get_device_power_state(get_fh());
2760 if (rc == 0) {
2761 // Power down reported by GetDevicePowerState(), using a passthrough ioctl would
2762 // spin up the drive => simulate ATA result STANDBY.
2763 regs.bSectorCountReg = 0x00;
2764 out_regs_set = true;
2765 }
2766 else if (rc > 0) {
2767 // Power up reported by GetDevicePowerState(), but this reflects the actual mode
2768 // only if it is selected by the device driver => try a passthrough ioctl to get the
2769 // actual mode, if none available simulate ACTIVE/IDLE.
2770 powered_up = true;
2771 rc = -1; errno = ENOSYS;
2772 }
2773 break;
2774 }
2775
2776 if (!rc)
2777 // Working ioctl found
2778 break;
2779
2780 if (errno != ENOSYS)
2781 // Abort on I/O error
2782 return set_err(errno);
2783
2784 out_regs_set = false;
2785 // CAUTION: *_ioctl() MUST NOT change "regs" Parameter in the ENOSYS case
2786 }
2787
2788 // Return IDEREGS if set
2789 if (out_regs_set) {
2790 ata_out_regs & lo = out.out_regs;
2791 lo.error = regs.bFeaturesReg;
2792 lo.sector_count = regs.bSectorCountReg;
2793 lo.lba_low = regs.bSectorNumberReg;
2794 lo.lba_mid = regs.bCylLowReg;
2795 lo.lba_high = regs.bCylHighReg;
2796 lo.device = regs.bDriveHeadReg;
2797 lo.status = regs.bCommandReg;
2798 if (in.in_regs.is_48bit_cmd()) {
2799 ata_out_regs & hi = out.out_regs.prev;
2800 hi.sector_count = prev_regs.bSectorCountReg;
2801 hi.lba_low = prev_regs.bSectorNumberReg;
2802 hi.lba_mid = prev_regs.bCylLowReg;
2803 hi.lba_high = prev_regs.bCylHighReg;
2804 }
2805 }
2806 return true;
2807 }
2808
2809 // Return true if OS caches the ATA identify sector
2810 bool win_ata_device::ata_identify_is_cached() const
2811 {
2812 // Not RAID and WinNT4/2000/XP => true, RAID or Win9x/ME => false
2813 // TODO: Set according to ioctl used.
2814 return (m_port < 0 && !is_win9x());
2815 }
2816
2817
2818 /////////////////////////////////////////////////////////////////////////////
2819 // ASPI Interface (for SCSI devices)
2820 /////////////////////////////////////////////////////////////////////////////
2821
2822 #pragma pack(1)
2823
2824 #define ASPI_SENSE_SIZE 18
2825
2826 // ASPI SCSI Request block header
2827
2828 typedef struct {
2829 unsigned char cmd; // 00: Command code
2830 unsigned char status; // 01: ASPI status
2831 unsigned char adapter; // 02: Host adapter number
2832 unsigned char flags; // 03: Request flags
2833 unsigned char reserved[4]; // 04: 0
2834 } ASPI_SRB_HEAD;
2835
2836 // SRB for host adapter inquiry
2837
2838 typedef struct {
2839 ASPI_SRB_HEAD h; // 00: Header
2840 unsigned char adapters; // 08: Number of adapters
2841 unsigned char target_id; // 09: Target ID ?
2842 char manager_id[16]; // 10: SCSI manager ID
2843 char adapter_id[16]; // 26: Host adapter ID
2844 unsigned char parameters[16]; // 42: Host adapter unique parmameters
2845 } ASPI_SRB_INQUIRY;
2846
2847 // SRB for get device type
2848
2849 typedef struct {
2850 ASPI_SRB_HEAD h; // 00: Header
2851 unsigned char target_id; // 08: Target ID
2852 unsigned char lun; // 09: LUN
2853 unsigned char devtype; // 10: Device type
2854 unsigned char reserved; // 11: Reserved
2855 } ASPI_SRB_DEVTYPE;
2856
2857 // SRB for SCSI I/O
2858
2859 typedef struct {
2860 ASPI_SRB_HEAD h; // 00: Header
2861 unsigned char target_id; // 08: Target ID
2862 unsigned char lun; // 09: LUN
2863 unsigned char reserved[2]; // 10: Reserved
2864 unsigned long data_size; // 12: Data alloc. lenght
2865 void * data_addr; // 16: Data buffer pointer
2866 unsigned char sense_size; // 20: Sense alloc. length
2867 unsigned char cdb_size; // 21: CDB length
2868 unsigned char host_status; // 22: Host status
2869 unsigned char target_status; // 23: Target status
2870 void * event_handle; // 24: Event handle
2871 unsigned char workspace[20]; // 28: ASPI workspace
2872 unsigned char cdb[16+ASPI_SENSE_SIZE];
2873 } ASPI_SRB_IO;
2874
2875 // Macro to retrieve start of sense information
2876 #define ASPI_SRB_SENSE(srb,cdbsz) ((srb)->cdb + 16)
2877
2878 // SRB union
2879
2880 typedef union {
2881 ASPI_SRB_HEAD h; // Common header
2882 ASPI_SRB_INQUIRY q; // Inquiry
2883 ASPI_SRB_DEVTYPE t; // Device type
2884 ASPI_SRB_IO i; // I/O
2885 } ASPI_SRB;
2886
2887 #pragma pack()
2888
2889 // ASPI commands
2890 #define ASPI_CMD_ADAPTER_INQUIRE 0x00
2891 #define ASPI_CMD_GET_DEVICE_TYPE 0x01
2892 #define ASPI_CMD_EXECUTE_IO 0x02
2893 #define ASPI_CMD_ABORT_IO 0x03
2894
2895 // Request flags
2896 #define ASPI_REQFLAG_DIR_TO_HOST 0x08
2897 #define ASPI_REQFLAG_DIR_TO_TARGET 0x10
2898 #define ASPI_REQFLAG_DIR_NO_XFER 0x18
2899 #define ASPI_REQFLAG_EVENT_NOTIFY 0x40
2900
2901 // ASPI status
2902 #define ASPI_STATUS_IN_PROGRESS 0x00
2903 #define ASPI_STATUS_NO_ERROR 0x01
2904 #define ASPI_STATUS_ABORTED 0x02
2905 #define ASPI_STATUS_ABORT_ERR 0x03
2906 #define ASPI_STATUS_ERROR 0x04
2907 #define ASPI_STATUS_INVALID_COMMAND 0x80
2908 #define ASPI_STATUS_INVALID_ADAPTER 0x81
2909 #define ASPI_STATUS_INVALID_TARGET 0x82
2910 #define ASPI_STATUS_NO_ADAPTERS 0xE8
2911
2912 // Adapter (host) status
2913 #define ASPI_HSTATUS_NO_ERROR 0x00
2914 #define ASPI_HSTATUS_SELECTION_TIMEOUT 0x11
2915 #define ASPI_HSTATUS_DATA_OVERRUN 0x12
2916 #define ASPI_HSTATUS_BUS_FREE 0x13
2917 #define ASPI_HSTATUS_BUS_PHASE_ERROR 0x14
2918 #define ASPI_HSTATUS_BAD_SGLIST 0x1A
2919
2920 // Target status
2921 #define ASPI_TSTATUS_NO_ERROR 0x00
2922 #define ASPI_TSTATUS_CHECK_CONDITION 0x02
2923 #define ASPI_TSTATUS_BUSY 0x08
2924 #define ASPI_TSTATUS_RESERV_CONFLICT 0x18
2925
2926
2927 static HINSTANCE h_aspi_dll; // DLL handle
2928 static UINT (* aspi_entry)(ASPI_SRB * srb); // ASPI entrypoint
2929 static unsigned num_aspi_adapters;
2930
2931 #ifdef __CYGWIN__
2932 // h_aspi_dll+aspi_entry is not inherited by Cygwin's fork()
2933 static DWORD aspi_dll_pid; // PID of DLL owner to detect fork()
2934 #define aspi_entry_valid() (aspi_entry && (aspi_dll_pid == GetCurrentProcessId()))
2935 #else
2936 #define aspi_entry_valid() (!!aspi_entry)
2937 #endif
2938
2939
2940 static int aspi_call(ASPI_SRB * srb)
2941 {
2942 int i;
2943 aspi_entry(srb);
2944 i = 0;
2945 while (((volatile ASPI_SRB *)srb)->h.status == ASPI_STATUS_IN_PROGRESS) {
2946 if (++i > 100/*10sek*/) {
2947 pout("ASPI Adapter %u: Timed out\n", srb->h.adapter);
2948 aspi_entry = 0;
2949 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
2950 errno = EIO;
2951 return -1;
2952 }
2953 if (con->reportscsiioctl > 1)
2954 pout("ASPI Adapter %u: Waiting (%d) ...\n", srb->h.adapter, i);
2955 Sleep(100);
2956 }
2957 return 0;
2958 }
2959
2960
2961 // Get ASPI entrypoint from wnaspi32.dll
2962
2963 static FARPROC aspi_get_address(const char * name, int verbose)
2964 {
2965 FARPROC addr;
2966 assert(h_aspi_dll && h_aspi_dll != INVALID_HANDLE_VALUE);
2967
2968 if (!(addr = GetProcAddress(h_aspi_dll, name))) {
2969 if (verbose)
2970 pout("Missing %s() in WNASPI32.DLL\n", name);
2971 aspi_entry = 0;
2972 FreeLibrary(h_aspi_dll);
2973 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
2974 errno = ENOSYS;
2975 return 0;
2976 }
2977 return addr;
2978 }
2979
2980
2981 static int aspi_open_dll(int verbose)
2982 {
2983 UINT (*aspi_info)(void);
2984 UINT info, rc;
2985
2986 assert(!aspi_entry_valid());
2987
2988 // Check structure layout
2989 assert(sizeof(ASPI_SRB_HEAD) == 8);
2990 assert(sizeof(ASPI_SRB_INQUIRY) == 58);
2991 assert(sizeof(ASPI_SRB_DEVTYPE) == 12);
2992 assert(sizeof(ASPI_SRB_IO) == 64+ASPI_SENSE_SIZE);
2993 assert(offsetof(ASPI_SRB,h.cmd) == 0);
2994 assert(offsetof(ASPI_SRB,h.flags) == 3);
2995 assert(offsetof(ASPI_SRB_IO,lun) == 9);
2996 assert(offsetof(ASPI_SRB_IO,data_addr) == 16);
2997 assert(offsetof(ASPI_SRB_IO,workspace) == 28);
2998 assert(offsetof(ASPI_SRB_IO,cdb) == 48);
2999
3000 if (h_aspi_dll == INVALID_HANDLE_VALUE) {
3001 // do not retry
3002 errno = ENOENT;
3003 return -1;
3004 }
3005
3006 // Load ASPI DLL
3007 if (!(h_aspi_dll = LoadLibraryA("WNASPI32.DLL"))) {
3008 if (verbose)
3009 pout("Cannot load WNASPI32.DLL, Error=%ld\n", GetLastError());
3010 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
3011 errno = ENOENT;
3012 return -1;
3013 }
3014 if (con->reportscsiioctl > 1) {
3015 // Print full path of WNASPI32.DLL
3016 char path[MAX_PATH];
3017 if (!GetModuleFileName(h_aspi_dll, path, sizeof(path)))
3018 strcpy(path, "*unknown*");
3019 pout("Using ASPI interface \"%s\"\n", path);
3020 }
3021
3022 // Get ASPI entrypoints
3023 if (!(aspi_info = (UINT (*)(void))aspi_get_address("GetASPI32SupportInfo", verbose)))
3024 return -1;
3025 if (!(aspi_entry = (UINT (*)(ASPI_SRB *))aspi_get_address("SendASPI32Command", verbose)))
3026 return -1;
3027
3028 // Init ASPI manager and get number of adapters
3029 info = (aspi_info)();
3030 if (con->reportscsiioctl > 1)
3031 pout("GetASPI32SupportInfo() returns 0x%04x\n", info);
3032 rc = (info >> 8) & 0xff;
3033 if (rc == ASPI_STATUS_NO_ADAPTERS) {
3034 num_aspi_adapters = 0;
3035 }
3036 else if (rc == ASPI_STATUS_NO_ERROR) {
3037 num_aspi_adapters = info & 0xff;
3038 }
3039 else {
3040 if (verbose)
3041 pout("Got strange 0x%04x from GetASPI32SupportInfo()\n", info);
3042 aspi_entry = 0;
3043 FreeLibrary(h_aspi_dll);
3044 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
3045 errno = ENOENT;
3046 return -1;
3047 }
3048
3049 if (con->reportscsiioctl)
3050 pout("%u ASPI Adapter%s detected\n",num_aspi_adapters, (num_aspi_adapters!=1?"s":""));
3051
3052 #ifdef __CYGWIN__
3053 // save PID to detect fork() in aspi_entry_valid()
3054 aspi_dll_pid = GetCurrentProcessId();
3055 #endif
3056 assert(aspi_entry_valid());
3057 return 0;
3058 }
3059
3060
3061 static int aspi_io_call(ASPI_SRB * srb, unsigned timeout)
3062 {
3063 HANDLE event;
3064 // Create event
3065 if (!(event = CreateEventA(NULL, FALSE, FALSE, NULL))) {
3066 pout("CreateEvent(): Error=%ld\n", GetLastError()); return -EIO;
3067 }
3068 srb->i.event_handle = event;
3069 srb->h.flags |= ASPI_REQFLAG_EVENT_NOTIFY;
3070 // Start ASPI request
3071 aspi_entry(srb);
3072 if (((volatile ASPI_SRB *)srb)->h.status == ASPI_STATUS_IN_PROGRESS) {
3073 // Wait for event
3074 DWORD rc = WaitForSingleObject(event, timeout*1000L);
3075 if (rc != WAIT_OBJECT_0) {
3076 if (rc == WAIT_TIMEOUT) {
3077 pout("ASPI Adapter %u, ID %u: Timed out after %u seconds\n",
3078 srb->h.adapter, srb->i.target_id, timeout);
3079 }
3080 else {
3081 pout("WaitForSingleObject(%lx) = 0x%lx,%ld, Error=%ld\n",
3082 (unsigned long)event, rc, rc, GetLastError());
3083 }
3084 // TODO: ASPI_ABORT_IO command
3085 aspi_entry = 0;
3086 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
3087 return -EIO;
3088 }
3089 }
3090 CloseHandle(event);
3091 return 0;
3092 }
3093
3094
3095 win_aspi_device::win_aspi_device(smart_interface * intf,
3096 const char * dev_name, const char * req_type)
3097 : smart_device(intf, dev_name, "scsi", req_type),
3098 m_adapter(-1), m_id(0)
3099 {
3100 }
3101
3102 bool win_aspi_device::is_open() const
3103 {
3104 return (m_adapter >= 0);
3105 }
3106
3107 bool win_aspi_device::open()
3108 {
3109 // scsi[0-9][0-f] => ASPI Adapter 0-9, ID 0-15, LUN 0
3110 unsigned adapter = ~0, id = ~0; int n1 = -1;
3111 const char * name = skipdev(get_dev_name());
3112 if (!(sscanf(name,"scsi%1u%1x%n", &adapter, &id, &n1) == 2 && n1 == (int)strlen(name)
3113 && adapter <= 9 && id < 16))
3114 return set_err(EINVAL);
3115
3116 if (!aspi_entry_valid()) {
3117 if (aspi_open_dll(1/*verbose*/))
3118 return set_err(ENOENT);
3119 }
3120
3121 // Adapter OK?
3122 if (adapter >= num_aspi_adapters) {
3123 pout("ASPI Adapter %u does not exist (%u Adapter%s detected).\n",
3124 adapter, num_aspi_adapters, (num_aspi_adapters!=1?"s":""));
3125 if (!is_permissive())
3126 return set_err(ENOENT);
3127 }
3128
3129 // Device present ?
3130 ASPI_SRB srb;
3131 memset(&srb, 0, sizeof(srb));
3132 srb.h.cmd = ASPI_CMD_GET_DEVICE_TYPE;
3133 srb.h.adapter = adapter; srb.i.target_id = id;
3134 if (aspi_call(&srb))
3135 return set_err(EIO);
3136 if (srb.h.status != ASPI_STATUS_NO_ERROR) {
3137 pout("ASPI Adapter %u, ID %u: No such device (Status=0x%02x)\n", adapter, id, srb.h.status);
3138 if (!is_permissive())
3139 return set_err(srb.h.status == ASPI_STATUS_INVALID_TARGET ? ENOENT : EIO);
3140 }
3141 else if (con->reportscsiioctl)
3142 pout("ASPI Adapter %u, ID %u: Device Type=0x%02x\n", adapter, id, srb.t.devtype);
3143
3144 m_adapter = (int)adapter; m_id = (unsigned char)id;
3145 return true;
3146 }
3147
3148
3149 bool win_aspi_device::close()
3150 {
3151 // No FreeLibrary(h_aspi_dll) to prevent problems with ASPI threads
3152 return true;
3153 }
3154
3155
3156 // Scan for ASPI drives
3157
3158 bool win9x_smart_interface::scsi_scan(smart_device_list & devlist)
3159 {
3160 if (!aspi_entry_valid()) {
3161 if (aspi_open_dll(con->reportscsiioctl/*default is quiet*/))
3162 return true;
3163 }
3164
3165 for (unsigned ad = 0; ad < num_aspi_adapters; ad++) {
3166 ASPI_SRB srb;
3167
3168 if (ad > 9) {
3169 if (con->reportscsiioctl)
3170 pout(" ASPI Adapter %u: Ignored\n", ad);
3171 continue;
3172 }
3173
3174 // Get adapter name
3175 memset(&srb, 0, sizeof(srb));
3176 srb.h.cmd = ASPI_CMD_ADAPTER_INQUIRE;
3177 srb.h.adapter = ad;
3178 if (aspi_call(&srb))
3179 break;
3180
3181 if (srb.h.status != ASPI_STATUS_NO_ERROR) {
3182 if (con->reportscsiioctl)
3183 pout(" ASPI Adapter %u: Status=0x%02x\n", ad, srb.h.status);
3184 continue;
3185 }
3186
3187 if (con->reportscsiioctl) {
3188 for (int i = 1; i < 16 && srb.q.adapter_id[i]; i++)
3189 if (!(' ' <= srb.q.adapter_id[i] && srb.q.adapter_id[i] <= '~'))
3190 srb.q.adapter_id[i] = '?';
3191 pout(" ASPI Adapter %u (\"%.16s\"):\n", ad, srb.q.adapter_id);
3192 }
3193
3194 bool ignore = !strnicmp(srb.q.adapter_id, "3ware", 5);
3195
3196 for (unsigned id = 0; id <= 7; id++) {
3197 // Get device type
3198 memset(&srb, 0, sizeof(srb));
3199 srb.h.cmd = ASPI_CMD_GET_DEVICE_TYPE;
3200 srb.h.adapter = ad; srb.i.target_id = id;
3201 if (aspi_call(&srb))
3202 return 0;
3203 if (srb.h.status != ASPI_STATUS_NO_ERROR) {
3204 if (con->reportscsiioctl > 1)
3205 pout(" ID %u: No such device (Status=0x%02x)\n", id, srb.h.status);
3206 continue;
3207 }
3208
3209 if (!ignore && srb.t.devtype == 0x00/*HDD*/) {
3210 if (con->reportscsiioctl)
3211 pout(" ID %u: Device Type=0x%02x\n", id, srb.t.devtype);
3212 char name[20];
3213 sprintf(name, "/dev/scsi%u%u", ad, id);
3214 devlist.push_back( new win_aspi_device(this, name, "scsi") );
3215 }
3216 else if (con->reportscsiioctl)
3217 pout(" ID %u: Device Type=0x%02x (ignored)\n", id, srb.t.devtype);
3218 }
3219 }
3220 return true;
3221 }
3222
3223
3224 // Interface to ASPI SCSI devices
3225 bool win_aspi_device::scsi_pass_through(scsi_cmnd_io * iop)
3226 {
3227 int report = con->reportscsiioctl; // TODO
3228
3229 if (m_adapter < 0) {
3230 set_err(EBADF);
3231 return false;
3232 }
3233
3234 if (!aspi_entry_valid()) {
3235 set_err(EBADF);
3236 return false;
3237 }
3238
3239 if (!(iop->cmnd_len == 6 || iop->cmnd_len == 10 || iop->cmnd_len == 12 || iop->cmnd_len == 16)) {
3240 set_err(EINVAL, "bad CDB length");
3241 return false;
3242 }
3243
3244 if (report > 0) {
3245 // From os_linux.c
3246 int k, j;
3247 const unsigned char * ucp = iop->cmnd;
3248 const char * np;
3249 char buff[256];
3250 const int sz = (int)sizeof(buff);
3251
3252 np = scsi_get_opcode_name(ucp[0]);
3253 j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
3254 for (k = 0; k < (int)iop->cmnd_len; ++k)
3255 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);
3256 if ((report > 1) &&
3257 (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
3258 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
3259
3260 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing "
3261 "data, len=%d%s:\n", (int)iop->dxfer_len,
3262 (trunc ? " [only first 256 bytes shown]" : ""));
3263 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
3264 }
3265 else
3266 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
3267 pout(buff);
3268 }
3269
3270 ASPI_SRB srb;
3271 memset(&srb, 0, sizeof(srb));
3272 srb.h.cmd = ASPI_CMD_EXECUTE_IO;
3273 srb.h.adapter = m_adapter;
3274 srb.i.target_id = m_id;
3275 //srb.i.lun = 0;
3276 srb.i.sense_size = ASPI_SENSE_SIZE;
3277 srb.i.cdb_size = iop->cmnd_len;
3278 memcpy(srb.i.cdb, iop->cmnd, iop->cmnd_len);
3279
3280 switch (iop->dxfer_dir) {
3281 case DXFER_NONE:
3282 srb.h.flags = ASPI_REQFLAG_DIR_NO_XFER;
3283 break;
3284 case DXFER_FROM_DEVICE:
3285 srb.h.flags = ASPI_REQFLAG_DIR_TO_HOST;
3286 srb.i.data_size = iop->dxfer_len;
3287 srb.i.data_addr = iop->dxferp;
3288 break;
3289 case DXFER_TO_DEVICE:
3290 srb.h.flags = ASPI_REQFLAG_DIR_TO_TARGET;
3291 srb.i.data_size = iop->dxfer_len;
3292 srb.i.data_addr = iop->dxferp;
3293 break;
3294 default:
3295 set_err(EINVAL, "bad dxfer_dir");
3296 return false;
3297 }
3298
3299 iop->resp_sense_len = 0;
3300 iop->scsi_status = 0;
3301 iop->resid = 0;
3302
3303 if (aspi_io_call(&srb, (iop->timeout ? iop->timeout : 60))) {
3304 // Timeout
3305 set_err(EIO, "ASPI Timeout"); return false;
3306 }
3307
3308 if (srb.h.status != ASPI_STATUS_NO_ERROR) {
3309 if ( srb.h.status == ASPI_STATUS_ERROR
3310 && srb.i.host_status == ASPI_HSTATUS_NO_ERROR
3311 && srb.i.target_status == ASPI_TSTATUS_CHECK_CONDITION) {
3312 // Sense valid
3313 const unsigned char * sense = ASPI_SRB_SENSE(&srb.i, iop->cmnd_len);
3314 int len = (ASPI_SENSE_SIZE < iop->max_sense_len ? ASPI_SENSE_SIZE : iop->max_sense_len);
3315 iop->scsi_status = SCSI_STATUS_CHECK_CONDITION;
3316 if (len > 0 && iop->sensep) {
3317 memcpy(iop->sensep, sense, len);
3318 iop->resp_sense_len = len;
3319 if (report > 1) {
3320 pout(" >>> Sense buffer, len=%d:\n", (int)len);
3321 dStrHex(iop->sensep, len , 1);
3322 }
3323 }
3324 if (report) {
3325 pout(" sense_key=%x asc=%x ascq=%x\n",
3326 sense[2] & 0xf, sense[12], sense[13]);
3327 }
3328 return true;
3329 }
3330 else {
3331 if (report)
3332 pout(" ASPI call failed, (0x%02x,0x%02x,0x%02x)\n", srb.h.status, srb.i.host_status, srb.i.target_status);
3333 set_err(EIO);
3334 return false;
3335 }
3336 }
3337
3338 if (report > 0)
3339 pout(" OK\n");
3340
3341 if (iop->dxfer_dir == DXFER_FROM_DEVICE && report > 1) {
3342 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
3343 pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
3344 (trunc ? " [only first 256 bytes shown]" : ""));
3345 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
3346 }
3347
3348 return true;
3349 }
3350
3351
3352 /////////////////////////////////////////////////////////////////////////////
3353 // SPT Interface (for SCSI devices and ATA devices behind SATLs)
3354 // Only supported in NT and later
3355 /////////////////////////////////////////////////////////////////////////////
3356
3357 win_scsi_device::win_scsi_device(smart_interface * intf,
3358 const char * dev_name, const char * req_type)
3359 : smart_device(intf, dev_name, "scsi", req_type)
3360 {
3361 }
3362
3363 bool win_scsi_device::open()
3364 {
3365 const char * name = skipdev(get_dev_name()); int len = strlen(name);
3366 // sd[a-z],N => Physical drive 0-26, RAID port N
3367 char drive[1+1] = ""; int sub_addr = -1; int n1 = -1; int n2 = -1;
3368 if ( sscanf(name, "sd%1[a-z]%n,%d%n", drive, &n1, &sub_addr, &n2) >= 1
3369 && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0)) ) {
3370 return open(drive[0] - 'a', -1, -1, sub_addr);
3371 }
3372 // pd<m>,N => Physical drive <m>, RAID port N
3373 int pd_num = -1; sub_addr = -1; n1 = -1; n2 = -1;
3374 if ( sscanf(name, "pd%d%n,%d%n", &pd_num, &n1, &sub_addr, &n2) >= 1
3375 && pd_num >= 0 && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0))) {
3376 return open(pd_num, -1, -1, sub_addr);
3377 }
3378 // [a-zA-Z]: => Physical drive behind logical drive 0-25
3379 int logdrive = drive_letter(name);
3380 if (logdrive >= 0) {
3381 return open(-1, logdrive, -1, -1);
3382 }
3383 // n?st<m> => tape drive <m> (same names used in Cygwin's /dev emulation)
3384 int tape_num = -1; n1 = -1;
3385 if (sscanf(name, "st%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) {
3386 return open(-1, -1, tape_num, -1);
3387 }
3388 tape_num = -1; n1 = -1;
3389 if (sscanf(name, "nst%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) {
3390 return open(-1, -1, tape_num, -1);
3391 }
3392 // tape<m> => tape drive <m>
3393 tape_num = -1; n1 = -1;
3394 if (sscanf(name, "tape%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) {
3395 return open(-1, -1, tape_num, -1);
3396 }
3397
3398 return set_err(EINVAL);
3399 }
3400
3401 bool win_scsi_device::open(int pd_num, int ld_num, int tape_num, int /*sub_addr*/)
3402 {
3403 char b[128];
3404 b[sizeof(b) - 1] = '\0';
3405 if (pd_num >= 0)
3406 snprintf(b, sizeof(b) - 1, "\\\\.\\PhysicalDrive%d", pd_num);
3407 else if (ld_num >= 0)
3408 snprintf(b, sizeof(b) - 1, "\\\\.\\%c:", 'A' + ld_num);
3409 else if (tape_num >= 0)
3410 snprintf(b, sizeof(b) - 1, "\\\\.\\TAPE%d", tape_num);
3411 else {
3412 set_err(EINVAL);
3413 return false;
3414 }
3415
3416 // Open device
3417 HANDLE h = CreateFileA(b, GENERIC_READ|GENERIC_WRITE,
3418 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
3419 OPEN_EXISTING, 0, 0);
3420 if (h == INVALID_HANDLE_VALUE) {
3421 set_err(ENODEV, "%s: Open failed, Error=%ld", b, GetLastError());
3422 return false;
3423 }
3424 set_fh(h);
3425 return true;
3426 }
3427
3428
3429 bool winnt_smart_interface::scsi_scan(smart_device_list & devlist)
3430 {
3431 char name[20];
3432 for (int i = 0; i <= 9; i++) {
3433 if (get_phy_drive_type(i) != DEV_SCSI)
3434 continue;
3435 // STORAGE_QUERY_PROPERTY returned SCSI/SAS/...
3436 sprintf(name, "/dev/sd%c", 'a'+i);
3437 devlist.push_back( new win_scsi_device(this, name, "scsi") );
3438 }
3439 return true;
3440 }
3441
3442
3443 #define IOCTL_SCSI_PASS_THROUGH_DIRECT \
3444 CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
3445
3446 typedef struct _SCSI_PASS_THROUGH_DIRECT {
3447 USHORT Length;
3448 UCHAR ScsiStatus;
3449 UCHAR PathId;
3450 UCHAR TargetId;
3451 UCHAR Lun;
3452 UCHAR CdbLength;
3453 UCHAR SenseInfoLength;
3454 UCHAR DataIn;
3455 ULONG DataTransferLength;
3456 ULONG TimeOutValue;
3457 PVOID DataBuffer;
3458 ULONG SenseInfoOffset;
3459 UCHAR Cdb[16];
3460 } SCSI_PASS_THROUGH_DIRECT;
3461
3462 typedef struct {
3463 SCSI_PASS_THROUGH_DIRECT spt;
3464 ULONG Filler;
3465 UCHAR ucSenseBuf[64];
3466 } SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
3467
3468
3469 // Issue command via IOCTL_SCSI_PASS_THROUGH instead of *_DIRECT.
3470 // Used if DataTransferLength not supported by *_DIRECT.
3471 static long scsi_pass_through_indirect(HANDLE h,
3472 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER * sbd)
3473 {
3474 struct SCSI_PASS_THROUGH_WITH_BUFFERS {
3475 SCSI_PASS_THROUGH spt;
3476 ULONG Filler;
3477 UCHAR ucSenseBuf[sizeof(sbd->ucSenseBuf)];
3478 UCHAR ucDataBuf[512];
3479 };
3480
3481 SCSI_PASS_THROUGH_WITH_BUFFERS sb;
3482 memset(&sb, 0, sizeof(sb));
3483
3484 // DATA_OUT not implemented yet
3485 if (!( sbd->spt.DataIn == SCSI_IOCTL_DATA_IN
3486 && sbd->spt.DataTransferLength <= sizeof(sb.ucDataBuf)))
3487 return ERROR_INVALID_PARAMETER;
3488
3489 sb.spt.Length = sizeof(sb.spt);
3490 sb.spt.CdbLength = sbd->spt.CdbLength;
3491 memcpy(sb.spt.Cdb, sbd->spt.Cdb, sizeof(sb.spt.Cdb));
3492 sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf);
3493 sb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf);
3494 sb.spt.DataIn = sbd->spt.DataIn;
3495 sb.spt.DataTransferLength = sbd->spt.DataTransferLength;
3496 sb.spt.DataBufferOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf);
3497 sb.spt.TimeOutValue = sbd->spt.TimeOutValue;
3498
3499 DWORD num_out;
3500 if (!DeviceIoControl(h, IOCTL_SCSI_PASS_THROUGH,
3501 &sb, sizeof(sb), &sb, sizeof(sb), &num_out, 0))
3502 return GetLastError();
3503
3504 sbd->spt.ScsiStatus = sb.spt.ScsiStatus;
3505 if (sb.spt.ScsiStatus & SCSI_STATUS_CHECK_CONDITION)
3506 memcpy(sbd->ucSenseBuf, sb.ucSenseBuf, sizeof(sbd->ucSenseBuf));
3507
3508 sbd->spt.DataTransferLength = sb.spt.DataTransferLength;
3509 if (sbd->spt.DataIn == SCSI_IOCTL_DATA_IN && sb.spt.DataTransferLength > 0)
3510 memcpy(sbd->spt.DataBuffer, sb.ucDataBuf, sb.spt.DataTransferLength);
3511 return 0;
3512 }
3513
3514
3515 // Interface to SPT SCSI devices. See scsicmds.h and os_linux.c
3516 bool win_scsi_device::scsi_pass_through(struct scsi_cmnd_io * iop)
3517 {
3518 int report = con->reportscsiioctl; // TODO
3519
3520 if (report > 0) {
3521 int k, j;
3522 const unsigned char * ucp = iop->cmnd;
3523 const char * np;
3524 char buff[256];
3525 const int sz = (int)sizeof(buff);
3526
3527 np = scsi_get_opcode_name(ucp[0]);
3528 j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
3529 for (k = 0; k < (int)iop->cmnd_len; ++k)
3530 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);
3531 if ((report > 1) &&
3532 (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
3533 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
3534
3535 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing "
3536 "data, len=%d%s:\n", (int)iop->dxfer_len,
3537 (trunc ? " [only first 256 bytes shown]" : ""));
3538 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
3539 }
3540 else
3541 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
3542 pout(buff);
3543 }
3544
3545 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb;
3546 if (iop->cmnd_len > (int)sizeof(sb.spt.Cdb)) {
3547 set_err(EINVAL, "cmnd_len too large");
3548 return false;
3549 }
3550
3551 memset(&sb, 0, sizeof(sb));
3552 sb.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
3553 sb.spt.CdbLength = iop->cmnd_len;
3554 memcpy(sb.spt.Cdb, iop->cmnd, iop->cmnd_len);
3555 sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf);
3556 sb.spt.SenseInfoOffset =
3557 offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
3558 sb.spt.TimeOutValue = (iop->timeout ? iop->timeout : 60);
3559
3560 bool direct = true;
3561 switch (iop->dxfer_dir) {
3562 case DXFER_NONE:
3563 sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
3564 break;
3565 case DXFER_FROM_DEVICE:
3566 sb.spt.DataIn = SCSI_IOCTL_DATA_IN;
3567 sb.spt.DataTransferLength = iop->dxfer_len;
3568 sb.spt.DataBuffer = iop->dxferp;
3569 // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte
3570 // transfers (needed for SMART STATUS check of JMicron USB briges)
3571 if (sb.spt.DataTransferLength == 1)
3572 direct = false;
3573 break;
3574 case DXFER_TO_DEVICE:
3575 sb.spt.DataIn = SCSI_IOCTL_DATA_OUT;
3576 sb.spt.DataTransferLength = iop->dxfer_len;
3577 sb.spt.DataBuffer = iop->dxferp;
3578 break;
3579 default:
3580 set_err(EINVAL, "bad dxfer_dir");
3581 return false;
3582 }
3583
3584 long err = 0;
3585 if (direct) {
3586 DWORD num_out;
3587 if (!DeviceIoControl(get_fh(), IOCTL_SCSI_PASS_THROUGH_DIRECT,
3588 &sb, sizeof(sb), &sb, sizeof(sb), &num_out, 0))
3589 err = GetLastError();
3590 }
3591 else
3592 err = scsi_pass_through_indirect(get_fh(), &sb);
3593
3594 if (err)
3595 return set_err((err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO),
3596 "IOCTL_SCSI_PASS_THROUGH%s failed, Error=%ld",
3597 (direct ? "_DIRECT" : ""), err);
3598
3599 iop->scsi_status = sb.spt.ScsiStatus;
3600 if (SCSI_STATUS_CHECK_CONDITION & iop->scsi_status) {
3601 int slen = sb.ucSenseBuf[7] + 8;
3602
3603 if (slen > (int)sizeof(sb.ucSenseBuf))
3604 slen = sizeof(sb.ucSenseBuf);
3605 if (slen > (int)iop->max_sense_len)
3606 slen = iop->max_sense_len;
3607 memcpy(iop->sensep, sb.ucSenseBuf, slen);
3608 iop->resp_sense_len = slen;
3609 if (report) {
3610 if ((iop->sensep[0] & 0x7f) > 0x71)
3611 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
3612 iop->scsi_status, iop->sensep[1] & 0xf,
3613 iop->sensep[2], iop->sensep[3]);
3614 else
3615 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
3616 iop->scsi_status, iop->sensep[2] & 0xf,
3617 iop->sensep[12], iop->sensep[13]);
3618 }
3619 } else
3620 iop->resp_sense_len = 0;
3621
3622 if ((iop->dxfer_len > 0) && (sb.spt.DataTransferLength > 0))
3623 iop->resid = iop->dxfer_len - sb.spt.DataTransferLength;
3624 else
3625 iop->resid = 0;
3626
3627 if ((iop->dxfer_dir == DXFER_FROM_DEVICE) && (report > 1)) {
3628 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
3629 pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
3630 (trunc ? " [only first 256 bytes shown]" : ""));
3631 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
3632 }
3633 return true;
3634 }
3635
3636
3637 //////////////////////////////////////////////////////////////////////////////////////////////////
3638
3639
3640 } // namespace
3641
3642 /////////////////////////////////////////////////////////////////////////////
3643
3644 // Initialize platform interface and register with smi()
3645 void smart_interface::init()
3646 {
3647 // Select interface for Windows flavor
3648 if (os_win32::is_win9x()) {
3649 static os_win32::win9x_smart_interface the_win9x_interface;
3650 smart_interface::set(&the_win9x_interface);
3651 }
3652 else {
3653 static os_win32::winnt_smart_interface the_winnt_interface;
3654 smart_interface::set(&the_winnt_interface);
3655 }
3656 }
3657