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