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