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