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