4 * Home page of code is: http://smartmontools.sourceforge.net
6 * Copyright (C) 2004-6 Christian Franke <smartmontools-support@lists.sourceforge.net>
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)
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.
23 extern smartmonctrl
* con
; // con->permissive,reportataioctl
26 extern int64_t bytes
; // malloc() byte count
32 #define assert(x) /**/
34 #define WIN32_LEAN_AND_MEAN
36 #include <stddef.h> // offsetof()
37 #include <io.h> // access()
39 #define ARGUSED(x) ((void)(x))
41 // Needed by '-V' option (CVS versioning) of smartd/smartctl
42 const char *os_XXXX_c_cvsid
="$Id: os_win32.c,v 1.33 2006/04/07 15:02:19 chrfranke Exp $"
43 ATACMDS_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID
;
46 #ifndef HAVE_GET_OS_VERSION_STR
47 #error define of HAVE_GET_OS_VERSION_STR missing in config.h
50 // Return build host and OS version as static string
51 const char * get_os_version_str()
53 static char vstr
[sizeof(SMARTMONTOOLS_BUILD_HOST
)-3-1+sizeof("-2003r2-sp2.1")+13];
54 char * const vptr
= vstr
+sizeof(SMARTMONTOOLS_BUILD_HOST
)-3-1;
55 const int vlen
= sizeof(vstr
)-(sizeof(SMARTMONTOOLS_BUILD_HOST
)-3);
60 // remove "-pc" to avoid long lines
61 assert(!strncmp(SMARTMONTOOLS_BUILD_HOST
+5, "pc-", 3));
62 strcpy(vstr
, "i686-"); strcpy(vstr
+5, SMARTMONTOOLS_BUILD_HOST
+5+3);
63 assert(vptr
== vstr
+strlen(vstr
) && vptr
+vlen
+1 == vstr
+sizeof(vstr
));
65 memset(&vi
, 0, sizeof(vi
));
66 vi
.dwOSVersionInfoSize
= sizeof(vi
);
67 if (!GetVersionExA((OSVERSIONINFOA
*)&vi
)) {
68 memset(&vi
, 0, sizeof(vi
));
69 vi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
70 if (!GetVersionExA((OSVERSIONINFOA
*)&vi
))
74 if (vi
.dwPlatformId
> 0xff || vi
.dwMajorVersion
> 0xff || vi
.dwMinorVersion
> 0xff)
77 switch (vi
.dwPlatformId
<< 16 | vi
.dwMajorVersion
<< 8 | vi
.dwMinorVersion
) {
78 case VER_PLATFORM_WIN32_WINDOWS
<<16|0x0400| 0:
79 w
= (vi
.szCSDVersion
[1] == 'B' ||
80 vi
.szCSDVersion
[1] == 'C' ? "95-osr2" : "95"); break;
81 case VER_PLATFORM_WIN32_WINDOWS
<<16|0x0400|10:
82 w
= (vi
.szCSDVersion
[1] == 'A' ? "98se" : "98"); break;
83 case VER_PLATFORM_WIN32_WINDOWS
<<16|0x0400|90: w
= "me"; break;
84 //case VER_PLATFORM_WIN32_NT <<16|0x0300|51: w = "nt3.51"; break;
85 case VER_PLATFORM_WIN32_NT
<<16|0x0400| 0: w
= "nt4"; break;
86 case VER_PLATFORM_WIN32_NT
<<16|0x0500| 0: w
= "2000"; break;
87 case VER_PLATFORM_WIN32_NT
<<16|0x0500| 1:
88 w
= (!GetSystemMetrics(87/*SM_MEDIACENTER*/) ? "xp"
90 case VER_PLATFORM_WIN32_NT
<<16|0x0500| 2:
91 w
= (!GetSystemMetrics(89/*SM_SERVERR2*/) ? "2003"
93 case VER_PLATFORM_WIN32_NT
<<16|0x0600| 0: w
= "vista"; break;
94 default: w
= 0; break;
98 snprintf(vptr
, vlen
, "-%s%lu.%lu",
99 (vi
.dwPlatformId
==VER_PLATFORM_WIN32_NT
? "nt" : "9x"),
100 vi
.dwMajorVersion
, vi
.dwMinorVersion
);
101 else if (vi
.wServicePackMinor
)
102 snprintf(vptr
, vlen
, "-%s-sp%u.%u", w
, vi
.wServicePackMajor
, vi
.wServicePackMinor
);
103 else if (vi
.wServicePackMajor
)
104 snprintf(vptr
, vlen
, "-%s-sp%u", w
, vi
.wServicePackMajor
);
106 snprintf(vptr
, vlen
, "-%s", w
);
111 static int ata_open(int drive
);
112 static void ata_close(int fd
);
113 static int ata_scan(unsigned long * drives
);
115 static int aspi_open(unsigned adapter
, unsigned id
);
116 static void aspi_close(int fd
);
117 static int aspi_scan(unsigned long * drives
);
120 static int is_permissive()
122 if (con
->permissive
<= 0) {
123 pout("To continue, add one or more '-T permissive' options.\n");
130 static const char * skipdev(const char * s
)
132 return (!strncmp(s
, "/dev/", 5) ? s
+ 5 : s
);
136 // tries to guess device type given the name (a path). See utility.h
137 // for return values.
138 int guess_device_type (const char * dev_name
)
140 dev_name
= skipdev(dev_name
);
141 if (!strncmp(dev_name
, "hd", 2))
142 return CONTROLLER_ATA
;
143 if (!strncmp(dev_name
, "scsi", 4))
144 return CONTROLLER_SCSI
;
145 return CONTROLLER_UNKNOWN
;
149 // makes a list of ATA or SCSI devices for the DEVICESCAN directive of
150 // smartd. Returns number N of devices, or -1 if out of
151 // memory. Allocates N+1 arrays: one of N pointers (devlist), the
152 // others each contain null-terminated character strings.
153 int make_device_names (char*** devlist
, const char* type
)
155 unsigned long drives
[3];
156 int i
, j
, n
, nmax
, sz
;
159 drives
[0] = drives
[1] = drives
[2] = 0;
160 if (!strcmp(type
, "ATA")) {
161 // bit i set => drive i present
162 n
= ata_scan(drives
);
166 else if (!strcmp(type
, "SCSI")) {
167 // bit i set => drive with ID (i & 0x7) on adapter (i >> 3) present
168 n
= aspi_scan(drives
);
169 path
= "/dev/scsi00";
179 sz
= n
* sizeof(char **);
180 *devlist
= (char **)malloc(sz
); bytes
+= sz
;
183 for (i
= j
= 0; i
< n
; i
++) {
186 s
= (char *)malloc(sz
); bytes
+= sz
;
188 while (j
< nmax
&& !(drives
[j
>> 5] & (1L << (j
& 0x1f))))
193 s
[sz
-2] += j
; // /dev/hd[a-j]
196 assert((j
>> 3) <= 9);
197 s
[sz
-3] += (j
>> 3); // /dev/scsi[0-9].....
198 s
[sz
-2] += (j
& 0x7); // .....[0-7]
207 // Like open(). Return positive integer handle, only used by
208 // functions below. type="ATA" or "SCSI". If you need to store extra
209 // information about your devices, create a private internal array
210 // within this file (see os_freebsd.c for an example).
211 int deviceopen(const char * pathname
, char *type
)
214 pathname
= skipdev(pathname
);
215 len
= strlen(pathname
);
217 if (!strcmp(type
, "ATA")) {
218 // hd[a-z] => ATA 0-9
219 if (!(len
== 3 && pathname
[0] == 'h' && pathname
[1] == 'd'
220 && 'a' <= pathname
[2] && pathname
[2] <= 'j')) {
224 return ata_open(pathname
[2] - 'a');
227 if (!strcmp(type
, "SCSI")) {
228 // scsi[0-9][0-f] => SCSI Adapter 0-9, ID 0-15, LUN 0
229 unsigned adapter
= ~0, id
= ~0; int n
= -1;
230 if (!(sscanf(pathname
,"scsi%1u%1x%n", &adapter
, &id
, &n
) == 2 && n
== len
)) {
234 return aspi_open(adapter
, id
);
241 // Like close(). Acts only on handles returned by above function.
242 // (Never called in smartctl!)
243 int deviceclose(int fd
)
255 // print examples for smartctl
256 void print_smartctl_examples(){
257 printf("=================================================== SMARTCTL EXAMPLES =====\n\n"
258 " smartctl -a /dev/hda (Prints all SMART information)\n\n"
259 #ifdef HAVE_GETOPT_LONG
260 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/hda\n"
261 " (Enables SMART on first disk)\n\n"
262 " smartctl -t long /dev/hda (Executes extended disk self-test)\n\n"
263 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/hda\n"
264 " (Prints Self-Test & Attribute errors)\n"
266 " smartctl -s on -o on -S on /dev/hda (Enables SMART on first disk)\n"
267 " smartctl -t long /dev/hda (Executes extended disk self-test)\n"
268 " smartctl -A -l selftest -q errorsonly /dev/hda\n"
269 " (Prints Self-Test & Attribute errors)\n"
271 " smartctl -a /dev/scsi21\n"
272 " (Prints all information for SCSI disk on ASPI adapter 2, ID 1)\n"
277 /////////////////////////////////////////////////////////////////////////////
279 /////////////////////////////////////////////////////////////////////////////
281 // SMART_* IOCTLs, also known as DFP_* (Disk Fault Protection)
283 // Deklarations from:
284 // http://cvs.sourceforge.net/viewcvs.py/mingw/w32api/include/ddk/ntdddisk.h?rev=1.3
286 #define FILE_READ_ACCESS 0x0001
287 #define FILE_WRITE_ACCESS 0x0002
288 #define METHOD_BUFFERED 0
289 #define CTL_CODE(DeviceType, Function, Method, Access) (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
291 #define FILE_DEVICE_DISK 7
292 #define IOCTL_DISK_BASE FILE_DEVICE_DISK
294 #define SMART_GET_VERSION \
295 CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS)
297 #define SMART_RCV_DRIVE_DATA \
298 CTL_CODE(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
300 #define SMART_SEND_DRIVE_COMMAND \
301 CTL_CODE(IOCTL_DISK_BASE, 0x0021, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
303 #define SMART_CYL_LOW 0x4F
304 #define SMART_CYL_HI 0xC2
308 typedef struct _GETVERSIONOUTPARAMS
{
315 } GETVERSIONOUTPARAMS
, *PGETVERSIONOUTPARAMS
, *LPGETVERSIONOUTPARAMS
;
317 typedef struct _IDEREGS
{
319 UCHAR bSectorCountReg
;
320 UCHAR bSectorNumberReg
;
326 } IDEREGS
, *PIDEREGS
, *LPIDEREGS
;
328 typedef struct _SENDCMDINPARAMS
{
335 } SENDCMDINPARAMS
, *PSENDCMDINPARAMS
, *LPSENDCMDINPARAMS
;
337 /* DRIVERSTATUS.bDriverError constants (just for info, not used)
338 #define SMART_NO_ERROR 0
339 #define SMART_IDE_ERROR 1
340 #define SMART_INVALID_FLAG 2
341 #define SMART_INVALID_COMMAND 3
342 #define SMART_INVALID_BUFFER 4
343 #define SMART_INVALID_DRIVE 5
344 #define SMART_INVALID_IOCTL 6
345 #define SMART_ERROR_NO_MEM 7
346 #define SMART_INVALID_REGISTER 8
347 #define SMART_NOT_SUPPORTED 9
348 #define SMART_NO_IDE_DEVICE 10
351 typedef struct _DRIVERSTATUS
{
356 } DRIVERSTATUS
, *PDRIVERSTATUS
, *LPDRIVERSTATUS
;
358 typedef struct _SENDCMDOUTPARAMS
{
360 DRIVERSTATUS DriverStatus
;
362 } SENDCMDOUTPARAMS
, *PSENDCMDOUTPARAMS
, *LPSENDCMDOUTPARAMS
;
367 /////////////////////////////////////////////////////////////////////////////
369 static void print_ide_regs(const IDEREGS
* r
, int out
)
371 pout("%s=0x%02x,%s=0x%02x, SC=0x%02x, NS=0x%02x, CL=0x%02x, CH=0x%02x, SEL=0x%02x\n",
372 (out
?"STS":"CMD"), r
->bCommandReg
, (out
?"ERR":" FR"), r
->bFeaturesReg
,
373 r
->bSectorCountReg
, r
->bSectorNumberReg
, r
->bCylLowReg
, r
->bCylHighReg
, r
->bDriveHeadReg
);
376 static void print_ide_regs_io(const IDEREGS
* ri
, const IDEREGS
* ro
)
378 pout(" Input : "); print_ide_regs(ri
, 0);
380 pout(" Output: "); print_ide_regs(ro
, 1);
384 /////////////////////////////////////////////////////////////////////////////
386 // call SMART_* ioctl
388 static int smart_ioctl(HANDLE hdevice
, int drive
, IDEREGS
* regs
, char * data
, unsigned datasize
)
390 SENDCMDINPARAMS inpar
;
391 unsigned char outbuf
[sizeof(SENDCMDOUTPARAMS
)-1 + 512];
392 const SENDCMDOUTPARAMS
* outpar
;
394 unsigned int size_out
;
397 assert(SMART_SEND_DRIVE_COMMAND
== 0x07c084);
398 assert(SMART_RCV_DRIVE_DATA
== 0x07c088);
399 assert(sizeof(SENDCMDINPARAMS
)-1 == 32);
400 assert(sizeof(SENDCMDOUTPARAMS
)-1 == 16);
402 memset(&inpar
, 0, sizeof(inpar
));
403 inpar
.irDriveRegs
= *regs
;
404 // drive is set to 0-3 on Win9x only
405 inpar
.irDriveRegs
.bDriveHeadReg
= 0xA0 | ((drive
& 1) << 4);
406 inpar
.bDriveNumber
= drive
;
408 assert(datasize
== 0 || datasize
== 512);
410 code
= SMART_RCV_DRIVE_DATA
; name
= "SMART_RCV_DRIVE_DATA";
411 inpar
.cBufferSize
= size_out
= 512;
414 code
= SMART_SEND_DRIVE_COMMAND
; name
= "SMART_SEND_DRIVE_COMMAND";
415 if (regs
->bFeaturesReg
== ATA_SMART_STATUS
)
416 size_out
= sizeof(IDEREGS
); // ioctl returns new IDEREGS as data
417 // Note: cBufferSize must be 0 on Win9x
422 memset(&outbuf
, 0, sizeof(outbuf
));
424 if (!DeviceIoControl(hdevice
, code
, &inpar
, sizeof(SENDCMDINPARAMS
)-1,
425 outbuf
, sizeof(SENDCMDOUTPARAMS
)-1 + size_out
, &num_out
, NULL
)) {
426 // CAUTION: DO NOT change "regs" Parameter in this case, see ata_command_interface()
427 long err
= GetLastError();
428 if (con
->reportataioctl
&& (err
!= ERROR_INVALID_PARAMETER
|| con
->reportataioctl
> 1)) {
429 pout(" %s failed, Error=%ld\n", name
, err
);
430 print_ide_regs_io(regs
, NULL
);
432 errno
= ( err
== ERROR_INVALID_FUNCTION
/*9x*/
433 || err
== ERROR_INVALID_PARAMETER
/*NT/2K/XP*/ ? ENOSYS
: EIO
);
436 // NOTE: On Win9x, inpar.irDriveRegs now contains the returned regs
438 outpar
= (const SENDCMDOUTPARAMS
*)outbuf
;
440 if (outpar
->DriverStatus
.bDriverError
) {
441 if (con
->reportataioctl
) {
442 pout(" %s failed, DriverError=0x%02x, IDEError=0x%02x\n", name
,
443 outpar
->DriverStatus
.bDriverError
, outpar
->DriverStatus
.bIDEError
);
444 print_ide_regs_io(regs
, NULL
);
450 if (con
->reportataioctl
> 1) {
451 pout(" %s suceeded, bytes returned: %lu (buffer %lu)\n", name
,
452 num_out
, outpar
->cBufferSize
);
453 print_ide_regs_io(regs
, (regs
->bFeaturesReg
== ATA_SMART_STATUS
?
454 (const IDEREGS
*)(outpar
->bBuffer
) : NULL
));
458 memcpy(data
, outpar
->bBuffer
, 512);
459 else if (regs
->bFeaturesReg
== ATA_SMART_STATUS
)
460 *regs
= *(const IDEREGS
*)(outpar
->bBuffer
);
466 /////////////////////////////////////////////////////////////////////////////
468 // IDE PASS THROUGH for W2K/XP (does not work on W9x/NT4)
469 // Only used for SMART commands not supported by SMART_* IOCTLs
471 // Based on WinATA.cpp, 2002 c't/Matthias Withopf
472 // ftp://ftp.heise.de/pub/ct/listings/0207-218.zip
474 #define FILE_DEVICE_CONTROLLER 4
475 #define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER
477 #define IOCTL_IDE_PASS_THROUGH \
478 CTL_CODE(IOCTL_SCSI_BASE, 0x040A, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
484 ULONG DataBufferSize
;
491 /////////////////////////////////////////////////////////////////////////////
493 static int ide_pass_through_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, unsigned datasize
)
495 unsigned int size
= sizeof(ATA_PASS_THROUGH
)-1 + datasize
;
496 ATA_PASS_THROUGH
* buf
= (ATA_PASS_THROUGH
*)VirtualAlloc(NULL
, size
, MEM_COMMIT
, PAGE_READWRITE
);
498 const unsigned char magic
= 0xcf;
499 assert(sizeof(ATA_PASS_THROUGH
)-1 == 12);
500 assert(IOCTL_IDE_PASS_THROUGH
== 0x04d028);
508 buf
->DataBufferSize
= datasize
;
510 buf
->DataBuffer
[0] = magic
;
512 if (!DeviceIoControl(hdevice
, IOCTL_IDE_PASS_THROUGH
,
513 buf
, size
, buf
, size
, &num_out
, NULL
)) {
514 long err
= GetLastError();
515 if (con
->reportataioctl
)
516 pout(" IOCTL_IDE_PASS_THROUGH failed, Error=%ld\n", err
);
517 VirtualFree(buf
, 0, MEM_RELEASE
);
518 errno
= (err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
523 if (buf
->IdeReg
.bCommandReg
/*Status*/ & 0x01) {
524 if (con
->reportataioctl
) {
525 pout(" IOCTL_IDE_PASS_THROUGH command failed:\n");
526 print_ide_regs_io(regs
, &buf
->IdeReg
);
528 VirtualFree(buf
, 0, MEM_RELEASE
);
533 // Check and copy data
536 || (buf
->DataBuffer
[0] == magic
&& !nonempty(buf
->DataBuffer
+1, datasize
-1))) {
537 if (con
->reportataioctl
) {
538 pout(" IOCTL_IDE_PASS_THROUGH output data missing (%lu, %lu)\n",
539 num_out
, buf
->DataBufferSize
);
540 print_ide_regs_io(regs
, &buf
->IdeReg
);
542 VirtualFree(buf
, 0, MEM_RELEASE
);
546 memcpy(data
, buf
->DataBuffer
, datasize
);
549 if (con
->reportataioctl
> 1) {
550 pout(" IOCTL_IDE_PASS_THROUGH suceeded, bytes returned: %lu (buffer %lu)\n",
551 num_out
, buf
->DataBufferSize
);
552 print_ide_regs_io(regs
, &buf
->IdeReg
);
556 // Caution: VirtualFree() fails if parameter "dwSize" is nonzero
557 VirtualFree(buf
, 0, MEM_RELEASE
);
563 /////////////////////////////////////////////////////////////////////////////
565 // ATA PASS THROUGH via SCSI PASS THROUGH for NT4 only
566 // Only used for SMART commands not supported by SMART_* IOCTLs
568 // Declarations from:
569 // http://cvs.sourceforge.net/viewcvs.py/mingw/w32api/include/ddk/ntddscsi.h?rev=1.2
571 #define IOCTL_SCSI_PASS_THROUGH \
572 CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
574 #define SCSI_IOCTL_DATA_OUT 0
575 #define SCSI_IOCTL_DATA_IN 1
576 #define SCSI_IOCTL_DATA_UNSPECIFIED 2
577 // undocumented SCSI opcode to for ATA passthrough
578 #define SCSIOP_ATA_PASSTHROUGH 0xCC
580 typedef struct _SCSI_PASS_THROUGH
{
587 UCHAR SenseInfoLength
;
589 ULONG DataTransferLength
;
591 ULONG
/*_PTR*/ DataBufferOffset
;
592 ULONG SenseInfoOffset
;
594 } SCSI_PASS_THROUGH
, *PSCSI_PASS_THROUGH
;
597 /////////////////////////////////////////////////////////////////////////////
599 static int ata_via_scsi_pass_through_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, unsigned datasize
)
602 SCSI_PASS_THROUGH spt
;
604 UCHAR ucSenseBuf
[32];
605 UCHAR ucDataBuf
[512];
606 } SCSI_PASS_THROUGH_WITH_BUFFERS
;
608 SCSI_PASS_THROUGH_WITH_BUFFERS sb
;
612 const unsigned char magic
= 0xcf;
614 assert(sizeof(SCSI_PASS_THROUGH
) == 44);
615 assert(IOCTL_SCSI_PASS_THROUGH
== 0x04d004);
617 memset(&sb
, 0, sizeof(sb
));
618 sb
.spt
.Length
= sizeof(SCSI_PASS_THROUGH
);
622 sb
.spt
.CdbLength
= 10; sb
.spt
.SenseInfoLength
= 24;
623 sb
.spt
.TimeOutValue
= 10;
624 sb
.spt
.SenseInfoOffset
= offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS
, ucSenseBuf
);
625 size
= offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS
, ucDataBuf
);
626 sb
.spt
.DataBufferOffset
= size
;
629 if (datasize
> sizeof(sb
.ucDataBuf
)) {
633 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_IN
;
634 sb
.spt
.DataTransferLength
= datasize
;
636 sb
.ucDataBuf
[0] = magic
;
639 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_UNSPECIFIED
;
640 //sb.spt.DataTransferLength = 0;
643 // Use pseudo SCSI command followed by registers
644 sb
.spt
.Cdb
[0] = SCSIOP_ATA_PASSTHROUGH
;
645 cdbregs
= (IDEREGS
*)(sb
.spt
.Cdb
+2);
648 if (!DeviceIoControl(hdevice
, IOCTL_SCSI_PASS_THROUGH
,
649 &sb
, size
, &sb
, size
, &num_out
, NULL
)) {
650 long err
= GetLastError();
651 if (con
->reportataioctl
)
652 pout(" ATA via IOCTL_SCSI_PASS_THROUGH failed, Error=%ld\n", err
);
653 errno
= (err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
657 // Cannot check ATA status, because command does not return IDEREGS
659 // Check and copy data
662 || (sb
.ucDataBuf
[0] == magic
&& !nonempty(sb
.ucDataBuf
+1, datasize
-1))) {
663 if (con
->reportataioctl
) {
664 pout(" ATA via IOCTL_SCSI_PASS_THROUGH output data missing (%lu)\n", num_out
);
665 print_ide_regs_io(regs
, NULL
);
670 memcpy(data
, sb
.ucDataBuf
, datasize
);
673 if (con
->reportataioctl
> 1) {
674 pout(" ATA via IOCTL_SCSI_PASS_THROUGH suceeded, bytes returned: %lu\n", num_out
);
675 print_ide_regs_io(regs
, NULL
);
681 /////////////////////////////////////////////////////////////////////////////
683 static HANDLE h_ata_ioctl
= 0;
686 // Print SMARTVSD error message, return errno
688 static int smartvsd_error()
692 if (!(5 <= (len
= GetSystemDirectoryA(path
, MAX_PATH
)) && len
< MAX_PATH
/2))
694 // SMARTVSD.VXD present?
695 strcpy(path
+len
, "\\IOSUBSYS\\SMARTVSD.VXD");
696 if (!access(path
, 0)) {
697 // Yes, standard IDE driver used?
699 if ( (h
= CreateFileA("\\\\.\\ESDI_506",
700 GENERIC_READ
|GENERIC_WRITE
, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
701 NULL
, OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
702 && GetLastError() == ERROR_FILE_NOT_FOUND
) {
703 pout("Standard IDE driver ESDI_506.PDR not used, or no IDE/ATA drives present.\n");
707 if (h
!= INVALID_HANDLE_VALUE
) // should not happen
709 pout("SMART driver SMARTVSD.VXD is installed, but not loaded.\n");
714 // Some Windows versions install SMARTVSD.VXD in SYSTEM directory
715 // http://support.microsoft.com/default.aspx?scid=kb;en-us;265854
716 strcpy(path
+len
, "\\SMARTVSD.VXD");
717 if (!access(path
, 0)) {
719 pout("SMART driver is not properly installed,\n"
720 " move SMARTVSD.VXD from \"%s\" to \"%s\\IOSUBSYS\"\n"
721 " and reboot Windows.\n", path
, path
);
725 pout("SMARTVSD.VXD is missing in folder \"%s\\IOSUBSYS\".\n", path
);
732 static int ata_open(int drive
)
736 GETVERSIONOUTPARAMS vers
;
739 assert(SMART_GET_VERSION
== 0x074080);
740 assert(sizeof(GETVERSIONOUTPARAMS
) == 24);
742 // TODO: This version does not allow to open more than 1 ATA devices
748 win9x
= ((GetVersion() & 0x80000000) != 0);
750 if (!(0 <= drive
&& drive
<= (win9x
? 3 : 9))) {
754 // path depends on Windows Version
756 strcpy(devpath
, "\\\\.\\SMARTVSD");
758 snprintf(devpath
, sizeof(devpath
)-1, "\\\\.\\PhysicalDrive%d", drive
);
761 if ((h_ata_ioctl
= CreateFileA(devpath
,
762 GENERIC_READ
|GENERIC_WRITE
, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
763 NULL
, OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
) {
764 long err
= GetLastError();
765 pout("Cannot open device %s, Error=%ld\n", devpath
, err
);
766 if (err
== ERROR_FILE_NOT_FOUND
)
767 errno
= (win9x
? smartvsd_error() : ENOENT
);
768 else if (err
== ERROR_ACCESS_DENIED
) {
770 pout("Administrator rights are necessary to access physical drives.\n");
780 memset(&vers
, 0, sizeof(vers
));
781 if (!DeviceIoControl(h_ata_ioctl
, SMART_GET_VERSION
,
782 NULL
, 0, &vers
, sizeof(vers
), &num_out
, NULL
)) {
783 pout("%s: SMART_GET_VERSION failed, Error=%ld\n", devpath
, GetLastError());
785 pout("If this is a SCSI disk, try \"scsi<adapter><id>\".\n");
786 if (!is_permissive()) {
787 CloseHandle(h_ata_ioctl
); h_ata_ioctl
= 0;
793 if (con
->reportataioctl
> 1)
794 pout("%s: SMART_GET_VERSION (%ld bytes):\n"
795 " Vers = %d.%d, Caps = 0x%lx, DeviceMap = 0x%02x\n",
796 devpath
, num_out
, vers
.bVersion
, vers
.bRevision
,
797 vers
.fCapabilities
, vers
.bIDEDeviceMap
);
799 // TODO: Check vers.fCapabilities here?
802 // NT4/2K/XP: Drive exists, Drive number not necessary for ioctl
805 // Win9x/ME: Check device presence & type
806 if (((vers
.bIDEDeviceMap
>> drive
) & 0x11) != 0x01) {
807 unsigned char atapi
= (vers
.bIDEDeviceMap
>> drive
) & 0x10;
809 ? "Drive %d is an ATAPI device (IDEDeviceMap=0x%02x).\n"
810 : "Drive %d does not exist (IDEDeviceMap=0x%02x).\n"),
811 drive
, vers
.bIDEDeviceMap
);
812 // Win9x Drive existence check may not work as expected
813 // The atapi.sys driver incorrectly fills in the bIDEDeviceMap with 0x01
814 // http://support.microsoft.com/support/kb/articles/Q196/1/20.ASP
815 if (!is_permissive()) {
816 CloseHandle(h_ata_ioctl
); h_ata_ioctl
= 0;
817 errno
= (atapi
? ENOSYS
: ENOENT
);
821 // Use drive number as fd for ioctl
826 static void ata_close(int fd
)
829 CloseHandle(h_ata_ioctl
);
834 // Scan for ATA drives, fill bitmask of drives present, return #drives
836 static int ata_scan(unsigned long * drives
)
838 int win9x
= ((GetVersion() & 0x80000000) != 0);
841 for (i
= 0; i
<= 9; i
++) {
843 GETVERSIONOUTPARAMS vers
;
847 strcpy(devpath
, "\\\\.\\SMARTVSD");
849 snprintf(devpath
, sizeof(devpath
)-1, "\\\\.\\PhysicalDrive%d", i
);
852 if ((h
= CreateFileA(devpath
,
853 GENERIC_READ
|GENERIC_WRITE
, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
854 NULL
, OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
) {
855 if (con
->reportataioctl
> 1)
856 pout(" %s: Open failed, Error=%ld\n", devpath
, GetLastError());
858 break; // SMARTVSD.VXD missing or no ATA devices
859 continue; // Disk not found or access denied (break;?)
863 memset(&vers
, 0, sizeof(vers
));
864 if (!DeviceIoControl(h
, SMART_GET_VERSION
,
865 NULL
, 0, &vers
, sizeof(vers
), &num_out
, NULL
)) {
866 if (con
->reportataioctl
)
867 pout(" %s: SMART_GET_VERSION failed, Error=%ld\n", devpath
, GetLastError());
870 break; // Should not happen
871 continue; // Non ATA disk or no SMART ioctl support (possibly SCSI disk)
875 if (con
->reportataioctl
)
876 pout(" %s: SMART_GET_VERSION (%ld bytes):\n"
877 " Vers = %d.%d, Caps = 0x%lx, DeviceMap = 0x%02x\n",
878 devpath
, num_out
, vers
.bVersion
, vers
.bRevision
,
879 vers
.fCapabilities
, vers
.bIDEDeviceMap
);
882 // Check ATA device presence, remove ATAPI devices
883 drives
[0] = (vers
.bIDEDeviceMap
& 0xf) & ~((vers
.bIDEDeviceMap
>> 4) & 0xf);
884 cnt
= (drives
[0]&1) + ((drives
[0]>>1)&1) + ((drives
[0]>>2)&1) + ((drives
[0]>>3)&1);
888 // ATA drive exists and driver supports SMART ioctl
889 drives
[0] |= (1L << i
);
897 /////////////////////////////////////////////////////////////////////////////
899 // Interface to ATA devices. See os_linux.c
900 int ata_command_interface(int fd
, smart_command_set command
, int select
, char * data
)
903 int copydata
, try_ioctl
;
905 if (!(0 <= fd
&& fd
<= 3)) {
910 // CMD,CYL default to SMART, changed by P?IDENTIFY and CHECK_POWER_MODE
911 memset(®s
, 0, sizeof(regs
));
912 regs
.bCommandReg
= ATA_SMART_CMD
;
913 regs
.bCylHighReg
= SMART_CYL_HI
; regs
.bCylLowReg
= SMART_CYL_LOW
;
915 try_ioctl
= 0x01; // 0x01=SMART_*, 0x02=IDE_PASS_THROUGH [, 0x04=ATA_PASS_THROUGH]
919 // TODO. Not supported by SMART IOCTL (no data out ioctl available),
920 // also not supported by IOCTL_IDE_PASS_THROUGH (data out not working)
923 case CHECK_POWER_MODE
:
924 regs
.bCommandReg
= ATA_CHECK_POWER_MODE
;
925 regs
.bCylLowReg
= regs
.bCylHighReg
= 0;
926 try_ioctl
= 0x02; // IOCTL_IDE_PASS_THROUGH
927 // Note: returns SectorCountReg in data[0]
930 regs
.bFeaturesReg
= ATA_SMART_READ_VALUES
;
931 regs
.bSectorNumberReg
= regs
.bSectorCountReg
= 1;
934 case READ_THRESHOLDS
:
935 regs
.bFeaturesReg
= ATA_SMART_READ_THRESHOLDS
;
936 regs
.bSectorNumberReg
= regs
.bSectorCountReg
= 1;
940 regs
.bFeaturesReg
= ATA_SMART_READ_LOG_SECTOR
;
941 regs
.bSectorNumberReg
= select
;
942 regs
.bSectorCountReg
= 1;
943 // Read log only supported on Win9x, retry with pass through command
944 try_ioctl
= 0x03; // SMART_RCV_DRIVE_DATA, then IOCTL_IDE_PASS_THROUGH
948 // Note: WinNT4/2000/XP return identify data cached during boot
949 // (true for SMART_RCV_DRIVE_DATA and IOCTL_IDE_PASS_THROUGH)
950 regs
.bCommandReg
= ATA_IDENTIFY_DEVICE
;
951 regs
.bCylLowReg
= regs
.bCylHighReg
= 0;
952 regs
.bSectorCountReg
= 1;
956 regs
.bCommandReg
= ATA_IDENTIFY_PACKET_DEVICE
;
957 regs
.bCylLowReg
= regs
.bCylHighReg
= 0;
958 regs
.bSectorCountReg
= 1;
962 regs
.bFeaturesReg
= ATA_SMART_ENABLE
;
963 regs
.bSectorNumberReg
= 1;
966 regs
.bFeaturesReg
= ATA_SMART_DISABLE
;
967 regs
.bSectorNumberReg
= 1;
971 regs
.bFeaturesReg
= ATA_SMART_STATUS
;
974 regs
.bFeaturesReg
= ATA_SMART_AUTO_OFFLINE
;
975 regs
.bSectorCountReg
= select
; // YET NOTE - THIS IS A NON-DATA COMMAND!!
978 regs
.bFeaturesReg
= ATA_SMART_AUTOSAVE
;
979 regs
.bSectorCountReg
= select
; // YET NOTE - THIS IS A NON-DATA COMMAND!!
981 case IMMEDIATE_OFFLINE
:
982 regs
.bFeaturesReg
= ATA_SMART_IMMEDIATE_OFFLINE
;
983 regs
.bSectorNumberReg
= select
;
984 if (select
== ABORT_SELF_TEST
) // Abort only supported on Win9x, try
985 try_ioctl
= 0x03; // SMART_SEND_DRIVE_COMMAND, then IOCTL_IDE_PASS_THROUGH
988 pout("Unrecognized command %d in win32_ata_command_interface()\n"
989 "Please contact " PACKAGE_BUGREPORT
"\n", command
);
994 if (try_ioctl
& 0x01) {
995 if (smart_ioctl(h_ata_ioctl
, fd
, ®s
, data
, (copydata
?512:0))) {
996 if (!(try_ioctl
& 0x02) || errno
!= ENOSYS
)
998 // CAUTION: smart_ioctl() MUST NOT change "regs" Parameter in this case
1004 if (try_ioctl
& 0x02) {
1006 if ((GetVersion() & 0x8000ffff) == 0x00000004) {
1007 // Special case WinNT4
1008 if (command
== CHECK_POWER_MODE
) { // SCSI_PASS_THROUGH does not return regs!
1012 if (ata_via_scsi_pass_through_ioctl(h_ata_ioctl
, ®s
, data
, (copydata
?512:0)))
1016 if (ide_pass_through_ioctl(h_ata_ioctl
, ®s
, data
, (copydata
?512:0)))
1024 case CHECK_POWER_MODE
:
1025 // Return power mode from SectorCountReg in data[0]
1026 data
[0] = regs
.bSectorCountReg
;
1030 // Cyl low and Cyl high unchanged means "Good SMART status"
1031 if (regs
.bCylHighReg
== SMART_CYL_HI
&& regs
.bCylLowReg
== SMART_CYL_LOW
)
1034 // These values mean "Bad SMART status"
1035 if (regs
.bCylHighReg
== 0x2c && regs
.bCylLowReg
== 0xf4)
1038 // We haven't gotten output that makes sense; print out some debugging info
1039 syserror("Error SMART Status command failed");
1040 pout("Please get assistance from %s\n", PACKAGE_HOMEPAGE
);
1041 print_ide_regs(®s
, 1);
1052 #ifndef HAVE_ATA_IDENTIFY_IS_CACHED
1053 #error define of HAVE_ATA_IDENTIFY_IS_CACHED missing in config.h
1056 // Return true if OS caches the ATA identify sector
1057 int ata_identify_is_cached(int fd
)
1060 // WinNT4/2000/XP => true, Win9x/ME => false
1061 return ((GetVersion() & 0x80000000) == 0);
1065 // Print not implemeted warning once
1066 static void pr_not_impl(const char * what
, int * warned
)
1071 "#######################################################################\n"
1073 "NOT IMPLEMENTED under Win32.\n"
1074 "Please contact " PACKAGE_BUGREPORT
" if\n"
1075 "you want to help in porting smartmontools to Win32.\n"
1076 "#######################################################################\n"
1082 // Interface to ATA devices behind 3ware escalade RAID controller cards. See os_linux.c
1083 int escalade_command_interface(int fd
, int disknum
, int escalade_type
, smart_command_set command
, int select
, char *data
)
1085 static int warned
= 0;
1086 ARGUSED(fd
); ARGUSED(disknum
); ARGUSED(escalade_type
); ARGUSED(command
); ARGUSED(select
); ARGUSED(data
);
1087 pr_not_impl("3ware Escalade Controller command routine escalade_command_interface()", &warned
);
1092 // Interface to ATA devices behind Marvell chip-set based controllers. See os_linux.c
1093 int marvell_command_interface(int fd
, smart_command_set command
, int select
, char * data
)
1095 static int warned
= 0;
1096 ARGUSED(fd
); ARGUSED(command
); ARGUSED(select
); ARGUSED(data
);
1097 pr_not_impl("Marvell chip-set command routine marvell_command_interface()", &warned
);
1103 /////////////////////////////////////////////////////////////////////////////
1105 /////////////////////////////////////////////////////////////////////////////
1109 #define ASPI_SENSE_SIZE 18
1111 // ASPI SCSI Request block header
1114 unsigned char cmd
; // 00: Command code
1115 unsigned char status
; // 01: ASPI status
1116 unsigned char adapter
; // 02: Host adapter number
1117 unsigned char flags
; // 03: Request flags
1118 unsigned char reserved
[4]; // 04: 0
1121 // SRB for host adapter inquiry
1124 ASPI_SRB_HEAD h
; // 00: Header
1125 unsigned char adapters
; // 08: Number of adapters
1126 unsigned char target_id
; // 09: Target ID ?
1127 char manager_id
[16]; // 10: SCSI manager ID
1128 char adapter_id
[16]; // 26: Host adapter ID
1129 unsigned char parameters
[16]; // 42: Host adapter unique parmameters
1132 // SRB for get device type
1135 ASPI_SRB_HEAD h
; // 00: Header
1136 unsigned char target_id
; // 08: Target ID
1137 unsigned char lun
; // 09: LUN
1138 unsigned char devtype
; // 10: Device type
1139 unsigned char reserved
; // 11: Reserved
1145 ASPI_SRB_HEAD h
; // 00: Header
1146 unsigned char target_id
; // 08: Target ID
1147 unsigned char lun
; // 09: LUN
1148 unsigned char reserved
[2]; // 10: Reserved
1149 unsigned long data_size
; // 12: Data alloc. lenght
1150 void * data_addr
; // 16: Data buffer pointer
1151 unsigned char sense_size
; // 20: Sense alloc. length
1152 unsigned char cdb_size
; // 21: CDB length
1153 unsigned char host_status
; // 22: Host status
1154 unsigned char target_status
; // 23: Target status
1155 void * event_handle
; // 24: Event handle
1156 unsigned char workspace
[20]; // 28: ASPI workspace
1157 unsigned char cdb
[16+ASPI_SENSE_SIZE
];
1160 // Macro to retrieve start of sense information
1161 #define ASPI_SRB_SENSE(srb,cdbsz) ((srb)->cdb + 16)
1166 ASPI_SRB_HEAD h
; // Common header
1167 ASPI_SRB_INQUIRY q
; // Inquiry
1168 ASPI_SRB_DEVTYPE t
; // Device type
1169 ASPI_SRB_IO i
; // I/O
1175 #define ASPI_CMD_ADAPTER_INQUIRE 0x00
1176 #define ASPI_CMD_GET_DEVICE_TYPE 0x01
1177 #define ASPI_CMD_EXECUTE_IO 0x02
1178 #define ASPI_CMD_ABORT_IO 0x03
1181 #define ASPI_REQFLAG_DIR_TO_HOST 0x08
1182 #define ASPI_REQFLAG_DIR_TO_TARGET 0x10
1183 #define ASPI_REQFLAG_DIR_NO_XFER 0x18
1184 #define ASPI_REQFLAG_EVENT_NOTIFY 0x40
1187 #define ASPI_STATUS_IN_PROGRESS 0x00
1188 #define ASPI_STATUS_NO_ERROR 0x01
1189 #define ASPI_STATUS_ABORTED 0x02
1190 #define ASPI_STATUS_ABORT_ERR 0x03
1191 #define ASPI_STATUS_ERROR 0x04
1192 #define ASPI_STATUS_INVALID_COMMAND 0x80
1193 #define ASPI_STATUS_INVALID_ADAPTER 0x81
1194 #define ASPI_STATUS_INVALID_TARGET 0x82
1195 #define ASPI_STATUS_NO_ADAPTERS 0xE8
1197 // Adapter (host) status
1198 #define ASPI_HSTATUS_NO_ERROR 0x00
1199 #define ASPI_HSTATUS_SELECTION_TIMEOUT 0x11
1200 #define ASPI_HSTATUS_DATA_OVERRUN 0x12
1201 #define ASPI_HSTATUS_BUS_FREE 0x13
1202 #define ASPI_HSTATUS_BUS_PHASE_ERROR 0x14
1203 #define ASPI_HSTATUS_BAD_SGLIST 0x1A
1206 #define ASPI_TSTATUS_NO_ERROR 0x00
1207 #define ASPI_TSTATUS_CHECK_CONDITION 0x02
1208 #define ASPI_TSTATUS_BUSY 0x08
1209 #define ASPI_TSTATUS_RESERV_CONFLICT 0x18
1212 static HINSTANCE h_aspi_dll
; // DLL handle
1213 static UINT (* aspi_entry
)(ASPI_SRB
* srb
); // ASPI entrypoint
1214 static unsigned num_aspi_adapters
;
1217 // h_aspi_dll+aspi_entry is not inherited by Cygwin's fork()
1218 static DWORD aspi_dll_pid
; // PID of DLL owner to detect fork()
1219 #define aspi_entry_valid() (aspi_entry && (aspi_dll_pid == GetCurrentProcessId()))
1221 #define aspi_entry_valid() (!!aspi_entry)
1225 static int aspi_call(ASPI_SRB
* srb
)
1230 while (((volatile ASPI_SRB
*)srb
)->h
.status
== ASPI_STATUS_IN_PROGRESS
) {
1231 if (++i
> 100/*10sek*/) {
1232 pout("ASPI Adapter %u: Timed out\n", srb
->h
.adapter
);
1234 h_aspi_dll
= INVALID_HANDLE_VALUE
;
1238 if (con
->reportscsiioctl
> 1)
1239 pout("ASPI Adapter %u: Waiting (%d) ...\n", srb
->h
.adapter
, i
);
1246 // Get ASPI entrypoint from wnaspi32.dll
1248 static FARPROC
aspi_get_address(const char * name
, int verbose
)
1251 assert(h_aspi_dll
&& h_aspi_dll
!= INVALID_HANDLE_VALUE
);
1253 if (!(addr
= GetProcAddress(h_aspi_dll
, name
))) {
1255 pout("Missing %s() in WNASPI32.DLL\n", name
);
1257 FreeLibrary(h_aspi_dll
);
1258 h_aspi_dll
= INVALID_HANDLE_VALUE
;
1266 static int aspi_open_dll(int verbose
)
1268 UINT (*aspi_info
)(void);
1271 assert(!aspi_entry_valid());
1273 // Check structure layout
1274 assert(sizeof(ASPI_SRB_HEAD
) == 8);
1275 assert(sizeof(ASPI_SRB_INQUIRY
) == 58);
1276 assert(sizeof(ASPI_SRB_DEVTYPE
) == 12);
1277 assert(sizeof(ASPI_SRB_IO
) == 64+ASPI_SENSE_SIZE
);
1278 assert(offsetof(ASPI_SRB
,h
.cmd
) == 0);
1279 assert(offsetof(ASPI_SRB
,h
.flags
) == 3);
1280 assert(offsetof(ASPI_SRB_IO
,lun
) == 9);
1281 assert(offsetof(ASPI_SRB_IO
,data_addr
) == 16);
1282 assert(offsetof(ASPI_SRB_IO
,workspace
) == 28);
1283 assert(offsetof(ASPI_SRB_IO
,cdb
) == 48);
1285 if (h_aspi_dll
== INVALID_HANDLE_VALUE
) {
1292 if (!(h_aspi_dll
= LoadLibraryA("WNASPI32.DLL"))) {
1294 pout("Cannot load WNASPI32.DLL, Error=%ld\n", GetLastError());
1295 h_aspi_dll
= INVALID_HANDLE_VALUE
;
1299 if (con
->reportscsiioctl
> 1) {
1300 // Print full path of WNASPI32.DLL
1301 char path
[MAX_PATH
];
1302 if (!GetModuleFileName(h_aspi_dll
, path
, sizeof(path
)))
1303 strcpy(path
, "*unknown*");
1304 pout("Using ASPI interface \"%s\"\n", path
);
1307 // Get ASPI entrypoints
1308 if (!(aspi_info
= (UINT (*)(void))aspi_get_address("GetASPI32SupportInfo", verbose
)))
1310 if (!(aspi_entry
= (UINT (*)(ASPI_SRB
*))aspi_get_address("SendASPI32Command", verbose
)))
1313 // Init ASPI manager and get number of adapters
1314 info
= (aspi_info
)();
1315 if (con
->reportscsiioctl
> 1)
1316 pout("GetASPI32SupportInfo() returns 0x%04x\n", info
);
1317 rc
= (info
>> 8) & 0xff;
1318 if (rc
== ASPI_STATUS_NO_ADAPTERS
) {
1319 num_aspi_adapters
= 0;
1321 else if (rc
== ASPI_STATUS_NO_ERROR
) {
1322 num_aspi_adapters
= info
& 0xff;
1326 pout("Got strange 0x%04x from GetASPI32SupportInfo()\n", info
);
1328 FreeLibrary(h_aspi_dll
);
1329 h_aspi_dll
= INVALID_HANDLE_VALUE
;
1334 if (con
->reportscsiioctl
)
1335 pout("%u ASPI Adapter%s detected\n",num_aspi_adapters
, (num_aspi_adapters
!=1?"s":""));
1338 // save PID to detect fork() in aspi_entry_valid()
1339 aspi_dll_pid
= GetCurrentProcessId();
1341 assert(aspi_entry_valid());
1346 static int aspi_io_call(ASPI_SRB
* srb
, unsigned timeout
)
1350 if (!(event
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
))) {
1351 pout("CreateEvent(): Error=%ld\n", GetLastError()); return -EIO
;
1353 srb
->i
.event_handle
= event
;
1354 srb
->h
.flags
|= ASPI_REQFLAG_EVENT_NOTIFY
;
1355 // Start ASPI request
1357 if (((volatile ASPI_SRB
*)srb
)->h
.status
== ASPI_STATUS_IN_PROGRESS
) {
1359 DWORD rc
= WaitForSingleObject(event
, timeout
*1000L);
1360 if (rc
!= WAIT_OBJECT_0
) {
1361 if (rc
== WAIT_TIMEOUT
) {
1362 pout("ASPI Adapter %u, ID %u: Timed out after %u seconds\n",
1363 srb
->h
.adapter
, srb
->i
.target_id
, timeout
);
1366 pout("WaitForSingleObject(%lx) = 0x%lx,%ld, Error=%ld\n",
1367 (unsigned long)event
, rc
, rc
, GetLastError());
1369 // TODO: ASPI_ABORT_IO command
1371 h_aspi_dll
= INVALID_HANDLE_VALUE
;
1380 static int aspi_open(unsigned adapter
, unsigned id
)
1383 if (!(adapter
<= 9 && id
< 16)) {
1388 if (!aspi_entry_valid()) {
1389 if (aspi_open_dll(1/*verbose*/))
1394 if (adapter
>= num_aspi_adapters
) {
1395 pout("ASPI Adapter %u does not exist (%u Adapter%s detected).\n",
1396 adapter
, num_aspi_adapters
, (num_aspi_adapters
!=1?"s":""));
1397 if (!is_permissive()) {
1404 memset(&srb
, 0, sizeof(srb
));
1405 srb
.h
.cmd
= ASPI_CMD_GET_DEVICE_TYPE
;
1406 srb
.h
.adapter
= adapter
; srb
.i
.target_id
= id
;
1407 if (aspi_call(&srb
)) {
1411 if (srb
.h
.status
!= ASPI_STATUS_NO_ERROR
) {
1412 pout("ASPI Adapter %u, ID %u: No such device (Status=0x%02x)\n", adapter
, id
, srb
.h
.status
);
1413 if (!is_permissive()) {
1414 errno
= (srb
.h
.status
== ASPI_STATUS_INVALID_TARGET
? ENOENT
: EIO
);
1418 else if (con
->reportscsiioctl
)
1419 pout("ASPI Adapter %u, ID %u: Device Type=0x%02x\n", adapter
, id
, srb
.t
.devtype
);
1421 return (0x0100 | ((adapter
& 0xf)<<4) | (id
& 0xf));
1425 static void aspi_close(int fd
)
1427 // No FreeLibrary(h_aspi_dll) to prevent problems with ASPI threads
1432 // Scan for SCSI drives, fill bitmask [adapter:0-9][id:0-7] of drives present,
1435 static int aspi_scan(unsigned long * drives
)
1440 if (!aspi_entry_valid()) {
1441 if (aspi_open_dll(con
->reportscsiioctl
/*default is quiet*/))
1445 for (ad
= 0; ad
< num_aspi_adapters
; ad
++) {
1446 ASPI_SRB srb
; unsigned id
;
1449 if (con
->reportscsiioctl
)
1450 pout(" ASPI Adapter %u: Ignored\n", ad
);
1455 memset(&srb
, 0, sizeof(srb
));
1456 srb
.h
.cmd
= ASPI_CMD_ADAPTER_INQUIRE
;
1458 if (aspi_call(&srb
))
1461 if (srb
.h
.status
!= ASPI_STATUS_NO_ERROR
) {
1462 if (con
->reportscsiioctl
)
1463 pout(" ASPI Adapter %u: Status=0x%02x\n", ad
, srb
.h
.status
);
1467 if (con
->reportscsiioctl
) {
1469 for (i
= 1; i
< 16 && srb
.q
.adapter_id
[i
]; i
++)
1470 if (!(' ' <= srb
.q
.adapter_id
[i
] && srb
.q
.adapter_id
[i
] <= '~'))
1471 srb
.q
.adapter_id
[i
] = '?';
1472 pout(" ASPI Adapter %u (\"%.16s\"):\n", ad
, srb
.q
.adapter_id
);
1475 for (id
= 0; id
<= 7; id
++) {
1477 memset(&srb
, 0, sizeof(srb
));
1478 srb
.h
.cmd
= ASPI_CMD_GET_DEVICE_TYPE
;
1479 srb
.h
.adapter
= ad
; srb
.i
.target_id
= id
;
1480 if (aspi_call(&srb
))
1482 if (srb
.h
.status
!= ASPI_STATUS_NO_ERROR
) {
1483 if (con
->reportscsiioctl
> 1)
1484 pout(" ID %u: No such device (Status=0x%02x)\n", id
, srb
.h
.status
);
1487 if (con
->reportscsiioctl
)
1488 pout(" ID %u: Device Type=0x%02x\n", id
, srb
.t
.devtype
);
1489 if (srb
.t
.devtype
== 0x00/*HDD*/) {
1490 drives
[ad
>> 2] |= (1L << (((ad
& 0x3) << 3) + id
));
1499 /////////////////////////////////////////////////////////////////////////////
1501 // Interface to SCSI devices. See os_linux.c
1502 int do_scsi_cmnd_io(int fd
, struct scsi_cmnd_io
* iop
, int report
)
1506 if (!aspi_entry_valid())
1508 if (!((fd
& ~0xff) == 0x100))
1511 if (!(iop
->cmnd_len
== 6 || iop
->cmnd_len
== 10 || iop
->cmnd_len
== 12)) {
1512 pout("do_scsi_cmnd_io: bad CDB length\n");
1519 const unsigned char * ucp
= iop
->cmnd
;
1522 const int sz
= (int)sizeof(buff
);
1524 np
= scsi_get_opcode_name(ucp
[0]);
1525 j
= snprintf(buff
, sz
, " [%s: ", np
? np
: "<unknown opcode>");
1526 for (k
= 0; k
< (int)iop
->cmnd_len
; ++k
)
1527 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "%02x ", ucp
[k
]);
1529 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
1530 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
1532 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n Outgoing "
1533 "data, len=%d%s:\n", (int)iop
->dxfer_len
,
1534 (trunc
? " [only first 256 bytes shown]" : ""));
1535 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
1538 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n");
1542 memset(&srb
, 0, sizeof(srb
));
1543 srb
.h
.cmd
= ASPI_CMD_EXECUTE_IO
;
1544 srb
.h
.adapter
= ((fd
>> 4) & 0xf);
1545 srb
.i
.target_id
= (fd
& 0xf);
1547 srb
.i
.sense_size
= ASPI_SENSE_SIZE
;
1548 srb
.i
.cdb_size
= iop
->cmnd_len
;
1549 memcpy(srb
.i
.cdb
, iop
->cmnd
, iop
->cmnd_len
);
1551 switch (iop
->dxfer_dir
) {
1553 srb
.h
.flags
= ASPI_REQFLAG_DIR_NO_XFER
;
1555 case DXFER_FROM_DEVICE
:
1556 srb
.h
.flags
= ASPI_REQFLAG_DIR_TO_HOST
;
1557 srb
.i
.data_size
= iop
->dxfer_len
;
1558 srb
.i
.data_addr
= iop
->dxferp
;
1560 case DXFER_TO_DEVICE
:
1561 srb
.h
.flags
= ASPI_REQFLAG_DIR_TO_TARGET
;
1562 srb
.i
.data_size
= iop
->dxfer_len
;
1563 srb
.i
.data_addr
= iop
->dxferp
;
1566 pout("do_scsi_cmnd_io: bad dxfer_dir\n");
1570 iop
->resp_sense_len
= 0;
1571 iop
->scsi_status
= 0;
1574 if (aspi_io_call(&srb
, (iop
->timeout
? iop
->timeout
: 60))) {
1579 if (srb
.h
.status
!= ASPI_STATUS_NO_ERROR
) {
1580 if ( srb
.h
.status
== ASPI_STATUS_ERROR
1581 && srb
.i
.host_status
== ASPI_HSTATUS_NO_ERROR
1582 && srb
.i
.target_status
== ASPI_TSTATUS_CHECK_CONDITION
) {
1584 const unsigned char * sense
= ASPI_SRB_SENSE(&srb
.i
, iop
->cmnd_len
);
1585 int len
= (ASPI_SENSE_SIZE
< iop
->max_sense_len
? ASPI_SENSE_SIZE
: iop
->max_sense_len
);
1586 iop
->scsi_status
= SCSI_STATUS_CHECK_CONDITION
;
1587 if (len
> 0 && iop
->sensep
) {
1588 memcpy(iop
->sensep
, sense
, len
);
1589 iop
->resp_sense_len
= len
;
1591 pout(" >>> Sense buffer, len=%d:\n", (int)len
);
1592 dStrHex(iop
->sensep
, len
, 1);
1596 pout(" sense_key=%x asc=%x ascq=%x\n",
1597 sense
[2] & 0xf, sense
[12], sense
[13]);
1603 pout(" ASPI call failed, (0x%02x,0x%02x,0x%02x)\n", srb
.h
.status
, srb
.i
.host_status
, srb
.i
.target_status
);
1611 if (iop
->dxfer_dir
== DXFER_FROM_DEVICE
&& report
> 1) {
1612 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
1613 pout(" Incoming data, len=%d%s:\n", (int)iop
->dxfer_len
,
1614 (trunc
? " [only first 256 bytes shown]" : ""));
1615 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);