smartmontools  SVN Rev 4345
Utility to control and monitor storage systems with "S.M.A.R.T."
os_win32.cpp
Go to the documentation of this file.
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 4340 2016-09-07 20:34:24Z 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 {
146  UCHAR DataBuffer[1];
148 
149 #pragma pack()
150 
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;
172  ULONG_PTR DataBufferOffset;
174  UCHAR CurrentTaskFile[8];
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 
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 
234  ULONG Version;
235  ULONG Size;
236  UCHAR DeviceType;
238  BOOLEAN RemovableMedia;
244  STORAGE_BUS_TYPE BusType;
248 
249 typedef enum _STORAGE_QUERY_TYPE {
255 
256 typedef enum _STORAGE_PROPERTY_ID {
265 
266 typedef struct _STORAGE_PROPERTY_QUERY {
271 
272 #endif // IOCTL_STORAGE_QUERY_PROPERTY
273 
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;
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];
302 
303 typedef struct _SENDCMDINPARAMS_EX {
304  DWORD cBufferSize;
307  BYTE bPortNumber; // 3ware specific: port number
308  WORD wIdentifier; // Vendor specific identifier
309  DWORD dwReserved[4];
310  BYTE bBuffer[1];
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)
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];
343 #pragma pack()
344 
345 #endif // NVME_PASS_THROUGH_SRB_IO_CODE
346 
350 
351 
352 // CSMI structs
353 
354 ASSERT_SIZEOF(IOCTL_HEADER, sizeof(SRB_IO_CONTROL));
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  }
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 
426 : virtual public /*implements*/ smart_device
427 {
428 public:
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 
457 {
458  if (m_fh != INVALID_HANDLE_VALUE)
459  ::CloseHandle(m_fh);
460 }
461 
463 {
464  return (m_fh != INVALID_HANDLE_VALUE);
465 }
466 
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,
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);
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 {
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) {
845  code = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS; name = "READ_SMART_ATTRIBS"; break;
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;
859  code = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS; name = "EXECUTE_OFFLINE_DIAGS"; break;
861  code = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE; name = "ENABLE_DISABLE_AUTO_OFFLINE"; break;
863  code = IOCTL_SCSI_MINIPORT_READ_SMART_LOG; name = "READ_SMART_LOG"; break;
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);
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 
1066  char raw[256];
1067 };
1068 
1069 // Get STORAGE_DEVICE_DESCRIPTOR_DATA for device.
1070 // (This works without admin rights)
1071 
1073 {
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
1141 {
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 
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
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 
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 
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.
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
1627 {
1628  // No multi-sector support for now, see above
1629  // warning about IOCTL_ATA_PASS_THROUGH
1630  if (!ata_cmd_is_supported(in,
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
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:
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:
1663  case ATA_SMART_AUTOSAVE:
1664  case ATA_SMART_ENABLE:
1665  case ATA_SMART_DISABLE:
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 
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 
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 
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  }
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);
1853  if (rc == 0 && m_phydrive >= 0)
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:
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);
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 
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
1949 {
1950  return m_id_is_cached;
1951 }
1952 
1953 
1954 //////////////////////////////////////////////////////////////////////
1955 // csmi_device
1956 
1958 : virtual public /*extends*/ smart_device
1959 {
1960 public:
1961  /// Get bitmask of used ports
1962  unsigned get_ports_used();
1963 
1964 protected:
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
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 
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 
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];
2053  continue;
2055  continue;
2056  switch (pe.Attached.bTargetPortProtocol) {
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 
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];
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];
2117  return set_err(ENOENT, "No device on port %d", port);
2118 
2119  switch (phy_ent.Attached.bTargetPortProtocol) {
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 
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:
2145  : smart_device(never_called) { }
2146 };
2147 
2148 
2149 //////////////////////////////////////////////////////////////////////
2150 
2152 {
2153  if (!ata_cmd_is_supported(in,
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));
2174 
2175  // Set transfer mode
2176  switch (in.direction) {
2177  case ata_cmd_in::no_data:
2179  break;
2180  case ata_cmd_in::data_in:
2182  pthru.uDataLength = in.size;
2183  break;
2184  case ata_cmd_in::data_out:
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 
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 
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 
2289 {
2290  if (m_fh != INVALID_HANDLE_VALUE)
2291  CloseHandle(m_fh);
2292 }
2293 
2295 {
2296  return (m_fh != INVALID_HANDLE_VALUE);
2297 }
2298 
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 
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 
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 
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:
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 
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 
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
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 
2652 {
2653  m_ident_valid = m_smart_valid = false;
2654  return true;
2655 }
2656 
2657 
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 
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 
2707  const char * dev_name, const char * req_type)
2708 : smart_device(intf, dev_name, "scsi", req_type)
2709 {
2710 }
2711 
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];
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,
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
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 
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;
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 
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;
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 
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 
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 
3145 {
3146  return this;
3147 }
3148 
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 
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 
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 
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 
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 
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
3276  close();
3277  delete this;
3278  newdev->open(); // TODO: Can possibly pass open fd
3279 
3280  return newdev.release();
3281 }
3282 
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 
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 
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 
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
3356 
3357  //Channel(Lun) of the device
3358  int m_lun;
3359 
3360  //Id of the device
3362 };
3363 
3364 
3365 /////////////////////////////////////////////////////////////////////////////
3366 
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 
3377 {
3378 }
3379 
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 
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;
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 
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:
3553 };
3554 
3555 
3556 /////////////////////////////////////////////////////////////////////////////
3557 
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 
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
3598 {
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 
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 
3669 {
3670  // Create buffer with appropriate size
3671  raw_buffer pthru_raw_buf(offsetof(NVME_PASS_THROUGH_IOCTL, DataBuffer) + in.size);
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 
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
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  unsigned build = 0;
3810  if ( vi.dwPlatformId == VER_PLATFORM_WIN32_NT
3811  && vi.dwMajorVersion <= 0xf && vi.dwMinorVersion <= 0xf) {
3812  switch ( (vi.dwMajorVersion << 4 | vi.dwMinorVersion) << 1
3813  | (vi.wProductType > VER_NT_WORKSTATION ? 1 : 0) ) {
3814  case 0x50<<1 :
3815  case 0x50<<1 | 1: w = "2000"; break;
3816  case 0x51<<1 : w = "xp"; break;
3817  case 0x52<<1 : w = "xp64"; break;
3818  case 0x52<<1 | 1: w = (!GetSystemMetrics(89/*SM_SERVERR2*/)
3819  ? "2003"
3820  : "2003r2"); break;
3821  case 0x60<<1 : w = "vista"; break;
3822  case 0x60<<1 | 1: w = "2008"; break;
3823  case 0x61<<1 : w = "win7"; break;
3824  case 0x61<<1 | 1: w = "2008r2"; break;
3825  case 0x62<<1 : w = "win8"; break;
3826  case 0x62<<1 | 1: w = "2012"; break;
3827  case 0x63<<1 : w = "win8.1"; break;
3828  case 0x63<<1 | 1: w = "2012r2"; break;
3829  case 0xa0<<1 :
3830  switch (vi.dwBuildNumber) {
3831  case 10240: w = "w10-1507"; break;
3832  case 10586: w = "w10-1511"; break;
3833  case 14393: w = "w10-1607"; break;
3834  default: w = "w10"; build = vi.dwBuildNumber; break;
3835  } break;
3836  case 0xa0<<1 | 1: w = "2016"; build = vi.dwBuildNumber; break;
3837  }
3838  }
3839 
3840  const char * w64 = "";
3841 #ifndef _WIN64
3842  if (is_wow64())
3843  w64 = "(64)";
3844 #endif
3845 
3846  if (!w)
3847  snprintf(vptr, vlen, "-%s%u.%u%s",
3848  (vi.dwPlatformId==VER_PLATFORM_WIN32_NT ? "nt" : "??"),
3849  (unsigned)vi.dwMajorVersion, (unsigned)vi.dwMinorVersion, w64);
3850  else if (build)
3851  snprintf(vptr, vlen, "-%s%s-b%u", w, w64, build);
3852  else if (vi.wServicePackMinor)
3853  snprintf(vptr, vlen, "-%s%s-sp%u.%u", w, w64, vi.wServicePackMajor, vi.wServicePackMinor);
3854  else if (vi.wServicePackMajor)
3855  snprintf(vptr, vlen, "-%s%s-sp%u", w, w64, vi.wServicePackMajor);
3856  else
3857  snprintf(vptr, vlen, "-%s%s", w, w64);
3858  return vstr;
3859 }
3860 
3861 #ifndef __CYGWIN__
3862 // MSVCRT only provides ftime() which uses GetSystemTime()
3863 // This provides only ~15ms resolution by default.
3864 // Use QueryPerformanceCounter instead (~300ns).
3865 // (Cygwin provides CLOCK_MONOTONIC which has the same effect)
3867 {
3868  static int64_t freq = 0;
3869 
3870  LARGE_INTEGER t;
3871  if (freq == 0)
3872  freq = (QueryPerformanceFrequency(&t) ? t.QuadPart : -1);
3873  if (freq <= 0)
3875 
3876  if (!QueryPerformanceCounter(&t))
3877  return -1;
3878  if (!(0 <= t.QuadPart && t.QuadPart <= (int64_t)(~(uint64_t)0 >> 1)/1000000))
3879  return -1;
3880 
3881  return (t.QuadPart * 1000000LL) / freq;
3882 }
3883 #endif // __CYGWIN__
3884 
3885 
3886 ata_device * win_smart_interface::get_ata_device(const char * name, const char * type)
3887 {
3888  const char * testname = skipdev(name);
3889  if (!strncmp(testname, "csmi", 4))
3890  return new win_csmi_device(this, name, type);
3891  if (!strncmp(testname, "tw_cli", 6))
3892  return new win_tw_cli_device(this, name, type);
3893  return new win_ata_device(this, name, type);
3894 }
3895 
3896 scsi_device * win_smart_interface::get_scsi_device(const char * name, const char * type)
3897 {
3898  return new win_scsi_device(this, name, type);
3899 }
3900 
3901 nvme_device * win_smart_interface::get_nvme_device(const char * name, const char * type,
3902  unsigned nsid)
3903 {
3904  return new win_nvme_device(this, name, type, nsid);
3905 }
3906 
3907 
3908 smart_device * win_smart_interface::get_custom_smart_device(const char * name, const char * type)
3909 {
3910  // Areca?
3911  int disknum = -1, n1 = -1, n2 = -1;
3912  int encnum = 1;
3913  char devpath[32];
3914 
3915  if (sscanf(type, "areca,%n%d/%d%n", &n1, &disknum, &encnum, &n2) >= 1 || n1 == 6) {
3916  if (!(1 <= disknum && disknum <= 128)) {
3917  set_err(EINVAL, "Option -d areca,N/E (N=%d) must have 1 <= N <= 128", disknum);
3918  return 0;
3919  }
3920  if (!(1 <= encnum && encnum <= 8)) {
3921  set_err(EINVAL, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum);
3922  return 0;
3923  }
3924 
3925  name = skipdev(name);
3926 #define ARECA_MAX_CTLR_NUM 16
3927  n1 = -1;
3928  int ctlrindex = 0;
3929  if (sscanf(name, "arcmsr%d%n", &ctlrindex, &n1) >= 1 && n1 == (int)strlen(name)) {
3930  /*
3931  1. scan from "\\\\.\\scsi[0]:" up to "\\\\.\\scsi[ARECA_MAX_CTLR_NUM]:" and
3932  2. map arcmsrX into "\\\\.\\scsiX"
3933  */
3934  for (int idx = 0; idx < ARECA_MAX_CTLR_NUM; idx++) {
3935  memset(devpath, 0, sizeof(devpath));
3936  snprintf(devpath, sizeof(devpath), "\\\\.\\scsi%d:", idx);
3937  win_areca_ata_device *arcdev = new win_areca_ata_device(this, devpath, disknum, encnum);
3938  if(arcdev->arcmsr_probe()) {
3939  if(ctlrindex-- == 0) {
3940  return arcdev;
3941  }
3942  }
3943  delete arcdev;
3944  }
3945  set_err(ENOENT, "No Areca controller found");
3946  }
3947  else
3948  set_err(EINVAL, "Option -d areca,N/E requires device name /dev/arcmsrX");
3949  return 0;
3950  }
3951 
3952  // aacraid?
3953  unsigned ctrnum, lun, target;
3954  n1 = -1;
3955 
3956  if ( sscanf(type, "aacraid,%u,%u,%u%n", &ctrnum, &lun, &target, &n1) >= 3
3957  && n1 == (int)strlen(type)) {
3958 #define aacraid_MAX_CTLR_NUM 16
3959  if (ctrnum >= aacraid_MAX_CTLR_NUM) {
3960  set_err(EINVAL, "aacraid: invalid host number %u", ctrnum);
3961  return 0;
3962  }
3963 
3964  /*
3965  1. scan from "\\\\.\\scsi[0]:" up to "\\\\.\\scsi[AACRAID_MAX_CTLR_NUM]:" and
3966  2. map ARCX into "\\\\.\\scsiX"
3967  */
3968  memset(devpath, 0, sizeof(devpath));
3969  unsigned ctlrindex = 0;
3970  for (int portNum = 0; portNum < aacraid_MAX_CTLR_NUM; portNum++){
3971  char subKey[63];
3972  snprintf(subKey, sizeof(subKey), "HARDWARE\\DEVICEMAP\\Scsi\\Scsi Port %d", portNum);
3973  HKEY hScsiKey = 0;
3974  long regStatus = RegOpenKeyExA(HKEY_LOCAL_MACHINE, subKey, 0, KEY_READ, &hScsiKey);
3975  if (regStatus == ERROR_SUCCESS){
3976  char driverName[20];
3977  DWORD driverNameSize = sizeof(driverName);
3978  DWORD regType = 0;
3979  regStatus = RegQueryValueExA(hScsiKey, "Driver", NULL, &regType, (LPBYTE) driverName, &driverNameSize);
3980  if (regStatus == ERROR_SUCCESS){
3981  if (regType == REG_SZ){
3982  if (stricmp(driverName, "arcsas") == 0){
3983  if(ctrnum == ctlrindex){
3984  snprintf(devpath, sizeof(devpath), "\\\\.\\Scsi%d:", portNum);
3985  return get_sat_device("sat,auto",
3986  new win_aacraid_device(this, devpath, ctrnum, target, lun));
3987  }
3988  ctlrindex++;
3989  }
3990  }
3991  }
3992  RegCloseKey(hScsiKey);
3993  }
3994  }
3995 
3996  set_err(EINVAL, "aacraid: host %u not found", ctrnum);
3997  return 0;
3998  }
3999 
4000  return 0;
4001 }
4002 
4004 {
4005  return "aacraid,H,L,ID, areca,N[/E]";
4006 }
4007 
4008 
4009 // Return value for device detection functions
4011 
4012 // Return true if ATA drive behind a SAT layer
4014 {
4015  if (!data->desc.VendorIdOffset)
4016  return false;
4017  if (strcmp(data->raw + data->desc.VendorIdOffset, "ATA "))
4018  return false;
4019  return true;
4020 }
4021 
4022 // Return true if Intel ICHxR RAID volume
4024 {
4025  if (!(data->desc.VendorIdOffset && data->desc.ProductIdOffset))
4026  return false;
4027  const char * vendor = data->raw + data->desc.VendorIdOffset;
4028  if (!(!strnicmp(vendor, "Intel", 5) && strspn(vendor+5, " ") == strlen(vendor+5)))
4029  return false;
4030  if (strnicmp(data->raw + data->desc.ProductIdOffset, "Raid ", 5))
4031  return false;
4032  return true;
4033 }
4034 
4035 // get DEV_* for open handle
4036 static win_dev_type get_controller_type(HANDLE hdevice, bool admin, GETVERSIONINPARAMS_EX * ata_version_ex)
4037 {
4038  // Get BusType from device descriptor
4040  if (storage_query_property_ioctl(hdevice, &data))
4041  return DEV_UNKNOWN;
4042 
4043  // Newer BusType* values are missing in older includes
4044  switch ((int)data.desc.BusType) {
4045  case BusTypeAta:
4046  case 0x0b: // BusTypeSata
4047  // Certain Intel AHCI drivers (C600+/C220+) have broken
4048  // IOCTL_ATA_PASS_THROUGH support and a working SAT layer
4049  if (is_sat(&data))
4050  return DEV_SAT;
4051 
4052  if (ata_version_ex)
4053  memset(ata_version_ex, 0, sizeof(*ata_version_ex));
4054  return DEV_ATA;
4055 
4056  case BusTypeScsi:
4057  case BusTypeRAID:
4058  if (is_sat(&data))
4059  return DEV_SAT;
4060 
4061  // Intel ICHxR RAID volume: reports SMART_GET_VERSION but does not support SMART_*
4062  if (is_intel_raid_volume(&data))
4063  return DEV_SCSI;
4064  // LSI/3ware RAID volume: supports SMART_*
4065  if (admin && smart_get_version(hdevice, ata_version_ex) >= 0)
4066  return DEV_ATA;
4067 
4068  return DEV_SCSI;
4069 
4070  case 0x09: // BusTypeiScsi
4071  case 0x0a: // BusTypeSas
4072  if (is_sat(&data))
4073  return DEV_SAT;
4074 
4075  return DEV_SCSI;
4076 
4077  case BusTypeUsb:
4078  return DEV_USB;
4079 
4080  default:
4081  return DEV_UNKNOWN;
4082  }
4083  /*NOTREACHED*/
4084 }
4085 
4086 // get DEV_* for device path
4087 static win_dev_type get_controller_type(const char * path, GETVERSIONINPARAMS_EX * ata_version_ex = 0)
4088 {
4089  bool admin = true;
4090  HANDLE h = CreateFileA(path, GENERIC_READ|GENERIC_WRITE,
4091  FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
4092  if (h == INVALID_HANDLE_VALUE) {
4093  admin = false;
4094  h = CreateFileA(path, 0,
4095  FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
4096  if (h == INVALID_HANDLE_VALUE)
4097  return DEV_UNKNOWN;
4098  }
4099  if (ata_debugmode > 1 || scsi_debugmode > 1)
4100  pout(" %s: successfully opened%s\n", path, (!admin ? " (without admin rights)" :""));
4101  win_dev_type type = get_controller_type(h, admin, ata_version_ex);
4102  CloseHandle(h);
4103  return type;
4104 }
4105 
4106 // get DEV_* for physical drive number
4107 static win_dev_type get_phy_drive_type(int drive, GETVERSIONINPARAMS_EX * ata_version_ex)
4108 {
4109  char path[30];
4110  snprintf(path, sizeof(path)-1, "\\\\.\\PhysicalDrive%d", drive);
4111  return get_controller_type(path, ata_version_ex);
4112 }
4113 
4115 {
4116  return get_phy_drive_type(drive, 0);
4117 }
4118 
4119 // get DEV_* for logical drive number
4121 {
4122  char path[30];
4123  snprintf(path, sizeof(path)-1, "\\\\.\\%c:", 'A'+drive);
4124  return get_controller_type(path);
4125 }
4126 
4127 static win_dev_type get_dev_type(const char * name, int & phydrive, int & logdrive)
4128 {
4129  phydrive = logdrive = -1;
4130 
4131  name = skipdev(name);
4132  if (!strncmp(name, "st", 2))
4133  return DEV_SCSI;
4134  if (!strncmp(name, "nst", 3))
4135  return DEV_SCSI;
4136  if (!strncmp(name, "tape", 4))
4137  return DEV_SCSI;
4138 
4139  logdrive = drive_letter(name);
4140  if (logdrive >= 0) {
4141  win_dev_type type = get_log_drive_type(logdrive);
4142  return (type != DEV_UNKNOWN ? type : DEV_SCSI);
4143  }
4144 
4145  char drive[2+1] = "";
4146  if (sscanf(name, "sd%2[a-z]", drive) == 1) {
4147  phydrive = sdxy_to_phydrive(drive);
4148  return get_phy_drive_type(phydrive);
4149  }
4150 
4151  if (sscanf(name, "pd%d", &phydrive) == 1 && phydrive >= 0)
4152  return get_phy_drive_type(phydrive);
4153 
4154  return DEV_UNKNOWN;
4155 }
4156 
4157 
4159  int phydrive, int logdrive /* = -1 */)
4160 {
4161  // Get USB bridge ID
4162  unsigned short vendor_id = 0, product_id = 0;
4163  if (!get_usb_id(phydrive, logdrive, vendor_id, product_id)) {
4164  set_err(EINVAL, "Unable to read USB device ID");
4165  return 0;
4166  }
4167 
4168  // Get type name for this ID
4169  const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id);
4170  if (!usbtype)
4171  return 0;
4172 
4173  // Return SAT/USB device for this type
4174  return get_sat_device(usbtype, new win_scsi_device(this, name, ""));
4175 }
4176 
4178 {
4179  const char * testname = skipdev(name);
4180  if (str_starts_with(testname, "hd"))
4181  return new win_ata_device(this, name, "");
4182 
4183  if (str_starts_with(testname, "tw_cli"))
4184  return new win_tw_cli_device(this, name, "");
4185 
4186  if (str_starts_with(testname, "csmi"))
4187  return new win_csmi_device(this, name, "");
4188 
4189  if (str_starts_with(testname, "nvme"))
4190  return new win_nvme_device(this, name, "", 0 /* use default nsid */);
4191 
4192  int phydrive = -1, logdrive = -1;
4193  win_dev_type type = get_dev_type(name, phydrive, logdrive);
4194 
4195  if (type == DEV_ATA)
4196  return new win_ata_device(this, name, "");
4197 
4198  if (type == DEV_SCSI)
4199  return new win_scsi_device(this, name, "");
4200 
4201  if (type == DEV_SAT)
4202  return get_sat_device("sat", new win_scsi_device(this, name, ""));
4203 
4204  if (type == DEV_USB)
4205  return get_usb_device(name, phydrive, logdrive);
4206 
4207  return 0;
4208 }
4209 
4210 
4211 // Scan for devices
4213  const char * type, const char * pattern /* = 0*/)
4214 {
4215  if (pattern) {
4216  set_err(EINVAL, "DEVICESCAN with pattern not implemented yet");
4217  return false;
4218  }
4219 
4220  // Check for "[*,]pd" type
4221  bool pd = false;
4222  char type2[16+1] = "";
4223  if (type) {
4224  int nc = -1;
4225  if (!strcmp(type, "pd")) {
4226  pd = true;
4227  type = 0;
4228  }
4229  else if (sscanf(type, "%16[^,],pd%n", type2, &nc) == 1 &&
4230  nc == (int)strlen(type)) {
4231  pd = true;
4232  type = type2;
4233  }
4234  }
4235 
4236  // Set valid types
4237  bool ata, scsi, sat, usb, csmi, nvme;
4238  if (!type) {
4239  ata = scsi = usb = sat = csmi = true;
4240 #ifdef WITH_NVME_DEVICESCAN // TODO: Remove when NVMe support is no longer EXPERIMENTAL
4241  nvme = true;
4242 #else
4243  nvme = false;
4244 #endif
4245  }
4246  else {
4247  ata = scsi = usb = sat = csmi = nvme = false;
4248  if (!strcmp(type, "ata"))
4249  ata = true;
4250  else if (!strcmp(type, "scsi"))
4251  scsi = true;
4252  else if (!strcmp(type, "sat"))
4253  sat = true;
4254  else if (!strcmp(type, "usb"))
4255  usb = true;
4256  else if (!strcmp(type, "csmi"))
4257  csmi = true;
4258  else if (!strcmp(type, "nvme"))
4259  nvme = true;
4260  else {
4261  set_err(EINVAL,
4262  "Invalid type '%s', valid arguments are: ata[,pd], scsi[,pd], "
4263  "sat[,pd], usb[,pd], csmi, nvme, pd", type);
4264  return false;
4265  }
4266  }
4267 
4268  char name[20];
4269 
4270  if (ata || scsi || sat || usb) {
4271  // Scan up to 128 drives and 2 3ware controllers
4272  const int max_raid = 2;
4273  bool raid_seen[max_raid] = {false, false};
4274 
4275  for (int i = 0; i < 128; i++) {
4276  if (pd)
4277  snprintf(name, sizeof(name), "/dev/pd%d", i);
4278  else if (i + 'a' <= 'z')
4279  snprintf(name, sizeof(name), "/dev/sd%c", i + 'a');
4280  else
4281  snprintf(name, sizeof(name), "/dev/sd%c%c",
4282  i / ('z'-'a'+1) - 1 + 'a',
4283  i % ('z'-'a'+1) + 'a');
4284 
4285  smart_device * dev = 0;
4286  GETVERSIONINPARAMS_EX vers_ex;
4287 
4288  switch (get_phy_drive_type(i, (ata ? &vers_ex : 0))) {
4289  case DEV_ATA:
4290  // Driver supports SMART_GET_VERSION or STORAGE_QUERY_PROPERTY returned ATA/SATA
4291  if (!ata)
4292  continue;
4293 
4294  // Interpret RAID drive map if present
4295  if (vers_ex.wIdentifier == SMART_VENDOR_3WARE) {
4296  // Skip if too many controllers or logical drive from this controller already seen
4297  if (!(vers_ex.wControllerId < max_raid && !raid_seen[vers_ex.wControllerId]))
4298  continue;
4299  raid_seen[vers_ex.wControllerId] = true;
4300  // Add physical drives
4301  int len = strlen(name);
4302  for (unsigned int pi = 0; pi < 32; pi++) {
4303  if (vers_ex.dwDeviceMapEx & (1L << pi)) {
4304  snprintf(name+len, sizeof(name)-1-len, ",%u", pi);
4305  devlist.push_back( new win_ata_device(this, name, "ata") );
4306  }
4307  }
4308  continue;
4309  }
4310 
4311  dev = new win_ata_device(this, name, "ata");
4312  break;
4313 
4314  case DEV_SCSI:
4315  // STORAGE_QUERY_PROPERTY returned SCSI/SAS/...
4316  if (!scsi)
4317  continue;
4318  dev = new win_scsi_device(this, name, "scsi");
4319  break;
4320 
4321  case DEV_SAT:
4322  // STORAGE_QUERY_PROPERTY returned VendorId "ATA "
4323  if (!sat)
4324  continue;
4325  dev = get_sat_device("sat", new win_scsi_device(this, name, ""));
4326  break;
4327 
4328  case DEV_USB:
4329  // STORAGE_QUERY_PROPERTY returned USB
4330  if (!usb)
4331  continue;
4332  dev = get_usb_device(name, i);
4333  if (!dev)
4334  // Unknown or unsupported USB ID, return as SCSI
4335  dev = new win_scsi_device(this, name, "");
4336  break;
4337 
4338  default:
4339  // Unknown type
4340  continue;
4341  }
4342 
4343  devlist.push_back(dev);
4344  }
4345  }
4346 
4347  if (csmi) {
4348  // Scan CSMI devices
4349  for (int i = 0; i <= 9; i++) {
4350  snprintf(name, sizeof(name)-1, "/dev/csmi%d,0", i);
4351  win_csmi_device test_dev(this, name, "");
4352  if (!test_dev.open_scsi())
4353  continue;
4354 
4355  unsigned ports_used = test_dev.get_ports_used();
4356  if (!ports_used)
4357  continue;
4358 
4359  for (int pi = 0; pi < 32; pi++) {
4360  if (!(ports_used & (1 << pi)))
4361  continue;
4362  snprintf(name, sizeof(name)-1, "/dev/csmi%d,%d", i, pi);
4363  devlist.push_back( new win_csmi_device(this, name, "ata") );
4364  }
4365  }
4366  }
4367 
4368  if (nvme) {
4369  // Scan \\.\Scsi[0-31] for up to 10 NVMe devices
4370  int nvme_cnt = 0;
4371  for (int i = 0; i < 32; i++) {
4372  snprintf(name, sizeof(name)-1, "/dev/nvme%d", i);
4373  win_nvme_device test_dev(this, name, "", 0);
4374  if (!test_dev.open_scsi(i)) {
4375  if (test_dev.get_errno() == EACCES)
4376  break;
4377  continue;
4378  }
4379 
4380  if (!test_dev.probe())
4381  continue;
4382  if (++nvme_cnt >= 10)
4383  break;
4384  }
4385 
4386  for (int i = 0; i < nvme_cnt; i++) {
4387  snprintf(name, sizeof(name)-1, "/dev/nvme%d", i);
4388  devlist.push_back( new win_nvme_device(this, name, "nvme", 0) );
4389  }
4390  }
4391  return true;
4392 }
4393 
4394 
4395 // get examples for smartctl
4396 std::string win_smart_interface::get_app_examples(const char * appname)
4397 {
4398  if (strcmp(appname, "smartctl"))
4399  return "";
4400  return "=================================================== SMARTCTL EXAMPLES =====\n\n"
4401  " smartctl -a /dev/sda (Prints all SMART information)\n\n"
4402  " smartctl --smart=on --offlineauto=on --saveauto=on /dev/sda\n"
4403  " (Enables SMART on first disk)\n\n"
4404  " smartctl -t long /dev/sda (Executes extended disk self-test)\n\n"
4405  " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/sda\n"
4406  " (Prints Self-Test & Attribute errors)\n"
4407  " smartctl -a /dev/sda\n"
4408  " (Prints all information for disk on PhysicalDrive 0)\n"
4409  " smartctl -a /dev/pd3\n"
4410  " (Prints all information for disk on PhysicalDrive 3)\n"
4411  " smartctl -a /dev/tape1\n"
4412  " (Prints all information for SCSI tape on Tape 1)\n"
4413  " smartctl -A /dev/hdb,3\n"
4414  " (Prints Attributes for physical drive 3 on 3ware 9000 RAID)\n"
4415  " smartctl -A /dev/tw_cli/c0/p1\n"
4416  " (Prints Attributes for 3ware controller 0, port 1 using tw_cli)\n"
4417  " smartctl --all --device=areca,3/1 /dev/arcmsr0\n"
4418  " (Prints all SMART info for 3rd ATA disk of the 1st enclosure\n"
4419  " on 1st Areca RAID controller)\n"
4420  "\n"
4421  " ATA SMART access methods and ordering may be specified by modifiers\n"
4422  " following the device name: /dev/hdX:[saicm], where\n"
4423  " 's': SMART_* IOCTLs, 'a': IOCTL_ATA_PASS_THROUGH,\n"
4424  " 'i': IOCTL_IDE_PASS_THROUGH, 'f': IOCTL_STORAGE_*,\n"
4425  " 'm': IOCTL_SCSI_MINIPORT_*.\n"
4426  + strprintf(
4427  " The default on this system is /dev/sdX:%s\n", ata_get_def_options()
4428  );
4429 }
4430 
4431 
4433 {
4434  if (disable) {
4435  SYSTEM_POWER_STATUS ps;
4436  if (!GetSystemPowerStatus(&ps))
4437  return set_err(ENOSYS, "Unknown power status");
4438  if (ps.ACLineStatus != 1) {
4439  SetThreadExecutionState(ES_CONTINUOUS);
4440  if (ps.ACLineStatus == 0)
4441  set_err(EIO, "AC offline");
4442  else
4443  set_err(EIO, "Unknown AC line status");
4444  return false;
4445  }
4446  }
4447 
4448  if (!SetThreadExecutionState(ES_CONTINUOUS | (disable ? ES_SYSTEM_REQUIRED : 0)))
4449  return set_err(ENOSYS);
4450  return true;
4451 }
4452 
4453 
4454 } // namespace
4455 
4456 /////////////////////////////////////////////////////////////////////////////
4457 
4458 // Initialize platform interface and register with smi()
4459 void smart_interface::init()
4460 {
4461  {
4462  // Remove "." from DLL search path if supported
4463  // to prevent DLL preloading attacks
4464  BOOL (WINAPI * SetDllDirectoryA_p)(LPCSTR) = (BOOL (WINAPI *)(LPCSTR))
4465  GetProcAddress(GetModuleHandleA("kernel32.dll"), "SetDllDirectoryA");
4466  if (SetDllDirectoryA_p)
4467  SetDllDirectoryA_p("");
4468  }
4469 
4470  static os_win32::win_smart_interface the_win_interface;
4471  smart_interface::set(&the_win_interface);
4472 }
4473 
4474 
4475 #ifndef __CYGWIN__
4476 
4477 // Get exe directory
4478 // (prototype in utiliy.h)
4479 std::string get_exe_dir()
4480 {
4481  char path[MAX_PATH];
4482  // Get path of this exe
4483  if (!GetModuleFileNameA(GetModuleHandleA(0), path, sizeof(path)))
4484  throw std::runtime_error("GetModuleFileName() failed");
4485  // Replace backslash by slash
4486  int sl = -1;
4487  for (int i = 0; path[i]; i++)
4488  if (path[i] == '\\') {
4489  path[i] = '/'; sl = i;
4490  }
4491  // Remove filename
4492  if (sl >= 0)
4493  path[sl] = 0;
4494  return path;
4495 }
4496 
4497 #endif
#define SRB_FUNCTION_EXECUTE_SCSI
Definition: aacraid.h:48
virtual bool open()
Open device, return false on error.
Definition: os_win32.cpp:2346
#define ATA_SMART_READ_LOG_SECTOR
Definition: atacmds.h:100
virtual int64_t get_timer_usec()
Get microseconds since some unspecified starting point.
#define ATA_SMART_WRITE_LOG_SECTOR
Definition: atacmds.h:101
virtual bool open()
Open device, return false on error.
Definition: os_win32.cpp:3380
#define CSMI_SAS_STP_UNSPECIFIED
Definition: csmisas.h:859
static const char * skipdev(const char *s)
Definition: os_win32.cpp:396
virtual bool ata_identify_is_cached() const
Return true if OS caches ATA identify sector.
Definition: os_win32.cpp:1948
unsigned char direction() const
Get I/O direction from opcode.
UCHAR bReserved
Definition: os_os2.cpp:57
const CSMI_SAS_PHY_ENTITY & get_phy_ent() const
Get info for selected physical drive.
Definition: os_win32.cpp:1976
#define IOCTL_SCSI_MINIPORT_READ_SMART_LOG
Definition: os_win32.cpp:217
u16 s[6]
Definition: megaraid.h:97
virtual bool nvme_pass_through(const nvme_cmd_in &in, nvme_cmd_out &out)
NVMe pass through.
Definition: os_win32.cpp:3668
#define assert(x)
Definition: os_win32.cpp:47
virtual int64_t get_timer_usec()
Get microseconds since some unspecified starting point.
Definition: os_win32.cpp:3866
virtual std::string get_valid_custom_dev_types_str()
Return valid 'type' args accepted by above.
Definition: os_win32.cpp:4003
virtual bool csmi_ioctl(unsigned code, IOCTL_HEADER *csmi_buffer, unsigned csmi_bufsiz)
Call platform-specific CSMI ioctl.
Definition: os_win32.cpp:2361
u32 size
Definition: megaraid.h:79
#define SCSI_STATUS_CHECK_CONDITION
Definition: scsicmds.h:258
UINT8 * sensep
Definition: scsicmds.h:122
void set_disknum(int disknum)
Definition: dev_areca.h:126
UCHAR bSectorNumberReg
Definition: os_os2.cpp:52
_STORAGE_QUERY_TYPE
Definition: os_win32.cpp:249
virtual smart_device * get_custom_smart_device(const char *name, const char *type)
Return device for platform specific 'type'.
Definition: os_win32.cpp:3908
virtual ata_device * get_sat_device(const char *type, scsi_device *scsidev)
Return ATA->SCSI filter for a SAT or USB 'type'.
Definition: scsiata.cpp:1487
ata_in_regs prev
"previous content"
ata_identify_device m_ident_buf
Definition: os_win32.cpp:2439
ata_register error
__u8 szDescription[81]
Definition: csmisas.h:1014
#define ATA_SMART_CMD
Definition: atacmds.h:75
static win_dev_type get_controller_type(HANDLE hdevice, bool admin, GETVERSIONINPARAMS_EX *ata_version_ex)
Definition: os_win32.cpp:4036
ata_register lba_mid
#define NVME_SIG_STR
Definition: os_win32.cpp:323
static bool is_wow64()
Definition: os_win32.cpp:3767
static int update_3ware_devicemap_ioctl(HANDLE hdevice)
Definition: os_win32.cpp:1029
virtual bool is_open() const
Return true if device is open.
Definition: os_win32.cpp:2455
struct _SENDCMDINPARAMS_EX SENDCMDINPARAMS_EX
int get_errno() const
Get last error number.
#define DXFER_FROM_DEVICE
Definition: scsicmds.h:111
bool str_starts_with(const char *str, const char *prefix)
Definition: utility.h:57
bool execute(const char *str, unsigned nmatch, regmatch_t *pmatch, int flags=0) const
Return true if substring matches pattern, fill regmatch_t array.
Definition: utility.h:275
#define CSMI_SAS_STP_READ
Definition: csmisas.h:857
virtual bool disable_system_auto_standby(bool disable)
Disable/Enable system auto standby/sleep mode.
Definition: os_win32.cpp:4432
bool set_nvme_err(nvme_cmd_out &out, unsigned status, const char *msg=0)
Set last error number and message if pass-through returns NVMe error status.
Smart pointer class for device pointers.
unsigned size() const
Definition: utility.h:156
#define CSMI_SAS_SIGNATURE
Definition: csmisas.h:714
#define SRB_DataIn
Definition: aacraid.h:50
static long scsi_pass_through_direct(HANDLE fd, UCHAR targetid, struct scsi_cmnd_io *iop)
Areca RAID support.
Definition: os_win32.cpp:2961
ULONG DataBufferSize
Definition: os_win32.cpp:145
ata_register device
const char * scsi_get_opcode_name(UINT8 opcode)
Definition: scsicmds.cpp:177
static int ide_pass_through_ioctl(HANDLE hdevice, IDEREGS *regs, char *data, unsigned datasize)
Definition: os_win32.cpp:639
#define SYNCOBJNAME
int m_port
Port number.
Definition: os_win32.cpp:2275
CSMI_SAS_IDENTIFY Attached
Definition: csmisas.h:1539
static win_dev_type get_dev_type(const char *name, int &phydrive, int &logdrive)
Definition: os_win32.cpp:4127
ata_register sector_count
ULONG_PTR DataBufferOffset
Definition: os_win32.cpp:172
#define CSMI_SAS_NO_DEVICE_ATTACHED
Definition: csmisas.h:725
unsigned cdw11
#define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
Definition: os_win32.cpp:213
unsigned timeout
Definition: scsicmds.h:125
SRB_IO_CONTROL SrbIoCtrl
Definition: os_win32.cpp:332
#define ATA_SMART_DISABLE
Definition: atacmds.h:104
virtual bool close()
Close device, return false on error.
Definition: os_win32.cpp:2299
#define ARECA_MAX_CTLR_NUM
Adapter class to implement new ATA pass through old interface.
ATA Input registers (for 28-bit commands)
virtual bool ata_pass_through(const ata_cmd_in &in, ata_cmd_out &out)
ATA pass through.
Definition: os_win32.cpp:1626
#define CSMI_SAS_TIMEOUT
Definition: csmisas.h:719
win_tw_cli_device(smart_interface *intf, const char *dev_name, const char *req_type)
Definition: os_win32.cpp:2446
NVMe pass through input parameters.
#define ATA_SMART_AUTOSAVE
Definition: atacmds.h:97
virtual std::string get_os_version_str()
Return info string about build host and/or OS version.
Definition: os_win32.cpp:3782
device_info & set_info()
R/W access to device info struct.
#define snprintf
Definition: utility.h:68
virtual bool is_powered_down()
Early test if device is powered up or down.
Definition: os_win32.cpp:1609
virtual int arcmsr_get_dev_type()
Definition: dev_areca.cpp:350
#define IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS
Definition: os_win32.cpp:208
const char * os_win32_cpp_cvsid
Definition: os_win32.cpp:115
virtual bool is_open() const
Return true if device is open.
Definition: os_win32.cpp:2294
UCHAR bSectorCountReg
Definition: os_os2.cpp:51
void * buffer
Pointer to data buffer.
HANDLE get_fh() const
Return handle for derived classes.
Definition: os_win32.cpp:446
NVMe pass through output parameters.
unsigned char ata_debugmode
Definition: atacmds.cpp:43
static int smart_get_version(HANDLE hdevice, GETVERSIONINPARAMS_EX *ata_version_ex=0)
Definition: os_win32.cpp:501
virtual bool scsi_pass_through(scsi_cmnd_io *iop)
SCSI pass through.
Definition: os_win32.cpp:2832
size_t resp_sense_len
Definition: scsicmds.h:126
#define IOCTL_SCSI_MINIPORT_DISABLE_SMART
Definition: os_win32.cpp:211
UCHAR PreviousTaskFile[8]
Definition: os_win32.cpp:173
void push_back(smart_device *dev)
#define IOCTL_ATA_PASS_THROUGH
Definition: os_win32.cpp:159
#define ATA_IDENTIFY_DEVICE
Definition: atacmds.h:72
virtual ata_device * get_ata_device(const char *name, const char *type)
Return standard ATA device.
Definition: os_win32.cpp:3886
ata_register lba_mid
virtual bool open()
Open device, return false on error.
Definition: os_win32.cpp:2712
bool get_phy_info(CSMI_SAS_PHY_INFO &phy_info)
Get phy info.
Definition: os_win32.cpp:1990
bool nonempty(const void *data, int size)
Definition: utility.cpp:633
struct _ATA_PASS_THROUGH_EX ATA_PASS_THROUGH_EX
#define ATA_IDENTIFY_PACKET_DEVICE
Definition: atacmds.h:73
win_csmi_device(smart_interface *intf, const char *dev_name, const char *req_type)
Definition: os_win32.cpp:2281
virtual std::string get_app_examples(const char *appname)
Return example string for program 'appname'.
Definition: os_win32.cpp:4396
struct _STORAGE_DEVICE_DESCRIPTOR STORAGE_DEVICE_DESCRIPTOR
bool ata_cmd_is_supported(const ata_cmd_in &in, unsigned flags, const char *type=0)
Check command input parameters.
#define SELECT_WIN_32_64(x32, x64)
Definition: os_win32.cpp:103
uint32_t nsid
unsigned char nvme_debugmode
Definition: nvmecmds.cpp:39
ata_in_regs_48bit in_regs
Input registers.
UINT8 * dxferp
Definition: scsicmds.h:120
std::string get_exe_dir()
Definition: os_win32.cpp:4479
Definition: scsiata.cpp:102
#define aacraid_MAX_CTLR_NUM
ata_device * get_usb_device(const char *name, int phydrive, int logdrive=-1)
Definition: os_win32.cpp:4158
UCHAR DataBuffer[1]
Definition: os_win32.cpp:146
ata_out_regs_48bit out_regs
Output registers.
std::string dev_type
Actual device type.
Definition: dev_interface.h:54
UINT8 * cmnd
Definition: scsicmds.h:116
enum _STORAGE_PROPERTY_ID STORAGE_PROPERTY_ID
unsigned result
Command specific result (DW0)
ptr_t data
Definition: megaraid.h:94
static int drive_letter(const char *s)
Definition: os_win32.cpp:386
static bool match(const char *pattern, const char *str)
static int run_cmd(const char *cmd, char *dataout, int outsize)
Definition: os_win32.cpp:2486
List of devices for DEVICESCAN.
enum ata_cmd_in::@27 direction
I/O direction.
device_type * release()
Return the pointer and release ownership.
#define ATA_CHECK_POWER_MODE
Definition: atacmds.h:71
ata_out_regs prev
read with HOB=1
struct _STORAGE_PROPERTY_QUERY STORAGE_PROPERTY_QUERY
struct _IDEREGS IDEREGS
static void init()
Initialize platform interface and register with smi().
Definition: dev_legacy.cpp:341
#define IOCTL_STORAGE_QUERY_PROPERTY
Definition: os_win32.cpp:230
The platform interface abstraction.
static int get_device_power_state(HANDLE hdevice)
Definition: os_win32.cpp:1368
CSMI_SAS_DRIVER_INFO Information
Definition: csmisas.h:1026
static bool is_sat(const STORAGE_DEVICE_DESCRIPTOR_DATA *data)
Definition: os_win32.cpp:4013
NVMe device access.
static void set(smart_interface *intf)
Set interface to use, must be called from init().
void * buffer
Pointer to data buffer.
unsigned get_nsid() const
Get namespace id.
static int smart_ioctl(HANDLE hdevice, IDEREGS *regs, char *data, unsigned datasize, int port)
Definition: os_win32.cpp:536
static int is_permissive()
Definition: os_win32.cpp:373
win_areca_ata_device(smart_interface *intf, const char *dev_name, int disknum, int encnum=1)
Definition: os_win32.cpp:3225
__u8 bDestinationSASAddress[8]
Definition: csmisas.h:1679
const char * get_errmsg() const
Get last error message.
long long int64_t
Definition: int64.h:51
#define ATA_FLAGS_DATA_OUT
Definition: os_win32.cpp:179
static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice, IDEREGS *regs, char *data, int datasize)
Definition: os_win32.cpp:836
void dStrHex(const char *str, int len, int no_ascii)
Definition: scsicmds.cpp:87
unsigned char failuretest_permissive
Definition: smartctl.cpp:1189
#define CSMI_ALL_SIGNATURE
Definition: csmisas.h:403
unsigned char opcode
Opcode (CDW0 07:00)
UCHAR bDriveHeadReg
Definition: os_os2.cpp:55
unsigned char scsi_debugmode
Definition: scsicmds.cpp:54
#define IOCTL_SCSI_MINIPORT_ENABLE_SMART
Definition: os_win32.cpp:210
static win_dev_type get_phy_drive_type(int drive, GETVERSIONINPARAMS_EX *ata_version_ex)
Definition: os_win32.cpp:4107
mega_passthru pthru
Definition: megaraid.h:93
bool is_ata() const
Return true if ATA device.
Definition: dev_interface.h:93
void pout(const char *fmt,...)
Definition: smartctl.cpp:1170
size_t max_sense_len
Definition: scsicmds.h:124
virtual bool close()
Close device, return false on error.
Definition: os_win32.cpp:467
HANDLE m_fh
Controller device handle.
Definition: os_win32.cpp:2274
unsigned char fw_rev[8]
Definition: atacmds.h:133
ptr_t buffer
Definition: megaraid.h:89
#define CSMI_SAS_PROTOCOL_SATA
Definition: csmisas.h:733
unsigned cdw12
#define SRB_DataOut
Definition: aacraid.h:51
#define ASSERT_CONST(c, n)
Definition: os_win32.cpp:97
UCHAR bCommandReg
Definition: os_os2.cpp:56
ata_register status
int dxfer_dir
Definition: scsicmds.h:118
IOCTL_HEADER IoctlHeader
Definition: csmisas.h:1551
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
#define IOCTL_IDE_PASS_THROUGH
Definition: os_win32.cpp:136
virtual int ata_command_interface(smart_command_set command, int select, char *data)
Old ATA interface called by ata_pass_through()
Definition: os_win32.cpp:2658
#define ATA_SMART_READ_VALUES
Definition: atacmds.h:95
void set_encnum(int encnum)
Definition: dev_areca.h:129
unsigned size
Size of buffer.
static int sdxy_to_phydrive(const char(&xy)[2+1])
Definition: os_win32.cpp:402
Wrapper class for regex(3).
Definition: utility.h:232
win_areca_scsi_device(smart_interface *intf, const char *dev_name, int disknum, int encnum=1)
Definition: os_win32.cpp:3111
ata_register lba_low
virtual bool open()
Open device, return false on error.
Definition: os_win32.cpp:2547
unsigned cdw15
Cmd specific.
SCSI device access.
Definition: atacmds.h:55
unsigned nsid
Namespace ID.
ata_register features
u8 b[12]
Definition: megaraid.h:96
#define DXFER_NONE
Definition: scsicmds.h:110
#define IOCTL_SCSI_MINIPORT_IDENTIFY
Definition: os_win32.cpp:207
#define SRB_NoDataXfer
Definition: aacraid.h:52
#define ATA_SMART_AUTO_OFFLINE
Definition: atacmds.h:108
CSMI_SAS_IDENTIFY Identify
Definition: csmisas.h:1530
static int storage_predict_failure_ioctl(HANDLE hdevice, char *data=0)
Definition: os_win32.cpp:1110
virtual bool scan_smart_devices(smart_device_list &devlist, const char *type, const char *pattern=0)
Fill 'devlist' with devices of some 'type' with device names specified by some optional 'pattern'...
Definition: os_win32.cpp:4212
smart_command_set
Definition: atacmds.h:48
void set_data_in(unsigned char op, void *buf, unsigned sz)
virtual smart_device * autodetect_open()
Open device with autodetection support.
Definition: os_win32.cpp:3258
#define CSMI_SAS_PROTOCOL_STP
Definition: csmisas.h:735
u32 w[3]
Definition: megaraid.h:98
UCHAR bCylLowReg
Definition: os_os2.cpp:53
#define DXFER_TO_DEVICE
Definition: scsicmds.h:112
virtual bool is_open() const
Return true if device is open.
Definition: os_win32.cpp:462
STORAGE_BUS_TYPE BusType
Definition: os_win32.cpp:244
virtual bool arcmsr_probe()
Definition: dev_areca.cpp:264
#define ATA_SMART_READ_THRESHOLDS
Definition: atacmds.h:96
bool is_48bit_cmd() const
Return true if 48-bit command.
virtual scsi_device * get_scsi_device(const char *name, const char *type)
Return standard SCSI device.
Definition: os_win32.cpp:3896
virtual const char * get_usb_dev_type_by_id(int vendor_id, int product_id, int version=-1)
Get type name for USB device with known VENDOR:PRODUCT ID.
Definition: scsiata.cpp:1594
#define ASSERT_SIZEOF(t, n)
Definition: os_win32.cpp:99
u8 lun
Definition: megaraid.h:86
enum _STORAGE_QUERY_TYPE STORAGE_QUERY_TYPE
ata_register device
Base class for all devices.
Definition: dev_interface.h:39
virtual smart_device * autodetect_open()
Open device with autodetection support.
Definition: os_win32.cpp:3144
ata_register lba_high
#define CSMI_SAS_LINK_RATE_NEGOTIATED
Definition: csmisas.h:804
#define IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG
Definition: os_win32.cpp:218
bool select_port(int port)
Select physical drive.
Definition: os_win32.cpp:2075
static win_dev_type get_log_drive_type(int drive)
Definition: os_win32.cpp:4120
#define IOCTL_SCSI_MINIPORT_RETURN_STATUS
Definition: os_win32.cpp:212
size_t cmnd_len
Definition: scsicmds.h:117
UCHAR bFeaturesReg
Definition: os_os2.cpp:50
ATA device access.
ata_register sector_count
#define ATA_SMART_IMMEDIATE_OFFLINE
Definition: atacmds.h:99
#define ATA_FLAGS_48BIT_COMMAND
Definition: os_win32.cpp:180
win_aacraid_device(smart_interface *intf, const char *dev_name, unsigned int ctrnum, unsigned int target, unsigned int lun)
Definition: os_win32.cpp:3367
static int storage_query_property_ioctl(HANDLE hdevice, STORAGE_DEVICE_DESCRIPTOR_DATA *data)
Definition: os_win32.cpp:1072
unsigned char serial_no[20]
Definition: atacmds.h:131
STORAGE_QUERY_TYPE QueryType
Definition: os_win32.cpp:268
win_nvme_device(smart_interface *intf, const char *dev_name, const char *req_type, unsigned nsid)
Definition: os_win32.cpp:3558
unsigned long long uint64_t
Definition: int64.h:54
unsigned char * data()
Definition: utility.h:159
__u8 bTargetPortProtocol
Definition: csmisas.h:1520
_STORAGE_PROPERTY_ID
Definition: os_win32.cpp:256
unsigned size
Size of buffer.
static bool is_intel_raid_volume(const STORAGE_DEVICE_DESCRIPTOR_DATA *data)
Definition: os_win32.cpp:4023
virtual bool open()
Open device, return false on error.
Definition: os_win32.cpp:1449
UCHAR CurrentTaskFile[8]
Definition: os_win32.cpp:174
static int ata_pass_through_ioctl(HANDLE hdevice, IDEREGS *regs, IDEREGS *prev_regs, char *data, int datasize)
Definition: os_win32.cpp:724
CSMI_SAS_STP_PASSTHRU_STATUS Status
Definition: csmisas.h:1699
unsigned cdw13
ata_register command
__u8 bSASAddress[8]
Definition: csmisas.h:1522
static long scsi_pass_through_indirect(HANDLE h, SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER *sbd)
Definition: os_win32.cpp:2787
static const char * findstr(const char *str, const char *sub)
Definition: os_win32.cpp:2540
HANDLE m_fh
File handle.
Definition: os_win32.cpp:450
UINT8 scsi_status
Definition: scsicmds.h:127
UCHAR bCylHighReg
Definition: os_os2.cpp:54
ata_smart_values m_smart_buf
Definition: os_win32.cpp:2440
ATA pass through input parameters.
unsigned cdw10
static int get_clipboard(char *data, int datasize)
Definition: os_win32.cpp:2463
#define CSMI_SAS_STP_WRITE
Definition: csmisas.h:858
STORAGE_PROPERTY_ID PropertyId
Definition: os_win32.cpp:267
#define ATA_SMART_ENABLE
Definition: atacmds.h:103
CSMI_SAS_STP_PASSTHRU Parameters
Definition: csmisas.h:1698
CSMI_SAS_PHY_INFO Information
Definition: csmisas.h:1552
virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io *iop)
Definition: os_win32.cpp:3283
virtual bool close()
Close device, return false on error.
Definition: os_win32.cpp:2651
#define SMART_VENDOR_3WARE
Definition: os_win32.cpp:287
virtual bool csmi_ioctl(unsigned code, IOCTL_HEADER *csmi_buffer, unsigned csmi_bufsiz)=0
Call platform-specific CSMI ioctl.
std::string strprintf(const char *fmt,...)
Definition: utility.cpp:750
UCHAR AdditionalParameters[1]
Definition: os_win32.cpp:269
STORAGE_DEVICE_DESCRIPTOR desc
Definition: os_win32.cpp:1065
virtual bool scsi_pass_through(struct scsi_cmnd_io *iop)
SCSI pass through.
Definition: os_win32.cpp:3399
static bool get_serial_from_wmi(int drive, ata_identify_device *id)
Definition: os_win32.cpp:1182
#define CSMI_SAS_STP_PIO
Definition: csmisas.h:860
#define IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS
Definition: os_win32.cpp:209
ata_register lba_low
void set_nsid(unsigned nsid)
Set namespace id.
unsigned char model[40]
Definition: atacmds.h:134
virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io *iop)
Definition: os_win32.cpp:3149
#define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE
Definition: os_win32.cpp:216
static void copy_swapped(unsigned char *dest, const char *src, int destsize)
Definition: os_win32.cpp:410
#define ATA_FLAGS_DATA_IN
Definition: os_win32.cpp:178
static int get_identify_from_device_property(HANDLE hdevice, ata_identify_device *id)
Definition: os_win32.cpp:1140
virtual bool ata_pass_through(const ata_cmd_in &in, ata_cmd_out &out)
ATA pass through.
Definition: os_win32.cpp:2151
ata_register lba_high
struct _GETVERSIONINPARAMS_EX GETVERSIONINPARAMS_EX
u8 cmd
Definition: megaraid.h:80
smart_interface * smi()
Get interface which produced this object.
unsigned get_ports_used()
Get bitmask of used ports.
Definition: os_win32.cpp:2043
CSMI_SAS_PHY_ENTITY Phy[32]
Definition: csmisas.h:1546
size_t dxfer_len
Definition: scsicmds.h:121
void clear_err()
Clear last error info.
const char * get_dev_name() const
Get device (path)name.
Definition: atacmds.h:50
std::string info_name
Informal name.
Definition: dev_interface.h:53
win_scsi_device(smart_interface *intf, const char *dev_name, const char *req_type)
Definition: os_win32.cpp:2706
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
static int ata_via_3ware_miniport_ioctl(HANDLE hdevice, IDEREGS *regs, char *data, int datasize, int port)
Definition: os_win32.cpp:966
ATA Output registers (for 28-bit commands)
static void print_ide_regs(const IDEREGS *r, int out)
Definition: os_win32.cpp:482
virtual nvme_device * get_nvme_device(const char *name, const char *type, unsigned nsid)
Return standard NVMe device.
Definition: os_win32.cpp:3901
virtual bool open()
Open device, return false on error.
Definition: os_win32.cpp:3120
static void print_ide_regs_io(const IDEREGS *ri, const IDEREGS *ro)
Definition: os_win32.cpp:489
win_ata_device(smart_interface *intf, const char *dev_name, const char *req_type)
Definition: os_win32.cpp:1423
#define NVME_PASS_THROUGH_SRB_IO_CODE
Definition: os_win32.cpp:326
virtual bool open()
Open device, return false on error.
Definition: os_win32.cpp:3234
static bool get_usb_id(int phydrive, int logdrive, unsigned short &vendor_id, unsigned short &product_id)
Definition: os_win32.cpp:1211
ATA pass through output parameters.
void set_fh(HANDLE fh)
Set handle for open() in derived classes.
Definition: os_win32.cpp:442
CSMI_SAS_PHY_ENTITY m_phy_ent
CSMI info for this phy.
Definition: os_win32.cpp:1984
#define IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
Definition: os_win32.cpp:215
struct _NVME_PASS_THROUGH_IOCTL NVME_PASS_THROUGH_IOCTL
virtual bool open()
Open device, return false on error.
Definition: os_win32.cpp:3612
virtual smart_device * autodetect_smart_device(const char *name)
Autodetect device if no device type specified.
Definition: os_win32.cpp:4177
static const char * ata_get_def_options()
Definition: os_win32.cpp:1441
unsigned cdw14
#define ATA_SMART_STATUS
Definition: atacmds.h:105