]> git.proxmox.com Git - mirror_smartmontools-debian.git/blob - os_win32.cpp
Merge branch 'upstream'
[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-6 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 #define ARGUSED(x) ((void)(x))
40
41 // Macro to check constants at compile time using a dummy typedef
42 #define ASSERT_CONST(c, n) \
43 typedef char assert_const_##c[((c) == (n)) ? 1 : -1]
44 #define ASSERT_SIZEOF(t, n) \
45 typedef char assert_sizeof_##t[(sizeof(t) == (n)) ? 1 : -1]
46
47
48 // Needed by '-V' option (CVS versioning) of smartd/smartctl
49 const char *os_XXXX_c_cvsid="$Id: os_win32.cpp,v 1.49 2006/10/27 21:49:41 chrfranke Exp $"
50 ATACMDS_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
51
52
53 #ifndef HAVE_GET_OS_VERSION_STR
54 #error define of HAVE_GET_OS_VERSION_STR missing in config.h
55 #endif
56
57 // Return build host and OS version as static string
58 const char * get_os_version_str()
59 {
60 static char vstr[sizeof(SMARTMONTOOLS_BUILD_HOST)-3-1+sizeof("-2003r2-sp2.1")+13];
61 char * const vptr = vstr+sizeof(SMARTMONTOOLS_BUILD_HOST)-3-1;
62 const int vlen = sizeof(vstr)-(sizeof(SMARTMONTOOLS_BUILD_HOST)-3);
63
64 OSVERSIONINFOEXA vi;
65 const char * w;
66
67 // remove "-pc" to avoid long lines
68 assert(!strncmp(SMARTMONTOOLS_BUILD_HOST+5, "pc-", 3));
69 strcpy(vstr, "i686-"); strcpy(vstr+5, SMARTMONTOOLS_BUILD_HOST+5+3);
70 assert(vptr == vstr+strlen(vstr) && vptr+vlen+1 == vstr+sizeof(vstr));
71
72 memset(&vi, 0, sizeof(vi));
73 vi.dwOSVersionInfoSize = sizeof(vi);
74 if (!GetVersionExA((OSVERSIONINFOA *)&vi)) {
75 memset(&vi, 0, sizeof(vi));
76 vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
77 if (!GetVersionExA((OSVERSIONINFOA *)&vi))
78 return vstr;
79 }
80
81 if (vi.dwPlatformId > 0xff || vi.dwMajorVersion > 0xff || vi.dwMinorVersion > 0xff)
82 return vstr;
83
84 switch (vi.dwPlatformId << 16 | vi.dwMajorVersion << 8 | vi.dwMinorVersion) {
85 case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400| 0:
86 w = (vi.szCSDVersion[1] == 'B' ||
87 vi.szCSDVersion[1] == 'C' ? "95-osr2" : "95"); break;
88 case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400|10:
89 w = (vi.szCSDVersion[1] == 'A' ? "98se" : "98"); break;
90 case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400|90: w = "me"; break;
91 //case VER_PLATFORM_WIN32_NT <<16|0x0300|51: w = "nt3.51"; break;
92 case VER_PLATFORM_WIN32_NT <<16|0x0400| 0: w = "nt4"; break;
93 case VER_PLATFORM_WIN32_NT <<16|0x0500| 0: w = "2000"; break;
94 case VER_PLATFORM_WIN32_NT <<16|0x0500| 1:
95 w = (!GetSystemMetrics(87/*SM_MEDIACENTER*/) ? "xp"
96 : "xp-mc"); break;
97 case VER_PLATFORM_WIN32_NT <<16|0x0500| 2:
98 w = (!GetSystemMetrics(89/*SM_SERVERR2*/) ? "2003"
99 : "2003r2"); break;
100 case VER_PLATFORM_WIN32_NT <<16|0x0600| 0: w = "vista"; break;
101 default: w = 0; break;
102 }
103
104 if (!w)
105 snprintf(vptr, vlen, "-%s%lu.%lu",
106 (vi.dwPlatformId==VER_PLATFORM_WIN32_NT ? "nt" : "9x"),
107 vi.dwMajorVersion, vi.dwMinorVersion);
108 else if (vi.wServicePackMinor)
109 snprintf(vptr, vlen, "-%s-sp%u.%u", w, vi.wServicePackMajor, vi.wServicePackMinor);
110 else if (vi.wServicePackMajor)
111 snprintf(vptr, vlen, "-%s-sp%u", w, vi.wServicePackMajor);
112 else
113 snprintf(vptr, vlen, "-%s", w);
114 return vstr;
115 }
116
117
118 #define ATARAID_FDOFFSET 0x0200
119
120 static int ata_open(int drive, const char * options, int port);
121 static void ata_close(int fd);
122 static int ata_scan(unsigned long * drives, int * rdriveno, unsigned long * rdrives);
123 static const char * ata_get_def_options(void);
124
125 #define ASPI_FDOFFSET 0x0100
126
127 static int aspi_open(unsigned adapter, unsigned id);
128 static void aspi_close(int fd);
129 static int aspi_scan(unsigned long * drives);
130
131 #define SPT_FDOFFSET 0x0400
132
133 static int spt_open(int pd_num, int tape_num, int sub_addr);
134 static void spt_close(int fd);
135
136
137 static int is_permissive()
138 {
139 if (!con->permissive) {
140 pout("To continue, add one or more '-T permissive' options.\n");
141 return 0;
142 }
143 con->permissive--;
144 return 1;
145 }
146
147 static const char * skipdev(const char * s)
148 {
149 return (!strncmp(s, "/dev/", 5) ? s + 5 : s);
150 }
151
152
153 // tries to guess device type given the name (a path). See utility.h
154 // for return values.
155 int guess_device_type (const char * dev_name)
156 {
157 dev_name = skipdev(dev_name);
158 if (!strncmp(dev_name, "hd", 2))
159 return CONTROLLER_ATA;
160 if (!strncmp(dev_name, "scsi", 4))
161 return CONTROLLER_SCSI;
162 if (!strncmp(dev_name, "sd", 2))
163 return CONTROLLER_SCSI;
164 if (!strncmp(dev_name, "pd", 2))
165 return CONTROLLER_SCSI;
166 if (!strncmp(dev_name, "tape", 4))
167 return CONTROLLER_SCSI;
168 return CONTROLLER_UNKNOWN;
169 }
170
171
172 // makes a list of ATA or SCSI devices for the DEVICESCAN directive of
173 // smartd. Returns number N of devices, or -1 if out of
174 // memory. Allocates N+1 arrays: one of N pointers (devlist), the
175 // others each contain null-terminated character strings.
176 int make_device_names (char*** devlist, const char* type)
177 {
178 unsigned long drives[3];
179 int rdriveno[2];
180 unsigned long rdrives[2];
181 int i, j, n, nmax, sz;
182 const char * path;
183
184 drives[0] = drives[1] = drives[2] = 0;
185 rdriveno[0] = rdriveno[1] = -1;
186 rdrives[0] = rdrives[1] = 0;
187
188 if (!strcmp(type, "ATA")) {
189 // bit i set => drive i present
190 n = ata_scan(drives, rdriveno, rdrives);
191 path = "/dev/hda";
192 nmax = 10;
193 }
194 else if (!strcmp(type, "SCSI")) {
195 // bit i set => drive with ID (i & 0x7) on adapter (i >> 3) present
196 n = aspi_scan(drives);
197 path = "/dev/scsi00";
198 nmax = 10*8;
199 }
200 else
201 return -1;
202
203 if (n <= 0)
204 return 0;
205
206 // Alloc devlist
207 sz = n * sizeof(char **);
208 *devlist = (char **)malloc(sz); bytes += sz;
209
210 // Add devices
211 for (i = j = 0; i < n; ) {
212 while (j < nmax && !(drives[j >> 5] & (1L << (j & 0x1f))))
213 j++;
214 assert(j < nmax);
215
216 if (j == rdriveno[0] || j == rdriveno[1]) {
217 // Add physical drives behind this logical drive
218 int ci = (j == rdriveno[0] ? 0 : 1);
219 for (int pi = 0; pi < 32 && i < n; pi++) {
220 if (!(rdrives[ci] & (1L << pi)))
221 continue;
222 char rpath[20];
223 sprintf(rpath, "/dev/hd%c,%u", 'a'+j, pi);
224 sz = strlen(rpath)+1;
225 char * s = (char *)malloc(sz); bytes += sz;
226 strcpy(s, rpath);
227 (*devlist)[i++] = s;
228 }
229 }
230 else {
231 sz = strlen(path)+1;
232 char * s = (char *)malloc(sz); bytes += sz;
233 strcpy(s, path);
234
235 if (nmax <= 10) {
236 assert(j <= 9);
237 s[sz-2] += j; // /dev/hd[a-j]
238 }
239 else {
240 assert((j >> 3) <= 9);
241 s[sz-3] += (j >> 3); // /dev/scsi[0-9].....
242 s[sz-2] += (j & 0x7); // .....[0-7]
243 }
244 (*devlist)[i++] = s;
245 }
246 j++;
247 }
248
249 return n;
250 }
251
252
253 // Like open(). Return positive integer handle, only used by
254 // functions below. type="ATA" or "SCSI". If you need to store extra
255 // information about your devices, create a private internal array
256 // within this file (see os_freebsd.cpp for an example).
257 int deviceopen(const char * pathname, char *type)
258 {
259 pathname = skipdev(pathname);
260 int len = strlen(pathname);
261
262 if (!strcmp(type, "ATA")) {
263 // hd[a-j](:[saicp]+)? => ATA 0-9 with options
264 char drive[1+1] = "", options[5+1] = ""; int n1 = -1, n2 = -1;
265 if ( sscanf(pathname, "hd%1[a-j]%n:%5[saicp]%n", drive, &n1, options, &n2) >= 1
266 && ((n1 == len && !options[0]) || n2 == len) ) {
267 return ata_open(drive[0] - 'a', options, -1);
268 }
269 // hd[a-j],N(:[saicp]+)? => Physical drive 0-9, RAID port N, with options
270 drive[0] = 0; options[0] = 0; n1 = -1; n2 = -1;
271 unsigned port = ~0;
272 if ( sscanf(pathname, "hd%1[a-j],%u%n:%5[saicp]%n", drive, &port, &n1, options, &n2) >= 2
273 && port < 32 && ((n1 == len && !options[0]) || n2 == len) ) {
274 return ata_open(drive[0] - 'a', options, port);
275 }
276 } else if (!strcmp(type, "SCSI")) {
277 // scsi[0-9][0-f] => ASPI Adapter 0-9, ID 0-15, LUN 0
278 unsigned adapter = ~0, id = ~0; int n1 = -1;
279 if (sscanf(pathname,"scsi%1u%1x%n", &adapter, &id, &n1) == 2 && n1 == len) {
280 return aspi_open(adapter, id);
281 }
282 // sd[a-z],N => Physical drive 0-26, RAID port N
283 char drive[1+1] = ""; int sub_addr = -1; n1 = -1; int n2 = -1;
284 if ( sscanf(pathname, "sd%1[a-z]%n,%d%n", drive, &n1, &sub_addr, &n2) >= 1
285 && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0)) ) {
286 return spt_open(drive[0] - 'a', -1, sub_addr);
287 }
288 // pd<m>,N => Physical drive <m>, RAID port N
289 int pd_num = -1; sub_addr = -1; n1 = -1; n2 = -1;
290 if ( sscanf(pathname, "pd%d%n,%d%n", &pd_num, &n1, &sub_addr, &n2) >= 1
291 && pd_num >= 0 && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0))) {
292 return spt_open(pd_num, -1, sub_addr);
293 }
294 // tape<m> => tape drive <m>
295 int tape_num = -1; n1 = -1;
296 if (sscanf(pathname, "tape%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) {
297 return spt_open(-1, tape_num, -1);
298 }
299 }
300
301 errno = EINVAL;
302 return -1;
303 }
304
305
306 // Like close(). Acts only on handles returned by above function.
307 // (Never called in smartctl!)
308 int deviceclose(int fd)
309 {
310 if ((fd & 0xff00) == ASPI_FDOFFSET)
311 aspi_close(fd);
312 else if (fd >= SPT_FDOFFSET)
313 spt_close(fd);
314 else
315 ata_close(fd);
316 return 0;
317 }
318
319
320 // print examples for smartctl
321 void print_smartctl_examples(){
322 printf("=================================================== SMARTCTL EXAMPLES =====\n\n"
323 " smartctl -a /dev/hda (Prints all SMART information)\n\n"
324 #ifdef HAVE_GETOPT_LONG
325 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/hda\n"
326 " (Enables SMART on first disk)\n\n"
327 " smartctl -t long /dev/hda (Executes extended disk self-test)\n\n"
328 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/hda\n"
329 " (Prints Self-Test & Attribute errors)\n"
330 #else
331 " smartctl -s on -o on -S on /dev/hda (Enables SMART on first disk)\n"
332 " smartctl -t long /dev/hda (Executes extended disk self-test)\n"
333 " smartctl -A -l selftest -q errorsonly /dev/hda\n"
334 " (Prints Self-Test & Attribute errors)\n"
335 #endif
336 " smartctl -a /dev/scsi21\n"
337 " (Prints all information for SCSI disk on ASPI adapter 2, ID 1)\n"
338 " smartctl -a /dev/sda\n"
339 " (Prints all information for SCSI disk on PhysicalDrive 0)\n"
340 " smartctl -a /dev/pd3\n"
341 " (Prints all information for SCSI disk on PhysicalDrive 3)\n"
342 " smartctl -a /dev/tape1\n"
343 " (Prints all information for SCSI tape on Tape 1)\n"
344 " smartctl -A /dev/hdb,3\n"
345 " (Prints Attributes for physical drive 3 on 3ware 9000 RAID)\n"
346 "\n"
347 " ATA SMART access methods and ordering may be specified by modifiers\n"
348 " following the device name: /dev/hdX:[saic], where\n"
349 " 's': SMART_* IOCTLs, 'a': IOCTL_ATA_PASS_THROUGH,\n"
350 " 'i': IOCTL_IDE_PASS_THROUGH, 'c': ATA via IOCTL_SCSI_PASS_THROUGH.\n"
351 " The default on this system is /dev/hdX:%s\n", ata_get_def_options()
352 );
353 }
354
355
356 /////////////////////////////////////////////////////////////////////////////
357 // ATA Interface
358 /////////////////////////////////////////////////////////////////////////////
359
360 // SMART_* IOCTLs, also known as DFP_* (Disk Fault Protection)
361
362 // Deklarations from:
363 // http://cvs.sourceforge.net/viewcvs.py/mingw/w32api/include/ddk/ntdddisk.h?rev=1.3
364
365 #define FILE_READ_ACCESS 0x0001
366 #define FILE_WRITE_ACCESS 0x0002
367 #define METHOD_BUFFERED 0
368 #define CTL_CODE(DeviceType, Function, Method, Access) (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
369
370 #define FILE_DEVICE_DISK 7
371 #define IOCTL_DISK_BASE FILE_DEVICE_DISK
372
373 #define SMART_GET_VERSION \
374 CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS)
375
376 #define SMART_SEND_DRIVE_COMMAND \
377 CTL_CODE(IOCTL_DISK_BASE, 0x0021, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
378
379 #define SMART_RCV_DRIVE_DATA \
380 CTL_CODE(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
381
382 ASSERT_CONST(SMART_GET_VERSION , 0x074080);
383 ASSERT_CONST(SMART_SEND_DRIVE_COMMAND, 0x07c084);
384 ASSERT_CONST(SMART_RCV_DRIVE_DATA , 0x07c088);
385
386 #define SMART_CYL_LOW 0x4F
387 #define SMART_CYL_HI 0xC2
388
389
390 #pragma pack(1)
391
392 typedef struct _GETVERSIONOUTPARAMS {
393 UCHAR bVersion;
394 UCHAR bRevision;
395 UCHAR bReserved;
396 UCHAR bIDEDeviceMap;
397 ULONG fCapabilities;
398 ULONG dwReserved[4];
399 } GETVERSIONOUTPARAMS, *PGETVERSIONOUTPARAMS, *LPGETVERSIONOUTPARAMS;
400
401 ASSERT_SIZEOF(GETVERSIONOUTPARAMS, 24);
402
403
404 #define SMART_VENDOR_3WARE 0x13C1 // identifies 3ware specific parameters
405
406 typedef struct _GETVERSIONINPARAMS_EX {
407 BYTE bVersion;
408 BYTE bRevision;
409 BYTE bReserved;
410 BYTE bIDEDeviceMap;
411 DWORD fCapabilities;
412 DWORD dwDeviceMapEx; // 3ware specific: RAID drive bit map
413 WORD wIdentifier; // Vendor specific identifier
414 WORD wControllerId; // 3ware specific: Controller ID (0,1,...)
415 ULONG dwReserved[2];
416 } GETVERSIONINPARAMS_EX, *PGETVERSIONINPARAMS_EX, *LPGETVERSIONINPARAMS_EX;
417
418 ASSERT_SIZEOF(GETVERSIONINPARAMS_EX, sizeof(GETVERSIONOUTPARAMS));
419
420
421 typedef struct _IDEREGS {
422 UCHAR bFeaturesReg;
423 UCHAR bSectorCountReg;
424 UCHAR bSectorNumberReg;
425 UCHAR bCylLowReg;
426 UCHAR bCylHighReg;
427 UCHAR bDriveHeadReg;
428 UCHAR bCommandReg;
429 UCHAR bReserved;
430 } IDEREGS, *PIDEREGS, *LPIDEREGS;
431
432 typedef struct _SENDCMDINPARAMS {
433 ULONG cBufferSize;
434 IDEREGS irDriveRegs;
435 UCHAR bDriveNumber;
436 UCHAR bReserved[3];
437 ULONG dwReserved[4];
438 UCHAR bBuffer[1];
439 } SENDCMDINPARAMS, *PSENDCMDINPARAMS, *LPSENDCMDINPARAMS;
440
441 ASSERT_SIZEOF(SENDCMDINPARAMS, 32+1);
442
443 typedef struct _SENDCMDINPARAMS_EX {
444 DWORD cBufferSize;
445 IDEREGS irDriveRegs;
446 BYTE bDriveNumber;
447 BYTE bPortNumber; // 3ware specific: port number
448 WORD wIdentifier; // Vendor specific identifier
449 DWORD dwReserved[4];
450 BYTE bBuffer[1];
451 } SENDCMDINPARAMS_EX, *PSENDCMDINPARAMS_EX, *LPSENDCMDINPARAMS_EX;
452
453 ASSERT_SIZEOF(SENDCMDINPARAMS_EX, sizeof(SENDCMDINPARAMS));
454
455
456 /* DRIVERSTATUS.bDriverError constants (just for info, not used)
457 #define SMART_NO_ERROR 0
458 #define SMART_IDE_ERROR 1
459 #define SMART_INVALID_FLAG 2
460 #define SMART_INVALID_COMMAND 3
461 #define SMART_INVALID_BUFFER 4
462 #define SMART_INVALID_DRIVE 5
463 #define SMART_INVALID_IOCTL 6
464 #define SMART_ERROR_NO_MEM 7
465 #define SMART_INVALID_REGISTER 8
466 #define SMART_NOT_SUPPORTED 9
467 #define SMART_NO_IDE_DEVICE 10
468 */
469
470 typedef struct _DRIVERSTATUS {
471 UCHAR bDriverError;
472 UCHAR bIDEError;
473 UCHAR bReserved[2];
474 ULONG dwReserved[2];
475 } DRIVERSTATUS, *PDRIVERSTATUS, *LPDRIVERSTATUS;
476
477 typedef struct _SENDCMDOUTPARAMS {
478 ULONG cBufferSize;
479 DRIVERSTATUS DriverStatus;
480 UCHAR bBuffer[1];
481 } SENDCMDOUTPARAMS, *PSENDCMDOUTPARAMS, *LPSENDCMDOUTPARAMS;
482
483 ASSERT_SIZEOF(SENDCMDOUTPARAMS, 16+1);
484
485 #pragma pack()
486
487
488 /////////////////////////////////////////////////////////////////////////////
489
490 static void print_ide_regs(const IDEREGS * r, int out)
491 {
492 pout("%s=0x%02x,%s=0x%02x, SC=0x%02x, NS=0x%02x, CL=0x%02x, CH=0x%02x, SEL=0x%02x\n",
493 (out?"STS":"CMD"), r->bCommandReg, (out?"ERR":" FR"), r->bFeaturesReg,
494 r->bSectorCountReg, r->bSectorNumberReg, r->bCylLowReg, r->bCylHighReg, r->bDriveHeadReg);
495 }
496
497 static void print_ide_regs_io(const IDEREGS * ri, const IDEREGS * ro)
498 {
499 pout(" Input : "); print_ide_regs(ri, 0);
500 if (ro) {
501 pout(" Output: "); print_ide_regs(ro, 1);
502 }
503 }
504
505 /////////////////////////////////////////////////////////////////////////////
506
507 // call SMART_GET_VERSION, return device map or -1 on error
508
509 static int smart_get_version(HANDLE hdevice, unsigned long * portmap = 0)
510 {
511 GETVERSIONOUTPARAMS vers;
512 const GETVERSIONINPARAMS_EX & vers_ex = (const GETVERSIONINPARAMS_EX &)vers;
513 DWORD num_out;
514
515 memset(&vers, 0, sizeof(vers));
516 if (!DeviceIoControl(hdevice, SMART_GET_VERSION,
517 NULL, 0, &vers, sizeof(vers), &num_out, NULL)) {
518 if (con->reportataioctl)
519 pout(" SMART_GET_VERSION failed, Error=%ld\n", GetLastError());
520 errno = ENOSYS;
521 return -1;
522 }
523 assert(num_out == sizeof(GETVERSIONOUTPARAMS));
524
525 if (portmap) {
526 // Return bitmask of valid RAID ports
527 if (vers_ex.wIdentifier != SMART_VENDOR_3WARE) {
528 pout(" SMART_GET_VERSION returns unknown Identifier = %04x\n"
529 " This is no 3ware 9000 controller or driver has no SMART support.\n", vers_ex.wIdentifier);
530 errno = ENOENT;
531 return -1;
532 }
533 *portmap = vers_ex.dwDeviceMapEx;
534 }
535
536 if (con->reportataioctl > 1) {
537 pout(" SMART_GET_VERSION suceeded, bytes returned: %lu\n"
538 " Vers = %d.%d, Caps = 0x%lx, DeviceMap = 0x%02x\n",
539 num_out, vers.bVersion, vers.bRevision,
540 vers.fCapabilities, vers.bIDEDeviceMap);
541 if (vers_ex.wIdentifier == SMART_VENDOR_3WARE)
542 pout(" Identifier = %04x(3WARE), ControllerId=%u, DeviceMapEx = 0x%08lx\n",
543 vers_ex.wIdentifier, vers_ex.wControllerId, vers_ex.dwDeviceMapEx);
544 }
545
546 // TODO: Check vers.fCapabilities here?
547 return vers.bIDEDeviceMap;
548 }
549
550
551 // call SMART_* ioctl
552
553 static int smart_ioctl(HANDLE hdevice, int drive, IDEREGS * regs, char * data, unsigned datasize, int port)
554 {
555 SENDCMDINPARAMS inpar;
556 SENDCMDINPARAMS_EX & inpar_ex = (SENDCMDINPARAMS_EX &)inpar;
557
558 unsigned char outbuf[sizeof(SENDCMDOUTPARAMS)-1 + 512];
559 const SENDCMDOUTPARAMS * outpar;
560 DWORD code, num_out;
561 unsigned int size_out;
562 const char * name;
563
564 memset(&inpar, 0, sizeof(inpar));
565 inpar.irDriveRegs = *regs;
566 // drive is set to 0-3 on Win9x only
567 inpar.irDriveRegs.bDriveHeadReg = 0xA0 | ((drive & 1) << 4);
568 inpar.bDriveNumber = drive;
569
570 if (port >= 0) {
571 // Set RAID port
572 inpar_ex.wIdentifier = SMART_VENDOR_3WARE;
573 inpar_ex.bPortNumber = port;
574 }
575
576 assert(datasize == 0 || datasize == 512);
577 if (datasize) {
578 code = SMART_RCV_DRIVE_DATA; name = "SMART_RCV_DRIVE_DATA";
579 inpar.cBufferSize = size_out = 512;
580 }
581 else {
582 code = SMART_SEND_DRIVE_COMMAND; name = "SMART_SEND_DRIVE_COMMAND";
583 if (regs->bFeaturesReg == ATA_SMART_STATUS) {
584 size_out = sizeof(IDEREGS); // ioctl returns new IDEREGS as data
585 // Note: cBufferSize must be 0 on Win9x
586 inpar.cBufferSize = size_out;
587 }
588 else
589 size_out = 0;
590 }
591
592 memset(&outbuf, 0, sizeof(outbuf));
593
594 if (!DeviceIoControl(hdevice, code, &inpar, sizeof(SENDCMDINPARAMS)-1,
595 outbuf, sizeof(SENDCMDOUTPARAMS)-1 + size_out, &num_out, NULL)) {
596 // CAUTION: DO NOT change "regs" Parameter in this case, see ata_command_interface()
597 long err = GetLastError();
598 if (con->reportataioctl && (err != ERROR_INVALID_PARAMETER || con->reportataioctl > 1)) {
599 pout(" %s failed, Error=%ld\n", name, err);
600 print_ide_regs_io(regs, NULL);
601 }
602 errno = ( err == ERROR_INVALID_FUNCTION /*9x*/
603 || err == ERROR_INVALID_PARAMETER/*NT/2K/XP*/ ? ENOSYS : EIO);
604 return -1;
605 }
606 // NOTE: On Win9x, inpar.irDriveRegs now contains the returned regs
607
608 outpar = (const SENDCMDOUTPARAMS *)outbuf;
609
610 if (outpar->DriverStatus.bDriverError) {
611 if (con->reportataioctl) {
612 pout(" %s failed, DriverError=0x%02x, IDEError=0x%02x\n", name,
613 outpar->DriverStatus.bDriverError, outpar->DriverStatus.bIDEError);
614 print_ide_regs_io(regs, NULL);
615 }
616 errno = (!outpar->DriverStatus.bIDEError ? ENOSYS : EIO);
617 return -1;
618 }
619
620 if (con->reportataioctl > 1) {
621 pout(" %s suceeded, bytes returned: %lu (buffer %lu)\n", name,
622 num_out, outpar->cBufferSize);
623 print_ide_regs_io(regs, (regs->bFeaturesReg == ATA_SMART_STATUS ?
624 (const IDEREGS *)(outpar->bBuffer) : NULL));
625 }
626
627 if (datasize)
628 memcpy(data, outpar->bBuffer, 512);
629 else if (regs->bFeaturesReg == ATA_SMART_STATUS) {
630 if (nonempty(const_cast<unsigned char *>(outpar->bBuffer), sizeof(IDEREGS)))
631 *regs = *(const IDEREGS *)(outpar->bBuffer);
632 else { // Workaround for driver not returning regs
633 if (con->reportataioctl)
634 pout(" WARNING: driver does not return ATA registers in output buffer!\n");
635 *regs = inpar.irDriveRegs;
636 }
637 }
638
639 return 0;
640 }
641
642
643 /////////////////////////////////////////////////////////////////////////////
644
645 // IDE PASS THROUGH (2000, XP, undocumented)
646 //
647 // Based on WinATA.cpp, 2002 c't/Matthias Withopf
648 // ftp://ftp.heise.de/pub/ct/listings/0207-218.zip
649
650 #define FILE_DEVICE_CONTROLLER 4
651 #define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER
652
653 #define IOCTL_IDE_PASS_THROUGH \
654 CTL_CODE(IOCTL_SCSI_BASE, 0x040A, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
655
656 ASSERT_CONST(IOCTL_IDE_PASS_THROUGH, 0x04d028);
657
658 #pragma pack(1)
659
660 typedef struct {
661 IDEREGS IdeReg;
662 ULONG DataBufferSize;
663 UCHAR DataBuffer[1];
664 } ATA_PASS_THROUGH;
665
666 ASSERT_SIZEOF(ATA_PASS_THROUGH, 12+1);
667
668 #pragma pack()
669
670
671 /////////////////////////////////////////////////////////////////////////////
672
673 static int ide_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize)
674 {
675 if (datasize > 512) {
676 errno = EINVAL;
677 return -1;
678 }
679 unsigned int size = sizeof(ATA_PASS_THROUGH)-1 + datasize;
680 ATA_PASS_THROUGH * buf = (ATA_PASS_THROUGH *)VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
681 DWORD num_out;
682 const unsigned char magic = 0xcf;
683
684 if (!buf) {
685 errno = ENOMEM;
686 return -1;
687 }
688
689 buf->IdeReg = *regs;
690 buf->DataBufferSize = datasize;
691 if (datasize)
692 buf->DataBuffer[0] = magic;
693
694 if (!DeviceIoControl(hdevice, IOCTL_IDE_PASS_THROUGH,
695 buf, size, buf, size, &num_out, NULL)) {
696 long err = GetLastError();
697 if (con->reportataioctl) {
698 pout(" IOCTL_IDE_PASS_THROUGH failed, Error=%ld\n", err);
699 print_ide_regs_io(regs, NULL);
700 }
701 VirtualFree(buf, 0, MEM_RELEASE);
702 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
703 return -1;
704 }
705
706 // Check ATA status
707 if (buf->IdeReg.bCommandReg/*Status*/ & 0x01) {
708 if (con->reportataioctl) {
709 pout(" IOCTL_IDE_PASS_THROUGH command failed:\n");
710 print_ide_regs_io(regs, &buf->IdeReg);
711 }
712 VirtualFree(buf, 0, MEM_RELEASE);
713 errno = EIO;
714 return -1;
715 }
716
717 // Check and copy data
718 if (datasize) {
719 if ( num_out != size
720 || (buf->DataBuffer[0] == magic && !nonempty(buf->DataBuffer+1, datasize-1))) {
721 if (con->reportataioctl) {
722 pout(" IOCTL_IDE_PASS_THROUGH output data missing (%lu, %lu)\n",
723 num_out, buf->DataBufferSize);
724 print_ide_regs_io(regs, &buf->IdeReg);
725 }
726 VirtualFree(buf, 0, MEM_RELEASE);
727 errno = EIO;
728 return -1;
729 }
730 memcpy(data, buf->DataBuffer, datasize);
731 }
732
733 if (con->reportataioctl > 1) {
734 pout(" IOCTL_IDE_PASS_THROUGH suceeded, bytes returned: %lu (buffer %lu)\n",
735 num_out, buf->DataBufferSize);
736 print_ide_regs_io(regs, &buf->IdeReg);
737 }
738 *regs = buf->IdeReg;
739
740 // Caution: VirtualFree() fails if parameter "dwSize" is nonzero
741 VirtualFree(buf, 0, MEM_RELEASE);
742 return 0;
743 }
744
745
746 /////////////////////////////////////////////////////////////////////////////
747
748 // ATA PASS THROUGH (Win2003, XP SP2)
749
750 #define IOCTL_ATA_PASS_THROUGH \
751 CTL_CODE(IOCTL_SCSI_BASE, 0x040B, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
752
753 ASSERT_CONST(IOCTL_ATA_PASS_THROUGH, 0x04d02c);
754
755 typedef struct _ATA_PASS_THROUGH_EX {
756 USHORT Length;
757 USHORT AtaFlags;
758 UCHAR PathId;
759 UCHAR TargetId;
760 UCHAR Lun;
761 UCHAR ReservedAsUchar;
762 ULONG DataTransferLength;
763 ULONG TimeOutValue;
764 ULONG ReservedAsUlong;
765 ULONG/*_PTR*/ DataBufferOffset;
766 UCHAR PreviousTaskFile[8];
767 UCHAR CurrentTaskFile[8];
768 } ATA_PASS_THROUGH_EX, *PATA_PASS_THROUGH_EX;
769
770 ASSERT_SIZEOF(ATA_PASS_THROUGH_EX, 40);
771
772 #define ATA_FLAGS_DRDY_REQUIRED 0x01
773 #define ATA_FLAGS_DATA_IN 0x02
774 #define ATA_FLAGS_DATA_OUT 0x04
775 #define ATA_FLAGS_48BIT_COMMAND 0x08
776
777
778 /////////////////////////////////////////////////////////////////////////////
779
780 static int ata_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, int datasize)
781 {
782 typedef struct {
783 ATA_PASS_THROUGH_EX apt;
784 ULONG Filler;
785 UCHAR ucDataBuf[512];
786 } ATA_PASS_THROUGH_EX_WITH_BUFFERS;
787
788 const unsigned char magic = 0xcf;
789
790 ATA_PASS_THROUGH_EX_WITH_BUFFERS ab; memset(&ab, 0, sizeof(ab));
791 ab.apt.Length = sizeof(ATA_PASS_THROUGH_EX);
792 //ab.apt.PathId = 0;
793 //ab.apt.TargetId = 0;
794 //ab.apt.Lun = 0;
795 ab.apt.TimeOutValue = 10;
796 unsigned size = offsetof(ATA_PASS_THROUGH_EX_WITH_BUFFERS, ucDataBuf);
797 ab.apt.DataBufferOffset = size;
798
799 if (datasize > 0) {
800 if (datasize > (int)sizeof(ab.ucDataBuf)) {
801 errno = EINVAL;
802 return -1;
803 }
804 ab.apt.AtaFlags = ATA_FLAGS_DATA_IN;
805 ab.apt.DataTransferLength = datasize;
806 size += datasize;
807 ab.ucDataBuf[0] = magic;
808 }
809 else if (datasize < 0) {
810 if (-datasize > (int)sizeof(ab.ucDataBuf)) {
811 errno = EINVAL;
812 return -1;
813 }
814 ab.apt.AtaFlags = ATA_FLAGS_DATA_OUT;
815 ab.apt.DataTransferLength = -datasize;
816 size += -datasize;
817 memcpy(ab.ucDataBuf, data, -datasize);
818 }
819 else {
820 assert(ab.apt.AtaFlags == 0);
821 assert(ab.apt.DataTransferLength == 0);
822 }
823
824 assert(sizeof(ab.apt.CurrentTaskFile) == sizeof(IDEREGS));
825 IDEREGS * ctfregs = (IDEREGS *)ab.apt.CurrentTaskFile;
826 *ctfregs = *regs;
827
828 DWORD num_out;
829 if (!DeviceIoControl(hdevice, IOCTL_ATA_PASS_THROUGH,
830 &ab, size, &ab, size, &num_out, NULL)) {
831 long err = GetLastError();
832 if (con->reportataioctl) {
833 pout(" IOCTL_ATA_PASS_THROUGH failed, Error=%ld\n", err);
834 print_ide_regs_io(regs, NULL);
835 }
836 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
837 return -1;
838 }
839
840 // Check ATA status
841 if (ctfregs->bCommandReg/*Status*/ & 0x01) {
842 if (con->reportataioctl) {
843 pout(" IOCTL_ATA_PASS_THROUGH command failed:\n");
844 print_ide_regs_io(regs, ctfregs);
845 }
846 errno = EIO;
847 return -1;
848 }
849
850 // Check and copy data
851 if (datasize > 0) {
852 if ( num_out != size
853 || (ab.ucDataBuf[0] == magic && !nonempty(ab.ucDataBuf+1, datasize-1))) {
854 if (con->reportataioctl) {
855 pout(" IOCTL_ATA_PASS_THROUGH output data missing (%lu)\n", num_out);
856 print_ide_regs_io(regs, ctfregs);
857 }
858 errno = EIO;
859 return -1;
860 }
861 memcpy(data, ab.ucDataBuf, datasize);
862 }
863
864 if (con->reportataioctl > 1) {
865 pout(" IOCTL_ATA_PASS_THROUGH suceeded, bytes returned: %lu\n", num_out);
866 print_ide_regs_io(regs, ctfregs);
867 }
868 *regs = *ctfregs;
869
870 return 0;
871 }
872
873
874 /////////////////////////////////////////////////////////////////////////////
875
876 // ATA PASS THROUGH via SCSI PASS THROUGH (WinNT4 only)
877
878 // Declarations from:
879 // http://cvs.sourceforge.net/viewcvs.py/mingw/w32api/include/ddk/ntddscsi.h?rev=1.2
880
881 #define IOCTL_SCSI_PASS_THROUGH \
882 CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
883
884 ASSERT_CONST(IOCTL_SCSI_PASS_THROUGH, 0x04d004);
885
886 #define SCSI_IOCTL_DATA_OUT 0
887 #define SCSI_IOCTL_DATA_IN 1
888 #define SCSI_IOCTL_DATA_UNSPECIFIED 2
889 // undocumented SCSI opcode to for ATA passthrough
890 #define SCSIOP_ATA_PASSTHROUGH 0xCC
891
892 typedef struct _SCSI_PASS_THROUGH {
893 USHORT Length;
894 UCHAR ScsiStatus;
895 UCHAR PathId;
896 UCHAR TargetId;
897 UCHAR Lun;
898 UCHAR CdbLength;
899 UCHAR SenseInfoLength;
900 UCHAR DataIn;
901 ULONG DataTransferLength;
902 ULONG TimeOutValue;
903 ULONG/*_PTR*/ DataBufferOffset;
904 ULONG SenseInfoOffset;
905 UCHAR Cdb[16];
906 } SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;
907
908 ASSERT_SIZEOF(SCSI_PASS_THROUGH, 44);
909
910
911 /////////////////////////////////////////////////////////////////////////////
912
913 static int ata_via_scsi_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize)
914 {
915 typedef struct {
916 SCSI_PASS_THROUGH spt;
917 ULONG Filler;
918 UCHAR ucSenseBuf[32];
919 UCHAR ucDataBuf[512];
920 } SCSI_PASS_THROUGH_WITH_BUFFERS;
921
922 SCSI_PASS_THROUGH_WITH_BUFFERS sb;
923 IDEREGS * cdbregs;
924 unsigned int size;
925 DWORD num_out;
926 const unsigned char magic = 0xcf;
927
928 memset(&sb, 0, sizeof(sb));
929 sb.spt.Length = sizeof(SCSI_PASS_THROUGH);
930 //sb.spt.PathId = 0;
931 sb.spt.TargetId = 1;
932 //sb.spt.Lun = 0;
933 sb.spt.CdbLength = 10; sb.spt.SenseInfoLength = 24;
934 sb.spt.TimeOutValue = 10;
935 sb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf);
936 size = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf);
937 sb.spt.DataBufferOffset = size;
938
939 if (datasize) {
940 if (datasize > sizeof(sb.ucDataBuf)) {
941 errno = EINVAL;
942 return -1;
943 }
944 sb.spt.DataIn = SCSI_IOCTL_DATA_IN;
945 sb.spt.DataTransferLength = datasize;
946 size += datasize;
947 sb.ucDataBuf[0] = magic;
948 }
949 else {
950 sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
951 //sb.spt.DataTransferLength = 0;
952 }
953
954 // Use pseudo SCSI command followed by registers
955 sb.spt.Cdb[0] = SCSIOP_ATA_PASSTHROUGH;
956 cdbregs = (IDEREGS *)(sb.spt.Cdb+2);
957 *cdbregs = *regs;
958
959 if (!DeviceIoControl(hdevice, IOCTL_SCSI_PASS_THROUGH,
960 &sb, size, &sb, size, &num_out, NULL)) {
961 long err = GetLastError();
962 if (con->reportataioctl)
963 pout(" ATA via IOCTL_SCSI_PASS_THROUGH failed, Error=%ld\n", err);
964 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
965 return -1;
966 }
967
968 // Cannot check ATA status, because command does not return IDEREGS
969
970 // Check and copy data
971 if (datasize) {
972 if ( num_out != size
973 || (sb.ucDataBuf[0] == magic && !nonempty(sb.ucDataBuf+1, datasize-1))) {
974 if (con->reportataioctl) {
975 pout(" ATA via IOCTL_SCSI_PASS_THROUGH output data missing (%lu)\n", num_out);
976 print_ide_regs_io(regs, NULL);
977 }
978 errno = EIO;
979 return -1;
980 }
981 memcpy(data, sb.ucDataBuf, datasize);
982 }
983
984 if (con->reportataioctl > 1) {
985 pout(" ATA via IOCTL_SCSI_PASS_THROUGH suceeded, bytes returned: %lu\n", num_out);
986 print_ide_regs_io(regs, NULL);
987 }
988 return 0;
989 }
990
991
992 /////////////////////////////////////////////////////////////////////////////
993
994 // ATA PASS THROUGH via 3ware specific SCSI MINIPORT ioctl
995
996 #define IOCTL_SCSI_MINIPORT \
997 CTL_CODE(IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
998
999 ASSERT_CONST(IOCTL_SCSI_MINIPORT, 0x04d008);
1000
1001 typedef struct _SRB_IO_CONTROL {
1002 ULONG HeaderLength;
1003 UCHAR Signature[8];
1004 ULONG Timeout;
1005 ULONG ControlCode;
1006 ULONG ReturnCode;
1007 ULONG Length;
1008 } SRB_IO_CONTROL, *PSRB_IO_CONTROL;
1009
1010 ASSERT_SIZEOF(SRB_IO_CONTROL, 28);
1011
1012 /////////////////////////////////////////////////////////////////////////////
1013
1014 static int ata_via_3ware_miniport_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, int datasize, int port)
1015 {
1016 struct {
1017 SRB_IO_CONTROL srbc;
1018 IDEREGS regs;
1019 UCHAR buffer[512];
1020 } sb;
1021 ASSERT_SIZEOF(sb, sizeof(SRB_IO_CONTROL)+sizeof(IDEREGS)+512);
1022
1023 if (!(0 <= datasize && datasize <= (int)sizeof(sb.buffer) && port >= 0)) {
1024 errno = EINVAL;
1025 return -1;
1026 }
1027 memset(&sb, 0, sizeof(sb));
1028 strcpy((char *)sb.srbc.Signature, "<3ware>");
1029 sb.srbc.HeaderLength = sizeof(SRB_IO_CONTROL);
1030 sb.srbc.Timeout = 60; // seconds
1031 sb.srbc.ControlCode = 0xA0000000;
1032 sb.srbc.ReturnCode = 0;
1033 sb.srbc.Length = sizeof(IDEREGS) + (datasize > 0 ? datasize : 1);
1034 sb.regs = *regs;
1035 sb.regs.bReserved = port;
1036
1037 DWORD num_out;
1038 if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
1039 &sb, sizeof(sb), &sb, sizeof(sb), &num_out, NULL)) {
1040 long err = GetLastError();
1041 if (con->reportataioctl) {
1042 pout(" ATA via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err);
1043 print_ide_regs_io(regs, NULL);
1044 }
1045 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
1046 return -1;
1047 }
1048
1049 if (sb.srbc.ReturnCode) {
1050 if (con->reportataioctl) {
1051 pout(" ATA via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08lx\n", sb.srbc.ReturnCode);
1052 print_ide_regs_io(regs, NULL);
1053 }
1054 errno = EIO;
1055 return -1;
1056 }
1057
1058 // Copy data
1059 if (datasize > 0)
1060 memcpy(data, sb.buffer, datasize);
1061
1062 if (con->reportataioctl > 1) {
1063 pout(" ATA via IOCTL_SCSI_MINIPORT suceeded, bytes returned: %lu\n", num_out);
1064 print_ide_regs_io(regs, &sb.regs);
1065 }
1066 *regs = sb.regs;
1067
1068 return 0;
1069 }
1070
1071
1072 /////////////////////////////////////////////////////////////////////////////
1073
1074 // 3ware specific call to update the devicemap returned by SMART_GET_VERSION.
1075 // 3DM/CLI "Rescan Controller" function does not to always update it.
1076
1077 static int update_3ware_devicemap_ioctl(HANDLE hdevice)
1078 {
1079 SRB_IO_CONTROL srbc;
1080 memset(&srbc, 0, sizeof(srbc));
1081 strcpy((char *)srbc.Signature, "<3ware>");
1082 srbc.HeaderLength = sizeof(SRB_IO_CONTROL);
1083 srbc.Timeout = 60; // seconds
1084 srbc.ControlCode = 0xCC010014;
1085 srbc.ReturnCode = 0;
1086 srbc.Length = 0;
1087
1088 DWORD num_out;
1089 if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
1090 &srbc, sizeof(srbc), &srbc, sizeof(srbc), &num_out, NULL)) {
1091 long err = GetLastError();
1092 if (con->reportataioctl)
1093 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err);
1094 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
1095 return -1;
1096 }
1097 if (srbc.ReturnCode) {
1098 if (con->reportataioctl)
1099 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08lx\n", srbc.ReturnCode);
1100 errno = EIO;
1101 return -1;
1102 }
1103 if (con->reportataioctl > 1)
1104 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT suceeded\n");
1105 return 0;
1106 }
1107
1108
1109 /////////////////////////////////////////////////////////////////////////////
1110
1111 // Call GetDevicePowerState() if available (Win98/ME/2000/XP/2003)
1112 // returns: 1=active, 0=standby, -1=error
1113 // (This would also work for SCSI drives)
1114
1115 static int get_device_power_state(HANDLE hdevice)
1116 {
1117 static HINSTANCE h_kernel_dll = 0;
1118 #ifdef __CYGWIN__
1119 static DWORD kernel_dll_pid = 0;
1120 #endif
1121 static BOOL (WINAPI * GetDevicePowerState_p)(HANDLE, BOOL *) = 0;
1122
1123 BOOL state = TRUE;
1124
1125 if (!GetDevicePowerState_p
1126 #ifdef __CYGWIN__
1127 || kernel_dll_pid != GetCurrentProcessId() // detect fork()
1128 #endif
1129 ) {
1130 if (h_kernel_dll == INVALID_HANDLE_VALUE) {
1131 errno = ENOSYS;
1132 return -1;
1133 }
1134 if (!(h_kernel_dll = LoadLibraryA("KERNEL32.DLL"))) {
1135 pout("Cannot load KERNEL32.DLL, Error=%ld\n", GetLastError());
1136 h_kernel_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
1137 errno = ENOSYS;
1138 return -1;
1139 }
1140 if (!(GetDevicePowerState_p = (BOOL (WINAPI *)(HANDLE, BOOL *))
1141 GetProcAddress(h_kernel_dll, "GetDevicePowerState"))) {
1142 if (con->reportataioctl)
1143 pout(" GetDevicePowerState() not found, Error=%ld\n", GetLastError());
1144 FreeLibrary(h_kernel_dll);
1145 h_kernel_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
1146 errno = ENOSYS;
1147 return -1;
1148 }
1149 #ifdef __CYGWIN__
1150 kernel_dll_pid = GetCurrentProcessId();
1151 #endif
1152 }
1153
1154 if (!GetDevicePowerState_p(hdevice, &state)) {
1155 long err = GetLastError();
1156 if (con->reportataioctl)
1157 pout(" GetDevicePowerState() failed, Error=%ld\n", err);
1158 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
1159 // TODO: This may not work as expected on transient errors,
1160 // because smartd interprets -1 as SLEEP mode regardless of errno.
1161 return -1;
1162 }
1163
1164 if (con->reportataioctl > 1)
1165 pout(" GetDevicePowerState() succeeded, state=%d\n", state);
1166 return state;
1167 }
1168
1169
1170 /////////////////////////////////////////////////////////////////////////////
1171
1172 // TODO: Put in a struct indexed by fd (or better a C++ object of course ;-)
1173 static HANDLE h_ata_ioctl = 0;
1174 static const char * ata_def_options;
1175 static char * ata_cur_options;
1176 static int ata_driveno; // Drive number
1177 static char ata_smartver_state[10]; // SMART_GET_VERSION: 0=unknown, 1=OK, 2=failed
1178
1179 // Print SMARTVSD error message, return errno
1180
1181 static int smartvsd_error()
1182 {
1183 char path[MAX_PATH];
1184 unsigned len;
1185 if (!(5 <= (len = GetSystemDirectoryA(path, MAX_PATH)) && len < MAX_PATH/2))
1186 return ENOENT;
1187 // SMARTVSD.VXD present?
1188 strcpy(path+len, "\\IOSUBSYS\\SMARTVSD.VXD");
1189 if (!access(path, 0)) {
1190 // Yes, standard IDE driver used?
1191 HANDLE h;
1192 if ( (h = CreateFileA("\\\\.\\ESDI_506",
1193 GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1194 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE
1195 && GetLastError() == ERROR_FILE_NOT_FOUND ) {
1196 pout("Standard IDE driver ESDI_506.PDR not used, or no IDE/ATA drives present.\n");
1197 return ENOENT;
1198 }
1199 else {
1200 if (h != INVALID_HANDLE_VALUE) // should not happen
1201 CloseHandle(h);
1202 pout("SMART driver SMARTVSD.VXD is installed, but not loaded.\n");
1203 return ENOSYS;
1204 }
1205 }
1206 else {
1207 strcpy(path+len, "\\SMARTVSD.VXD");
1208 if (!access(path, 0)) {
1209 // Some Windows versions install SMARTVSD.VXD in SYSTEM directory
1210 // (http://support.microsoft.com/kb/265854/en-us).
1211 path[len] = 0;
1212 pout("SMART driver is not properly installed,\n"
1213 " move SMARTVSD.VXD from \"%s\" to \"%s\\IOSUBSYS\"\n"
1214 " and reboot Windows.\n", path, path);
1215 }
1216 else {
1217 // Some Windows versions do not provide SMARTVSD.VXD
1218 // (http://support.microsoft.com/kb/199886/en-us).
1219 path[len] = 0;
1220 pout("SMARTVSD.VXD is missing in folder \"%s\\IOSUBSYS\".\n", path);
1221 }
1222 return ENOSYS;
1223 }
1224 }
1225
1226
1227 // Get default ATA device options
1228
1229 static const char * ata_get_def_options()
1230 {
1231 DWORD ver = GetVersion();
1232 if ((ver & 0x80000000) || (ver & 0xff) < 4) // Win9x/ME
1233 return "s"; // SMART_* only
1234 else if ((ver & 0xff) == 4) // WinNT4
1235 return "sc"; // SMART_*, SCSI_PASS_THROUGH
1236 else // WinXP, 2003, Vista
1237 return "psai"; // GetDevicePowerState(), SMART_*, ATA_, IDE_PASS_THROUGH
1238 }
1239
1240
1241 // Open ATA device
1242
1243 static int ata_open(int drive, const char * options, int port)
1244 {
1245 int win9x;
1246 char devpath[30];
1247 int devmap;
1248
1249 // TODO: This version does not allow to open more than 1 ATA devices
1250 if (h_ata_ioctl) {
1251 errno = ENFILE;
1252 return -1;
1253 }
1254
1255 win9x = ((GetVersion() & 0x80000000) != 0);
1256
1257 if (!(0 <= drive && drive <= (win9x ? 7 : 9))) {
1258 errno = ENOENT;
1259 return -1;
1260 }
1261
1262 // path depends on Windows Version
1263 if (win9x)
1264 // Use patched "smartvse.vxd" for drives 4-7, see INSTALL file for details
1265 strcpy(devpath, (drive <= 3 ? "\\\\.\\SMARTVSD" : "\\\\.\\SMARTVSE"));
1266 else
1267 snprintf(devpath, sizeof(devpath)-1, "\\\\.\\PhysicalDrive%d", drive);
1268
1269 // Open device
1270 if ((h_ata_ioctl = CreateFileA(devpath,
1271 GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1272 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
1273 long err = GetLastError();
1274 pout("Cannot open device %s, Error=%ld\n", devpath, err);
1275 if (err == ERROR_FILE_NOT_FOUND)
1276 errno = (win9x && drive <= 3 ? smartvsd_error() : ENOENT);
1277 else if (err == ERROR_ACCESS_DENIED) {
1278 if (!win9x)
1279 pout("Administrator rights are necessary to access physical drives.\n");
1280 errno = EACCES;
1281 }
1282 else
1283 errno = EIO;
1284 h_ata_ioctl = 0;
1285 return -1;
1286 }
1287
1288 if (con->reportataioctl > 1)
1289 pout("%s: successfully opened\n", devpath);
1290
1291 // Save options
1292 if (!*options) {
1293 // Set default options according to Windows version
1294 if (!ata_def_options)
1295 ata_def_options = ata_get_def_options();
1296 options = (port < 0 ? ata_def_options : "s3"); // RAID: SMART_* and SCSI_MINIPORT
1297 }
1298 ata_cur_options = strdup(options);
1299
1300 // NT4/2000/XP: SMART_GET_VERSION may spin up disk, so delay until first real SMART_* call
1301 ata_driveno = drive;
1302 if (!win9x && port < 0)
1303 return 0;
1304
1305 // Win9X/ME: Get drive map
1306 // RAID: Get port map
1307 unsigned long portmap = 0;
1308 devmap = smart_get_version(h_ata_ioctl, (port >= 0 ? &portmap : 0));
1309 if (devmap < 0) {
1310 if (!is_permissive()) {
1311 ata_close(0);
1312 errno = ENOSYS;
1313 return -1;
1314 }
1315 devmap = 0x0f;
1316 }
1317 ata_smartver_state[drive] = 1;
1318
1319 if (port >= 0) {
1320 // 3ware RAID: update devicemap first
1321 if (!update_3ware_devicemap_ioctl(h_ata_ioctl)) {
1322 unsigned long portmap1 = 0;
1323 if (smart_get_version(h_ata_ioctl, &portmap1) >= 0)
1324 portmap = portmap1;
1325 }
1326 // Check port existence
1327 if (!(portmap & (1L << port))) {
1328 pout("%s: Port %d is empty or does not exist\n", devpath, port);
1329 if (!is_permissive()) {
1330 ata_close(0);
1331 errno = ENOENT;
1332 return -1;
1333 }
1334 }
1335 // Encode port into pseudo fd
1336 return (ATARAID_FDOFFSET | port);
1337 }
1338
1339 // Win9x/ME: Check device presence & type
1340 if (((devmap >> (drive & 0x3)) & 0x11) != 0x01) {
1341 unsigned char atapi = (devmap >> (drive & 0x3)) & 0x10;
1342 pout("%s: Drive %d %s (IDEDeviceMap=0x%02x).\n", devpath,
1343 drive, (atapi?"is an ATAPI device":"does not exist"), devmap);
1344 // Win9x drive existence check may not work as expected
1345 // The atapi.sys driver incorrectly fills in the bIDEDeviceMap with 0x01
1346 // (The related KB Article Q196120 is no longer available)
1347 if (!is_permissive()) {
1348 ata_close(0);
1349 errno = (atapi ? ENOSYS : ENOENT);
1350 return -1;
1351 }
1352 }
1353 // Use drive number as fd for ioctl
1354 return (drive & 0x3);
1355 }
1356
1357
1358 static void ata_close(int fd)
1359 {
1360 ARGUSED(fd);
1361 CloseHandle(h_ata_ioctl);
1362 h_ata_ioctl = 0;
1363 if (ata_cur_options) {
1364 free(ata_cur_options);
1365 ata_cur_options = 0;
1366 }
1367 }
1368
1369
1370 // Scan for ATA drives, fill bitmask of drives present, return #drives
1371
1372 static int ata_scan(unsigned long * drives, int * rdriveno, unsigned long * rdrives)
1373 {
1374 int win9x = ((GetVersion() & 0x80000000) != 0);
1375 int cnt = 0, i;
1376
1377 for (i = 0; i <= 9; i++) {
1378 char devpath[30];
1379 GETVERSIONOUTPARAMS vers;
1380 const GETVERSIONINPARAMS_EX & vers_ex = (const GETVERSIONINPARAMS_EX &)vers;
1381 DWORD num_out;
1382 HANDLE h;
1383 if (win9x)
1384 strcpy(devpath, "\\\\.\\SMARTVSD");
1385 else
1386 snprintf(devpath, sizeof(devpath)-1, "\\\\.\\PhysicalDrive%d", i);
1387
1388 // Open device
1389 if ((h = CreateFileA(devpath,
1390 GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1391 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
1392 if (con->reportataioctl > 1)
1393 pout(" %s: Open failed, Error=%ld\n", devpath, GetLastError());
1394 if (win9x)
1395 break; // SMARTVSD.VXD missing or no ATA devices
1396 continue; // Disk not found or access denied (break;?)
1397 }
1398
1399 // Get drive map
1400 memset(&vers, 0, sizeof(vers));
1401 if (!DeviceIoControl(h, SMART_GET_VERSION,
1402 NULL, 0, &vers, sizeof(vers), &num_out, NULL)) {
1403 if (con->reportataioctl)
1404 pout(" %s: SMART_GET_VERSION failed, Error=%ld\n", devpath, GetLastError());
1405 CloseHandle(h);
1406 if (win9x)
1407 break; // Should not happen
1408 continue; // Non ATA disk or no SMART ioctl support (possibly SCSI disk)
1409 }
1410 CloseHandle(h);
1411
1412 if (con->reportataioctl) {
1413 pout(" %s: SMART_GET_VERSION (%ld bytes):\n"
1414 " Vers = %d.%d, Caps = 0x%lx, DeviceMap = 0x%02x\n",
1415 devpath, num_out, vers.bVersion, vers.bRevision,
1416 vers.fCapabilities, vers.bIDEDeviceMap);
1417 if (vers_ex.wIdentifier == SMART_VENDOR_3WARE)
1418 pout(" Identifier = %04x(3WARE), ControllerId=%u, DeviceMapEx = 0x%08lx\n",
1419 vers_ex.wIdentifier, vers_ex.wControllerId, vers_ex.dwDeviceMapEx);
1420 }
1421
1422 if (win9x) {
1423 // Check ATA device presence, remove ATAPI devices
1424 drives[0] = (vers.bIDEDeviceMap & 0xf) & ~((vers.bIDEDeviceMap >> 4) & 0xf);
1425 cnt = (drives[0]&1) + ((drives[0]>>1)&1) + ((drives[0]>>2)&1) + ((drives[0]>>3)&1);
1426 break;
1427 }
1428
1429 if (vers_ex.wIdentifier == SMART_VENDOR_3WARE) {
1430 // Skip if more than 2 controllers or logical drive from this controller already seen
1431 if (vers_ex.wControllerId >= 2 || rdriveno[vers_ex.wControllerId] >= 0)
1432 continue;
1433 assert(rdrives[vers_ex.wControllerId] == 0);
1434 // Count physical drives
1435 int pcnt = 0;
1436 for (int pi = 0; pi < 32; pi++) {
1437 if (vers_ex.dwDeviceMapEx & (1L << pi))
1438 pcnt++;
1439 }
1440 if (!pcnt)
1441 continue; // Should not happen
1442 rdrives[vers_ex.wControllerId] = vers_ex.dwDeviceMapEx;
1443 rdriveno[vers_ex.wControllerId] = i;
1444 cnt += pcnt-1;
1445 }
1446
1447 // ATA drive exists and driver supports SMART ioctl
1448 drives[0] |= (1L << i);
1449 cnt++;
1450 }
1451
1452 return cnt;
1453 }
1454
1455
1456 /////////////////////////////////////////////////////////////////////////////
1457
1458 // Interface to ATA devices. See os_linux.c
1459 int ata_command_interface(int fd, smart_command_set command, int select, char * data)
1460 {
1461 int port = -1;
1462 if ((fd & ~0x1f) == ATARAID_FDOFFSET) {
1463 // RAID Port encoded into pseudo fd
1464 port = fd & 0x1f;
1465 fd = 0;
1466 }
1467
1468 if (!(0 <= fd && fd <= 3)) {
1469 errno = EBADF;
1470 return -1;
1471 }
1472
1473 // CMD,CYL default to SMART, changed by P?IDENTIFY and CHECK_POWER_MODE
1474 IDEREGS regs; memset(&regs, 0, sizeof(regs));
1475 regs.bCommandReg = ATA_SMART_CMD;
1476 regs.bCylHighReg = SMART_CYL_HI; regs.bCylLowReg = SMART_CYL_LOW;
1477 int datasize = 0;
1478
1479 // Try all IOCTLS by default: SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH
1480 const char * valid_options = "saic";
1481
1482 switch (command) {
1483 case CHECK_POWER_MODE:
1484 // Not a SMART command, needs IDE register return
1485 regs.bCommandReg = ATA_CHECK_POWER_MODE;
1486 regs.bCylLowReg = regs.bCylHighReg = 0;
1487 valid_options = "pai3"; // Try GetDevicePowerState() first, ATA/IDE_PASS_THROUGH may spin up disk
1488 // Note: returns SectorCountReg in data[0]
1489 break;
1490 case READ_VALUES:
1491 regs.bFeaturesReg = ATA_SMART_READ_VALUES;
1492 regs.bSectorNumberReg = regs.bSectorCountReg = 1;
1493 datasize = 512;
1494 break;
1495 case READ_THRESHOLDS:
1496 regs.bFeaturesReg = ATA_SMART_READ_THRESHOLDS;
1497 regs.bSectorNumberReg = regs.bSectorCountReg = 1;
1498 datasize = 512;
1499 break;
1500 case READ_LOG:
1501 regs.bFeaturesReg = ATA_SMART_READ_LOG_SECTOR;
1502 regs.bSectorNumberReg = select;
1503 regs.bSectorCountReg = 1;
1504 valid_options = "saic3";
1505 // Note: SMART_RCV_DRIVE_DATA supports this only on Win9x/ME
1506 datasize = 512;
1507 break;
1508 case WRITE_LOG:
1509 regs.bFeaturesReg = ATA_SMART_WRITE_LOG_SECTOR;
1510 regs.bSectorNumberReg = select;
1511 regs.bSectorCountReg = 1;
1512 valid_options = "a"; // ATA_PASS_THROUGH only, others don't support DATA_OUT
1513 datasize = -512; // DATA_OUT!
1514 break;
1515 case IDENTIFY:
1516 // Note: WinNT4/2000/XP return identify data cached during boot
1517 // (true for SMART_RCV_DRIVE_DATA and IOCTL_IDE_PASS_THROUGH)
1518 regs.bCommandReg = ATA_IDENTIFY_DEVICE;
1519 regs.bCylLowReg = regs.bCylHighReg = 0;
1520 regs.bSectorCountReg = 1;
1521 datasize = 512;
1522 break;
1523 case PIDENTIFY:
1524 regs.bCommandReg = ATA_IDENTIFY_PACKET_DEVICE;
1525 regs.bCylLowReg = regs.bCylHighReg = 0;
1526 regs.bSectorCountReg = 1;
1527 datasize = 512;
1528 break;
1529 case ENABLE:
1530 regs.bFeaturesReg = ATA_SMART_ENABLE;
1531 regs.bSectorNumberReg = 1;
1532 break;
1533 case DISABLE:
1534 regs.bFeaturesReg = ATA_SMART_DISABLE;
1535 regs.bSectorNumberReg = 1;
1536 break;
1537 case STATUS_CHECK:
1538 valid_options = "sai"; // Needs IDE register return
1539 case STATUS:
1540 regs.bFeaturesReg = ATA_SMART_STATUS;
1541 break;
1542 case AUTO_OFFLINE:
1543 regs.bFeaturesReg = ATA_SMART_AUTO_OFFLINE;
1544 regs.bSectorCountReg = select; // YET NOTE - THIS IS A NON-DATA COMMAND!!
1545 break;
1546 case AUTOSAVE:
1547 regs.bFeaturesReg = ATA_SMART_AUTOSAVE;
1548 regs.bSectorCountReg = select; // YET NOTE - THIS IS A NON-DATA COMMAND!!
1549 break;
1550 case IMMEDIATE_OFFLINE:
1551 regs.bFeaturesReg = ATA_SMART_IMMEDIATE_OFFLINE;
1552 regs.bSectorNumberReg = select;
1553 valid_options = "saic3";
1554 // Note: SMART_SEND_DRIVE_COMMAND supports ABORT_SELF_TEST only on Win9x/ME
1555 break;
1556 default:
1557 pout("Unrecognized command %d in win32_ata_command_interface()\n"
1558 "Please contact " PACKAGE_BUGREPORT "\n", command);
1559 errno = ENOSYS;
1560 return -1;
1561 }
1562
1563 // Try all valid ioctls in the order specified in dev_ioctls;
1564 bool powered_up = false;
1565 for (int i = 0; ; i++) {
1566 char opt = ata_cur_options[i];
1567
1568 if (!opt) {
1569 if (command == CHECK_POWER_MODE && powered_up) {
1570 // Power up reported by GetDevicePowerState() and no ioctl available
1571 // to detect the actual mode of the drive => simulate ATA result ACTIVE/IDLE.
1572 regs.bSectorCountReg = 0xff;
1573 break;
1574 }
1575 // No IOCTL found
1576 errno = ENOSYS;
1577 return -1;
1578 }
1579 if (!strchr(valid_options, opt))
1580 // Invalid for this command
1581 continue;
1582
1583 errno = 0;
1584 assert(datasize == 0 || datasize == 512 || (opt == 'a' && datasize == -512));
1585 int rc;
1586 switch (opt) {
1587 default: assert(0);
1588 case 's':
1589 // call SMART_GET_VERSION once for each drive
1590 assert(0 <= ata_driveno && ata_driveno < sizeof(ata_smartver_state));
1591 if (ata_smartver_state[ata_driveno] > 1) {
1592 rc = -1; errno = ENOSYS;
1593 break;
1594 }
1595 if (!ata_smartver_state[ata_driveno]) {
1596 assert(port == -1);
1597 if (smart_get_version(h_ata_ioctl) < 0) {
1598 if (!con->permissive) {
1599 pout("ATA/SATA driver is possibly a SCSI class driver not supporting SMART.\n");
1600 pout("If this is a SCSI disk, try \"scsi<adapter><id>\".\n");
1601 ata_smartver_state[ata_driveno] = 2;
1602 rc = -1; errno = ENOSYS;
1603 break;
1604 }
1605 con->permissive--;
1606 }
1607 ata_smartver_state[ata_driveno] = 1;
1608 }
1609 rc = smart_ioctl(h_ata_ioctl, fd, &regs, data, datasize, port);
1610 break;
1611 case 'a':
1612 rc = ata_pass_through_ioctl(h_ata_ioctl, &regs, data, datasize);
1613 break;
1614 case 'i':
1615 rc = ide_pass_through_ioctl(h_ata_ioctl, &regs, data, datasize);
1616 break;
1617 case 'c':
1618 rc = ata_via_scsi_pass_through_ioctl(h_ata_ioctl, &regs, data, datasize);
1619 break;
1620 case '3':
1621 rc = ata_via_3ware_miniport_ioctl(h_ata_ioctl, &regs, data, datasize, port);
1622 break;
1623 case 'p':
1624 assert(command == CHECK_POWER_MODE && datasize == 0);
1625 rc = get_device_power_state(h_ata_ioctl);
1626 if (rc == 0) {
1627 // Power down reported by GetDevicePowerState(), using a passthrough ioctl would
1628 // spin up the drive => simulate ATA result STANDBY.
1629 regs.bSectorCountReg = 0x00;
1630 }
1631 else if (rc > 0) {
1632 // Power up reported by GetDevicePowerState(), but this reflects the actual mode
1633 // only if it is selected by the device driver => try a passthrough ioctl to get the
1634 // actual mode, if none available simulate ACTIVE/IDLE.
1635 powered_up = true;
1636 errno = ENOSYS; rc = -1;
1637 }
1638 break;
1639 }
1640
1641 if (!rc)
1642 // Working ioctl found
1643 break;
1644
1645 if (errno != ENOSYS)
1646 // Abort on I/O error
1647 return -1;
1648
1649 // CAUTION: *_ioctl() MUST NOT change "regs" Parameter in the ENOSYS case
1650 }
1651
1652 switch (command) {
1653 case CHECK_POWER_MODE:
1654 // Return power mode from SectorCountReg in data[0]
1655 data[0] = regs.bSectorCountReg;
1656 return 0;
1657
1658 case STATUS_CHECK:
1659 // Cyl low and Cyl high unchanged means "Good SMART status"
1660 if (regs.bCylHighReg == SMART_CYL_HI && regs.bCylLowReg == SMART_CYL_LOW)
1661 return 0;
1662
1663 // These values mean "Bad SMART status"
1664 if (regs.bCylHighReg == 0x2c && regs.bCylLowReg == 0xf4)
1665 return 1;
1666
1667 // We haven't gotten output that makes sense; print out some debugging info
1668 syserror("Error SMART Status command failed");
1669 pout("Please get assistance from %s\n", PACKAGE_HOMEPAGE);
1670 print_ide_regs(&regs, 1);
1671 errno = EIO;
1672 return -1;
1673
1674 default:
1675 return 0;
1676 }
1677 /*NOTREACHED*/
1678 }
1679
1680
1681 #ifndef HAVE_ATA_IDENTIFY_IS_CACHED
1682 #error define of HAVE_ATA_IDENTIFY_IS_CACHED missing in config.h
1683 #endif
1684
1685 // Return true if OS caches the ATA identify sector
1686 int ata_identify_is_cached(int fd)
1687 {
1688 // Not RAID and WinNT4/2000/XP => true, RAID or Win9x/ME => false
1689 return (!(fd & 0xff00) && (GetVersion() & 0x80000000) == 0);
1690 }
1691
1692
1693 // Print not implemeted warning once
1694 static void pr_not_impl(const char * what, int * warned)
1695 {
1696 if (*warned)
1697 return;
1698 pout(
1699 "#######################################################################\n"
1700 "%s\n"
1701 "NOT IMPLEMENTED under Win32.\n"
1702 "Please contact " PACKAGE_BUGREPORT " if\n"
1703 "you want to help in porting smartmontools to Win32.\n"
1704 "#######################################################################\n"
1705 "\n", what
1706 );
1707 *warned = 1;
1708 }
1709
1710 // Interface to ATA devices behind 3ware escalade RAID controller cards. See os_linux.c
1711 int escalade_command_interface(int fd, int disknum, int escalade_type, smart_command_set command, int select, char *data)
1712 {
1713 static int warned = 0;
1714 ARGUSED(fd); ARGUSED(escalade_type); ARGUSED(command); ARGUSED(select); ARGUSED(data);
1715 if (!warned) {
1716 pout("Option '-d 3ware,%d' does not work on Windows.\n"
1717 "Controller port can be specified in the device name: '/dev/hd%c,%d'.\n\n",
1718 disknum, 'a'+ata_driveno, disknum);
1719 warned = 1;
1720 }
1721 errno = ENOSYS;
1722 return -1;
1723 }
1724
1725 // Interface to ATA devices behind Marvell chip-set based controllers. See os_linux.c
1726 int marvell_command_interface(int fd, smart_command_set command, int select, char * data)
1727 {
1728 static int warned = 0;
1729 ARGUSED(fd); ARGUSED(command); ARGUSED(select); ARGUSED(data);
1730 pr_not_impl("Marvell chip-set command routine marvell_command_interface()", &warned);
1731 errno = ENOSYS;
1732 return -1;
1733 }
1734
1735 // Interface to ATA devices behind HighPoint Raid controllers. See os_linux.c
1736 int highpoint_command_interface(int fd, smart_command_set command, int select, char * data)
1737 {
1738 static int warned = 0;
1739 ARGUSED(fd); ARGUSED(command); ARGUSED(select); ARGUSED(data);
1740 pr_not_impl("HighPoint raid controller command routine highpoint_command_interface()", &warned);
1741 errno = ENOSYS;
1742 return -1;
1743 }
1744
1745
1746 /////////////////////////////////////////////////////////////////////////////
1747 // ASPI Interface (for SCSI devices)
1748 /////////////////////////////////////////////////////////////////////////////
1749
1750 #pragma pack(1)
1751
1752 #define ASPI_SENSE_SIZE 18
1753
1754 // ASPI SCSI Request block header
1755
1756 typedef struct {
1757 unsigned char cmd; // 00: Command code
1758 unsigned char status; // 01: ASPI status
1759 unsigned char adapter; // 02: Host adapter number
1760 unsigned char flags; // 03: Request flags
1761 unsigned char reserved[4]; // 04: 0
1762 } ASPI_SRB_HEAD;
1763
1764 // SRB for host adapter inquiry
1765
1766 typedef struct {
1767 ASPI_SRB_HEAD h; // 00: Header
1768 unsigned char adapters; // 08: Number of adapters
1769 unsigned char target_id; // 09: Target ID ?
1770 char manager_id[16]; // 10: SCSI manager ID
1771 char adapter_id[16]; // 26: Host adapter ID
1772 unsigned char parameters[16]; // 42: Host adapter unique parmameters
1773 } ASPI_SRB_INQUIRY;
1774
1775 // SRB for get device type
1776
1777 typedef struct {
1778 ASPI_SRB_HEAD h; // 00: Header
1779 unsigned char target_id; // 08: Target ID
1780 unsigned char lun; // 09: LUN
1781 unsigned char devtype; // 10: Device type
1782 unsigned char reserved; // 11: Reserved
1783 } ASPI_SRB_DEVTYPE;
1784
1785 // SRB for SCSI I/O
1786
1787 typedef struct {
1788 ASPI_SRB_HEAD h; // 00: Header
1789 unsigned char target_id; // 08: Target ID
1790 unsigned char lun; // 09: LUN
1791 unsigned char reserved[2]; // 10: Reserved
1792 unsigned long data_size; // 12: Data alloc. lenght
1793 void * data_addr; // 16: Data buffer pointer
1794 unsigned char sense_size; // 20: Sense alloc. length
1795 unsigned char cdb_size; // 21: CDB length
1796 unsigned char host_status; // 22: Host status
1797 unsigned char target_status; // 23: Target status
1798 void * event_handle; // 24: Event handle
1799 unsigned char workspace[20]; // 28: ASPI workspace
1800 unsigned char cdb[16+ASPI_SENSE_SIZE];
1801 } ASPI_SRB_IO;
1802
1803 // Macro to retrieve start of sense information
1804 #define ASPI_SRB_SENSE(srb,cdbsz) ((srb)->cdb + 16)
1805
1806 // SRB union
1807
1808 typedef union {
1809 ASPI_SRB_HEAD h; // Common header
1810 ASPI_SRB_INQUIRY q; // Inquiry
1811 ASPI_SRB_DEVTYPE t; // Device type
1812 ASPI_SRB_IO i; // I/O
1813 } ASPI_SRB;
1814
1815 #pragma pack()
1816
1817 // ASPI commands
1818 #define ASPI_CMD_ADAPTER_INQUIRE 0x00
1819 #define ASPI_CMD_GET_DEVICE_TYPE 0x01
1820 #define ASPI_CMD_EXECUTE_IO 0x02
1821 #define ASPI_CMD_ABORT_IO 0x03
1822
1823 // Request flags
1824 #define ASPI_REQFLAG_DIR_TO_HOST 0x08
1825 #define ASPI_REQFLAG_DIR_TO_TARGET 0x10
1826 #define ASPI_REQFLAG_DIR_NO_XFER 0x18
1827 #define ASPI_REQFLAG_EVENT_NOTIFY 0x40
1828
1829 // ASPI status
1830 #define ASPI_STATUS_IN_PROGRESS 0x00
1831 #define ASPI_STATUS_NO_ERROR 0x01
1832 #define ASPI_STATUS_ABORTED 0x02
1833 #define ASPI_STATUS_ABORT_ERR 0x03
1834 #define ASPI_STATUS_ERROR 0x04
1835 #define ASPI_STATUS_INVALID_COMMAND 0x80
1836 #define ASPI_STATUS_INVALID_ADAPTER 0x81
1837 #define ASPI_STATUS_INVALID_TARGET 0x82
1838 #define ASPI_STATUS_NO_ADAPTERS 0xE8
1839
1840 // Adapter (host) status
1841 #define ASPI_HSTATUS_NO_ERROR 0x00
1842 #define ASPI_HSTATUS_SELECTION_TIMEOUT 0x11
1843 #define ASPI_HSTATUS_DATA_OVERRUN 0x12
1844 #define ASPI_HSTATUS_BUS_FREE 0x13
1845 #define ASPI_HSTATUS_BUS_PHASE_ERROR 0x14
1846 #define ASPI_HSTATUS_BAD_SGLIST 0x1A
1847
1848 // Target status
1849 #define ASPI_TSTATUS_NO_ERROR 0x00
1850 #define ASPI_TSTATUS_CHECK_CONDITION 0x02
1851 #define ASPI_TSTATUS_BUSY 0x08
1852 #define ASPI_TSTATUS_RESERV_CONFLICT 0x18
1853
1854
1855 static HINSTANCE h_aspi_dll; // DLL handle
1856 static UINT (* aspi_entry)(ASPI_SRB * srb); // ASPI entrypoint
1857 static unsigned num_aspi_adapters;
1858
1859 #ifdef __CYGWIN__
1860 // h_aspi_dll+aspi_entry is not inherited by Cygwin's fork()
1861 static DWORD aspi_dll_pid; // PID of DLL owner to detect fork()
1862 #define aspi_entry_valid() (aspi_entry && (aspi_dll_pid == GetCurrentProcessId()))
1863 #else
1864 #define aspi_entry_valid() (!!aspi_entry)
1865 #endif
1866
1867
1868 static int aspi_call(ASPI_SRB * srb)
1869 {
1870 int i;
1871 aspi_entry(srb);
1872 i = 0;
1873 while (((volatile ASPI_SRB *)srb)->h.status == ASPI_STATUS_IN_PROGRESS) {
1874 if (++i > 100/*10sek*/) {
1875 pout("ASPI Adapter %u: Timed out\n", srb->h.adapter);
1876 aspi_entry = 0;
1877 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
1878 errno = EIO;
1879 return -1;
1880 }
1881 if (con->reportscsiioctl > 1)
1882 pout("ASPI Adapter %u: Waiting (%d) ...\n", srb->h.adapter, i);
1883 Sleep(100);
1884 }
1885 return 0;
1886 }
1887
1888
1889 // Get ASPI entrypoint from wnaspi32.dll
1890
1891 static FARPROC aspi_get_address(const char * name, int verbose)
1892 {
1893 FARPROC addr;
1894 assert(h_aspi_dll && h_aspi_dll != INVALID_HANDLE_VALUE);
1895
1896 if (!(addr = GetProcAddress(h_aspi_dll, name))) {
1897 if (verbose)
1898 pout("Missing %s() in WNASPI32.DLL\n", name);
1899 aspi_entry = 0;
1900 FreeLibrary(h_aspi_dll);
1901 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
1902 errno = ENOSYS;
1903 return 0;
1904 }
1905 return addr;
1906 }
1907
1908
1909 static int aspi_open_dll(int verbose)
1910 {
1911 UINT (*aspi_info)(void);
1912 UINT info, rc;
1913
1914 assert(!aspi_entry_valid());
1915
1916 // Check structure layout
1917 assert(sizeof(ASPI_SRB_HEAD) == 8);
1918 assert(sizeof(ASPI_SRB_INQUIRY) == 58);
1919 assert(sizeof(ASPI_SRB_DEVTYPE) == 12);
1920 assert(sizeof(ASPI_SRB_IO) == 64+ASPI_SENSE_SIZE);
1921 assert(offsetof(ASPI_SRB,h.cmd) == 0);
1922 assert(offsetof(ASPI_SRB,h.flags) == 3);
1923 assert(offsetof(ASPI_SRB_IO,lun) == 9);
1924 assert(offsetof(ASPI_SRB_IO,data_addr) == 16);
1925 assert(offsetof(ASPI_SRB_IO,workspace) == 28);
1926 assert(offsetof(ASPI_SRB_IO,cdb) == 48);
1927
1928 if (h_aspi_dll == INVALID_HANDLE_VALUE) {
1929 // do not retry
1930 errno = ENOENT;
1931 return -1;
1932 }
1933
1934 // Load ASPI DLL
1935 if (!(h_aspi_dll = LoadLibraryA("WNASPI32.DLL"))) {
1936 if (verbose)
1937 pout("Cannot load WNASPI32.DLL, Error=%ld\n", GetLastError());
1938 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
1939 errno = ENOENT;
1940 return -1;
1941 }
1942 if (con->reportscsiioctl > 1) {
1943 // Print full path of WNASPI32.DLL
1944 char path[MAX_PATH];
1945 if (!GetModuleFileName(h_aspi_dll, path, sizeof(path)))
1946 strcpy(path, "*unknown*");
1947 pout("Using ASPI interface \"%s\"\n", path);
1948 }
1949
1950 // Get ASPI entrypoints
1951 if (!(aspi_info = (UINT (*)(void))aspi_get_address("GetASPI32SupportInfo", verbose)))
1952 return -1;
1953 if (!(aspi_entry = (UINT (*)(ASPI_SRB *))aspi_get_address("SendASPI32Command", verbose)))
1954 return -1;
1955
1956 // Init ASPI manager and get number of adapters
1957 info = (aspi_info)();
1958 if (con->reportscsiioctl > 1)
1959 pout("GetASPI32SupportInfo() returns 0x%04x\n", info);
1960 rc = (info >> 8) & 0xff;
1961 if (rc == ASPI_STATUS_NO_ADAPTERS) {
1962 num_aspi_adapters = 0;
1963 }
1964 else if (rc == ASPI_STATUS_NO_ERROR) {
1965 num_aspi_adapters = info & 0xff;
1966 }
1967 else {
1968 if (verbose)
1969 pout("Got strange 0x%04x from GetASPI32SupportInfo()\n", info);
1970 aspi_entry = 0;
1971 FreeLibrary(h_aspi_dll);
1972 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
1973 errno = ENOENT;
1974 return -1;
1975 }
1976
1977 if (con->reportscsiioctl)
1978 pout("%u ASPI Adapter%s detected\n",num_aspi_adapters, (num_aspi_adapters!=1?"s":""));
1979
1980 #ifdef __CYGWIN__
1981 // save PID to detect fork() in aspi_entry_valid()
1982 aspi_dll_pid = GetCurrentProcessId();
1983 #endif
1984 assert(aspi_entry_valid());
1985 return 0;
1986 }
1987
1988
1989 static int aspi_io_call(ASPI_SRB * srb, unsigned timeout)
1990 {
1991 HANDLE event;
1992 // Create event
1993 if (!(event = CreateEventA(NULL, FALSE, FALSE, NULL))) {
1994 pout("CreateEvent(): Error=%ld\n", GetLastError()); return -EIO;
1995 }
1996 srb->i.event_handle = event;
1997 srb->h.flags |= ASPI_REQFLAG_EVENT_NOTIFY;
1998 // Start ASPI request
1999 aspi_entry(srb);
2000 if (((volatile ASPI_SRB *)srb)->h.status == ASPI_STATUS_IN_PROGRESS) {
2001 // Wait for event
2002 DWORD rc = WaitForSingleObject(event, timeout*1000L);
2003 if (rc != WAIT_OBJECT_0) {
2004 if (rc == WAIT_TIMEOUT) {
2005 pout("ASPI Adapter %u, ID %u: Timed out after %u seconds\n",
2006 srb->h.adapter, srb->i.target_id, timeout);
2007 }
2008 else {
2009 pout("WaitForSingleObject(%lx) = 0x%lx,%ld, Error=%ld\n",
2010 (unsigned long)event, rc, rc, GetLastError());
2011 }
2012 // TODO: ASPI_ABORT_IO command
2013 aspi_entry = 0;
2014 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
2015 return -EIO;
2016 }
2017 }
2018 CloseHandle(event);
2019 return 0;
2020 }
2021
2022
2023 static int aspi_open(unsigned adapter, unsigned id)
2024 {
2025 ASPI_SRB srb;
2026 if (!(adapter <= 9 && id < 16)) {
2027 errno = ENOENT;
2028 return -1;
2029 }
2030
2031 if (!aspi_entry_valid()) {
2032 if (aspi_open_dll(1/*verbose*/))
2033 return -1;
2034 }
2035
2036 // Adapter OK?
2037 if (adapter >= num_aspi_adapters) {
2038 pout("ASPI Adapter %u does not exist (%u Adapter%s detected).\n",
2039 adapter, num_aspi_adapters, (num_aspi_adapters!=1?"s":""));
2040 if (!is_permissive()) {
2041 errno = ENOENT;
2042 return -1;
2043 }
2044 }
2045
2046 // Device present ?
2047 memset(&srb, 0, sizeof(srb));
2048 srb.h.cmd = ASPI_CMD_GET_DEVICE_TYPE;
2049 srb.h.adapter = adapter; srb.i.target_id = id;
2050 if (aspi_call(&srb)) {
2051 errno = EIO;
2052 return -1;
2053 }
2054 if (srb.h.status != ASPI_STATUS_NO_ERROR) {
2055 pout("ASPI Adapter %u, ID %u: No such device (Status=0x%02x)\n", adapter, id, srb.h.status);
2056 if (!is_permissive()) {
2057 errno = (srb.h.status == ASPI_STATUS_INVALID_TARGET ? ENOENT : EIO);
2058 return -1;
2059 }
2060 }
2061 else if (con->reportscsiioctl)
2062 pout("ASPI Adapter %u, ID %u: Device Type=0x%02x\n", adapter, id, srb.t.devtype);
2063
2064 return (ASPI_FDOFFSET | ((adapter & 0xf)<<4) | (id & 0xf));
2065 }
2066
2067
2068 static void aspi_close(int fd)
2069 {
2070 // No FreeLibrary(h_aspi_dll) to prevent problems with ASPI threads
2071 ARGUSED(fd);
2072 }
2073
2074
2075 // Scan for SCSI drives, fill bitmask [adapter:0-9][id:0-7] of drives present,
2076 // return #drives
2077
2078 static int aspi_scan(unsigned long * drives)
2079 {
2080 int cnt = 0;
2081 unsigned ad;
2082
2083 if (!aspi_entry_valid()) {
2084 if (aspi_open_dll(con->reportscsiioctl/*default is quiet*/))
2085 return 0;
2086 }
2087
2088 for (ad = 0; ad < num_aspi_adapters; ad++) {
2089 ASPI_SRB srb; unsigned id;
2090
2091 if (ad > 9) {
2092 if (con->reportscsiioctl)
2093 pout(" ASPI Adapter %u: Ignored\n", ad);
2094 continue;
2095 }
2096
2097 // Get adapter name
2098 memset(&srb, 0, sizeof(srb));
2099 srb.h.cmd = ASPI_CMD_ADAPTER_INQUIRE;
2100 srb.h.adapter = ad;
2101 if (aspi_call(&srb))
2102 return 0;
2103
2104 if (srb.h.status != ASPI_STATUS_NO_ERROR) {
2105 if (con->reportscsiioctl)
2106 pout(" ASPI Adapter %u: Status=0x%02x\n", ad, srb.h.status);
2107 continue;
2108 }
2109
2110 if (con->reportscsiioctl) {
2111 int i;
2112 for (i = 1; i < 16 && srb.q.adapter_id[i]; i++)
2113 if (!(' ' <= srb.q.adapter_id[i] && srb.q.adapter_id[i] <= '~'))
2114 srb.q.adapter_id[i] = '?';
2115 pout(" ASPI Adapter %u (\"%.16s\"):\n", ad, srb.q.adapter_id);
2116 }
2117
2118 bool ignore = !strnicmp(srb.q.adapter_id, "3ware", 5);
2119
2120 for (id = 0; id <= 7; id++) {
2121 // Get device type
2122 memset(&srb, 0, sizeof(srb));
2123 srb.h.cmd = ASPI_CMD_GET_DEVICE_TYPE;
2124 srb.h.adapter = ad; srb.i.target_id = id;
2125 if (aspi_call(&srb))
2126 return 0;
2127 if (srb.h.status != ASPI_STATUS_NO_ERROR) {
2128 if (con->reportscsiioctl > 1)
2129 pout(" ID %u: No such device (Status=0x%02x)\n", id, srb.h.status);
2130 continue;
2131 }
2132
2133 if (!ignore && srb.t.devtype == 0x00/*HDD*/) {
2134 if (con->reportscsiioctl)
2135 pout(" ID %u: Device Type=0x%02x\n", id, srb.t.devtype);
2136 drives[ad >> 2] |= (1L << (((ad & 0x3) << 3) + id));
2137 cnt++;
2138 }
2139 else if (con->reportscsiioctl)
2140 pout(" ID %u: Device Type=0x%02x (ignored)\n", id, srb.t.devtype);
2141 }
2142 }
2143 return cnt;
2144 }
2145
2146
2147 /////////////////////////////////////////////////////////////////////////////
2148
2149 // Interface to ASPI SCSI devices. See scsicmds.h and os_linux.c
2150 static int do_aspi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report)
2151 {
2152 ASPI_SRB srb;
2153
2154 if (!aspi_entry_valid())
2155 return -EBADF;
2156 if (!((fd & ~0xff) == ASPI_FDOFFSET))
2157 return -EBADF;
2158
2159 if (!(iop->cmnd_len == 6 || iop->cmnd_len == 10 || iop->cmnd_len == 12 || iop->cmnd_len == 16)) {
2160 pout("do_aspi_cmnd_io: bad CDB length\n");
2161 return -EINVAL;
2162 }
2163
2164 if (report > 0) {
2165 // From os_linux.c
2166 int k, j;
2167 const unsigned char * ucp = iop->cmnd;
2168 const char * np;
2169 char buff[256];
2170 const int sz = (int)sizeof(buff);
2171
2172 np = scsi_get_opcode_name(ucp[0]);
2173 j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
2174 for (k = 0; k < (int)iop->cmnd_len; ++k)
2175 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);
2176 if ((report > 1) &&
2177 (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
2178 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
2179
2180 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing "
2181 "data, len=%d%s:\n", (int)iop->dxfer_len,
2182 (trunc ? " [only first 256 bytes shown]" : ""));
2183 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
2184 }
2185 else
2186 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
2187 pout(buff);
2188 }
2189
2190 memset(&srb, 0, sizeof(srb));
2191 srb.h.cmd = ASPI_CMD_EXECUTE_IO;
2192 srb.h.adapter = ((fd >> 4) & 0xf);
2193 srb.i.target_id = (fd & 0xf);
2194 //srb.i.lun = 0;
2195 srb.i.sense_size = ASPI_SENSE_SIZE;
2196 srb.i.cdb_size = iop->cmnd_len;
2197 memcpy(srb.i.cdb, iop->cmnd, iop->cmnd_len);
2198
2199 switch (iop->dxfer_dir) {
2200 case DXFER_NONE:
2201 srb.h.flags = ASPI_REQFLAG_DIR_NO_XFER;
2202 break;
2203 case DXFER_FROM_DEVICE:
2204 srb.h.flags = ASPI_REQFLAG_DIR_TO_HOST;
2205 srb.i.data_size = iop->dxfer_len;
2206 srb.i.data_addr = iop->dxferp;
2207 break;
2208 case DXFER_TO_DEVICE:
2209 srb.h.flags = ASPI_REQFLAG_DIR_TO_TARGET;
2210 srb.i.data_size = iop->dxfer_len;
2211 srb.i.data_addr = iop->dxferp;
2212 break;
2213 default:
2214 pout("do_aspi_cmnd_io: bad dxfer_dir\n");
2215 return -EINVAL;
2216 }
2217
2218 iop->resp_sense_len = 0;
2219 iop->scsi_status = 0;
2220 iop->resid = 0;
2221
2222 if (aspi_io_call(&srb, (iop->timeout ? iop->timeout : 60))) {
2223 // Timeout
2224 return -EIO;
2225 }
2226
2227 if (srb.h.status != ASPI_STATUS_NO_ERROR) {
2228 if ( srb.h.status == ASPI_STATUS_ERROR
2229 && srb.i.host_status == ASPI_HSTATUS_NO_ERROR
2230 && srb.i.target_status == ASPI_TSTATUS_CHECK_CONDITION) {
2231 // Sense valid
2232 const unsigned char * sense = ASPI_SRB_SENSE(&srb.i, iop->cmnd_len);
2233 int len = (ASPI_SENSE_SIZE < iop->max_sense_len ? ASPI_SENSE_SIZE : iop->max_sense_len);
2234 iop->scsi_status = SCSI_STATUS_CHECK_CONDITION;
2235 if (len > 0 && iop->sensep) {
2236 memcpy(iop->sensep, sense, len);
2237 iop->resp_sense_len = len;
2238 if (report > 1) {
2239 pout(" >>> Sense buffer, len=%d:\n", (int)len);
2240 dStrHex(iop->sensep, len , 1);
2241 }
2242 }
2243 if (report) {
2244 pout(" sense_key=%x asc=%x ascq=%x\n",
2245 sense[2] & 0xf, sense[12], sense[13]);
2246 }
2247 return 0;
2248 }
2249 else {
2250 if (report)
2251 pout(" ASPI call failed, (0x%02x,0x%02x,0x%02x)\n", srb.h.status, srb.i.host_status, srb.i.target_status);
2252 return -EIO;
2253 }
2254 }
2255
2256 if (report > 0)
2257 pout(" OK\n");
2258
2259 if (iop->dxfer_dir == DXFER_FROM_DEVICE && report > 1) {
2260 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
2261 pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
2262 (trunc ? " [only first 256 bytes shown]" : ""));
2263 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
2264 }
2265
2266 return 0;
2267 }
2268
2269
2270 /////////////////////////////////////////////////////////////////////////////
2271 // SPT Interface (for SCSI devices and ATA devices behind SATLs)
2272 // Only supported in NT and later
2273 /////////////////////////////////////////////////////////////////////////////
2274
2275 #define SPT_MAXDEV 64
2276
2277 struct spt_dev_info {
2278 HANDLE h_spt_ioctl;
2279 int pd_num; // physical drive number
2280 int tape_num; // tape number ('\\.\TAPE<n>')
2281 int sub_addr; // addressing disks within a RAID, for example
2282 };
2283
2284 // Private table of open devices: guaranteed zero on startup since
2285 // part of static data.
2286 static struct spt_dev_info * spt_dev_arr[SPT_MAXDEV];
2287
2288
2289 static int spt_open(int pd_num, int tape_num, int sub_addr)
2290 {
2291 int k;
2292 struct spt_dev_info * sdip;
2293 char b[128];
2294 HANDLE h;
2295
2296 for (k = 0; k < SPT_MAXDEV; k++)
2297 if (! spt_dev_arr[k])
2298 break;
2299
2300 // If no free entry found, return error. We have max allowed number
2301 // of "file descriptors" already allocated.
2302 if (k == SPT_MAXDEV) {
2303 if (con->reportscsiioctl)
2304 pout("spt_open: too many open file descriptors (%d)\n",
2305 SPT_MAXDEV);
2306 errno = EMFILE;
2307 return -1;
2308 }
2309 sdip = (struct spt_dev_info *)malloc(sizeof(struct spt_dev_info));
2310 if (NULL == sdip) {
2311 errno = ENOMEM;
2312 return -1;
2313 }
2314 spt_dev_arr[k] = sdip;
2315 sdip->pd_num = pd_num;
2316 sdip->tape_num = tape_num;
2317 sdip->sub_addr = sub_addr;
2318
2319 b[sizeof(b) - 1] = '\0';
2320 if (pd_num >= 0)
2321 snprintf(b, sizeof(b) - 1, "\\\\.\\PhysicalDrive%d", pd_num);
2322 else if (tape_num >= 0)
2323 snprintf(b, sizeof(b) - 1, "\\\\.\\TAPE%d", tape_num);
2324 else {
2325 if (con->reportscsiioctl)
2326 pout("spt_open: bad parameters\n");
2327 errno = EINVAL;
2328 goto err_out;
2329 }
2330
2331 // Open device
2332 if ((h = CreateFileA(b, GENERIC_READ|GENERIC_WRITE,
2333 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
2334 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
2335 if (con->reportscsiioctl)
2336 pout(" %s: Open failed, Error=%ld\n", b, GetLastError());
2337 errno = ENODEV;
2338 goto err_out;
2339 }
2340 sdip->h_spt_ioctl = h;
2341 return k + SPT_FDOFFSET;
2342
2343 err_out:
2344 spt_dev_arr[k] = NULL;
2345 free(sdip);
2346 return -1;
2347 }
2348
2349
2350 static void spt_close(int fd)
2351 {
2352 struct spt_dev_info * sdip;
2353 int index = fd - SPT_FDOFFSET;
2354
2355 if ((index < 0) || (index >= SPT_MAXDEV)) {
2356 if (con->reportscsiioctl)
2357 pout("spt_close: bad fd range\n");
2358 return;
2359 }
2360 sdip = spt_dev_arr[index];
2361 if (NULL == sdip) {
2362 if (con->reportscsiioctl)
2363 pout("spt_close: fd already closed\n");
2364 return;
2365 }
2366 free(sdip);
2367 spt_dev_arr[index] = NULL;
2368 }
2369
2370
2371 #define IOCTL_SCSI_PASS_THROUGH_DIRECT \
2372 CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
2373
2374 typedef struct _SCSI_PASS_THROUGH_DIRECT {
2375 USHORT Length;
2376 UCHAR ScsiStatus;
2377 UCHAR PathId;
2378 UCHAR TargetId;
2379 UCHAR Lun;
2380 UCHAR CdbLength;
2381 UCHAR SenseInfoLength;
2382 UCHAR DataIn;
2383 ULONG DataTransferLength;
2384 ULONG TimeOutValue;
2385 PVOID DataBuffer;
2386 ULONG SenseInfoOffset;
2387 UCHAR Cdb[16];
2388 } SCSI_PASS_THROUGH_DIRECT;
2389
2390 typedef struct {
2391 SCSI_PASS_THROUGH_DIRECT spt;
2392 ULONG Filler;
2393 UCHAR ucSenseBuf[64];
2394 } SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
2395
2396
2397 // Interface to SPT SCSI devices. See scsicmds.h and os_linux.c
2398 static int do_spt_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report)
2399 {
2400 struct spt_dev_info * sdip;
2401 int index = fd - SPT_FDOFFSET;
2402 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb;
2403 DWORD num_out;
2404
2405 if ((index < 0) || (index >= SPT_MAXDEV)) {
2406 if (report)
2407 pout("do_spt_cmnd_io: bad fd range\n");
2408 return -EBADF;
2409 }
2410 sdip = spt_dev_arr[index];
2411 if (NULL == sdip) {
2412 if (report)
2413 pout("do_spt_cmnd_io: fd already closed\n");
2414 return -EBADF;
2415 }
2416
2417 if (report > 0) {
2418 int k, j;
2419 const unsigned char * ucp = iop->cmnd;
2420 const char * np;
2421 char buff[256];
2422 const int sz = (int)sizeof(buff);
2423
2424 np = scsi_get_opcode_name(ucp[0]);
2425 j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
2426 for (k = 0; k < (int)iop->cmnd_len; ++k)
2427 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);
2428 if ((report > 1) &&
2429 (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
2430 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
2431
2432 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing "
2433 "data, len=%d%s:\n", (int)iop->dxfer_len,
2434 (trunc ? " [only first 256 bytes shown]" : ""));
2435 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
2436 }
2437 else
2438 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
2439 pout(buff);
2440 }
2441 if (iop->cmnd_len > (int)sizeof(sb.spt.Cdb)) {
2442 if (report)
2443 pout("do_spt_cmnd_io: cmnd_len too large\n");
2444 return -EINVAL;
2445 }
2446
2447 memset(&sb, 0, sizeof(sb));
2448 sb.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
2449 sb.spt.CdbLength = iop->cmnd_len;
2450 memcpy(sb.spt.Cdb, iop->cmnd, iop->cmnd_len);
2451 sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf);
2452 sb.spt.SenseInfoOffset =
2453 offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
2454 sb.spt.TimeOutValue = (iop->timeout ? iop->timeout : 60);
2455 switch (iop->dxfer_dir) {
2456 case DXFER_NONE:
2457 sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
2458 break;
2459 case DXFER_FROM_DEVICE:
2460 sb.spt.DataIn = SCSI_IOCTL_DATA_IN;
2461 sb.spt.DataTransferLength = iop->dxfer_len;
2462 sb.spt.DataBuffer = iop->dxferp;
2463 break;
2464 case DXFER_TO_DEVICE:
2465 sb.spt.DataIn = SCSI_IOCTL_DATA_OUT;
2466 sb.spt.DataTransferLength = iop->dxfer_len;
2467 sb.spt.DataBuffer = iop->dxferp;
2468 break;
2469 default:
2470 pout("do_spt_cmnd_io: bad dxfer_dir\n");
2471 return -EINVAL;
2472 }
2473
2474 if (! DeviceIoControl(sdip->h_spt_ioctl, IOCTL_SCSI_PASS_THROUGH_DIRECT,
2475 &sb, sizeof(sb), &sb, sizeof(sb), &num_out, NULL)) {
2476 long err = GetLastError();
2477
2478 if (report)
2479 pout(" IOCTL_SCSI_PASS_THROUGH_DIRECT failed, Error=%ld\n", err);
2480 return -(err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
2481 }
2482
2483 iop->scsi_status = sb.spt.ScsiStatus;
2484 if (SCSI_STATUS_CHECK_CONDITION & iop->scsi_status) {
2485 int slen = sb.ucSenseBuf[7] + 8;
2486
2487 if (slen > (int)sizeof(sb.ucSenseBuf))
2488 slen = sizeof(sb.ucSenseBuf);
2489 if (slen > (int)iop->max_sense_len)
2490 slen = iop->max_sense_len;
2491 memcpy(iop->sensep, sb.ucSenseBuf, slen);
2492 iop->resp_sense_len = slen;
2493 if (report) {
2494 if ((iop->sensep[0] & 0x7f) > 0x71)
2495 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
2496 iop->scsi_status, iop->sensep[1] & 0xf,
2497 iop->sensep[2], iop->sensep[3]);
2498 else
2499 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
2500 iop->scsi_status, iop->sensep[2] & 0xf,
2501 iop->sensep[12], iop->sensep[13]);
2502 }
2503 } else
2504 iop->resp_sense_len = 0;
2505
2506 if ((iop->dxfer_len > 0) && (sb.spt.DataTransferLength > 0))
2507 iop->resid = iop->dxfer_len - sb.spt.DataTransferLength;
2508 else
2509 iop->resid = 0;
2510
2511 if ((iop->dxfer_dir == DXFER_FROM_DEVICE) && (report > 1)) {
2512 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
2513 pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
2514 (trunc ? " [only first 256 bytes shown]" : ""));
2515 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
2516 }
2517 return 0;
2518 }
2519
2520
2521 // Decides which SCSI implementation based on pseudo fd.
2522 // Declaration and explanation in scsicmds.h
2523 int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report)
2524 {
2525 if ((fd & ~0xff) == ASPI_FDOFFSET)
2526 return do_aspi_cmnd_io(fd, iop, report);
2527 else
2528 return do_spt_cmnd_io(fd, iop, report);
2529 }