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 // 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]
48 // Needed by '-V' option (CVS versioning) of smartd/smartctl
49 const char *os_XXXX_c_cvsid
="$Id: os_win32.cpp,v 1.50 2006/11/15 22:48:04 chrfranke Exp $"
50 ATACMDS_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID
;
53 #ifndef HAVE_GET_OS_VERSION_STR
54 #error define of HAVE_GET_OS_VERSION_STR missing in config.h
57 // Return build host and OS version as static string
58 const char * get_os_version_str()
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);
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
));
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
))
81 if (vi
.dwPlatformId
> 0xff || vi
.dwMajorVersion
> 0xff || vi
.dwMinorVersion
> 0xff)
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"
97 case VER_PLATFORM_WIN32_NT
<<16|0x0500| 2:
98 w
= (!GetSystemMetrics(89/*SM_SERVERR2*/) ? "2003"
100 case VER_PLATFORM_WIN32_NT
<<16|0x0600| 0: w
= "vista"; break;
101 default: w
= 0; break;
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
);
113 snprintf(vptr
, vlen
, "-%s", w
);
118 #define ATARAID_FDOFFSET 0x0200
120 static int ata_open(int drive
, const char * options
, int port
);
121 static void ata_close(int fd
);
122 static int ata_scan(unsigned long * drives
, int * rdriveno
, unsigned long * rdrives
);
123 static const char * ata_get_def_options(void);
125 #define TW_CLI_FDOFFSET 0x0300
127 static int tw_cli_open(const char * name
);
128 static void tw_cli_close();
130 #define ASPI_FDOFFSET 0x0100
132 static int aspi_open(unsigned adapter
, unsigned id
);
133 static void aspi_close(int fd
);
134 static int aspi_scan(unsigned long * drives
);
136 #define SPT_FDOFFSET 0x0400
138 static int spt_open(int pd_num
, int tape_num
, int sub_addr
);
139 static void spt_close(int fd
);
142 static int is_permissive()
144 if (!con
->permissive
) {
145 pout("To continue, add one or more '-T permissive' options.\n");
152 static const char * skipdev(const char * s
)
154 return (!strncmp(s
, "/dev/", 5) ? s
+ 5 : s
);
158 // tries to guess device type given the name (a path). See utility.h
159 // for return values.
160 int guess_device_type (const char * dev_name
)
162 dev_name
= skipdev(dev_name
);
163 if (!strncmp(dev_name
, "hd", 2))
164 return CONTROLLER_ATA
;
165 if (!strncmp(dev_name
, "tw_cli", 6))
166 return CONTROLLER_ATA
;
167 if (!strncmp(dev_name
, "scsi", 4))
168 return CONTROLLER_SCSI
;
169 if (!strncmp(dev_name
, "sd", 2))
170 return CONTROLLER_SCSI
;
171 if (!strncmp(dev_name
, "pd", 2))
172 return CONTROLLER_SCSI
;
173 if (!strncmp(dev_name
, "tape", 4))
174 return CONTROLLER_SCSI
;
175 return CONTROLLER_UNKNOWN
;
179 // makes a list of ATA or SCSI devices for the DEVICESCAN directive of
180 // smartd. Returns number N of devices, or -1 if out of
181 // memory. Allocates N+1 arrays: one of N pointers (devlist), the
182 // others each contain null-terminated character strings.
183 int make_device_names (char*** devlist
, const char* type
)
185 unsigned long drives
[3];
187 unsigned long rdrives
[2];
188 int i
, j
, n
, nmax
, sz
;
191 drives
[0] = drives
[1] = drives
[2] = 0;
192 rdriveno
[0] = rdriveno
[1] = -1;
193 rdrives
[0] = rdrives
[1] = 0;
195 if (!strcmp(type
, "ATA")) {
196 // bit i set => drive i present
197 n
= ata_scan(drives
, rdriveno
, rdrives
);
201 else if (!strcmp(type
, "SCSI")) {
202 // bit i set => drive with ID (i & 0x7) on adapter (i >> 3) present
203 n
= aspi_scan(drives
);
204 path
= "/dev/scsi00";
214 sz
= n
* sizeof(char **);
215 *devlist
= (char **)malloc(sz
); bytes
+= sz
;
218 for (i
= j
= 0; i
< n
; ) {
219 while (j
< nmax
&& !(drives
[j
>> 5] & (1L << (j
& 0x1f))))
223 if (j
== rdriveno
[0] || j
== rdriveno
[1]) {
224 // Add physical drives behind this logical drive
225 int ci
= (j
== rdriveno
[0] ? 0 : 1);
226 for (int pi
= 0; pi
< 32 && i
< n
; pi
++) {
227 if (!(rdrives
[ci
] & (1L << pi
)))
230 sprintf(rpath
, "/dev/hd%c,%u", 'a'+j
, pi
);
231 sz
= strlen(rpath
)+1;
232 char * s
= (char *)malloc(sz
); bytes
+= sz
;
239 char * s
= (char *)malloc(sz
); bytes
+= sz
;
244 s
[sz
-2] += j
; // /dev/hd[a-j]
247 assert((j
>> 3) <= 9);
248 s
[sz
-3] += (j
>> 3); // /dev/scsi[0-9].....
249 s
[sz
-2] += (j
& 0x7); // .....[0-7]
260 // Like open(). Return positive integer handle, only used by
261 // functions below. type="ATA" or "SCSI". If you need to store extra
262 // information about your devices, create a private internal array
263 // within this file (see os_freebsd.cpp for an example).
264 int deviceopen(const char * pathname
, char *type
)
266 pathname
= skipdev(pathname
);
267 int len
= strlen(pathname
);
269 if (!strcmp(type
, "ATA")) {
270 // hd[a-j](:[saicp]+)? => ATA 0-9 with options
271 char drive
[1+1] = "", options
[5+1] = ""; int n1
= -1, n2
= -1;
272 if ( sscanf(pathname
, "hd%1[a-j]%n:%5[saicp]%n", drive
, &n1
, options
, &n2
) >= 1
273 && ((n1
== len
&& !options
[0]) || n2
== len
) ) {
274 return ata_open(drive
[0] - 'a', options
, -1);
276 // hd[a-j],N(:[saicp]+)? => Physical drive 0-9, RAID port N, with options
277 drive
[0] = 0; options
[0] = 0; n1
= -1; n2
= -1;
279 if ( sscanf(pathname
, "hd%1[a-j],%u%n:%5[saicp]%n", drive
, &port
, &n1
, options
, &n2
) >= 2
280 && port
< 32 && ((n1
== len
&& !options
[0]) || n2
== len
) ) {
281 return ata_open(drive
[0] - 'a', options
, port
);
283 // tw_cli/... => Parse tw_cli output
284 if (!strncmp(pathname
, "tw_cli/", 7)) {
285 return tw_cli_open(pathname
+7);
287 } else if (!strcmp(type
, "SCSI")) {
288 // scsi[0-9][0-f] => ASPI Adapter 0-9, ID 0-15, LUN 0
289 unsigned adapter
= ~0, id
= ~0; int n1
= -1;
290 if (sscanf(pathname
,"scsi%1u%1x%n", &adapter
, &id
, &n1
) == 2 && n1
== len
) {
291 return aspi_open(adapter
, id
);
293 // sd[a-z],N => Physical drive 0-26, RAID port N
294 char drive
[1+1] = ""; int sub_addr
= -1; n1
= -1; int n2
= -1;
295 if ( sscanf(pathname
, "sd%1[a-z]%n,%d%n", drive
, &n1
, &sub_addr
, &n2
) >= 1
296 && ((n1
== len
&& sub_addr
== -1) || (n2
== len
&& sub_addr
>= 0)) ) {
297 return spt_open(drive
[0] - 'a', -1, sub_addr
);
299 // pd<m>,N => Physical drive <m>, RAID port N
300 int pd_num
= -1; sub_addr
= -1; n1
= -1; n2
= -1;
301 if ( sscanf(pathname
, "pd%d%n,%d%n", &pd_num
, &n1
, &sub_addr
, &n2
) >= 1
302 && pd_num
>= 0 && ((n1
== len
&& sub_addr
== -1) || (n2
== len
&& sub_addr
>= 0))) {
303 return spt_open(pd_num
, -1, sub_addr
);
305 // tape<m> => tape drive <m>
306 int tape_num
= -1; n1
= -1;
307 if (sscanf(pathname
, "tape%d%n", &tape_num
, &n1
) == 1 && tape_num
>= 0 && n1
== len
) {
308 return spt_open(-1, tape_num
, -1);
317 // Like close(). Acts only on handles returned by above function.
318 // (Never called in smartctl!)
319 int deviceclose(int fd
)
321 if ((fd
& 0xff00) == ASPI_FDOFFSET
)
323 else if (fd
>= SPT_FDOFFSET
)
325 else if (fd
== TW_CLI_FDOFFSET
)
333 // print examples for smartctl
334 void print_smartctl_examples(){
335 printf("=================================================== SMARTCTL EXAMPLES =====\n\n"
336 " smartctl -a /dev/hda (Prints all SMART information)\n\n"
337 #ifdef HAVE_GETOPT_LONG
338 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/hda\n"
339 " (Enables SMART on first disk)\n\n"
340 " smartctl -t long /dev/hda (Executes extended disk self-test)\n\n"
341 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/hda\n"
342 " (Prints Self-Test & Attribute errors)\n"
344 " smartctl -s on -o on -S on /dev/hda (Enables SMART on first disk)\n"
345 " smartctl -t long /dev/hda (Executes extended disk self-test)\n"
346 " smartctl -A -l selftest -q errorsonly /dev/hda\n"
347 " (Prints Self-Test & Attribute errors)\n"
349 " smartctl -a /dev/scsi21\n"
350 " (Prints all information for SCSI disk on ASPI adapter 2, ID 1)\n"
351 " smartctl -a /dev/sda\n"
352 " (Prints all information for SCSI disk on PhysicalDrive 0)\n"
353 " smartctl -a /dev/pd3\n"
354 " (Prints all information for SCSI disk on PhysicalDrive 3)\n"
355 " smartctl -a /dev/tape1\n"
356 " (Prints all information for SCSI tape on Tape 1)\n"
357 " smartctl -A /dev/hdb,3\n"
358 " (Prints Attributes for physical drive 3 on 3ware 9000 RAID)\n"
359 " smartctl -A /dev/tw_cli/c0/p1\n"
360 " (Prints Attributes for 3ware controller 0, port 1 using tw_cli)\n"
362 " ATA SMART access methods and ordering may be specified by modifiers\n"
363 " following the device name: /dev/hdX:[saic], where\n"
364 " 's': SMART_* IOCTLs, 'a': IOCTL_ATA_PASS_THROUGH,\n"
365 " 'i': IOCTL_IDE_PASS_THROUGH, 'c': ATA via IOCTL_SCSI_PASS_THROUGH.\n"
366 " The default on this system is /dev/hdX:%s\n", ata_get_def_options()
371 /////////////////////////////////////////////////////////////////////////////
373 /////////////////////////////////////////////////////////////////////////////
375 // SMART_* IOCTLs, also known as DFP_* (Disk Fault Protection)
377 // Deklarations from:
378 // http://cvs.sourceforge.net/viewcvs.py/mingw/w32api/include/ddk/ntdddisk.h?rev=1.3
380 #define FILE_READ_ACCESS 0x0001
381 #define FILE_WRITE_ACCESS 0x0002
382 #define METHOD_BUFFERED 0
383 #define CTL_CODE(DeviceType, Function, Method, Access) (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
385 #define FILE_DEVICE_DISK 7
386 #define IOCTL_DISK_BASE FILE_DEVICE_DISK
388 #define SMART_GET_VERSION \
389 CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS)
391 #define SMART_SEND_DRIVE_COMMAND \
392 CTL_CODE(IOCTL_DISK_BASE, 0x0021, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
394 #define SMART_RCV_DRIVE_DATA \
395 CTL_CODE(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
397 ASSERT_CONST(SMART_GET_VERSION
, 0x074080);
398 ASSERT_CONST(SMART_SEND_DRIVE_COMMAND
, 0x07c084);
399 ASSERT_CONST(SMART_RCV_DRIVE_DATA
, 0x07c088);
401 #define SMART_CYL_LOW 0x4F
402 #define SMART_CYL_HI 0xC2
407 typedef struct _GETVERSIONOUTPARAMS
{
414 } GETVERSIONOUTPARAMS
, *PGETVERSIONOUTPARAMS
, *LPGETVERSIONOUTPARAMS
;
416 ASSERT_SIZEOF(GETVERSIONOUTPARAMS
, 24);
419 #define SMART_VENDOR_3WARE 0x13C1 // identifies 3ware specific parameters
421 typedef struct _GETVERSIONINPARAMS_EX
{
427 DWORD dwDeviceMapEx
; // 3ware specific: RAID drive bit map
428 WORD wIdentifier
; // Vendor specific identifier
429 WORD wControllerId
; // 3ware specific: Controller ID (0,1,...)
431 } GETVERSIONINPARAMS_EX
, *PGETVERSIONINPARAMS_EX
, *LPGETVERSIONINPARAMS_EX
;
433 ASSERT_SIZEOF(GETVERSIONINPARAMS_EX
, sizeof(GETVERSIONOUTPARAMS
));
436 typedef struct _IDEREGS
{
438 UCHAR bSectorCountReg
;
439 UCHAR bSectorNumberReg
;
445 } IDEREGS
, *PIDEREGS
, *LPIDEREGS
;
447 typedef struct _SENDCMDINPARAMS
{
454 } SENDCMDINPARAMS
, *PSENDCMDINPARAMS
, *LPSENDCMDINPARAMS
;
456 ASSERT_SIZEOF(SENDCMDINPARAMS
, 32+1);
458 typedef struct _SENDCMDINPARAMS_EX
{
462 BYTE bPortNumber
; // 3ware specific: port number
463 WORD wIdentifier
; // Vendor specific identifier
466 } SENDCMDINPARAMS_EX
, *PSENDCMDINPARAMS_EX
, *LPSENDCMDINPARAMS_EX
;
468 ASSERT_SIZEOF(SENDCMDINPARAMS_EX
, sizeof(SENDCMDINPARAMS
));
471 /* DRIVERSTATUS.bDriverError constants (just for info, not used)
472 #define SMART_NO_ERROR 0
473 #define SMART_IDE_ERROR 1
474 #define SMART_INVALID_FLAG 2
475 #define SMART_INVALID_COMMAND 3
476 #define SMART_INVALID_BUFFER 4
477 #define SMART_INVALID_DRIVE 5
478 #define SMART_INVALID_IOCTL 6
479 #define SMART_ERROR_NO_MEM 7
480 #define SMART_INVALID_REGISTER 8
481 #define SMART_NOT_SUPPORTED 9
482 #define SMART_NO_IDE_DEVICE 10
485 typedef struct _DRIVERSTATUS
{
490 } DRIVERSTATUS
, *PDRIVERSTATUS
, *LPDRIVERSTATUS
;
492 typedef struct _SENDCMDOUTPARAMS
{
494 DRIVERSTATUS DriverStatus
;
496 } SENDCMDOUTPARAMS
, *PSENDCMDOUTPARAMS
, *LPSENDCMDOUTPARAMS
;
498 ASSERT_SIZEOF(SENDCMDOUTPARAMS
, 16+1);
503 /////////////////////////////////////////////////////////////////////////////
505 static void print_ide_regs(const IDEREGS
* r
, int out
)
507 pout("%s=0x%02x,%s=0x%02x, SC=0x%02x, NS=0x%02x, CL=0x%02x, CH=0x%02x, SEL=0x%02x\n",
508 (out
?"STS":"CMD"), r
->bCommandReg
, (out
?"ERR":" FR"), r
->bFeaturesReg
,
509 r
->bSectorCountReg
, r
->bSectorNumberReg
, r
->bCylLowReg
, r
->bCylHighReg
, r
->bDriveHeadReg
);
512 static void print_ide_regs_io(const IDEREGS
* ri
, const IDEREGS
* ro
)
514 pout(" Input : "); print_ide_regs(ri
, 0);
516 pout(" Output: "); print_ide_regs(ro
, 1);
520 /////////////////////////////////////////////////////////////////////////////
522 // call SMART_GET_VERSION, return device map or -1 on error
524 static int smart_get_version(HANDLE hdevice
, unsigned long * portmap
= 0)
526 GETVERSIONOUTPARAMS vers
;
527 const GETVERSIONINPARAMS_EX
& vers_ex
= (const GETVERSIONINPARAMS_EX
&)vers
;
530 memset(&vers
, 0, sizeof(vers
));
531 if (!DeviceIoControl(hdevice
, SMART_GET_VERSION
,
532 NULL
, 0, &vers
, sizeof(vers
), &num_out
, NULL
)) {
533 if (con
->reportataioctl
)
534 pout(" SMART_GET_VERSION failed, Error=%ld\n", GetLastError());
538 assert(num_out
== sizeof(GETVERSIONOUTPARAMS
));
541 // Return bitmask of valid RAID ports
542 if (vers_ex
.wIdentifier
!= SMART_VENDOR_3WARE
) {
543 pout(" SMART_GET_VERSION returns unknown Identifier = %04x\n"
544 " This is no 3ware 9000 controller or driver has no SMART support.\n", vers_ex
.wIdentifier
);
548 *portmap
= vers_ex
.dwDeviceMapEx
;
551 if (con
->reportataioctl
> 1) {
552 pout(" SMART_GET_VERSION suceeded, bytes returned: %lu\n"
553 " Vers = %d.%d, Caps = 0x%lx, DeviceMap = 0x%02x\n",
554 num_out
, vers
.bVersion
, vers
.bRevision
,
555 vers
.fCapabilities
, vers
.bIDEDeviceMap
);
556 if (vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
)
557 pout(" Identifier = %04x(3WARE), ControllerId=%u, DeviceMapEx = 0x%08lx\n",
558 vers_ex
.wIdentifier
, vers_ex
.wControllerId
, vers_ex
.dwDeviceMapEx
);
561 // TODO: Check vers.fCapabilities here?
562 return vers
.bIDEDeviceMap
;
566 // call SMART_* ioctl
568 static int smart_ioctl(HANDLE hdevice
, int drive
, IDEREGS
* regs
, char * data
, unsigned datasize
, int port
)
570 SENDCMDINPARAMS inpar
;
571 SENDCMDINPARAMS_EX
& inpar_ex
= (SENDCMDINPARAMS_EX
&)inpar
;
573 unsigned char outbuf
[sizeof(SENDCMDOUTPARAMS
)-1 + 512];
574 const SENDCMDOUTPARAMS
* outpar
;
576 unsigned int size_out
;
579 memset(&inpar
, 0, sizeof(inpar
));
580 inpar
.irDriveRegs
= *regs
;
581 // drive is set to 0-3 on Win9x only
582 inpar
.irDriveRegs
.bDriveHeadReg
= 0xA0 | ((drive
& 1) << 4);
583 inpar
.bDriveNumber
= drive
;
587 inpar_ex
.wIdentifier
= SMART_VENDOR_3WARE
;
588 inpar_ex
.bPortNumber
= port
;
591 assert(datasize
== 0 || datasize
== 512);
593 code
= SMART_RCV_DRIVE_DATA
; name
= "SMART_RCV_DRIVE_DATA";
594 inpar
.cBufferSize
= size_out
= 512;
597 code
= SMART_SEND_DRIVE_COMMAND
; name
= "SMART_SEND_DRIVE_COMMAND";
598 if (regs
->bFeaturesReg
== ATA_SMART_STATUS
) {
599 size_out
= sizeof(IDEREGS
); // ioctl returns new IDEREGS as data
600 // Note: cBufferSize must be 0 on Win9x
601 inpar
.cBufferSize
= size_out
;
607 memset(&outbuf
, 0, sizeof(outbuf
));
609 if (!DeviceIoControl(hdevice
, code
, &inpar
, sizeof(SENDCMDINPARAMS
)-1,
610 outbuf
, sizeof(SENDCMDOUTPARAMS
)-1 + size_out
, &num_out
, NULL
)) {
611 // CAUTION: DO NOT change "regs" Parameter in this case, see ata_command_interface()
612 long err
= GetLastError();
613 if (con
->reportataioctl
&& (err
!= ERROR_INVALID_PARAMETER
|| con
->reportataioctl
> 1)) {
614 pout(" %s failed, Error=%ld\n", name
, err
);
615 print_ide_regs_io(regs
, NULL
);
617 errno
= ( err
== ERROR_INVALID_FUNCTION
/*9x*/
618 || err
== ERROR_INVALID_PARAMETER
/*NT/2K/XP*/ ? ENOSYS
: EIO
);
621 // NOTE: On Win9x, inpar.irDriveRegs now contains the returned regs
623 outpar
= (const SENDCMDOUTPARAMS
*)outbuf
;
625 if (outpar
->DriverStatus
.bDriverError
) {
626 if (con
->reportataioctl
) {
627 pout(" %s failed, DriverError=0x%02x, IDEError=0x%02x\n", name
,
628 outpar
->DriverStatus
.bDriverError
, outpar
->DriverStatus
.bIDEError
);
629 print_ide_regs_io(regs
, NULL
);
631 errno
= (!outpar
->DriverStatus
.bIDEError
? ENOSYS
: EIO
);
635 if (con
->reportataioctl
> 1) {
636 pout(" %s suceeded, bytes returned: %lu (buffer %lu)\n", name
,
637 num_out
, outpar
->cBufferSize
);
638 print_ide_regs_io(regs
, (regs
->bFeaturesReg
== ATA_SMART_STATUS
?
639 (const IDEREGS
*)(outpar
->bBuffer
) : NULL
));
643 memcpy(data
, outpar
->bBuffer
, 512);
644 else if (regs
->bFeaturesReg
== ATA_SMART_STATUS
) {
645 if (nonempty(const_cast<unsigned char *>(outpar
->bBuffer
), sizeof(IDEREGS
)))
646 *regs
= *(const IDEREGS
*)(outpar
->bBuffer
);
647 else { // Workaround for driver not returning regs
648 if (con
->reportataioctl
)
649 pout(" WARNING: driver does not return ATA registers in output buffer!\n");
650 *regs
= inpar
.irDriveRegs
;
658 /////////////////////////////////////////////////////////////////////////////
660 // IDE PASS THROUGH (2000, XP, undocumented)
662 // Based on WinATA.cpp, 2002 c't/Matthias Withopf
663 // ftp://ftp.heise.de/pub/ct/listings/0207-218.zip
665 #define FILE_DEVICE_CONTROLLER 4
666 #define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER
668 #define IOCTL_IDE_PASS_THROUGH \
669 CTL_CODE(IOCTL_SCSI_BASE, 0x040A, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
671 ASSERT_CONST(IOCTL_IDE_PASS_THROUGH
, 0x04d028);
677 ULONG DataBufferSize
;
681 ASSERT_SIZEOF(ATA_PASS_THROUGH
, 12+1);
686 /////////////////////////////////////////////////////////////////////////////
688 static int ide_pass_through_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, unsigned datasize
)
690 if (datasize
> 512) {
694 unsigned int size
= sizeof(ATA_PASS_THROUGH
)-1 + datasize
;
695 ATA_PASS_THROUGH
* buf
= (ATA_PASS_THROUGH
*)VirtualAlloc(NULL
, size
, MEM_COMMIT
, PAGE_READWRITE
);
697 const unsigned char magic
= 0xcf;
705 buf
->DataBufferSize
= datasize
;
707 buf
->DataBuffer
[0] = magic
;
709 if (!DeviceIoControl(hdevice
, IOCTL_IDE_PASS_THROUGH
,
710 buf
, size
, buf
, size
, &num_out
, NULL
)) {
711 long err
= GetLastError();
712 if (con
->reportataioctl
) {
713 pout(" IOCTL_IDE_PASS_THROUGH failed, Error=%ld\n", err
);
714 print_ide_regs_io(regs
, NULL
);
716 VirtualFree(buf
, 0, MEM_RELEASE
);
717 errno
= (err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
722 if (buf
->IdeReg
.bCommandReg
/*Status*/ & 0x01) {
723 if (con
->reportataioctl
) {
724 pout(" IOCTL_IDE_PASS_THROUGH command failed:\n");
725 print_ide_regs_io(regs
, &buf
->IdeReg
);
727 VirtualFree(buf
, 0, MEM_RELEASE
);
732 // Check and copy data
735 || (buf
->DataBuffer
[0] == magic
&& !nonempty(buf
->DataBuffer
+1, datasize
-1))) {
736 if (con
->reportataioctl
) {
737 pout(" IOCTL_IDE_PASS_THROUGH output data missing (%lu, %lu)\n",
738 num_out
, buf
->DataBufferSize
);
739 print_ide_regs_io(regs
, &buf
->IdeReg
);
741 VirtualFree(buf
, 0, MEM_RELEASE
);
745 memcpy(data
, buf
->DataBuffer
, datasize
);
748 if (con
->reportataioctl
> 1) {
749 pout(" IOCTL_IDE_PASS_THROUGH suceeded, bytes returned: %lu (buffer %lu)\n",
750 num_out
, buf
->DataBufferSize
);
751 print_ide_regs_io(regs
, &buf
->IdeReg
);
755 // Caution: VirtualFree() fails if parameter "dwSize" is nonzero
756 VirtualFree(buf
, 0, MEM_RELEASE
);
761 /////////////////////////////////////////////////////////////////////////////
763 // ATA PASS THROUGH (Win2003, XP SP2)
765 #define IOCTL_ATA_PASS_THROUGH \
766 CTL_CODE(IOCTL_SCSI_BASE, 0x040B, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
768 ASSERT_CONST(IOCTL_ATA_PASS_THROUGH
, 0x04d02c);
770 typedef struct _ATA_PASS_THROUGH_EX
{
776 UCHAR ReservedAsUchar
;
777 ULONG DataTransferLength
;
779 ULONG ReservedAsUlong
;
780 ULONG
/*_PTR*/ DataBufferOffset
;
781 UCHAR PreviousTaskFile
[8];
782 UCHAR CurrentTaskFile
[8];
783 } ATA_PASS_THROUGH_EX
, *PATA_PASS_THROUGH_EX
;
785 ASSERT_SIZEOF(ATA_PASS_THROUGH_EX
, 40);
787 #define ATA_FLAGS_DRDY_REQUIRED 0x01
788 #define ATA_FLAGS_DATA_IN 0x02
789 #define ATA_FLAGS_DATA_OUT 0x04
790 #define ATA_FLAGS_48BIT_COMMAND 0x08
793 /////////////////////////////////////////////////////////////////////////////
795 static int ata_pass_through_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, int datasize
)
798 ATA_PASS_THROUGH_EX apt
;
800 UCHAR ucDataBuf
[512];
801 } ATA_PASS_THROUGH_EX_WITH_BUFFERS
;
803 const unsigned char magic
= 0xcf;
805 ATA_PASS_THROUGH_EX_WITH_BUFFERS ab
; memset(&ab
, 0, sizeof(ab
));
806 ab
.apt
.Length
= sizeof(ATA_PASS_THROUGH_EX
);
808 //ab.apt.TargetId = 0;
810 ab
.apt
.TimeOutValue
= 10;
811 unsigned size
= offsetof(ATA_PASS_THROUGH_EX_WITH_BUFFERS
, ucDataBuf
);
812 ab
.apt
.DataBufferOffset
= size
;
815 if (datasize
> (int)sizeof(ab
.ucDataBuf
)) {
819 ab
.apt
.AtaFlags
= ATA_FLAGS_DATA_IN
;
820 ab
.apt
.DataTransferLength
= datasize
;
822 ab
.ucDataBuf
[0] = magic
;
824 else if (datasize
< 0) {
825 if (-datasize
> (int)sizeof(ab
.ucDataBuf
)) {
829 ab
.apt
.AtaFlags
= ATA_FLAGS_DATA_OUT
;
830 ab
.apt
.DataTransferLength
= -datasize
;
832 memcpy(ab
.ucDataBuf
, data
, -datasize
);
835 assert(ab
.apt
.AtaFlags
== 0);
836 assert(ab
.apt
.DataTransferLength
== 0);
839 assert(sizeof(ab
.apt
.CurrentTaskFile
) == sizeof(IDEREGS
));
840 IDEREGS
* ctfregs
= (IDEREGS
*)ab
.apt
.CurrentTaskFile
;
844 if (!DeviceIoControl(hdevice
, IOCTL_ATA_PASS_THROUGH
,
845 &ab
, size
, &ab
, size
, &num_out
, NULL
)) {
846 long err
= GetLastError();
847 if (con
->reportataioctl
) {
848 pout(" IOCTL_ATA_PASS_THROUGH failed, Error=%ld\n", err
);
849 print_ide_regs_io(regs
, NULL
);
851 errno
= (err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
856 if (ctfregs
->bCommandReg
/*Status*/ & 0x01) {
857 if (con
->reportataioctl
) {
858 pout(" IOCTL_ATA_PASS_THROUGH command failed:\n");
859 print_ide_regs_io(regs
, ctfregs
);
865 // Check and copy data
868 || (ab
.ucDataBuf
[0] == magic
&& !nonempty(ab
.ucDataBuf
+1, datasize
-1))) {
869 if (con
->reportataioctl
) {
870 pout(" IOCTL_ATA_PASS_THROUGH output data missing (%lu)\n", num_out
);
871 print_ide_regs_io(regs
, ctfregs
);
876 memcpy(data
, ab
.ucDataBuf
, datasize
);
879 if (con
->reportataioctl
> 1) {
880 pout(" IOCTL_ATA_PASS_THROUGH suceeded, bytes returned: %lu\n", num_out
);
881 print_ide_regs_io(regs
, ctfregs
);
889 /////////////////////////////////////////////////////////////////////////////
891 // ATA PASS THROUGH via SCSI PASS THROUGH (WinNT4 only)
893 // Declarations from:
894 // http://cvs.sourceforge.net/viewcvs.py/mingw/w32api/include/ddk/ntddscsi.h?rev=1.2
896 #define IOCTL_SCSI_PASS_THROUGH \
897 CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
899 ASSERT_CONST(IOCTL_SCSI_PASS_THROUGH
, 0x04d004);
901 #define SCSI_IOCTL_DATA_OUT 0
902 #define SCSI_IOCTL_DATA_IN 1
903 #define SCSI_IOCTL_DATA_UNSPECIFIED 2
904 // undocumented SCSI opcode to for ATA passthrough
905 #define SCSIOP_ATA_PASSTHROUGH 0xCC
907 typedef struct _SCSI_PASS_THROUGH
{
914 UCHAR SenseInfoLength
;
916 ULONG DataTransferLength
;
918 ULONG
/*_PTR*/ DataBufferOffset
;
919 ULONG SenseInfoOffset
;
921 } SCSI_PASS_THROUGH
, *PSCSI_PASS_THROUGH
;
923 ASSERT_SIZEOF(SCSI_PASS_THROUGH
, 44);
926 /////////////////////////////////////////////////////////////////////////////
928 static int ata_via_scsi_pass_through_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, unsigned datasize
)
931 SCSI_PASS_THROUGH spt
;
933 UCHAR ucSenseBuf
[32];
934 UCHAR ucDataBuf
[512];
935 } SCSI_PASS_THROUGH_WITH_BUFFERS
;
937 SCSI_PASS_THROUGH_WITH_BUFFERS sb
;
941 const unsigned char magic
= 0xcf;
943 memset(&sb
, 0, sizeof(sb
));
944 sb
.spt
.Length
= sizeof(SCSI_PASS_THROUGH
);
948 sb
.spt
.CdbLength
= 10; sb
.spt
.SenseInfoLength
= 24;
949 sb
.spt
.TimeOutValue
= 10;
950 sb
.spt
.SenseInfoOffset
= offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS
, ucSenseBuf
);
951 size
= offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS
, ucDataBuf
);
952 sb
.spt
.DataBufferOffset
= size
;
955 if (datasize
> sizeof(sb
.ucDataBuf
)) {
959 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_IN
;
960 sb
.spt
.DataTransferLength
= datasize
;
962 sb
.ucDataBuf
[0] = magic
;
965 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_UNSPECIFIED
;
966 //sb.spt.DataTransferLength = 0;
969 // Use pseudo SCSI command followed by registers
970 sb
.spt
.Cdb
[0] = SCSIOP_ATA_PASSTHROUGH
;
971 cdbregs
= (IDEREGS
*)(sb
.spt
.Cdb
+2);
974 if (!DeviceIoControl(hdevice
, IOCTL_SCSI_PASS_THROUGH
,
975 &sb
, size
, &sb
, size
, &num_out
, NULL
)) {
976 long err
= GetLastError();
977 if (con
->reportataioctl
)
978 pout(" ATA via IOCTL_SCSI_PASS_THROUGH failed, Error=%ld\n", err
);
979 errno
= (err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
983 // Cannot check ATA status, because command does not return IDEREGS
985 // Check and copy data
988 || (sb
.ucDataBuf
[0] == magic
&& !nonempty(sb
.ucDataBuf
+1, datasize
-1))) {
989 if (con
->reportataioctl
) {
990 pout(" ATA via IOCTL_SCSI_PASS_THROUGH output data missing (%lu)\n", num_out
);
991 print_ide_regs_io(regs
, NULL
);
996 memcpy(data
, sb
.ucDataBuf
, datasize
);
999 if (con
->reportataioctl
> 1) {
1000 pout(" ATA via IOCTL_SCSI_PASS_THROUGH suceeded, bytes returned: %lu\n", num_out
);
1001 print_ide_regs_io(regs
, NULL
);
1007 /////////////////////////////////////////////////////////////////////////////
1009 // ATA PASS THROUGH via 3ware specific SCSI MINIPORT ioctl
1011 #define IOCTL_SCSI_MINIPORT \
1012 CTL_CODE(IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
1014 ASSERT_CONST(IOCTL_SCSI_MINIPORT
, 0x04d008);
1016 typedef struct _SRB_IO_CONTROL
{
1023 } SRB_IO_CONTROL
, *PSRB_IO_CONTROL
;
1025 ASSERT_SIZEOF(SRB_IO_CONTROL
, 28);
1027 /////////////////////////////////////////////////////////////////////////////
1029 static int ata_via_3ware_miniport_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, int datasize
, int port
)
1032 SRB_IO_CONTROL srbc
;
1036 ASSERT_SIZEOF(sb
, sizeof(SRB_IO_CONTROL
)+sizeof(IDEREGS
)+512);
1038 if (!(0 <= datasize
&& datasize
<= (int)sizeof(sb
.buffer
) && port
>= 0)) {
1042 memset(&sb
, 0, sizeof(sb
));
1043 strcpy((char *)sb
.srbc
.Signature
, "<3ware>");
1044 sb
.srbc
.HeaderLength
= sizeof(SRB_IO_CONTROL
);
1045 sb
.srbc
.Timeout
= 60; // seconds
1046 sb
.srbc
.ControlCode
= 0xA0000000;
1047 sb
.srbc
.ReturnCode
= 0;
1048 sb
.srbc
.Length
= sizeof(IDEREGS
) + (datasize
> 0 ? datasize
: 1);
1050 sb
.regs
.bReserved
= port
;
1053 if (!DeviceIoControl(hdevice
, IOCTL_SCSI_MINIPORT
,
1054 &sb
, sizeof(sb
), &sb
, sizeof(sb
), &num_out
, NULL
)) {
1055 long err
= GetLastError();
1056 if (con
->reportataioctl
) {
1057 pout(" ATA via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err
);
1058 print_ide_regs_io(regs
, NULL
);
1060 errno
= (err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
1064 if (sb
.srbc
.ReturnCode
) {
1065 if (con
->reportataioctl
) {
1066 pout(" ATA via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08lx\n", sb
.srbc
.ReturnCode
);
1067 print_ide_regs_io(regs
, NULL
);
1075 memcpy(data
, sb
.buffer
, datasize
);
1077 if (con
->reportataioctl
> 1) {
1078 pout(" ATA via IOCTL_SCSI_MINIPORT suceeded, bytes returned: %lu\n", num_out
);
1079 print_ide_regs_io(regs
, &sb
.regs
);
1087 /////////////////////////////////////////////////////////////////////////////
1089 // 3ware specific call to update the devicemap returned by SMART_GET_VERSION.
1090 // 3DM/CLI "Rescan Controller" function does not to always update it.
1092 static int update_3ware_devicemap_ioctl(HANDLE hdevice
)
1094 SRB_IO_CONTROL srbc
;
1095 memset(&srbc
, 0, sizeof(srbc
));
1096 strcpy((char *)srbc
.Signature
, "<3ware>");
1097 srbc
.HeaderLength
= sizeof(SRB_IO_CONTROL
);
1098 srbc
.Timeout
= 60; // seconds
1099 srbc
.ControlCode
= 0xCC010014;
1100 srbc
.ReturnCode
= 0;
1104 if (!DeviceIoControl(hdevice
, IOCTL_SCSI_MINIPORT
,
1105 &srbc
, sizeof(srbc
), &srbc
, sizeof(srbc
), &num_out
, NULL
)) {
1106 long err
= GetLastError();
1107 if (con
->reportataioctl
)
1108 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err
);
1109 errno
= (err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
1112 if (srbc
.ReturnCode
) {
1113 if (con
->reportataioctl
)
1114 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08lx\n", srbc
.ReturnCode
);
1118 if (con
->reportataioctl
> 1)
1119 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT suceeded\n");
1125 /////////////////////////////////////////////////////////////////////////////
1127 // Routines for pseudo device /dev/tw_cli/*
1128 // Parses output of 3ware "tw_cli /cx/py show all" or 3DM SMART data window
1131 // Get clipboard data
1133 static int get_clipboard(char * data
, int datasize
)
1135 if (!OpenClipboard(NULL
))
1137 HANDLE h
= GetClipboardData(CF_TEXT
);
1142 const void * p
= GlobalLock(h
);
1143 int n
= GlobalSize(h
);
1153 // Run a command, write stdout to dataout
1154 // TODO: Combine with daemon_win32.cpp:daemon_spawn()
1156 static int run_cmd(const char * cmd
, char * dataout
, int outsize
)
1158 // Create stdout pipe
1159 SECURITY_ATTRIBUTES sa
= {sizeof(sa
), 0, TRUE
};
1160 HANDLE pipe_out_w
, h
;
1161 if (!CreatePipe(&h
, &pipe_out_w
, &sa
/*inherit*/, outsize
))
1163 HANDLE self
= GetCurrentProcess();
1165 if (!DuplicateHandle(self
, h
, self
, &pipe_out_r
,
1166 GENERIC_READ
, FALSE
/*!inherit*/, DUPLICATE_CLOSE_SOURCE
)) {
1167 CloseHandle(pipe_out_w
);
1171 if (!DuplicateHandle(self
, pipe_out_w
, self
, &pipe_err_w
,
1172 0, TRUE
/*inherit*/, DUPLICATE_SAME_ACCESS
)) {
1173 CloseHandle(pipe_out_r
); CloseHandle(pipe_out_w
);
1178 STARTUPINFO si
; memset(&si
, 0, sizeof(si
)); si
.cb
= sizeof(si
);
1179 si
.hStdInput
= INVALID_HANDLE_VALUE
;
1180 si
.hStdOutput
= pipe_out_w
; si
.hStdError
= pipe_err_w
;
1181 si
.dwFlags
= STARTF_USESTDHANDLES
;
1182 PROCESS_INFORMATION pi
;
1184 NULL
, const_cast<char *>(cmd
),
1185 NULL
, NULL
, TRUE
/*inherit*/,
1186 CREATE_NO_WINDOW
/*do not create a new console window*/,
1187 NULL
, NULL
, &si
, &pi
)) {
1188 CloseHandle(pipe_err_w
); CloseHandle(pipe_out_r
); CloseHandle(pipe_out_w
);
1191 CloseHandle(pi
.hThread
);
1192 CloseHandle(pipe_err_w
); CloseHandle(pipe_out_w
);
1194 // Copy stdout to output buffer
1196 while (i
< outsize
) {
1198 if (!ReadFile(pipe_out_r
, dataout
+i
, outsize
-i
, &num_read
, NULL
) || num_read
== 0)
1202 CloseHandle(pipe_out_r
);
1204 WaitForSingleObject(pi
.hProcess
, INFINITE
);
1205 CloseHandle(pi
.hProcess
);
1210 static const char * findstr(const char * str
, const char * sub
)
1212 const char * s
= strstr(str
, sub
);
1213 return (s
? s
+strlen(sub
) : "");
1217 static void copy_swapped(unsigned char * dest
, const char * src
, int destsize
)
1219 int srclen
= strcspn(src
, "\r\n");
1221 for (i
= 0; i
< destsize
-1 && i
< srclen
-1; i
+=2) {
1222 dest
[i
] = src
[i
+1]; dest
[i
+1] = src
[i
];
1224 if (i
< destsize
-1 && i
< srclen
)
1229 static ata_identify_device
* tw_cli_identbuf
= 0;
1230 static ata_smart_values
* tw_cli_smartbuf
= 0;
1232 static int tw_cli_open(const char * name
)
1234 // Read tw_cli or 3DM browser output into buffer
1236 int size
= -1, n1
= -1;
1237 if (!strcmp(name
, "clip")) { // tw_cli/clip => read clipboard
1238 size
= get_clipboard(buffer
, sizeof(buffer
));
1240 else if (!strcmp(name
, "stdin")) { // tw_cli/stdin => read stdin
1241 size
= fread(buffer
, 1, sizeof(buffer
), stdin
);
1243 else if (sscanf(name
, "c%*u/p%*u%n", &n1
) >= 0 && n1
== (int)strlen(name
)) {
1244 // tw_cli/cx/py => read output from "tw_cli /cx/py show all"
1246 snprintf(cmd
, sizeof(cmd
), "tw_cli /%s show all", name
);
1247 if (con
->reportataioctl
> 1)
1248 pout("tw_cli/%s: Run: \"%s\"\n", name
, cmd
);
1249 size
= run_cmd(cmd
, buffer
, sizeof(buffer
));
1252 errno
= EINVAL
; return -1;
1255 if (con
->reportataioctl
> 1)
1256 pout("tw_cli/%s: Read %d bytes\n", name
, size
);
1258 errno
= ENOENT
; return -1;
1260 if (size
>= (int)sizeof(buffer
)) {
1261 errno
= EIO
; return -1;
1264 if (con
->reportataioctl
> 1)
1265 pout("[\n%.100s%s\n]\n", buffer
, (size
>100?"...":""));
1267 // Fake identify sector
1268 ASSERT_SIZEOF(ata_identify_device
, 512);
1269 ata_identify_device
* id
= (ata_identify_device
*)malloc(sizeof(ata_identify_device
));
1270 memset(id
, 0, sizeof(*id
));
1271 copy_swapped(id
->model
, findstr(buffer
, " Model = " ), sizeof(id
->model
));
1272 copy_swapped(id
->fw_rev
, findstr(buffer
, " Firmware Version = "), sizeof(id
->fw_rev
));
1273 copy_swapped(id
->serial_no
, findstr(buffer
, " Serial = " ), sizeof(id
->serial_no
));
1274 unsigned long nblocks
= 0; // "Capacity = N.N GB (N Blocks)"
1275 sscanf(findstr(buffer
, "Capacity = "), "%*[^(\r\n](%lu", &nblocks
);
1277 id
->words047_079
[49-47] = 0x0200; // size valid
1278 id
->words047_079
[60-47] = (unsigned short)(nblocks
); // secs_16
1279 id
->words047_079
[61-47] = (unsigned short)(nblocks
>>16); // secs_32
1281 id
->major_rev_num
= 0x1<<3; // ATA-3
1282 id
->command_set_1
= 0x0001; id
->command_set_2
= 0x4000; // SMART supported, words 82,83 valid
1283 id
->cfs_enable_1
= 0x0001; id
->csf_default
= 0x4000; // SMART enabled, words 85,87 valid
1285 // Parse smart data hex dump
1286 const char * s
= findstr(buffer
, "Drive Smart Data:");
1288 s
= findstr(buffer
, "S.M.A.R.T. (Controller"); // from 3DM browser window
1290 const char * s1
= findstr(s
, "<td class"); // html version
1293 s
+= strcspn(s
, "\r\n");
1296 s
= buffer
; // try raw hex dump without header
1298 unsigned char * sd
= (unsigned char *)malloc(512);
1301 unsigned x
= ~0; int n
= -1;
1302 if (!(sscanf(s
, "%x %n", &x
, &n
) == 1 && !(x
& ~0xff)))
1304 sd
[i
] = (unsigned char)x
;
1305 if (!(++i
< 512 && n
> 0))
1308 if (*s
== '<') // "<br>"
1309 s
+= strcspn(s
, "\r\n");
1313 if (!id
->model
[1]) {
1314 // No useful data found
1316 char * err
= strstr(buffer
, "Error:");
1318 err
= strstr(buffer
, "error :");
1320 // Print tw_cli error message
1321 err
[strcspn(err
, "\r\n")] = 0;
1330 tw_cli_identbuf
= id
;
1331 tw_cli_smartbuf
= (ata_smart_values
*)sd
;
1332 return TW_CLI_FDOFFSET
;
1336 static void tw_cli_close()
1338 if (tw_cli_identbuf
) {
1339 free(tw_cli_identbuf
); tw_cli_identbuf
= 0;
1341 if (tw_cli_smartbuf
) {
1342 free(tw_cli_smartbuf
); tw_cli_smartbuf
= 0;
1347 static int tw_cli_command_interface(smart_command_set command
, int /*select*/, char * data
)
1351 if (!tw_cli_identbuf
)
1353 memcpy(data
, tw_cli_identbuf
, 512);
1356 if (!tw_cli_smartbuf
)
1358 memcpy(data
, tw_cli_smartbuf
, 512);
1360 case READ_THRESHOLDS
:
1361 if (!tw_cli_smartbuf
)
1363 // Fake zero thresholds
1365 const ata_smart_values
* sv
= tw_cli_smartbuf
;
1366 ata_smart_thresholds_pvt
* tr
= (ata_smart_thresholds_pvt
*)data
;
1368 // TODO: Indicate missing thresholds in ataprint.cpp:PrintSmartAttribWithThres()
1369 // (ATA_SMART_READ_THRESHOLDS is marked obsolete since ATA-5)
1370 for (int i
= 0; i
< NUMBER_ATA_SMART_ATTRIBUTES
; i
++)
1371 tr
->chksum
-= tr
->thres_entries
[i
].id
= sv
->vendor_attributes
[i
].id
;
1376 case STATUS_CHECK
: // Fake "good" SMART status
1381 // Arrive here for all unsupported commands
1387 /////////////////////////////////////////////////////////////////////////////
1389 // Call GetDevicePowerState() if available (Win98/ME/2000/XP/2003)
1390 // returns: 1=active, 0=standby, -1=error
1391 // (This would also work for SCSI drives)
1393 static int get_device_power_state(HANDLE hdevice
)
1395 static HINSTANCE h_kernel_dll
= 0;
1397 static DWORD kernel_dll_pid
= 0;
1399 static BOOL (WINAPI
* GetDevicePowerState_p
)(HANDLE
, BOOL
*) = 0;
1403 if (!GetDevicePowerState_p
1405 || kernel_dll_pid
!= GetCurrentProcessId() // detect fork()
1408 if (h_kernel_dll
== INVALID_HANDLE_VALUE
) {
1412 if (!(h_kernel_dll
= LoadLibraryA("KERNEL32.DLL"))) {
1413 pout("Cannot load KERNEL32.DLL, Error=%ld\n", GetLastError());
1414 h_kernel_dll
= (HINSTANCE
)INVALID_HANDLE_VALUE
;
1418 if (!(GetDevicePowerState_p
= (BOOL (WINAPI
*)(HANDLE
, BOOL
*))
1419 GetProcAddress(h_kernel_dll
, "GetDevicePowerState"))) {
1420 if (con
->reportataioctl
)
1421 pout(" GetDevicePowerState() not found, Error=%ld\n", GetLastError());
1422 FreeLibrary(h_kernel_dll
);
1423 h_kernel_dll
= (HINSTANCE
)INVALID_HANDLE_VALUE
;
1428 kernel_dll_pid
= GetCurrentProcessId();
1432 if (!GetDevicePowerState_p(hdevice
, &state
)) {
1433 long err
= GetLastError();
1434 if (con
->reportataioctl
)
1435 pout(" GetDevicePowerState() failed, Error=%ld\n", err
);
1436 errno
= (err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
1437 // TODO: This may not work as expected on transient errors,
1438 // because smartd interprets -1 as SLEEP mode regardless of errno.
1442 if (con
->reportataioctl
> 1)
1443 pout(" GetDevicePowerState() succeeded, state=%d\n", state
);
1448 /////////////////////////////////////////////////////////////////////////////
1450 // TODO: Put in a struct indexed by fd (or better a C++ object of course ;-)
1451 static HANDLE h_ata_ioctl
= 0;
1452 static const char * ata_def_options
;
1453 static char * ata_cur_options
;
1454 static int ata_driveno
; // Drive number
1455 static char ata_smartver_state
[10]; // SMART_GET_VERSION: 0=unknown, 1=OK, 2=failed
1457 // Print SMARTVSD error message, return errno
1459 static int smartvsd_error()
1461 char path
[MAX_PATH
];
1463 if (!(5 <= (len
= GetSystemDirectoryA(path
, MAX_PATH
)) && len
< MAX_PATH
/2))
1465 // SMARTVSD.VXD present?
1466 strcpy(path
+len
, "\\IOSUBSYS\\SMARTVSD.VXD");
1467 if (!access(path
, 0)) {
1468 // Yes, standard IDE driver used?
1470 if ( (h
= CreateFileA("\\\\.\\ESDI_506",
1471 GENERIC_READ
|GENERIC_WRITE
, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
1472 NULL
, OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
1473 && GetLastError() == ERROR_FILE_NOT_FOUND
) {
1474 pout("Standard IDE driver ESDI_506.PDR not used, or no IDE/ATA drives present.\n");
1478 if (h
!= INVALID_HANDLE_VALUE
) // should not happen
1480 pout("SMART driver SMARTVSD.VXD is installed, but not loaded.\n");
1485 strcpy(path
+len
, "\\SMARTVSD.VXD");
1486 if (!access(path
, 0)) {
1487 // Some Windows versions install SMARTVSD.VXD in SYSTEM directory
1488 // (http://support.microsoft.com/kb/265854/en-us).
1490 pout("SMART driver is not properly installed,\n"
1491 " move SMARTVSD.VXD from \"%s\" to \"%s\\IOSUBSYS\"\n"
1492 " and reboot Windows.\n", path
, path
);
1495 // Some Windows versions do not provide SMARTVSD.VXD
1496 // (http://support.microsoft.com/kb/199886/en-us).
1498 pout("SMARTVSD.VXD is missing in folder \"%s\\IOSUBSYS\".\n", path
);
1505 // Get default ATA device options
1507 static const char * ata_get_def_options()
1509 DWORD ver
= GetVersion();
1510 if ((ver
& 0x80000000) || (ver
& 0xff) < 4) // Win9x/ME
1511 return "s"; // SMART_* only
1512 else if ((ver
& 0xff) == 4) // WinNT4
1513 return "sc"; // SMART_*, SCSI_PASS_THROUGH
1514 else // WinXP, 2003, Vista
1515 return "psai"; // GetDevicePowerState(), SMART_*, ATA_, IDE_PASS_THROUGH
1521 static int ata_open(int drive
, const char * options
, int port
)
1527 // TODO: This version does not allow to open more than 1 ATA devices
1533 win9x
= ((GetVersion() & 0x80000000) != 0);
1535 if (!(0 <= drive
&& drive
<= (win9x
? 7 : 9))) {
1540 // path depends on Windows Version
1542 // Use patched "smartvse.vxd" for drives 4-7, see INSTALL file for details
1543 strcpy(devpath
, (drive
<= 3 ? "\\\\.\\SMARTVSD" : "\\\\.\\SMARTVSE"));
1545 snprintf(devpath
, sizeof(devpath
)-1, "\\\\.\\PhysicalDrive%d", drive
);
1548 if ((h_ata_ioctl
= CreateFileA(devpath
,
1549 GENERIC_READ
|GENERIC_WRITE
, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
1550 NULL
, OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
) {
1551 long err
= GetLastError();
1552 pout("Cannot open device %s, Error=%ld\n", devpath
, err
);
1553 if (err
== ERROR_FILE_NOT_FOUND
)
1554 errno
= (win9x
&& drive
<= 3 ? smartvsd_error() : ENOENT
);
1555 else if (err
== ERROR_ACCESS_DENIED
) {
1557 pout("Administrator rights are necessary to access physical drives.\n");
1566 if (con
->reportataioctl
> 1)
1567 pout("%s: successfully opened\n", devpath
);
1571 // Set default options according to Windows version
1572 if (!ata_def_options
)
1573 ata_def_options
= ata_get_def_options();
1574 options
= (port
< 0 ? ata_def_options
: "s3"); // RAID: SMART_* and SCSI_MINIPORT
1576 ata_cur_options
= strdup(options
);
1578 // NT4/2000/XP: SMART_GET_VERSION may spin up disk, so delay until first real SMART_* call
1579 ata_driveno
= drive
;
1580 if (!win9x
&& port
< 0)
1583 // Win9X/ME: Get drive map
1584 // RAID: Get port map
1585 unsigned long portmap
= 0;
1586 devmap
= smart_get_version(h_ata_ioctl
, (port
>= 0 ? &portmap
: 0));
1588 if (!is_permissive()) {
1595 ata_smartver_state
[drive
] = 1;
1598 // 3ware RAID: update devicemap first
1599 if (!update_3ware_devicemap_ioctl(h_ata_ioctl
)) {
1600 unsigned long portmap1
= 0;
1601 if (smart_get_version(h_ata_ioctl
, &portmap1
) >= 0)
1604 // Check port existence
1605 if (!(portmap
& (1L << port
))) {
1606 pout("%s: Port %d is empty or does not exist\n", devpath
, port
);
1607 if (!is_permissive()) {
1613 // Encode port into pseudo fd
1614 return (ATARAID_FDOFFSET
| port
);
1617 // Win9x/ME: Check device presence & type
1618 if (((devmap
>> (drive
& 0x3)) & 0x11) != 0x01) {
1619 unsigned char atapi
= (devmap
>> (drive
& 0x3)) & 0x10;
1620 pout("%s: Drive %d %s (IDEDeviceMap=0x%02x).\n", devpath
,
1621 drive
, (atapi
?"is an ATAPI device":"does not exist"), devmap
);
1622 // Win9x drive existence check may not work as expected
1623 // The atapi.sys driver incorrectly fills in the bIDEDeviceMap with 0x01
1624 // (The related KB Article Q196120 is no longer available)
1625 if (!is_permissive()) {
1627 errno
= (atapi
? ENOSYS
: ENOENT
);
1631 // Use drive number as fd for ioctl
1632 return (drive
& 0x3);
1636 static void ata_close(int fd
)
1639 CloseHandle(h_ata_ioctl
);
1641 if (ata_cur_options
) {
1642 free(ata_cur_options
);
1643 ata_cur_options
= 0;
1648 // Scan for ATA drives, fill bitmask of drives present, return #drives
1650 static int ata_scan(unsigned long * drives
, int * rdriveno
, unsigned long * rdrives
)
1652 int win9x
= ((GetVersion() & 0x80000000) != 0);
1655 for (i
= 0; i
<= 9; i
++) {
1657 GETVERSIONOUTPARAMS vers
;
1658 const GETVERSIONINPARAMS_EX
& vers_ex
= (const GETVERSIONINPARAMS_EX
&)vers
;
1662 strcpy(devpath
, "\\\\.\\SMARTVSD");
1664 snprintf(devpath
, sizeof(devpath
)-1, "\\\\.\\PhysicalDrive%d", i
);
1667 if ((h
= CreateFileA(devpath
,
1668 GENERIC_READ
|GENERIC_WRITE
, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
1669 NULL
, OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
) {
1670 if (con
->reportataioctl
> 1)
1671 pout(" %s: Open failed, Error=%ld\n", devpath
, GetLastError());
1673 break; // SMARTVSD.VXD missing or no ATA devices
1674 continue; // Disk not found or access denied (break;?)
1678 memset(&vers
, 0, sizeof(vers
));
1679 if (!DeviceIoControl(h
, SMART_GET_VERSION
,
1680 NULL
, 0, &vers
, sizeof(vers
), &num_out
, NULL
)) {
1681 if (con
->reportataioctl
)
1682 pout(" %s: SMART_GET_VERSION failed, Error=%ld\n", devpath
, GetLastError());
1685 break; // Should not happen
1686 continue; // Non ATA disk or no SMART ioctl support (possibly SCSI disk)
1690 if (con
->reportataioctl
) {
1691 pout(" %s: SMART_GET_VERSION (%ld bytes):\n"
1692 " Vers = %d.%d, Caps = 0x%lx, DeviceMap = 0x%02x\n",
1693 devpath
, num_out
, vers
.bVersion
, vers
.bRevision
,
1694 vers
.fCapabilities
, vers
.bIDEDeviceMap
);
1695 if (vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
)
1696 pout(" Identifier = %04x(3WARE), ControllerId=%u, DeviceMapEx = 0x%08lx\n",
1697 vers_ex
.wIdentifier
, vers_ex
.wControllerId
, vers_ex
.dwDeviceMapEx
);
1701 // Check ATA device presence, remove ATAPI devices
1702 drives
[0] = (vers
.bIDEDeviceMap
& 0xf) & ~((vers
.bIDEDeviceMap
>> 4) & 0xf);
1703 cnt
= (drives
[0]&1) + ((drives
[0]>>1)&1) + ((drives
[0]>>2)&1) + ((drives
[0]>>3)&1);
1707 if (vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
) {
1708 // Skip if more than 2 controllers or logical drive from this controller already seen
1709 if (vers_ex
.wControllerId
>= 2 || rdriveno
[vers_ex
.wControllerId
] >= 0)
1711 assert(rdrives
[vers_ex
.wControllerId
] == 0);
1712 // Count physical drives
1714 for (int pi
= 0; pi
< 32; pi
++) {
1715 if (vers_ex
.dwDeviceMapEx
& (1L << pi
))
1719 continue; // Should not happen
1720 rdrives
[vers_ex
.wControllerId
] = vers_ex
.dwDeviceMapEx
;
1721 rdriveno
[vers_ex
.wControllerId
] = i
;
1725 // ATA drive exists and driver supports SMART ioctl
1726 drives
[0] |= (1L << i
);
1734 /////////////////////////////////////////////////////////////////////////////
1736 // Interface to ATA devices. See os_linux.c
1737 int ata_command_interface(int fd
, smart_command_set command
, int select
, char * data
)
1739 if (fd
== TW_CLI_FDOFFSET
) // Parse tw_cli output
1740 return tw_cli_command_interface(command
, select
, data
);
1743 if ((fd
& ~0x1f) == ATARAID_FDOFFSET
) {
1744 // RAID Port encoded into pseudo fd
1749 if (!(0 <= fd
&& fd
<= 3)) {
1754 // CMD,CYL default to SMART, changed by P?IDENTIFY and CHECK_POWER_MODE
1755 IDEREGS regs
; memset(®s
, 0, sizeof(regs
));
1756 regs
.bCommandReg
= ATA_SMART_CMD
;
1757 regs
.bCylHighReg
= SMART_CYL_HI
; regs
.bCylLowReg
= SMART_CYL_LOW
;
1760 // Try all IOCTLS by default: SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH
1761 const char * valid_options
= "saic";
1764 case CHECK_POWER_MODE
:
1765 // Not a SMART command, needs IDE register return
1766 regs
.bCommandReg
= ATA_CHECK_POWER_MODE
;
1767 regs
.bCylLowReg
= regs
.bCylHighReg
= 0;
1768 valid_options
= "pai3"; // Try GetDevicePowerState() first, ATA/IDE_PASS_THROUGH may spin up disk
1769 // Note: returns SectorCountReg in data[0]
1772 regs
.bFeaturesReg
= ATA_SMART_READ_VALUES
;
1773 regs
.bSectorNumberReg
= regs
.bSectorCountReg
= 1;
1776 case READ_THRESHOLDS
:
1777 regs
.bFeaturesReg
= ATA_SMART_READ_THRESHOLDS
;
1778 regs
.bSectorNumberReg
= regs
.bSectorCountReg
= 1;
1782 regs
.bFeaturesReg
= ATA_SMART_READ_LOG_SECTOR
;
1783 regs
.bSectorNumberReg
= select
;
1784 regs
.bSectorCountReg
= 1;
1785 valid_options
= "saic3";
1786 // Note: SMART_RCV_DRIVE_DATA supports this only on Win9x/ME
1790 regs
.bFeaturesReg
= ATA_SMART_WRITE_LOG_SECTOR
;
1791 regs
.bSectorNumberReg
= select
;
1792 regs
.bSectorCountReg
= 1;
1793 valid_options
= "a"; // ATA_PASS_THROUGH only, others don't support DATA_OUT
1794 datasize
= -512; // DATA_OUT!
1797 // Note: WinNT4/2000/XP return identify data cached during boot
1798 // (true for SMART_RCV_DRIVE_DATA and IOCTL_IDE_PASS_THROUGH)
1799 regs
.bCommandReg
= ATA_IDENTIFY_DEVICE
;
1800 regs
.bCylLowReg
= regs
.bCylHighReg
= 0;
1801 regs
.bSectorCountReg
= 1;
1805 regs
.bCommandReg
= ATA_IDENTIFY_PACKET_DEVICE
;
1806 regs
.bCylLowReg
= regs
.bCylHighReg
= 0;
1807 regs
.bSectorCountReg
= 1;
1811 regs
.bFeaturesReg
= ATA_SMART_ENABLE
;
1812 regs
.bSectorNumberReg
= 1;
1815 regs
.bFeaturesReg
= ATA_SMART_DISABLE
;
1816 regs
.bSectorNumberReg
= 1;
1819 valid_options
= "sai"; // Needs IDE register return
1821 regs
.bFeaturesReg
= ATA_SMART_STATUS
;
1824 regs
.bFeaturesReg
= ATA_SMART_AUTO_OFFLINE
;
1825 regs
.bSectorCountReg
= select
; // YET NOTE - THIS IS A NON-DATA COMMAND!!
1828 regs
.bFeaturesReg
= ATA_SMART_AUTOSAVE
;
1829 regs
.bSectorCountReg
= select
; // YET NOTE - THIS IS A NON-DATA COMMAND!!
1831 case IMMEDIATE_OFFLINE
:
1832 regs
.bFeaturesReg
= ATA_SMART_IMMEDIATE_OFFLINE
;
1833 regs
.bSectorNumberReg
= select
;
1834 valid_options
= "saic3";
1835 // Note: SMART_SEND_DRIVE_COMMAND supports ABORT_SELF_TEST only on Win9x/ME
1838 pout("Unrecognized command %d in win32_ata_command_interface()\n"
1839 "Please contact " PACKAGE_BUGREPORT
"\n", command
);
1844 // Try all valid ioctls in the order specified in dev_ioctls;
1845 bool powered_up
= false;
1846 for (int i
= 0; ; i
++) {
1847 char opt
= ata_cur_options
[i
];
1850 if (command
== CHECK_POWER_MODE
&& powered_up
) {
1851 // Power up reported by GetDevicePowerState() and no ioctl available
1852 // to detect the actual mode of the drive => simulate ATA result ACTIVE/IDLE.
1853 regs
.bSectorCountReg
= 0xff;
1860 if (!strchr(valid_options
, opt
))
1861 // Invalid for this command
1865 assert(datasize
== 0 || datasize
== 512 || (opt
== 'a' && datasize
== -512));
1870 // call SMART_GET_VERSION once for each drive
1871 assert(0 <= ata_driveno
&& ata_driveno
< sizeof(ata_smartver_state
));
1872 if (ata_smartver_state
[ata_driveno
] > 1) {
1873 rc
= -1; errno
= ENOSYS
;
1876 if (!ata_smartver_state
[ata_driveno
]) {
1878 if (smart_get_version(h_ata_ioctl
) < 0) {
1879 if (!con
->permissive
) {
1880 pout("ATA/SATA driver is possibly a SCSI class driver not supporting SMART.\n");
1881 pout("If this is a SCSI disk, try \"scsi<adapter><id>\".\n");
1882 ata_smartver_state
[ata_driveno
] = 2;
1883 rc
= -1; errno
= ENOSYS
;
1888 ata_smartver_state
[ata_driveno
] = 1;
1890 rc
= smart_ioctl(h_ata_ioctl
, fd
, ®s
, data
, datasize
, port
);
1893 rc
= ata_pass_through_ioctl(h_ata_ioctl
, ®s
, data
, datasize
);
1896 rc
= ide_pass_through_ioctl(h_ata_ioctl
, ®s
, data
, datasize
);
1899 rc
= ata_via_scsi_pass_through_ioctl(h_ata_ioctl
, ®s
, data
, datasize
);
1902 rc
= ata_via_3ware_miniport_ioctl(h_ata_ioctl
, ®s
, data
, datasize
, port
);
1905 assert(command
== CHECK_POWER_MODE
&& datasize
== 0);
1906 rc
= get_device_power_state(h_ata_ioctl
);
1908 // Power down reported by GetDevicePowerState(), using a passthrough ioctl would
1909 // spin up the drive => simulate ATA result STANDBY.
1910 regs
.bSectorCountReg
= 0x00;
1913 // Power up reported by GetDevicePowerState(), but this reflects the actual mode
1914 // only if it is selected by the device driver => try a passthrough ioctl to get the
1915 // actual mode, if none available simulate ACTIVE/IDLE.
1917 errno
= ENOSYS
; rc
= -1;
1923 // Working ioctl found
1926 if (errno
!= ENOSYS
)
1927 // Abort on I/O error
1930 // CAUTION: *_ioctl() MUST NOT change "regs" Parameter in the ENOSYS case
1934 case CHECK_POWER_MODE
:
1935 // Return power mode from SectorCountReg in data[0]
1936 data
[0] = regs
.bSectorCountReg
;
1940 // Cyl low and Cyl high unchanged means "Good SMART status"
1941 if (regs
.bCylHighReg
== SMART_CYL_HI
&& regs
.bCylLowReg
== SMART_CYL_LOW
)
1944 // These values mean "Bad SMART status"
1945 if (regs
.bCylHighReg
== 0x2c && regs
.bCylLowReg
== 0xf4)
1948 // We haven't gotten output that makes sense; print out some debugging info
1949 syserror("Error SMART Status command failed");
1950 pout("Please get assistance from %s\n", PACKAGE_HOMEPAGE
);
1951 print_ide_regs(®s
, 1);
1962 #ifndef HAVE_ATA_IDENTIFY_IS_CACHED
1963 #error define of HAVE_ATA_IDENTIFY_IS_CACHED missing in config.h
1966 // Return true if OS caches the ATA identify sector
1967 int ata_identify_is_cached(int fd
)
1969 // Not RAID and WinNT4/2000/XP => true, RAID or Win9x/ME => false
1970 return (!(fd
& 0xff00) && (GetVersion() & 0x80000000) == 0);
1974 // Print not implemeted warning once
1975 static void pr_not_impl(const char * what
, int * warned
)
1980 "#######################################################################\n"
1982 "NOT IMPLEMENTED under Win32.\n"
1983 "Please contact " PACKAGE_BUGREPORT
" if\n"
1984 "you want to help in porting smartmontools to Win32.\n"
1985 "#######################################################################\n"
1991 // Interface to ATA devices behind 3ware escalade RAID controller cards. See os_linux.c
1992 int escalade_command_interface(int fd
, int disknum
, int escalade_type
, smart_command_set command
, int select
, char *data
)
1994 static int warned
= 0;
1995 ARGUSED(fd
); ARGUSED(escalade_type
); ARGUSED(command
); ARGUSED(select
); ARGUSED(data
);
1997 pout("Option '-d 3ware,%d' does not work on Windows.\n"
1998 "Controller port can be specified in the device name: '/dev/hd%c,%d'.\n\n",
1999 disknum
, 'a'+ata_driveno
, disknum
);
2006 // Interface to ATA devices behind Marvell chip-set based controllers. See os_linux.c
2007 int marvell_command_interface(int fd
, smart_command_set command
, int select
, char * data
)
2009 static int warned
= 0;
2010 ARGUSED(fd
); ARGUSED(command
); ARGUSED(select
); ARGUSED(data
);
2011 pr_not_impl("Marvell chip-set command routine marvell_command_interface()", &warned
);
2016 // Interface to ATA devices behind HighPoint Raid controllers. See os_linux.c
2017 int highpoint_command_interface(int fd
, smart_command_set command
, int select
, char * data
)
2019 static int warned
= 0;
2020 ARGUSED(fd
); ARGUSED(command
); ARGUSED(select
); ARGUSED(data
);
2021 pr_not_impl("HighPoint raid controller command routine highpoint_command_interface()", &warned
);
2027 /////////////////////////////////////////////////////////////////////////////
2028 // ASPI Interface (for SCSI devices)
2029 /////////////////////////////////////////////////////////////////////////////
2033 #define ASPI_SENSE_SIZE 18
2035 // ASPI SCSI Request block header
2038 unsigned char cmd
; // 00: Command code
2039 unsigned char status
; // 01: ASPI status
2040 unsigned char adapter
; // 02: Host adapter number
2041 unsigned char flags
; // 03: Request flags
2042 unsigned char reserved
[4]; // 04: 0
2045 // SRB for host adapter inquiry
2048 ASPI_SRB_HEAD h
; // 00: Header
2049 unsigned char adapters
; // 08: Number of adapters
2050 unsigned char target_id
; // 09: Target ID ?
2051 char manager_id
[16]; // 10: SCSI manager ID
2052 char adapter_id
[16]; // 26: Host adapter ID
2053 unsigned char parameters
[16]; // 42: Host adapter unique parmameters
2056 // SRB for get device type
2059 ASPI_SRB_HEAD h
; // 00: Header
2060 unsigned char target_id
; // 08: Target ID
2061 unsigned char lun
; // 09: LUN
2062 unsigned char devtype
; // 10: Device type
2063 unsigned char reserved
; // 11: Reserved
2069 ASPI_SRB_HEAD h
; // 00: Header
2070 unsigned char target_id
; // 08: Target ID
2071 unsigned char lun
; // 09: LUN
2072 unsigned char reserved
[2]; // 10: Reserved
2073 unsigned long data_size
; // 12: Data alloc. lenght
2074 void * data_addr
; // 16: Data buffer pointer
2075 unsigned char sense_size
; // 20: Sense alloc. length
2076 unsigned char cdb_size
; // 21: CDB length
2077 unsigned char host_status
; // 22: Host status
2078 unsigned char target_status
; // 23: Target status
2079 void * event_handle
; // 24: Event handle
2080 unsigned char workspace
[20]; // 28: ASPI workspace
2081 unsigned char cdb
[16+ASPI_SENSE_SIZE
];
2084 // Macro to retrieve start of sense information
2085 #define ASPI_SRB_SENSE(srb,cdbsz) ((srb)->cdb + 16)
2090 ASPI_SRB_HEAD h
; // Common header
2091 ASPI_SRB_INQUIRY q
; // Inquiry
2092 ASPI_SRB_DEVTYPE t
; // Device type
2093 ASPI_SRB_IO i
; // I/O
2099 #define ASPI_CMD_ADAPTER_INQUIRE 0x00
2100 #define ASPI_CMD_GET_DEVICE_TYPE 0x01
2101 #define ASPI_CMD_EXECUTE_IO 0x02
2102 #define ASPI_CMD_ABORT_IO 0x03
2105 #define ASPI_REQFLAG_DIR_TO_HOST 0x08
2106 #define ASPI_REQFLAG_DIR_TO_TARGET 0x10
2107 #define ASPI_REQFLAG_DIR_NO_XFER 0x18
2108 #define ASPI_REQFLAG_EVENT_NOTIFY 0x40
2111 #define ASPI_STATUS_IN_PROGRESS 0x00
2112 #define ASPI_STATUS_NO_ERROR 0x01
2113 #define ASPI_STATUS_ABORTED 0x02
2114 #define ASPI_STATUS_ABORT_ERR 0x03
2115 #define ASPI_STATUS_ERROR 0x04
2116 #define ASPI_STATUS_INVALID_COMMAND 0x80
2117 #define ASPI_STATUS_INVALID_ADAPTER 0x81
2118 #define ASPI_STATUS_INVALID_TARGET 0x82
2119 #define ASPI_STATUS_NO_ADAPTERS 0xE8
2121 // Adapter (host) status
2122 #define ASPI_HSTATUS_NO_ERROR 0x00
2123 #define ASPI_HSTATUS_SELECTION_TIMEOUT 0x11
2124 #define ASPI_HSTATUS_DATA_OVERRUN 0x12
2125 #define ASPI_HSTATUS_BUS_FREE 0x13
2126 #define ASPI_HSTATUS_BUS_PHASE_ERROR 0x14
2127 #define ASPI_HSTATUS_BAD_SGLIST 0x1A
2130 #define ASPI_TSTATUS_NO_ERROR 0x00
2131 #define ASPI_TSTATUS_CHECK_CONDITION 0x02
2132 #define ASPI_TSTATUS_BUSY 0x08
2133 #define ASPI_TSTATUS_RESERV_CONFLICT 0x18
2136 static HINSTANCE h_aspi_dll
; // DLL handle
2137 static UINT (* aspi_entry
)(ASPI_SRB
* srb
); // ASPI entrypoint
2138 static unsigned num_aspi_adapters
;
2141 // h_aspi_dll+aspi_entry is not inherited by Cygwin's fork()
2142 static DWORD aspi_dll_pid
; // PID of DLL owner to detect fork()
2143 #define aspi_entry_valid() (aspi_entry && (aspi_dll_pid == GetCurrentProcessId()))
2145 #define aspi_entry_valid() (!!aspi_entry)
2149 static int aspi_call(ASPI_SRB
* srb
)
2154 while (((volatile ASPI_SRB
*)srb
)->h
.status
== ASPI_STATUS_IN_PROGRESS
) {
2155 if (++i
> 100/*10sek*/) {
2156 pout("ASPI Adapter %u: Timed out\n", srb
->h
.adapter
);
2158 h_aspi_dll
= (HINSTANCE
)INVALID_HANDLE_VALUE
;
2162 if (con
->reportscsiioctl
> 1)
2163 pout("ASPI Adapter %u: Waiting (%d) ...\n", srb
->h
.adapter
, i
);
2170 // Get ASPI entrypoint from wnaspi32.dll
2172 static FARPROC
aspi_get_address(const char * name
, int verbose
)
2175 assert(h_aspi_dll
&& h_aspi_dll
!= INVALID_HANDLE_VALUE
);
2177 if (!(addr
= GetProcAddress(h_aspi_dll
, name
))) {
2179 pout("Missing %s() in WNASPI32.DLL\n", name
);
2181 FreeLibrary(h_aspi_dll
);
2182 h_aspi_dll
= (HINSTANCE
)INVALID_HANDLE_VALUE
;
2190 static int aspi_open_dll(int verbose
)
2192 UINT (*aspi_info
)(void);
2195 assert(!aspi_entry_valid());
2197 // Check structure layout
2198 assert(sizeof(ASPI_SRB_HEAD
) == 8);
2199 assert(sizeof(ASPI_SRB_INQUIRY
) == 58);
2200 assert(sizeof(ASPI_SRB_DEVTYPE
) == 12);
2201 assert(sizeof(ASPI_SRB_IO
) == 64+ASPI_SENSE_SIZE
);
2202 assert(offsetof(ASPI_SRB
,h
.cmd
) == 0);
2203 assert(offsetof(ASPI_SRB
,h
.flags
) == 3);
2204 assert(offsetof(ASPI_SRB_IO
,lun
) == 9);
2205 assert(offsetof(ASPI_SRB_IO
,data_addr
) == 16);
2206 assert(offsetof(ASPI_SRB_IO
,workspace
) == 28);
2207 assert(offsetof(ASPI_SRB_IO
,cdb
) == 48);
2209 if (h_aspi_dll
== INVALID_HANDLE_VALUE
) {
2216 if (!(h_aspi_dll
= LoadLibraryA("WNASPI32.DLL"))) {
2218 pout("Cannot load WNASPI32.DLL, Error=%ld\n", GetLastError());
2219 h_aspi_dll
= (HINSTANCE
)INVALID_HANDLE_VALUE
;
2223 if (con
->reportscsiioctl
> 1) {
2224 // Print full path of WNASPI32.DLL
2225 char path
[MAX_PATH
];
2226 if (!GetModuleFileName(h_aspi_dll
, path
, sizeof(path
)))
2227 strcpy(path
, "*unknown*");
2228 pout("Using ASPI interface \"%s\"\n", path
);
2231 // Get ASPI entrypoints
2232 if (!(aspi_info
= (UINT (*)(void))aspi_get_address("GetASPI32SupportInfo", verbose
)))
2234 if (!(aspi_entry
= (UINT (*)(ASPI_SRB
*))aspi_get_address("SendASPI32Command", verbose
)))
2237 // Init ASPI manager and get number of adapters
2238 info
= (aspi_info
)();
2239 if (con
->reportscsiioctl
> 1)
2240 pout("GetASPI32SupportInfo() returns 0x%04x\n", info
);
2241 rc
= (info
>> 8) & 0xff;
2242 if (rc
== ASPI_STATUS_NO_ADAPTERS
) {
2243 num_aspi_adapters
= 0;
2245 else if (rc
== ASPI_STATUS_NO_ERROR
) {
2246 num_aspi_adapters
= info
& 0xff;
2250 pout("Got strange 0x%04x from GetASPI32SupportInfo()\n", info
);
2252 FreeLibrary(h_aspi_dll
);
2253 h_aspi_dll
= (HINSTANCE
)INVALID_HANDLE_VALUE
;
2258 if (con
->reportscsiioctl
)
2259 pout("%u ASPI Adapter%s detected\n",num_aspi_adapters
, (num_aspi_adapters
!=1?"s":""));
2262 // save PID to detect fork() in aspi_entry_valid()
2263 aspi_dll_pid
= GetCurrentProcessId();
2265 assert(aspi_entry_valid());
2270 static int aspi_io_call(ASPI_SRB
* srb
, unsigned timeout
)
2274 if (!(event
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
))) {
2275 pout("CreateEvent(): Error=%ld\n", GetLastError()); return -EIO
;
2277 srb
->i
.event_handle
= event
;
2278 srb
->h
.flags
|= ASPI_REQFLAG_EVENT_NOTIFY
;
2279 // Start ASPI request
2281 if (((volatile ASPI_SRB
*)srb
)->h
.status
== ASPI_STATUS_IN_PROGRESS
) {
2283 DWORD rc
= WaitForSingleObject(event
, timeout
*1000L);
2284 if (rc
!= WAIT_OBJECT_0
) {
2285 if (rc
== WAIT_TIMEOUT
) {
2286 pout("ASPI Adapter %u, ID %u: Timed out after %u seconds\n",
2287 srb
->h
.adapter
, srb
->i
.target_id
, timeout
);
2290 pout("WaitForSingleObject(%lx) = 0x%lx,%ld, Error=%ld\n",
2291 (unsigned long)event
, rc
, rc
, GetLastError());
2293 // TODO: ASPI_ABORT_IO command
2295 h_aspi_dll
= (HINSTANCE
)INVALID_HANDLE_VALUE
;
2304 static int aspi_open(unsigned adapter
, unsigned id
)
2307 if (!(adapter
<= 9 && id
< 16)) {
2312 if (!aspi_entry_valid()) {
2313 if (aspi_open_dll(1/*verbose*/))
2318 if (adapter
>= num_aspi_adapters
) {
2319 pout("ASPI Adapter %u does not exist (%u Adapter%s detected).\n",
2320 adapter
, num_aspi_adapters
, (num_aspi_adapters
!=1?"s":""));
2321 if (!is_permissive()) {
2328 memset(&srb
, 0, sizeof(srb
));
2329 srb
.h
.cmd
= ASPI_CMD_GET_DEVICE_TYPE
;
2330 srb
.h
.adapter
= adapter
; srb
.i
.target_id
= id
;
2331 if (aspi_call(&srb
)) {
2335 if (srb
.h
.status
!= ASPI_STATUS_NO_ERROR
) {
2336 pout("ASPI Adapter %u, ID %u: No such device (Status=0x%02x)\n", adapter
, id
, srb
.h
.status
);
2337 if (!is_permissive()) {
2338 errno
= (srb
.h
.status
== ASPI_STATUS_INVALID_TARGET
? ENOENT
: EIO
);
2342 else if (con
->reportscsiioctl
)
2343 pout("ASPI Adapter %u, ID %u: Device Type=0x%02x\n", adapter
, id
, srb
.t
.devtype
);
2345 return (ASPI_FDOFFSET
| ((adapter
& 0xf)<<4) | (id
& 0xf));
2349 static void aspi_close(int fd
)
2351 // No FreeLibrary(h_aspi_dll) to prevent problems with ASPI threads
2356 // Scan for SCSI drives, fill bitmask [adapter:0-9][id:0-7] of drives present,
2359 static int aspi_scan(unsigned long * drives
)
2364 if (!aspi_entry_valid()) {
2365 if (aspi_open_dll(con
->reportscsiioctl
/*default is quiet*/))
2369 for (ad
= 0; ad
< num_aspi_adapters
; ad
++) {
2370 ASPI_SRB srb
; unsigned id
;
2373 if (con
->reportscsiioctl
)
2374 pout(" ASPI Adapter %u: Ignored\n", ad
);
2379 memset(&srb
, 0, sizeof(srb
));
2380 srb
.h
.cmd
= ASPI_CMD_ADAPTER_INQUIRE
;
2382 if (aspi_call(&srb
))
2385 if (srb
.h
.status
!= ASPI_STATUS_NO_ERROR
) {
2386 if (con
->reportscsiioctl
)
2387 pout(" ASPI Adapter %u: Status=0x%02x\n", ad
, srb
.h
.status
);
2391 if (con
->reportscsiioctl
) {
2393 for (i
= 1; i
< 16 && srb
.q
.adapter_id
[i
]; i
++)
2394 if (!(' ' <= srb
.q
.adapter_id
[i
] && srb
.q
.adapter_id
[i
] <= '~'))
2395 srb
.q
.adapter_id
[i
] = '?';
2396 pout(" ASPI Adapter %u (\"%.16s\"):\n", ad
, srb
.q
.adapter_id
);
2399 bool ignore
= !strnicmp(srb
.q
.adapter_id
, "3ware", 5);
2401 for (id
= 0; id
<= 7; id
++) {
2403 memset(&srb
, 0, sizeof(srb
));
2404 srb
.h
.cmd
= ASPI_CMD_GET_DEVICE_TYPE
;
2405 srb
.h
.adapter
= ad
; srb
.i
.target_id
= id
;
2406 if (aspi_call(&srb
))
2408 if (srb
.h
.status
!= ASPI_STATUS_NO_ERROR
) {
2409 if (con
->reportscsiioctl
> 1)
2410 pout(" ID %u: No such device (Status=0x%02x)\n", id
, srb
.h
.status
);
2414 if (!ignore
&& srb
.t
.devtype
== 0x00/*HDD*/) {
2415 if (con
->reportscsiioctl
)
2416 pout(" ID %u: Device Type=0x%02x\n", id
, srb
.t
.devtype
);
2417 drives
[ad
>> 2] |= (1L << (((ad
& 0x3) << 3) + id
));
2420 else if (con
->reportscsiioctl
)
2421 pout(" ID %u: Device Type=0x%02x (ignored)\n", id
, srb
.t
.devtype
);
2428 /////////////////////////////////////////////////////////////////////////////
2430 // Interface to ASPI SCSI devices. See scsicmds.h and os_linux.c
2431 static int do_aspi_cmnd_io(int fd
, struct scsi_cmnd_io
* iop
, int report
)
2435 if (!aspi_entry_valid())
2437 if (!((fd
& ~0xff) == ASPI_FDOFFSET
))
2440 if (!(iop
->cmnd_len
== 6 || iop
->cmnd_len
== 10 || iop
->cmnd_len
== 12 || iop
->cmnd_len
== 16)) {
2441 pout("do_aspi_cmnd_io: bad CDB length\n");
2448 const unsigned char * ucp
= iop
->cmnd
;
2451 const int sz
= (int)sizeof(buff
);
2453 np
= scsi_get_opcode_name(ucp
[0]);
2454 j
= snprintf(buff
, sz
, " [%s: ", np
? np
: "<unknown opcode>");
2455 for (k
= 0; k
< (int)iop
->cmnd_len
; ++k
)
2456 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "%02x ", ucp
[k
]);
2458 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
2459 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
2461 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n Outgoing "
2462 "data, len=%d%s:\n", (int)iop
->dxfer_len
,
2463 (trunc
? " [only first 256 bytes shown]" : ""));
2464 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
2467 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n");
2471 memset(&srb
, 0, sizeof(srb
));
2472 srb
.h
.cmd
= ASPI_CMD_EXECUTE_IO
;
2473 srb
.h
.adapter
= ((fd
>> 4) & 0xf);
2474 srb
.i
.target_id
= (fd
& 0xf);
2476 srb
.i
.sense_size
= ASPI_SENSE_SIZE
;
2477 srb
.i
.cdb_size
= iop
->cmnd_len
;
2478 memcpy(srb
.i
.cdb
, iop
->cmnd
, iop
->cmnd_len
);
2480 switch (iop
->dxfer_dir
) {
2482 srb
.h
.flags
= ASPI_REQFLAG_DIR_NO_XFER
;
2484 case DXFER_FROM_DEVICE
:
2485 srb
.h
.flags
= ASPI_REQFLAG_DIR_TO_HOST
;
2486 srb
.i
.data_size
= iop
->dxfer_len
;
2487 srb
.i
.data_addr
= iop
->dxferp
;
2489 case DXFER_TO_DEVICE
:
2490 srb
.h
.flags
= ASPI_REQFLAG_DIR_TO_TARGET
;
2491 srb
.i
.data_size
= iop
->dxfer_len
;
2492 srb
.i
.data_addr
= iop
->dxferp
;
2495 pout("do_aspi_cmnd_io: bad dxfer_dir\n");
2499 iop
->resp_sense_len
= 0;
2500 iop
->scsi_status
= 0;
2503 if (aspi_io_call(&srb
, (iop
->timeout
? iop
->timeout
: 60))) {
2508 if (srb
.h
.status
!= ASPI_STATUS_NO_ERROR
) {
2509 if ( srb
.h
.status
== ASPI_STATUS_ERROR
2510 && srb
.i
.host_status
== ASPI_HSTATUS_NO_ERROR
2511 && srb
.i
.target_status
== ASPI_TSTATUS_CHECK_CONDITION
) {
2513 const unsigned char * sense
= ASPI_SRB_SENSE(&srb
.i
, iop
->cmnd_len
);
2514 int len
= (ASPI_SENSE_SIZE
< iop
->max_sense_len
? ASPI_SENSE_SIZE
: iop
->max_sense_len
);
2515 iop
->scsi_status
= SCSI_STATUS_CHECK_CONDITION
;
2516 if (len
> 0 && iop
->sensep
) {
2517 memcpy(iop
->sensep
, sense
, len
);
2518 iop
->resp_sense_len
= len
;
2520 pout(" >>> Sense buffer, len=%d:\n", (int)len
);
2521 dStrHex(iop
->sensep
, len
, 1);
2525 pout(" sense_key=%x asc=%x ascq=%x\n",
2526 sense
[2] & 0xf, sense
[12], sense
[13]);
2532 pout(" ASPI call failed, (0x%02x,0x%02x,0x%02x)\n", srb
.h
.status
, srb
.i
.host_status
, srb
.i
.target_status
);
2540 if (iop
->dxfer_dir
== DXFER_FROM_DEVICE
&& report
> 1) {
2541 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
2542 pout(" Incoming data, len=%d%s:\n", (int)iop
->dxfer_len
,
2543 (trunc
? " [only first 256 bytes shown]" : ""));
2544 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
2551 /////////////////////////////////////////////////////////////////////////////
2552 // SPT Interface (for SCSI devices and ATA devices behind SATLs)
2553 // Only supported in NT and later
2554 /////////////////////////////////////////////////////////////////////////////
2556 #define SPT_MAXDEV 64
2558 struct spt_dev_info
{
2560 int pd_num
; // physical drive number
2561 int tape_num
; // tape number ('\\.\TAPE<n>')
2562 int sub_addr
; // addressing disks within a RAID, for example
2565 // Private table of open devices: guaranteed zero on startup since
2566 // part of static data.
2567 static struct spt_dev_info
* spt_dev_arr
[SPT_MAXDEV
];
2570 static int spt_open(int pd_num
, int tape_num
, int sub_addr
)
2573 struct spt_dev_info
* sdip
;
2577 for (k
= 0; k
< SPT_MAXDEV
; k
++)
2578 if (! spt_dev_arr
[k
])
2581 // If no free entry found, return error. We have max allowed number
2582 // of "file descriptors" already allocated.
2583 if (k
== SPT_MAXDEV
) {
2584 if (con
->reportscsiioctl
)
2585 pout("spt_open: too many open file descriptors (%d)\n",
2590 sdip
= (struct spt_dev_info
*)malloc(sizeof(struct spt_dev_info
));
2595 spt_dev_arr
[k
] = sdip
;
2596 sdip
->pd_num
= pd_num
;
2597 sdip
->tape_num
= tape_num
;
2598 sdip
->sub_addr
= sub_addr
;
2600 b
[sizeof(b
) - 1] = '\0';
2602 snprintf(b
, sizeof(b
) - 1, "\\\\.\\PhysicalDrive%d", pd_num
);
2603 else if (tape_num
>= 0)
2604 snprintf(b
, sizeof(b
) - 1, "\\\\.\\TAPE%d", tape_num
);
2606 if (con
->reportscsiioctl
)
2607 pout("spt_open: bad parameters\n");
2613 if ((h
= CreateFileA(b
, GENERIC_READ
|GENERIC_WRITE
,
2614 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
,
2615 OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
) {
2616 if (con
->reportscsiioctl
)
2617 pout(" %s: Open failed, Error=%ld\n", b
, GetLastError());
2621 sdip
->h_spt_ioctl
= h
;
2622 return k
+ SPT_FDOFFSET
;
2625 spt_dev_arr
[k
] = NULL
;
2631 static void spt_close(int fd
)
2633 struct spt_dev_info
* sdip
;
2634 int index
= fd
- SPT_FDOFFSET
;
2636 if ((index
< 0) || (index
>= SPT_MAXDEV
)) {
2637 if (con
->reportscsiioctl
)
2638 pout("spt_close: bad fd range\n");
2641 sdip
= spt_dev_arr
[index
];
2643 if (con
->reportscsiioctl
)
2644 pout("spt_close: fd already closed\n");
2648 spt_dev_arr
[index
] = NULL
;
2652 #define IOCTL_SCSI_PASS_THROUGH_DIRECT \
2653 CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
2655 typedef struct _SCSI_PASS_THROUGH_DIRECT
{
2662 UCHAR SenseInfoLength
;
2664 ULONG DataTransferLength
;
2667 ULONG SenseInfoOffset
;
2669 } SCSI_PASS_THROUGH_DIRECT
;
2672 SCSI_PASS_THROUGH_DIRECT spt
;
2674 UCHAR ucSenseBuf
[64];
2675 } SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
;
2678 // Interface to SPT SCSI devices. See scsicmds.h and os_linux.c
2679 static int do_spt_cmnd_io(int fd
, struct scsi_cmnd_io
* iop
, int report
)
2681 struct spt_dev_info
* sdip
;
2682 int index
= fd
- SPT_FDOFFSET
;
2683 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb
;
2686 if ((index
< 0) || (index
>= SPT_MAXDEV
)) {
2688 pout("do_spt_cmnd_io: bad fd range\n");
2691 sdip
= spt_dev_arr
[index
];
2694 pout("do_spt_cmnd_io: fd already closed\n");
2700 const unsigned char * ucp
= iop
->cmnd
;
2703 const int sz
= (int)sizeof(buff
);
2705 np
= scsi_get_opcode_name(ucp
[0]);
2706 j
= snprintf(buff
, sz
, " [%s: ", np
? np
: "<unknown opcode>");
2707 for (k
= 0; k
< (int)iop
->cmnd_len
; ++k
)
2708 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "%02x ", ucp
[k
]);
2710 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
2711 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
2713 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n Outgoing "
2714 "data, len=%d%s:\n", (int)iop
->dxfer_len
,
2715 (trunc
? " [only first 256 bytes shown]" : ""));
2716 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
2719 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n");
2722 if (iop
->cmnd_len
> (int)sizeof(sb
.spt
.Cdb
)) {
2724 pout("do_spt_cmnd_io: cmnd_len too large\n");
2728 memset(&sb
, 0, sizeof(sb
));
2729 sb
.spt
.Length
= sizeof(SCSI_PASS_THROUGH_DIRECT
);
2730 sb
.spt
.CdbLength
= iop
->cmnd_len
;
2731 memcpy(sb
.spt
.Cdb
, iop
->cmnd
, iop
->cmnd_len
);
2732 sb
.spt
.SenseInfoLength
= sizeof(sb
.ucSenseBuf
);
2733 sb
.spt
.SenseInfoOffset
=
2734 offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
, ucSenseBuf
);
2735 sb
.spt
.TimeOutValue
= (iop
->timeout
? iop
->timeout
: 60);
2736 switch (iop
->dxfer_dir
) {
2738 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_UNSPECIFIED
;
2740 case DXFER_FROM_DEVICE
:
2741 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_IN
;
2742 sb
.spt
.DataTransferLength
= iop
->dxfer_len
;
2743 sb
.spt
.DataBuffer
= iop
->dxferp
;
2745 case DXFER_TO_DEVICE
:
2746 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_OUT
;
2747 sb
.spt
.DataTransferLength
= iop
->dxfer_len
;
2748 sb
.spt
.DataBuffer
= iop
->dxferp
;
2751 pout("do_spt_cmnd_io: bad dxfer_dir\n");
2755 if (! DeviceIoControl(sdip
->h_spt_ioctl
, IOCTL_SCSI_PASS_THROUGH_DIRECT
,
2756 &sb
, sizeof(sb
), &sb
, sizeof(sb
), &num_out
, NULL
)) {
2757 long err
= GetLastError();
2760 pout(" IOCTL_SCSI_PASS_THROUGH_DIRECT failed, Error=%ld\n", err
);
2761 return -(err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
2764 iop
->scsi_status
= sb
.spt
.ScsiStatus
;
2765 if (SCSI_STATUS_CHECK_CONDITION
& iop
->scsi_status
) {
2766 int slen
= sb
.ucSenseBuf
[7] + 8;
2768 if (slen
> (int)sizeof(sb
.ucSenseBuf
))
2769 slen
= sizeof(sb
.ucSenseBuf
);
2770 if (slen
> (int)iop
->max_sense_len
)
2771 slen
= iop
->max_sense_len
;
2772 memcpy(iop
->sensep
, sb
.ucSenseBuf
, slen
);
2773 iop
->resp_sense_len
= slen
;
2775 if ((iop
->sensep
[0] & 0x7f) > 0x71)
2776 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
2777 iop
->scsi_status
, iop
->sensep
[1] & 0xf,
2778 iop
->sensep
[2], iop
->sensep
[3]);
2780 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
2781 iop
->scsi_status
, iop
->sensep
[2] & 0xf,
2782 iop
->sensep
[12], iop
->sensep
[13]);
2785 iop
->resp_sense_len
= 0;
2787 if ((iop
->dxfer_len
> 0) && (sb
.spt
.DataTransferLength
> 0))
2788 iop
->resid
= iop
->dxfer_len
- sb
.spt
.DataTransferLength
;
2792 if ((iop
->dxfer_dir
== DXFER_FROM_DEVICE
) && (report
> 1)) {
2793 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
2794 pout(" Incoming data, len=%d%s:\n", (int)iop
->dxfer_len
,
2795 (trunc
? " [only first 256 bytes shown]" : ""));
2796 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
2802 // Decides which SCSI implementation based on pseudo fd.
2803 // Declaration and explanation in scsicmds.h
2804 int do_scsi_cmnd_io(int fd
, struct scsi_cmnd_io
* iop
, int report
)
2806 if ((fd
& ~0xff) == ASPI_FDOFFSET
)
2807 return do_aspi_cmnd_io(fd
, iop
, report
);
2809 return do_spt_cmnd_io(fd
, iop
, report
);