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