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