root/trunk/sm5/os_win32.cpp @ 2266

Revision 2266, 54.2 KB (checked in by shattered, 8 years ago)

s/.c/.cpp/ in comments.

Line 
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"
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
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
49const char *os_XXXX_c_cvsid="$Id: os_win32.cpp,v 1.41 2006/09/20 16:17:31 shattered Exp $"
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
118static int ata_open(int drive, const char * options);
119static void ata_close(int fd);
120static int ata_scan(unsigned long * drives);
121static const char * ata_get_def_options(void);
122
123static int aspi_open(unsigned adapter, unsigned id);
124static void aspi_close(int fd);
125static int aspi_scan(unsigned long * drives);
126
127
128static int is_permissive()
129{
130        if (!con->permissive) {
131                pout("To continue, add one or more '-T permissive' options.\n");
132                return 0;
133        }
134        con->permissive--;
135        return 1;
136}
137
138static const char * skipdev(const char * s)
139{
140        return (!strncmp(s, "/dev/", 5) ? s + 5 : s);
141}
142
143
144// tries to guess device type given the name (a path).  See utility.h
145// for return values.
146int guess_device_type (const char * dev_name)
147{
148        dev_name = skipdev(dev_name);
149        if (!strncmp(dev_name, "hd", 2))
150                return CONTROLLER_ATA;
151        if (!strncmp(dev_name, "scsi", 4))
152                return CONTROLLER_SCSI;
153        return CONTROLLER_UNKNOWN;
154}
155
156
157// makes a list of ATA or SCSI devices for the DEVICESCAN directive of
158// smartd.  Returns number N of devices, or -1 if out of
159// memory. Allocates N+1 arrays: one of N pointers (devlist), the
160// others each contain null-terminated character strings.
161int make_device_names (char*** devlist, const char* type)
162{
163        unsigned long drives[3];
164        int i, j, n, nmax, sz;
165        const char * path;
166
167        drives[0] = drives[1] = drives[2] = 0;
168        if (!strcmp(type, "ATA")) {
169                // bit i set => drive i present
170                n = ata_scan(drives);
171                path = "/dev/hda";
172                nmax = 10;
173        }
174        else if (!strcmp(type, "SCSI")) {
175                // bit i set => drive with ID (i & 0x7) on adapter (i >> 3) present
176                n = aspi_scan(drives);
177                path = "/dev/scsi00";
178                nmax = 10*8;
179        }
180        else
181                return -1;
182
183        if (n <= 0)
184                return 0;
185
186        // Alloc devlist
187        sz = n * sizeof(char **);
188        *devlist = (char **)malloc(sz); bytes += sz;
189
190        // Add devices
191        for (i = j = 0; i < n; i++) {
192                char * s;
193                sz = strlen(path)+1;
194                s = (char *)malloc(sz); bytes += sz;
195                strcpy(s, path);
196                while (j < nmax && !(drives[j >> 5] & (1L << (j & 0x1f))))
197                        j++;
198                assert(j < nmax);
199                if (nmax <= 10) {
200                        assert(j <= 9);
201                        s[sz-2] += j; // /dev/hd[a-j]
202                }
203                else {
204                        assert((j >> 3) <= 9);
205                        s[sz-3] += (j >> 3);  // /dev/scsi[0-9].....
206                        s[sz-2] += (j & 0x7); //          .....[0-7]
207                }
208                (*devlist)[i] = s;
209                j++;
210        }
211        return n;
212}
213
214
215// Like open().  Return positive integer handle, only used by
216// functions below.  type="ATA" or "SCSI".  If you need to store extra
217// information about your devices, create a private internal array
218// within this file (see os_freebsd.cpp for an example).
219int deviceopen(const char * pathname, char *type)
220{
221        int len;
222        pathname = skipdev(pathname);
223        len = strlen(pathname);
224
225        if (!strcmp(type, "ATA")) {
226                // hd[a-j](:[saic]+)? => ATA 0-9 with options
227                char drive[1+1] = "", options[5+1] = ""; int n1 = -1, n2 = -1;
228                if (!(sscanf(pathname, "hd%1[a-j]%n:%5[saicp]%n", drive, &n1, options, &n2) >= 1
229                      && ((n1 == len && !options[0]) || n2 == len)                             )) {
230                        errno = ENOENT;
231                        return -1;
232                }
233                return ata_open(drive[0] - 'a', options);
234        }
235
236        if (!strcmp(type, "SCSI")) {
237                // scsi[0-9][0-f] => SCSI Adapter 0-9, ID 0-15, LUN 0
238                unsigned adapter = ~0, id = ~0; int n = -1;
239                if (!(sscanf(pathname,"scsi%1u%1x%n", &adapter, &id, &n) == 2 && n == len)) {
240                        errno = ENOENT;
241                        return -1;
242                }
243                return aspi_open(adapter, id);
244        }
245        errno = ENOENT;
246        return -1;
247}
248
249
250// Like close().  Acts only on handles returned by above function.
251// (Never called in smartctl!)
252int deviceclose(int fd)
253{
254        if (fd < 0x100) {
255                ata_close(fd);
256        }
257        else {
258                aspi_close(fd);
259        }
260        return 0;
261}
262
263
264// print examples for smartctl
265void print_smartctl_examples(){
266  printf("=================================================== SMARTCTL EXAMPLES =====\n\n"
267         "  smartctl -a /dev/hda                       (Prints all SMART information)\n\n"
268#ifdef HAVE_GETOPT_LONG
269         "  smartctl --smart=on --offlineauto=on --saveauto=on /dev/hda\n"
270         "                                              (Enables SMART on first disk)\n\n"
271         "  smartctl -t long /dev/hda              (Executes extended disk self-test)\n\n"
272         "  smartctl --attributes --log=selftest --quietmode=errorsonly /dev/hda\n"
273         "                                      (Prints Self-Test & Attribute errors)\n"
274#else
275         "  smartctl -s on -o on -S on /dev/hda         (Enables SMART on first disk)\n"
276         "  smartctl -t long /dev/hda              (Executes extended disk self-test)\n"
277         "  smartctl -A -l selftest -q errorsonly /dev/hda\n"
278         "                                      (Prints Self-Test & Attribute errors)\n"
279#endif
280         "  smartctl -a /dev/scsi21\n"
281         "             (Prints all information for SCSI disk on ASPI adapter 2, ID 1)\n"
282         "\n"
283         "  ATA SMART access methods and ordering may be specified by modifiers\n"
284         "  following the device name: /dev/hdX:[saic], where\n"
285         "  's': SMART_* IOCTLs,         'a': IOCTL_ATA_PASS_THROUGH,\n"
286         "  'i': IOCTL_IDE_PASS_THROUGH, 'c': ATA via IOCTL_SCSI_PASS_THROUGH.\n"
287         "  The default on this system is /dev/hdX:%s\n", ata_get_def_options()
288  );
289}
290
291
292/////////////////////////////////////////////////////////////////////////////
293// ATA Interface
294/////////////////////////////////////////////////////////////////////////////
295
296// SMART_* IOCTLs, also known as DFP_* (Disk Fault Protection)
297
298// Deklarations from:
299// http://cvs.sourceforge.net/viewcvs.py/mingw/w32api/include/ddk/ntdddisk.h?rev=1.3
300
301#define FILE_READ_ACCESS       0x0001
302#define FILE_WRITE_ACCESS      0x0002
303#define METHOD_BUFFERED             0
304#define CTL_CODE(DeviceType, Function, Method, Access) (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
305
306#define FILE_DEVICE_DISK           7
307#define IOCTL_DISK_BASE        FILE_DEVICE_DISK
308
309#define SMART_GET_VERSION \
310  CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS)
311
312#define SMART_SEND_DRIVE_COMMAND \
313  CTL_CODE(IOCTL_DISK_BASE, 0x0021, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
314
315#define SMART_RCV_DRIVE_DATA \
316  CTL_CODE(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
317
318ASSERT_CONST(SMART_GET_VERSION       , 0x074080);
319ASSERT_CONST(SMART_SEND_DRIVE_COMMAND, 0x07c084);
320ASSERT_CONST(SMART_RCV_DRIVE_DATA    , 0x07c088);
321
322#define SMART_CYL_LOW  0x4F
323#define SMART_CYL_HI   0xC2
324
325
326#pragma pack(1)
327
328typedef struct _GETVERSIONOUTPARAMS {
329        UCHAR  bVersion;
330        UCHAR  bRevision;
331        UCHAR  bReserved;
332        UCHAR  bIDEDeviceMap;
333        ULONG  fCapabilities;
334        ULONG  dwReserved[4];
335} GETVERSIONOUTPARAMS, *PGETVERSIONOUTPARAMS, *LPGETVERSIONOUTPARAMS;
336
337ASSERT_SIZEOF(GETVERSIONOUTPARAMS, 24);
338
339typedef struct _IDEREGS {
340        UCHAR  bFeaturesReg;
341        UCHAR  bSectorCountReg;
342        UCHAR  bSectorNumberReg;
343        UCHAR  bCylLowReg;
344        UCHAR  bCylHighReg;
345        UCHAR  bDriveHeadReg;
346        UCHAR  bCommandReg;
347        UCHAR  bReserved;
348} IDEREGS, *PIDEREGS, *LPIDEREGS;
349
350typedef struct _SENDCMDINPARAMS {
351        ULONG  cBufferSize;
352        IDEREGS  irDriveRegs;
353        UCHAR  bDriveNumber;
354        UCHAR  bReserved[3];
355        ULONG  dwReserved[4];
356        UCHAR  bBuffer[1];
357} SENDCMDINPARAMS, *PSENDCMDINPARAMS, *LPSENDCMDINPARAMS;
358
359ASSERT_SIZEOF(SENDCMDINPARAMS, 32+1);
360
361/* DRIVERSTATUS.bDriverError constants (just for info, not used)
362#define SMART_NO_ERROR                    0
363#define SMART_IDE_ERROR                   1
364#define SMART_INVALID_FLAG                2
365#define SMART_INVALID_COMMAND             3
366#define SMART_INVALID_BUFFER              4
367#define SMART_INVALID_DRIVE               5
368#define SMART_INVALID_IOCTL               6
369#define SMART_ERROR_NO_MEM                7
370#define SMART_INVALID_REGISTER            8
371#define SMART_NOT_SUPPORTED               9
372#define SMART_NO_IDE_DEVICE               10
373*/
374
375typedef struct _DRIVERSTATUS {
376        UCHAR  bDriverError;
377        UCHAR  bIDEError;
378        UCHAR  bReserved[2];
379        ULONG  dwReserved[2];
380} DRIVERSTATUS, *PDRIVERSTATUS, *LPDRIVERSTATUS;
381
382typedef struct _SENDCMDOUTPARAMS {
383        ULONG  cBufferSize;
384        DRIVERSTATUS  DriverStatus;
385        UCHAR  bBuffer[1];
386} SENDCMDOUTPARAMS, *PSENDCMDOUTPARAMS, *LPSENDCMDOUTPARAMS;
387
388ASSERT_SIZEOF(SENDCMDOUTPARAMS, 16+1);
389
390#pragma pack()
391
392
393/////////////////////////////////////////////////////////////////////////////
394
395static void print_ide_regs(const IDEREGS * r, int out)
396{
397        pout("%s=0x%02x,%s=0x%02x, SC=0x%02x, NS=0x%02x, CL=0x%02x, CH=0x%02x, SEL=0x%02x\n",
398        (out?"STS":"CMD"), r->bCommandReg, (out?"ERR":" FR"), r->bFeaturesReg,
399        r->bSectorCountReg, r->bSectorNumberReg, r->bCylLowReg, r->bCylHighReg, r->bDriveHeadReg);
400}
401
402static void print_ide_regs_io(const IDEREGS * ri, const IDEREGS * ro)
403{
404        pout("    Input : "); print_ide_regs(ri, 0);
405        if (ro) {
406                pout("    Output: "); print_ide_regs(ro, 1);
407        }
408}
409
410/////////////////////////////////////////////////////////////////////////////
411
412// call SMART_GET_VERSION, return device map or -1 on error
413
414static int smart_get_version(HANDLE hdevice)
415{
416        GETVERSIONOUTPARAMS vers;
417        DWORD num_out;
418
419        memset(&vers, 0, sizeof(vers));
420        if (!DeviceIoControl(hdevice, SMART_GET_VERSION,
421                NULL, 0, &vers, sizeof(vers), &num_out, NULL)) {
422                if (con->reportataioctl)
423                        pout("  SMART_GET_VERSION failed, Error=%ld\n", GetLastError());
424                errno = ENOSYS;
425                return -1;
426        }
427        assert(num_out == sizeof(GETVERSIONOUTPARAMS));
428
429        if (con->reportataioctl > 1)
430                pout("  SMART_GET_VERSION suceeded, bytes returned: %lu\n"
431                     "    Vers = %d.%d, Caps = 0x%lx, DeviceMap = 0x%02x\n",
432                        num_out, vers.bVersion, vers.bRevision,
433                        vers.fCapabilities, vers.bIDEDeviceMap);
434
435        // TODO: Check vers.fCapabilities here?
436        return vers.bIDEDeviceMap;
437}
438
439
440// call SMART_* ioctl
441
442static int smart_ioctl(HANDLE hdevice, int drive, IDEREGS * regs, char * data, unsigned datasize)
443{
444        SENDCMDINPARAMS inpar;
445        unsigned char outbuf[sizeof(SENDCMDOUTPARAMS)-1 + 512];
446        const SENDCMDOUTPARAMS * outpar;
447        DWORD code, num_out;
448        unsigned int size_out;
449        const char * name;
450
451        memset(&inpar, 0, sizeof(inpar));
452        inpar.irDriveRegs = *regs;
453        // drive is set to 0-3 on Win9x only
454        inpar.irDriveRegs.bDriveHeadReg = 0xA0 | ((drive & 1) << 4);
455        inpar.bDriveNumber = drive;
456
457        assert(datasize == 0 || datasize == 512);
458        if (datasize) {
459                code = SMART_RCV_DRIVE_DATA; name = "SMART_RCV_DRIVE_DATA";
460                inpar.cBufferSize = size_out = 512;
461        }
462        else {
463                code = SMART_SEND_DRIVE_COMMAND; name = "SMART_SEND_DRIVE_COMMAND";
464                if (regs->bFeaturesReg == ATA_SMART_STATUS)
465                        size_out = sizeof(IDEREGS); // ioctl returns new IDEREGS as data
466                        // Note: cBufferSize must be 0 on Win9x
467                else
468                        size_out = 0;
469        }
470
471        memset(&outbuf, 0, sizeof(outbuf));
472
473        if (!DeviceIoControl(hdevice, code, &inpar, sizeof(SENDCMDINPARAMS)-1,
474                outbuf, sizeof(SENDCMDOUTPARAMS)-1 + size_out, &num_out, NULL)) {
475                // CAUTION: DO NOT change "regs" Parameter in this case, see ata_command_interface()
476                long err = GetLastError();
477                if (con->reportataioctl && (err != ERROR_INVALID_PARAMETER || con->reportataioctl > 1)) {
478                        pout("  %s failed, Error=%ld\n", name, err);
479                        print_ide_regs_io(regs, NULL);
480                }
481                errno = (   err == ERROR_INVALID_FUNCTION /*9x*/
482                         || err == ERROR_INVALID_PARAMETER/*NT/2K/XP*/ ? ENOSYS : EIO);
483                return -1;
484        }
485        // NOTE: On Win9x, inpar.irDriveRegs now contains the returned regs
486
487        outpar = (const SENDCMDOUTPARAMS *)outbuf;
488
489        if (outpar->DriverStatus.bDriverError) {
490                if (con->reportataioctl) {
491                        pout("  %s failed, DriverError=0x%02x, IDEError=0x%02x\n", name,
492                                outpar->DriverStatus.bDriverError, outpar->DriverStatus.bIDEError);
493                        print_ide_regs_io(regs, NULL);
494                }
495                errno = (!outpar->DriverStatus.bIDEError ? ENOSYS : EIO);
496                return -1;
497        }
498
499        if (con->reportataioctl > 1) {
500                pout("  %s suceeded, bytes returned: %lu (buffer %lu)\n", name,
501                        num_out, outpar->cBufferSize);
502                print_ide_regs_io(regs, (regs->bFeaturesReg == ATA_SMART_STATUS ?
503                        (const IDEREGS *)(outpar->bBuffer) : NULL));
504        }
505
506        if (datasize)
507                memcpy(data, outpar->bBuffer, 512);
508        else if (regs->bFeaturesReg == ATA_SMART_STATUS)
509                *regs = *(const IDEREGS *)(outpar->bBuffer);
510
511        return 0;
512}
513
514
515/////////////////////////////////////////////////////////////////////////////
516
517// IDE PASS THROUGH (2000, XP, undocumented)
518//
519// Based on WinATA.cpp, 2002 c't/Matthias Withopf
520// ftp://ftp.heise.de/pub/ct/listings/0207-218.zip
521
522#define FILE_DEVICE_CONTROLLER  4
523#define IOCTL_SCSI_BASE         FILE_DEVICE_CONTROLLER
524
525#define IOCTL_IDE_PASS_THROUGH \
526  CTL_CODE(IOCTL_SCSI_BASE, 0x040A, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
527
528ASSERT_CONST(IOCTL_IDE_PASS_THROUGH, 0x04d028);
529
530#pragma pack(1)
531
532typedef struct {
533        IDEREGS IdeReg;
534        ULONG   DataBufferSize;
535        UCHAR   DataBuffer[1];
536} ATA_PASS_THROUGH;
537
538ASSERT_SIZEOF(ATA_PASS_THROUGH, 12+1);
539
540#pragma pack()
541
542
543/////////////////////////////////////////////////////////////////////////////
544
545static int ide_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize)
546{ 
547        unsigned int size = sizeof(ATA_PASS_THROUGH)-1 + datasize;
548        ATA_PASS_THROUGH * buf = (ATA_PASS_THROUGH *)VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
549        DWORD num_out;
550        const unsigned char magic = 0xcf;
551
552        if (!buf) {
553                errno = ENOMEM;
554                return -1;
555        }
556
557        buf->IdeReg = *regs;
558        buf->DataBufferSize = datasize;
559        if (datasize)
560                buf->DataBuffer[0] = magic;
561
562        if (!DeviceIoControl(hdevice, IOCTL_IDE_PASS_THROUGH,
563                buf, size, buf, size, &num_out, NULL)) {
564                long err = GetLastError();
565                if (con->reportataioctl) {
566                        pout("  IOCTL_IDE_PASS_THROUGH failed, Error=%ld\n", err);
567                        print_ide_regs_io(regs, NULL);
568                }
569                VirtualFree(buf, 0, MEM_RELEASE);
570                errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
571                return -1;
572        }
573
574        // Check ATA status
575        if (buf->IdeReg.bCommandReg/*Status*/ & 0x01) {
576                if (con->reportataioctl) {
577                        pout("  IOCTL_IDE_PASS_THROUGH command failed:\n");
578                        print_ide_regs_io(regs, &buf->IdeReg);
579                }
580                VirtualFree(buf, 0, MEM_RELEASE);
581                errno = EIO;
582                return -1;
583        }
584
585        // Check and copy data
586        if (datasize) {
587                if (   num_out != size
588                    || (buf->DataBuffer[0] == magic && !nonempty(buf->DataBuffer+1, datasize-1))) {
589                        if (con->reportataioctl) {
590                                pout("  IOCTL_IDE_PASS_THROUGH output data missing (%lu, %lu)\n",
591                                        num_out, buf->DataBufferSize);
592                                print_ide_regs_io(regs, &buf->IdeReg);
593                        }
594                        VirtualFree(buf, 0, MEM_RELEASE);
595                        errno = EIO;
596                        return -1;
597                }
598                memcpy(data, buf->DataBuffer, datasize);
599        }
600
601        if (con->reportataioctl > 1) {
602                pout("  IOCTL_IDE_PASS_THROUGH suceeded, bytes returned: %lu (buffer %lu)\n",
603                        num_out, buf->DataBufferSize);
604                print_ide_regs_io(regs, &buf->IdeReg);
605        }
606        *regs = buf->IdeReg;
607
608        // Caution: VirtualFree() fails if parameter "dwSize" is nonzero
609        VirtualFree(buf, 0, MEM_RELEASE);
610        return 0;
611}
612
613
614/////////////////////////////////////////////////////////////////////////////
615
616// ATA PASS THROUGH (Win2003, XP SP2)
617
618#define IOCTL_ATA_PASS_THROUGH \
619        CTL_CODE(IOCTL_SCSI_BASE, 0x040B, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
620
621ASSERT_CONST(IOCTL_ATA_PASS_THROUGH, 0x04d02c);
622
623typedef struct _ATA_PASS_THROUGH_EX {
624        USHORT  Length;
625        USHORT  AtaFlags;
626        UCHAR  PathId;
627        UCHAR  TargetId;
628        UCHAR  Lun;
629        UCHAR  ReservedAsUchar;
630        ULONG  DataTransferLength;
631        ULONG  TimeOutValue;
632        ULONG  ReservedAsUlong;
633        ULONG/*_PTR*/ DataBufferOffset;
634        UCHAR  PreviousTaskFile[8];
635        UCHAR  CurrentTaskFile[8];
636} ATA_PASS_THROUGH_EX, *PATA_PASS_THROUGH_EX;
637
638ASSERT_SIZEOF(ATA_PASS_THROUGH_EX, 40);
639
640#define ATA_FLAGS_DRDY_REQUIRED 0x01
641#define ATA_FLAGS_DATA_IN       0x02
642#define ATA_FLAGS_DATA_OUT      0x04
643#define ATA_FLAGS_48BIT_COMMAND 0x08
644
645
646/////////////////////////////////////////////////////////////////////////////
647
648static int ata_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, int datasize)
649{ 
650        typedef struct {
651                ATA_PASS_THROUGH_EX apt;
652                ULONG Filler;
653                UCHAR ucDataBuf[512];
654        } ATA_PASS_THROUGH_EX_WITH_BUFFERS;
655
656        ATA_PASS_THROUGH_EX_WITH_BUFFERS ab;
657        IDEREGS * ctfregs;
658        unsigned int size;
659        DWORD num_out;
660        const unsigned char magic = 0xcf;
661
662        memset(&ab, 0, sizeof(ab));
663        ab.apt.Length = sizeof(ATA_PASS_THROUGH_EX);
664        //ab.apt.PathId = 0;
665        //ab.apt.TargetId = 0;
666        //ab.apt.Lun = 0;
667        ab.apt.TimeOutValue = 10;
668        size = offsetof(ATA_PASS_THROUGH_EX_WITH_BUFFERS, ucDataBuf);
669        ab.apt.DataBufferOffset = size;
670 
671        if (datasize) {
672                if (!(0 <= datasize && datasize <= (int)sizeof(ab.ucDataBuf))) {
673                        errno = EINVAL;
674                        return -1;
675                }
676                ab.apt.AtaFlags = ATA_FLAGS_DATA_IN;
677                ab.apt.DataTransferLength = datasize;
678                size += datasize;
679                ab.ucDataBuf[0] = magic;
680        }
681        else {
682                //ab.apt.AtaFlags = 0;
683                //ab.apt.DataTransferLength = 0;
684        }
685
686        assert(sizeof(ab.apt.CurrentTaskFile) == sizeof(IDEREGS));
687        ctfregs = (IDEREGS *)ab.apt.CurrentTaskFile;
688        *ctfregs = *regs;
689
690        if (!DeviceIoControl(hdevice, IOCTL_ATA_PASS_THROUGH,
691                &ab, size, &ab, size, &num_out, NULL)) {
692                long err = GetLastError();
693                if (con->reportataioctl) {
694                        pout("  IOCTL_ATA_PASS_THROUGH_EX failed, Error=%ld\n", err);
695                        print_ide_regs_io(regs, NULL);
696                }
697                errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
698                return -1;
699        }
700
701        // Check and copy data
702        if (datasize) {
703                if (   num_out != size
704                    || (ab.ucDataBuf[0] == magic && !nonempty(ab.ucDataBuf+1, datasize-1))) {
705                        if (con->reportataioctl) {
706                                pout("  IOCTL_ATA_PASS_THROUGH_EX output data missing (%lu)\n", num_out);
707                                print_ide_regs_io(regs, ctfregs);
708                        }
709                        errno = EIO;
710                        return -1;
711                }
712                memcpy(data, ab.ucDataBuf, datasize);
713        }
714
715        if (con->reportataioctl > 1) {
716                pout("  IOCTL_ATA_PASS_THROUGH_EX suceeded, bytes returned: %lu\n", num_out);
717                print_ide_regs_io(regs, ctfregs);
718        }
719        *regs = *ctfregs;
720
721        return 0;
722}
723
724
725/////////////////////////////////////////////////////////////////////////////
726
727// ATA PASS THROUGH via SCSI PASS THROUGH (WinNT4 only)
728
729// Declarations from:
730// http://cvs.sourceforge.net/viewcvs.py/mingw/w32api/include/ddk/ntddscsi.h?rev=1.2
731
732#define IOCTL_SCSI_PASS_THROUGH \
733        CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
734
735ASSERT_CONST(IOCTL_SCSI_PASS_THROUGH, 0x04d004);
736
737#define SCSI_IOCTL_DATA_OUT          0
738#define SCSI_IOCTL_DATA_IN           1
739#define SCSI_IOCTL_DATA_UNSPECIFIED  2
740// undocumented SCSI opcode to for ATA passthrough
741#define SCSIOP_ATA_PASSTHROUGH    0xCC
742
743typedef struct _SCSI_PASS_THROUGH {
744        USHORT  Length;
745        UCHAR  ScsiStatus;
746        UCHAR  PathId;
747        UCHAR  TargetId;
748        UCHAR  Lun;
749        UCHAR  CdbLength;
750        UCHAR  SenseInfoLength;
751        UCHAR  DataIn;
752        ULONG  DataTransferLength;
753        ULONG  TimeOutValue;
754        ULONG/*_PTR*/ DataBufferOffset;
755        ULONG  SenseInfoOffset;
756        UCHAR  Cdb[16];
757} SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;
758
759ASSERT_SIZEOF(SCSI_PASS_THROUGH, 44);
760
761
762/////////////////////////////////////////////////////////////////////////////
763
764static int ata_via_scsi_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize)
765{
766        typedef struct {
767                SCSI_PASS_THROUGH spt;
768                ULONG Filler;
769                UCHAR ucSenseBuf[32];
770                UCHAR ucDataBuf[512];
771        } SCSI_PASS_THROUGH_WITH_BUFFERS;
772
773        SCSI_PASS_THROUGH_WITH_BUFFERS sb;
774        IDEREGS * cdbregs;
775        unsigned int size;
776        DWORD num_out;
777        const unsigned char magic = 0xcf;
778
779        memset(&sb, 0, sizeof(sb));
780        sb.spt.Length = sizeof(SCSI_PASS_THROUGH);
781        //sb.spt.PathId = 0;
782        sb.spt.TargetId = 1;
783        //sb.spt.Lun = 0;
784        sb.spt.CdbLength = 10; sb.spt.SenseInfoLength = 24;
785        sb.spt.TimeOutValue = 10;
786        sb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf);
787        size = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf);
788        sb.spt.DataBufferOffset = size;
789 
790        if (datasize) {
791                if (datasize > sizeof(sb.ucDataBuf)) {
792                        errno = EINVAL;
793                        return -1;
794                }
795                sb.spt.DataIn = SCSI_IOCTL_DATA_IN;
796                sb.spt.DataTransferLength = datasize;
797                size += datasize;
798                sb.ucDataBuf[0] = magic;
799        }
800        else {
801                sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
802                //sb.spt.DataTransferLength = 0;
803        }
804
805        // Use pseudo SCSI command followed by registers
806        sb.spt.Cdb[0] = SCSIOP_ATA_PASSTHROUGH;
807        cdbregs = (IDEREGS *)(sb.spt.Cdb+2);
808        *cdbregs = *regs;
809
810        if (!DeviceIoControl(hdevice, IOCTL_SCSI_PASS_THROUGH,
811                &sb, size, &sb, size, &num_out, NULL)) {
812                long err = GetLastError();
813                if (con->reportataioctl)
814                        pout("  ATA via IOCTL_SCSI_PASS_THROUGH failed, Error=%ld\n", err);
815                errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
816                return -1;
817        }
818
819        // Cannot check ATA status, because command does not return IDEREGS
820
821        // Check and copy data
822        if (datasize) {
823                if (   num_out != size
824                    || (sb.ucDataBuf[0] == magic && !nonempty(sb.ucDataBuf+1, datasize-1))) {
825                        if (con->reportataioctl) {
826                                pout("  ATA via IOCTL_SCSI_PASS_THROUGH output data missing (%lu)\n", num_out);
827                                print_ide_regs_io(regs, NULL);
828                        }
829                        errno = EIO;
830                        return -1;
831                }
832                memcpy(data, sb.ucDataBuf, datasize);
833        }
834
835        if (con->reportataioctl > 1) {
836                pout("  ATA via IOCTL_SCSI_PASS_THROUGH suceeded, bytes returned: %lu\n", num_out);
837                print_ide_regs_io(regs, NULL);
838        }
839        return 0;
840}
841
842/////////////////////////////////////////////////////////////////////////////
843
844// Call GetDevicePowerState() if available (Win98/ME/2000/XP/2003)
845// returns: 1=active, 0=standby, -1=error
846// (This would also work for SCSI drives)
847
848static int get_device_power_state(HANDLE hdevice)
849{
850        static HINSTANCE h_kernel_dll = 0;
851#ifdef __CYGWIN__
852        static DWORD kernel_dll_pid = 0;
853#endif
854        static BOOL (WINAPI * GetDevicePowerState_p)(HANDLE, BOOL *) = 0;
855
856        BOOL state = TRUE;
857
858        if (!GetDevicePowerState_p
859#ifdef __CYGWIN__
860            || kernel_dll_pid != GetCurrentProcessId() // detect fork()
861#endif
862           ) {
863                if (h_kernel_dll == INVALID_HANDLE_VALUE) {
864                        errno = ENOSYS;
865                        return -1;
866                }
867                if (!(h_kernel_dll = LoadLibraryA("KERNEL32.DLL"))) {
868                        pout("Cannot load KERNEL32.DLL, Error=%ld\n", GetLastError());
869                        h_kernel_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
870                        errno = ENOSYS;
871                        return -1;
872                }
873                if (!(GetDevicePowerState_p = (BOOL (WINAPI *)(HANDLE, BOOL *))
874                                              GetProcAddress(h_kernel_dll, "GetDevicePowerState"))) {
875                        if (con->reportataioctl)
876                                pout("  GetDevicePowerState() not found, Error=%ld\n", GetLastError());
877                        FreeLibrary(h_kernel_dll);
878                        h_kernel_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
879                        errno = ENOSYS;
880                        return -1;
881                }
882#ifdef __CYGWIN__
883                kernel_dll_pid = GetCurrentProcessId();
884#endif
885        }
886
887        if (!GetDevicePowerState_p(hdevice, &state)) {
888                long err = GetLastError();
889                if (con->reportataioctl)
890                        pout("  GetDevicePowerState() failed, Error=%ld\n", err);
891                errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
892                // TODO: This may not work as expected on transient errors,
893                // because smartd interprets -1 as SLEEP mode regardless of errno.
894                return -1;
895        }
896
897        if (con->reportataioctl > 1)
898                pout("  GetDevicePowerState() succeeded, state=%d\n", state);
899        return state;
900}
901
902
903/////////////////////////////////////////////////////////////////////////////
904
905// TODO: Put in a struct indexed by fd (or better a C++ object of course ;-)
906static HANDLE h_ata_ioctl = 0;
907static const char * ata_def_options;
908static char * ata_cur_options;
909static int ata_driveno; // Drive number
910static char ata_smartver_state[10]; // SMART_GET_VERSION: 0=unknown, 1=OK, 2=failed
911
912// Print SMARTVSD error message, return errno
913
914static int smartvsd_error()
915{
916        char path[MAX_PATH];
917        unsigned len;
918        if (!(5 <= (len = GetSystemDirectoryA(path, MAX_PATH)) && len < MAX_PATH/2))
919                return ENOENT;
920        // SMARTVSD.VXD present?
921        strcpy(path+len, "\\IOSUBSYS\\SMARTVSD.VXD");
922        if (!access(path, 0)) {
923                // Yes, standard IDE driver used?
924                HANDLE h;
925                if (   (h = CreateFileA("\\\\.\\ESDI_506",
926                             GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
927                             NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE
928                    && GetLastError() == ERROR_FILE_NOT_FOUND                             ) {
929                        pout("Standard IDE driver ESDI_506.PDR not used, or no IDE/ATA drives present.\n");
930                        return ENOENT;
931                }
932                else {
933                        if (h != INVALID_HANDLE_VALUE) // should not happen
934                                CloseHandle(h);
935                        pout("SMART driver SMARTVSD.VXD is installed, but not loaded.\n");
936                        return ENOSYS;
937                }
938        }
939        else {
940                strcpy(path+len, "\\SMARTVSD.VXD");
941                if (!access(path, 0)) {
942                        // Some Windows versions install SMARTVSD.VXD in SYSTEM directory
943                        // (http://support.microsoft.com/kb/265854/en-us).
944                        path[len] = 0;
945                        pout("SMART driver is not properly installed,\n"
946                                 " move SMARTVSD.VXD from \"%s\" to \"%s\\IOSUBSYS\"\n"
947                                 " and reboot Windows.\n", path, path);
948                }
949                else {
950                        // Some Windows versions do not provide SMARTVSD.VXD
951                        // (http://support.microsoft.com/kb/199886/en-us).
952                        path[len] = 0;
953                        pout("SMARTVSD.VXD is missing in folder \"%s\\IOSUBSYS\".\n", path);
954                }
955                return ENOSYS;
956        }
957}
958
959
960// Get default ATA device options
961
962static const char * ata_get_def_options()
963{
964        DWORD ver = GetVersion();
965        if ((ver & 0x80000000) || (ver & 0xff) < 4) // Win9x/ME
966                return "s"; // SMART_* only
967        else if ((ver & 0xff) == 4) // WinNT4
968                return "sc"; // SMART_*, SCSI_PASS_THROUGH
969        else // WinXP, 2003, Vista
970                return "psai"; // GetDevicePowerState(), SMART_*, ATA_, IDE_PASS_THROUGH
971}
972
973
974// Open ATA device
975
976static int ata_open(int drive, const char * options)
977{
978        int win9x;
979        char devpath[30];
980        int devmap;
981
982        // TODO: This version does not allow to open more than 1 ATA devices
983        if (h_ata_ioctl) {
984                errno = ENFILE;
985                return -1;
986        }
987
988        win9x = ((GetVersion() & 0x80000000) != 0);
989
990        if (!(0 <= drive && drive <= (win9x ? 7 : 9))) {
991                errno = ENOENT;
992                return -1;
993        }
994
995        // path depends on Windows Version
996        if (win9x)
997                // Use patched "smartvse.vxd" for drives 4-7, see INSTALL file for details
998                strcpy(devpath, (drive <= 3 ? "\\\\.\\SMARTVSD" : "\\\\.\\SMARTVSE"));
999        else
1000                snprintf(devpath, sizeof(devpath)-1, "\\\\.\\PhysicalDrive%d", drive);
1001
1002        // Open device
1003        if ((h_ata_ioctl = CreateFileA(devpath,
1004                GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1005                NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
1006                long err = GetLastError();     
1007                pout("Cannot open device %s, Error=%ld\n", devpath, err);
1008                if (err == ERROR_FILE_NOT_FOUND)
1009                        errno = (win9x && drive <= 3 ? smartvsd_error() : ENOENT);
1010                else if (err == ERROR_ACCESS_DENIED) {
1011                        if (!win9x)
1012                                pout("Administrator rights are necessary to access physical drives.\n");
1013                        errno = EACCES;
1014                }
1015                else
1016                        errno = EIO;
1017                h_ata_ioctl = 0;
1018                return -1;
1019        }
1020
1021        if (con->reportataioctl > 1)
1022                pout("%s: successfully opened\n", devpath);
1023
1024        // Save options
1025        if (!*options) {
1026                // Set default options according to Windows version
1027                if (!ata_def_options)
1028                        ata_def_options = ata_get_def_options();
1029                options = ata_def_options;
1030        }
1031        ata_cur_options = strdup(options);
1032
1033        // NT4/2000/XP: SMART_GET_VERSION may spin up disk, so delay until first real SMART_* call
1034        ata_driveno = drive;
1035        if (!win9x)
1036                return 0;
1037
1038        // Win9X/ME: Get drive map
1039        devmap = smart_get_version(h_ata_ioctl);
1040        if (devmap < 0) {
1041                if (!is_permissive()) {
1042                        ata_close(0);
1043                        errno = ENOSYS;
1044                        return -1;
1045                }
1046                devmap = 0x0f;
1047        }
1048        ata_smartver_state[drive] = 1;
1049
1050        // Win9x/ME: Check device presence & type
1051        if (((devmap >> (drive & 0x3)) & 0x11) != 0x01) {
1052                unsigned char atapi = (devmap >> (drive & 0x3)) & 0x10;
1053                pout("%s: Drive %d %s (IDEDeviceMap=0x%02x).\n", devpath,
1054                     drive, (atapi?"is an ATAPI device":"does not exist"), devmap);
1055                // Win9x drive existence check may not work as expected
1056                // The atapi.sys driver incorrectly fills in the bIDEDeviceMap with 0x01
1057                // (The related KB Article Q196120 is no longer available)
1058                if (!is_permissive()) {
1059                        ata_close(0);
1060                        errno = (atapi ? ENOSYS : ENOENT);
1061                        return -1;
1062                }
1063        }
1064        // Use drive number as fd for ioctl
1065        return (drive & 0x3);
1066}
1067
1068
1069static void ata_close(int fd)
1070{
1071        ARGUSED(fd);
1072        CloseHandle(h_ata_ioctl);
1073        h_ata_ioctl = 0;
1074        if (ata_cur_options)
1075                free(ata_cur_options);
1076}
1077
1078
1079// Scan for ATA drives, fill bitmask of drives present, return #drives
1080
1081static int ata_scan(unsigned long * drives)
1082{
1083        int win9x = ((GetVersion() & 0x80000000) != 0);
1084        int cnt = 0, i;
1085
1086        for (i = 0; i <= 9; i++) {
1087                char devpath[30];
1088                GETVERSIONOUTPARAMS vers;
1089                DWORD num_out;
1090                HANDLE h;
1091                if (win9x)
1092                        strcpy(devpath, "\\\\.\\SMARTVSD");
1093                else
1094                        snprintf(devpath, sizeof(devpath)-1, "\\\\.\\PhysicalDrive%d", i);
1095
1096                // Open device
1097                if ((h = CreateFileA(devpath,
1098                        GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1099                        NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
1100                        if (con->reportataioctl > 1)
1101                                pout(" %s: Open failed, Error=%ld\n", devpath, GetLastError());
1102                        if (win9x)
1103                                break; // SMARTVSD.VXD missing or no ATA devices
1104                        continue; // Disk not found or access denied (break;?)
1105                }
1106
1107                // Get drive map
1108                memset(&vers, 0, sizeof(vers));
1109                if (!DeviceIoControl(h, SMART_GET_VERSION,
1110                        NULL, 0, &vers, sizeof(vers), &num_out, NULL)) {
1111                        if (con->reportataioctl)
1112                                pout(" %s: SMART_GET_VERSION failed, Error=%ld\n", devpath, GetLastError());
1113                        CloseHandle(h);
1114                        if (win9x)
1115                                break; // Should not happen
1116                        continue; // Non ATA disk or no SMART ioctl support (possibly SCSI disk)
1117                }
1118                CloseHandle(h);
1119
1120                if (con->reportataioctl)
1121                        pout(" %s: SMART_GET_VERSION (%ld bytes):\n"
1122                             "  Vers = %d.%d, Caps = 0x%lx, DeviceMap = 0x%02x\n",
1123                                devpath, num_out, vers.bVersion, vers.bRevision,
1124                                vers.fCapabilities, vers.bIDEDeviceMap);
1125
1126                if (win9x) {
1127                        // Check ATA device presence, remove ATAPI devices
1128                        drives[0] = (vers.bIDEDeviceMap & 0xf) & ~((vers.bIDEDeviceMap >> 4) & 0xf);
1129                        cnt = (drives[0]&1) + ((drives[0]>>1)&1) + ((drives[0]>>2)&1) + ((drives[0]>>3)&1);
1130                        break;
1131                }
1132
1133                // ATA drive exists and driver supports SMART ioctl
1134                drives[0] |= (1L << i);
1135                cnt++;
1136        }
1137
1138        return cnt;
1139}
1140
1141
1142/////////////////////////////////////////////////////////////////////////////
1143
1144// Interface to ATA devices.  See os_linux.c
1145int ata_command_interface(int fd, smart_command_set command, int select, char * data)
1146{
1147        IDEREGS regs;
1148        int datasize;
1149        const char * valid_options;
1150        int i;
1151
1152        if (!(0 <= fd && fd <= 3)) {
1153                errno = EBADF;
1154                return -1;
1155        }
1156
1157        // CMD,CYL default to SMART, changed by P?IDENTIFY and CHECK_POWER_MODE
1158        memset(&regs, 0, sizeof(regs));
1159        regs.bCommandReg = ATA_SMART_CMD;
1160        regs.bCylHighReg = SMART_CYL_HI; regs.bCylLowReg = SMART_CYL_LOW;
1161        datasize = 0;
1162
1163        // Try all IOCTLS by default: SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH
1164        valid_options = "saic";
1165
1166        switch (command) {
1167          case WRITE_LOG:
1168                // TODO. Requires DATA OUT support
1169                errno = ENOSYS;
1170                return -1;
1171          case CHECK_POWER_MODE:
1172                // Not a SMART command, needs IDE register return
1173                regs.bCommandReg = ATA_CHECK_POWER_MODE;
1174                regs.bCylLowReg = regs.bCylHighReg = 0;
1175                valid_options = "pai"; // Try GetDevicePowerState() first, ATA/IDE_PASS_THROUGH may spin up disk
1176                // Note: returns SectorCountReg in data[0]
1177                break;
1178          case READ_VALUES:
1179                regs.bFeaturesReg = ATA_SMART_READ_VALUES;
1180                regs.bSectorNumberReg = regs.bSectorCountReg = 1;
1181                datasize = 512;
1182                break;
1183          case READ_THRESHOLDS:
1184                regs.bFeaturesReg = ATA_SMART_READ_THRESHOLDS;
1185                regs.bSectorNumberReg = regs.bSectorCountReg = 1;
1186                datasize = 512;
1187                break;
1188          case READ_LOG:
1189                regs.bFeaturesReg = ATA_SMART_READ_LOG_SECTOR;
1190                regs.bSectorNumberReg = select;
1191                regs.bSectorCountReg = 1;
1192                // Note: SMART_RCV_DRIVE_DATA supports this only on Win9x/ME
1193                datasize = 512;
1194                break;
1195          case IDENTIFY:
1196                // Note: WinNT4/2000/XP return identify data cached during boot
1197                // (true for SMART_RCV_DRIVE_DATA and IOCTL_IDE_PASS_THROUGH)
1198                regs.bCommandReg = ATA_IDENTIFY_DEVICE;
1199                regs.bCylLowReg = regs.bCylHighReg = 0;
1200                regs.bSectorCountReg = 1;
1201                datasize = 512;
1202                break;
1203          case PIDENTIFY:
1204                regs.bCommandReg = ATA_IDENTIFY_PACKET_DEVICE;
1205                regs.bCylLowReg = regs.bCylHighReg = 0;
1206                regs.bSectorCountReg = 1;
1207                datasize = 512;
1208                break;
1209          case ENABLE:
1210                regs.bFeaturesReg = ATA_SMART_ENABLE;
1211                regs.bSectorNumberReg = 1;
1212                break;
1213          case DISABLE:
1214                regs.bFeaturesReg = ATA_SMART_DISABLE;
1215                regs.bSectorNumberReg = 1;
1216                break;
1217          case STATUS_CHECK:
1218                valid_options = "sai"; // Needs IDE register return
1219          case STATUS:
1220                regs.bFeaturesReg = ATA_SMART_STATUS;
1221                break;
1222          case AUTO_OFFLINE:
1223                regs.bFeaturesReg = ATA_SMART_AUTO_OFFLINE;
1224                regs.bSectorCountReg = select;   // YET NOTE - THIS IS A NON-DATA COMMAND!!
1225                break;
1226          case AUTOSAVE:
1227                regs.bFeaturesReg = ATA_SMART_AUTOSAVE;
1228                regs.bSectorCountReg = select;   // YET NOTE - THIS IS A NON-DATA COMMAND!!
1229                break;
1230          case IMMEDIATE_OFFLINE:
1231                regs.bFeaturesReg = ATA_SMART_IMMEDIATE_OFFLINE;
1232                regs.bSectorNumberReg = select;
1233                // Note: SMART_SEND_DRIVE_COMMAND supports ABORT_SELF_TEST this only on Win9x/ME
1234                break;
1235          default:
1236                pout("Unrecognized command %d in win32_ata_command_interface()\n"
1237                 "Please contact " PACKAGE_BUGREPORT "\n", command);
1238                errno = ENOSYS;
1239                return -1;
1240        }
1241
1242        // Try all valid ioctls in the order specified in dev_ioctls;
1243        for (i = 0; ; i++) {
1244                char opt = ata_cur_options[i];
1245                int rc;
1246
1247                if (!opt) {
1248                        // No IOCTL found
1249                        errno = ENOSYS;
1250                        return -1;
1251                }
1252                if (!strchr(valid_options, opt))
1253                        // Invalid for this command
1254                        continue;
1255
1256                errno = 0;
1257                assert(datasize == 0 || datasize == 512);
1258                switch (opt) {
1259                  default: assert(0);
1260                  case 's':
1261                        // call SMART_GET_VERSION once for each drive
1262                        assert(0 <= ata_driveno && ata_driveno < sizeof(ata_smartver_state));
1263                        if (ata_smartver_state[ata_driveno] > 1) {
1264                                rc = -1; errno = ENOSYS;
1265                                break;
1266                        }
1267                        if (!ata_smartver_state[ata_driveno]) {
1268                                if (smart_get_version(h_ata_ioctl) < 0) {
1269                                        if (!con->permissive) {
1270                                                pout("ATA/SATA driver is possibly a SCSI class driver not supporting SMART.\n");
1271                                                pout("If this is a SCSI disk, try \"scsi<adapter><id>\".\n");
1272                                                ata_smartver_state[ata_driveno] = 2;
1273                                                rc = -1; errno = ENOSYS;
1274                                                break;
1275                                        }
1276                                        con->permissive--;
1277                                }
1278                                ata_smartver_state[ata_driveno] = 1;
1279                        }
1280                        rc = smart_ioctl(h_ata_ioctl, fd, &regs, data, datasize);
1281                        break;
1282                  case 'a':
1283                        rc = ata_pass_through_ioctl(h_ata_ioctl, &regs, data, datasize);
1284                        break;
1285                  case 'i':
1286                        rc = ide_pass_through_ioctl(h_ata_ioctl, &regs, data, datasize);
1287                        break;
1288                  case 'c':
1289                        rc = ata_via_scsi_pass_through_ioctl(h_ata_ioctl, &regs, data, datasize);
1290                        break;
1291                  case 'p':
1292                        assert(command == CHECK_POWER_MODE && datasize == 0);
1293                        rc = get_device_power_state(h_ata_ioctl);
1294                        if (rc >= 0) { // Simulate ATA command result
1295                                regs.bSectorCountReg = (rc ? 0xff/*ACTIVE/IDLE*/ : 0x00/*STANDBY*/);
1296                                rc = 0;
1297                        }
1298                        break;
1299                }
1300
1301                if (!rc)
1302                        // Working ioctl found
1303                        break;
1304
1305                if (errno != ENOSYS)
1306                        // Abort on I/O error
1307                        return -1;
1308
1309                // CAUTION: *_ioctl() MUST NOT change "regs" Parameter in the ENOSYS case
1310        }
1311
1312        switch (command) {
1313          case CHECK_POWER_MODE:
1314                // Return power mode from SectorCountReg in data[0]
1315                data[0] = regs.bSectorCountReg;
1316                return 0;
1317
1318          case STATUS_CHECK:
1319                // Cyl low and Cyl high unchanged means "Good SMART status"
1320                if (regs.bCylHighReg == SMART_CYL_HI && regs.bCylLowReg == SMART_CYL_LOW)
1321                  return 0;
1322
1323                // These values mean "Bad SMART status"
1324                if (regs.bCylHighReg == 0x2c && regs.bCylLowReg == 0xf4)
1325                  return 1;
1326
1327                // We haven't gotten output that makes sense; print out some debugging info
1328                syserror("Error SMART Status command failed");
1329                pout("Please get assistance from %s\n", PACKAGE_HOMEPAGE);
1330                print_ide_regs(&regs, 1);
1331                errno = EIO;
1332                return -1;
1333
1334          default:
1335                return 0;
1336        }
1337        /*NOTREACHED*/
1338}
1339
1340
1341#ifndef HAVE_ATA_IDENTIFY_IS_CACHED
1342#error define of HAVE_ATA_IDENTIFY_IS_CACHED missing in config.h
1343#endif
1344
1345// Return true if OS caches the ATA identify sector
1346int ata_identify_is_cached(int fd)
1347{
1348        ARGUSED(fd);
1349        // WinNT4/2000/XP => true, Win9x/ME => false
1350        return ((GetVersion() & 0x80000000) == 0);
1351}
1352
1353
1354// Print not implemeted warning once
1355static void pr_not_impl(const char * what, int * warned)
1356{
1357        if (*warned)
1358                return;
1359        pout(
1360                "#######################################################################\n"
1361                "%s\n"
1362                "NOT IMPLEMENTED under Win32.\n"
1363                "Please contact " PACKAGE_BUGREPORT " if\n"
1364                "you want to help in porting smartmontools to Win32.\n"
1365                "#######################################################################\n"
1366                "\n", what
1367        );
1368        *warned = 1;
1369}
1370
1371// Interface to ATA devices behind 3ware escalade RAID controller cards.  See os_linux.c
1372int escalade_command_interface(int fd, int disknum, int escalade_type, smart_command_set command, int select, char *data)
1373{
1374        static int warned = 0;
1375        ARGUSED(fd); ARGUSED(disknum); ARGUSED(escalade_type); ARGUSED(command); ARGUSED(select); ARGUSED(data);
1376        pr_not_impl("3ware Escalade Controller command routine escalade_command_interface()", &warned);
1377        errno = ENOSYS;
1378        return -1;
1379}
1380
1381// Interface to ATA devices behind Marvell chip-set based controllers.  See os_linux.c
1382int marvell_command_interface(int fd, smart_command_set command, int select, char * data)
1383{
1384        static int warned = 0;
1385        ARGUSED(fd); ARGUSED(command); ARGUSED(select); ARGUSED(data);
1386        pr_not_impl("Marvell chip-set command routine marvell_command_interface()", &warned);
1387        errno = ENOSYS;
1388        return -1;
1389}
1390
1391// Interface to ATA devices behind HighPoint Raid controllers.  See os_linux.c
1392int highpoint_command_interface(int fd, smart_command_set command, int select, char * data)
1393{
1394        static int warned = 0;
1395        ARGUSED(fd); ARGUSED(command); ARGUSED(select); ARGUSED(data);
1396        pr_not_impl("HighPoint raid controller command routine highpoint_command_interface()", &warned);
1397        errno = ENOSYS;
1398        return -1;
1399}
1400
1401
1402/////////////////////////////////////////////////////////////////////////////
1403// ASPI Interface
1404/////////////////////////////////////////////////////////////////////////////
1405
1406#pragma pack(1)
1407
1408#define ASPI_SENSE_SIZE 18
1409
1410// ASPI SCSI Request block header
1411
1412typedef struct {
1413        unsigned char cmd;             // 00: Command code
1414        unsigned char status;          // 01: ASPI status
1415        unsigned char adapter;         // 02: Host adapter number
1416        unsigned char flags;           // 03: Request flags
1417        unsigned char reserved[4];     // 04: 0
1418} ASPI_SRB_HEAD;
1419
1420// SRB for host adapter inquiry
1421
1422typedef struct {
1423        ASPI_SRB_HEAD h;               // 00: Header
1424        unsigned char adapters;        // 08: Number of adapters
1425        unsigned char target_id;       // 09: Target ID ?
1426        char manager_id[16];           // 10: SCSI manager ID
1427        char adapter_id[16];           // 26: Host adapter ID
1428        unsigned char parameters[16];  // 42: Host adapter unique parmameters
1429} ASPI_SRB_INQUIRY;
1430
1431// SRB for get device type
1432
1433typedef struct {
1434        ASPI_SRB_HEAD h;               // 00: Header
1435        unsigned char target_id;       // 08: Target ID
1436        unsigned char lun;             // 09: LUN
1437        unsigned char devtype;         // 10: Device type
1438        unsigned char reserved;        // 11: Reserved
1439} ASPI_SRB_DEVTYPE;
1440
1441// SRB for SCSI I/O
1442
1443typedef struct {
1444        ASPI_SRB_HEAD h;               // 00: Header
1445        unsigned char target_id;       // 08: Target ID
1446        unsigned char lun;             // 09: LUN
1447        unsigned char reserved[2];     // 10: Reserved
1448        unsigned long data_size;       // 12: Data alloc. lenght
1449        void * data_addr;              // 16: Data buffer pointer
1450        unsigned char sense_size;      // 20: Sense alloc. length
1451        unsigned char cdb_size;        // 21: CDB length
1452        unsigned char host_status;     // 22: Host status
1453        unsigned char target_status;   // 23: Target status
1454        void * event_handle;           // 24: Event handle
1455        unsigned char workspace[20];   // 28: ASPI workspace
1456        unsigned char cdb[16+ASPI_SENSE_SIZE];
1457} ASPI_SRB_IO;
1458
1459// Macro to retrieve start of sense information
1460#define ASPI_SRB_SENSE(srb,cdbsz) ((srb)->cdb + 16)
1461
1462// SRB union
1463
1464typedef union {
1465        ASPI_SRB_HEAD h;       // Common header
1466        ASPI_SRB_INQUIRY q;    // Inquiry
1467        ASPI_SRB_DEVTYPE t;    // Device type
1468        ASPI_SRB_IO i;         // I/O
1469} ASPI_SRB;
1470
1471#pragma pack()
1472
1473// ASPI commands
1474#define ASPI_CMD_ADAPTER_INQUIRE        0x00
1475#define ASPI_CMD_GET_DEVICE_TYPE        0x01
1476#define ASPI_CMD_EXECUTE_IO             0x02
1477#define ASPI_CMD_ABORT_IO               0x03
1478
1479// Request flags
1480#define ASPI_REQFLAG_DIR_TO_HOST        0x08
1481#define ASPI_REQFLAG_DIR_TO_TARGET      0x10
1482#define ASPI_REQFLAG_DIR_NO_XFER        0x18
1483#define ASPI_REQFLAG_EVENT_NOTIFY       0x40
1484
1485// ASPI status
1486#define ASPI_STATUS_IN_PROGRESS         0x00
1487#define ASPI_STATUS_NO_ERROR            0x01
1488#define ASPI_STATUS_ABORTED             0x02
1489#define ASPI_STATUS_ABORT_ERR           0x03
1490#define ASPI_STATUS_ERROR               0x04
1491#define ASPI_STATUS_INVALID_COMMAND     0x80
1492#define ASPI_STATUS_INVALID_ADAPTER     0x81
1493#define ASPI_STATUS_INVALID_TARGET      0x82
1494#define ASPI_STATUS_NO_ADAPTERS         0xE8
1495
1496// Adapter (host) status
1497#define ASPI_HSTATUS_NO_ERROR           0x00
1498#define ASPI_HSTATUS_SELECTION_TIMEOUT  0x11
1499#define ASPI_HSTATUS_DATA_OVERRUN       0x12
1500#define ASPI_HSTATUS_BUS_FREE           0x13
1501#define ASPI_HSTATUS_BUS_PHASE_ERROR    0x14
1502#define ASPI_HSTATUS_BAD_SGLIST         0x1A
1503
1504// Target status
1505#define ASPI_TSTATUS_NO_ERROR           0x00
1506#define ASPI_TSTATUS_CHECK_CONDITION    0x02
1507#define ASPI_TSTATUS_BUSY               0x08
1508#define ASPI_TSTATUS_RESERV_CONFLICT    0x18
1509
1510
1511static HINSTANCE h_aspi_dll; // DLL handle
1512static UINT (* aspi_entry)(ASPI_SRB * srb); // ASPI entrypoint
1513static unsigned num_aspi_adapters;
1514
1515#ifdef __CYGWIN__
1516// h_aspi_dll+aspi_entry is not inherited by Cygwin's fork()
1517static DWORD aspi_dll_pid; // PID of DLL owner to detect fork()
1518#define aspi_entry_valid() (aspi_entry && (aspi_dll_pid == GetCurrentProcessId()))
1519#else
1520#define aspi_entry_valid() (!!aspi_entry)
1521#endif
1522
1523
1524static int aspi_call(ASPI_SRB * srb)
1525{
1526        int i;
1527        aspi_entry(srb);
1528        i = 0;
1529        while (((volatile ASPI_SRB *)srb)->h.status == ASPI_STATUS_IN_PROGRESS) {
1530                if (++i > 100/*10sek*/) {
1531                        pout("ASPI Adapter %u: Timed out\n", srb->h.adapter);
1532                        aspi_entry = 0;
1533                        h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
1534                        errno = EIO;
1535                        return -1;
1536                }
1537                if (con->reportscsiioctl > 1)
1538                        pout("ASPI Adapter %u: Waiting (%d) ...\n", srb->h.adapter, i);
1539                Sleep(100);
1540        }
1541        return 0;
1542}
1543
1544
1545// Get ASPI entrypoint from wnaspi32.dll
1546
1547static FARPROC aspi_get_address(const char * name, int verbose)
1548{
1549        FARPROC addr;
1550        assert(h_aspi_dll && h_aspi_dll != INVALID_HANDLE_VALUE);
1551
1552        if (!(addr = GetProcAddress(h_aspi_dll, name))) {
1553                if (verbose)
1554                        pout("Missing %s() in WNASPI32.DLL\n", name);
1555                aspi_entry = 0;
1556                FreeLibrary(h_aspi_dll);
1557                h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
1558                errno = ENOSYS;
1559                return 0;
1560        }
1561        return addr;
1562}
1563
1564
1565static int aspi_open_dll(int verbose)
1566{
1567        UINT (*aspi_info)(void);
1568        UINT info, rc;
1569
1570        assert(!aspi_entry_valid());
1571
1572        // Check structure layout
1573        assert(sizeof(ASPI_SRB_HEAD) == 8);
1574        assert(sizeof(ASPI_SRB_INQUIRY) == 58);
1575        assert(sizeof(ASPI_SRB_DEVTYPE) == 12);
1576        assert(sizeof(ASPI_SRB_IO) == 64+ASPI_SENSE_SIZE);
1577        assert(offsetof(ASPI_SRB,h.cmd) == 0);
1578        assert(offsetof(ASPI_SRB,h.flags) == 3);
1579        assert(offsetof(ASPI_SRB_IO,lun) == 9);
1580        assert(offsetof(ASPI_SRB_IO,data_addr) == 16);
1581        assert(offsetof(ASPI_SRB_IO,workspace) == 28);
1582        assert(offsetof(ASPI_SRB_IO,cdb) == 48);
1583
1584        if (h_aspi_dll == INVALID_HANDLE_VALUE) {
1585                // do not retry
1586                errno = ENOENT;
1587                return -1;
1588        }
1589
1590        // Load ASPI DLL
1591        if (!(h_aspi_dll = LoadLibraryA("WNASPI32.DLL"))) {
1592                if (verbose)
1593                        pout("Cannot load WNASPI32.DLL, Error=%ld\n", GetLastError());
1594                h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
1595                errno = ENOENT;
1596                return -1;
1597        }
1598        if (con->reportscsiioctl > 1) {
1599                // Print full path of WNASPI32.DLL
1600                char path[MAX_PATH];
1601                if (!GetModuleFileName(h_aspi_dll, path, sizeof(path)))
1602                        strcpy(path, "*unknown*");
1603                pout("Using ASPI interface \"%s\"\n", path);
1604        }
1605
1606        // Get ASPI entrypoints
1607        if (!(aspi_info = (UINT (*)(void))aspi_get_address("GetASPI32SupportInfo", verbose)))
1608                return -1;
1609        if (!(aspi_entry = (UINT (*)(ASPI_SRB *))aspi_get_address("SendASPI32Command", verbose)))
1610                return -1;
1611
1612        // Init ASPI manager and get number of adapters
1613        info = (aspi_info)();
1614        if (con->reportscsiioctl > 1)
1615                pout("GetASPI32SupportInfo() returns 0x%04x\n", info);
1616        rc = (info >> 8) & 0xff;
1617        if (rc == ASPI_STATUS_NO_ADAPTERS) {
1618                num_aspi_adapters = 0;
1619        }
1620        else if (rc == ASPI_STATUS_NO_ERROR) {
1621                num_aspi_adapters = info & 0xff;
1622        }
1623        else {
1624                if (verbose)
1625                        pout("Got strange 0x%04x from GetASPI32SupportInfo()\n", info);
1626                aspi_entry = 0;
1627                FreeLibrary(h_aspi_dll);
1628                h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
1629                errno = ENOENT;
1630                return -1;
1631        }
1632
1633        if (con->reportscsiioctl)
1634                pout("%u ASPI Adapter%s detected\n",num_aspi_adapters, (num_aspi_adapters!=1?"s":""));
1635
1636#ifdef __CYGWIN__
1637        // save PID to detect fork() in aspi_entry_valid()
1638        aspi_dll_pid = GetCurrentProcessId();
1639#endif
1640        assert(aspi_entry_valid());
1641        return 0;
1642}
1643
1644
1645static int aspi_io_call(ASPI_SRB * srb, unsigned timeout)
1646{
1647        HANDLE event;
1648        // Create event
1649        if (!(event = CreateEventA(NULL, FALSE, FALSE, NULL))) {
1650                pout("CreateEvent(): Error=%ld\n", GetLastError()); return -EIO;
1651        }
1652        srb->i.event_handle = event;
1653        srb->h.flags |= ASPI_REQFLAG_EVENT_NOTIFY;
1654        // Start ASPI request
1655        aspi_entry(srb);
1656        if (((volatile ASPI_SRB *)srb)->h.status == ASPI_STATUS_IN_PROGRESS) {
1657                // Wait for event
1658                DWORD rc = WaitForSingleObject(event, timeout*1000L);
1659                if (rc != WAIT_OBJECT_0) {
1660                        if (rc == WAIT_TIMEOUT) {
1661                                pout("ASPI Adapter %u, ID %u: Timed out after %u seconds\n",
1662                                        srb->h.adapter, srb->i.target_id, timeout);
1663                        }
1664                        else {
1665                                pout("WaitForSingleObject(%lx) = 0x%lx,%ld, Error=%ld\n",
1666                                        (unsigned long)event, rc, rc, GetLastError());
1667                        }
1668                        // TODO: ASPI_ABORT_IO command
1669                        aspi_entry = 0;
1670                        h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
1671                        return -EIO;
1672                }
1673        }
1674        CloseHandle(event);
1675        return 0;
1676}
1677
1678
1679static int aspi_open(unsigned adapter, unsigned id)
1680{
1681        ASPI_SRB srb;
1682        if (!(adapter <= 9 && id < 16)) {
1683                errno = ENOENT;
1684                return -1;
1685        }
1686
1687        if (!aspi_entry_valid()) {
1688                if (aspi_open_dll(1/*verbose*/))
1689                        return -1;
1690        }
1691
1692        // Adapter OK?
1693        if (adapter >= num_aspi_adapters) {
1694                pout("ASPI Adapter %u does not exist (%u Adapter%s detected).\n",
1695                        adapter, num_aspi_adapters, (num_aspi_adapters!=1?"s":""));
1696                if (!is_permissive()) {
1697                        errno = ENOENT;
1698                        return -1;
1699                }
1700        }
1701
1702        // Device present ?
1703        memset(&srb, 0, sizeof(srb));
1704        srb.h.cmd = ASPI_CMD_GET_DEVICE_TYPE;
1705        srb.h.adapter = adapter; srb.i.target_id = id;
1706        if (aspi_call(&srb)) {
1707                errno = EIO;
1708                return -1;
1709        }
1710        if (srb.h.status != ASPI_STATUS_NO_ERROR) {
1711                pout("ASPI Adapter %u, ID %u: No such device (Status=0x%02x)\n", adapter, id, srb.h.status);
1712                if (!is_permissive()) {
1713                        errno = (srb.h.status == ASPI_STATUS_INVALID_TARGET ? ENOENT : EIO);
1714                        return -1;
1715                }
1716        }
1717        else if (con->reportscsiioctl)
1718                pout("ASPI Adapter %u, ID %u: Device Type=0x%02x\n", adapter, id, srb.t.devtype);
1719
1720        return (0x0100 | ((adapter & 0xf)<<4) | (id & 0xf));
1721}
1722
1723
1724static void aspi_close(int fd)
1725{
1726        // No FreeLibrary(h_aspi_dll) to prevent problems with ASPI threads
1727        ARGUSED(fd);
1728}
1729
1730
1731// Scan for SCSI drives, fill bitmask [adapter:0-9][id:0-7] of drives present,
1732// return #drives
1733
1734static int aspi_scan(unsigned long * drives)
1735{
1736        int cnt = 0;
1737        unsigned ad;
1738
1739        if (!aspi_entry_valid()) {
1740                if (aspi_open_dll(con->reportscsiioctl/*default is quiet*/))
1741                        return 0;
1742        }
1743
1744        for (ad = 0; ad < num_aspi_adapters; ad++) {
1745                ASPI_SRB srb; unsigned id;
1746
1747                if (ad > 9) {
1748                        if (con->reportscsiioctl)
1749                                pout(" ASPI Adapter %u: Ignored\n", ad);
1750                        continue;
1751                }
1752
1753                // Get adapter name
1754                memset(&srb, 0, sizeof(srb));
1755                srb.h.cmd = ASPI_CMD_ADAPTER_INQUIRE;
1756                srb.h.adapter = ad;
1757                if (aspi_call(&srb))
1758                        return 0;
1759
1760                if (srb.h.status != ASPI_STATUS_NO_ERROR) {
1761                        if (con->reportscsiioctl)
1762                                pout(" ASPI Adapter %u: Status=0x%02x\n", ad, srb.h.status);
1763                        continue;
1764                }
1765
1766                if (con->reportscsiioctl) {
1767                        int i;
1768                        for (i = 1; i < 16 && srb.q.adapter_id[i]; i++)
1769                                if (!(' ' <= srb.q.adapter_id[i] && srb.q.adapter_id[i] <= '~'))
1770                                        srb.q.adapter_id[i] = '?';
1771                        pout(" ASPI Adapter %u (\"%.16s\"):\n", ad, srb.q.adapter_id);
1772                }
1773
1774                for (id = 0; id <= 7; id++) {
1775                        // Get device type
1776                        memset(&srb, 0, sizeof(srb));
1777                        srb.h.cmd = ASPI_CMD_GET_DEVICE_TYPE;
1778                        srb.h.adapter = ad; srb.i.target_id = id;
1779                        if (aspi_call(&srb))
1780                                return 0;
1781                        if (srb.h.status != ASPI_STATUS_NO_ERROR) {
1782                                if (con->reportscsiioctl > 1)
1783                                        pout("  ID %u: No such device (Status=0x%02x)\n", id, srb.h.status);
1784                                continue;
1785                        }
1786                        if (con->reportscsiioctl)
1787                                pout("  ID %u: Device Type=0x%02x\n", id, srb.t.devtype);
1788                        if (srb.t.devtype == 0x00/*HDD*/) {
1789                                drives[ad >> 2] |= (1L << (((ad & 0x3) << 3) + id));
1790                                cnt++;
1791                        }
1792                }
1793        }
1794        return cnt;
1795}
1796
1797
1798/////////////////////////////////////////////////////////////////////////////
1799
1800// Interface to SCSI devices.  See os_linux.c
1801int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report)
1802{
1803        ASPI_SRB srb;
1804
1805        if (!aspi_entry_valid())
1806                return -EBADF;
1807        if (!((fd & ~0xff) == 0x100))
1808                return -EBADF;
1809
1810        if (!(iop->cmnd_len == 6 || iop->cmnd_len == 10 || iop->cmnd_len == 12 || iop->cmnd_len == 16)) {
1811                pout("do_scsi_cmnd_io: bad CDB length\n");
1812                return -EINVAL;
1813        }
1814
1815        if (report > 0) {
1816                // From os_linux.c
1817                int k, j;
1818                const unsigned char * ucp = iop->cmnd;
1819                const char * np;
1820                char buff[256];
1821                const int sz = (int)sizeof(buff);
1822
1823                np = scsi_get_opcode_name(ucp[0]);
1824                j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
1825                for (k = 0; k < (int)iop->cmnd_len; ++k)
1826                        j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);
1827                if ((report > 1) && 
1828                        (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
1829                        int trunc = (iop->dxfer_len > 256) ? 1 : 0;
1830
1831                        j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n  Outgoing "
1832                                                  "data, len=%d%s:\n", (int)iop->dxfer_len,
1833                                                  (trunc ? " [only first 256 bytes shown]" : ""));
1834                        dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
1835                }
1836                else
1837                        j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
1838                pout(buff);
1839        }
1840
1841        memset(&srb, 0, sizeof(srb));
1842        srb.h.cmd = ASPI_CMD_EXECUTE_IO;
1843        srb.h.adapter = ((fd >> 4) & 0xf);
1844        srb.i.target_id = (fd & 0xf);
1845        //srb.i.lun = 0;
1846        srb.i.sense_size = ASPI_SENSE_SIZE;
1847        srb.i.cdb_size = iop->cmnd_len;
1848        memcpy(srb.i.cdb, iop->cmnd, iop->cmnd_len);
1849
1850        switch (iop->dxfer_dir) {
1851                case DXFER_NONE:
1852                        srb.h.flags = ASPI_REQFLAG_DIR_NO_XFER;
1853                        break;
1854                case DXFER_FROM_DEVICE:
1855                        srb.h.flags = ASPI_REQFLAG_DIR_TO_HOST;
1856                        srb.i.data_size = iop->dxfer_len;
1857                        srb.i.data_addr = iop->dxferp;
1858                        break;
1859                case DXFER_TO_DEVICE:
1860                        srb.h.flags = ASPI_REQFLAG_DIR_TO_TARGET;
1861                        srb.i.data_size = iop->dxfer_len;
1862                        srb.i.data_addr = iop->dxferp;
1863                        break;
1864                default:
1865                        pout("do_scsi_cmnd_io: bad dxfer_dir\n");
1866                        return -EINVAL;
1867        }
1868
1869        iop->resp_sense_len = 0;
1870        iop->scsi_status = 0;
1871        iop->resid = 0;
1872
1873        if (aspi_io_call(&srb, (iop->timeout ? iop->timeout : 60))) {
1874                // Timeout
1875                return -EIO;
1876        }
1877
1878        if (srb.h.status != ASPI_STATUS_NO_ERROR) {
1879                if (   srb.h.status        == ASPI_STATUS_ERROR
1880                    && srb.i.host_status   == ASPI_HSTATUS_NO_ERROR
1881                    && srb.i.target_status == ASPI_TSTATUS_CHECK_CONDITION) {
1882                        // Sense valid
1883                        const unsigned char * sense = ASPI_SRB_SENSE(&srb.i, iop->cmnd_len);
1884                        int len = (ASPI_SENSE_SIZE < iop->max_sense_len ? ASPI_SENSE_SIZE : iop->max_sense_len);
1885                        iop->scsi_status = SCSI_STATUS_CHECK_CONDITION;
1886                        if (len > 0 && iop->sensep) {
1887                                memcpy(iop->sensep, sense, len);
1888                                iop->resp_sense_len = len;
1889                                if (report > 1) {
1890                                        pout("  >>> Sense buffer, len=%d:\n", (int)len);
1891                                        dStrHex(iop->sensep, len , 1);
1892                                }
1893                        }
1894                        if (report) {
1895                                pout("  sense_key=%x asc=%x ascq=%x\n",
1896                                 sense[2] & 0xf, sense[12], sense[13]);
1897                        }
1898                        return 0;
1899                }
1900                else {
1901                        if (report)
1902                                pout("  ASPI call failed, (0x%02x,0x%02x,0x%02x)\n", srb.h.status, srb.i.host_status, srb.i.target_status);
1903                        return -EIO;
1904                }
1905        }
1906
1907        if (report > 0)
1908                pout("  OK\n");
1909
1910        if (iop->dxfer_dir == DXFER_FROM_DEVICE && report > 1) {
1911                 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
1912                 pout("  Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
1913                          (trunc ? " [only first 256 bytes shown]" : ""));
1914                                dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
1915        }
1916
1917        return 0;
1918}
Note: See TracBrowser for help on using the browser.