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