]> git.proxmox.com Git - mirror_smartmontools-debian.git/blob - os_win32.cpp
Imported upstream version 5.38~cvs20071118
[mirror_smartmontools-debian.git] / os_win32.cpp
1 /*
2 * os_win32.cpp
3 *
4 * Home page of code is: http://smartmontools.sourceforge.net
5 *
6 * Copyright (C) 2004-7 Christian Franke <smartmontools-support@lists.sourceforge.net>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * You should have received a copy of the GNU General Public License
14 * (for example COPYING); if not, write to the Free
15 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 *
17 */
18
19 #include "config.h"
20 #include "int64.h"
21 #include "atacmds.h"
22 #include "extern.h"
23 extern smartmonctrl * con; // con->permissive,reportataioctl
24 #include "scsicmds.h"
25 #include "utility.h"
26 extern int64_t bytes; // malloc() byte count
27
28 #include <errno.h>
29 #ifdef _DEBUG
30 #include <assert.h>
31 #else
32 #define assert(x) /**/
33 #endif
34 #define WIN32_LEAN_AND_MEAN
35 #include <windows.h>
36 #include <stddef.h> // offsetof()
37 #include <io.h> // access()
38
39 // Macro to check constants at compile time using a dummy typedef
40 #define ASSERT_CONST(c, n) \
41 typedef char assert_const_##c[((c) == (n)) ? 1 : -1]
42 #define ASSERT_SIZEOF(t, n) \
43 typedef char assert_sizeof_##t[(sizeof(t) == (n)) ? 1 : -1]
44
45
46 // Needed by '-V' option (CVS versioning) of smartd/smartctl
47 const char *os_XXXX_c_cvsid="$Id: os_win32.cpp,v 1.59 2007/10/31 22:08:04 chrfranke Exp $"
48 ATACMDS_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
49
50
51 // Running on Win9x/ME ?
52 static inline bool is_win9x()
53 {
54 return !!(GetVersion() & 0x80000000);
55 }
56
57 // Running on 64-bit Windows as 32-bit app ?
58 static bool is_wow64()
59 {
60 HMODULE hk = GetModuleHandleA("kernel32");
61 if (!hk)
62 return false;
63 BOOL (WINAPI * IsWow64Process_p)(HANDLE, PBOOL) =
64 (BOOL (WINAPI *)(HANDLE, PBOOL))GetProcAddress(hk, "IsWow64Process");
65 if (!IsWow64Process_p)
66 return false;
67 BOOL w64 = FALSE;
68 if (!IsWow64Process_p(GetCurrentProcess(), &w64))
69 return false;
70 return !!w64;
71 }
72
73
74 #ifndef HAVE_GET_OS_VERSION_STR
75 #error define of HAVE_GET_OS_VERSION_STR missing in config.h
76 #endif
77
78 // Return build host and OS version as static string
79 const char * get_os_version_str()
80 {
81 static char vstr[sizeof(SMARTMONTOOLS_BUILD_HOST)-3-1+sizeof("-2003r2(64)-sp2.1")+13];
82 char * const vptr = vstr+sizeof(SMARTMONTOOLS_BUILD_HOST)-3-1;
83 const int vlen = sizeof(vstr)-(sizeof(SMARTMONTOOLS_BUILD_HOST)-3);
84
85 // remove "-pc" to avoid long lines
86 assert(!strncmp(SMARTMONTOOLS_BUILD_HOST+5, "pc-", 3));
87 strcpy(vstr, "i686-"); strcpy(vstr+5, SMARTMONTOOLS_BUILD_HOST+5+3);
88 assert(vptr == vstr+strlen(vstr) && vptr+vlen+1 == vstr+sizeof(vstr));
89
90 OSVERSIONINFOEXA vi; memset(&vi, 0, sizeof(vi));
91 vi.dwOSVersionInfoSize = sizeof(vi);
92 if (!GetVersionExA((OSVERSIONINFOA *)&vi)) {
93 memset(&vi, 0, sizeof(vi));
94 vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
95 if (!GetVersionExA((OSVERSIONINFOA *)&vi))
96 return vstr;
97 }
98
99 if (vi.dwPlatformId > 0xff || vi.dwMajorVersion > 0xff || vi.dwMinorVersion > 0xff)
100 return vstr;
101
102 const char * w;
103 switch (vi.dwPlatformId << 16 | vi.dwMajorVersion << 8 | vi.dwMinorVersion) {
104 case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400| 0:
105 w = (vi.szCSDVersion[1] == 'B' ||
106 vi.szCSDVersion[1] == 'C' ? "95-osr2" : "95"); break;
107 case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400|10:
108 w = (vi.szCSDVersion[1] == 'A' ? "98se" : "98"); break;
109 case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400|90: w = "me"; break;
110 //case VER_PLATFORM_WIN32_NT <<16|0x0300|51: w = "nt3.51"; break;
111 case VER_PLATFORM_WIN32_NT <<16|0x0400| 0: w = "nt4"; break;
112 case VER_PLATFORM_WIN32_NT <<16|0x0500| 0: w = "2000"; break;
113 case VER_PLATFORM_WIN32_NT <<16|0x0500| 1:
114 w = (!GetSystemMetrics(87/*SM_MEDIACENTER*/) ? "xp"
115 : "xp-mc"); break;
116 case VER_PLATFORM_WIN32_NT <<16|0x0500| 2:
117 w = (!GetSystemMetrics(89/*SM_SERVERR2*/) ? "2003"
118 : "2003r2"); break;
119 case VER_PLATFORM_WIN32_NT <<16|0x0600| 0: w = "vista"; break;
120 default: w = 0; break;
121 }
122
123 const char * w64 = (is_wow64() ? "(64)" : "");
124 if (!w)
125 snprintf(vptr, vlen, "-%s%lu.%lu%s",
126 (vi.dwPlatformId==VER_PLATFORM_WIN32_NT ? "nt" : "9x"),
127 vi.dwMajorVersion, vi.dwMinorVersion, w64);
128 else if (vi.wServicePackMinor)
129 snprintf(vptr, vlen, "-%s%s-sp%u.%u", w, w64, vi.wServicePackMajor, vi.wServicePackMinor);
130 else if (vi.wServicePackMajor)
131 snprintf(vptr, vlen, "-%s%s-sp%u", w, w64, vi.wServicePackMajor);
132 else
133 snprintf(vptr, vlen, "-%s%s", w, w64);
134 return vstr;
135 }
136
137
138 static int get_phy_drive_type(int drive);
139 static int get_log_drive_type(int drive);
140
141 #define ATARAID_FDOFFSET 0x0200
142
143 static int ata_open(int phydrive, int logdrive, const char * options, int port);
144 static void ata_close(int fd);
145 static int ata_scan_win9x(unsigned long * drives);
146 static int ata_scan(unsigned long * drives, int * rdriveno, unsigned long * rdrives);
147 static const char * ata_get_def_options(void);
148
149 #define TW_CLI_FDOFFSET 0x0300
150
151 static int tw_cli_open(const char * name);
152 static void tw_cli_close();
153
154 #define ASPI_FDOFFSET 0x0100
155
156 static int aspi_open(unsigned adapter, unsigned id);
157 static void aspi_close(int fd);
158 static int aspi_scan(unsigned long * drives);
159
160 #define SPT_FDOFFSET 0x0400
161
162 static int spt_open(int pd_num, int ld_num, int tape_num, int sub_addr);
163 static void spt_close(int fd);
164 static int spt_scan(unsigned long * drives);
165
166
167 static int is_permissive()
168 {
169 if (!con->permissive) {
170 pout("To continue, add one or more '-T permissive' options.\n");
171 return 0;
172 }
173 con->permissive--;
174 return 1;
175 }
176
177 // return number for drive letter, -1 on error
178 // "[A-Za-z]:([/\\][.]?)?" => 0-25
179 // Accepts trailing '"' to fix broken "X:\" parameter passing from .bat files
180 static int drive_letter(const char * s)
181 {
182 return ( (('A' <= s[0] && s[0] <= 'Z') || ('a' <= s[0] && s[0] <= 'z'))
183 && s[1] == ':'
184 && (!s[2] || ( strchr("/\\\"", s[2])
185 && (!s[3] || (s[3] == '.' && !s[4]))) ) ?
186 (s[0] & 0x1f) - 1 : -1);
187 }
188
189 // Skip trailing "/dev/", do not allow "/dev/X:"
190 static const char * skipdev(const char * s)
191 {
192 return (!strncmp(s, "/dev/", 5) && drive_letter(s+5) < 0 ? s+5 : s);
193 }
194
195
196 // tries to guess device type given the name (a path). See utility.h
197 // for return values.
198 int guess_device_type (const char * dev_name)
199 {
200 dev_name = skipdev(dev_name);
201 if (!strncmp(dev_name, "scsi", 4))
202 return CONTROLLER_SCSI;
203 if (is_win9x())
204 return CONTROLLER_ATA;
205 if (!strncmp(dev_name, "hd", 2))
206 return CONTROLLER_ATA;
207 if (!strncmp(dev_name, "tw_cli", 6))
208 return CONTROLLER_ATA;
209 if (!strncmp(dev_name, "st", 2))
210 return CONTROLLER_SCSI;
211 if (!strncmp(dev_name, "nst", 3))
212 return CONTROLLER_SCSI;
213 if (!strncmp(dev_name, "tape", 4))
214 return CONTROLLER_SCSI;
215 int logdrive = drive_letter(dev_name);
216 if (logdrive >= 0) {
217 int type = get_log_drive_type(logdrive);
218 return (type != CONTROLLER_UNKNOWN ? type : CONTROLLER_SCSI);
219 }
220 char drive[1+1] = "";
221 if (sscanf(dev_name, "sd%1[a-z]", drive) == 1)
222 return get_phy_drive_type(drive[0]-'a');
223 int phydrive = -1;
224 if (sscanf(dev_name, "pd%d", &phydrive) == 1 && phydrive >= 0)
225 return get_phy_drive_type(phydrive);
226 return CONTROLLER_UNKNOWN;
227 }
228
229
230 // makes a list of ATA or SCSI devices for the DEVICESCAN directive of
231 // smartd. Returns number N of devices, or -1 if out of
232 // memory. Allocates N+1 arrays: one of N pointers (devlist), the
233 // others each contain null-terminated character strings.
234 int make_device_names (char*** devlist, const char* type)
235 {
236 unsigned long drives[3];
237 int rdriveno[2];
238 unsigned long rdrives[2];
239 int i, j, n, nmax, sz;
240 const char * path;
241
242 drives[0] = drives[1] = drives[2] = 0;
243 rdriveno[0] = rdriveno[1] = -1;
244 rdrives[0] = rdrives[1] = 0;
245
246 bool win9x = is_win9x();
247 if (!strcmp(type, "ATA")) {
248 // bit i set => drive i present
249 if (win9x) {
250 n = ata_scan_win9x(drives);
251 path = "/dev/hda";
252 }
253 else {
254 n = ata_scan(drives, rdriveno, rdrives);
255 path = "/dev/sda";
256 }
257 nmax = 10;
258 }
259 else if (!strcmp(type, "SCSI")) {
260 if (win9x) {
261 // bit i set => drive with ID (i & 0x7) on adapter (i >> 3) present
262 n = aspi_scan(drives);
263 path = "/dev/scsi00";
264 nmax = 10*8;
265 }
266 else {
267 // bit i set => drive i present
268 n = spt_scan(drives);
269 path = "/dev/sda";
270 nmax = 10;
271 }
272 }
273 else
274 return -1;
275
276 if (n <= 0)
277 return 0;
278
279 // Alloc devlist
280 sz = n * sizeof(char **);
281 *devlist = (char **)malloc(sz); bytes += sz;
282
283 // Add devices
284 for (i = j = 0; i < n; ) {
285 while (j < nmax && !(drives[j >> 5] & (1L << (j & 0x1f))))
286 j++;
287 assert(j < nmax);
288
289 if (j == rdriveno[0] || j == rdriveno[1]) {
290 // Add physical drives behind this logical drive
291 int ci = (j == rdriveno[0] ? 0 : 1);
292 for (int pi = 0; pi < 32 && i < n; pi++) {
293 if (!(rdrives[ci] & (1L << pi)))
294 continue;
295 char rpath[20];
296 sprintf(rpath, "/dev/sd%c,%u", 'a'+j, pi);
297 sz = strlen(rpath)+1;
298 char * s = (char *)malloc(sz); bytes += sz;
299 strcpy(s, rpath);
300 (*devlist)[i++] = s;
301 }
302 }
303 else {
304 sz = strlen(path)+1;
305 char * s = (char *)malloc(sz); bytes += sz;
306 strcpy(s, path);
307
308 if (nmax <= 10) {
309 assert(j <= 9);
310 s[sz-2] += j; // /dev/hd[a-j]
311 }
312 else {
313 assert((j >> 3) <= 9);
314 s[sz-3] += (j >> 3); // /dev/scsi[0-9].....
315 s[sz-2] += (j & 0x7); // .....[0-7]
316 }
317 (*devlist)[i++] = s;
318 }
319 j++;
320 }
321
322 return n;
323 }
324
325
326 // Like open(). Return positive integer handle, only used by
327 // functions below. type="ATA" or "SCSI". If you need to store extra
328 // information about your devices, create a private internal array
329 // within this file (see os_freebsd.cpp for an example).
330 int deviceopen(const char * pathname, char *type)
331 {
332 pathname = skipdev(pathname);
333 int len = strlen(pathname);
334
335 if (!strcmp(type, "ATA")) {
336 // [sh]d[a-z](:[saicp]+)? => Physical drive 0-25, with options
337 char drive[1+1] = "", options[7+1] = ""; int n1 = -1, n2 = -1;
338 if ( sscanf(pathname, "%*[sh]d%1[a-z]%n:%6[saicmp]%n", drive, &n1, options, &n2) >= 1
339 && ((n1 == len && !options[0]) || n2 == len) ) {
340 return ata_open(drive[0] - 'a', -1, options, -1);
341 }
342 // [sh]d[a-z],N(:[saicp]+)? => Physical drive 0-25, RAID port N, with options
343 drive[0] = 0; options[0] = 0; n1 = -1; n2 = -1;
344 unsigned port = ~0;
345 if ( sscanf(pathname, "%*[sh]d%1[a-z],%u%n:%7[saicmp3]%n", drive, &port, &n1, options, &n2) >= 2
346 && port < 32 && ((n1 == len && !options[0]) || n2 == len) ) {
347 return ata_open(drive[0] - 'a', -1, options, port);
348 }
349 // pd<m>,N => Physical drive <m>, RAID port N
350 int phydrive = -1; port = ~0; n1 = -1; n2 = -1;
351 if ( sscanf(pathname, "pd%d%n,%u%n", &phydrive, &n1, &port, &n2) >= 1
352 && phydrive >= 0 && ((n1 == len && (int)port < 0) || (n2 == len && port < 32))) {
353 return ata_open(phydrive, -1, "", (int)port);
354 }
355 // [a-zA-Z]: => Physical drive behind logical drive 0-25
356 int logdrive = drive_letter(pathname);
357 if (logdrive >= 0) {
358 return ata_open(-1, logdrive, "", -1);
359 }
360 // tw_cli/... => Parse tw_cli output
361 if (!strncmp(pathname, "tw_cli/", 7)) {
362 return tw_cli_open(pathname+7);
363 }
364 } else if (!strcmp(type, "SCSI")) {
365 // scsi[0-9][0-f] => ASPI Adapter 0-9, ID 0-15, LUN 0
366 unsigned adapter = ~0, id = ~0; int n1 = -1;
367 if (sscanf(pathname,"scsi%1u%1x%n", &adapter, &id, &n1) == 2 && n1 == len) {
368 return aspi_open(adapter, id);
369 }
370 // sd[a-z],N => Physical drive 0-25, RAID port N
371 char drive[1+1] = ""; int sub_addr = -1; n1 = -1; int n2 = -1;
372 if ( sscanf(pathname, "sd%1[a-z]%n,%d%n", drive, &n1, &sub_addr, &n2) >= 1
373 && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0)) ) {
374 return spt_open(drive[0] - 'a', -1, -1, sub_addr);
375 }
376 // pd<m>,N => Physical drive <m>, RAID port N
377 int pd_num = -1; sub_addr = -1; n1 = -1; n2 = -1;
378 if ( sscanf(pathname, "pd%d%n,%d%n", &pd_num, &n1, &sub_addr, &n2) >= 1
379 && pd_num >= 0 && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0))) {
380 return spt_open(pd_num, -1, -1, sub_addr);
381 }
382 // [a-zA-Z]: => Physical drive behind logical drive 0-25
383 int logdrive = drive_letter(pathname);
384 if (logdrive >= 0) {
385 return spt_open(-1, logdrive, -1, -1);
386 }
387 // n?st<m> => tape drive <m> (same names used in Cygwin's /dev emulation)
388 int tape_num = -1; n1 = -1;
389 if (sscanf(pathname, "st%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) {
390 return spt_open(-1, -1, tape_num, -1);
391 }
392 tape_num = -1; n1 = -1;
393 if (sscanf(pathname, "nst%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) {
394 return spt_open(-1, -1, tape_num, -1);
395 }
396 // tape<m> => tape drive <m>
397 tape_num = -1; n1 = -1;
398 if (sscanf(pathname, "tape%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) {
399 return spt_open(-1, -1, tape_num, -1);
400 }
401 }
402
403 errno = EINVAL;
404 return -1;
405 }
406
407
408 // Like close(). Acts only on handles returned by above function.
409 // (Never called in smartctl!)
410 int deviceclose(int fd)
411 {
412 if ((fd & 0xff00) == ASPI_FDOFFSET)
413 aspi_close(fd);
414 else if (fd >= SPT_FDOFFSET)
415 spt_close(fd);
416 else if (fd == TW_CLI_FDOFFSET)
417 tw_cli_close();
418 else
419 ata_close(fd);
420 return 0;
421 }
422
423
424 // print examples for smartctl
425 void print_smartctl_examples(){
426 printf("=================================================== SMARTCTL EXAMPLES =====\n\n"
427 " smartctl -a /dev/hda (Prints all SMART information)\n\n"
428 #ifdef HAVE_GETOPT_LONG
429 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/hda\n"
430 " (Enables SMART on first disk)\n\n"
431 " smartctl -t long /dev/hda (Executes extended disk self-test)\n\n"
432 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/hda\n"
433 " (Prints Self-Test & Attribute errors)\n"
434 #else
435 " smartctl -s on -o on -S on /dev/hda (Enables SMART on first disk)\n"
436 " smartctl -t long /dev/hda (Executes extended disk self-test)\n"
437 " smartctl -A -l selftest -q errorsonly /dev/hda\n"
438 " (Prints Self-Test & Attribute errors)\n"
439 #endif
440 " smartctl -a /dev/scsi21\n"
441 " (Prints all information for SCSI disk on ASPI adapter 2, ID 1)\n"
442 " smartctl -a /dev/sda\n"
443 " (Prints all information for SCSI disk on PhysicalDrive 0)\n"
444 " smartctl -a /dev/pd3\n"
445 " (Prints all information for SCSI disk on PhysicalDrive 3)\n"
446 " smartctl -a /dev/tape1\n"
447 " (Prints all information for SCSI tape on Tape 1)\n"
448 " smartctl -A /dev/hdb,3\n"
449 " (Prints Attributes for physical drive 3 on 3ware 9000 RAID)\n"
450 " smartctl -A /dev/tw_cli/c0/p1\n"
451 " (Prints Attributes for 3ware controller 0, port 1 using tw_cli)\n"
452 "\n"
453 " ATA SMART access methods and ordering may be specified by modifiers\n"
454 " following the device name: /dev/hdX:[saicm], where\n"
455 " 's': SMART_* IOCTLs, 'a': IOCTL_ATA_PASS_THROUGH,\n"
456 " 'i': IOCTL_IDE_PASS_THROUGH, 'c': ATA via IOCTL_SCSI_PASS_THROUGH,\n"
457 " 'm': IOCTL_SCSI_MINIPORT_*.\n"
458 " The default on this system is /dev/hdX:%s\n", ata_get_def_options()
459 );
460 }
461
462
463 /////////////////////////////////////////////////////////////////////////////
464 // ATA Interface
465 /////////////////////////////////////////////////////////////////////////////
466
467 // SMART_* IOCTLs, also known as DFP_* (Disk Fault Protection)
468
469 #define FILE_READ_ACCESS 0x0001
470 #define FILE_WRITE_ACCESS 0x0002
471 #define METHOD_BUFFERED 0
472 #define CTL_CODE(DeviceType, Function, Method, Access) (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
473
474 #define FILE_DEVICE_DISK 7
475 #define IOCTL_DISK_BASE FILE_DEVICE_DISK
476
477 #define SMART_GET_VERSION \
478 CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS)
479
480 #define SMART_SEND_DRIVE_COMMAND \
481 CTL_CODE(IOCTL_DISK_BASE, 0x0021, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
482
483 #define SMART_RCV_DRIVE_DATA \
484 CTL_CODE(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
485
486 ASSERT_CONST(SMART_GET_VERSION , 0x074080);
487 ASSERT_CONST(SMART_SEND_DRIVE_COMMAND, 0x07c084);
488 ASSERT_CONST(SMART_RCV_DRIVE_DATA , 0x07c088);
489
490 #define SMART_CYL_LOW 0x4F
491 #define SMART_CYL_HI 0xC2
492
493
494 #pragma pack(1)
495
496 typedef struct _GETVERSIONOUTPARAMS {
497 UCHAR bVersion;
498 UCHAR bRevision;
499 UCHAR bReserved;
500 UCHAR bIDEDeviceMap;
501 ULONG fCapabilities;
502 ULONG dwReserved[4];
503 } GETVERSIONOUTPARAMS, *PGETVERSIONOUTPARAMS, *LPGETVERSIONOUTPARAMS;
504
505 ASSERT_SIZEOF(GETVERSIONOUTPARAMS, 24);
506
507
508 #define SMART_VENDOR_3WARE 0x13C1 // identifies 3ware specific parameters
509
510 typedef struct _GETVERSIONINPARAMS_EX {
511 BYTE bVersion;
512 BYTE bRevision;
513 BYTE bReserved;
514 BYTE bIDEDeviceMap;
515 DWORD fCapabilities;
516 DWORD dwDeviceMapEx; // 3ware specific: RAID drive bit map
517 WORD wIdentifier; // Vendor specific identifier
518 WORD wControllerId; // 3ware specific: Controller ID (0,1,...)
519 ULONG dwReserved[2];
520 } GETVERSIONINPARAMS_EX, *PGETVERSIONINPARAMS_EX, *LPGETVERSIONINPARAMS_EX;
521
522 ASSERT_SIZEOF(GETVERSIONINPARAMS_EX, sizeof(GETVERSIONOUTPARAMS));
523
524
525 typedef struct _IDEREGS {
526 UCHAR bFeaturesReg;
527 UCHAR bSectorCountReg;
528 UCHAR bSectorNumberReg;
529 UCHAR bCylLowReg;
530 UCHAR bCylHighReg;
531 UCHAR bDriveHeadReg;
532 UCHAR bCommandReg;
533 UCHAR bReserved;
534 } IDEREGS, *PIDEREGS, *LPIDEREGS;
535
536 typedef struct _SENDCMDINPARAMS {
537 ULONG cBufferSize;
538 IDEREGS irDriveRegs;
539 UCHAR bDriveNumber;
540 UCHAR bReserved[3];
541 ULONG dwReserved[4];
542 UCHAR bBuffer[1];
543 } SENDCMDINPARAMS, *PSENDCMDINPARAMS, *LPSENDCMDINPARAMS;
544
545 ASSERT_SIZEOF(SENDCMDINPARAMS, 32+1);
546
547 typedef struct _SENDCMDINPARAMS_EX {
548 DWORD cBufferSize;
549 IDEREGS irDriveRegs;
550 BYTE bDriveNumber;
551 BYTE bPortNumber; // 3ware specific: port number
552 WORD wIdentifier; // Vendor specific identifier
553 DWORD dwReserved[4];
554 BYTE bBuffer[1];
555 } SENDCMDINPARAMS_EX, *PSENDCMDINPARAMS_EX, *LPSENDCMDINPARAMS_EX;
556
557 ASSERT_SIZEOF(SENDCMDINPARAMS_EX, sizeof(SENDCMDINPARAMS));
558
559
560 /* DRIVERSTATUS.bDriverError constants (just for info, not used)
561 #define SMART_NO_ERROR 0
562 #define SMART_IDE_ERROR 1
563 #define SMART_INVALID_FLAG 2
564 #define SMART_INVALID_COMMAND 3
565 #define SMART_INVALID_BUFFER 4
566 #define SMART_INVALID_DRIVE 5
567 #define SMART_INVALID_IOCTL 6
568 #define SMART_ERROR_NO_MEM 7
569 #define SMART_INVALID_REGISTER 8
570 #define SMART_NOT_SUPPORTED 9
571 #define SMART_NO_IDE_DEVICE 10
572 */
573
574 typedef struct _DRIVERSTATUS {
575 UCHAR bDriverError;
576 UCHAR bIDEError;
577 UCHAR bReserved[2];
578 ULONG dwReserved[2];
579 } DRIVERSTATUS, *PDRIVERSTATUS, *LPDRIVERSTATUS;
580
581 typedef struct _SENDCMDOUTPARAMS {
582 ULONG cBufferSize;
583 DRIVERSTATUS DriverStatus;
584 UCHAR bBuffer[1];
585 } SENDCMDOUTPARAMS, *PSENDCMDOUTPARAMS, *LPSENDCMDOUTPARAMS;
586
587 ASSERT_SIZEOF(SENDCMDOUTPARAMS, 16+1);
588
589 #pragma pack()
590
591
592 /////////////////////////////////////////////////////////////////////////////
593
594 static void print_ide_regs(const IDEREGS * r, int out)
595 {
596 pout("%s=0x%02x,%s=0x%02x, SC=0x%02x, SN=0x%02x, CL=0x%02x, CH=0x%02x, SEL=0x%02x\n",
597 (out?"STS":"CMD"), r->bCommandReg, (out?"ERR":" FR"), r->bFeaturesReg,
598 r->bSectorCountReg, r->bSectorNumberReg, r->bCylLowReg, r->bCylHighReg, r->bDriveHeadReg);
599 }
600
601 static void print_ide_regs_io(const IDEREGS * ri, const IDEREGS * ro)
602 {
603 pout(" Input : "); print_ide_regs(ri, 0);
604 if (ro) {
605 pout(" Output: "); print_ide_regs(ro, 1);
606 }
607 }
608
609 /////////////////////////////////////////////////////////////////////////////
610
611 // call SMART_GET_VERSION, return device map or -1 on error
612
613 static int smart_get_version(HANDLE hdevice, GETVERSIONINPARAMS_EX * ata_version_ex = 0)
614 {
615 GETVERSIONOUTPARAMS vers; memset(&vers, 0, sizeof(vers));
616 const GETVERSIONINPARAMS_EX & vers_ex = (const GETVERSIONINPARAMS_EX &)vers;
617 DWORD num_out;
618
619 if (!DeviceIoControl(hdevice, SMART_GET_VERSION,
620 NULL, 0, &vers, sizeof(vers), &num_out, NULL)) {
621 if (con->reportataioctl)
622 pout(" SMART_GET_VERSION failed, Error=%ld\n", GetLastError());
623 errno = ENOSYS;
624 return -1;
625 }
626 assert(num_out == sizeof(GETVERSIONOUTPARAMS));
627
628 if (con->reportataioctl > 1) {
629 pout(" SMART_GET_VERSION suceeded, bytes returned: %lu\n"
630 " Vers = %d.%d, Caps = 0x%lx, DeviceMap = 0x%02x\n",
631 num_out, vers.bVersion, vers.bRevision,
632 vers.fCapabilities, vers.bIDEDeviceMap);
633 if (vers_ex.wIdentifier == SMART_VENDOR_3WARE)
634 pout(" Identifier = %04x(3WARE), ControllerId=%u, DeviceMapEx = 0x%08lx\n",
635 vers_ex.wIdentifier, vers_ex.wControllerId, vers_ex.dwDeviceMapEx);
636 }
637
638 if (ata_version_ex)
639 *ata_version_ex = vers_ex;
640
641 // TODO: Check vers.fCapabilities here?
642 return vers.bIDEDeviceMap;
643 }
644
645
646 // call SMART_* ioctl
647
648 static int smart_ioctl(HANDLE hdevice, int drive, IDEREGS * regs, char * data, unsigned datasize, int port)
649 {
650 SENDCMDINPARAMS inpar;
651 SENDCMDINPARAMS_EX & inpar_ex = (SENDCMDINPARAMS_EX &)inpar;
652
653 unsigned char outbuf[sizeof(SENDCMDOUTPARAMS)-1 + 512];
654 const SENDCMDOUTPARAMS * outpar;
655 DWORD code, num_out;
656 unsigned int size_out;
657 const char * name;
658
659 memset(&inpar, 0, sizeof(inpar));
660 inpar.irDriveRegs = *regs;
661 // drive is set to 0-3 on Win9x only
662 inpar.irDriveRegs.bDriveHeadReg = 0xA0 | ((drive & 1) << 4);
663 inpar.bDriveNumber = drive;
664
665 if (port >= 0) {
666 // Set RAID port
667 inpar_ex.wIdentifier = SMART_VENDOR_3WARE;
668 inpar_ex.bPortNumber = port;
669 }
670
671 assert(datasize == 0 || datasize == 512);
672 if (datasize) {
673 code = SMART_RCV_DRIVE_DATA; name = "SMART_RCV_DRIVE_DATA";
674 inpar.cBufferSize = size_out = 512;
675 }
676 else {
677 code = SMART_SEND_DRIVE_COMMAND; name = "SMART_SEND_DRIVE_COMMAND";
678 if (regs->bFeaturesReg == ATA_SMART_STATUS)
679 size_out = sizeof(IDEREGS); // ioctl returns new IDEREGS as data
680 // Note: cBufferSize must be 0 on Win9x
681 else
682 size_out = 0;
683 }
684
685 memset(&outbuf, 0, sizeof(outbuf));
686
687 if (!DeviceIoControl(hdevice, code, &inpar, sizeof(SENDCMDINPARAMS)-1,
688 outbuf, sizeof(SENDCMDOUTPARAMS)-1 + size_out, &num_out, NULL)) {
689 // CAUTION: DO NOT change "regs" Parameter in this case, see ata_command_interface()
690 long err = GetLastError();
691 if (con->reportataioctl && (err != ERROR_INVALID_PARAMETER || con->reportataioctl > 1)) {
692 pout(" %s failed, Error=%ld\n", name, err);
693 print_ide_regs_io(regs, NULL);
694 }
695 errno = ( err == ERROR_INVALID_FUNCTION/*9x*/
696 || err == ERROR_INVALID_PARAMETER/*NT/2K/XP*/
697 || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
698 return -1;
699 }
700 // NOTE: On Win9x, inpar.irDriveRegs now contains the returned regs
701
702 outpar = (const SENDCMDOUTPARAMS *)outbuf;
703
704 if (outpar->DriverStatus.bDriverError) {
705 if (con->reportataioctl) {
706 pout(" %s failed, DriverError=0x%02x, IDEError=0x%02x\n", name,
707 outpar->DriverStatus.bDriverError, outpar->DriverStatus.bIDEError);
708 print_ide_regs_io(regs, NULL);
709 }
710 errno = (!outpar->DriverStatus.bIDEError ? ENOSYS : EIO);
711 return -1;
712 }
713
714 if (con->reportataioctl > 1) {
715 pout(" %s suceeded, bytes returned: %lu (buffer %lu)\n", name,
716 num_out, outpar->cBufferSize);
717 print_ide_regs_io(regs, (regs->bFeaturesReg == ATA_SMART_STATUS ?
718 (const IDEREGS *)(outpar->bBuffer) : NULL));
719 }
720
721 if (datasize)
722 memcpy(data, outpar->bBuffer, 512);
723 else if (regs->bFeaturesReg == ATA_SMART_STATUS) {
724 if (nonempty(const_cast<unsigned char *>(outpar->bBuffer), sizeof(IDEREGS)))
725 *regs = *(const IDEREGS *)(outpar->bBuffer);
726 else { // Workaround for driver not returning regs
727 if (con->reportataioctl)
728 pout(" WARNING: driver does not return ATA registers in output buffer!\n");
729 *regs = inpar.irDriveRegs;
730 }
731 }
732
733 return 0;
734 }
735
736
737 /////////////////////////////////////////////////////////////////////////////
738
739 // IDE PASS THROUGH (2000, XP, undocumented)
740 //
741 // Based on WinATA.cpp, 2002 c't/Matthias Withopf
742 // ftp://ftp.heise.de/pub/ct/listings/0207-218.zip
743
744 #define FILE_DEVICE_CONTROLLER 4
745 #define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER
746
747 #define IOCTL_IDE_PASS_THROUGH \
748 CTL_CODE(IOCTL_SCSI_BASE, 0x040A, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
749
750 ASSERT_CONST(IOCTL_IDE_PASS_THROUGH, 0x04d028);
751
752 #pragma pack(1)
753
754 typedef struct {
755 IDEREGS IdeReg;
756 ULONG DataBufferSize;
757 UCHAR DataBuffer[1];
758 } ATA_PASS_THROUGH;
759
760 ASSERT_SIZEOF(ATA_PASS_THROUGH, 12+1);
761
762 #pragma pack()
763
764
765 /////////////////////////////////////////////////////////////////////////////
766
767 static int ide_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize)
768 {
769 if (datasize > 512) {
770 errno = EINVAL;
771 return -1;
772 }
773 unsigned int size = sizeof(ATA_PASS_THROUGH)-1 + datasize;
774 ATA_PASS_THROUGH * buf = (ATA_PASS_THROUGH *)VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
775 DWORD num_out;
776 const unsigned char magic = 0xcf;
777
778 if (!buf) {
779 errno = ENOMEM;
780 return -1;
781 }
782
783 buf->IdeReg = *regs;
784 buf->DataBufferSize = datasize;
785 if (datasize)
786 buf->DataBuffer[0] = magic;
787
788 if (!DeviceIoControl(hdevice, IOCTL_IDE_PASS_THROUGH,
789 buf, size, buf, size, &num_out, NULL)) {
790 long err = GetLastError();
791 if (con->reportataioctl) {
792 pout(" IOCTL_IDE_PASS_THROUGH failed, Error=%ld\n", err);
793 print_ide_regs_io(regs, NULL);
794 }
795 VirtualFree(buf, 0, MEM_RELEASE);
796 errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
797 return -1;
798 }
799
800 // Check ATA status
801 if (buf->IdeReg.bCommandReg/*Status*/ & 0x01) {
802 if (con->reportataioctl) {
803 pout(" IOCTL_IDE_PASS_THROUGH command failed:\n");
804 print_ide_regs_io(regs, &buf->IdeReg);
805 }
806 VirtualFree(buf, 0, MEM_RELEASE);
807 errno = EIO;
808 return -1;
809 }
810
811 // Check and copy data
812 if (datasize) {
813 if ( num_out != size
814 || (buf->DataBuffer[0] == magic && !nonempty(buf->DataBuffer+1, datasize-1))) {
815 if (con->reportataioctl) {
816 pout(" IOCTL_IDE_PASS_THROUGH output data missing (%lu, %lu)\n",
817 num_out, buf->DataBufferSize);
818 print_ide_regs_io(regs, &buf->IdeReg);
819 }
820 VirtualFree(buf, 0, MEM_RELEASE);
821 errno = EIO;
822 return -1;
823 }
824 memcpy(data, buf->DataBuffer, datasize);
825 }
826
827 if (con->reportataioctl > 1) {
828 pout(" IOCTL_IDE_PASS_THROUGH suceeded, bytes returned: %lu (buffer %lu)\n",
829 num_out, buf->DataBufferSize);
830 print_ide_regs_io(regs, &buf->IdeReg);
831 }
832 *regs = buf->IdeReg;
833
834 // Caution: VirtualFree() fails if parameter "dwSize" is nonzero
835 VirtualFree(buf, 0, MEM_RELEASE);
836 return 0;
837 }
838
839
840 /////////////////////////////////////////////////////////////////////////////
841
842 // ATA PASS THROUGH (Win2003, XP SP2)
843
844 #define IOCTL_ATA_PASS_THROUGH \
845 CTL_CODE(IOCTL_SCSI_BASE, 0x040B, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
846
847 ASSERT_CONST(IOCTL_ATA_PASS_THROUGH, 0x04d02c);
848
849 typedef struct _ATA_PASS_THROUGH_EX {
850 USHORT Length;
851 USHORT AtaFlags;
852 UCHAR PathId;
853 UCHAR TargetId;
854 UCHAR Lun;
855 UCHAR ReservedAsUchar;
856 ULONG DataTransferLength;
857 ULONG TimeOutValue;
858 ULONG ReservedAsUlong;
859 ULONG/*_PTR*/ DataBufferOffset;
860 UCHAR PreviousTaskFile[8];
861 UCHAR CurrentTaskFile[8];
862 } ATA_PASS_THROUGH_EX, *PATA_PASS_THROUGH_EX;
863
864 ASSERT_SIZEOF(ATA_PASS_THROUGH_EX, 40);
865
866 #define ATA_FLAGS_DRDY_REQUIRED 0x01
867 #define ATA_FLAGS_DATA_IN 0x02
868 #define ATA_FLAGS_DATA_OUT 0x04
869 #define ATA_FLAGS_48BIT_COMMAND 0x08
870
871
872 /////////////////////////////////////////////////////////////////////////////
873
874 static int ata_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, int datasize)
875 {
876 typedef struct {
877 ATA_PASS_THROUGH_EX apt;
878 ULONG Filler;
879 UCHAR ucDataBuf[512];
880 } ATA_PASS_THROUGH_EX_WITH_BUFFERS;
881
882 const unsigned char magic = 0xcf;
883
884 ATA_PASS_THROUGH_EX_WITH_BUFFERS ab; memset(&ab, 0, sizeof(ab));
885 ab.apt.Length = sizeof(ATA_PASS_THROUGH_EX);
886 //ab.apt.PathId = 0;
887 //ab.apt.TargetId = 0;
888 //ab.apt.Lun = 0;
889 ab.apt.TimeOutValue = 10;
890 unsigned size = offsetof(ATA_PASS_THROUGH_EX_WITH_BUFFERS, ucDataBuf);
891 ab.apt.DataBufferOffset = size;
892
893 if (datasize > 0) {
894 if (datasize > (int)sizeof(ab.ucDataBuf)) {
895 errno = EINVAL;
896 return -1;
897 }
898 ab.apt.AtaFlags = ATA_FLAGS_DATA_IN;
899 ab.apt.DataTransferLength = datasize;
900 size += datasize;
901 ab.ucDataBuf[0] = magic;
902 }
903 else if (datasize < 0) {
904 if (-datasize > (int)sizeof(ab.ucDataBuf)) {
905 errno = EINVAL;
906 return -1;
907 }
908 ab.apt.AtaFlags = ATA_FLAGS_DATA_OUT;
909 ab.apt.DataTransferLength = -datasize;
910 size += -datasize;
911 memcpy(ab.ucDataBuf, data, -datasize);
912 }
913 else {
914 assert(ab.apt.AtaFlags == 0);
915 assert(ab.apt.DataTransferLength == 0);
916 }
917
918 assert(sizeof(ab.apt.CurrentTaskFile) == sizeof(IDEREGS));
919 IDEREGS * ctfregs = (IDEREGS *)ab.apt.CurrentTaskFile;
920 *ctfregs = *regs;
921
922 DWORD num_out;
923 if (!DeviceIoControl(hdevice, IOCTL_ATA_PASS_THROUGH,
924 &ab, size, &ab, size, &num_out, NULL)) {
925 long err = GetLastError();
926 if (con->reportataioctl) {
927 pout(" IOCTL_ATA_PASS_THROUGH failed, Error=%ld\n", err);
928 print_ide_regs_io(regs, NULL);
929 }
930 errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
931 return -1;
932 }
933
934 // Check ATA status
935 if (ctfregs->bCommandReg/*Status*/ & 0x01) {
936 if (con->reportataioctl) {
937 pout(" IOCTL_ATA_PASS_THROUGH command failed:\n");
938 print_ide_regs_io(regs, ctfregs);
939 }
940 errno = EIO;
941 return -1;
942 }
943
944 // Check and copy data
945 if (datasize > 0) {
946 if ( num_out != size
947 || (ab.ucDataBuf[0] == magic && !nonempty(ab.ucDataBuf+1, datasize-1))) {
948 if (con->reportataioctl) {
949 pout(" IOCTL_ATA_PASS_THROUGH output data missing (%lu)\n", num_out);
950 print_ide_regs_io(regs, ctfregs);
951 }
952 errno = EIO;
953 return -1;
954 }
955 memcpy(data, ab.ucDataBuf, datasize);
956 }
957
958 if (con->reportataioctl > 1) {
959 pout(" IOCTL_ATA_PASS_THROUGH suceeded, bytes returned: %lu\n", num_out);
960 print_ide_regs_io(regs, ctfregs);
961 }
962 *regs = *ctfregs;
963
964 return 0;
965 }
966
967
968 /////////////////////////////////////////////////////////////////////////////
969
970 // ATA PASS THROUGH via SCSI PASS THROUGH (WinNT4 only)
971
972 #define IOCTL_SCSI_PASS_THROUGH \
973 CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
974
975 ASSERT_CONST(IOCTL_SCSI_PASS_THROUGH, 0x04d004);
976
977 #define SCSI_IOCTL_DATA_OUT 0
978 #define SCSI_IOCTL_DATA_IN 1
979 #define SCSI_IOCTL_DATA_UNSPECIFIED 2
980 // undocumented SCSI opcode to for ATA passthrough
981 #define SCSIOP_ATA_PASSTHROUGH 0xCC
982
983 typedef struct _SCSI_PASS_THROUGH {
984 USHORT Length;
985 UCHAR ScsiStatus;
986 UCHAR PathId;
987 UCHAR TargetId;
988 UCHAR Lun;
989 UCHAR CdbLength;
990 UCHAR SenseInfoLength;
991 UCHAR DataIn;
992 ULONG DataTransferLength;
993 ULONG TimeOutValue;
994 ULONG/*_PTR*/ DataBufferOffset;
995 ULONG SenseInfoOffset;
996 UCHAR Cdb[16];
997 } SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;
998
999 ASSERT_SIZEOF(SCSI_PASS_THROUGH, 44);
1000
1001
1002 /////////////////////////////////////////////////////////////////////////////
1003
1004 static int ata_via_scsi_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize)
1005 {
1006 typedef struct {
1007 SCSI_PASS_THROUGH spt;
1008 ULONG Filler;
1009 UCHAR ucSenseBuf[32];
1010 UCHAR ucDataBuf[512];
1011 } SCSI_PASS_THROUGH_WITH_BUFFERS;
1012
1013 SCSI_PASS_THROUGH_WITH_BUFFERS sb;
1014 IDEREGS * cdbregs;
1015 unsigned int size;
1016 DWORD num_out;
1017 const unsigned char magic = 0xcf;
1018
1019 memset(&sb, 0, sizeof(sb));
1020 sb.spt.Length = sizeof(SCSI_PASS_THROUGH);
1021 //sb.spt.PathId = 0;
1022 sb.spt.TargetId = 1;
1023 //sb.spt.Lun = 0;
1024 sb.spt.CdbLength = 10; sb.spt.SenseInfoLength = 24;
1025 sb.spt.TimeOutValue = 10;
1026 sb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf);
1027 size = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf);
1028 sb.spt.DataBufferOffset = size;
1029
1030 if (datasize) {
1031 if (datasize > sizeof(sb.ucDataBuf)) {
1032 errno = EINVAL;
1033 return -1;
1034 }
1035 sb.spt.DataIn = SCSI_IOCTL_DATA_IN;
1036 sb.spt.DataTransferLength = datasize;
1037 size += datasize;
1038 sb.ucDataBuf[0] = magic;
1039 }
1040 else {
1041 sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
1042 //sb.spt.DataTransferLength = 0;
1043 }
1044
1045 // Use pseudo SCSI command followed by registers
1046 sb.spt.Cdb[0] = SCSIOP_ATA_PASSTHROUGH;
1047 cdbregs = (IDEREGS *)(sb.spt.Cdb+2);
1048 *cdbregs = *regs;
1049
1050 if (!DeviceIoControl(hdevice, IOCTL_SCSI_PASS_THROUGH,
1051 &sb, size, &sb, size, &num_out, NULL)) {
1052 long err = GetLastError();
1053 if (con->reportataioctl)
1054 pout(" ATA via IOCTL_SCSI_PASS_THROUGH failed, Error=%ld\n", err);
1055 errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
1056 return -1;
1057 }
1058
1059 // Cannot check ATA status, because command does not return IDEREGS
1060
1061 // Check and copy data
1062 if (datasize) {
1063 if ( num_out != size
1064 || (sb.ucDataBuf[0] == magic && !nonempty(sb.ucDataBuf+1, datasize-1))) {
1065 if (con->reportataioctl) {
1066 pout(" ATA via IOCTL_SCSI_PASS_THROUGH output data missing (%lu)\n", num_out);
1067 print_ide_regs_io(regs, NULL);
1068 }
1069 errno = EIO;
1070 return -1;
1071 }
1072 memcpy(data, sb.ucDataBuf, datasize);
1073 }
1074
1075 if (con->reportataioctl > 1) {
1076 pout(" ATA via IOCTL_SCSI_PASS_THROUGH suceeded, bytes returned: %lu\n", num_out);
1077 print_ide_regs_io(regs, NULL);
1078 }
1079 return 0;
1080 }
1081
1082
1083 /////////////////////////////////////////////////////////////////////////////
1084
1085 // SMART IOCTL via SCSI MINIPORT ioctl
1086
1087 // This function is handled by ATAPI port driver (atapi.sys) or by SCSI
1088 // miniport driver (via SCSI port driver scsiport.sys).
1089 // It can be used to skip the missing or broken handling of some SMART
1090 // command codes (e.g. READ_LOG) in the disk class driver (disk.sys)
1091
1092 #define IOCTL_SCSI_MINIPORT \
1093 CTL_CODE(IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
1094
1095 ASSERT_CONST(IOCTL_SCSI_MINIPORT, 0x04d008);
1096
1097 typedef struct _SRB_IO_CONTROL {
1098 ULONG HeaderLength;
1099 UCHAR Signature[8];
1100 ULONG Timeout;
1101 ULONG ControlCode;
1102 ULONG ReturnCode;
1103 ULONG Length;
1104 } SRB_IO_CONTROL, *PSRB_IO_CONTROL;
1105
1106 ASSERT_SIZEOF(SRB_IO_CONTROL, 28);
1107
1108 #define FILE_DEVICE_SCSI 0x001b
1109
1110 #define IOCTL_SCSI_MINIPORT_SMART_VERSION ((FILE_DEVICE_SCSI << 16) + 0x0500)
1111 #define IOCTL_SCSI_MINIPORT_IDENTIFY ((FILE_DEVICE_SCSI << 16) + 0x0501)
1112 #define IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS ((FILE_DEVICE_SCSI << 16) + 0x0502)
1113 #define IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS ((FILE_DEVICE_SCSI << 16) + 0x0503)
1114 #define IOCTL_SCSI_MINIPORT_ENABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0504)
1115 #define IOCTL_SCSI_MINIPORT_DISABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0505)
1116 #define IOCTL_SCSI_MINIPORT_RETURN_STATUS ((FILE_DEVICE_SCSI << 16) + 0x0506)
1117 #define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE ((FILE_DEVICE_SCSI << 16) + 0x0507)
1118 #define IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES ((FILE_DEVICE_SCSI << 16) + 0x0508)
1119 #define IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS ((FILE_DEVICE_SCSI << 16) + 0x0509)
1120 #define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE ((FILE_DEVICE_SCSI << 16) + 0x050a)
1121 #define IOCTL_SCSI_MINIPORT_READ_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050b)
1122 #define IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050c)
1123
1124 /////////////////////////////////////////////////////////////////////////////
1125
1126 static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, int datasize)
1127 {
1128 // Select code
1129 DWORD code = 0; const char * name = 0;
1130 if (regs->bCommandReg == ATA_IDENTIFY_DEVICE) {
1131 code = IOCTL_SCSI_MINIPORT_IDENTIFY; name = "IDENTIFY";
1132 }
1133 else if (regs->bCommandReg == ATA_SMART_CMD) switch (regs->bFeaturesReg) {
1134 case ATA_SMART_READ_VALUES:
1135 code = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS; name = "READ_SMART_ATTRIBS"; break;
1136 case ATA_SMART_READ_THRESHOLDS:
1137 code = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS; name = "READ_SMART_THRESHOLDS"; break;
1138 case ATA_SMART_ENABLE:
1139 code = IOCTL_SCSI_MINIPORT_ENABLE_SMART; name = "ENABLE_SMART"; break;
1140 case ATA_SMART_DISABLE:
1141 code = IOCTL_SCSI_MINIPORT_DISABLE_SMART; name = "DISABLE_SMART"; break;
1142 case ATA_SMART_STATUS:
1143 code = IOCTL_SCSI_MINIPORT_RETURN_STATUS; name = "RETURN_STATUS"; break;
1144 case ATA_SMART_AUTOSAVE:
1145 code = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE; name = "ENABLE_DISABLE_AUTOSAVE"; break;
1146 //case ATA_SMART_SAVE: // obsolete since ATA-6, not used by smartmontools
1147 // code = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES; name = "SAVE_ATTRIBUTE_VALUES"; break;
1148 case ATA_SMART_IMMEDIATE_OFFLINE:
1149 code = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS; name = "EXECUTE_OFFLINE_DIAGS"; break;
1150 case ATA_SMART_AUTO_OFFLINE:
1151 code = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE; name = "ENABLE_DISABLE_AUTO_OFFLINE"; break;
1152 case ATA_SMART_READ_LOG_SECTOR:
1153 code = IOCTL_SCSI_MINIPORT_READ_SMART_LOG; name = "READ_SMART_LOG"; break;
1154 case ATA_SMART_WRITE_LOG_SECTOR:
1155 code = IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG; name = "WRITE_SMART_LOG"; break;
1156 }
1157 if (!code) {
1158 errno = ENOSYS;
1159 return -1;
1160 }
1161
1162 // Set SRB
1163 struct {
1164 SRB_IO_CONTROL srbc;
1165 union {
1166 SENDCMDINPARAMS in;
1167 SENDCMDOUTPARAMS out;
1168 } params;
1169 char space[512-1];
1170 } sb;
1171 ASSERT_SIZEOF(sb, sizeof(SRB_IO_CONTROL)+sizeof(SENDCMDINPARAMS)-1+512);
1172 memset(&sb, 0, sizeof(sb));
1173
1174 unsigned size;
1175 if (datasize > 0) {
1176 if (datasize > (int)sizeof(sb.space)+1) {
1177 errno = EINVAL;
1178 return -1;
1179 }
1180 size = datasize;
1181 }
1182 else if (datasize < 0) {
1183 if (-datasize > (int)sizeof(sb.space)+1) {
1184 errno = EINVAL;
1185 return -1;
1186 }
1187 size = -datasize;
1188 memcpy(sb.params.in.bBuffer, data, size);
1189 }
1190 else if (code == IOCTL_SCSI_MINIPORT_RETURN_STATUS)
1191 size = sizeof(IDEREGS);
1192 else
1193 size = 0;
1194 sb.srbc.HeaderLength = sizeof(SRB_IO_CONTROL);
1195 memcpy(sb.srbc.Signature, "SCSIDISK", 8); // atapi.sys
1196 sb.srbc.Timeout = 60; // seconds
1197 sb.srbc.ControlCode = code;
1198 //sb.srbc.ReturnCode = 0;
1199 sb.srbc.Length = sizeof(SENDCMDINPARAMS)-1 + size;
1200 sb.params.in.irDriveRegs = *regs;
1201 sb.params.in.cBufferSize = size;
1202
1203 // Call miniport ioctl
1204 size += sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)-1;
1205 DWORD num_out;
1206 if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
1207 &sb, size, &sb, size, &num_out, NULL)) {
1208 long err = GetLastError();
1209 if (con->reportataioctl) {
1210 pout(" IOCTL_SCSI_MINIPORT_%s failed, Error=%ld\n", name, err);
1211 print_ide_regs_io(regs, NULL);
1212 }
1213 errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
1214 return -1;
1215 }
1216
1217 // Check result
1218 if (sb.srbc.ReturnCode) {
1219 if (con->reportataioctl) {
1220 pout(" IOCTL_SCSI_MINIPORT_%s failed, ReturnCode=0x%08lx\n", name, sb.srbc.ReturnCode);
1221 print_ide_regs_io(regs, NULL);
1222 }
1223 errno = EIO;
1224 return -1;
1225 }
1226
1227 if (sb.params.out.DriverStatus.bDriverError) {
1228 if (con->reportataioctl) {
1229 pout(" IOCTL_SCSI_MINIPORT_%s failed, DriverError=0x%02x, IDEError=0x%02x\n", name,
1230 sb.params.out.DriverStatus.bDriverError, sb.params.out.DriverStatus.bIDEError);
1231 print_ide_regs_io(regs, NULL);
1232 }
1233 errno = (!sb.params.out.DriverStatus.bIDEError ? ENOSYS : EIO);
1234 return -1;
1235 }
1236
1237 if (con->reportataioctl > 1) {
1238 pout(" IOCTL_SCSI_MINIPORT_%s suceeded, bytes returned: %lu (buffer %lu)\n", name,
1239 num_out, sb.params.out.cBufferSize);
1240 print_ide_regs_io(regs, (code == IOCTL_SCSI_MINIPORT_RETURN_STATUS ?
1241 (const IDEREGS *)(sb.params.out.bBuffer) : 0));
1242 }
1243
1244 if (datasize > 0)
1245 memcpy(data, sb.params.out.bBuffer, datasize);
1246 else if (datasize == 0 && code == IOCTL_SCSI_MINIPORT_RETURN_STATUS)
1247 *regs = *(const IDEREGS *)(sb.params.out.bBuffer);
1248
1249 return 0;
1250 }
1251
1252
1253 /////////////////////////////////////////////////////////////////////////////
1254
1255 // ATA PASS THROUGH via 3ware specific SCSI MINIPORT ioctl
1256
1257 static int ata_via_3ware_miniport_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, int datasize, int port)
1258 {
1259 struct {
1260 SRB_IO_CONTROL srbc;
1261 IDEREGS regs;
1262 UCHAR buffer[512];
1263 } sb;
1264 ASSERT_SIZEOF(sb, sizeof(SRB_IO_CONTROL)+sizeof(IDEREGS)+512);
1265
1266 if (!(0 <= datasize && datasize <= (int)sizeof(sb.buffer) && port >= 0)) {
1267 errno = EINVAL;
1268 return -1;
1269 }
1270 memset(&sb, 0, sizeof(sb));
1271 strcpy((char *)sb.srbc.Signature, "<3ware>");
1272 sb.srbc.HeaderLength = sizeof(SRB_IO_CONTROL);
1273 sb.srbc.Timeout = 60; // seconds
1274 sb.srbc.ControlCode = 0xA0000000;
1275 sb.srbc.ReturnCode = 0;
1276 sb.srbc.Length = sizeof(IDEREGS) + (datasize > 0 ? datasize : 1);
1277 sb.regs = *regs;
1278 sb.regs.bReserved = port;
1279
1280 DWORD num_out;
1281 if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
1282 &sb, sizeof(sb), &sb, sizeof(sb), &num_out, NULL)) {
1283 long err = GetLastError();
1284 if (con->reportataioctl) {
1285 pout(" ATA via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err);
1286 print_ide_regs_io(regs, NULL);
1287 }
1288 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
1289 return -1;
1290 }
1291
1292 if (sb.srbc.ReturnCode) {
1293 if (con->reportataioctl) {
1294 pout(" ATA via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08lx\n", sb.srbc.ReturnCode);
1295 print_ide_regs_io(regs, NULL);
1296 }
1297 errno = EIO;
1298 return -1;
1299 }
1300
1301 // Copy data
1302 if (datasize > 0)
1303 memcpy(data, sb.buffer, datasize);
1304
1305 if (con->reportataioctl > 1) {
1306 pout(" ATA via IOCTL_SCSI_MINIPORT suceeded, bytes returned: %lu\n", num_out);
1307 print_ide_regs_io(regs, &sb.regs);
1308 }
1309 *regs = sb.regs;
1310
1311 return 0;
1312 }
1313
1314
1315 /////////////////////////////////////////////////////////////////////////////
1316
1317 // 3ware specific call to update the devicemap returned by SMART_GET_VERSION.
1318 // 3DM/CLI "Rescan Controller" function does not to always update it.
1319
1320 static int update_3ware_devicemap_ioctl(HANDLE hdevice)
1321 {
1322 SRB_IO_CONTROL srbc;
1323 memset(&srbc, 0, sizeof(srbc));
1324 strcpy((char *)srbc.Signature, "<3ware>");
1325 srbc.HeaderLength = sizeof(SRB_IO_CONTROL);
1326 srbc.Timeout = 60; // seconds
1327 srbc.ControlCode = 0xCC010014;
1328 srbc.ReturnCode = 0;
1329 srbc.Length = 0;
1330
1331 DWORD num_out;
1332 if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
1333 &srbc, sizeof(srbc), &srbc, sizeof(srbc), &num_out, NULL)) {
1334 long err = GetLastError();
1335 if (con->reportataioctl)
1336 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err);
1337 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
1338 return -1;
1339 }
1340 if (srbc.ReturnCode) {
1341 if (con->reportataioctl)
1342 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08lx\n", srbc.ReturnCode);
1343 errno = EIO;
1344 return -1;
1345 }
1346 if (con->reportataioctl > 1)
1347 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT suceeded\n");
1348 return 0;
1349 }
1350
1351
1352
1353 /////////////////////////////////////////////////////////////////////////////
1354
1355 // Routines for pseudo device /dev/tw_cli/*
1356 // Parses output of 3ware "tw_cli /cx/py show all" or 3DM SMART data window
1357
1358
1359 // Get clipboard data
1360
1361 static int get_clipboard(char * data, int datasize)
1362 {
1363 if (!OpenClipboard(NULL))
1364 return -1;
1365 HANDLE h = GetClipboardData(CF_TEXT);
1366 if (!h) {
1367 CloseClipboard();
1368 return 0;
1369 }
1370 const void * p = GlobalLock(h);
1371 int n = GlobalSize(h);
1372 if (n > datasize)
1373 n = datasize;
1374 memcpy(data, p, n);
1375 GlobalFree(h);
1376 CloseClipboard();
1377 return n;
1378 }
1379
1380
1381 // Run a command, write stdout to dataout
1382 // TODO: Combine with daemon_win32.cpp:daemon_spawn()
1383
1384 static int run_cmd(const char * cmd, char * dataout, int outsize)
1385 {
1386 // Create stdout pipe
1387 SECURITY_ATTRIBUTES sa = {sizeof(sa), 0, TRUE};
1388 HANDLE pipe_out_w, h;
1389 if (!CreatePipe(&h, &pipe_out_w, &sa/*inherit*/, outsize))
1390 return -1;
1391 HANDLE self = GetCurrentProcess();
1392 HANDLE pipe_out_r;
1393 if (!DuplicateHandle(self, h, self, &pipe_out_r,
1394 GENERIC_READ, FALSE/*!inherit*/, DUPLICATE_CLOSE_SOURCE)) {
1395 CloseHandle(pipe_out_w);
1396 return -1;
1397 }
1398 HANDLE pipe_err_w;
1399 if (!DuplicateHandle(self, pipe_out_w, self, &pipe_err_w,
1400 0, TRUE/*inherit*/, DUPLICATE_SAME_ACCESS)) {
1401 CloseHandle(pipe_out_r); CloseHandle(pipe_out_w);
1402 return -1;
1403 }
1404
1405 // Create process
1406 STARTUPINFO si; memset(&si, 0, sizeof(si)); si.cb = sizeof(si);
1407 si.hStdInput = INVALID_HANDLE_VALUE;
1408 si.hStdOutput = pipe_out_w; si.hStdError = pipe_err_w;
1409 si.dwFlags = STARTF_USESTDHANDLES;
1410 PROCESS_INFORMATION pi;
1411 if (!CreateProcess(
1412 NULL, const_cast<char *>(cmd),
1413 NULL, NULL, TRUE/*inherit*/,
1414 CREATE_NO_WINDOW/*do not create a new console window*/,
1415 NULL, NULL, &si, &pi)) {
1416 CloseHandle(pipe_err_w); CloseHandle(pipe_out_r); CloseHandle(pipe_out_w);
1417 return -1;
1418 }
1419 CloseHandle(pi.hThread);
1420 CloseHandle(pipe_err_w); CloseHandle(pipe_out_w);
1421
1422 // Copy stdout to output buffer
1423 int i = 0;
1424 while (i < outsize) {
1425 DWORD num_read;
1426 if (!ReadFile(pipe_out_r, dataout+i, outsize-i, &num_read, NULL) || num_read == 0)
1427 break;
1428 i += num_read;
1429 }
1430 CloseHandle(pipe_out_r);
1431 // Wait for process
1432 WaitForSingleObject(pi.hProcess, INFINITE);
1433 CloseHandle(pi.hProcess);
1434 return i;
1435 }
1436
1437
1438 static const char * findstr(const char * str, const char * sub)
1439 {
1440 const char * s = strstr(str, sub);
1441 return (s ? s+strlen(sub) : "");
1442 }
1443
1444
1445 static void copy_swapped(unsigned char * dest, const char * src, int destsize)
1446 {
1447 int srclen = strcspn(src, "\r\n");
1448 int i;
1449 for (i = 0; i < destsize-1 && i < srclen-1; i+=2) {
1450 dest[i] = src[i+1]; dest[i+1] = src[i];
1451 }
1452 if (i < destsize-1 && i < srclen)
1453 dest[i+1] = src[i];
1454 }
1455
1456
1457 static ata_identify_device * tw_cli_identbuf = 0;
1458 static ata_smart_values * tw_cli_smartbuf = 0;
1459
1460 static int tw_cli_open(const char * name)
1461 {
1462 // Read tw_cli or 3DM browser output into buffer
1463 char buffer[4096];
1464 int size = -1, n1 = -1;
1465 if (!strcmp(name, "clip")) { // tw_cli/clip => read clipboard
1466 size = get_clipboard(buffer, sizeof(buffer));
1467 }
1468 else if (!strcmp(name, "stdin")) { // tw_cli/stdin => read stdin
1469 size = fread(buffer, 1, sizeof(buffer), stdin);
1470 }
1471 else if (sscanf(name, "c%*u/p%*u%n", &n1) >= 0 && n1 == (int)strlen(name)) {
1472 // tw_cli/cx/py => read output from "tw_cli /cx/py show all"
1473 char cmd[100];
1474 snprintf(cmd, sizeof(cmd), "tw_cli /%s show all", name);
1475 if (con->reportataioctl > 1)
1476 pout("tw_cli/%s: Run: \"%s\"\n", name, cmd);
1477 size = run_cmd(cmd, buffer, sizeof(buffer));
1478 }
1479 else {
1480 errno = EINVAL; return -1;
1481 }
1482
1483 if (con->reportataioctl > 1)
1484 pout("tw_cli/%s: Read %d bytes\n", name, size);
1485 if (size <= 0) {
1486 errno = ENOENT; return -1;
1487 }
1488 if (size >= (int)sizeof(buffer)) {
1489 errno = EIO; return -1;
1490 }
1491 buffer[size] = 0;
1492 if (con->reportataioctl > 1)
1493 pout("[\n%.100s%s\n]\n", buffer, (size>100?"...":""));
1494
1495 // Fake identify sector
1496 ASSERT_SIZEOF(ata_identify_device, 512);
1497 ata_identify_device * id = (ata_identify_device *)malloc(sizeof(ata_identify_device));
1498 memset(id, 0, sizeof(*id));
1499 copy_swapped(id->model , findstr(buffer, " Model = " ), sizeof(id->model));
1500 copy_swapped(id->fw_rev , findstr(buffer, " Firmware Version = "), sizeof(id->fw_rev));
1501 copy_swapped(id->serial_no, findstr(buffer, " Serial = " ), sizeof(id->serial_no));
1502 unsigned long nblocks = 0; // "Capacity = N.N GB (N Blocks)"
1503 sscanf(findstr(buffer, "Capacity = "), "%*[^(\r\n](%lu", &nblocks);
1504 if (nblocks) {
1505 id->words047_079[49-47] = 0x0200; // size valid
1506 id->words047_079[60-47] = (unsigned short)(nblocks ); // secs_16
1507 id->words047_079[61-47] = (unsigned short)(nblocks>>16); // secs_32
1508 }
1509 id->major_rev_num = 0x1<<3; // ATA-3
1510 id->command_set_1 = 0x0001; id->command_set_2 = 0x4000; // SMART supported, words 82,83 valid
1511 id->cfs_enable_1 = 0x0001; id->csf_default = 0x4000; // SMART enabled, words 85,87 valid
1512
1513 // Parse smart data hex dump
1514 const char * s = findstr(buffer, "Drive Smart Data:");
1515 if (!*s) {
1516 s = findstr(buffer, "S.M.A.R.T. (Controller"); // from 3DM browser window
1517 if (*s) {
1518 const char * s1 = findstr(s, "<td class"); // html version
1519 if (*s1)
1520 s = s1;
1521 s += strcspn(s, "\r\n");
1522 }
1523 else
1524 s = buffer; // try raw hex dump without header
1525 }
1526 unsigned char * sd = (unsigned char *)malloc(512);
1527 int i = 0;
1528 for (;;) {
1529 unsigned x = ~0; int n = -1;
1530 if (!(sscanf(s, "%x %n", &x, &n) == 1 && !(x & ~0xff)))
1531 break;
1532 sd[i] = (unsigned char)x;
1533 if (!(++i < 512 && n > 0))
1534 break;
1535 s += n;
1536 if (*s == '<') // "<br>"
1537 s += strcspn(s, "\r\n");
1538 }
1539 if (i < 512) {
1540 free(sd);
1541 if (!id->model[1]) {
1542 // No useful data found
1543 free(id);
1544 char * err = strstr(buffer, "Error:");
1545 if (!err)
1546 err = strstr(buffer, "error :");
1547 if (err) {
1548 // Print tw_cli error message
1549 err[strcspn(err, "\r\n")] = 0;
1550 pout("%s\n", err);
1551 }
1552 errno = EIO;
1553 return -1;
1554 }
1555 sd = 0;
1556 }
1557
1558 tw_cli_identbuf = id;
1559 tw_cli_smartbuf = (ata_smart_values *)sd;
1560 return TW_CLI_FDOFFSET;
1561 }
1562
1563
1564 static void tw_cli_close()
1565 {
1566 if (tw_cli_identbuf) {
1567 free(tw_cli_identbuf); tw_cli_identbuf = 0;
1568 }
1569 if (tw_cli_smartbuf) {
1570 free(tw_cli_smartbuf); tw_cli_smartbuf = 0;
1571 }
1572 }
1573
1574
1575 static int tw_cli_command_interface(smart_command_set command, int /*select*/, char * data)
1576 {
1577 switch (command) {
1578 case IDENTIFY:
1579 if (!tw_cli_identbuf)
1580 break;
1581 memcpy(data, tw_cli_identbuf, 512);
1582 return 0;
1583 case READ_VALUES:
1584 if (!tw_cli_smartbuf)
1585 break;
1586 memcpy(data, tw_cli_smartbuf, 512);
1587 return 0;
1588 case READ_THRESHOLDS:
1589 if (!tw_cli_smartbuf)
1590 break;
1591 // Fake zero thresholds
1592 {
1593 const ata_smart_values * sv = tw_cli_smartbuf;
1594 ata_smart_thresholds_pvt * tr = (ata_smart_thresholds_pvt *)data;
1595 memset(tr, 0, 512);
1596 // TODO: Indicate missing thresholds in ataprint.cpp:PrintSmartAttribWithThres()
1597 // (ATA_SMART_READ_THRESHOLDS is marked obsolete since ATA-5)
1598 for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++)
1599 tr->chksum -= tr->thres_entries[i].id = sv->vendor_attributes[i].id;
1600 }
1601 return 0;
1602 case ENABLE:
1603 case STATUS:
1604 case STATUS_CHECK: // Fake "good" SMART status
1605 return 0;
1606 default:
1607 break;
1608 }
1609 // Arrive here for all unsupported commands
1610 errno = ENOSYS;
1611 return -1;
1612 }
1613
1614
1615 /////////////////////////////////////////////////////////////////////////////
1616
1617 // IOCTL_STORAGE_QUERY_PROPERTY
1618
1619 #define FILE_DEVICE_MASS_STORAGE 0x0000002d
1620 #define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE
1621 #define FILE_ANY_ACCESS 0
1622
1623 #define IOCTL_STORAGE_QUERY_PROPERTY \
1624 CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)
1625
1626 typedef enum _STORAGE_BUS_TYPE {
1627 BusTypeUnknown = 0x00,
1628 BusTypeScsi = 0x01,
1629 BusTypeAtapi = 0x02,
1630 BusTypeAta = 0x03,
1631 BusType1394 = 0x04,
1632 BusTypeSsa = 0x05,
1633 BusTypeFibre = 0x06,
1634 BusTypeUsb = 0x07,
1635 BusTypeRAID = 0x08,
1636 BusTypeiScsi = 0x09,
1637 BusTypeSas = 0x0A,
1638 BusTypeSata = 0x0B,
1639 BusTypeSd = 0x0C,
1640 BusTypeMmc = 0x0D,
1641 BusTypeMax = 0x0E,
1642 BusTypeMaxReserved = 0x7F
1643 } STORAGE_BUS_TYPE, *PSTORAGE_BUS_TYPE;
1644
1645 typedef struct _STORAGE_DEVICE_DESCRIPTOR {
1646 ULONG Version;
1647 ULONG Size;
1648 UCHAR DeviceType;
1649 UCHAR DeviceTypeModifier;
1650 BOOLEAN RemovableMedia;
1651 BOOLEAN CommandQueueing;
1652 ULONG VendorIdOffset;
1653 ULONG ProductIdOffset;
1654 ULONG ProductRevisionOffset;
1655 ULONG SerialNumberOffset;
1656 STORAGE_BUS_TYPE BusType;
1657 ULONG RawPropertiesLength;
1658 UCHAR RawDeviceProperties[1];
1659 } STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR;
1660
1661 typedef enum _STORAGE_QUERY_TYPE {
1662 PropertyStandardQuery = 0,
1663 PropertyExistsQuery,
1664 PropertyMaskQuery,
1665 PropertyQueryMaxDefined
1666 } STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE;
1667
1668 typedef enum _STORAGE_PROPERTY_ID {
1669 StorageDeviceProperty = 0,
1670 StorageAdapterProperty,
1671 StorageDeviceIdProperty,
1672 StorageDeviceUniqueIdProperty,
1673 StorageDeviceWriteCacheProperty,
1674 StorageMiniportProperty,
1675 StorageAccessAlignmentProperty
1676 } STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID;
1677
1678 typedef struct _STORAGE_PROPERTY_QUERY {
1679 STORAGE_PROPERTY_ID PropertyId;
1680 STORAGE_QUERY_TYPE QueryType;
1681 UCHAR AdditionalParameters[1];
1682 } STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY;
1683
1684
1685 /////////////////////////////////////////////////////////////////////////////
1686
1687 // Return STORAGE_BUS_TYPE for device, BusTypeUnknown on error.
1688 // (HANDLE does not need any access rights, therefore this works
1689 // without admin rights)
1690
1691 static STORAGE_BUS_TYPE ioctl_get_storage_bus_type(HANDLE hdevice)
1692 {
1693 STORAGE_PROPERTY_QUERY query = {StorageDeviceProperty, PropertyStandardQuery, 0};
1694
1695 union {
1696 STORAGE_DEVICE_DESCRIPTOR dev;
1697 char raw[256];
1698 } prop;
1699 memset(&prop, 0, sizeof(prop));
1700
1701 DWORD num_out;
1702 if (!DeviceIoControl(hdevice, IOCTL_STORAGE_QUERY_PROPERTY,
1703 &query, sizeof(query), &prop, sizeof(prop), &num_out, NULL)) {
1704 if (con->reportataioctl > 1 || con->reportscsiioctl > 1)
1705 pout(" IOCTL_STORAGE_QUERY_PROPERTY failed, Error=%ld\n", GetLastError());
1706 return BusTypeUnknown;
1707 }
1708
1709 if (con->reportataioctl > 1 || con->reportscsiioctl > 1) {
1710 pout(" IOCTL_STORAGE_QUERY_PROPERTY returns:\n"
1711 " Vendor: \"%s\"\n"
1712 " Product: \"%s\"\n"
1713 " Revision: \"%s\"\n"
1714 " Removable: %s\n"
1715 " BusType: 0x%02x\n",
1716 (prop.dev.VendorIdOffset ? prop.raw+prop.dev.VendorIdOffset : ""),
1717 (prop.dev.ProductIdOffset ? prop.raw+prop.dev.ProductIdOffset : ""),
1718 (prop.dev.ProductRevisionOffset ? prop.raw+prop.dev.ProductRevisionOffset : ""),
1719 (prop.dev.RemovableMedia? "Yes":"No"), prop.dev.BusType
1720 );
1721 }
1722 return prop.dev.BusType;
1723 }
1724
1725
1726 /////////////////////////////////////////////////////////////////////////////
1727
1728 // get CONTROLLER_* for open handle
1729 static int get_controller_type(HANDLE hdevice, GETVERSIONINPARAMS_EX * ata_version_ex = 0)
1730 {
1731 // Try SMART_GET_VERSION first to detect ATA SMART support
1732 // for drivers reporting BusTypeScsi (3ware)
1733 if (smart_get_version(hdevice, ata_version_ex) >= 0)
1734 return CONTROLLER_ATA;
1735
1736 STORAGE_BUS_TYPE type = ioctl_get_storage_bus_type(hdevice);
1737 switch (type) {
1738 case BusTypeAta:
1739 case BusTypeSata:
1740 if (ata_version_ex)
1741 memset(ata_version_ex, 0, sizeof(*ata_version_ex));
1742 return CONTROLLER_ATA;
1743 case BusTypeScsi:
1744 case BusTypeiScsi:
1745 case BusTypeSas:
1746 return CONTROLLER_SCSI;
1747 default:
1748 return CONTROLLER_UNKNOWN;
1749 }
1750 /*NOTREACHED*/
1751 }
1752
1753 // get CONTROLLER_* for device path
1754 static int get_controller_type(const char * path, GETVERSIONINPARAMS_EX * ata_version_ex = 0)
1755 {
1756 HANDLE h = CreateFileA(path, GENERIC_READ|GENERIC_WRITE,
1757 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
1758 if (h == INVALID_HANDLE_VALUE)
1759 return CONTROLLER_UNKNOWN;
1760 if (con->reportataioctl > 1 || con->reportscsiioctl > 1)
1761 pout(" %s: successfully opened\n", path);
1762 int type = get_controller_type(h, ata_version_ex);
1763 CloseHandle(h);
1764 return type;
1765 }
1766
1767 // get CONTROLLER_* for physical drive number
1768 static int get_phy_drive_type(int drive, GETVERSIONINPARAMS_EX * ata_version_ex)
1769 {
1770 char path[30];
1771 snprintf(path, sizeof(path)-1, "\\\\.\\PhysicalDrive%d", drive);
1772 return get_controller_type(path, ata_version_ex);
1773 }
1774
1775 static int get_phy_drive_type(int drive)
1776 {
1777 return get_phy_drive_type(drive, 0);
1778 }
1779
1780 // get CONTROLLER_* for logical drive number
1781 static int get_log_drive_type(int drive)
1782 {
1783 char path[30];
1784 snprintf(path, sizeof(path)-1, "\\\\.\\%c:", 'A'+drive);
1785 return get_controller_type(path);
1786 }
1787
1788
1789 /////////////////////////////////////////////////////////////////////////////
1790
1791 // Call GetDevicePowerState() if available (Win98/ME/2000/XP/2003)
1792 // returns: 1=active, 0=standby, -1=error
1793 // (This would also work for SCSI drives)
1794
1795 static int get_device_power_state(HANDLE hdevice)
1796 {
1797 static HINSTANCE h_kernel_dll = 0;
1798 #ifdef __CYGWIN__
1799 static DWORD kernel_dll_pid = 0;
1800 #endif
1801 static BOOL (WINAPI * GetDevicePowerState_p)(HANDLE, BOOL *) = 0;
1802
1803 BOOL state = TRUE;
1804
1805 if (!GetDevicePowerState_p
1806 #ifdef __CYGWIN__
1807 || kernel_dll_pid != GetCurrentProcessId() // detect fork()
1808 #endif
1809 ) {
1810 if (h_kernel_dll == INVALID_HANDLE_VALUE) {
1811 errno = ENOSYS;
1812 return -1;
1813 }
1814 if (!(h_kernel_dll = LoadLibraryA("KERNEL32.DLL"))) {
1815 pout("Cannot load KERNEL32.DLL, Error=%ld\n", GetLastError());
1816 h_kernel_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
1817 errno = ENOSYS;
1818 return -1;
1819 }
1820 if (!(GetDevicePowerState_p = (BOOL (WINAPI *)(HANDLE, BOOL *))
1821 GetProcAddress(h_kernel_dll, "GetDevicePowerState"))) {
1822 if (con->reportataioctl)
1823 pout(" GetDevicePowerState() not found, Error=%ld\n", GetLastError());
1824 FreeLibrary(h_kernel_dll);
1825 h_kernel_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
1826 errno = ENOSYS;
1827 return -1;
1828 }
1829 #ifdef __CYGWIN__
1830 kernel_dll_pid = GetCurrentProcessId();
1831 #endif
1832 }
1833
1834 if (!GetDevicePowerState_p(hdevice, &state)) {
1835 long err = GetLastError();
1836 if (con->reportataioctl)
1837 pout(" GetDevicePowerState() failed, Error=%ld\n", err);
1838 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
1839 // TODO: This may not work as expected on transient errors,
1840 // because smartd interprets -1 as SLEEP mode regardless of errno.
1841 return -1;
1842 }
1843
1844 if (con->reportataioctl > 1)
1845 pout(" GetDevicePowerState() succeeded, state=%d\n", state);
1846 return state;
1847 }
1848
1849
1850 /////////////////////////////////////////////////////////////////////////////
1851
1852 // TODO: Put in a struct indexed by fd (or better a C++ object of course ;-)
1853 static HANDLE h_ata_ioctl = 0;
1854 static const char * ata_def_options;
1855 static char * ata_usr_options;
1856 const int max_ata_driveno = 25;
1857 static int ata_driveno; // Drive number
1858 static int ata_driveno_is_log = -1; // 0=physical drivenumber, 1=logical drive number, -1=unknown
1859 static char ata_smartver_state[max_ata_driveno+1]; // SMART_GET_VERSION: 0=unknown, 1=OK, 2=failed
1860
1861 // Print SMARTVSD error message, return errno
1862
1863 static int smartvsd_error()
1864 {
1865 char path[MAX_PATH];
1866 unsigned len;
1867 if (!(5 <= (len = GetSystemDirectoryA(path, MAX_PATH)) && len < MAX_PATH/2))
1868 return ENOENT;
1869 // SMARTVSD.VXD present?
1870 strcpy(path+len, "\\IOSUBSYS\\SMARTVSD.VXD");
1871 if (!access(path, 0)) {
1872 // Yes, standard IDE driver used?
1873 HANDLE h;
1874 if ( (h = CreateFileA("\\\\.\\ESDI_506",
1875 GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1876 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE
1877 && GetLastError() == ERROR_FILE_NOT_FOUND ) {
1878 pout("Standard IDE driver ESDI_506.PDR not used, or no IDE/ATA drives present.\n");
1879 return ENOENT;
1880 }
1881 else {
1882 if (h != INVALID_HANDLE_VALUE) // should not happen
1883 CloseHandle(h);
1884 pout("SMART driver SMARTVSD.VXD is installed, but not loaded.\n");
1885 return ENOSYS;
1886 }
1887 }
1888 else {
1889 strcpy(path+len, "\\SMARTVSD.VXD");
1890 if (!access(path, 0)) {
1891 // Some Windows versions install SMARTVSD.VXD in SYSTEM directory
1892 // (http://support.microsoft.com/kb/265854/en-us).
1893 path[len] = 0;
1894 pout("SMART driver is not properly installed,\n"
1895 " move SMARTVSD.VXD from \"%s\" to \"%s\\IOSUBSYS\"\n"
1896 " and reboot Windows.\n", path, path);
1897 }
1898 else {
1899 // Some Windows versions do not provide SMARTVSD.VXD
1900 // (http://support.microsoft.com/kb/199886/en-us).
1901 path[len] = 0;
1902 pout("SMARTVSD.VXD is missing in folder \"%s\\IOSUBSYS\".\n", path);
1903 }
1904 return ENOSYS;
1905 }
1906 }
1907
1908
1909 // Get default ATA device options
1910
1911 static const char * ata_get_def_options()
1912 {
1913 DWORD ver = GetVersion();
1914 if ((ver & 0x80000000) || (ver & 0xff) < 4) // Win9x/ME
1915 return "s"; // SMART_* only
1916 else if ((ver & 0xff) == 4) // WinNT4
1917 return "sc"; // SMART_*, SCSI_PASS_THROUGH
1918 else // WinXP, 2003, Vista
1919 return "psaim"; // GetDevicePowerState(), SMART_*, ATA_, IDE_PASS_THROUGH, SCSI_MINIPORT_*
1920 }
1921
1922
1923 // Open ATA device
1924
1925 static int ata_open(int phydrive, int logdrive, const char * options, int port)
1926 {
1927 // TODO: This version does not allow to open more than 1 ATA devices
1928 if (h_ata_ioctl) {
1929 errno = ENFILE;
1930 return -1;
1931 }
1932
1933 // Using both physical and logical drive names (in smartd.conf) not supported yet
1934 if (!( ata_driveno_is_log < 0
1935 || (phydrive >= 0 && !ata_driveno_is_log)
1936 || (logdrive >= 0 && ata_driveno_is_log))) {
1937 pout("Using both /dev/hdX and X: is not supported\n");
1938 errno = EINVAL;
1939 return -1;
1940 }
1941
1942 // path depends on Windows Version
1943 bool win9x = is_win9x();
1944 char devpath[30];
1945 if (win9x && 0 <= phydrive && phydrive <= 7)
1946 // Use patched "smartvse.vxd" for drives 4-7, see INSTALL file for details
1947 strcpy(devpath, (phydrive <= 3 ? "\\\\.\\SMARTVSD" : "\\\\.\\SMARTVSE"));
1948 else if (!win9x && 0 <= phydrive && phydrive <= max_ata_driveno)
1949 snprintf(devpath, sizeof(devpath)-1, "\\\\.\\PhysicalDrive%d", phydrive);
1950 else if (!win9x && 0 <= logdrive && logdrive <= max_ata_driveno) {
1951 snprintf(devpath, sizeof(devpath)-1, "\\\\.\\%c:", 'A'+logdrive);
1952 }
1953 else {
1954 errno = ENOENT;
1955 return -1;
1956 }
1957
1958 // Open device
1959 if ((h_ata_ioctl = CreateFileA(devpath,
1960 GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1961 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
1962 long err = GetLastError();
1963 pout("Cannot open device %s, Error=%ld\n", devpath, err);
1964 if (err == ERROR_FILE_NOT_FOUND)
1965 errno = (win9x && phydrive <= 3 ? smartvsd_error() : ENOENT);
1966 else if (err == ERROR_ACCESS_DENIED) {
1967 if (!win9x)
1968 pout("Administrator rights are necessary to access physical drives.\n");
1969 errno = EACCES;
1970 }
1971 else
1972 errno = EIO;
1973 h_ata_ioctl = 0;
1974 return -1;
1975 }
1976
1977 if (con->reportataioctl > 1)
1978 pout("%s: successfully opened\n", devpath);
1979
1980 // Set default options according to Windows version
1981 if (!ata_def_options)
1982 ata_def_options = ata_get_def_options();
1983 // Save user options
1984 if (port >= 0 && !*options)
1985 options = "s3"; // RAID: SMART_* and SCSI_MINIPORT
1986 assert(!ata_usr_options);
1987 if (*options)
1988 ata_usr_options = strdup(options);
1989
1990 // NT4/2000/XP: SMART_GET_VERSION may spin up disk, so delay until first real SMART_* call
1991 if (phydrive >= 0) {
1992 ata_driveno = phydrive; ata_driveno_is_log = 0;
1993 }
1994 else {
1995 assert(logdrive >= 0);
1996 ata_driveno = logdrive; ata_driveno_is_log = 1;
1997 }
1998 if (!win9x && port < 0)
1999 return 0;
2000
2001 // Win9X/ME: Get drive map
2002 // RAID: Get port map
2003 GETVERSIONINPARAMS_EX vers_ex;
2004 int devmap = smart_get_version(h_ata_ioctl, (port >= 0 ? &vers_ex : 0));
2005
2006 unsigned long portmap = 0;
2007 if (port >= 0 && devmap >= 0) {
2008 // 3ware RAID: check vendor id
2009 if (vers_ex.wIdentifier != SMART_VENDOR_3WARE) {
2010 pout("SMART_GET_VERSION returns unknown Identifier = %04x\n"
2011 "This is no 3ware 9000 controller or driver has no SMART support.\n",
2012 vers_ex.wIdentifier);
2013 devmap = -1;
2014 }
2015 else
2016 portmap = vers_ex.dwDeviceMapEx;
2017 }
2018 if (devmap < 0) {
2019 pout("%s: ATA driver has no SMART support\n", devpath);
2020 if (!is_permissive()) {
2021 ata_close(0);
2022 errno = ENOSYS;
2023 return -1;
2024 }
2025 devmap = 0x0f;
2026 }
2027 ata_smartver_state[ata_driveno] = 1;
2028
2029 if (port >= 0) {
2030 // 3ware RAID: update devicemap first
2031 if (!update_3ware_devicemap_ioctl(h_ata_ioctl)) {
2032 if ( smart_get_version(h_ata_ioctl, &vers_ex) >= 0
2033 && vers_ex.wIdentifier == SMART_VENDOR_3WARE )
2034 portmap = vers_ex.dwDeviceMapEx;
2035 }
2036 // Check port existence
2037 if (!(portmap & (1L << port))) {
2038 pout("%s: Port %d is empty or does not exist\n", devpath, port);
2039 if (!is_permissive()) {
2040 ata_close(0);
2041 errno = ENOENT;
2042 return -1;
2043 }
2044 }
2045 // Encode port into pseudo fd
2046 return (ATARAID_FDOFFSET | port);
2047 }
2048
2049 // Win9x/ME: Check device presence & type
2050 if (((devmap >> (ata_driveno & 0x3)) & 0x11) != 0x01) {
2051 unsigned char atapi = (devmap >> (ata_driveno & 0x3)) & 0x10;
2052 pout("%s: Drive %d %s (IDEDeviceMap=0x%02x).\n", devpath,
2053 ata_driveno, (atapi?"is an ATAPI device":"does not exist"), devmap);
2054 // Win9x drive existence check may not work as expected
2055 // The atapi.sys driver incorrectly fills in the bIDEDeviceMap with 0x01
2056 // (The related KB Article Q196120 is no longer available)
2057 if (!is_permissive()) {
2058 ata_close(0);
2059 errno = (atapi ? ENOSYS : ENOENT);
2060 return -1;
2061 }
2062 }
2063 // Use drive number as fd for ioctl
2064 return (ata_driveno & 0x3);
2065 }
2066
2067
2068 static void ata_close(int /*fd*/)
2069 {
2070 CloseHandle(h_ata_ioctl);
2071 h_ata_ioctl = 0;
2072 if (ata_usr_options) {
2073 free(ata_usr_options);
2074 ata_usr_options = 0;
2075 }
2076 }
2077
2078
2079 // Scan for ATA drives on Win9x/ME, fill bitmask of drives present, return #drives
2080
2081 static int ata_scan_win9x(unsigned long * drives)
2082 {
2083 // Open device
2084 const char devpath[] = "\\\\.\\SMARTVSD";
2085 HANDLE h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,
2086 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
2087 if (h == INVALID_HANDLE_VALUE) {
2088 if (con->reportataioctl > 1)
2089 pout(" %s: Open failed, Error=%ld\n", devpath, GetLastError());
2090 return 0; // SMARTVSD.VXD missing or no ATA devices
2091 }
2092
2093 // Get drive map
2094 int devmap = smart_get_version(h);
2095 CloseHandle(h);
2096 if (devmap < 0)
2097 return 0; // Should not happen
2098
2099 // Check ATA device presence, remove ATAPI devices
2100 drives[0] = (devmap & 0xf) & ~((devmap >> 4) & 0xf);
2101 return (drives[0]&1) + ((drives[0]>>1)&1) + ((drives[0]>>2)&1) + ((drives[0]>>3)&1);
2102 }
2103
2104
2105 // Scan for ATA drives, fill bitmask of drives present, return #drives
2106
2107 static int ata_scan(unsigned long * drives, int * rdriveno, unsigned long * rdrives)
2108 {
2109 int cnt = 0;
2110 for (int i = 0; i <= 9; i++) {
2111 GETVERSIONINPARAMS_EX vers_ex;
2112 if (get_phy_drive_type(i, &vers_ex) != CONTROLLER_ATA)
2113 continue;
2114
2115 // Interpret RAID drive map if present
2116 if (vers_ex.wIdentifier == SMART_VENDOR_3WARE) {
2117 // Skip if more than 2 controllers or logical drive from this controller already seen
2118 if (vers_ex.wControllerId >= 2 || rdriveno[vers_ex.wControllerId] >= 0)
2119 continue;
2120 assert(rdrives[vers_ex.wControllerId] == 0);
2121 // Count physical drives
2122 int pcnt = 0;
2123 for (int pi = 0; pi < 32; pi++) {
2124 if (vers_ex.dwDeviceMapEx & (1L << pi))
2125 pcnt++;
2126 }
2127 if (!pcnt)
2128 continue; // Should not happen
2129 rdrives[vers_ex.wControllerId] = vers_ex.dwDeviceMapEx;
2130 rdriveno[vers_ex.wControllerId] = i;
2131 cnt += pcnt-1;
2132 }
2133
2134 // Driver supports SMART_GET_VERSION or STORAGE_QUERY_PROPERTY returns ATA/SATA
2135 drives[0] |= (1L << i);
2136 cnt++;
2137 }
2138
2139 return cnt;
2140 }
2141
2142
2143 /////////////////////////////////////////////////////////////////////////////
2144
2145 // Interface to ATA devices. See os_linux.c
2146 int ata_command_interface(int fd, smart_command_set command, int select, char * data)
2147 {
2148 if (fd == TW_CLI_FDOFFSET) // Parse tw_cli output
2149 return tw_cli_command_interface(command, select, data);
2150
2151 int port = -1;
2152 if ((fd & ~0x1f) == ATARAID_FDOFFSET) {
2153 // RAID Port encoded into pseudo fd
2154 port = fd & 0x1f;
2155 fd = 0;
2156 }
2157
2158 if (!(0 <= fd && fd <= 3)) {
2159 errno = EBADF;
2160 return -1;
2161 }
2162
2163 // CMD,CYL default to SMART, changed by P?IDENTIFY and CHECK_POWER_MODE
2164 IDEREGS regs; memset(&regs, 0, sizeof(regs));
2165 regs.bCommandReg = ATA_SMART_CMD;
2166 regs.bCylHighReg = SMART_CYL_HI; regs.bCylLowReg = SMART_CYL_LOW;
2167 int datasize = 0;
2168
2169 // Try by default: SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH,
2170 // and SCSI_MINIPORT_* if requested by user
2171 const char * valid_options = (ata_usr_options ? "saicm" : "saic");
2172
2173 switch (command) {
2174 case CHECK_POWER_MODE:
2175 // Not a SMART command, needs IDE register return
2176 regs.bCommandReg = ATA_CHECK_POWER_MODE;
2177 regs.bCylLowReg = regs.bCylHighReg = 0;
2178 valid_options = "pai3"; // Try GetDevicePowerState() first, ATA/IDE_PASS_THROUGH may spin up disk
2179 // Note: returns SectorCountReg in data[0]
2180 break;
2181 case READ_VALUES:
2182 regs.bFeaturesReg = ATA_SMART_READ_VALUES;
2183 regs.bSectorNumberReg = regs.bSectorCountReg = 1;
2184 datasize = 512;
2185 break;
2186 case READ_THRESHOLDS:
2187 regs.bFeaturesReg = ATA_SMART_READ_THRESHOLDS;
2188 regs.bSectorNumberReg = regs.bSectorCountReg = 1;
2189 datasize = 512;
2190 break;
2191 case READ_LOG:
2192 regs.bFeaturesReg = ATA_SMART_READ_LOG_SECTOR;
2193 regs.bSectorNumberReg = select;
2194 regs.bSectorCountReg = 1;
2195 // SMART_RCV_DRIVE_DATA supports this only on Win9x/ME
2196 // Try SCSI_MINIPORT also to skip buggy class driver
2197 valid_options = (ata_usr_options || is_win9x() ? "saicm3" : "aicm3");
2198 datasize = 512;
2199 break;
2200 case WRITE_LOG:
2201 regs.bFeaturesReg = ATA_SMART_WRITE_LOG_SECTOR;
2202 regs.bSectorNumberReg = select;
2203 regs.bSectorCountReg = 1;
2204 // ATA_PASS_THROUGH, SCSI_MINIPORT, others don't support DATA_OUT
2205 // but SCSI_MINIPORT_* only if requested by user
2206 valid_options = (ata_usr_options ? "am" : "a");
2207 datasize = -512; // DATA_OUT!
2208 break;
2209 case IDENTIFY:
2210 // Note: WinNT4/2000/XP return identify data cached during boot
2211 // (true for SMART_RCV_DRIVE_DATA and IOCTL_IDE_PASS_THROUGH)
2212 regs.bCommandReg = ATA_IDENTIFY_DEVICE;
2213 regs.bCylLowReg = regs.bCylHighReg = 0;
2214 regs.bSectorCountReg = 1;
2215 datasize = 512;
2216 break;
2217 case PIDENTIFY:
2218 regs.bCommandReg = ATA_IDENTIFY_PACKET_DEVICE;
2219 regs.bCylLowReg = regs.bCylHighReg = 0;
2220 regs.bSectorCountReg = 1;
2221 datasize = 512;
2222 break;
2223 case ENABLE:
2224 regs.bFeaturesReg = ATA_SMART_ENABLE;
2225 regs.bSectorNumberReg = 1;
2226 break;
2227 case DISABLE:
2228 regs.bFeaturesReg = ATA_SMART_DISABLE;
2229 regs.bSectorNumberReg = 1;
2230 break;
2231 case STATUS_CHECK:
2232 // Requires CL,CH register return
2233 valid_options = (ata_usr_options ? "saim" : "sai");
2234 case STATUS:
2235 regs.bFeaturesReg = ATA_SMART_STATUS;
2236 break;
2237 case AUTO_OFFLINE:
2238 regs.bFeaturesReg = ATA_SMART_AUTO_OFFLINE;
2239 regs.bSectorCountReg = select; // YET NOTE - THIS IS A NON-DATA COMMAND!!
2240 break;
2241 case AUTOSAVE:
2242 regs.bFeaturesReg = ATA_SMART_AUTOSAVE;
2243 regs.bSectorCountReg = select; // YET NOTE - THIS IS A NON-DATA COMMAND!!
2244 break;
2245 case IMMEDIATE_OFFLINE:
2246 regs.bFeaturesReg = ATA_SMART_IMMEDIATE_OFFLINE;
2247 regs.bSectorNumberReg = select;
2248 // SMART_SEND_DRIVE_COMMAND supports ABORT_SELF_TEST only on Win9x/ME
2249 valid_options = (ata_usr_options || select != 127/*ABORT*/ || is_win9x() ?
2250 "saicm3" : "aicm3");
2251 break;
2252 default:
2253 pout("Unrecognized command %d in win32_ata_command_interface()\n"
2254 "Please contact " PACKAGE_BUGREPORT "\n", command);
2255 errno = ENOSYS;
2256 return -1;
2257 }
2258
2259 // Try all valid ioctls in the order specified in dev_ioctls;
2260 bool powered_up = false;
2261 assert(ata_def_options);
2262 const char * options = (ata_usr_options ? ata_usr_options : ata_def_options);
2263 for (int i = 0; ; i++) {
2264 char opt = options[i];
2265
2266 if (!opt) {
2267 if (command == CHECK_POWER_MODE && powered_up) {
2268 // Power up reported by GetDevicePowerState() and no ioctl available
2269 // to detect the actual mode of the drive => simulate ATA result ACTIVE/IDLE.
2270 regs.bSectorCountReg = 0xff;
2271 break;
2272 }
2273 // No IOCTL found
2274 errno = ENOSYS;
2275 return -1;
2276 }
2277 if (!strchr(valid_options, opt))
2278 // Invalid for this command
2279 continue;
2280
2281 errno = 0;
2282 assert(datasize == 0 || datasize == 512 || (strchr("am", opt) && datasize == -512));
2283 int rc;
2284 switch (opt) {
2285 default: assert(0);
2286 case 's':
2287 // call SMART_GET_VERSION once for each drive
2288 assert(0 <= ata_driveno && ata_driveno < sizeof(ata_smartver_state));
2289 if (ata_smartver_state[ata_driveno] > 1) {
2290 rc = -1; errno = ENOSYS;
2291 break;
2292 }
2293 if (!ata_smartver_state[ata_driveno]) {
2294 assert(port == -1);
2295 if (smart_get_version(h_ata_ioctl) < 0) {
2296 if (!con->permissive) {
2297 pout("ATA/SATA driver is possibly a SCSI driver not supporting SMART.\n");
2298 pout("If this is a SCSI disk, please try adding '-d scsi'.\n");
2299 ata_smartver_state[ata_driveno] = 2;
2300 rc = -1; errno = ENOSYS;
2301 break;
2302 }
2303 con->permissive--;
2304 }
2305 ata_smartver_state[ata_driveno] = 1;
2306 }
2307 rc = smart_ioctl(h_ata_ioctl, fd, &regs, data, datasize, port);
2308 break;
2309 case 'm':
2310 rc = ata_via_scsi_miniport_smart_ioctl(h_ata_ioctl, &regs, data, datasize);
2311 break;
2312 case 'a':
2313 rc = ata_pass_through_ioctl(h_ata_ioctl, &regs, data, datasize);
2314 break;
2315 case 'i':
2316 rc = ide_pass_through_ioctl(h_ata_ioctl, &regs, data, datasize);
2317 break;
2318 case 'c':
2319 rc = ata_via_scsi_pass_through_ioctl(h_ata_ioctl, &regs, data, datasize);
2320 break;
2321 case '3':
2322 rc = ata_via_3ware_miniport_ioctl(h_ata_ioctl, &regs, data, datasize, port);
2323 break;
2324 case 'p':
2325 assert(command == CHECK_POWER_MODE && datasize == 0);
2326 rc = get_device_power_state(h_ata_ioctl);
2327 if (rc == 0) {
2328 // Power down reported by GetDevicePowerState(), using a passthrough ioctl would
2329 // spin up the drive => simulate ATA result STANDBY.
2330 regs.bSectorCountReg = 0x00;
2331 }
2332 else if (rc > 0) {
2333 // Power up reported by GetDevicePowerState(), but this reflects the actual mode
2334 // only if it is selected by the device driver => try a passthrough ioctl to get the
2335 // actual mode, if none available simulate ACTIVE/IDLE.
2336 powered_up = true;
2337 errno = ENOSYS; rc = -1;
2338 }
2339 break;
2340 }
2341
2342 if (!rc)
2343 // Working ioctl found
2344 break;
2345
2346 if (errno != ENOSYS)
2347 // Abort on I/O error
2348 return -1;
2349
2350 // CAUTION: *_ioctl() MUST NOT change "regs" Parameter in the ENOSYS case
2351 }
2352
2353 switch (command) {
2354 case CHECK_POWER_MODE:
2355 // Return power mode from SectorCountReg in data[0]
2356 data[0] = regs.bSectorCountReg;
2357 return 0;
2358
2359 case STATUS_CHECK:
2360 // Cyl low and Cyl high unchanged means "Good SMART status"
2361 if (regs.bCylHighReg == SMART_CYL_HI && regs.bCylLowReg == SMART_CYL_LOW)
2362 return 0;
2363
2364 // These values mean "Bad SMART status"
2365 if (regs.bCylHighReg == 0x2c && regs.bCylLowReg == 0xf4)
2366 return 1;
2367
2368 // We haven't gotten output that makes sense; print out some debugging info
2369 syserror("Error SMART Status command failed");
2370 pout("Please get assistance from %s\n", PACKAGE_HOMEPAGE);
2371 print_ide_regs(&regs, 1);
2372 errno = EIO;
2373 return -1;
2374
2375 default:
2376 return 0;
2377 }
2378 /*NOTREACHED*/
2379 }
2380
2381
2382 #ifndef HAVE_ATA_IDENTIFY_IS_CACHED
2383 #error define of HAVE_ATA_IDENTIFY_IS_CACHED missing in config.h
2384 #endif
2385
2386 // Return true if OS caches the ATA identify sector
2387 int ata_identify_is_cached(int fd)
2388 {
2389 // Not RAID and WinNT4/2000/XP => true, RAID or Win9x/ME => false
2390 return (!(fd & 0xff00) && !is_win9x());
2391 }
2392
2393
2394 // Print not implemeted warning once
2395 static void pr_not_impl(const char * what, int * warned)
2396 {
2397 if (*warned)
2398 return;
2399 pout(
2400 "#######################################################################\n"
2401 "%s\n"
2402 "NOT IMPLEMENTED under Win32.\n"
2403 "Please contact " PACKAGE_BUGREPORT " if\n"
2404 "you want to help in porting smartmontools to Win32.\n"
2405 "#######################################################################\n"
2406 "\n", what
2407 );
2408 *warned = 1;
2409 }
2410
2411 // Interface to ATA devices behind 3ware escalade RAID controller cards. See os_linux.c
2412 int escalade_command_interface(int /*fd*/, int disknum, int /*escalade_type*/, smart_command_set /*command*/, int /*select*/, char * /*data*/)
2413 {
2414 static int warned = 0;
2415 if (!warned) {
2416 pout("Option '-d 3ware,%d' does not work on Windows.\n"
2417 "Controller port can be specified in the device name: '/dev/hd%c,%d'.\n\n",
2418 disknum, 'a'+ata_driveno, disknum);
2419 warned = 1;
2420 }
2421 errno = ENOSYS;
2422 return -1;
2423 }
2424
2425 // Interface to ATA devices behind Marvell chip-set based controllers. See os_linux.c
2426 int marvell_command_interface(int /*fd*/, smart_command_set /*command*/, int /*select*/, char * /*data*/)
2427 {
2428 static int warned = 0;
2429 pr_not_impl("Marvell chip-set command routine marvell_command_interface()", &warned);
2430 errno = ENOSYS;
2431 return -1;
2432 }
2433
2434 // Interface to ATA devices behind HighPoint Raid controllers. See os_linux.c
2435 int highpoint_command_interface(int /*fd*/, smart_command_set /*command*/, int /*select*/, char * /*data*/)
2436 {
2437 static int warned = 0;
2438 pr_not_impl("HighPoint raid controller command routine highpoint_command_interface()", &warned);
2439 errno = ENOSYS;
2440 return -1;
2441 }
2442
2443
2444 /////////////////////////////////////////////////////////////////////////////
2445 // ASPI Interface (for SCSI devices)
2446 /////////////////////////////////////////////////////////////////////////////
2447
2448 #pragma pack(1)
2449
2450 #define ASPI_SENSE_SIZE 18
2451
2452 // ASPI SCSI Request block header
2453
2454 typedef struct {
2455 unsigned char cmd; // 00: Command code
2456 unsigned char status; // 01: ASPI status
2457 unsigned char adapter; // 02: Host adapter number
2458 unsigned char flags; // 03: Request flags
2459 unsigned char reserved[4]; // 04: 0
2460 } ASPI_SRB_HEAD;
2461
2462 // SRB for host adapter inquiry
2463
2464 typedef struct {
2465 ASPI_SRB_HEAD h; // 00: Header
2466 unsigned char adapters; // 08: Number of adapters
2467 unsigned char target_id; // 09: Target ID ?
2468 char manager_id[16]; // 10: SCSI manager ID
2469 char adapter_id[16]; // 26: Host adapter ID
2470 unsigned char parameters[16]; // 42: Host adapter unique parmameters
2471 } ASPI_SRB_INQUIRY;
2472
2473 // SRB for get device type
2474
2475 typedef struct {
2476 ASPI_SRB_HEAD h; // 00: Header
2477 unsigned char target_id; // 08: Target ID
2478 unsigned char lun; // 09: LUN
2479 unsigned char devtype; // 10: Device type
2480 unsigned char reserved; // 11: Reserved
2481 } ASPI_SRB_DEVTYPE;
2482
2483 // SRB for SCSI I/O
2484
2485 typedef struct {
2486 ASPI_SRB_HEAD h; // 00: Header
2487 unsigned char target_id; // 08: Target ID
2488 unsigned char lun; // 09: LUN
2489 unsigned char reserved[2]; // 10: Reserved
2490 unsigned long data_size; // 12: Data alloc. lenght
2491 void * data_addr; // 16: Data buffer pointer
2492 unsigned char sense_size; // 20: Sense alloc. length
2493 unsigned char cdb_size; // 21: CDB length
2494 unsigned char host_status; // 22: Host status
2495 unsigned char target_status; // 23: Target status
2496 void * event_handle; // 24: Event handle
2497 unsigned char workspace[20]; // 28: ASPI workspace
2498 unsigned char cdb[16+ASPI_SENSE_SIZE];
2499 } ASPI_SRB_IO;
2500
2501 // Macro to retrieve start of sense information
2502 #define ASPI_SRB_SENSE(srb,cdbsz) ((srb)->cdb + 16)
2503
2504 // SRB union
2505
2506 typedef union {
2507 ASPI_SRB_HEAD h; // Common header
2508 ASPI_SRB_INQUIRY q; // Inquiry
2509 ASPI_SRB_DEVTYPE t; // Device type
2510 ASPI_SRB_IO i; // I/O
2511 } ASPI_SRB;
2512
2513 #pragma pack()
2514
2515 // ASPI commands
2516 #define ASPI_CMD_ADAPTER_INQUIRE 0x00
2517 #define ASPI_CMD_GET_DEVICE_TYPE 0x01
2518 #define ASPI_CMD_EXECUTE_IO 0x02
2519 #define ASPI_CMD_ABORT_IO 0x03
2520
2521 // Request flags
2522 #define ASPI_REQFLAG_DIR_TO_HOST 0x08
2523 #define ASPI_REQFLAG_DIR_TO_TARGET 0x10
2524 #define ASPI_REQFLAG_DIR_NO_XFER 0x18
2525 #define ASPI_REQFLAG_EVENT_NOTIFY 0x40
2526
2527 // ASPI status
2528 #define ASPI_STATUS_IN_PROGRESS 0x00
2529 #define ASPI_STATUS_NO_ERROR 0x01
2530 #define ASPI_STATUS_ABORTED 0x02
2531 #define ASPI_STATUS_ABORT_ERR 0x03
2532 #define ASPI_STATUS_ERROR 0x04
2533 #define ASPI_STATUS_INVALID_COMMAND 0x80
2534 #define ASPI_STATUS_INVALID_ADAPTER 0x81
2535 #define ASPI_STATUS_INVALID_TARGET 0x82
2536 #define ASPI_STATUS_NO_ADAPTERS 0xE8
2537
2538 // Adapter (host) status
2539 #define ASPI_HSTATUS_NO_ERROR 0x00
2540 #define ASPI_HSTATUS_SELECTION_TIMEOUT 0x11
2541 #define ASPI_HSTATUS_DATA_OVERRUN 0x12
2542 #define ASPI_HSTATUS_BUS_FREE 0x13
2543 #define ASPI_HSTATUS_BUS_PHASE_ERROR 0x14
2544 #define ASPI_HSTATUS_BAD_SGLIST 0x1A
2545
2546 // Target status
2547 #define ASPI_TSTATUS_NO_ERROR 0x00
2548 #define ASPI_TSTATUS_CHECK_CONDITION 0x02
2549 #define ASPI_TSTATUS_BUSY 0x08
2550 #define ASPI_TSTATUS_RESERV_CONFLICT 0x18
2551
2552
2553 static HINSTANCE h_aspi_dll; // DLL handle
2554 static UINT (* aspi_entry)(ASPI_SRB * srb); // ASPI entrypoint
2555 static unsigned num_aspi_adapters;
2556
2557 #ifdef __CYGWIN__
2558 // h_aspi_dll+aspi_entry is not inherited by Cygwin's fork()
2559 static DWORD aspi_dll_pid; // PID of DLL owner to detect fork()
2560 #define aspi_entry_valid() (aspi_entry && (aspi_dll_pid == GetCurrentProcessId()))
2561 #else
2562 #define aspi_entry_valid() (!!aspi_entry)
2563 #endif
2564
2565
2566 static int aspi_call(ASPI_SRB * srb)
2567 {
2568 int i;
2569 aspi_entry(srb);
2570 i = 0;
2571 while (((volatile ASPI_SRB *)srb)->h.status == ASPI_STATUS_IN_PROGRESS) {
2572 if (++i > 100/*10sek*/) {
2573 pout("ASPI Adapter %u: Timed out\n", srb->h.adapter);
2574 aspi_entry = 0;
2575 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
2576 errno = EIO;
2577 return -1;
2578 }
2579 if (con->reportscsiioctl > 1)
2580 pout("ASPI Adapter %u: Waiting (%d) ...\n", srb->h.adapter, i);
2581 Sleep(100);
2582 }
2583 return 0;
2584 }
2585
2586
2587 // Get ASPI entrypoint from wnaspi32.dll
2588
2589 static FARPROC aspi_get_address(const char * name, int verbose)
2590 {
2591 FARPROC addr;
2592 assert(h_aspi_dll && h_aspi_dll != INVALID_HANDLE_VALUE);
2593
2594 if (!(addr = GetProcAddress(h_aspi_dll, name))) {
2595 if (verbose)
2596 pout("Missing %s() in WNASPI32.DLL\n", name);
2597 aspi_entry = 0;
2598 FreeLibrary(h_aspi_dll);
2599 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
2600 errno = ENOSYS;
2601 return 0;
2602 }
2603 return addr;
2604 }
2605
2606
2607 static int aspi_open_dll(int verbose)
2608 {
2609 UINT (*aspi_info)(void);
2610 UINT info, rc;
2611
2612 assert(!aspi_entry_valid());
2613
2614 // Check structure layout
2615 assert(sizeof(ASPI_SRB_HEAD) == 8);
2616 assert(sizeof(ASPI_SRB_INQUIRY) == 58);
2617 assert(sizeof(ASPI_SRB_DEVTYPE) == 12);
2618 assert(sizeof(ASPI_SRB_IO) == 64+ASPI_SENSE_SIZE);
2619 assert(offsetof(ASPI_SRB,h.cmd) == 0);
2620 assert(offsetof(ASPI_SRB,h.flags) == 3);
2621 assert(offsetof(ASPI_SRB_IO,lun) == 9);
2622 assert(offsetof(ASPI_SRB_IO,data_addr) == 16);
2623 assert(offsetof(ASPI_SRB_IO,workspace) == 28);
2624 assert(offsetof(ASPI_SRB_IO,cdb) == 48);
2625
2626 if (h_aspi_dll == INVALID_HANDLE_VALUE) {
2627 // do not retry
2628 errno = ENOENT;
2629 return -1;
2630 }
2631
2632 // Load ASPI DLL
2633 if (!(h_aspi_dll = LoadLibraryA("WNASPI32.DLL"))) {
2634 if (verbose)
2635 pout("Cannot load WNASPI32.DLL, Error=%ld\n", GetLastError());
2636 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
2637 errno = ENOENT;
2638 return -1;
2639 }
2640 if (con->reportscsiioctl > 1) {
2641 // Print full path of WNASPI32.DLL
2642 char path[MAX_PATH];
2643 if (!GetModuleFileName(h_aspi_dll, path, sizeof(path)))
2644 strcpy(path, "*unknown*");
2645 pout("Using ASPI interface \"%s\"\n", path);
2646 }
2647
2648 // Get ASPI entrypoints
2649 if (!(aspi_info = (UINT (*)(void))aspi_get_address("GetASPI32SupportInfo", verbose)))
2650 return -1;
2651 if (!(aspi_entry = (UINT (*)(ASPI_SRB *))aspi_get_address("SendASPI32Command", verbose)))
2652 return -1;
2653
2654 // Init ASPI manager and get number of adapters
2655 info = (aspi_info)();
2656 if (con->reportscsiioctl > 1)
2657 pout("GetASPI32SupportInfo() returns 0x%04x\n", info);
2658 rc = (info >> 8) & 0xff;
2659 if (rc == ASPI_STATUS_NO_ADAPTERS) {
2660 num_aspi_adapters = 0;
2661 }
2662 else if (rc == ASPI_STATUS_NO_ERROR) {
2663 num_aspi_adapters = info & 0xff;
2664 }
2665 else {
2666 if (verbose)
2667 pout("Got strange 0x%04x from GetASPI32SupportInfo()\n", info);
2668 aspi_entry = 0;
2669 FreeLibrary(h_aspi_dll);
2670 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
2671 errno = ENOENT;
2672 return -1;
2673 }
2674
2675 if (con->reportscsiioctl)
2676 pout("%u ASPI Adapter%s detected\n",num_aspi_adapters, (num_aspi_adapters!=1?"s":""));
2677
2678 #ifdef __CYGWIN__
2679 // save PID to detect fork() in aspi_entry_valid()
2680 aspi_dll_pid = GetCurrentProcessId();
2681 #endif
2682 assert(aspi_entry_valid());
2683 return 0;
2684 }
2685
2686
2687 static int aspi_io_call(ASPI_SRB * srb, unsigned timeout)
2688 {
2689 HANDLE event;
2690 // Create event
2691 if (!(event = CreateEventA(NULL, FALSE, FALSE, NULL))) {
2692 pout("CreateEvent(): Error=%ld\n", GetLastError()); return -EIO;
2693 }
2694 srb->i.event_handle = event;
2695 srb->h.flags |= ASPI_REQFLAG_EVENT_NOTIFY;
2696 // Start ASPI request
2697 aspi_entry(srb);
2698 if (((volatile ASPI_SRB *)srb)->h.status == ASPI_STATUS_IN_PROGRESS) {
2699 // Wait for event
2700 DWORD rc = WaitForSingleObject(event, timeout*1000L);
2701 if (rc != WAIT_OBJECT_0) {
2702 if (rc == WAIT_TIMEOUT) {
2703 pout("ASPI Adapter %u, ID %u: Timed out after %u seconds\n",
2704 srb->h.adapter, srb->i.target_id, timeout);
2705 }
2706 else {
2707 pout("WaitForSingleObject(%lx) = 0x%lx,%ld, Error=%ld\n",
2708 (unsigned long)event, rc, rc, GetLastError());
2709 }
2710 // TODO: ASPI_ABORT_IO command
2711 aspi_entry = 0;
2712 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
2713 return -EIO;
2714 }
2715 }
2716 CloseHandle(event);
2717 return 0;
2718 }
2719
2720
2721 static int aspi_open(unsigned adapter, unsigned id)
2722 {
2723 ASPI_SRB srb;
2724 if (!(adapter <= 9 && id < 16)) {
2725 errno = ENOENT;
2726 return -1;
2727 }
2728
2729 if (!aspi_entry_valid()) {
2730 if (aspi_open_dll(1/*verbose*/))
2731 return -1;
2732 }
2733
2734 // Adapter OK?
2735 if (adapter >= num_aspi_adapters) {
2736 pout("ASPI Adapter %u does not exist (%u Adapter%s detected).\n",
2737 adapter, num_aspi_adapters, (num_aspi_adapters!=1?"s":""));
2738 if (!is_permissive()) {
2739 errno = ENOENT;
2740 return -1;
2741 }
2742 }
2743
2744 // Device present ?
2745 memset(&srb, 0, sizeof(srb));
2746 srb.h.cmd = ASPI_CMD_GET_DEVICE_TYPE;
2747 srb.h.adapter = adapter; srb.i.target_id = id;
2748 if (aspi_call(&srb)) {
2749 errno = EIO;
2750 return -1;
2751 }
2752 if (srb.h.status != ASPI_STATUS_NO_ERROR) {
2753 pout("ASPI Adapter %u, ID %u: No such device (Status=0x%02x)\n", adapter, id, srb.h.status);
2754 if (!is_permissive()) {
2755 errno = (srb.h.status == ASPI_STATUS_INVALID_TARGET ? ENOENT : EIO);
2756 return -1;
2757 }
2758 }
2759 else if (con->reportscsiioctl)
2760 pout("ASPI Adapter %u, ID %u: Device Type=0x%02x\n", adapter, id, srb.t.devtype);
2761
2762 return (ASPI_FDOFFSET | ((adapter & 0xf)<<4) | (id & 0xf));
2763 }
2764
2765
2766 static void aspi_close(int /*fd*/)
2767 {
2768 // No FreeLibrary(h_aspi_dll) to prevent problems with ASPI threads
2769 }
2770
2771
2772 // Scan for SCSI drives, fill bitmask [adapter:0-9][id:0-7] of drives present,
2773 // return #drives
2774
2775 static int aspi_scan(unsigned long * drives)
2776 {
2777 int cnt = 0;
2778 unsigned ad;
2779
2780 if (!aspi_entry_valid()) {
2781 if (aspi_open_dll(con->reportscsiioctl/*default is quiet*/))
2782 return 0;
2783 }
2784
2785 for (ad = 0; ad < num_aspi_adapters; ad++) {
2786 ASPI_SRB srb; unsigned id;
2787
2788 if (ad > 9) {
2789 if (con->reportscsiioctl)
2790 pout(" ASPI Adapter %u: Ignored\n", ad);
2791 continue;
2792 }
2793
2794 // Get adapter name
2795 memset(&srb, 0, sizeof(srb));
2796 srb.h.cmd = ASPI_CMD_ADAPTER_INQUIRE;
2797 srb.h.adapter = ad;
2798 if (aspi_call(&srb))
2799 return 0;
2800
2801 if (srb.h.status != ASPI_STATUS_NO_ERROR) {
2802 if (con->reportscsiioctl)
2803 pout(" ASPI Adapter %u: Status=0x%02x\n", ad, srb.h.status);
2804 continue;
2805 }
2806
2807 if (con->reportscsiioctl) {
2808 int i;
2809 for (i = 1; i < 16 && srb.q.adapter_id[i]; i++)
2810 if (!(' ' <= srb.q.adapter_id[i] && srb.q.adapter_id[i] <= '~'))
2811 srb.q.adapter_id[i] = '?';
2812 pout(" ASPI Adapter %u (\"%.16s\"):\n", ad, srb.q.adapter_id);
2813 }
2814
2815 bool ignore = !strnicmp(srb.q.adapter_id, "3ware", 5);
2816
2817 for (id = 0; id <= 7; id++) {
2818 // Get device type
2819 memset(&srb, 0, sizeof(srb));
2820 srb.h.cmd = ASPI_CMD_GET_DEVICE_TYPE;
2821 srb.h.adapter = ad; srb.i.target_id = id;
2822 if (aspi_call(&srb))
2823 return 0;
2824 if (srb.h.status != ASPI_STATUS_NO_ERROR) {
2825 if (con->reportscsiioctl > 1)
2826 pout(" ID %u: No such device (Status=0x%02x)\n", id, srb.h.status);
2827 continue;
2828 }
2829
2830 if (!ignore && srb.t.devtype == 0x00/*HDD*/) {
2831 if (con->reportscsiioctl)
2832 pout(" ID %u: Device Type=0x%02x\n", id, srb.t.devtype);
2833 drives[ad >> 2] |= (1L << (((ad & 0x3) << 3) + id));
2834 cnt++;
2835 }
2836 else if (con->reportscsiioctl)
2837 pout(" ID %u: Device Type=0x%02x (ignored)\n", id, srb.t.devtype);
2838 }
2839 }
2840 return cnt;
2841 }
2842
2843
2844 /////////////////////////////////////////////////////////////////////////////
2845
2846 // Interface to ASPI SCSI devices. See scsicmds.h and os_linux.c
2847 static int do_aspi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report)
2848 {
2849 ASPI_SRB srb;
2850
2851 if (!aspi_entry_valid())
2852 return -EBADF;
2853 if (!((fd & ~0xff) == ASPI_FDOFFSET))
2854 return -EBADF;
2855
2856 if (!(iop->cmnd_len == 6 || iop->cmnd_len == 10 || iop->cmnd_len == 12 || iop->cmnd_len == 16)) {
2857 pout("do_aspi_cmnd_io: bad CDB length\n");
2858 return -EINVAL;
2859 }
2860
2861 if (report > 0) {
2862 // From os_linux.c
2863 int k, j;
2864 const unsigned char * ucp = iop->cmnd;
2865 const char * np;
2866 char buff[256];
2867 const int sz = (int)sizeof(buff);
2868
2869 np = scsi_get_opcode_name(ucp[0]);
2870 j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
2871 for (k = 0; k < (int)iop->cmnd_len; ++k)
2872 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);
2873 if ((report > 1) &&
2874 (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
2875 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
2876
2877 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing "
2878 "data, len=%d%s:\n", (int)iop->dxfer_len,
2879 (trunc ? " [only first 256 bytes shown]" : ""));
2880 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
2881 }
2882 else
2883 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
2884 pout(buff);
2885 }
2886
2887 memset(&srb, 0, sizeof(srb));
2888 srb.h.cmd = ASPI_CMD_EXECUTE_IO;
2889 srb.h.adapter = ((fd >> 4) & 0xf);
2890 srb.i.target_id = (fd & 0xf);
2891 //srb.i.lun = 0;
2892 srb.i.sense_size = ASPI_SENSE_SIZE;
2893 srb.i.cdb_size = iop->cmnd_len;
2894 memcpy(srb.i.cdb, iop->cmnd, iop->cmnd_len);
2895
2896 switch (iop->dxfer_dir) {
2897 case DXFER_NONE:
2898 srb.h.flags = ASPI_REQFLAG_DIR_NO_XFER;
2899 break;
2900 case DXFER_FROM_DEVICE:
2901 srb.h.flags = ASPI_REQFLAG_DIR_TO_HOST;
2902 srb.i.data_size = iop->dxfer_len;
2903 srb.i.data_addr = iop->dxferp;
2904 break;
2905 case DXFER_TO_DEVICE:
2906 srb.h.flags = ASPI_REQFLAG_DIR_TO_TARGET;
2907 srb.i.data_size = iop->dxfer_len;
2908 srb.i.data_addr = iop->dxferp;
2909 break;
2910 default:
2911 pout("do_aspi_cmnd_io: bad dxfer_dir\n");
2912 return -EINVAL;
2913 }
2914
2915 iop->resp_sense_len = 0;
2916 iop->scsi_status = 0;
2917 iop->resid = 0;
2918
2919 if (aspi_io_call(&srb, (iop->timeout ? iop->timeout : 60))) {
2920 // Timeout
2921 return -EIO;
2922 }
2923
2924 if (srb.h.status != ASPI_STATUS_NO_ERROR) {
2925 if ( srb.h.status == ASPI_STATUS_ERROR
2926 && srb.i.host_status == ASPI_HSTATUS_NO_ERROR
2927 && srb.i.target_status == ASPI_TSTATUS_CHECK_CONDITION) {
2928 // Sense valid
2929 const unsigned char * sense = ASPI_SRB_SENSE(&srb.i, iop->cmnd_len);
2930 int len = (ASPI_SENSE_SIZE < iop->max_sense_len ? ASPI_SENSE_SIZE : iop->max_sense_len);
2931 iop->scsi_status = SCSI_STATUS_CHECK_CONDITION;
2932 if (len > 0 && iop->sensep) {
2933 memcpy(iop->sensep, sense, len);
2934 iop->resp_sense_len = len;
2935 if (report > 1) {
2936 pout(" >>> Sense buffer, len=%d:\n", (int)len);
2937 dStrHex(iop->sensep, len , 1);
2938 }
2939 }
2940 if (report) {
2941 pout(" sense_key=%x asc=%x ascq=%x\n",
2942 sense[2] & 0xf, sense[12], sense[13]);
2943 }
2944 return 0;
2945 }
2946 else {
2947 if (report)
2948 pout(" ASPI call failed, (0x%02x,0x%02x,0x%02x)\n", srb.h.status, srb.i.host_status, srb.i.target_status);
2949 return -EIO;
2950 }
2951 }
2952
2953 if (report > 0)
2954 pout(" OK\n");
2955
2956 if (iop->dxfer_dir == DXFER_FROM_DEVICE && report > 1) {
2957 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
2958 pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
2959 (trunc ? " [only first 256 bytes shown]" : ""));
2960 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
2961 }
2962
2963 return 0;
2964 }
2965
2966
2967 /////////////////////////////////////////////////////////////////////////////
2968 // SPT Interface (for SCSI devices and ATA devices behind SATLs)
2969 // Only supported in NT and later
2970 /////////////////////////////////////////////////////////////////////////////
2971
2972 #define SPT_MAXDEV 64
2973
2974 struct spt_dev_info {
2975 HANDLE h_spt_ioctl;
2976 int sub_addr; // addressing disks within a RAID, for example
2977 };
2978
2979 // Private table of open devices: guaranteed zero on startup since
2980 // part of static data.
2981 static struct spt_dev_info * spt_dev_arr[SPT_MAXDEV];
2982
2983
2984 static int spt_open(int pd_num, int ld_num, int tape_num, int sub_addr)
2985 {
2986 int k;
2987 struct spt_dev_info * sdip;
2988 char b[128];
2989 HANDLE h;
2990
2991 for (k = 0; k < SPT_MAXDEV; k++)
2992 if (! spt_dev_arr[k])
2993 break;
2994
2995 // If no free entry found, return error. We have max allowed number
2996 // of "file descriptors" already allocated.
2997 if (k == SPT_MAXDEV) {
2998 if (con->reportscsiioctl)
2999 pout("spt_open: too many open file descriptors (%d)\n",
3000 SPT_MAXDEV);
3001 errno = EMFILE;
3002 return -1;
3003 }
3004 sdip = (struct spt_dev_info *)malloc(sizeof(struct spt_dev_info));
3005 if (NULL == sdip) {
3006 errno = ENOMEM;
3007 return -1;
3008 }
3009 spt_dev_arr[k] = sdip;
3010 sdip->sub_addr = sub_addr;
3011
3012 b[sizeof(b) - 1] = '\0';
3013 if (pd_num >= 0)
3014 snprintf(b, sizeof(b) - 1, "\\\\.\\PhysicalDrive%d", pd_num);
3015 else if (ld_num >= 0)
3016 snprintf(b, sizeof(b) - 1, "\\\\.\\%c:", 'A' + ld_num);
3017 else if (tape_num >= 0)
3018 snprintf(b, sizeof(b) - 1, "\\\\.\\TAPE%d", tape_num);
3019 else {
3020 if (con->reportscsiioctl)
3021 pout("spt_open: bad parameters\n");
3022 errno = EINVAL;
3023 goto err_out;
3024 }
3025
3026 // Open device
3027 if ((h = CreateFileA(b, GENERIC_READ|GENERIC_WRITE,
3028 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
3029 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
3030 if (con->reportscsiioctl)
3031 pout(" %s: Open failed, Error=%ld\n", b, GetLastError());
3032 errno = ENODEV;
3033 goto err_out;
3034 }
3035 sdip->h_spt_ioctl = h;
3036 return k + SPT_FDOFFSET;
3037
3038 err_out:
3039 spt_dev_arr[k] = NULL;
3040 free(sdip);
3041 return -1;
3042 }
3043
3044
3045 static void spt_close(int fd)
3046 {
3047 struct spt_dev_info * sdip;
3048 int index = fd - SPT_FDOFFSET;
3049
3050 if ((index < 0) || (index >= SPT_MAXDEV)) {
3051 if (con->reportscsiioctl)
3052 pout("spt_close: bad fd range\n");
3053 return;
3054 }
3055 sdip = spt_dev_arr[index];
3056 if (NULL == sdip) {
3057 if (con->reportscsiioctl)
3058 pout("spt_close: fd already closed\n");
3059 return;
3060 }
3061 free(sdip);
3062 spt_dev_arr[index] = NULL;
3063 }
3064
3065
3066 static int spt_scan(unsigned long * drives)
3067 {
3068 int cnt = 0;
3069 for (int i = 0; i <= 9; i++) {
3070 if (get_phy_drive_type(i) != CONTROLLER_SCSI)
3071 continue;
3072 // STORAGE_QUERY_PROPERTY returned SCSI/SAS/...
3073 drives[0] |= (1L << i);
3074 cnt++;
3075 }
3076 return cnt;
3077 }
3078
3079
3080 #define IOCTL_SCSI_PASS_THROUGH_DIRECT \
3081 CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
3082
3083 typedef struct _SCSI_PASS_THROUGH_DIRECT {
3084 USHORT Length;
3085 UCHAR ScsiStatus;
3086 UCHAR PathId;
3087 UCHAR TargetId;
3088 UCHAR Lun;
3089 UCHAR CdbLength;
3090 UCHAR SenseInfoLength;
3091 UCHAR DataIn;
3092 ULONG DataTransferLength;
3093 ULONG TimeOutValue;
3094 PVOID DataBuffer;
3095 ULONG SenseInfoOffset;
3096 UCHAR Cdb[16];
3097 } SCSI_PASS_THROUGH_DIRECT;
3098
3099 typedef struct {
3100 SCSI_PASS_THROUGH_DIRECT spt;
3101 ULONG Filler;
3102 UCHAR ucSenseBuf[64];
3103 } SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
3104
3105
3106 // Interface to SPT SCSI devices. See scsicmds.h and os_linux.c
3107 static int do_spt_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report)
3108 {
3109 struct spt_dev_info * sdip;
3110 int index = fd - SPT_FDOFFSET;
3111 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb;
3112 DWORD num_out;
3113
3114 if ((index < 0) || (index >= SPT_MAXDEV)) {
3115 if (report)
3116 pout("do_spt_cmnd_io: bad fd range\n");
3117 return -EBADF;
3118 }
3119 sdip = spt_dev_arr[index];
3120 if (NULL == sdip) {
3121 if (report)
3122 pout("do_spt_cmnd_io: fd already closed\n");
3123 return -EBADF;
3124 }
3125
3126 if (report > 0) {
3127 int k, j;
3128 const unsigned char * ucp = iop->cmnd;
3129 const char * np;
3130 char buff[256];
3131 const int sz = (int)sizeof(buff);
3132
3133 np = scsi_get_opcode_name(ucp[0]);
3134 j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
3135 for (k = 0; k < (int)iop->cmnd_len; ++k)
3136 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);
3137 if ((report > 1) &&
3138 (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
3139 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
3140
3141 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing "
3142 "data, len=%d%s:\n", (int)iop->dxfer_len,
3143 (trunc ? " [only first 256 bytes shown]" : ""));
3144 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
3145 }
3146 else
3147 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
3148 pout(buff);
3149 }
3150 if (iop->cmnd_len > (int)sizeof(sb.spt.Cdb)) {
3151 if (report)
3152 pout("do_spt_cmnd_io: cmnd_len too large\n");
3153 return -EINVAL;
3154 }
3155
3156 memset(&sb, 0, sizeof(sb));
3157 sb.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
3158 sb.spt.CdbLength = iop->cmnd_len;
3159 memcpy(sb.spt.Cdb, iop->cmnd, iop->cmnd_len);
3160 sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf);
3161 sb.spt.SenseInfoOffset =
3162 offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
3163 sb.spt.TimeOutValue = (iop->timeout ? iop->timeout : 60);
3164 switch (iop->dxfer_dir) {
3165 case DXFER_NONE:
3166 sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
3167 break;
3168 case DXFER_FROM_DEVICE:
3169 sb.spt.DataIn = SCSI_IOCTL_DATA_IN;
3170 sb.spt.DataTransferLength = iop->dxfer_len;
3171 sb.spt.DataBuffer = iop->dxferp;
3172 break;
3173 case DXFER_TO_DEVICE:
3174 sb.spt.DataIn = SCSI_IOCTL_DATA_OUT;
3175 sb.spt.DataTransferLength = iop->dxfer_len;
3176 sb.spt.DataBuffer = iop->dxferp;
3177 break;
3178 default:
3179 pout("do_spt_cmnd_io: bad dxfer_dir\n");
3180 return -EINVAL;
3181 }
3182
3183 if (! DeviceIoControl(sdip->h_spt_ioctl, IOCTL_SCSI_PASS_THROUGH_DIRECT,
3184 &sb, sizeof(sb), &sb, sizeof(sb), &num_out, NULL)) {
3185 long err = GetLastError();
3186
3187 if (report)
3188 pout(" IOCTL_SCSI_PASS_THROUGH_DIRECT failed, Error=%ld\n", err);
3189 return -(err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
3190 }
3191
3192 iop->scsi_status = sb.spt.ScsiStatus;
3193 if (SCSI_STATUS_CHECK_CONDITION & iop->scsi_status) {
3194 int slen = sb.ucSenseBuf[7] + 8;
3195
3196 if (slen > (int)sizeof(sb.ucSenseBuf))
3197 slen = sizeof(sb.ucSenseBuf);
3198 if (slen > (int)iop->max_sense_len)
3199 slen = iop->max_sense_len;
3200 memcpy(iop->sensep, sb.ucSenseBuf, slen);
3201 iop->resp_sense_len = slen;
3202 if (report) {
3203 if ((iop->sensep[0] & 0x7f) > 0x71)
3204 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
3205 iop->scsi_status, iop->sensep[1] & 0xf,
3206 iop->sensep[2], iop->sensep[3]);
3207 else
3208 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
3209 iop->scsi_status, iop->sensep[2] & 0xf,
3210 iop->sensep[12], iop->sensep[13]);
3211 }
3212 } else
3213 iop->resp_sense_len = 0;
3214
3215 if ((iop->dxfer_len > 0) && (sb.spt.DataTransferLength > 0))
3216 iop->resid = iop->dxfer_len - sb.spt.DataTransferLength;
3217 else
3218 iop->resid = 0;
3219
3220 if ((iop->dxfer_dir == DXFER_FROM_DEVICE) && (report > 1)) {
3221 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
3222 pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
3223 (trunc ? " [only first 256 bytes shown]" : ""));
3224 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
3225 }
3226 return 0;
3227 }
3228
3229
3230 // Decides which SCSI implementation based on pseudo fd.
3231 // Declaration and explanation in scsicmds.h
3232 int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report)
3233 {
3234 if ((fd & ~0xff) == ASPI_FDOFFSET)
3235 return do_aspi_cmnd_io(fd, iop, report);
3236 else
3237 return do_spt_cmnd_io(fd, iop, report);
3238 }