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