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