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