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