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