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