]> git.proxmox.com Git - mirror_smartmontools-debian.git/blob - os_win32.cpp
Imported Upstream version 5.42+svn3561
[mirror_smartmontools-debian.git] / os_win32.cpp
1 /*
2 * os_win32.cpp
3 *
4 * Home page of code is: http://smartmontools.sourceforge.net
5 *
6 * Copyright (C) 2004-12 Christian Franke <smartmontools-support@lists.sourceforge.net>
7 * Copyright (C) 2012 Hank Wu <hank@areca.com.tw>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
12 * any later version.
13 *
14 * You should have received a copy of the GNU General Public License
15 * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18
19 #include "config.h"
20 #define WINVER 0x0502
21 #define _WIN32_WINNT WINVER
22
23 #include "int64.h"
24 #include "atacmds.h"
25 #include "scsicmds.h"
26 #include "utility.h"
27 #include "smartctl.h" // TODO: Do not use smartctl only variables here
28
29 #include "dev_interface.h"
30 #include "dev_ata_cmd_set.h"
31
32 #include "os_win32/wmiquery.h"
33
34 #include <errno.h>
35
36 #ifdef _DEBUG
37 #include <assert.h>
38 #else
39 #undef assert
40 #define assert(x) /* */
41 #endif
42
43 #include <stddef.h> // offsetof()
44 #include <io.h> // access()
45
46 // WIN32_LEAN_AND_MEAN may be required to prevent inclusion of <winioctl.h>
47 #define WIN32_LEAN_AND_MEAN
48 #include <windows.h>
49
50 #if HAVE_NTDDDISK_H
51 // i686-w64-mingw32, x86_64-w64-mingw32
52 // (Missing: FILE_DEVICE_SCSI)
53 #include <devioctl.h>
54 #include <ntdddisk.h>
55 #include <ntddscsi.h>
56 #include <ntddstor.h>
57 #elif HAVE_DDK_NTDDDISK_H
58 // i686-pc-cygwin, i686-pc-mingw32, i586-mingw32msvc
59 // (Missing: IOCTL_IDE_PASS_THROUGH, IOCTL_ATA_PASS_THROUGH, FILE_DEVICE_SCSI)
60 #include <ddk/ntdddisk.h>
61 #include <ddk/ntddscsi.h>
62 #include <ddk/ntddstor.h>
63 #else
64 // MSVC10, older MinGW
65 // (Missing: IOCTL_SCSI_MINIPORT_*)
66 #include <ntddscsi.h>
67 #include <winioctl.h>
68 #endif
69
70 // CSMI support
71 #include "csmisas.h"
72
73 #ifdef __CYGWIN__
74 #include <cygwin/version.h> // CYGWIN_VERSION_DLL_MAJOR
75 #endif
76
77 // Macro to check constants at compile time using a dummy typedef
78 #define ASSERT_CONST(c, n) \
79 typedef char assert_const_##c[((c) == (n)) ? 1 : -1]
80 #define ASSERT_SIZEOF(t, n) \
81 typedef char assert_sizeof_##t[(sizeof(t) == (n)) ? 1 : -1]
82
83 #ifndef _WIN64
84 #define SELECT_WIN_32_64(x32, x64) (x32)
85 #else
86 #define SELECT_WIN_32_64(x32, x64) (x64)
87 #endif
88
89 const char * os_win32_cpp_cvsid = "$Id: os_win32.cpp 3558 2012-06-05 16:42:05Z chrfranke $";
90
91 // Disable Win9x/ME specific code if no longer supported by compiler.
92 #ifdef _WIN64
93 #undef WIN9X_SUPPORT
94 #elif !defined(WIN9X_SUPPORT)
95 #if defined(CYGWIN_VERSION_DLL_MAJOR) && (CYGWIN_VERSION_DLL_MAJOR >= 1007)
96 // Win9x/ME support was dropped in Cygwin 1.7
97 #elif defined(_MSC_VER) && (_MSC_VER >= 1500)
98 // Win9x/ME support was dropped in MSVC9 (cl.exe 15.0)
99 #else
100 #define WIN9X_SUPPORT 1
101 #endif
102 #endif
103
104 /////////////////////////////////////////////////////////////////////////////
105 // Windows I/O-controls, some declarations are missing in the include files
106
107 extern "C" {
108
109 // SMART_* IOCTLs, also known as DFP_* (Disk Fault Protection)
110
111 ASSERT_CONST(SMART_GET_VERSION, 0x074080);
112 ASSERT_CONST(SMART_SEND_DRIVE_COMMAND, 0x07c084);
113 ASSERT_CONST(SMART_RCV_DRIVE_DATA, 0x07c088);
114 ASSERT_SIZEOF(GETVERSIONINPARAMS, 24);
115 ASSERT_SIZEOF(SENDCMDINPARAMS, 32+1);
116 ASSERT_SIZEOF(SENDCMDOUTPARAMS, 16+1);
117
118
119 // IDE PASS THROUGH (2000, XP, undocumented)
120
121 #ifndef IOCTL_IDE_PASS_THROUGH
122
123 #define IOCTL_IDE_PASS_THROUGH \
124 CTL_CODE(IOCTL_SCSI_BASE, 0x040A, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
125
126 #endif // IOCTL_IDE_PASS_THROUGH
127
128 #pragma pack(1)
129
130 typedef struct {
131 IDEREGS IdeReg;
132 ULONG DataBufferSize;
133 UCHAR DataBuffer[1];
134 } ATA_PASS_THROUGH;
135
136 #pragma pack()
137
138 ASSERT_CONST(IOCTL_IDE_PASS_THROUGH, 0x04d028);
139 ASSERT_SIZEOF(ATA_PASS_THROUGH, 12+1);
140
141
142 // ATA PASS THROUGH (Win2003, XP SP2)
143
144 #ifndef IOCTL_ATA_PASS_THROUGH
145
146 #define IOCTL_ATA_PASS_THROUGH \
147 CTL_CODE(IOCTL_SCSI_BASE, 0x040B, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
148
149 typedef struct _ATA_PASS_THROUGH_EX {
150 USHORT Length;
151 USHORT AtaFlags;
152 UCHAR PathId;
153 UCHAR TargetId;
154 UCHAR Lun;
155 UCHAR ReservedAsUchar;
156 ULONG DataTransferLength;
157 ULONG TimeOutValue;
158 ULONG ReservedAsUlong;
159 ULONG_PTR DataBufferOffset;
160 UCHAR PreviousTaskFile[8];
161 UCHAR CurrentTaskFile[8];
162 } ATA_PASS_THROUGH_EX;
163
164 #define ATA_FLAGS_DRDY_REQUIRED 0x01
165 #define ATA_FLAGS_DATA_IN 0x02
166 #define ATA_FLAGS_DATA_OUT 0x04
167 #define ATA_FLAGS_48BIT_COMMAND 0x08
168 #define ATA_FLAGS_USE_DMA 0x10
169 #define ATA_FLAGS_NO_MULTIPLE 0x20 // Vista
170
171 #endif // IOCTL_ATA_PASS_THROUGH
172
173 ASSERT_CONST(IOCTL_ATA_PASS_THROUGH, 0x04d02c);
174 ASSERT_SIZEOF(ATA_PASS_THROUGH_EX, SELECT_WIN_32_64(40, 48));
175
176
177 // IOCTL_SCSI_PASS_THROUGH[_DIRECT]
178
179 ASSERT_CONST(IOCTL_SCSI_PASS_THROUGH, 0x04d004);
180 ASSERT_CONST(IOCTL_SCSI_PASS_THROUGH_DIRECT, 0x04d014);
181 ASSERT_SIZEOF(SCSI_PASS_THROUGH, SELECT_WIN_32_64(44, 56));
182 ASSERT_SIZEOF(SCSI_PASS_THROUGH_DIRECT, SELECT_WIN_32_64(44, 56));
183
184
185 // SMART IOCTL via SCSI MINIPORT ioctl
186
187 #ifndef FILE_DEVICE_SCSI
188 #define FILE_DEVICE_SCSI 0x001b
189 #endif
190
191 #ifndef IOCTL_SCSI_MINIPORT_SMART_VERSION
192
193 #define IOCTL_SCSI_MINIPORT_SMART_VERSION ((FILE_DEVICE_SCSI << 16) + 0x0500)
194 #define IOCTL_SCSI_MINIPORT_IDENTIFY ((FILE_DEVICE_SCSI << 16) + 0x0501)
195 #define IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS ((FILE_DEVICE_SCSI << 16) + 0x0502)
196 #define IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS ((FILE_DEVICE_SCSI << 16) + 0x0503)
197 #define IOCTL_SCSI_MINIPORT_ENABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0504)
198 #define IOCTL_SCSI_MINIPORT_DISABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0505)
199 #define IOCTL_SCSI_MINIPORT_RETURN_STATUS ((FILE_DEVICE_SCSI << 16) + 0x0506)
200 #define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE ((FILE_DEVICE_SCSI << 16) + 0x0507)
201 #define IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES ((FILE_DEVICE_SCSI << 16) + 0x0508)
202 #define IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS ((FILE_DEVICE_SCSI << 16) + 0x0509)
203 #define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE ((FILE_DEVICE_SCSI << 16) + 0x050a)
204 #define IOCTL_SCSI_MINIPORT_READ_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050b)
205 #define IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050c)
206
207 #endif // IOCTL_SCSI_MINIPORT_SMART_VERSION
208
209 ASSERT_CONST(IOCTL_SCSI_MINIPORT, 0x04d008);
210 ASSERT_SIZEOF(SRB_IO_CONTROL, 28);
211
212
213 // IOCTL_STORAGE_QUERY_PROPERTY
214
215 #ifndef IOCTL_STORAGE_QUERY_PROPERTY
216
217 #define IOCTL_STORAGE_QUERY_PROPERTY \
218 CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)
219
220 typedef struct _STORAGE_DEVICE_DESCRIPTOR {
221 ULONG Version;
222 ULONG Size;
223 UCHAR DeviceType;
224 UCHAR DeviceTypeModifier;
225 BOOLEAN RemovableMedia;
226 BOOLEAN CommandQueueing;
227 ULONG VendorIdOffset;
228 ULONG ProductIdOffset;
229 ULONG ProductRevisionOffset;
230 ULONG SerialNumberOffset;
231 STORAGE_BUS_TYPE BusType;
232 ULONG RawPropertiesLength;
233 UCHAR RawDeviceProperties[1];
234 } STORAGE_DEVICE_DESCRIPTOR;
235
236 typedef enum _STORAGE_QUERY_TYPE {
237 PropertyStandardQuery = 0,
238 PropertyExistsQuery,
239 PropertyMaskQuery,
240 PropertyQueryMaxDefined
241 } STORAGE_QUERY_TYPE;
242
243 typedef enum _STORAGE_PROPERTY_ID {
244 StorageDeviceProperty = 0,
245 StorageAdapterProperty,
246 StorageDeviceIdProperty,
247 StorageDeviceUniqueIdProperty,
248 StorageDeviceWriteCacheProperty,
249 StorageMiniportProperty,
250 StorageAccessAlignmentProperty
251 } STORAGE_PROPERTY_ID;
252
253 typedef struct _STORAGE_PROPERTY_QUERY {
254 STORAGE_PROPERTY_ID PropertyId;
255 STORAGE_QUERY_TYPE QueryType;
256 UCHAR AdditionalParameters[1];
257 } STORAGE_PROPERTY_QUERY;
258
259 #endif // IOCTL_STORAGE_QUERY_PROPERTY
260
261 ASSERT_CONST(IOCTL_STORAGE_QUERY_PROPERTY, 0x002d1400);
262 ASSERT_SIZEOF(STORAGE_DEVICE_DESCRIPTOR, 36+1+3);
263 ASSERT_SIZEOF(STORAGE_PROPERTY_QUERY, 8+1+3);
264
265
266 // IOCTL_STORAGE_PREDICT_FAILURE
267
268 ASSERT_CONST(IOCTL_STORAGE_PREDICT_FAILURE, 0x002d1100);
269 ASSERT_SIZEOF(STORAGE_PREDICT_FAILURE, 4+512);
270
271
272 // 3ware specific versions of SMART ioctl structs
273
274 #define SMART_VENDOR_3WARE 0x13C1 // identifies 3ware specific parameters
275
276 #pragma pack(1)
277
278 typedef struct _GETVERSIONINPARAMS_EX {
279 BYTE bVersion;
280 BYTE bRevision;
281 BYTE bReserved;
282 BYTE bIDEDeviceMap;
283 DWORD fCapabilities;
284 DWORD dwDeviceMapEx; // 3ware specific: RAID drive bit map
285 WORD wIdentifier; // Vendor specific identifier
286 WORD wControllerId; // 3ware specific: Controller ID (0,1,...)
287 ULONG dwReserved[2];
288 } GETVERSIONINPARAMS_EX;
289
290 typedef struct _SENDCMDINPARAMS_EX {
291 DWORD cBufferSize;
292 IDEREGS irDriveRegs;
293 BYTE bDriveNumber;
294 BYTE bPortNumber; // 3ware specific: port number
295 WORD wIdentifier; // Vendor specific identifier
296 DWORD dwReserved[4];
297 BYTE bBuffer[1];
298 } SENDCMDINPARAMS_EX;
299
300 #pragma pack()
301
302 ASSERT_SIZEOF(GETVERSIONINPARAMS_EX, sizeof(GETVERSIONINPARAMS));
303 ASSERT_SIZEOF(SENDCMDINPARAMS_EX, sizeof(SENDCMDINPARAMS));
304
305
306 // CSMI structs
307
308 ASSERT_SIZEOF(IOCTL_HEADER, sizeof(SRB_IO_CONTROL));
309 ASSERT_SIZEOF(CSMI_SAS_DRIVER_INFO_BUFFER, 204);
310 ASSERT_SIZEOF(CSMI_SAS_PHY_INFO_BUFFER, 2080);
311 ASSERT_SIZEOF(CSMI_SAS_STP_PASSTHRU_BUFFER, 168);
312
313 } // extern "C"
314
315 /////////////////////////////////////////////////////////////////////////////
316
317 namespace os_win32 { // no need to publish anything, name provided for Doxygen
318
319 #ifdef _MSC_VER
320 #pragma warning(disable:4250)
321 #endif
322
323 // Running on Win9x/ME ?
324 #if WIN9X_SUPPORT
325 // Set true in win9x_smart_interface ctor.
326 static bool win9x = false;
327 #else
328 // Never true (const allows compiler to remove dead code).
329 const bool win9x = false;
330 #endif
331
332
333 class win_smart_device
334 : virtual public /*implements*/ smart_device
335 {
336 public:
337 win_smart_device()
338 : smart_device(never_called),
339 m_fh(INVALID_HANDLE_VALUE)
340 { }
341
342 virtual ~win_smart_device() throw();
343
344 virtual bool is_open() const;
345
346 virtual bool close();
347
348 protected:
349 /// Set handle for open() in derived classes.
350 void set_fh(HANDLE fh)
351 { m_fh = fh; }
352
353 /// Return handle for derived classes.
354 HANDLE get_fh() const
355 { return m_fh; }
356
357 private:
358 HANDLE m_fh; ///< File handle
359 };
360
361
362 /////////////////////////////////////////////////////////////////////////////
363
364 class win_ata_device
365 : public /*implements*/ ata_device,
366 public /*extends*/ win_smart_device
367 {
368 public:
369 win_ata_device(smart_interface * intf, const char * dev_name, const char * req_type);
370
371 virtual ~win_ata_device() throw();
372
373 virtual bool open();
374
375 virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
376
377 virtual bool ata_identify_is_cached() const;
378
379 private:
380 bool open(int phydrive, int logdrive, const char * options, int port);
381
382 std::string m_options;
383 bool m_usr_options; // options set by user?
384 bool m_admin; // open with admin access?
385 bool m_id_is_cached; // ata_identify_is_cached() return value.
386 bool m_is_3ware; // AMCC/3ware controller detected?
387 int m_drive, m_port;
388 int m_smartver_state;
389 };
390
391
392 /////////////////////////////////////////////////////////////////////////////
393
394 class win_scsi_device
395 : public /*implements*/ scsi_device,
396 virtual public /*extends*/ win_smart_device
397 {
398 public:
399 win_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type);
400
401 virtual bool open();
402
403 virtual bool scsi_pass_through(scsi_cmnd_io * iop);
404
405 private:
406 bool open(int pd_num, int ld_num, int tape_num, int sub_addr);
407 };
408
409
410 /////////////////////////////////////////////////////////////////////////////
411
412 #if WIN9X_SUPPORT
413
414 class win_aspi_device
415 : public /*implements*/ scsi_device
416 {
417 public:
418 win_aspi_device(smart_interface * intf, const char * dev_name, const char * req_type);
419
420 virtual bool is_open() const;
421
422 virtual bool open();
423
424 virtual bool close();
425
426 virtual bool scsi_pass_through(scsi_cmnd_io * iop);
427
428 private:
429 int m_adapter;
430 unsigned char m_id;
431 };
432
433 #endif // WIN9X_SUPPORT
434
435
436 //////////////////////////////////////////////////////////////////////
437
438 class csmi_device
439 : virtual public /*extends*/ smart_device
440 {
441 public:
442 /// Get phy info
443 bool get_phy_info(CSMI_SAS_PHY_INFO & phy_info);
444
445 /// Check physical drive existence
446 bool check_phy(const CSMI_SAS_PHY_INFO & phy_info, unsigned phy_no);
447
448 protected:
449 csmi_device()
450 : smart_device(never_called)
451 { memset(&m_phy_ent, 0, sizeof(m_phy_ent)); }
452
453 /// Select physical drive
454 bool select_phy(unsigned phy_no);
455
456 /// Get info for selected physical drive
457 const CSMI_SAS_PHY_ENTITY & get_phy_ent() const
458 { return m_phy_ent; }
459
460 /// Call platform-specific CSMI ioctl
461 virtual bool csmi_ioctl(unsigned code, IOCTL_HEADER * csmi_buffer,
462 unsigned csmi_bufsiz) = 0;
463
464 private:
465 CSMI_SAS_PHY_ENTITY m_phy_ent; ///< CSMI info for this phy
466 };
467
468
469 class csmi_ata_device
470 : virtual public /*extends*/ csmi_device,
471 virtual public /*implements*/ ata_device
472 {
473 public:
474 virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
475
476 protected:
477 csmi_ata_device()
478 : smart_device(never_called) { }
479 };
480
481
482 //////////////////////////////////////////////////////////////////////
483
484 class win_csmi_device
485 : public /*implements*/ csmi_ata_device
486 {
487 public:
488 win_csmi_device(smart_interface * intf, const char * dev_name,
489 const char * req_type);
490
491 virtual ~win_csmi_device() throw();
492
493 virtual bool open();
494
495 virtual bool close();
496
497 virtual bool is_open() const;
498
499 bool open_scsi();
500
501 protected:
502 virtual bool csmi_ioctl(unsigned code, IOCTL_HEADER * csmi_buffer,
503 unsigned csmi_bufsiz);
504
505 private:
506 HANDLE m_fh; ///< Controller device handle
507 unsigned m_phy_no; ///< Physical drive number
508 };
509
510
511 //////////////////////////////////////////////////////////////////////
512
513 class win_tw_cli_device
514 : public /*implements*/ ata_device_with_command_set
515 {
516 public:
517 win_tw_cli_device(smart_interface * intf, const char * dev_name, const char * req_type);
518
519 virtual bool is_open() const;
520
521 virtual bool open();
522
523 virtual bool close();
524
525 protected:
526 virtual int ata_command_interface(smart_command_set command, int select, char * data);
527
528 private:
529 bool m_ident_valid, m_smart_valid;
530 ata_identify_device m_ident_buf;
531 ata_smart_values m_smart_buf;
532 };
533
534
535 /////////////////////////////////////////////////////////////////////////////
536 /// Areca RAID support
537
538 /* ARECA IO CONTROL CODE*/
539 #define ARCMSR_IOCTL_READ_RQBUFFER 0x90002004
540 #define ARCMSR_IOCTL_WRITE_WQBUFFER 0x90002008
541 #define ARCMSR_IOCTL_CLEAR_RQBUFFER 0x9000200C
542 #define ARCMSR_IOCTL_CLEAR_WQBUFFER 0x90002010
543 #define ARCMSR_IOCTL_RETURN_CODE_3F 0x90002018
544 #define ARECA_SIG_STR "ARCMSR"
545
546
547 // The SRB_IO_CONTROL & SRB_BUFFER structures are used to communicate(to/from) to areca driver
548 typedef struct _SRB_IO_CONTROL
549 {
550 unsigned int HeaderLength;
551 unsigned char Signature[8];
552 unsigned int Timeout;
553 unsigned int ControlCode;
554 unsigned int ReturnCode;
555 unsigned int Length;
556 } sSRB_IO_CONTROL;
557
558 typedef struct _SRB_BUFFER
559 {
560 sSRB_IO_CONTROL srbioctl;
561 unsigned char ioctldatabuffer[1032]; // the buffer to put the command data to/from firmware
562 } sSRB_BUFFER;
563
564 class win_areca_device
565 : public /*implements*/ ata_device,
566 public /*extends*/ win_smart_device
567 {
568 public:
569 win_areca_device(smart_interface * intf, const char * dev_name, HANDLE fh, int disknum, int encnum = 1);
570
571 static int arcmsr_command_handler(HANDLE fh, unsigned long arcmsr_cmd, unsigned char *data, int data_len);
572
573 protected:
574 virtual bool open();
575
576 virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
577
578 bool arcmsr_ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
579
580 private:
581 int m_disknum; ///< Disk number.
582 int m_encnum; ///< Enclosure number.
583 };
584
585
586 //////////////////////////////////////////////////////////////////////
587 // Platform specific interfaces
588
589 // Common to all windows flavors
590 class win_smart_interface
591 : public /*implements part of*/ smart_interface
592 {
593 public:
594 virtual std::string get_os_version_str();
595
596 virtual std::string get_app_examples(const char * appname);
597
598 #ifndef __CYGWIN__
599 virtual int64_t get_timer_usec();
600 #endif
601
602 //virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
603 // const char * pattern = 0);
604
605 protected:
606 virtual ata_device * get_ata_device(const char * name, const char * type);
607
608 //virtual scsi_device * get_scsi_device(const char * name, const char * type);
609
610 virtual smart_device * autodetect_smart_device(const char * name);
611 };
612
613 #if WIN9X_SUPPORT
614
615 // Win9x/ME reduced functionality
616 class win9x_smart_interface
617 : public /*extends*/ win_smart_interface
618 {
619 public:
620 win9x_smart_interface()
621 { win9x = true; }
622
623 virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
624 const char * pattern = 0);
625
626 protected:
627 virtual scsi_device * get_scsi_device(const char * name, const char * type);
628
629 private:
630 bool ata_scan(smart_device_list & devlist);
631
632 bool scsi_scan(smart_device_list & devlist);
633 };
634
635 #endif // WIN9X_SUPPORT
636
637 // WinNT,2000,XP,...
638 class winnt_smart_interface
639 : public /*extends*/ win_smart_interface
640 {
641 public:
642 virtual bool disable_system_auto_standby(bool disable);
643
644 virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
645 const char * pattern = 0);
646
647 protected:
648 virtual scsi_device * get_scsi_device(const char * name, const char * type);
649
650 virtual smart_device * autodetect_smart_device(const char * name);
651
652 virtual smart_device * get_custom_smart_device(const char * name, const char * type);
653
654 virtual std::string get_valid_custom_dev_types_str();
655 };
656
657
658 //////////////////////////////////////////////////////////////////////
659
660 #ifndef _WIN64
661 // Running on 64-bit Windows as 32-bit app ?
662 static bool is_wow64()
663 {
664 BOOL (WINAPI * IsWow64Process_p)(HANDLE, PBOOL) =
665 (BOOL (WINAPI *)(HANDLE, PBOOL))
666 GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
667 if (!IsWow64Process_p)
668 return false;
669 BOOL w64 = FALSE;
670 if (!IsWow64Process_p(GetCurrentProcess(), &w64))
671 return false;
672 return !!w64;
673 }
674 #endif // _WIN64
675
676 // Return info string about build host and OS version
677 std::string win_smart_interface::get_os_version_str()
678 {
679 char vstr[sizeof(SMARTMONTOOLS_BUILD_HOST)-1+sizeof("-2003r2(64)-sp2.1")+13]
680 = SMARTMONTOOLS_BUILD_HOST;
681 if (vstr[1] < '6')
682 vstr[1] = '6';
683 char * const vptr = vstr+sizeof(SMARTMONTOOLS_BUILD_HOST)-1;
684 const int vlen = sizeof(vstr)-sizeof(SMARTMONTOOLS_BUILD_HOST);
685 assert(vptr == vstr+strlen(vstr) && vptr+vlen+1 == vstr+sizeof(vstr));
686
687 OSVERSIONINFOEXA vi; memset(&vi, 0, sizeof(vi));
688 vi.dwOSVersionInfoSize = sizeof(vi);
689 if (!GetVersionExA((OSVERSIONINFOA *)&vi)) {
690 memset(&vi, 0, sizeof(vi));
691 vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
692 if (!GetVersionExA((OSVERSIONINFOA *)&vi))
693 return vstr;
694 }
695
696 if (vi.dwPlatformId > 0xff || vi.dwMajorVersion > 0xff || vi.dwMinorVersion > 0xff)
697 return vstr;
698
699 const char * w;
700 switch (vi.dwPlatformId << 16 | vi.dwMajorVersion << 8 | vi.dwMinorVersion) {
701 case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400| 0:
702 w = (vi.szCSDVersion[1] == 'B' ||
703 vi.szCSDVersion[1] == 'C' ? "95-osr2" : "95"); break;
704 case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400|10:
705 w = (vi.szCSDVersion[1] == 'A' ? "98se" : "98"); break;
706 case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400|90: w = "me"; break;
707 //case VER_PLATFORM_WIN32_NT <<16|0x0300|51: w = "nt3.51"; break;
708 case VER_PLATFORM_WIN32_NT <<16|0x0400| 0: w = "nt4"; break;
709 case VER_PLATFORM_WIN32_NT <<16|0x0500| 0: w = "2000"; break;
710 case VER_PLATFORM_WIN32_NT <<16|0x0500| 1:
711 w = (!GetSystemMetrics(87/*SM_MEDIACENTER*/) ? "xp"
712 : "xp-mc"); break;
713 case VER_PLATFORM_WIN32_NT <<16|0x0500| 2:
714 w = (!GetSystemMetrics(89/*SM_SERVERR2*/) ? "2003"
715 : "2003r2"); break;
716 case VER_PLATFORM_WIN32_NT <<16|0x0600| 0:
717 w = (vi.wProductType == VER_NT_WORKSTATION ? "vista"
718 : "2008" ); break;
719 case VER_PLATFORM_WIN32_NT <<16|0x0600| 1:
720 w = (vi.wProductType == VER_NT_WORKSTATION ? "win7"
721 : "2008r2"); break;
722 case VER_PLATFORM_WIN32_NT <<16|0x0600| 2:
723 w = (vi.wProductType == VER_NT_WORKSTATION ? "win8"
724 : "win8s"); break;
725 default: w = 0; break;
726 }
727
728 const char * w64 = "";
729 #ifndef _WIN64
730 if (is_wow64())
731 w64 = "(64)";
732 #endif
733
734 if (!w)
735 snprintf(vptr, vlen, "-%s%lu.%lu%s",
736 (vi.dwPlatformId==VER_PLATFORM_WIN32_NT ? "nt" : "9x"),
737 vi.dwMajorVersion, vi.dwMinorVersion, w64);
738 else if (vi.wServicePackMinor)
739 snprintf(vptr, vlen, "-%s%s-sp%u.%u", w, w64, vi.wServicePackMajor, vi.wServicePackMinor);
740 else if (vi.wServicePackMajor)
741 snprintf(vptr, vlen, "-%s%s-sp%u", w, w64, vi.wServicePackMajor);
742 else
743 snprintf(vptr, vlen, "-%s%s", w, w64);
744 return vstr;
745 }
746
747 #ifndef __CYGWIN__
748 // MSVCRT only provides ftime() which uses GetSystemTime()
749 // This provides only ~15ms resolution by default.
750 // Use QueryPerformanceCounter instead (~300ns).
751 // (Cygwin provides CLOCK_MONOTONIC which has the same effect)
752 int64_t win_smart_interface::get_timer_usec()
753 {
754 static int64_t freq = 0;
755
756 LARGE_INTEGER t;
757 if (freq == 0)
758 freq = (QueryPerformanceFrequency(&t) ? t.QuadPart : -1);
759 if (freq <= 0)
760 return smart_interface::get_timer_usec();
761
762 if (!QueryPerformanceCounter(&t))
763 return -1;
764 if (!(0 <= t.QuadPart && t.QuadPart <= (int64_t)(~(uint64_t)0 >> 1)/1000000))
765 return -1;
766
767 return (t.QuadPart * 1000000LL) / freq;
768 }
769 #endif // __CYGWIN__
770
771
772 // Return value for device detection functions
773 enum win_dev_type { DEV_UNKNOWN = 0, DEV_ATA, DEV_SCSI, DEV_USB };
774
775 static win_dev_type get_phy_drive_type(int drive);
776 static win_dev_type get_phy_drive_type(int drive, GETVERSIONINPARAMS_EX * ata_version_ex);
777 static win_dev_type get_log_drive_type(int drive);
778 static bool get_usb_id(int drive, unsigned short & vendor_id,
779 unsigned short & product_id);
780
781 static const char * ata_get_def_options(void);
782
783
784 static int is_permissive()
785 {
786 if (!failuretest_permissive) {
787 pout("To continue, add one or more '-T permissive' options.\n");
788 return 0;
789 }
790 failuretest_permissive--;
791 return 1;
792 }
793
794 // return number for drive letter, -1 on error
795 // "[A-Za-z]:([/\\][.]?)?" => 0-25
796 // Accepts trailing '"' to fix broken "X:\" parameter passing from .bat files
797 static int drive_letter(const char * s)
798 {
799 return ( (('A' <= s[0] && s[0] <= 'Z') || ('a' <= s[0] && s[0] <= 'z'))
800 && s[1] == ':'
801 && (!s[2] || ( strchr("/\\\"", s[2])
802 && (!s[3] || (s[3] == '.' && !s[4]))) ) ?
803 (s[0] & 0x1f) - 1 : -1);
804 }
805
806 // Skip trailing "/dev/", do not allow "/dev/X:"
807 static const char * skipdev(const char * s)
808 {
809 return (!strncmp(s, "/dev/", 5) && drive_letter(s+5) < 0 ? s+5 : s);
810 }
811
812 ata_device * win_smart_interface::get_ata_device(const char * name, const char * type)
813 {
814 const char * testname = skipdev(name);
815 if (!strncmp(testname, "csmi", 4))
816 return new win_csmi_device(this, name, type);
817 if (!strncmp(testname, "tw_cli", 6))
818 return new win_tw_cli_device(this, name, type);
819 return new win_ata_device(this, name, type);
820 }
821
822 #ifdef WIN9X_SUPPORT
823
824 scsi_device * win9x_smart_interface::get_scsi_device(const char * name, const char * type)
825 {
826 return new win_aspi_device(this, name, type);
827 }
828
829 #endif
830
831 scsi_device * winnt_smart_interface::get_scsi_device(const char * name, const char * type)
832 {
833 const char * testname = skipdev(name);
834 if (!strncmp(testname, "scsi", 4))
835 #if WIN9X_SUPPORT
836 return new win_aspi_device(this, name, type);
837 #else
838 return (set_err(EINVAL, "ASPI interface not supported"), (scsi_device *)0);
839 #endif
840 return new win_scsi_device(this, name, type);
841 }
842
843 static win_dev_type get_dev_type(const char * name, int & phydrive)
844 {
845 phydrive = -1;
846 name = skipdev(name);
847 if (!strncmp(name, "st", 2))
848 return DEV_SCSI;
849 if (!strncmp(name, "nst", 3))
850 return DEV_SCSI;
851 if (!strncmp(name, "tape", 4))
852 return DEV_SCSI;
853
854 int logdrive = drive_letter(name);
855 if (logdrive >= 0) {
856 win_dev_type type = get_log_drive_type(logdrive);
857 return (type != DEV_UNKNOWN ? type : DEV_SCSI);
858 }
859
860 char drive[1+1] = "";
861 if (sscanf(name, "sd%1[a-z]", drive) == 1) {
862 phydrive = drive[0] - 'a';
863 return get_phy_drive_type(phydrive);
864 }
865
866 phydrive = -1;
867 if (sscanf(name, "pd%d", &phydrive) == 1 && phydrive >= 0)
868 return get_phy_drive_type(phydrive);
869 return DEV_UNKNOWN;
870 }
871
872 smart_device * win_smart_interface::autodetect_smart_device(const char * name)
873 {
874 const char * testname = skipdev(name);
875 if (!strncmp(testname, "hd", 2))
876 return new win_ata_device(this, name, "");
877 #if WIN9X_SUPPORT
878 if (!strncmp(testname, "scsi", 4))
879 return new win_aspi_device(this, name, "");
880 #endif
881 if (!strncmp(testname, "tw_cli", 6))
882 return new win_tw_cli_device(this, name, "");
883 return 0;
884 }
885
886
887 smart_device * winnt_smart_interface::get_custom_smart_device(const char * name, const char * type)
888 {
889 // Areca?
890 int disknum = -1, n1 = -1, n2 = -1;
891 int encnum = 1;
892 HANDLE fh = INVALID_HANDLE_VALUE;
893 char devpath[32];
894
895 if (sscanf(type, "areca,%n%d/%d%n", &n1, &disknum, &encnum, &n2) >= 1 || n1 == 6) {
896 if (!(1 <= disknum && disknum <= 128)) {
897 set_err(EINVAL, "Option -d areca,N/E (N=%d) must have 1 <= N <= 128", disknum);
898 return 0;
899 }
900 if (!(1 <= encnum && encnum <= 8)) {
901 set_err(EINVAL, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum);
902 return 0;
903 }
904
905 name = skipdev(name);
906 #define ARECA_MAX_CTLR_NUM 16
907 n1 = -1;
908 int ctlrindex = 0;
909 if (sscanf(name, "arcmsr%d%n", &ctlrindex, &n1) >= 1 && n1 == (int)strlen(name)) {
910 /*
911 1. scan from "\\\\.\\scsi[0]:" up to "\\\\.\\scsi[ARECA_MAX_CTLR_NUM]:" and
912 2. map arcmsrX into "\\\\.\\scsiX"
913 */
914 for (int idx = 0; idx < ARECA_MAX_CTLR_NUM; idx++) {
915 memset(devpath, 0, sizeof(devpath));
916 sprintf(devpath, "\\\\.\\scsi%d:", idx);
917 if ( (fh = CreateFile( devpath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
918 NULL, OPEN_EXISTING, 0, NULL )) != INVALID_HANDLE_VALUE ) {
919 if (win_areca_device::arcmsr_command_handler(fh, ARCMSR_IOCTL_RETURN_CODE_3F, NULL, 0) == 0) {
920 if (ctlrindex-- == 0) {
921 return new win_areca_device(this, devpath, fh, disknum, encnum);
922 }
923 }
924 CloseHandle(fh);
925 }
926 }
927 set_err(ENOENT, "No Areca controller found");
928 }
929 else
930 set_err(EINVAL, "Option -d areca,N/E requires device name /dev/arcmsrX");
931 }
932
933 return 0;
934 }
935
936 std::string winnt_smart_interface::get_valid_custom_dev_types_str()
937 {
938 return "areca,N[/E]";
939 }
940
941
942 smart_device * winnt_smart_interface::autodetect_smart_device(const char * name)
943 {
944 smart_device * dev = win_smart_interface::autodetect_smart_device(name);
945 if (dev)
946 return dev;
947
948 if (!strncmp(skipdev(name), "csmi", 4))
949 return new win_csmi_device(this, name, "");
950
951 int phydrive = -1;
952 win_dev_type type = get_dev_type(name, phydrive);
953
954 if (type == DEV_ATA)
955 return new win_ata_device(this, name, "");
956 if (type == DEV_SCSI)
957 return new win_scsi_device(this, name, "");
958
959 if (type == DEV_USB) {
960 // Get USB bridge ID
961 unsigned short vendor_id = 0, product_id = 0;
962 if (!(phydrive >= 0 && get_usb_id(phydrive, vendor_id, product_id))) {
963 set_err(EINVAL, "Unable to read USB device ID");
964 return 0;
965 }
966 // Get type name for this ID
967 const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id);
968 if (!usbtype)
969 return 0;
970 // Return SAT/USB device for this type
971 return get_sat_device(usbtype, new win_scsi_device(this, name, ""));
972 }
973
974 return 0;
975 }
976
977
978 #if WIN9X_SUPPORT
979
980 // Scan for devices on Win9x/ME
981
982 bool win9x_smart_interface::scan_smart_devices(smart_device_list & devlist,
983 const char * type, const char * pattern /* = 0*/)
984 {
985 if (pattern) {
986 set_err(EINVAL, "DEVICESCAN with pattern not implemented yet");
987 return false;
988 }
989
990 if (!type || !strcmp(type, "ata")) {
991 if (!ata_scan(devlist))
992 return false;
993 }
994
995 if (!type || !strcmp(type, "scsi")) {
996 if (!scsi_scan(devlist))
997 return false;
998 }
999 return true;
1000 }
1001
1002 #endif // WIN9X_SUPPORT
1003
1004
1005 // Scan for devices
1006
1007 bool winnt_smart_interface::scan_smart_devices(smart_device_list & devlist,
1008 const char * type, const char * pattern /* = 0*/)
1009 {
1010 if (pattern) {
1011 set_err(EINVAL, "DEVICESCAN with pattern not implemented yet");
1012 return false;
1013 }
1014
1015 // Set valid types
1016 bool ata, scsi, usb, csmi;
1017 if (!type) {
1018 ata = scsi = usb = csmi = true;
1019 }
1020 else {
1021 ata = scsi = usb = csmi = false;
1022 if (!strcmp(type, "ata"))
1023 ata = true;
1024 else if (!strcmp(type, "scsi"))
1025 scsi = true;
1026 else if (!strcmp(type, "usb"))
1027 usb = true;
1028 else if (!strcmp(type, "csmi"))
1029 csmi = true;
1030 else {
1031 set_err(EINVAL, "Invalid type '%s', valid arguments are: ata, scsi, usb, csmi", type);
1032 return false;
1033 }
1034 }
1035
1036 // Scan up to 10 drives and 2 3ware controllers
1037 const int max_raid = 2;
1038 bool raid_seen[max_raid] = {false, false};
1039
1040 char name[20];
1041 for (int i = 0; i <= 9; i++) {
1042 sprintf(name, "/dev/sd%c", 'a'+i);
1043 GETVERSIONINPARAMS_EX vers_ex;
1044
1045 switch (get_phy_drive_type(i, (ata ? &vers_ex : 0))) {
1046 case DEV_ATA:
1047 // Driver supports SMART_GET_VERSION or STORAGE_QUERY_PROPERTY returned ATA/SATA
1048 if (!ata)
1049 continue;
1050
1051 // Interpret RAID drive map if present
1052 if (vers_ex.wIdentifier == SMART_VENDOR_3WARE) {
1053 // Skip if too many controllers or logical drive from this controller already seen
1054 if (!(vers_ex.wControllerId < max_raid && !raid_seen[vers_ex.wControllerId]))
1055 continue;
1056 raid_seen[vers_ex.wControllerId] = true;
1057 // Add physical drives
1058 int len = strlen(name);
1059 for (int pi = 0; pi < 32; pi++) {
1060 if (vers_ex.dwDeviceMapEx & (1L << pi)) {
1061 sprintf(name+len, ",%u", pi);
1062 devlist.push_back( new win_ata_device(this, name, "ata") );
1063 }
1064 }
1065 }
1066 else {
1067 devlist.push_back( new win_ata_device(this, name, "ata") );
1068 }
1069 break;
1070
1071 case DEV_SCSI:
1072 // STORAGE_QUERY_PROPERTY returned SCSI/SAS/...
1073 if (!scsi)
1074 continue;
1075 devlist.push_back( new win_scsi_device(this, name, "scsi") );
1076 break;
1077
1078 case DEV_USB:
1079 // STORAGE_QUERY_PROPERTY returned USB
1080 if (!usb)
1081 continue;
1082 {
1083 // TODO: Use common function for this and autodetect_smart_device()
1084 // Get USB bridge ID
1085 unsigned short vendor_id = 0, product_id = 0;
1086 if (!get_usb_id(i, vendor_id, product_id))
1087 continue;
1088 // Get type name for this ID
1089 const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id);
1090 if (!usbtype)
1091 continue;
1092 // Return SAT/USB device for this type
1093 ata_device * dev = get_sat_device(usbtype, new win_scsi_device(this, name, ""));
1094 if (!dev)
1095 continue;
1096 devlist.push_back(dev);
1097 }
1098 break;
1099
1100 default:
1101 // Unknown type
1102 break;
1103 }
1104 }
1105
1106 if (csmi) {
1107 // Scan CSMI devices
1108 for (int i = 0; i <= 9; i++) {
1109 snprintf(name, sizeof(name)-1, "/dev/csmi%d,0", i);
1110 win_csmi_device test_dev(this, name, "");
1111 if (!test_dev.open_scsi())
1112 continue;
1113 CSMI_SAS_PHY_INFO phy_info;
1114 if (!test_dev.get_phy_info(phy_info))
1115 continue;
1116
1117 for (int pi = 0; pi < phy_info.bNumberOfPhys; pi++) {
1118 if (!test_dev.check_phy(phy_info, pi))
1119 continue;
1120 snprintf(name, sizeof(name)-1, "/dev/csmi%d,%d", i, pi);
1121 devlist.push_back( new win_csmi_device(this, name, "ata") );
1122 }
1123 }
1124 }
1125 return true;
1126 }
1127
1128
1129 // get examples for smartctl
1130 std::string win_smart_interface::get_app_examples(const char * appname)
1131 {
1132 if (strcmp(appname, "smartctl"))
1133 return "";
1134 return "=================================================== SMARTCTL EXAMPLES =====\n\n"
1135 " smartctl -a /dev/hda (Prints all SMART information)\n\n"
1136 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/hda\n"
1137 " (Enables SMART on first disk)\n\n"
1138 " smartctl -t long /dev/hda (Executes extended disk self-test)\n\n"
1139 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/hda\n"
1140 " (Prints Self-Test & Attribute errors)\n"
1141 #if WIN9X_SUPPORT
1142 " smartctl -a /dev/scsi21\n"
1143 " (Prints all information for SCSI disk on ASPI adapter 2, ID 1)\n"
1144 #endif
1145 " smartctl -a /dev/sda\n"
1146 " (Prints all information for SCSI disk on PhysicalDrive 0)\n"
1147 " smartctl -a /dev/pd3\n"
1148 " (Prints all information for SCSI disk on PhysicalDrive 3)\n"
1149 " smartctl -a /dev/tape1\n"
1150 " (Prints all information for SCSI tape on Tape 1)\n"
1151 " smartctl -A /dev/hdb,3\n"
1152 " (Prints Attributes for physical drive 3 on 3ware 9000 RAID)\n"
1153 " smartctl -A /dev/tw_cli/c0/p1\n"
1154 " (Prints Attributes for 3ware controller 0, port 1 using tw_cli)\n"
1155 " smartctl --all --device=areca,3/1 /dev/arcmsr0\n"
1156 " (Prints all SMART info for 3rd ATA disk of the 1st enclosure\n"
1157 " on 1st Areca RAID controller)\n"
1158 "\n"
1159 " ATA SMART access methods and ordering may be specified by modifiers\n"
1160 " following the device name: /dev/hdX:[saicm], where\n"
1161 " 's': SMART_* IOCTLs, 'a': IOCTL_ATA_PASS_THROUGH,\n"
1162 " 'i': IOCTL_IDE_PASS_THROUGH, 'c': ATA via IOCTL_SCSI_PASS_THROUGH,\n"
1163 " 'f': IOCTL_STORAGE_*, 'm': IOCTL_SCSI_MINIPORT_*.\n"
1164 + strprintf(
1165 " The default on this system is /dev/sdX:%s\n", ata_get_def_options()
1166 );
1167 }
1168
1169
1170 bool winnt_smart_interface::disable_system_auto_standby(bool disable)
1171 {
1172 if (disable) {
1173 SYSTEM_POWER_STATUS ps;
1174 if (!GetSystemPowerStatus(&ps))
1175 return set_err(ENOSYS, "Unknown power status");
1176 if (ps.ACLineStatus != 1) {
1177 SetThreadExecutionState(ES_CONTINUOUS);
1178 if (ps.ACLineStatus == 0)
1179 set_err(EIO, "AC offline");
1180 else
1181 set_err(EIO, "Unknown AC line status");
1182 return false;
1183 }
1184 }
1185
1186 if (!SetThreadExecutionState(ES_CONTINUOUS | (disable ? ES_SYSTEM_REQUIRED : 0)))
1187 return set_err(ENOSYS);
1188 return true;
1189 }
1190
1191
1192 /////////////////////////////////////////////////////////////////////////////
1193 // ATA Interface
1194 /////////////////////////////////////////////////////////////////////////////
1195
1196 #define SMART_CYL_LOW 0x4F
1197 #define SMART_CYL_HI 0xC2
1198
1199 static void print_ide_regs(const IDEREGS * r, int out)
1200 {
1201 pout("%s=0x%02x,%s=0x%02x, SC=0x%02x, SN=0x%02x, CL=0x%02x, CH=0x%02x, SEL=0x%02x\n",
1202 (out?"STS":"CMD"), r->bCommandReg, (out?"ERR":" FR"), r->bFeaturesReg,
1203 r->bSectorCountReg, r->bSectorNumberReg, r->bCylLowReg, r->bCylHighReg, r->bDriveHeadReg);
1204 }
1205
1206 static void print_ide_regs_io(const IDEREGS * ri, const IDEREGS * ro)
1207 {
1208 pout(" Input : "); print_ide_regs(ri, 0);
1209 if (ro) {
1210 pout(" Output: "); print_ide_regs(ro, 1);
1211 }
1212 }
1213
1214 /////////////////////////////////////////////////////////////////////////////
1215
1216 // call SMART_GET_VERSION, return device map or -1 on error
1217
1218 static int smart_get_version(HANDLE hdevice, GETVERSIONINPARAMS_EX * ata_version_ex = 0)
1219 {
1220 GETVERSIONINPARAMS vers; memset(&vers, 0, sizeof(vers));
1221 const GETVERSIONINPARAMS_EX & vers_ex = (const GETVERSIONINPARAMS_EX &)vers;
1222 DWORD num_out;
1223
1224 if (!DeviceIoControl(hdevice, SMART_GET_VERSION,
1225 NULL, 0, &vers, sizeof(vers), &num_out, NULL)) {
1226 if (ata_debugmode)
1227 pout(" SMART_GET_VERSION failed, Error=%ld\n", GetLastError());
1228 errno = ENOSYS;
1229 return -1;
1230 }
1231 assert(num_out == sizeof(GETVERSIONINPARAMS));
1232
1233 if (ata_debugmode > 1) {
1234 pout(" SMART_GET_VERSION suceeded, bytes returned: %lu\n"
1235 " Vers = %d.%d, Caps = 0x%lx, DeviceMap = 0x%02x\n",
1236 num_out, vers.bVersion, vers.bRevision,
1237 vers.fCapabilities, vers.bIDEDeviceMap);
1238 if (vers_ex.wIdentifier == SMART_VENDOR_3WARE)
1239 pout(" Identifier = %04x(3WARE), ControllerId=%u, DeviceMapEx = 0x%08lx\n",
1240 vers_ex.wIdentifier, vers_ex.wControllerId, vers_ex.dwDeviceMapEx);
1241 }
1242
1243 if (ata_version_ex)
1244 *ata_version_ex = vers_ex;
1245
1246 // TODO: Check vers.fCapabilities here?
1247 return vers.bIDEDeviceMap;
1248 }
1249
1250
1251 // call SMART_* ioctl
1252
1253 static int smart_ioctl(HANDLE hdevice, int drive, IDEREGS * regs, char * data, unsigned datasize, int port)
1254 {
1255 SENDCMDINPARAMS inpar;
1256 SENDCMDINPARAMS_EX & inpar_ex = (SENDCMDINPARAMS_EX &)inpar;
1257
1258 unsigned char outbuf[sizeof(SENDCMDOUTPARAMS)-1 + 512];
1259 const SENDCMDOUTPARAMS * outpar;
1260 DWORD code, num_out;
1261 unsigned int size_out;
1262 const char * name;
1263
1264 memset(&inpar, 0, sizeof(inpar));
1265 inpar.irDriveRegs = *regs;
1266 // drive is set to 0-3 on Win9x only
1267 inpar.irDriveRegs.bDriveHeadReg = 0xA0 | ((drive & 1) << 4);
1268 inpar.bDriveNumber = drive;
1269
1270 if (port >= 0) {
1271 // Set RAID port
1272 inpar_ex.wIdentifier = SMART_VENDOR_3WARE;
1273 inpar_ex.bPortNumber = port;
1274 }
1275
1276 if (datasize == 512) {
1277 code = SMART_RCV_DRIVE_DATA; name = "SMART_RCV_DRIVE_DATA";
1278 inpar.cBufferSize = size_out = 512;
1279 }
1280 else if (datasize == 0) {
1281 code = SMART_SEND_DRIVE_COMMAND; name = "SMART_SEND_DRIVE_COMMAND";
1282 if (regs->bFeaturesReg == ATA_SMART_STATUS)
1283 size_out = sizeof(IDEREGS); // ioctl returns new IDEREGS as data
1284 // Note: cBufferSize must be 0 on Win9x
1285 else
1286 size_out = 0;
1287 }
1288 else {
1289 errno = EINVAL;
1290 return -1;
1291 }
1292
1293 memset(&outbuf, 0, sizeof(outbuf));
1294
1295 if (!DeviceIoControl(hdevice, code, &inpar, sizeof(SENDCMDINPARAMS)-1,
1296 outbuf, sizeof(SENDCMDOUTPARAMS)-1 + size_out, &num_out, NULL)) {
1297 // CAUTION: DO NOT change "regs" Parameter in this case, see ata_command_interface()
1298 long err = GetLastError();
1299 if (ata_debugmode && (err != ERROR_INVALID_PARAMETER || ata_debugmode > 1)) {
1300 pout(" %s failed, Error=%ld\n", name, err);
1301 print_ide_regs_io(regs, NULL);
1302 }
1303 errno = ( err == ERROR_INVALID_FUNCTION/*9x*/
1304 || err == ERROR_INVALID_PARAMETER/*NT/2K/XP*/
1305 || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
1306 return -1;
1307 }
1308 // NOTE: On Win9x, inpar.irDriveRegs now contains the returned regs
1309
1310 outpar = (const SENDCMDOUTPARAMS *)outbuf;
1311
1312 if (outpar->DriverStatus.bDriverError) {
1313 if (ata_debugmode) {
1314 pout(" %s failed, DriverError=0x%02x, IDEError=0x%02x\n", name,
1315 outpar->DriverStatus.bDriverError, outpar->DriverStatus.bIDEError);
1316 print_ide_regs_io(regs, NULL);
1317 }
1318 errno = (!outpar->DriverStatus.bIDEError ? ENOSYS : EIO);
1319 return -1;
1320 }
1321
1322 if (ata_debugmode > 1) {
1323 pout(" %s suceeded, bytes returned: %lu (buffer %lu)\n", name,
1324 num_out, outpar->cBufferSize);
1325 print_ide_regs_io(regs, (regs->bFeaturesReg == ATA_SMART_STATUS ?
1326 (const IDEREGS *)(outpar->bBuffer) : NULL));
1327 }
1328
1329 if (datasize)
1330 memcpy(data, outpar->bBuffer, 512);
1331 else if (regs->bFeaturesReg == ATA_SMART_STATUS) {
1332 if (nonempty(outpar->bBuffer, sizeof(IDEREGS)))
1333 memcpy(regs, outpar->bBuffer, sizeof(IDEREGS));
1334 else { // Workaround for driver not returning regs
1335 if (ata_debugmode)
1336 pout(" WARNING: driver does not return ATA registers in output buffer!\n");
1337 *regs = inpar.irDriveRegs;
1338 }
1339 }
1340
1341 return 0;
1342 }
1343
1344
1345 /////////////////////////////////////////////////////////////////////////////
1346 // IDE PASS THROUGH (2000, XP, undocumented)
1347 //
1348 // Based on WinATA.cpp, 2002 c't/Matthias Withopf
1349 // ftp://ftp.heise.de/pub/ct/listings/0207-218.zip
1350
1351 static int ide_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize)
1352 {
1353 if (datasize > 512) {
1354 errno = EINVAL;
1355 return -1;
1356 }
1357 unsigned int size = sizeof(ATA_PASS_THROUGH)-1 + datasize;
1358 ATA_PASS_THROUGH * buf = (ATA_PASS_THROUGH *)VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
1359 DWORD num_out;
1360 const unsigned char magic = 0xcf;
1361
1362 if (!buf) {
1363 errno = ENOMEM;
1364 return -1;
1365 }
1366
1367 buf->IdeReg = *regs;
1368 buf->DataBufferSize = datasize;
1369 if (datasize)
1370 buf->DataBuffer[0] = magic;
1371
1372 if (!DeviceIoControl(hdevice, IOCTL_IDE_PASS_THROUGH,
1373 buf, size, buf, size, &num_out, NULL)) {
1374 long err = GetLastError();
1375 if (ata_debugmode) {
1376 pout(" IOCTL_IDE_PASS_THROUGH failed, Error=%ld\n", err);
1377 print_ide_regs_io(regs, NULL);
1378 }
1379 VirtualFree(buf, 0, MEM_RELEASE);
1380 errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
1381 return -1;
1382 }
1383
1384 // Check ATA status
1385 if (buf->IdeReg.bCommandReg/*Status*/ & 0x01) {
1386 if (ata_debugmode) {
1387 pout(" IOCTL_IDE_PASS_THROUGH command failed:\n");
1388 print_ide_regs_io(regs, &buf->IdeReg);
1389 }
1390 VirtualFree(buf, 0, MEM_RELEASE);
1391 errno = EIO;
1392 return -1;
1393 }
1394
1395 // Check and copy data
1396 if (datasize) {
1397 if ( num_out != size
1398 || (buf->DataBuffer[0] == magic && !nonempty(buf->DataBuffer+1, datasize-1))) {
1399 if (ata_debugmode) {
1400 pout(" IOCTL_IDE_PASS_THROUGH output data missing (%lu, %lu)\n",
1401 num_out, buf->DataBufferSize);
1402 print_ide_regs_io(regs, &buf->IdeReg);
1403 }
1404 VirtualFree(buf, 0, MEM_RELEASE);
1405 errno = EIO;
1406 return -1;
1407 }
1408 memcpy(data, buf->DataBuffer, datasize);
1409 }
1410
1411 if (ata_debugmode > 1) {
1412 pout(" IOCTL_IDE_PASS_THROUGH suceeded, bytes returned: %lu (buffer %lu)\n",
1413 num_out, buf->DataBufferSize);
1414 print_ide_regs_io(regs, &buf->IdeReg);
1415 }
1416 *regs = buf->IdeReg;
1417
1418 // Caution: VirtualFree() fails if parameter "dwSize" is nonzero
1419 VirtualFree(buf, 0, MEM_RELEASE);
1420 return 0;
1421 }
1422
1423
1424 /////////////////////////////////////////////////////////////////////////////
1425 // ATA PASS THROUGH (Win2003, XP SP2)
1426
1427 // Warning:
1428 // IOCTL_ATA_PASS_THROUGH[_DIRECT] can only handle one interrupt/DRQ data
1429 // transfer per command. Therefore, multi-sector transfers are only supported
1430 // for the READ/WRITE MULTIPLE [EXT] commands. Other commands like READ/WRITE SECTORS
1431 // or READ/WRITE LOG EXT work only with single sector transfers.
1432 // The latter are supported on Vista (only) through new ATA_FLAGS_NO_MULTIPLE.
1433 // See:
1434 // http://social.msdn.microsoft.com/Forums/en-US/storageplatformata/thread/eb408507-f221-455b-9bbb-d1069b29c4da
1435
1436 static int ata_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, IDEREGS * prev_regs, char * data, int datasize)
1437 {
1438 const int max_sectors = 32; // TODO: Allocate dynamic buffer
1439
1440 typedef struct {
1441 ATA_PASS_THROUGH_EX apt;
1442 ULONG Filler;
1443 UCHAR ucDataBuf[max_sectors * 512];
1444 } ATA_PASS_THROUGH_EX_WITH_BUFFERS;
1445
1446 const unsigned char magic = 0xcf;
1447
1448 ATA_PASS_THROUGH_EX_WITH_BUFFERS ab; memset(&ab, 0, sizeof(ab));
1449 ab.apt.Length = sizeof(ATA_PASS_THROUGH_EX);
1450 //ab.apt.PathId = 0;
1451 //ab.apt.TargetId = 0;
1452 //ab.apt.Lun = 0;
1453 ab.apt.TimeOutValue = 10;
1454 unsigned size = offsetof(ATA_PASS_THROUGH_EX_WITH_BUFFERS, ucDataBuf);
1455 ab.apt.DataBufferOffset = size;
1456
1457 if (datasize > 0) {
1458 if (datasize > (int)sizeof(ab.ucDataBuf)) {
1459 errno = EINVAL;
1460 return -1;
1461 }
1462 ab.apt.AtaFlags = ATA_FLAGS_DATA_IN;
1463 ab.apt.DataTransferLength = datasize;
1464 size += datasize;
1465 ab.ucDataBuf[0] = magic;
1466 }
1467 else if (datasize < 0) {
1468 if (-datasize > (int)sizeof(ab.ucDataBuf)) {
1469 errno = EINVAL;
1470 return -1;
1471 }
1472 ab.apt.AtaFlags = ATA_FLAGS_DATA_OUT;
1473 ab.apt.DataTransferLength = -datasize;
1474 size += -datasize;
1475 memcpy(ab.ucDataBuf, data, -datasize);
1476 }
1477 else {
1478 assert(ab.apt.AtaFlags == 0);
1479 assert(ab.apt.DataTransferLength == 0);
1480 }
1481
1482 assert(sizeof(ab.apt.CurrentTaskFile) == sizeof(IDEREGS));
1483 IDEREGS * ctfregs = (IDEREGS *)ab.apt.CurrentTaskFile;
1484 IDEREGS * ptfregs = (IDEREGS *)ab.apt.PreviousTaskFile;
1485 *ctfregs = *regs;
1486
1487 if (prev_regs) {
1488 *ptfregs = *prev_regs;
1489 ab.apt.AtaFlags |= ATA_FLAGS_48BIT_COMMAND;
1490 }
1491
1492 DWORD num_out;
1493 if (!DeviceIoControl(hdevice, IOCTL_ATA_PASS_THROUGH,
1494 &ab, size, &ab, size, &num_out, NULL)) {
1495 long err = GetLastError();
1496 if (ata_debugmode) {
1497 pout(" IOCTL_ATA_PASS_THROUGH failed, Error=%ld\n", err);
1498 print_ide_regs_io(regs, NULL);
1499 }
1500 errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
1501 return -1;
1502 }
1503
1504 // Check ATA status
1505 if (ctfregs->bCommandReg/*Status*/ & (0x01/*Err*/|0x08/*DRQ*/)) {
1506 if (ata_debugmode) {
1507 pout(" IOCTL_ATA_PASS_THROUGH command failed:\n");
1508 print_ide_regs_io(regs, ctfregs);
1509 }
1510 errno = EIO;
1511 return -1;
1512 }
1513
1514 // Check and copy data
1515 if (datasize > 0) {
1516 if ( num_out != size
1517 || (ab.ucDataBuf[0] == magic && !nonempty(ab.ucDataBuf+1, datasize-1))) {
1518 if (ata_debugmode) {
1519 pout(" IOCTL_ATA_PASS_THROUGH output data missing (%lu)\n", num_out);
1520 print_ide_regs_io(regs, ctfregs);
1521 }
1522 errno = EIO;
1523 return -1;
1524 }
1525 memcpy(data, ab.ucDataBuf, datasize);
1526 }
1527
1528 if (ata_debugmode > 1) {
1529 pout(" IOCTL_ATA_PASS_THROUGH suceeded, bytes returned: %lu\n", num_out);
1530 print_ide_regs_io(regs, ctfregs);
1531 }
1532 *regs = *ctfregs;
1533 if (prev_regs)
1534 *prev_regs = *ptfregs;
1535
1536 return 0;
1537 }
1538
1539
1540 /////////////////////////////////////////////////////////////////////////////
1541 // ATA PASS THROUGH via SCSI PASS THROUGH (WinNT4 only)
1542
1543 // undocumented SCSI opcode to for ATA passthrough
1544 #define SCSIOP_ATA_PASSTHROUGH 0xCC
1545
1546 static int ata_via_scsi_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize)
1547 {
1548 typedef struct {
1549 SCSI_PASS_THROUGH spt;
1550 ULONG Filler;
1551 UCHAR ucSenseBuf[32];
1552 UCHAR ucDataBuf[512];
1553 } SCSI_PASS_THROUGH_WITH_BUFFERS;
1554
1555 SCSI_PASS_THROUGH_WITH_BUFFERS sb;
1556 IDEREGS * cdbregs;
1557 unsigned int size;
1558 DWORD num_out;
1559 const unsigned char magic = 0xcf;
1560
1561 memset(&sb, 0, sizeof(sb));
1562 sb.spt.Length = sizeof(SCSI_PASS_THROUGH);
1563 //sb.spt.PathId = 0;
1564 sb.spt.TargetId = 1;
1565 //sb.spt.Lun = 0;
1566 sb.spt.CdbLength = 10; sb.spt.SenseInfoLength = 24;
1567 sb.spt.TimeOutValue = 10;
1568 sb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf);
1569 size = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf);
1570 sb.spt.DataBufferOffset = size;
1571
1572 if (datasize) {
1573 if (datasize > sizeof(sb.ucDataBuf)) {
1574 errno = EINVAL;
1575 return -1;
1576 }
1577 sb.spt.DataIn = SCSI_IOCTL_DATA_IN;
1578 sb.spt.DataTransferLength = datasize;
1579 size += datasize;
1580 sb.ucDataBuf[0] = magic;
1581 }
1582 else {
1583 sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
1584 //sb.spt.DataTransferLength = 0;
1585 }
1586
1587 // Use pseudo SCSI command followed by registers
1588 sb.spt.Cdb[0] = SCSIOP_ATA_PASSTHROUGH;
1589 cdbregs = (IDEREGS *)(sb.spt.Cdb+2);
1590 *cdbregs = *regs;
1591
1592 if (!DeviceIoControl(hdevice, IOCTL_SCSI_PASS_THROUGH,
1593 &sb, size, &sb, size, &num_out, NULL)) {
1594 long err = GetLastError();
1595 if (ata_debugmode)
1596 pout(" ATA via IOCTL_SCSI_PASS_THROUGH failed, Error=%ld\n", err);
1597 errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
1598 return -1;
1599 }
1600
1601 // Cannot check ATA status, because command does not return IDEREGS
1602
1603 // Check and copy data
1604 if (datasize) {
1605 if ( num_out != size
1606 || (sb.ucDataBuf[0] == magic && !nonempty(sb.ucDataBuf+1, datasize-1))) {
1607 if (ata_debugmode) {
1608 pout(" ATA via IOCTL_SCSI_PASS_THROUGH output data missing (%lu)\n", num_out);
1609 print_ide_regs_io(regs, NULL);
1610 }
1611 errno = EIO;
1612 return -1;
1613 }
1614 memcpy(data, sb.ucDataBuf, datasize);
1615 }
1616
1617 if (ata_debugmode > 1) {
1618 pout(" ATA via IOCTL_SCSI_PASS_THROUGH suceeded, bytes returned: %lu\n", num_out);
1619 print_ide_regs_io(regs, NULL);
1620 }
1621 return 0;
1622 }
1623
1624
1625 /////////////////////////////////////////////////////////////////////////////
1626 // SMART IOCTL via SCSI MINIPORT ioctl
1627
1628 // This function is handled by ATAPI port driver (atapi.sys) or by SCSI
1629 // miniport driver (via SCSI port driver scsiport.sys).
1630 // It can be used to skip the missing or broken handling of some SMART
1631 // command codes (e.g. READ_LOG) in the disk class driver (disk.sys)
1632
1633 static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, int datasize)
1634 {
1635 // Select code
1636 DWORD code = 0; const char * name = 0;
1637 if (regs->bCommandReg == ATA_IDENTIFY_DEVICE) {
1638 code = IOCTL_SCSI_MINIPORT_IDENTIFY; name = "IDENTIFY";
1639 }
1640 else if (regs->bCommandReg == ATA_SMART_CMD) switch (regs->bFeaturesReg) {
1641 case ATA_SMART_READ_VALUES:
1642 code = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS; name = "READ_SMART_ATTRIBS"; break;
1643 case ATA_SMART_READ_THRESHOLDS:
1644 code = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS; name = "READ_SMART_THRESHOLDS"; break;
1645 case ATA_SMART_ENABLE:
1646 code = IOCTL_SCSI_MINIPORT_ENABLE_SMART; name = "ENABLE_SMART"; break;
1647 case ATA_SMART_DISABLE:
1648 code = IOCTL_SCSI_MINIPORT_DISABLE_SMART; name = "DISABLE_SMART"; break;
1649 case ATA_SMART_STATUS:
1650 code = IOCTL_SCSI_MINIPORT_RETURN_STATUS; name = "RETURN_STATUS"; break;
1651 case ATA_SMART_AUTOSAVE:
1652 code = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE; name = "ENABLE_DISABLE_AUTOSAVE"; break;
1653 //case ATA_SMART_SAVE: // obsolete since ATA-6, not used by smartmontools
1654 // code = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES; name = "SAVE_ATTRIBUTE_VALUES"; break;
1655 case ATA_SMART_IMMEDIATE_OFFLINE:
1656 code = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS; name = "EXECUTE_OFFLINE_DIAGS"; break;
1657 case ATA_SMART_AUTO_OFFLINE:
1658 code = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE; name = "ENABLE_DISABLE_AUTO_OFFLINE"; break;
1659 case ATA_SMART_READ_LOG_SECTOR:
1660 code = IOCTL_SCSI_MINIPORT_READ_SMART_LOG; name = "READ_SMART_LOG"; break;
1661 case ATA_SMART_WRITE_LOG_SECTOR:
1662 code = IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG; name = "WRITE_SMART_LOG"; break;
1663 }
1664 if (!code) {
1665 errno = ENOSYS;
1666 return -1;
1667 }
1668
1669 // Set SRB
1670 struct {
1671 SRB_IO_CONTROL srbc;
1672 union {
1673 SENDCMDINPARAMS in;
1674 SENDCMDOUTPARAMS out;
1675 } params;
1676 char space[512-1];
1677 } sb;
1678 ASSERT_SIZEOF(sb, sizeof(SRB_IO_CONTROL)+sizeof(SENDCMDINPARAMS)-1+512);
1679 memset(&sb, 0, sizeof(sb));
1680
1681 unsigned size;
1682 if (datasize > 0) {
1683 if (datasize > (int)sizeof(sb.space)+1) {
1684 errno = EINVAL;
1685 return -1;
1686 }
1687 size = datasize;
1688 }
1689 else if (datasize < 0) {
1690 if (-datasize > (int)sizeof(sb.space)+1) {
1691 errno = EINVAL;
1692 return -1;
1693 }
1694 size = -datasize;
1695 memcpy(sb.params.in.bBuffer, data, size);
1696 }
1697 else if (code == IOCTL_SCSI_MINIPORT_RETURN_STATUS)
1698 size = sizeof(IDEREGS);
1699 else
1700 size = 0;
1701 sb.srbc.HeaderLength = sizeof(SRB_IO_CONTROL);
1702 memcpy(sb.srbc.Signature, "SCSIDISK", 8); // atapi.sys
1703 sb.srbc.Timeout = 60; // seconds
1704 sb.srbc.ControlCode = code;
1705 //sb.srbc.ReturnCode = 0;
1706 sb.srbc.Length = sizeof(SENDCMDINPARAMS)-1 + size;
1707 sb.params.in.irDriveRegs = *regs;
1708 sb.params.in.cBufferSize = size;
1709
1710 // Call miniport ioctl
1711 size += sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)-1;
1712 DWORD num_out;
1713 if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
1714 &sb, size, &sb, size, &num_out, NULL)) {
1715 long err = GetLastError();
1716 if (ata_debugmode) {
1717 pout(" IOCTL_SCSI_MINIPORT_%s failed, Error=%ld\n", name, err);
1718 print_ide_regs_io(regs, NULL);
1719 }
1720 errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
1721 return -1;
1722 }
1723
1724 // Check result
1725 if (sb.srbc.ReturnCode) {
1726 if (ata_debugmode) {
1727 pout(" IOCTL_SCSI_MINIPORT_%s failed, ReturnCode=0x%08lx\n", name, sb.srbc.ReturnCode);
1728 print_ide_regs_io(regs, NULL);
1729 }
1730 errno = EIO;
1731 return -1;
1732 }
1733
1734 if (sb.params.out.DriverStatus.bDriverError) {
1735 if (ata_debugmode) {
1736 pout(" IOCTL_SCSI_MINIPORT_%s failed, DriverError=0x%02x, IDEError=0x%02x\n", name,
1737 sb.params.out.DriverStatus.bDriverError, sb.params.out.DriverStatus.bIDEError);
1738 print_ide_regs_io(regs, NULL);
1739 }
1740 errno = (!sb.params.out.DriverStatus.bIDEError ? ENOSYS : EIO);
1741 return -1;
1742 }
1743
1744 if (ata_debugmode > 1) {
1745 pout(" IOCTL_SCSI_MINIPORT_%s suceeded, bytes returned: %lu (buffer %lu)\n", name,
1746 num_out, sb.params.out.cBufferSize);
1747 print_ide_regs_io(regs, (code == IOCTL_SCSI_MINIPORT_RETURN_STATUS ?
1748 (const IDEREGS *)(sb.params.out.bBuffer) : 0));
1749 }
1750
1751 if (datasize > 0)
1752 memcpy(data, sb.params.out.bBuffer, datasize);
1753 else if (datasize == 0 && code == IOCTL_SCSI_MINIPORT_RETURN_STATUS)
1754 memcpy(regs, sb.params.out.bBuffer, sizeof(IDEREGS));
1755
1756 return 0;
1757 }
1758
1759
1760 /////////////////////////////////////////////////////////////////////////////
1761
1762 // ATA PASS THROUGH via 3ware specific SCSI MINIPORT ioctl
1763
1764 static int ata_via_3ware_miniport_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, int datasize, int port)
1765 {
1766 struct {
1767 SRB_IO_CONTROL srbc;
1768 IDEREGS regs;
1769 UCHAR buffer[512];
1770 } sb;
1771 ASSERT_SIZEOF(sb, sizeof(SRB_IO_CONTROL)+sizeof(IDEREGS)+512);
1772
1773 if (!(0 <= datasize && datasize <= (int)sizeof(sb.buffer) && port >= 0)) {
1774 errno = EINVAL;
1775 return -1;
1776 }
1777 memset(&sb, 0, sizeof(sb));
1778 strcpy((char *)sb.srbc.Signature, "<3ware>");
1779 sb.srbc.HeaderLength = sizeof(SRB_IO_CONTROL);
1780 sb.srbc.Timeout = 60; // seconds
1781 sb.srbc.ControlCode = 0xA0000000;
1782 sb.srbc.ReturnCode = 0;
1783 sb.srbc.Length = sizeof(IDEREGS) + (datasize > 0 ? datasize : 1);
1784 sb.regs = *regs;
1785 sb.regs.bReserved = port;
1786
1787 DWORD num_out;
1788 if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
1789 &sb, sizeof(sb), &sb, sizeof(sb), &num_out, NULL)) {
1790 long err = GetLastError();
1791 if (ata_debugmode) {
1792 pout(" ATA via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err);
1793 print_ide_regs_io(regs, NULL);
1794 }
1795 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
1796 return -1;
1797 }
1798
1799 if (sb.srbc.ReturnCode) {
1800 if (ata_debugmode) {
1801 pout(" ATA via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08lx\n", sb.srbc.ReturnCode);
1802 print_ide_regs_io(regs, NULL);
1803 }
1804 errno = EIO;
1805 return -1;
1806 }
1807
1808 // Copy data
1809 if (datasize > 0)
1810 memcpy(data, sb.buffer, datasize);
1811
1812 if (ata_debugmode > 1) {
1813 pout(" ATA via IOCTL_SCSI_MINIPORT suceeded, bytes returned: %lu\n", num_out);
1814 print_ide_regs_io(regs, &sb.regs);
1815 }
1816 *regs = sb.regs;
1817
1818 return 0;
1819 }
1820
1821
1822 /////////////////////////////////////////////////////////////////////////////
1823
1824 // 3ware specific call to update the devicemap returned by SMART_GET_VERSION.
1825 // 3DM/CLI "Rescan Controller" function does not to always update it.
1826
1827 static int update_3ware_devicemap_ioctl(HANDLE hdevice)
1828 {
1829 SRB_IO_CONTROL srbc;
1830 memset(&srbc, 0, sizeof(srbc));
1831 strcpy((char *)srbc.Signature, "<3ware>");
1832 srbc.HeaderLength = sizeof(SRB_IO_CONTROL);
1833 srbc.Timeout = 60; // seconds
1834 srbc.ControlCode = 0xCC010014;
1835 srbc.ReturnCode = 0;
1836 srbc.Length = 0;
1837
1838 DWORD num_out;
1839 if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
1840 &srbc, sizeof(srbc), &srbc, sizeof(srbc), &num_out, NULL)) {
1841 long err = GetLastError();
1842 if (ata_debugmode)
1843 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err);
1844 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
1845 return -1;
1846 }
1847 if (srbc.ReturnCode) {
1848 if (ata_debugmode)
1849 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08lx\n", srbc.ReturnCode);
1850 errno = EIO;
1851 return -1;
1852 }
1853 if (ata_debugmode > 1)
1854 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT suceeded\n");
1855 return 0;
1856 }
1857
1858
1859
1860 /////////////////////////////////////////////////////////////////////////////
1861
1862 // Routines for pseudo device /dev/tw_cli/*
1863 // Parses output of 3ware "tw_cli /cx/py show all" or 3DM SMART data window
1864
1865
1866 // Get clipboard data
1867
1868 static int get_clipboard(char * data, int datasize)
1869 {
1870 if (!OpenClipboard(NULL))
1871 return -1;
1872 HANDLE h = GetClipboardData(CF_TEXT);
1873 if (!h) {
1874 CloseClipboard();
1875 return 0;
1876 }
1877 const void * p = GlobalLock(h);
1878 int n = GlobalSize(h);
1879 if (n > datasize)
1880 n = datasize;
1881 memcpy(data, p, n);
1882 GlobalFree(h);
1883 CloseClipboard();
1884 return n;
1885 }
1886
1887
1888 // Run a command, write stdout to dataout
1889 // TODO: Combine with daemon_win32.cpp:daemon_spawn()
1890
1891 static int run_cmd(const char * cmd, char * dataout, int outsize)
1892 {
1893 // Create stdout pipe
1894 SECURITY_ATTRIBUTES sa = {sizeof(sa), 0, TRUE};
1895 HANDLE pipe_out_w, h;
1896 if (!CreatePipe(&h, &pipe_out_w, &sa/*inherit*/, outsize))
1897 return -1;
1898 HANDLE self = GetCurrentProcess();
1899 HANDLE pipe_out_r;
1900 if (!DuplicateHandle(self, h, self, &pipe_out_r,
1901 GENERIC_READ, FALSE/*!inherit*/, DUPLICATE_CLOSE_SOURCE)) {
1902 CloseHandle(pipe_out_w);
1903 return -1;
1904 }
1905 HANDLE pipe_err_w;
1906 if (!DuplicateHandle(self, pipe_out_w, self, &pipe_err_w,
1907 0, TRUE/*inherit*/, DUPLICATE_SAME_ACCESS)) {
1908 CloseHandle(pipe_out_r); CloseHandle(pipe_out_w);
1909 return -1;
1910 }
1911
1912 // Create process
1913 STARTUPINFO si; memset(&si, 0, sizeof(si)); si.cb = sizeof(si);
1914 si.hStdInput = INVALID_HANDLE_VALUE;
1915 si.hStdOutput = pipe_out_w; si.hStdError = pipe_err_w;
1916 si.dwFlags = STARTF_USESTDHANDLES;
1917 PROCESS_INFORMATION pi;
1918 if (!CreateProcess(
1919 NULL, const_cast<char *>(cmd),
1920 NULL, NULL, TRUE/*inherit*/,
1921 CREATE_NO_WINDOW/*do not create a new console window*/,
1922 NULL, NULL, &si, &pi)) {
1923 CloseHandle(pipe_err_w); CloseHandle(pipe_out_r); CloseHandle(pipe_out_w);
1924 return -1;
1925 }
1926 CloseHandle(pi.hThread);
1927 CloseHandle(pipe_err_w); CloseHandle(pipe_out_w);
1928
1929 // Copy stdout to output buffer
1930 int i = 0;
1931 while (i < outsize) {
1932 DWORD num_read;
1933 if (!ReadFile(pipe_out_r, dataout+i, outsize-i, &num_read, NULL) || num_read == 0)
1934 break;
1935 i += num_read;
1936 }
1937 CloseHandle(pipe_out_r);
1938 // Wait for process
1939 WaitForSingleObject(pi.hProcess, INFINITE);
1940 CloseHandle(pi.hProcess);
1941 return i;
1942 }
1943
1944
1945 static const char * findstr(const char * str, const char * sub)
1946 {
1947 const char * s = strstr(str, sub);
1948 return (s ? s+strlen(sub) : "");
1949 }
1950
1951
1952 static void copy_swapped(unsigned char * dest, const char * src, int destsize)
1953 {
1954 int srclen = strcspn(src, "\r\n");
1955 int i;
1956 for (i = 0; i < destsize-1 && i < srclen-1; i+=2) {
1957 dest[i] = src[i+1]; dest[i+1] = src[i];
1958 }
1959 if (i < destsize-1 && i < srclen)
1960 dest[i+1] = src[i];
1961 }
1962
1963
1964 // TODO: This is OS independent
1965
1966 win_tw_cli_device::win_tw_cli_device(smart_interface * intf, const char * dev_name, const char * req_type)
1967 : smart_device(intf, dev_name, "tw_cli", req_type),
1968 m_ident_valid(false), m_smart_valid(false)
1969 {
1970 memset(&m_ident_buf, 0, sizeof(m_ident_buf));
1971 memset(&m_smart_buf, 0, sizeof(m_smart_buf));
1972 }
1973
1974
1975 bool win_tw_cli_device::is_open() const
1976 {
1977 return (m_ident_valid || m_smart_valid);
1978 }
1979
1980
1981 bool win_tw_cli_device::open()
1982 {
1983 m_ident_valid = m_smart_valid = false;
1984 const char * name = skipdev(get_dev_name());
1985 // Read tw_cli or 3DM browser output into buffer
1986 char buffer[4096];
1987 int size = -1, n1 = -1, n2 = -1;
1988 if (!strcmp(name, "tw_cli/clip")) { // read clipboard
1989 size = get_clipboard(buffer, sizeof(buffer));
1990 }
1991 else if (!strcmp(name, "tw_cli/stdin")) { // read stdin
1992 size = fread(buffer, 1, sizeof(buffer), stdin);
1993 }
1994 else if (sscanf(name, "tw_cli/%nc%*u/p%*u%n", &n1, &n2) >= 0 && n2 == (int)strlen(name)) {
1995 // tw_cli/cx/py => read output from "tw_cli /cx/py show all"
1996 char cmd[100];
1997 snprintf(cmd, sizeof(cmd), "tw_cli /%s show all", name+n1);
1998 if (ata_debugmode > 1)
1999 pout("%s: Run: \"%s\"\n", name, cmd);
2000 size = run_cmd(cmd, buffer, sizeof(buffer));
2001 }
2002 else {
2003 return set_err(EINVAL);
2004 }
2005
2006 if (ata_debugmode > 1)
2007 pout("%s: Read %d bytes\n", name, size);
2008 if (size <= 0)
2009 return set_err(ENOENT);
2010 if (size >= (int)sizeof(buffer))
2011 return set_err(EIO);
2012
2013 buffer[size] = 0;
2014 if (ata_debugmode > 1)
2015 pout("[\n%.100s%s\n]\n", buffer, (size>100?"...":""));
2016
2017 // Fake identify sector
2018 ASSERT_SIZEOF(ata_identify_device, 512);
2019 ata_identify_device * id = &m_ident_buf;
2020 memset(id, 0, sizeof(*id));
2021 copy_swapped(id->model , findstr(buffer, " Model = " ), sizeof(id->model));
2022 copy_swapped(id->fw_rev , findstr(buffer, " Firmware Version = "), sizeof(id->fw_rev));
2023 copy_swapped(id->serial_no, findstr(buffer, " Serial = " ), sizeof(id->serial_no));
2024 unsigned long nblocks = 0; // "Capacity = N.N GB (N Blocks)"
2025 sscanf(findstr(buffer, "Capacity = "), "%*[^(\r\n](%lu", &nblocks);
2026 if (nblocks) {
2027 id->words047_079[49-47] = 0x0200; // size valid
2028 id->words047_079[60-47] = (unsigned short)(nblocks ); // secs_16
2029 id->words047_079[61-47] = (unsigned short)(nblocks>>16); // secs_32
2030 }
2031 id->command_set_1 = 0x0001; id->command_set_2 = 0x4000; // SMART supported, words 82,83 valid
2032 id->cfs_enable_1 = 0x0001; id->csf_default = 0x4000; // SMART enabled, words 85,87 valid
2033
2034 // Parse smart data hex dump
2035 const char * s = findstr(buffer, "Drive Smart Data:");
2036 if (!*s)
2037 s = findstr(buffer, "Drive SMART Data:"); // tw_cli from 9.5.x
2038 if (!*s) {
2039 s = findstr(buffer, "S.M.A.R.T. (Controller"); // from 3DM browser window
2040 if (*s) {
2041 const char * s1 = findstr(s, "<td class"); // html version
2042 if (*s1)
2043 s = s1;
2044 s += strcspn(s, "\r\n");
2045 }
2046 else
2047 s = buffer; // try raw hex dump without header
2048 }
2049 unsigned char * sd = (unsigned char *)&m_smart_buf;
2050 int i = 0;
2051 for (;;) {
2052 unsigned x = ~0; int n = -1;
2053 if (!(sscanf(s, "%x %n", &x, &n) == 1 && !(x & ~0xff)))
2054 break;
2055 sd[i] = (unsigned char)x;
2056 if (!(++i < 512 && n > 0))
2057 break;
2058 s += n;
2059 if (*s == '<') // "<br>"
2060 s += strcspn(s, "\r\n");
2061 }
2062 if (i < 512) {
2063 if (!id->model[1]) {
2064 // No useful data found
2065 char * err = strstr(buffer, "Error:");
2066 if (!err)
2067 err = strstr(buffer, "error :");
2068 if (err && (err = strchr(err, ':'))) {
2069 // Show tw_cli error message
2070 err++;
2071 err[strcspn(err, "\r\n")] = 0;
2072 return set_err(EIO, "%s", err);
2073 }
2074 return set_err(EIO);
2075 }
2076 sd = 0;
2077 }
2078
2079 m_ident_valid = true;
2080 m_smart_valid = !!sd;
2081 return true;
2082 }
2083
2084
2085 bool win_tw_cli_device::close()
2086 {
2087 m_ident_valid = m_smart_valid = false;
2088 return true;
2089 }
2090
2091
2092 int win_tw_cli_device::ata_command_interface(smart_command_set command, int /*select*/, char * data)
2093 {
2094 switch (command) {
2095 case IDENTIFY:
2096 if (!m_ident_valid)
2097 break;
2098 memcpy(data, &m_ident_buf, 512);
2099 return 0;
2100 case READ_VALUES:
2101 if (!m_smart_valid)
2102 break;
2103 memcpy(data, &m_smart_buf, 512);
2104 return 0;
2105 case ENABLE:
2106 case STATUS:
2107 case STATUS_CHECK: // Fake "good" SMART status
2108 return 0;
2109 default:
2110 break;
2111 }
2112 // Arrive here for all unsupported commands
2113 set_err(ENOSYS);
2114 return -1;
2115 }
2116
2117
2118 /////////////////////////////////////////////////////////////////////////////
2119 // IOCTL_STORAGE_QUERY_PROPERTY
2120
2121 union STORAGE_DEVICE_DESCRIPTOR_DATA {
2122 STORAGE_DEVICE_DESCRIPTOR desc;
2123 char raw[256];
2124 };
2125
2126 // Get STORAGE_DEVICE_DESCRIPTOR_DATA for device.
2127 // (This works without admin rights)
2128
2129 static int storage_query_property_ioctl(HANDLE hdevice, STORAGE_DEVICE_DESCRIPTOR_DATA * data)
2130 {
2131 STORAGE_PROPERTY_QUERY query = {StorageDeviceProperty, PropertyStandardQuery, {0} };
2132 memset(data, 0, sizeof(*data));
2133
2134 DWORD num_out;
2135 if (!DeviceIoControl(hdevice, IOCTL_STORAGE_QUERY_PROPERTY,
2136 &query, sizeof(query), data, sizeof(*data), &num_out, NULL)) {
2137 if (ata_debugmode > 1 || scsi_debugmode > 1)
2138 pout(" IOCTL_STORAGE_QUERY_PROPERTY failed, Error=%ld\n", GetLastError());
2139 errno = ENOSYS;
2140 return -1;
2141 }
2142
2143 if (ata_debugmode > 1 || scsi_debugmode > 1) {
2144 pout(" IOCTL_STORAGE_QUERY_PROPERTY returns:\n"
2145 " Vendor: \"%s\"\n"
2146 " Product: \"%s\"\n"
2147 " Revision: \"%s\"\n"
2148 " Removable: %s\n"
2149 " BusType: 0x%02x\n",
2150 (data->desc.VendorIdOffset ? data->raw+data->desc.VendorIdOffset : "(null)"),
2151 (data->desc.ProductIdOffset ? data->raw+data->desc.ProductIdOffset : "(null)"),
2152 (data->desc.ProductRevisionOffset ? data->raw+data->desc.ProductRevisionOffset : "(null)"),
2153 (data->desc.RemovableMedia? "Yes":"No"), data->desc.BusType
2154 );
2155 }
2156 return 0;
2157 }
2158
2159
2160 /////////////////////////////////////////////////////////////////////////////
2161 // IOCTL_STORAGE_PREDICT_FAILURE
2162
2163 // Call IOCTL_STORAGE_PREDICT_FAILURE, return PredictFailure value
2164 // or -1 on error, opionally return VendorSpecific data.
2165 // (This works without admin rights)
2166
2167 static int storage_predict_failure_ioctl(HANDLE hdevice, char * data = 0)
2168 {
2169 STORAGE_PREDICT_FAILURE pred;
2170 memset(&pred, 0, sizeof(pred));
2171
2172 DWORD num_out;
2173 if (!DeviceIoControl(hdevice, IOCTL_STORAGE_PREDICT_FAILURE,
2174 0, 0, &pred, sizeof(pred), &num_out, NULL)) {
2175 if (ata_debugmode > 1)
2176 pout(" IOCTL_STORAGE_PREDICT_FAILURE failed, Error=%ld\n", GetLastError());
2177 errno = ENOSYS;
2178 return -1;
2179 }
2180
2181 if (ata_debugmode > 1) {
2182 pout(" IOCTL_STORAGE_PREDICT_FAILURE returns:\n"
2183 " PredictFailure: 0x%08lx\n"
2184 " VendorSpecific: 0x%02x,0x%02x,0x%02x,...,0x%02x\n",
2185 pred.PredictFailure,
2186 pred.VendorSpecific[0], pred.VendorSpecific[1], pred.VendorSpecific[2],
2187 pred.VendorSpecific[sizeof(pred.VendorSpecific)-1]
2188 );
2189 }
2190 if (data)
2191 memcpy(data, pred.VendorSpecific, sizeof(pred.VendorSpecific));
2192 return (!pred.PredictFailure ? 0 : 1);
2193 }
2194
2195
2196 /////////////////////////////////////////////////////////////////////////////
2197
2198 // Return true if Intel ICHxR RAID volume
2199 static bool is_intel_raid_volume(const STORAGE_DEVICE_DESCRIPTOR_DATA * data)
2200 {
2201 if (!(data->desc.VendorIdOffset && data->desc.ProductIdOffset))
2202 return false;
2203 const char * vendor = data->raw + data->desc.VendorIdOffset;
2204 if (!(!strnicmp(vendor, "Intel", 5) && strspn(vendor+5, " ") == strlen(vendor+5)))
2205 return false;
2206 if (strnicmp(data->raw + data->desc.ProductIdOffset, "Raid ", 5))
2207 return false;
2208 return true;
2209 }
2210
2211 // get DEV_* for open handle
2212 static win_dev_type get_controller_type(HANDLE hdevice, bool admin, GETVERSIONINPARAMS_EX * ata_version_ex)
2213 {
2214 // Get BusType from device descriptor
2215 STORAGE_DEVICE_DESCRIPTOR_DATA data;
2216 if (storage_query_property_ioctl(hdevice, &data))
2217 return DEV_UNKNOWN;
2218
2219 // Newer BusType* values are missing in older includes
2220 switch ((int)data.desc.BusType) {
2221 case BusTypeAta:
2222 case 0x0b: // BusTypeSata
2223 if (ata_version_ex)
2224 memset(ata_version_ex, 0, sizeof(*ata_version_ex));
2225 return DEV_ATA;
2226
2227 case BusTypeScsi:
2228 case BusTypeRAID:
2229 // Intel ICHxR RAID volume: reports SMART_GET_VERSION but does not support SMART_*
2230 if (is_intel_raid_volume(&data))
2231 return DEV_SCSI;
2232 // LSI/3ware RAID volume: supports SMART_*
2233 if (admin && smart_get_version(hdevice, ata_version_ex) >= 0)
2234 return DEV_ATA;
2235 return DEV_SCSI;
2236
2237 case 0x09: // BusTypeiScsi
2238 case 0x0a: // BusTypeSas
2239 return DEV_SCSI;
2240
2241 case BusTypeUsb:
2242 return DEV_USB;
2243
2244 default:
2245 return DEV_UNKNOWN;
2246 }
2247 /*NOTREACHED*/
2248 }
2249
2250 // get DEV_* for device path
2251 static win_dev_type get_controller_type(const char * path, GETVERSIONINPARAMS_EX * ata_version_ex = 0)
2252 {
2253 bool admin = true;
2254 HANDLE h = CreateFileA(path, GENERIC_READ|GENERIC_WRITE,
2255 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
2256 if (h == INVALID_HANDLE_VALUE) {
2257 admin = false;
2258 h = CreateFileA(path, 0,
2259 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
2260 if (h == INVALID_HANDLE_VALUE)
2261 return DEV_UNKNOWN;
2262 }
2263 if (ata_debugmode > 1 || scsi_debugmode > 1)
2264 pout(" %s: successfully opened%s\n", path, (!admin ? " (without admin rights)" :""));
2265 win_dev_type type = get_controller_type(h, admin, ata_version_ex);
2266 CloseHandle(h);
2267 return type;
2268 }
2269
2270 // get DEV_* for physical drive number
2271 static win_dev_type get_phy_drive_type(int drive, GETVERSIONINPARAMS_EX * ata_version_ex)
2272 {
2273 char path[30];
2274 snprintf(path, sizeof(path)-1, "\\\\.\\PhysicalDrive%d", drive);
2275 return get_controller_type(path, ata_version_ex);
2276 }
2277
2278 static win_dev_type get_phy_drive_type(int drive)
2279 {
2280 return get_phy_drive_type(drive, 0);
2281 }
2282
2283 // get DEV_* for logical drive number
2284 static win_dev_type get_log_drive_type(int drive)
2285 {
2286 char path[30];
2287 snprintf(path, sizeof(path)-1, "\\\\.\\%c:", 'A'+drive);
2288 return get_controller_type(path);
2289 }
2290
2291 // Build IDENTIFY information from STORAGE_DEVICE_DESCRIPTOR
2292 static int get_identify_from_device_property(HANDLE hdevice, ata_identify_device * id)
2293 {
2294 STORAGE_DEVICE_DESCRIPTOR_DATA data;
2295 if (storage_query_property_ioctl(hdevice, &data))
2296 return -1;
2297
2298 memset(id, 0, sizeof(*id));
2299
2300 // Some drivers split ATA model string into VendorId and ProductId,
2301 // others return it as ProductId only.
2302 char model[sizeof(id->model) + 1] = "";
2303
2304 unsigned i = 0;
2305 if (data.desc.VendorIdOffset) {
2306 for ( ;i < sizeof(model)-1 && data.raw[data.desc.VendorIdOffset+i]; i++)
2307 model[i] = data.raw[data.desc.VendorIdOffset+i];
2308 }
2309
2310 if (data.desc.ProductIdOffset) {
2311 while (i > 1 && model[i-2] == ' ') // Keep last blank from VendorId
2312 i--;
2313 // Ignore VendorId "ATA"
2314 if (i <= 4 && !strncmp(model, "ATA", 3) && (i == 3 || model[3] == ' '))
2315 i = 0;
2316 for (unsigned j = 0; i < sizeof(model)-1 && data.raw[data.desc.ProductIdOffset+j]; i++, j++)
2317 model[i] = data.raw[data.desc.ProductIdOffset+j];
2318 }
2319
2320 while (i > 0 && model[i-1] == ' ')
2321 i--;
2322 model[i] = 0;
2323 copy_swapped(id->model, model, sizeof(id->model));
2324
2325 if (data.desc.ProductRevisionOffset)
2326 copy_swapped(id->fw_rev, data.raw+data.desc.ProductRevisionOffset, sizeof(id->fw_rev));
2327
2328 id->command_set_1 = 0x0001; id->command_set_2 = 0x4000; // SMART supported, words 82,83 valid
2329 id->cfs_enable_1 = 0x0001; id->csf_default = 0x4000; // SMART enabled, words 85,87 valid
2330 return 0;
2331 }
2332
2333
2334 /////////////////////////////////////////////////////////////////////////////
2335 // USB ID detection using WMI
2336
2337 // Get USB ID for a physical drive number
2338 static bool get_usb_id(int drive, unsigned short & vendor_id, unsigned short & product_id)
2339 {
2340 bool debug = (scsi_debugmode > 1);
2341
2342 wbem_services ws;
2343 if (!ws.connect()) {
2344 if (debug)
2345 pout("WMI connect failed\n");
2346 return false;
2347 }
2348
2349 // Get device name
2350 wbem_object wo;
2351 if (!ws.query1(wo, "SELECT Model FROM Win32_DiskDrive WHERE DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", drive))
2352 return false;
2353
2354 std::string name = wo.get_str("Model");
2355 if (debug)
2356 pout("PhysicalDrive%d, \"%s\":\n", drive, name.c_str());
2357
2358 // Get USB_CONTROLLER -> DEVICE associations
2359 wbem_enumerator we;
2360 if (!ws.query(we, "SELECT Antecedent,Dependent FROM Win32_USBControllerDevice"))
2361 return false;
2362
2363 unsigned short usb_venid = 0, prev_usb_venid = 0;
2364 unsigned short usb_proid = 0, prev_usb_proid = 0;
2365 std::string prev_usb_ant;
2366 std::string prev_ant, ant, dep;
2367
2368 const regular_expression regex("^.*PnPEntity\\.DeviceID=\"([^\"]*)\"", REG_EXTENDED);
2369
2370 while (we.next(wo)) {
2371 prev_ant = ant;
2372 // Find next 'USB_CONTROLLER, DEVICE' pair
2373 ant = wo.get_str("Antecedent");
2374 dep = wo.get_str("Dependent");
2375
2376 if (debug && ant != prev_ant)
2377 pout(" %s:\n", ant.c_str());
2378
2379 // Extract DeviceID
2380 regmatch_t match[2];
2381 if (!(regex.execute(dep.c_str(), 2, match) && match[1].rm_so >= 0)) {
2382 if (debug)
2383 pout(" | (\"%s\")\n", dep.c_str());
2384 continue;
2385 }
2386
2387 std::string devid(dep.c_str()+match[1].rm_so, match[1].rm_eo-match[1].rm_so);
2388
2389 if (str_starts_with(devid, "USB\\\\VID_")) {
2390 // USB bridge entry, save CONTROLLER, ID
2391 int nc = -1;
2392 if (!(sscanf(devid.c_str(), "USB\\\\VID_%4hx&PID_%4hx%n",
2393 &prev_usb_venid, &prev_usb_proid, &nc) == 2 && nc == 9+4+5+4)) {
2394 prev_usb_venid = prev_usb_proid = 0;
2395 }
2396 prev_usb_ant = ant;
2397 if (debug)
2398 pout(" +-> \"%s\" [0x%04x:0x%04x]\n", devid.c_str(), prev_usb_venid, prev_usb_proid);
2399 continue;
2400 }
2401 else if (str_starts_with(devid, "USBSTOR\\\\")) {
2402 // USBSTOR device found
2403 if (debug)
2404 pout(" +--> \"%s\"\n", devid.c_str());
2405
2406 // Retrieve name
2407 wbem_object wo2;
2408 if (!ws.query1(wo2, "SELECT Name FROM Win32_PnPEntity WHERE DeviceID=\"%s\"", devid.c_str()))
2409 continue;
2410 std::string name2 = wo2.get_str("Name");
2411
2412 // Continue if not name of physical disk drive
2413 if (name2 != name) {
2414 if (debug)
2415 pout(" +---> (\"%s\")\n", name2.c_str());
2416 continue;
2417 }
2418
2419 // Fail if previos USB bridge is associated to other controller or ID is unknown
2420 if (!(ant == prev_usb_ant && prev_usb_venid)) {
2421 if (debug)
2422 pout(" +---> \"%s\" (Error: No USB bridge found)\n", name2.c_str());
2423 return false;
2424 }
2425
2426 // Handle multiple devices with same name
2427 if (usb_venid) {
2428 // Fail if multiple devices with same name have different USB bridge types
2429 if (!(usb_venid == prev_usb_venid && usb_proid == prev_usb_proid)) {
2430 if (debug)
2431 pout(" +---> \"%s\" (Error: More than one USB ID found)\n", name2.c_str());
2432 return false;
2433 }
2434 }
2435
2436 // Found
2437 usb_venid = prev_usb_venid;
2438 usb_proid = prev_usb_proid;
2439 if (debug)
2440 pout(" +===> \"%s\" [0x%04x:0x%04x]\n", name2.c_str(), usb_venid, usb_proid);
2441
2442 // Continue to check for duplicate names ...
2443 }
2444 else {
2445 if (debug)
2446 pout(" | \"%s\"\n", devid.c_str());
2447 }
2448 }
2449
2450 if (!usb_venid)
2451 return false;
2452
2453 vendor_id = usb_venid;
2454 product_id = usb_proid;
2455
2456 return true;
2457 }
2458
2459
2460 /////////////////////////////////////////////////////////////////////////////
2461
2462 // Call GetDevicePowerState() if available (Win98/ME/2000/XP/2003)
2463 // returns: 1=active, 0=standby, -1=error
2464 // (This would also work for SCSI drives)
2465
2466 static int get_device_power_state(HANDLE hdevice)
2467 {
2468 static bool unsupported = false;
2469 if (unsupported) {
2470 errno = ENOSYS;
2471 return -1;
2472 }
2473
2474 #ifdef __CYGWIN__
2475 static DWORD kernel_dll_pid = 0;
2476 #endif
2477 static BOOL (WINAPI * GetDevicePowerState_p)(HANDLE, BOOL *) = 0;
2478
2479 if (!GetDevicePowerState_p
2480 #ifdef __CYGWIN__
2481 || kernel_dll_pid != GetCurrentProcessId() // detect fork()
2482 #endif
2483 ) {
2484 if (!(GetDevicePowerState_p = (BOOL (WINAPI *)(HANDLE, BOOL *))
2485 GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetDevicePowerState"))) {
2486 if (ata_debugmode)
2487 pout(" GetDevicePowerState() not found, Error=%ld\n", GetLastError());
2488 unsupported = true;
2489 errno = ENOSYS;
2490 return -1;
2491 }
2492 #ifdef __CYGWIN__
2493 kernel_dll_pid = GetCurrentProcessId();
2494 #endif
2495 }
2496
2497 BOOL state = TRUE;
2498 if (!GetDevicePowerState_p(hdevice, &state)) {
2499 long err = GetLastError();
2500 if (ata_debugmode)
2501 pout(" GetDevicePowerState() failed, Error=%ld\n", err);
2502 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
2503 // TODO: This may not work as expected on transient errors,
2504 // because smartd interprets -1 as SLEEP mode regardless of errno.
2505 return -1;
2506 }
2507
2508 if (ata_debugmode > 1)
2509 pout(" GetDevicePowerState() succeeded, state=%d\n", state);
2510 return state;
2511 }
2512
2513
2514 /////////////////////////////////////////////////////////////////////////////
2515
2516 #if WIN9X_SUPPORT
2517 // Print SMARTVSD error message, return errno
2518
2519 static int smartvsd_error()
2520 {
2521 char path[MAX_PATH];
2522 unsigned len;
2523 if (!(5 <= (len = GetSystemDirectoryA(path, MAX_PATH)) && len < MAX_PATH/2))
2524 return ENOENT;
2525 // SMARTVSD.VXD present?
2526 strcpy(path+len, "\\IOSUBSYS\\SMARTVSD.VXD");
2527 if (!access(path, 0)) {
2528 // Yes, standard IDE driver used?
2529 HANDLE h;
2530 if ( (h = CreateFileA("\\\\.\\ESDI_506",
2531 GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
2532 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE
2533 && GetLastError() == ERROR_FILE_NOT_FOUND ) {
2534 pout("Standard IDE driver ESDI_506.PDR not used, or no IDE/ATA drives present.\n");
2535 return ENOENT;
2536 }
2537 else {
2538 if (h != INVALID_HANDLE_VALUE) // should not happen
2539 CloseHandle(h);
2540 pout("SMART driver SMARTVSD.VXD is installed, but not loaded.\n");
2541 return ENOSYS;
2542 }
2543 }
2544 else {
2545 strcpy(path+len, "\\SMARTVSD.VXD");
2546 if (!access(path, 0)) {
2547 // Some Windows versions install SMARTVSD.VXD in SYSTEM directory
2548 // (http://support.microsoft.com/kb/265854/en-us).
2549 path[len] = 0;
2550 pout("SMART driver is not properly installed,\n"
2551 " move SMARTVSD.VXD from \"%s\" to \"%s\\IOSUBSYS\"\n"
2552 " and reboot Windows.\n", path, path);
2553 }
2554 else {
2555 // Some Windows versions do not provide SMARTVSD.VXD
2556 // (http://support.microsoft.com/kb/199886/en-us).
2557 path[len] = 0;
2558 pout("SMARTVSD.VXD is missing in folder \"%s\\IOSUBSYS\".\n", path);
2559 }
2560 return ENOSYS;
2561 }
2562 }
2563
2564 #endif // WIN9X_SUPPORT
2565
2566 // Get default ATA device options
2567
2568 static const char * ata_get_def_options()
2569 {
2570 DWORD ver = GetVersion();
2571 if ((ver & 0x80000000) || (ver & 0xff) < 4) // Win9x/ME
2572 return "s"; // SMART_* only
2573 else if ((ver & 0xff) == 4) // WinNT4
2574 return "sc"; // SMART_*, SCSI_PASS_THROUGH
2575 else // WinXP, 2003, Vista
2576 return "pasifm"; // GetDevicePowerState(), ATA_, SMART_*, IDE_PASS_THROUGH,
2577 // STORAGE_*, SCSI_MINIPORT_*
2578 }
2579
2580
2581 // Common routines for devices with HANDLEs
2582
2583 win_smart_device::~win_smart_device() throw()
2584 {
2585 if (m_fh != INVALID_HANDLE_VALUE)
2586 ::CloseHandle(m_fh);
2587 }
2588
2589 bool win_smart_device::is_open() const
2590 {
2591 return (m_fh != INVALID_HANDLE_VALUE);
2592 }
2593
2594 bool win_smart_device::close()
2595 {
2596 if (m_fh == INVALID_HANDLE_VALUE)
2597 return true;
2598 BOOL rc = ::CloseHandle(m_fh);
2599 m_fh = INVALID_HANDLE_VALUE;
2600 return !!rc;
2601 }
2602
2603 // ATA
2604
2605 win_ata_device::win_ata_device(smart_interface * intf, const char * dev_name, const char * req_type)
2606 : smart_device(intf, dev_name, "ata", req_type),
2607 m_usr_options(false),
2608 m_admin(false),
2609 m_id_is_cached(false),
2610 m_is_3ware(false),
2611 m_drive(0),
2612 m_port(-1),
2613 m_smartver_state(0)
2614 {
2615 }
2616
2617 win_ata_device::~win_ata_device() throw()
2618 {
2619 }
2620
2621
2622 // Open ATA device
2623
2624 bool win_ata_device::open()
2625 {
2626 const char * name = skipdev(get_dev_name()); int len = strlen(name);
2627 // [sh]d[a-z](:[saicmfp]+)? => Physical drive 0-25, with options
2628 char drive[1+1] = "", options[8+1] = ""; int n1 = -1, n2 = -1;
2629 if ( sscanf(name, "%*[sh]d%1[a-z]%n:%7[saicmfp]%n", drive, &n1, options, &n2) >= 1
2630 && ((n1 == len && !options[0]) || n2 == len) ) {
2631 return open(drive[0] - 'a', -1, options, -1);
2632 }
2633 // [sh]d[a-z],N(:[saicmfp3]+)? => Physical drive 0-25, RAID port N, with options
2634 drive[0] = 0; options[0] = 0; n1 = -1; n2 = -1;
2635 unsigned port = ~0;
2636 if ( sscanf(name, "%*[sh]d%1[a-z],%u%n:%8[saicmfp3]%n", drive, &port, &n1, options, &n2) >= 2
2637 && port < 32 && ((n1 == len && !options[0]) || n2 == len) ) {
2638 return open(drive[0] - 'a', -1, options, port);
2639 }
2640 // pd<m>,N => Physical drive <m>, RAID port N
2641 int phydrive = -1; port = ~0; n1 = -1; n2 = -1;
2642 if ( sscanf(name, "pd%d%n,%u%n", &phydrive, &n1, &port, &n2) >= 1
2643 && phydrive >= 0 && ((n1 == len && (int)port < 0) || (n2 == len && port < 32))) {
2644 return open(phydrive, -1, "", (int)port);
2645 }
2646 // [a-zA-Z]: => Physical drive behind logical drive 0-25
2647 int logdrive = drive_letter(name);
2648 if (logdrive >= 0) {
2649 return open(-1, logdrive, "", -1);
2650 }
2651
2652 return set_err(EINVAL);
2653 }
2654
2655
2656 bool win_ata_device::open(int phydrive, int logdrive, const char * options, int port)
2657 {
2658 // path depends on Windows Version
2659 char devpath[30];
2660 if (win9x && 0 <= phydrive && phydrive <= 7)
2661 // Use patched "smartvse.vxd" for drives 4-7, see INSTALL file for details
2662 strcpy(devpath, (phydrive <= 3 ? "\\\\.\\SMARTVSD" : "\\\\.\\SMARTVSE"));
2663 else if (!win9x && 0 <= phydrive && phydrive <= 255)
2664 snprintf(devpath, sizeof(devpath)-1, "\\\\.\\PhysicalDrive%d", phydrive);
2665 else if (!win9x && 0 <= logdrive && logdrive <= 'Z'-'A')
2666 snprintf(devpath, sizeof(devpath)-1, "\\\\.\\%c:", 'A'+logdrive);
2667 else
2668 return set_err(ENOENT);
2669
2670 // Open device
2671 HANDLE h = INVALID_HANDLE_VALUE;
2672 if (win9x || !(*options && !options[strspn(options, "fp")])) {
2673 // Open with admin rights
2674 m_admin = true;
2675 h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,
2676 FILE_SHARE_READ|FILE_SHARE_WRITE,
2677 NULL, OPEN_EXISTING, 0, 0);
2678 }
2679 if (!win9x && h == INVALID_HANDLE_VALUE) {
2680 // Open without admin rights
2681 m_admin = false;
2682 h = CreateFileA(devpath, 0,
2683 FILE_SHARE_READ|FILE_SHARE_WRITE,
2684 NULL, OPEN_EXISTING, 0, 0);
2685 }
2686 if (h == INVALID_HANDLE_VALUE) {
2687 long err = GetLastError();
2688 #if WIN9X_SUPPORT
2689 if (win9x && phydrive <= 3 && err == ERROR_FILE_NOT_FOUND)
2690 smartvsd_error();
2691 #endif
2692 if (err == ERROR_FILE_NOT_FOUND)
2693 set_err(ENOENT, "%s: not found", devpath);
2694 else if (err == ERROR_ACCESS_DENIED)
2695 set_err(EACCES, "%s: access denied", devpath);
2696 else
2697 set_err(EIO, "%s: Error=%ld", devpath, err);
2698 return false;
2699 }
2700 set_fh(h);
2701
2702 // Warn once if admin rights are missing
2703 if (!m_admin) {
2704 static bool noadmin_warning = false;
2705 if (!noadmin_warning) {
2706 pout("Warning: Limited functionality due to missing admin rights\n");
2707 noadmin_warning = true;
2708 }
2709 }
2710
2711 if (ata_debugmode > 1)
2712 pout("%s: successfully opened%s\n", devpath, (!m_admin ? " (without admin rights)" :""));
2713
2714 m_usr_options = false;
2715 if (*options) {
2716 // Save user options
2717 m_options = options; m_usr_options = true;
2718 }
2719 else if (port >= 0)
2720 // RAID: SMART_* and SCSI_MINIPORT
2721 m_options = "s3";
2722 else {
2723 // Set default options according to Windows version
2724 static const char * def_options = ata_get_def_options();
2725 m_options = def_options;
2726 }
2727
2728 // NT4/2000/XP: SMART_GET_VERSION may spin up disk, so delay until first real SMART_* call
2729 m_drive = 0; m_port = port;
2730 if (!win9x && port < 0)
2731 return true;
2732
2733 // Win9X/ME: Get drive map
2734 // RAID: Get port map
2735 GETVERSIONINPARAMS_EX vers_ex;
2736 int devmap = smart_get_version(h, &vers_ex);
2737
2738 // 3ware RAID if vendor id present
2739 m_is_3ware = (vers_ex.wIdentifier == SMART_VENDOR_3WARE);
2740
2741 unsigned long portmap = 0;
2742 if (port >= 0 && devmap >= 0) {
2743 // 3ware RAID: check vendor id
2744 if (!m_is_3ware) {
2745 pout("SMART_GET_VERSION returns unknown Identifier = 0x%04x\n"
2746 "This is no 3ware 9000 controller or driver has no SMART support.\n",
2747 vers_ex.wIdentifier);
2748 devmap = -1;
2749 }
2750 else
2751 portmap = vers_ex.dwDeviceMapEx;
2752 }
2753 if (devmap < 0) {
2754 pout("%s: ATA driver has no SMART support\n", devpath);
2755 if (!is_permissive()) {
2756 close();
2757 return set_err(ENOSYS);
2758 }
2759 devmap = 0x0f;
2760 }
2761 m_smartver_state = 1;
2762
2763 if (port >= 0) {
2764 // 3ware RAID: update devicemap first
2765
2766 if (!update_3ware_devicemap_ioctl(h)) {
2767 if ( smart_get_version(h, &vers_ex) >= 0
2768 && vers_ex.wIdentifier == SMART_VENDOR_3WARE )
2769 portmap = vers_ex.dwDeviceMapEx;
2770 }
2771 // Check port existence
2772 if (!(portmap & (1L << port))) {
2773 if (!is_permissive()) {
2774 close();
2775 return set_err(ENOENT, "%s: Port %d is empty or does not exist", devpath, port);
2776 }
2777 }
2778 return true;
2779 }
2780
2781 // Win9x/ME: Check device presence & type
2782 if (((devmap >> (phydrive & 0x3)) & 0x11) != 0x01) {
2783 unsigned char atapi = (devmap >> (phydrive & 0x3)) & 0x10;
2784 // Win9x drive existence check may not work as expected
2785 // The atapi.sys driver incorrectly fills in the bIDEDeviceMap with 0x01
2786 // (The related KB Article Q196120 is no longer available)
2787 if (!is_permissive()) {
2788 close();
2789 return set_err((atapi ? ENOSYS : ENOENT), "%s: Drive %d %s (IDEDeviceMap=0x%02x)",
2790 devpath, phydrive, (atapi?"is an ATAPI device":"does not exist"), devmap);
2791 }
2792 }
2793 // Drive number must be passed to ioctl
2794 m_drive = (phydrive & 0x3);
2795 return true;
2796 }
2797
2798
2799 #if WIN9X_SUPPORT
2800
2801 // Scan for ATA drives on Win9x/ME
2802
2803 bool win9x_smart_interface::ata_scan(smart_device_list & devlist)
2804 {
2805 // Open device
2806 const char devpath[] = "\\\\.\\SMARTVSD";
2807 HANDLE h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,
2808 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
2809 if (h == INVALID_HANDLE_VALUE) {
2810 if (ata_debugmode > 1)
2811 pout(" %s: Open failed, Error=%ld\n", devpath, GetLastError());
2812 return true; // SMARTVSD.VXD missing or no ATA devices
2813 }
2814
2815 // Get drive map
2816 int devmap = smart_get_version(h);
2817 CloseHandle(h);
2818 if (devmap < 0)
2819 return true; // Should not happen
2820
2821 // Check ATA device presence, remove ATAPI devices
2822 devmap = (devmap & 0xf) & ~((devmap >> 4) & 0xf);
2823 char name[20];
2824 for (int i = 0; i < 4; i++) {
2825 if (!(devmap & (1 << i)))
2826 continue;
2827 sprintf(name, "/dev/hd%c", 'a'+i);
2828 devlist.push_back( new win_ata_device(this, name, "ata") );
2829 }
2830 return true;
2831 }
2832
2833 #endif // WIN9X_SUPPORT
2834
2835
2836 /////////////////////////////////////////////////////////////////////////////
2837
2838 // Interface to ATA devices
2839 bool win_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
2840 {
2841 // No multi-sector support for now, see above
2842 // warning about IOCTL_ATA_PASS_THROUGH
2843 if (!ata_cmd_is_ok(in,
2844 true, // data_out_support
2845 false, // !multi_sector_support
2846 true) // ata_48bit_support
2847 )
2848 return false;
2849
2850 // 3ware RAID: SMART DISABLE without port number disables SMART functions
2851 if ( m_is_3ware && m_port < 0
2852 && in.in_regs.command == ATA_SMART_CMD
2853 && in.in_regs.features == ATA_SMART_DISABLE)
2854 return set_err(ENOSYS, "SMART DISABLE requires 3ware port number");
2855
2856 // Determine ioctl functions valid for this ATA cmd
2857 const char * valid_options = 0;
2858
2859 switch (in.in_regs.command) {
2860 case ATA_IDENTIFY_DEVICE:
2861 case ATA_IDENTIFY_PACKET_DEVICE:
2862 // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
2863 // and SCSI_MINIPORT_* if requested by user
2864 valid_options = (m_usr_options ? "saicmf" : "saicf");
2865 break;
2866
2867 case ATA_CHECK_POWER_MODE:
2868 // Try GetDevicePowerState() first, ATA/IDE_PASS_THROUGH may spin up disk
2869 valid_options = "pai3";
2870 break;
2871
2872 case ATA_SMART_CMD:
2873 switch (in.in_regs.features) {
2874 case ATA_SMART_READ_VALUES:
2875 case ATA_SMART_READ_THRESHOLDS:
2876 case ATA_SMART_AUTOSAVE:
2877 case ATA_SMART_ENABLE:
2878 case ATA_SMART_DISABLE:
2879 case ATA_SMART_AUTO_OFFLINE:
2880 // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
2881 // and SCSI_MINIPORT_* if requested by user
2882 valid_options = (m_usr_options ? "saicmf" : "saicf");
2883 break;
2884
2885 case ATA_SMART_IMMEDIATE_OFFLINE:
2886 // SMART_SEND_DRIVE_COMMAND supports ABORT_SELF_TEST only on Win9x/ME
2887 valid_options = (m_usr_options || in.in_regs.lba_low != 127/*ABORT*/ || win9x ?
2888 "saicm3" : "aicm3");
2889 break;
2890
2891 case ATA_SMART_READ_LOG_SECTOR:
2892 // SMART_RCV_DRIVE_DATA supports this only on Win9x/ME
2893 // Try SCSI_MINIPORT also to skip buggy class driver
2894 // SMART functions do not support multi sector I/O.
2895 if (in.size == 512)
2896 valid_options = (m_usr_options || win9x ? "saicm3" : "aicm3");
2897 else
2898 valid_options = "a";
2899 break;
2900
2901 case ATA_SMART_WRITE_LOG_SECTOR:
2902 // ATA_PASS_THROUGH, SCSI_MINIPORT, others don't support DATA_OUT
2903 // but SCSI_MINIPORT_* only if requested by user and single sector.
2904 valid_options = (in.size == 512 && m_usr_options ? "am" : "a");
2905 break;
2906
2907 case ATA_SMART_STATUS:
2908 // May require lba_mid,lba_high register return
2909 if (in.out_needed.is_set())
2910 valid_options = (m_usr_options ? "saimf" : "saif");
2911 else
2912 valid_options = (m_usr_options ? "saicmf" : "saicf");
2913 break;
2914
2915 default:
2916 // Unknown SMART command, handle below
2917 break;
2918 }
2919 break;
2920
2921 default:
2922 // Other ATA command, handle below
2923 break;
2924 }
2925
2926 if (!valid_options) {
2927 // No special ATA command found above, select a generic pass through ioctl.
2928 if (!( in.direction == ata_cmd_in::no_data
2929 || (in.direction == ata_cmd_in::data_in && in.size == 512))
2930 || in.in_regs.is_48bit_cmd() )
2931 // DATA_OUT, more than one sector, 48-bit command: ATA_PASS_THROUGH only
2932 valid_options = "a";
2933 else if (in.out_needed.is_set())
2934 // Need output registers: ATA/IDE_PASS_THROUGH
2935 valid_options = "ai";
2936 else
2937 valid_options = "aic";
2938 }
2939
2940 if (!m_admin) {
2941 // Restrict to IOCTL_STORAGE_*
2942 if (strchr(valid_options, 'f'))
2943 valid_options = "f";
2944 else if (strchr(valid_options, 'p'))
2945 valid_options = "p";
2946 else
2947 return set_err(ENOSYS, "Function requires admin rights");
2948 }
2949
2950 // Set IDEREGS
2951 IDEREGS regs, prev_regs;
2952 {
2953 const ata_in_regs & lo = in.in_regs;
2954 regs.bFeaturesReg = lo.features;
2955 regs.bSectorCountReg = lo.sector_count;
2956 regs.bSectorNumberReg = lo.lba_low;
2957 regs.bCylLowReg = lo.lba_mid;
2958 regs.bCylHighReg = lo.lba_high;
2959 regs.bDriveHeadReg = lo.device;
2960 regs.bCommandReg = lo.command;
2961 regs.bReserved = 0;
2962 }
2963 if (in.in_regs.is_48bit_cmd()) {
2964 const ata_in_regs & hi = in.in_regs.prev;
2965 prev_regs.bFeaturesReg = hi.features;
2966 prev_regs.bSectorCountReg = hi.sector_count;
2967 prev_regs.bSectorNumberReg = hi.lba_low;
2968 prev_regs.bCylLowReg = hi.lba_mid;
2969 prev_regs.bCylHighReg = hi.lba_high;
2970 prev_regs.bDriveHeadReg = hi.device;
2971 prev_regs.bCommandReg = hi.command;
2972 prev_regs.bReserved = 0;
2973 }
2974
2975 // Set data direction
2976 int datasize = 0;
2977 char * data = 0;
2978 switch (in.direction) {
2979 case ata_cmd_in::no_data:
2980 break;
2981 case ata_cmd_in::data_in:
2982 datasize = (int)in.size;
2983 data = (char *)in.buffer;
2984 break;
2985 case ata_cmd_in::data_out:
2986 datasize = -(int)in.size;
2987 data = (char *)in.buffer;
2988 break;
2989 default:
2990 return set_err(EINVAL, "win_ata_device::ata_pass_through: invalid direction=%d",
2991 (int)in.direction);
2992 }
2993
2994
2995 // Try all valid ioctls in the order specified in m_options
2996 bool powered_up = false;
2997 bool out_regs_set = false;
2998 bool id_is_cached = false;
2999 const char * options = m_options.c_str();
3000
3001 for (int i = 0; ; i++) {
3002 char opt = options[i];
3003
3004 if (!opt) {
3005 if (in.in_regs.command == ATA_CHECK_POWER_MODE && powered_up) {
3006 // Power up reported by GetDevicePowerState() and no ioctl available
3007 // to detect the actual mode of the drive => simulate ATA result ACTIVE/IDLE.
3008 regs.bSectorCountReg = 0xff;
3009 out_regs_set = true;
3010 break;
3011 }
3012 // No IOCTL found
3013 return set_err(ENOSYS);
3014 }
3015 if (!strchr(valid_options, opt))
3016 // Invalid for this command
3017 continue;
3018
3019 errno = 0;
3020 assert( datasize == 0 || datasize == 512
3021 || (datasize == -512 && strchr("am", opt))
3022 || (datasize > 512 && opt == 'a'));
3023 int rc;
3024 switch (opt) {
3025 default: assert(0);
3026 case 's':
3027 // call SMART_GET_VERSION once for each drive
3028 if (m_smartver_state > 1) {
3029 rc = -1; errno = ENOSYS;
3030 break;
3031 }
3032 if (!m_smartver_state) {
3033 assert(m_port == -1);
3034 GETVERSIONINPARAMS_EX vers_ex;
3035 if (smart_get_version(get_fh(), &vers_ex) < 0) {
3036 if (!failuretest_permissive) {
3037 m_smartver_state = 2;
3038 rc = -1; errno = ENOSYS;
3039 break;
3040 }
3041 failuretest_permissive--;
3042 }
3043 else {
3044 // 3ware RAID if vendor id present
3045 m_is_3ware = (vers_ex.wIdentifier == SMART_VENDOR_3WARE);
3046 }
3047
3048 m_smartver_state = 1;
3049 }
3050 rc = smart_ioctl(get_fh(), m_drive, &regs, data, datasize, m_port);
3051 out_regs_set = (in.in_regs.features == ATA_SMART_STATUS);
3052 id_is_cached = (m_port < 0 && !win9x); // Not cached by 3ware or Win9x/ME driver
3053 break;
3054 case 'm':
3055 rc = ata_via_scsi_miniport_smart_ioctl(get_fh(), &regs, data, datasize);
3056 id_is_cached = (m_port < 0 && !win9x);
3057 break;
3058 case 'a':
3059 rc = ata_pass_through_ioctl(get_fh(), &regs,
3060 (in.in_regs.is_48bit_cmd() ? &prev_regs : 0),
3061 data, datasize);
3062 out_regs_set = true;
3063 break;
3064 case 'i':
3065 rc = ide_pass_through_ioctl(get_fh(), &regs, data, datasize);
3066 out_regs_set = true;
3067 break;
3068 case 'c':
3069 rc = ata_via_scsi_pass_through_ioctl(get_fh(), &regs, data, datasize);
3070 break;
3071 case 'f':
3072 if (in.in_regs.command == ATA_IDENTIFY_DEVICE) {
3073 rc = get_identify_from_device_property(get_fh(), (ata_identify_device *)data);
3074 id_is_cached = true;
3075 }
3076 else if (in.in_regs.command == ATA_SMART_CMD) switch (in.in_regs.features) {
3077 case ATA_SMART_READ_VALUES:
3078 rc = storage_predict_failure_ioctl(get_fh(), data);
3079 if (rc > 0)
3080 rc = 0;
3081 break;
3082 case ATA_SMART_ENABLE:
3083 rc = 0;
3084 break;
3085 case ATA_SMART_STATUS:
3086 rc = storage_predict_failure_ioctl(get_fh());
3087 if (rc == 0) {
3088 // Good SMART status
3089 out.out_regs.lba_high = 0xc2; out.out_regs.lba_mid = 0x4f;
3090 }
3091 else if (rc > 0) {
3092 // Bad SMART status
3093 out.out_regs.lba_high = 0x2c; out.out_regs.lba_mid = 0xf4;
3094 rc = 0;
3095 }
3096 break;
3097 default:
3098 errno = ENOSYS; rc = -1;
3099 }
3100 else {
3101 errno = ENOSYS; rc = -1;
3102 }
3103 break;
3104 case '3':
3105 rc = ata_via_3ware_miniport_ioctl(get_fh(), &regs, data, datasize, m_port);
3106 out_regs_set = true;
3107 break;
3108 case 'p':
3109 assert(in.in_regs.command == ATA_CHECK_POWER_MODE && in.size == 0);
3110 rc = get_device_power_state(get_fh());
3111 if (rc == 0) {
3112 // Power down reported by GetDevicePowerState(), using a passthrough ioctl would
3113 // spin up the drive => simulate ATA result STANDBY.
3114 regs.bSectorCountReg = 0x00;
3115 out_regs_set = true;
3116 }
3117 else if (rc > 0) {
3118 // Power up reported by GetDevicePowerState(), but this reflects the actual mode
3119 // only if it is selected by the device driver => try a passthrough ioctl to get the
3120 // actual mode, if none available simulate ACTIVE/IDLE.
3121 powered_up = true;
3122 rc = -1; errno = ENOSYS;
3123 }
3124 break;
3125 }
3126
3127 if (!rc)
3128 // Working ioctl found
3129 break;
3130
3131 if (errno != ENOSYS)
3132 // Abort on I/O error
3133 return set_err(errno);
3134
3135 out_regs_set = false;
3136 // CAUTION: *_ioctl() MUST NOT change "regs" Parameter in the ENOSYS case
3137 }
3138
3139 // Return IDEREGS if set
3140 if (out_regs_set) {
3141 ata_out_regs & lo = out.out_regs;
3142 lo.error = regs.bFeaturesReg;
3143 lo.sector_count = regs.bSectorCountReg;
3144 lo.lba_low = regs.bSectorNumberReg;
3145 lo.lba_mid = regs.bCylLowReg;
3146 lo.lba_high = regs.bCylHighReg;
3147 lo.device = regs.bDriveHeadReg;
3148 lo.status = regs.bCommandReg;
3149 if (in.in_regs.is_48bit_cmd()) {
3150 ata_out_regs & hi = out.out_regs.prev;
3151 hi.sector_count = prev_regs.bSectorCountReg;
3152 hi.lba_low = prev_regs.bSectorNumberReg;
3153 hi.lba_mid = prev_regs.bCylLowReg;
3154 hi.lba_high = prev_regs.bCylHighReg;
3155 }
3156 }
3157
3158 if ( in.in_regs.command == ATA_IDENTIFY_DEVICE
3159 || in.in_regs.command == ATA_IDENTIFY_PACKET_DEVICE)
3160 // Update ata_identify_is_cached() result according to ioctl used.
3161 m_id_is_cached = id_is_cached;
3162
3163 return true;
3164 }
3165
3166 // Return true if OS caches the ATA identify sector
3167 bool win_ata_device::ata_identify_is_cached() const
3168 {
3169 return m_id_is_cached;
3170 }
3171
3172
3173 //////////////////////////////////////////////////////////////////////
3174 // csmi_ata_device
3175
3176 bool csmi_device::get_phy_info(CSMI_SAS_PHY_INFO & phy_info)
3177 {
3178 // Get driver info to check CSMI support
3179 CSMI_SAS_DRIVER_INFO_BUFFER driver_info_buf;
3180 memset(&driver_info_buf, 0, sizeof(driver_info_buf));
3181 if (!csmi_ioctl(CC_CSMI_SAS_GET_DRIVER_INFO, &driver_info_buf.IoctlHeader, sizeof(driver_info_buf)))
3182 return false;
3183
3184 if (scsi_debugmode > 1) {
3185 const CSMI_SAS_DRIVER_INFO & driver_info = driver_info_buf.Information;
3186 pout("CSMI_SAS_DRIVER_INFO:\n");
3187 pout(" Name: \"%.81s\"\n", driver_info.szName);
3188 pout(" Description: \"%.81s\"\n", driver_info.szDescription);
3189 pout(" Revision: %d.%d\n", driver_info.usMajorRevision, driver_info.usMinorRevision);
3190 }
3191
3192 // Get Phy info
3193 CSMI_SAS_PHY_INFO_BUFFER phy_info_buf;
3194 memset(&phy_info_buf, 0, sizeof(phy_info_buf));
3195 if (!csmi_ioctl(CC_CSMI_SAS_GET_PHY_INFO, &phy_info_buf.IoctlHeader, sizeof(phy_info_buf)))
3196 return false;
3197
3198 phy_info = phy_info_buf.Information;
3199 if (phy_info.bNumberOfPhys > sizeof(phy_info.Phy)/sizeof(phy_info.Phy[0]))
3200 return set_err(EIO, "CSMI_SAS_PHY_INFO: Bogus NumberOfPhys=%d", phy_info.bNumberOfPhys);
3201
3202 if (scsi_debugmode > 1) {
3203 pout("CSMI_SAS_PHY_INFO: NumberOfPhys=%d\n", phy_info.bNumberOfPhys);
3204 for (int i = 0; i < phy_info.bNumberOfPhys; i++) {
3205 const CSMI_SAS_PHY_ENTITY & pe = phy_info.Phy[i];
3206 const CSMI_SAS_IDENTIFY & id = pe.Identify, & at = pe.Attached;
3207 pout("Phy[%d] Port: 0x%02x\n", i, pe.bPortIdentifier);
3208 pout(" Type: 0x%02x, 0x%02x\n", id.bDeviceType, at.bDeviceType);
3209 pout(" InitProto: 0x%02x, 0x%02x\n", id.bInitiatorPortProtocol, at.bInitiatorPortProtocol);
3210 pout(" TargetProto: 0x%02x, 0x%02x\n", id.bTargetPortProtocol, at.bTargetPortProtocol);
3211 pout(" PhyIdent: 0x%02x, 0x%02x\n", id.bPhyIdentifier, at.bPhyIdentifier);
3212 const unsigned char * b = id.bSASAddress;
3213 pout(" SASAddress: %02x %02x %02x %02x %02x %02x %02x %02x, ",
3214 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
3215 b = at.bSASAddress;
3216 pout( "%02x %02x %02x %02x %02x %02x %02x %02x\n",
3217 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
3218 }
3219 }
3220
3221 return true;
3222 }
3223
3224 bool csmi_device::check_phy(const CSMI_SAS_PHY_INFO & phy_info, unsigned phy_no)
3225 {
3226 // Check Phy presence
3227 if (phy_no >= phy_info.bNumberOfPhys)
3228 return set_err(ENOENT, "Port %u does not exist (#ports: %d)", phy_no,
3229 phy_info.bNumberOfPhys);
3230
3231 const CSMI_SAS_PHY_ENTITY & phy_ent = phy_info.Phy[phy_no];
3232 if (phy_ent.Attached.bDeviceType == CSMI_SAS_NO_DEVICE_ATTACHED)
3233 return set_err(ENOENT, "No device on port %u", phy_no);
3234
3235 switch (phy_ent.Attached.bTargetPortProtocol) {
3236 case CSMI_SAS_PROTOCOL_SATA:
3237 case CSMI_SAS_PROTOCOL_STP:
3238 break;
3239 default:
3240 return set_err(ENOENT, "No SATA device on port %u (protocol: %u)",
3241 phy_no, phy_ent.Attached.bTargetPortProtocol);
3242 }
3243
3244 return true;
3245 }
3246
3247 bool csmi_device::select_phy(unsigned phy_no)
3248 {
3249 CSMI_SAS_PHY_INFO phy_info;
3250 if (!get_phy_info(phy_info))
3251 return false;
3252
3253
3254 if (!check_phy(phy_info, phy_no))
3255 return false;
3256
3257 m_phy_ent = phy_info.Phy[phy_no];
3258 return true;
3259 }
3260
3261
3262 bool csmi_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
3263 {
3264 if (!ata_cmd_is_ok(in,
3265 true, // data_out_support
3266 true, // multi_sector_support
3267 true) // ata_48bit_support
3268 )
3269 return false;
3270
3271 // Create buffer with appropriate size
3272 raw_buffer pthru_raw_buf(sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER) + in.size);
3273 CSMI_SAS_STP_PASSTHRU_BUFFER * pthru_buf = (CSMI_SAS_STP_PASSTHRU_BUFFER *)pthru_raw_buf.data();
3274
3275 // Set addresses from Phy info
3276 CSMI_SAS_STP_PASSTHRU & pthru = pthru_buf->Parameters;
3277 const CSMI_SAS_PHY_ENTITY & phy_ent = get_phy_ent();
3278 pthru.bPhyIdentifier = phy_ent.Identify.bPhyIdentifier;
3279 pthru.bPortIdentifier = phy_ent.bPortIdentifier;
3280 memcpy(pthru.bDestinationSASAddress, phy_ent.Attached.bSASAddress,
3281 sizeof(pthru.bDestinationSASAddress));
3282 pthru.bConnectionRate = CSMI_SAS_LINK_RATE_NEGOTIATED;
3283
3284 // Set transfer mode
3285 switch (in.direction) {
3286 case ata_cmd_in::no_data:
3287 pthru.uFlags = CSMI_SAS_STP_PIO | CSMI_SAS_STP_UNSPECIFIED;
3288 break;
3289 case ata_cmd_in::data_in:
3290 pthru.uFlags = CSMI_SAS_STP_PIO | CSMI_SAS_STP_READ;
3291 pthru.uDataLength = in.size;
3292 break;
3293 case ata_cmd_in::data_out:
3294 pthru.uFlags = CSMI_SAS_STP_PIO | CSMI_SAS_STP_WRITE;
3295 pthru.uDataLength = in.size;
3296 memcpy(pthru_buf->bDataBuffer, in.buffer, in.size);
3297 break;
3298 default:
3299 return set_err(EINVAL, "csmi_ata_device::ata_pass_through: invalid direction=%d",
3300 (int)in.direction);
3301 }
3302
3303 // Set host-to-device FIS
3304 {
3305 unsigned char * fis = pthru.bCommandFIS;
3306 const ata_in_regs & lo = in.in_regs;
3307 const ata_in_regs & hi = in.in_regs.prev;
3308 fis[ 0] = 0x27; // Type: host-to-device FIS
3309 fis[ 1] = 0x80; // Bit7: Update command register
3310 fis[ 2] = lo.command;
3311 fis[ 3] = lo.features;
3312 fis[ 4] = lo.lba_low;
3313 fis[ 5] = lo.lba_mid;
3314 fis[ 6] = lo.lba_high;
3315 fis[ 7] = lo.device;
3316 fis[ 8] = hi.lba_low;
3317 fis[ 9] = hi.lba_mid;
3318 fis[10] = hi.lba_high;
3319 fis[11] = hi.features;
3320 fis[12] = lo.sector_count;
3321 fis[13] = hi.sector_count;
3322 }
3323
3324 // Call ioctl
3325 if (!csmi_ioctl(CC_CSMI_SAS_STP_PASSTHRU, &pthru_buf->IoctlHeader, pthru_raw_buf.size())) {
3326 return false;
3327 }
3328
3329 // Get device-to-host FIS
3330 {
3331 const unsigned char * fis = pthru_buf->Status.bStatusFIS;
3332 ata_out_regs & lo = out.out_regs;
3333 lo.status = fis[ 2];
3334 lo.error = fis[ 3];
3335 lo.lba_low = fis[ 4];
3336 lo.lba_mid = fis[ 5];
3337 lo.lba_high = fis[ 6];
3338 lo.device = fis[ 7];
3339 lo.sector_count = fis[12];
3340 if (in.in_regs.is_48bit_cmd()) {
3341 ata_out_regs & hi = out.out_regs.prev;
3342 hi.lba_low = fis[ 8];
3343 hi.lba_mid = fis[ 9];
3344 hi.lba_high = fis[10];
3345 hi.sector_count = fis[13];
3346 }
3347 }
3348
3349 // Get data
3350 if (in.direction == ata_cmd_in::data_in)
3351 // TODO: Check ptru_buf->Status.uDataBytes
3352 memcpy(in.buffer, pthru_buf->bDataBuffer, in.size);
3353
3354 return true;
3355 }
3356
3357
3358 //////////////////////////////////////////////////////////////////////
3359 // win_csmi_device
3360
3361 win_csmi_device::win_csmi_device(smart_interface * intf, const char * dev_name,
3362 const char * req_type)
3363 : smart_device(intf, dev_name, "ata", req_type),
3364 m_fh(INVALID_HANDLE_VALUE), m_phy_no(0)
3365 {
3366 }
3367
3368 win_csmi_device::~win_csmi_device() throw()
3369 {
3370 if (m_fh != INVALID_HANDLE_VALUE)
3371 CloseHandle(m_fh);
3372 }
3373
3374 bool win_csmi_device::is_open() const
3375 {
3376 return (m_fh != INVALID_HANDLE_VALUE);
3377 }
3378
3379 bool win_csmi_device::close()
3380 {
3381 if (m_fh == INVALID_HANDLE_VALUE)
3382 return true;
3383 BOOL rc = CloseHandle(m_fh);
3384 m_fh = INVALID_HANDLE_VALUE;
3385 return !!rc;
3386 }
3387
3388
3389 bool win_csmi_device::open_scsi()
3390 {
3391 // Parse name
3392 unsigned contr_no = ~0, phy_no = ~0; int nc = -1;
3393 const char * name = skipdev(get_dev_name());
3394 if (!( sscanf(name, "csmi%u,%u%n", &contr_no, &phy_no, &nc) >= 0
3395 && nc == (int)strlen(name) && contr_no <= 9 && phy_no < 32) )
3396 return set_err(EINVAL);
3397
3398 // Open controller handle
3399 char devpath[30];
3400 snprintf(devpath, sizeof(devpath)-1, "\\\\.\\Scsi%u:", contr_no);
3401
3402 HANDLE h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,
3403 FILE_SHARE_READ|FILE_SHARE_WRITE,
3404 (SECURITY_ATTRIBUTES *)0, OPEN_EXISTING, 0, 0);
3405
3406 if (h == INVALID_HANDLE_VALUE) {
3407 long err = GetLastError();
3408 if (err == ERROR_FILE_NOT_FOUND)
3409 set_err(ENOENT, "%s: not found", devpath);
3410 else if (err == ERROR_ACCESS_DENIED)
3411 set_err(EACCES, "%s: access denied", devpath);
3412 else
3413 set_err(EIO, "%s: Error=%ld", devpath, err);
3414 return false;
3415 }
3416
3417 if (scsi_debugmode > 1)
3418 pout(" %s: successfully opened\n", devpath);
3419
3420 m_fh = h;
3421 m_phy_no = phy_no;
3422 return true;
3423 }
3424
3425
3426 bool win_csmi_device::open()
3427 {
3428 if (!open_scsi())
3429 return false;
3430
3431 // Get Phy info for this drive
3432 if (!select_phy(m_phy_no)) {
3433 close();
3434 return false;
3435 }
3436
3437 return true;
3438 }
3439
3440
3441 bool win_csmi_device::csmi_ioctl(unsigned code, IOCTL_HEADER * csmi_buffer,
3442 unsigned csmi_bufsiz)
3443 {
3444 // Determine signature
3445 const char * sig;
3446 switch (code) {
3447 case CC_CSMI_SAS_GET_DRIVER_INFO:
3448 sig = CSMI_ALL_SIGNATURE; break;
3449 case CC_CSMI_SAS_GET_PHY_INFO:
3450 case CC_CSMI_SAS_STP_PASSTHRU:
3451 sig = CSMI_SAS_SIGNATURE; break;
3452 default:
3453 return set_err(ENOSYS, "Unknown CSMI code=%u", code);
3454 }
3455
3456 // Set header
3457 csmi_buffer->HeaderLength = sizeof(IOCTL_HEADER);
3458 strncpy((char *)csmi_buffer->Signature, sig, sizeof(csmi_buffer->Signature));
3459 csmi_buffer->Timeout = CSMI_SAS_TIMEOUT;
3460 csmi_buffer->ControlCode = code;
3461 csmi_buffer->ReturnCode = 0;
3462 csmi_buffer->Length = csmi_bufsiz - sizeof(IOCTL_HEADER);
3463
3464 // Call function
3465 DWORD num_out = 0;
3466 if (!DeviceIoControl(m_fh, IOCTL_SCSI_MINIPORT,
3467 csmi_buffer, csmi_bufsiz, csmi_buffer, csmi_bufsiz, &num_out, (OVERLAPPED*)0)) {
3468 long err = GetLastError();
3469 if (scsi_debugmode)
3470 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, Error=%ld\n", code, err);
3471 if ( err == ERROR_INVALID_FUNCTION
3472 || err == ERROR_NOT_SUPPORTED
3473 || err == ERROR_DEV_NOT_EXIST)
3474 return set_err(ENOSYS, "CSMI is not supported (Error=%ld)", err);
3475 else
3476 return set_err(EIO, "CSMI(%u) failed with Error=%ld", code, err);
3477 }
3478
3479 // Check result
3480 if (csmi_buffer->ReturnCode) {
3481 if (scsi_debugmode) {
3482 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, ReturnCode=%lu\n",
3483 code, csmi_buffer->ReturnCode);
3484 }
3485 return set_err(EIO, "CSMI(%u) failed with ReturnCode=%lu", code, csmi_buffer->ReturnCode);
3486 }
3487
3488 if (scsi_debugmode > 1)
3489 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) succeeded, bytes returned: %lu\n", code, num_out);
3490
3491 return true;
3492 }
3493
3494
3495 /////////////////////////////////////////////////////////////////////////////
3496 // ASPI Interface (for SCSI devices on 9x/ME)
3497 /////////////////////////////////////////////////////////////////////////////
3498
3499 #if WIN9X_SUPPORT
3500
3501 #pragma pack(1)
3502
3503 #define ASPI_SENSE_SIZE 18
3504
3505 // ASPI SCSI Request block header
3506
3507 typedef struct {
3508 unsigned char cmd; // 00: Command code
3509 unsigned char status; // 01: ASPI status
3510 unsigned char adapter; // 02: Host adapter number
3511 unsigned char flags; // 03: Request flags
3512 unsigned char reserved[4]; // 04: 0
3513 } ASPI_SRB_HEAD;
3514
3515 // SRB for host adapter inquiry
3516
3517 typedef struct {
3518 ASPI_SRB_HEAD h; // 00: Header
3519 unsigned char adapters; // 08: Number of adapters
3520 unsigned char target_id; // 09: Target ID ?
3521 char manager_id[16]; // 10: SCSI manager ID
3522 char adapter_id[16]; // 26: Host adapter ID
3523 unsigned char parameters[16]; // 42: Host adapter unique parmameters
3524 } ASPI_SRB_INQUIRY;
3525
3526 // SRB for get device type
3527
3528 typedef struct {
3529 ASPI_SRB_HEAD h; // 00: Header
3530 unsigned char target_id; // 08: Target ID
3531 unsigned char lun; // 09: LUN
3532 unsigned char devtype; // 10: Device type
3533 unsigned char reserved; // 11: Reserved
3534 } ASPI_SRB_DEVTYPE;
3535
3536 // SRB for SCSI I/O
3537
3538 typedef struct {
3539 ASPI_SRB_HEAD h; // 00: Header
3540 unsigned char target_id; // 08: Target ID
3541 unsigned char lun; // 09: LUN
3542 unsigned char reserved[2]; // 10: Reserved
3543 unsigned long data_size; // 12: Data alloc. lenght
3544 void * data_addr; // 16: Data buffer pointer
3545 unsigned char sense_size; // 20: Sense alloc. length
3546 unsigned char cdb_size; // 21: CDB length
3547 unsigned char host_status; // 22: Host status
3548 unsigned char target_status; // 23: Target status
3549 void * event_handle; // 24: Event handle
3550 unsigned char workspace[20]; // 28: ASPI workspace
3551 unsigned char cdb[16+ASPI_SENSE_SIZE];
3552 } ASPI_SRB_IO;
3553
3554 // Macro to retrieve start of sense information
3555 #define ASPI_SRB_SENSE(srb,cdbsz) ((srb)->cdb + 16)
3556
3557 // SRB union
3558
3559 typedef union {
3560 ASPI_SRB_HEAD h; // Common header
3561 ASPI_SRB_INQUIRY q; // Inquiry
3562 ASPI_SRB_DEVTYPE t; // Device type
3563 ASPI_SRB_IO i; // I/O
3564 } ASPI_SRB;
3565
3566 #pragma pack()
3567
3568 // ASPI commands
3569 #define ASPI_CMD_ADAPTER_INQUIRE 0x00
3570 #define ASPI_CMD_GET_DEVICE_TYPE 0x01
3571 #define ASPI_CMD_EXECUTE_IO 0x02
3572 #define ASPI_CMD_ABORT_IO 0x03
3573
3574 // Request flags
3575 #define ASPI_REQFLAG_DIR_TO_HOST 0x08
3576 #define ASPI_REQFLAG_DIR_TO_TARGET 0x10
3577 #define ASPI_REQFLAG_DIR_NO_XFER 0x18
3578 #define ASPI_REQFLAG_EVENT_NOTIFY 0x40
3579
3580 // ASPI status
3581 #define ASPI_STATUS_IN_PROGRESS 0x00
3582 #define ASPI_STATUS_NO_ERROR 0x01
3583 #define ASPI_STATUS_ABORTED 0x02
3584 #define ASPI_STATUS_ABORT_ERR 0x03
3585 #define ASPI_STATUS_ERROR 0x04
3586 #define ASPI_STATUS_INVALID_COMMAND 0x80
3587 #define ASPI_STATUS_INVALID_ADAPTER 0x81
3588 #define ASPI_STATUS_INVALID_TARGET 0x82
3589 #define ASPI_STATUS_NO_ADAPTERS 0xE8
3590
3591 // Adapter (host) status
3592 #define ASPI_HSTATUS_NO_ERROR 0x00
3593 #define ASPI_HSTATUS_SELECTION_TIMEOUT 0x11
3594 #define ASPI_HSTATUS_DATA_OVERRUN 0x12
3595 #define ASPI_HSTATUS_BUS_FREE 0x13
3596 #define ASPI_HSTATUS_BUS_PHASE_ERROR 0x14
3597 #define ASPI_HSTATUS_BAD_SGLIST 0x1A
3598
3599 // Target status
3600 #define ASPI_TSTATUS_NO_ERROR 0x00
3601 #define ASPI_TSTATUS_CHECK_CONDITION 0x02
3602 #define ASPI_TSTATUS_BUSY 0x08
3603 #define ASPI_TSTATUS_RESERV_CONFLICT 0x18
3604
3605
3606 static HINSTANCE h_aspi_dll; // DLL handle
3607 static UINT (* aspi_entry)(ASPI_SRB * srb); // ASPI entrypoint
3608 static unsigned num_aspi_adapters;
3609
3610 #ifdef __CYGWIN__
3611 // h_aspi_dll+aspi_entry is not inherited by Cygwin's fork()
3612 static DWORD aspi_dll_pid; // PID of DLL owner to detect fork()
3613 #define aspi_entry_valid() (aspi_entry && (aspi_dll_pid == GetCurrentProcessId()))
3614 #else
3615 #define aspi_entry_valid() (!!aspi_entry)
3616 #endif
3617
3618
3619 static int aspi_call(ASPI_SRB * srb)
3620 {
3621 int i;
3622 aspi_entry(srb);
3623 i = 0;
3624 while (((volatile ASPI_SRB *)srb)->h.status == ASPI_STATUS_IN_PROGRESS) {
3625 if (++i > 100/*10sek*/) {
3626 pout("ASPI Adapter %u: Timed out\n", srb->h.adapter);
3627 aspi_entry = 0;
3628 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
3629 errno = EIO;
3630 return -1;
3631 }
3632 if (scsi_debugmode > 1)
3633 pout("ASPI Adapter %u: Waiting (%d) ...\n", srb->h.adapter, i);
3634 Sleep(100);
3635 }
3636 return 0;
3637 }
3638
3639
3640 // Get ASPI entrypoint from wnaspi32.dll
3641
3642 static FARPROC aspi_get_address(const char * name, int verbose)
3643 {
3644 FARPROC addr;
3645 assert(h_aspi_dll && h_aspi_dll != INVALID_HANDLE_VALUE);
3646
3647 if (!(addr = GetProcAddress(h_aspi_dll, name))) {
3648 if (verbose)
3649 pout("Missing %s() in WNASPI32.DLL\n", name);
3650 aspi_entry = 0;
3651 FreeLibrary(h_aspi_dll);
3652 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
3653 errno = ENOSYS;
3654 return 0;
3655 }
3656 return addr;
3657 }
3658
3659
3660 static int aspi_open_dll(int verbose)
3661 {
3662 UINT (*aspi_info)(void);
3663 UINT info, rc;
3664
3665 assert(!aspi_entry_valid());
3666
3667 // Check structure layout
3668 assert(sizeof(ASPI_SRB_HEAD) == 8);
3669 assert(sizeof(ASPI_SRB_INQUIRY) == 58);
3670 assert(sizeof(ASPI_SRB_DEVTYPE) == 12);
3671 assert(sizeof(ASPI_SRB_IO) == 64+ASPI_SENSE_SIZE);
3672 assert(offsetof(ASPI_SRB,h.cmd) == 0);
3673 assert(offsetof(ASPI_SRB,h.flags) == 3);
3674 assert(offsetof(ASPI_SRB_IO,lun) == 9);
3675 assert(offsetof(ASPI_SRB_IO,data_addr) == 16);
3676 assert(offsetof(ASPI_SRB_IO,workspace) == 28);
3677 assert(offsetof(ASPI_SRB_IO,cdb) == 48);
3678
3679 if (h_aspi_dll == INVALID_HANDLE_VALUE) {
3680 // do not retry
3681 errno = ENOENT;
3682 return -1;
3683 }
3684
3685 // Load ASPI DLL
3686 if (!(h_aspi_dll = LoadLibraryA("WNASPI32.DLL"))) {
3687 if (verbose)
3688 pout("Cannot load WNASPI32.DLL, Error=%ld\n", GetLastError());
3689 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
3690 errno = ENOENT;
3691 return -1;
3692 }
3693 if (scsi_debugmode > 1) {
3694 // Print full path of WNASPI32.DLL
3695 char path[MAX_PATH];
3696 if (!GetModuleFileName(h_aspi_dll, path, sizeof(path)))
3697 strcpy(path, "*unknown*");
3698 pout("Using ASPI interface \"%s\"\n", path);
3699 }
3700
3701 // Get ASPI entrypoints
3702 if (!(aspi_info = (UINT (*)(void))aspi_get_address("GetASPI32SupportInfo", verbose)))
3703 return -1;
3704 if (!(aspi_entry = (UINT (*)(ASPI_SRB *))aspi_get_address("SendASPI32Command", verbose)))
3705 return -1;
3706
3707 // Init ASPI manager and get number of adapters
3708 info = (aspi_info)();
3709 if (scsi_debugmode > 1)
3710 pout("GetASPI32SupportInfo() returns 0x%04x\n", info);
3711 rc = (info >> 8) & 0xff;
3712 if (rc == ASPI_STATUS_NO_ADAPTERS) {
3713 num_aspi_adapters = 0;
3714 }
3715 else if (rc == ASPI_STATUS_NO_ERROR) {
3716 num_aspi_adapters = info & 0xff;
3717 }
3718 else {
3719 if (verbose)
3720 pout("Got strange 0x%04x from GetASPI32SupportInfo()\n", info);
3721 aspi_entry = 0;
3722 FreeLibrary(h_aspi_dll);
3723 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
3724 errno = ENOENT;
3725 return -1;
3726 }
3727
3728 if (scsi_debugmode)
3729 pout("%u ASPI Adapter%s detected\n",num_aspi_adapters, (num_aspi_adapters!=1?"s":""));
3730
3731 #ifdef __CYGWIN__
3732 // save PID to detect fork() in aspi_entry_valid()
3733 aspi_dll_pid = GetCurrentProcessId();
3734 #endif
3735 assert(aspi_entry_valid());
3736 return 0;
3737 }
3738
3739
3740 static int aspi_io_call(ASPI_SRB * srb, unsigned timeout)
3741 {
3742 HANDLE event;
3743 // Create event
3744 if (!(event = CreateEventA(NULL, FALSE, FALSE, NULL))) {
3745 pout("CreateEvent(): Error=%ld\n", GetLastError()); return -EIO;
3746 }
3747 srb->i.event_handle = event;
3748 srb->h.flags |= ASPI_REQFLAG_EVENT_NOTIFY;
3749 // Start ASPI request
3750 aspi_entry(srb);
3751 if (((volatile ASPI_SRB *)srb)->h.status == ASPI_STATUS_IN_PROGRESS) {
3752 // Wait for event
3753 DWORD rc = WaitForSingleObject(event, timeout*1000L);
3754 if (rc != WAIT_OBJECT_0) {
3755 if (rc == WAIT_TIMEOUT) {
3756 pout("ASPI Adapter %u, ID %u: Timed out after %u seconds\n",
3757 srb->h.adapter, srb->i.target_id, timeout);
3758 }
3759 else {
3760 pout("WaitForSingleObject(%lx) = 0x%lx,%ld, Error=%ld\n",
3761 (unsigned long)(ULONG_PTR)event, rc, rc, GetLastError());
3762 }
3763 // TODO: ASPI_ABORT_IO command
3764 aspi_entry = 0;
3765 h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;
3766 return -EIO;
3767 }
3768 }
3769 CloseHandle(event);
3770 return 0;
3771 }
3772
3773
3774 win_aspi_device::win_aspi_device(smart_interface * intf,
3775 const char * dev_name, const char * req_type)
3776 : smart_device(intf, dev_name, "scsi", req_type),
3777 m_adapter(-1), m_id(0)
3778 {
3779 }
3780
3781 bool win_aspi_device::is_open() const
3782 {
3783 return (m_adapter >= 0);
3784 }
3785
3786 bool win_aspi_device::open()
3787 {
3788 // scsi[0-9][0-f] => ASPI Adapter 0-9, ID 0-15, LUN 0
3789 unsigned adapter = ~0, id = ~0; int n1 = -1;
3790 const char * name = skipdev(get_dev_name());
3791 if (!(sscanf(name,"scsi%1u%1x%n", &adapter, &id, &n1) == 2 && n1 == (int)strlen(name)
3792 && adapter <= 9 && id < 16))
3793 return set_err(EINVAL);
3794
3795 if (!aspi_entry_valid()) {
3796 if (aspi_open_dll(1/*verbose*/))
3797 return set_err(ENOENT);
3798 }
3799
3800 // Adapter OK?
3801 if (adapter >= num_aspi_adapters) {
3802 pout("ASPI Adapter %u does not exist (%u Adapter%s detected).\n",
3803 adapter, num_aspi_adapters, (num_aspi_adapters!=1?"s":""));
3804 if (!is_permissive())
3805 return set_err(ENOENT);
3806 }
3807
3808 // Device present ?
3809 ASPI_SRB srb;
3810 memset(&srb, 0, sizeof(srb));
3811 srb.h.cmd = ASPI_CMD_GET_DEVICE_TYPE;
3812 srb.h.adapter = adapter; srb.i.target_id = id;
3813 if (aspi_call(&srb))
3814 return set_err(EIO);
3815 if (srb.h.status != ASPI_STATUS_NO_ERROR) {
3816 pout("ASPI Adapter %u, ID %u: No such device (Status=0x%02x)\n", adapter, id, srb.h.status);
3817 if (!is_permissive())
3818 return set_err(srb.h.status == ASPI_STATUS_INVALID_TARGET ? ENOENT : EIO);
3819 }
3820 else if (scsi_debugmode)
3821 pout("ASPI Adapter %u, ID %u: Device Type=0x%02x\n", adapter, id, srb.t.devtype);
3822
3823 m_adapter = (int)adapter; m_id = (unsigned char)id;
3824 return true;
3825 }
3826
3827
3828 bool win_aspi_device::close()
3829 {
3830 // No FreeLibrary(h_aspi_dll) to prevent problems with ASPI threads
3831 return true;
3832 }
3833
3834
3835 // Scan for ASPI drives
3836
3837 bool win9x_smart_interface::scsi_scan(smart_device_list & devlist)
3838 {
3839 if (!aspi_entry_valid()) {
3840 if (aspi_open_dll(scsi_debugmode/*default is quiet*/))
3841 return true;
3842 }
3843
3844 for (unsigned ad = 0; ad < num_aspi_adapters; ad++) {
3845 ASPI_SRB srb;
3846
3847 if (ad > 9) {
3848 if (scsi_debugmode)
3849 pout(" ASPI Adapter %u: Ignored\n", ad);
3850 continue;
3851 }
3852
3853 // Get adapter name
3854 memset(&srb, 0, sizeof(srb));
3855 srb.h.cmd = ASPI_CMD_ADAPTER_INQUIRE;
3856 srb.h.adapter = ad;
3857 if (aspi_call(&srb))
3858 break;
3859
3860 if (srb.h.status != ASPI_STATUS_NO_ERROR) {
3861 if (scsi_debugmode)
3862 pout(" ASPI Adapter %u: Status=0x%02x\n", ad, srb.h.status);
3863 continue;
3864 }
3865
3866 if (scsi_debugmode) {
3867 for (int i = 1; i < 16 && srb.q.adapter_id[i]; i++)
3868 if (!(' ' <= srb.q.adapter_id[i] && srb.q.adapter_id[i] <= '~'))
3869 srb.q.adapter_id[i] = '?';
3870 pout(" ASPI Adapter %u (\"%.16s\"):\n", ad, srb.q.adapter_id);
3871 }
3872
3873 bool ignore = !strnicmp(srb.q.adapter_id, "3ware", 5);
3874
3875 for (unsigned id = 0; id <= 7; id++) {
3876 // Get device type
3877 memset(&srb, 0, sizeof(srb));
3878 srb.h.cmd = ASPI_CMD_GET_DEVICE_TYPE;
3879 srb.h.adapter = ad; srb.i.target_id = id;
3880 if (aspi_call(&srb))
3881 return 0;
3882 if (srb.h.status != ASPI_STATUS_NO_ERROR) {
3883 if (scsi_debugmode > 1)
3884 pout(" ID %u: No such device (Status=0x%02x)\n", id, srb.h.status);
3885 continue;
3886 }
3887
3888 if (!ignore && srb.t.devtype == 0x00/*HDD*/) {
3889 if (scsi_debugmode)
3890 pout(" ID %u: Device Type=0x%02x\n", id, srb.t.devtype);
3891 char name[20];
3892 sprintf(name, "/dev/scsi%u%u", ad, id);
3893 devlist.push_back( new win_aspi_device(this, name, "scsi") );
3894 }
3895 else if (scsi_debugmode)
3896 pout(" ID %u: Device Type=0x%02x (ignored)\n", id, srb.t.devtype);
3897 }
3898 }
3899 return true;
3900 }
3901
3902
3903 // Interface to ASPI SCSI devices
3904 bool win_aspi_device::scsi_pass_through(scsi_cmnd_io * iop)
3905 {
3906 int report = scsi_debugmode; // TODO
3907
3908 if (m_adapter < 0) {
3909 set_err(EBADF);
3910 return false;
3911 }
3912
3913 if (!aspi_entry_valid()) {
3914 set_err(EBADF);
3915 return false;
3916 }
3917
3918 if (!(iop->cmnd_len == 6 || iop->cmnd_len == 10 || iop->cmnd_len == 12 || iop->cmnd_len == 16)) {
3919 set_err(EINVAL, "bad CDB length");
3920 return false;
3921 }
3922
3923 if (report > 0) {
3924 // From os_linux.c
3925 int k, j;
3926 const unsigned char * ucp = iop->cmnd;
3927 const char * np;
3928 char buff[256];
3929 const int sz = (int)sizeof(buff);
3930
3931 np = scsi_get_opcode_name(ucp[0]);
3932 j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
3933 for (k = 0; k < (int)iop->cmnd_len; ++k)
3934 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);
3935 if ((report > 1) &&
3936 (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
3937 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
3938
3939 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing "
3940 "data, len=%d%s:\n", (int)iop->dxfer_len,
3941 (trunc ? " [only first 256 bytes shown]" : ""));
3942 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
3943 }
3944 else
3945 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
3946 pout("%s", buff);
3947 }
3948
3949 ASPI_SRB srb;
3950 memset(&srb, 0, sizeof(srb));
3951 srb.h.cmd = ASPI_CMD_EXECUTE_IO;
3952 srb.h.adapter = m_adapter;
3953 srb.i.target_id = m_id;
3954 //srb.i.lun = 0;
3955 srb.i.sense_size = ASPI_SENSE_SIZE;
3956 srb.i.cdb_size = iop->cmnd_len;
3957 memcpy(srb.i.cdb, iop->cmnd, iop->cmnd_len);
3958
3959 switch (iop->dxfer_dir) {
3960 case DXFER_NONE:
3961 srb.h.flags = ASPI_REQFLAG_DIR_NO_XFER;
3962 break;
3963 case DXFER_FROM_DEVICE:
3964 srb.h.flags = ASPI_REQFLAG_DIR_TO_HOST;
3965 srb.i.data_size = iop->dxfer_len;
3966 srb.i.data_addr = iop->dxferp;
3967 break;
3968 case DXFER_TO_DEVICE:
3969 srb.h.flags = ASPI_REQFLAG_DIR_TO_TARGET;
3970 srb.i.data_size = iop->dxfer_len;
3971 srb.i.data_addr = iop->dxferp;
3972 break;
3973 default:
3974 set_err(EINVAL, "bad dxfer_dir");
3975 return false;
3976 }
3977
3978 iop->resp_sense_len = 0;
3979 iop->scsi_status = 0;
3980 iop->resid = 0;
3981
3982 if (aspi_io_call(&srb, (iop->timeout ? iop->timeout : 60))) {
3983 // Timeout
3984 set_err(EIO, "ASPI Timeout"); return false;
3985 }
3986
3987 if (srb.h.status != ASPI_STATUS_NO_ERROR) {
3988 if ( srb.h.status == ASPI_STATUS_ERROR
3989 && srb.i.host_status == ASPI_HSTATUS_NO_ERROR
3990 && srb.i.target_status == ASPI_TSTATUS_CHECK_CONDITION) {
3991 // Sense valid
3992 const unsigned char * sense = ASPI_SRB_SENSE(&srb.i, iop->cmnd_len);
3993 int len = (ASPI_SENSE_SIZE < iop->max_sense_len ? ASPI_SENSE_SIZE : iop->max_sense_len);
3994 iop->scsi_status = SCSI_STATUS_CHECK_CONDITION;
3995 if (len > 0 && iop->sensep) {
3996 memcpy(iop->sensep, sense, len);
3997 iop->resp_sense_len = len;
3998 if (report > 1) {
3999 pout(" >>> Sense buffer, len=%d:\n", (int)len);
4000 dStrHex(iop->sensep, len , 1);
4001 }
4002 }
4003 if (report) {
4004 pout(" sense_key=%x asc=%x ascq=%x\n",
4005 sense[2] & 0xf, sense[12], sense[13]);
4006 }
4007 return true;
4008 }
4009 else {
4010 if (report)
4011 pout(" ASPI call failed, (0x%02x,0x%02x,0x%02x)\n", srb.h.status, srb.i.host_status, srb.i.target_status);
4012 set_err(EIO);
4013 return false;
4014 }
4015 }
4016
4017 if (report > 0)
4018 pout(" OK\n");
4019
4020 if (iop->dxfer_dir == DXFER_FROM_DEVICE && report > 1) {
4021 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
4022 pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
4023 (trunc ? " [only first 256 bytes shown]" : ""));
4024 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
4025 }
4026
4027 return true;
4028 }
4029
4030 #endif // WIN9X_SUPPORT
4031
4032 /////////////////////////////////////////////////////////////////////////////
4033 // SPT Interface (for SCSI devices and ATA devices behind SATLs)
4034 // Only supported in NT and later
4035 /////////////////////////////////////////////////////////////////////////////
4036
4037 win_scsi_device::win_scsi_device(smart_interface * intf,
4038 const char * dev_name, const char * req_type)
4039 : smart_device(intf, dev_name, "scsi", req_type)
4040 {
4041 }
4042
4043 bool win_scsi_device::open()
4044 {
4045 const char * name = skipdev(get_dev_name()); int len = strlen(name);
4046 // sd[a-z],N => Physical drive 0-26, RAID port N
4047 char drive[1+1] = ""; int sub_addr = -1; int n1 = -1; int n2 = -1;
4048 if ( sscanf(name, "sd%1[a-z]%n,%d%n", drive, &n1, &sub_addr, &n2) >= 1
4049 && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0)) ) {
4050 return open(drive[0] - 'a', -1, -1, sub_addr);
4051 }
4052 // pd<m>,N => Physical drive <m>, RAID port N
4053 int pd_num = -1; sub_addr = -1; n1 = -1; n2 = -1;
4054 if ( sscanf(name, "pd%d%n,%d%n", &pd_num, &n1, &sub_addr, &n2) >= 1
4055 && pd_num >= 0 && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0))) {
4056 return open(pd_num, -1, -1, sub_addr);
4057 }
4058 // [a-zA-Z]: => Physical drive behind logical drive 0-25
4059 int logdrive = drive_letter(name);
4060 if (logdrive >= 0) {
4061 return open(-1, logdrive, -1, -1);
4062 }
4063 // n?st<m> => tape drive <m> (same names used in Cygwin's /dev emulation)
4064 int tape_num = -1; n1 = -1;
4065 if (sscanf(name, "st%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) {
4066 return open(-1, -1, tape_num, -1);
4067 }
4068 tape_num = -1; n1 = -1;
4069 if (sscanf(name, "nst%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) {
4070 return open(-1, -1, tape_num, -1);
4071 }
4072 // tape<m> => tape drive <m>
4073 tape_num = -1; n1 = -1;
4074 if (sscanf(name, "tape%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) {
4075 return open(-1, -1, tape_num, -1);
4076 }
4077
4078 return set_err(EINVAL);
4079 }
4080
4081 bool win_scsi_device::open(int pd_num, int ld_num, int tape_num, int /*sub_addr*/)
4082 {
4083 char b[128];
4084 b[sizeof(b) - 1] = '\0';
4085 if (pd_num >= 0)
4086 snprintf(b, sizeof(b) - 1, "\\\\.\\PhysicalDrive%d", pd_num);
4087 else if (ld_num >= 0)
4088 snprintf(b, sizeof(b) - 1, "\\\\.\\%c:", 'A' + ld_num);
4089 else if (tape_num >= 0)
4090 snprintf(b, sizeof(b) - 1, "\\\\.\\TAPE%d", tape_num);
4091 else {
4092 set_err(EINVAL);
4093 return false;
4094 }
4095
4096 // Open device
4097 HANDLE h = CreateFileA(b, GENERIC_READ|GENERIC_WRITE,
4098 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
4099 OPEN_EXISTING, 0, 0);
4100 if (h == INVALID_HANDLE_VALUE) {
4101 set_err(ENODEV, "%s: Open failed, Error=%ld", b, GetLastError());
4102 return false;
4103 }
4104 set_fh(h);
4105 return true;
4106 }
4107
4108
4109 typedef struct {
4110 SCSI_PASS_THROUGH_DIRECT spt;
4111 ULONG Filler;
4112 UCHAR ucSenseBuf[64];
4113 } SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
4114
4115
4116 // Issue command via IOCTL_SCSI_PASS_THROUGH instead of *_DIRECT.
4117 // Used if DataTransferLength not supported by *_DIRECT.
4118 static long scsi_pass_through_indirect(HANDLE h,
4119 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER * sbd)
4120 {
4121 struct SCSI_PASS_THROUGH_WITH_BUFFERS {
4122 SCSI_PASS_THROUGH spt;
4123 ULONG Filler;
4124 UCHAR ucSenseBuf[sizeof(sbd->ucSenseBuf)];
4125 UCHAR ucDataBuf[512];
4126 };
4127
4128 SCSI_PASS_THROUGH_WITH_BUFFERS sb;
4129 memset(&sb, 0, sizeof(sb));
4130
4131 // DATA_OUT not implemented yet
4132 if (!( sbd->spt.DataIn == SCSI_IOCTL_DATA_IN
4133 && sbd->spt.DataTransferLength <= sizeof(sb.ucDataBuf)))
4134 return ERROR_INVALID_PARAMETER;
4135
4136 sb.spt.Length = sizeof(sb.spt);
4137 sb.spt.CdbLength = sbd->spt.CdbLength;
4138 memcpy(sb.spt.Cdb, sbd->spt.Cdb, sizeof(sb.spt.Cdb));
4139 sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf);
4140 sb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf);
4141 sb.spt.DataIn = sbd->spt.DataIn;
4142 sb.spt.DataTransferLength = sbd->spt.DataTransferLength;
4143 sb.spt.DataBufferOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf);
4144 sb.spt.TimeOutValue = sbd->spt.TimeOutValue;
4145
4146 DWORD num_out;
4147 if (!DeviceIoControl(h, IOCTL_SCSI_PASS_THROUGH,
4148 &sb, sizeof(sb), &sb, sizeof(sb), &num_out, 0))
4149 return GetLastError();
4150
4151 sbd->spt.ScsiStatus = sb.spt.ScsiStatus;
4152 if (sb.spt.ScsiStatus & SCSI_STATUS_CHECK_CONDITION)
4153 memcpy(sbd->ucSenseBuf, sb.ucSenseBuf, sizeof(sbd->ucSenseBuf));
4154
4155 sbd->spt.DataTransferLength = sb.spt.DataTransferLength;
4156 if (sbd->spt.DataIn == SCSI_IOCTL_DATA_IN && sb.spt.DataTransferLength > 0)
4157 memcpy(sbd->spt.DataBuffer, sb.ucDataBuf, sb.spt.DataTransferLength);
4158 return 0;
4159 }
4160
4161
4162 // Interface to SPT SCSI devices. See scsicmds.h and os_linux.c
4163 bool win_scsi_device::scsi_pass_through(struct scsi_cmnd_io * iop)
4164 {
4165 int report = scsi_debugmode; // TODO
4166
4167 if (report > 0) {
4168 int k, j;
4169 const unsigned char * ucp = iop->cmnd;
4170 const char * np;
4171 char buff[256];
4172 const int sz = (int)sizeof(buff);
4173
4174 np = scsi_get_opcode_name(ucp[0]);
4175 j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
4176 for (k = 0; k < (int)iop->cmnd_len; ++k)
4177 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);
4178 if ((report > 1) &&
4179 (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
4180 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
4181
4182 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing "
4183 "data, len=%d%s:\n", (int)iop->dxfer_len,
4184 (trunc ? " [only first 256 bytes shown]" : ""));
4185 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
4186 }
4187 else
4188 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
4189 pout("%s", buff);
4190 }
4191
4192 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb;
4193 if (iop->cmnd_len > (int)sizeof(sb.spt.Cdb)) {
4194 set_err(EINVAL, "cmnd_len too large");
4195 return false;
4196 }
4197
4198 memset(&sb, 0, sizeof(sb));
4199 sb.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
4200 sb.spt.CdbLength = iop->cmnd_len;
4201 memcpy(sb.spt.Cdb, iop->cmnd, iop->cmnd_len);
4202 sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf);
4203 sb.spt.SenseInfoOffset =
4204 offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
4205 sb.spt.TimeOutValue = (iop->timeout ? iop->timeout : 60);
4206
4207 bool direct = true;
4208 switch (iop->dxfer_dir) {
4209 case DXFER_NONE:
4210 sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
4211 break;
4212 case DXFER_FROM_DEVICE:
4213 sb.spt.DataIn = SCSI_IOCTL_DATA_IN;
4214 sb.spt.DataTransferLength = iop->dxfer_len;
4215 sb.spt.DataBuffer = iop->dxferp;
4216 // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte
4217 // transfers (needed for SMART STATUS check of JMicron USB bridges)
4218 if (sb.spt.DataTransferLength == 1)
4219 direct = false;
4220 break;
4221 case DXFER_TO_DEVICE:
4222 sb.spt.DataIn = SCSI_IOCTL_DATA_OUT;
4223 sb.spt.DataTransferLength = iop->dxfer_len;
4224 sb.spt.DataBuffer = iop->dxferp;
4225 break;
4226 default:
4227 set_err(EINVAL, "bad dxfer_dir");
4228 return false;
4229 }
4230
4231 long err = 0;
4232 if (direct) {
4233 DWORD num_out;
4234 if (!DeviceIoControl(get_fh(), IOCTL_SCSI_PASS_THROUGH_DIRECT,
4235 &sb, sizeof(sb), &sb, sizeof(sb), &num_out, 0))
4236 err = GetLastError();
4237 }
4238 else
4239 err = scsi_pass_through_indirect(get_fh(), &sb);
4240
4241 if (err)
4242 return set_err((err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO),
4243 "IOCTL_SCSI_PASS_THROUGH%s failed, Error=%ld",
4244 (direct ? "_DIRECT" : ""), err);
4245
4246 iop->scsi_status = sb.spt.ScsiStatus;
4247 if (SCSI_STATUS_CHECK_CONDITION & iop->scsi_status) {
4248 int slen = sb.ucSenseBuf[7] + 8;
4249
4250 if (slen > (int)sizeof(sb.ucSenseBuf))
4251 slen = sizeof(sb.ucSenseBuf);
4252 if (slen > (int)iop->max_sense_len)
4253 slen = iop->max_sense_len;
4254 memcpy(iop->sensep, sb.ucSenseBuf, slen);
4255 iop->resp_sense_len = slen;
4256 if (report) {
4257 if (report > 1) {
4258 pout(" >>> Sense buffer, len=%d:\n", slen);
4259 dStrHex(iop->sensep, slen , 1);
4260 }
4261 if ((iop->sensep[0] & 0x7f) > 0x71)
4262 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
4263 iop->scsi_status, iop->sensep[1] & 0xf,
4264 iop->sensep[2], iop->sensep[3]);
4265 else
4266 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
4267 iop->scsi_status, iop->sensep[2] & 0xf,
4268 iop->sensep[12], iop->sensep[13]);
4269 }
4270 } else
4271 iop->resp_sense_len = 0;
4272
4273 if ((iop->dxfer_len > 0) && (sb.spt.DataTransferLength > 0))
4274 iop->resid = iop->dxfer_len - sb.spt.DataTransferLength;
4275 else
4276 iop->resid = 0;
4277
4278 if ((iop->dxfer_dir == DXFER_FROM_DEVICE) && (report > 1)) {
4279 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
4280 pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
4281 (trunc ? " [only first 256 bytes shown]" : ""));
4282 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
4283 }
4284 return true;
4285 }
4286
4287 // Interface to SPT SCSI devices. See scsicmds.h and os_linux.c
4288 static long scsi_pass_through_direct(HANDLE fd, struct scsi_cmnd_io * iop)
4289 {
4290 int report = scsi_debugmode; // TODO
4291
4292 if (report > 0) {
4293 int k, j;
4294 const unsigned char * ucp = iop->cmnd;
4295 const char * np;
4296 char buff[256];
4297 const int sz = (int)sizeof(buff);
4298
4299 np = scsi_get_opcode_name(ucp[0]);
4300 j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
4301 for (k = 0; k < (int)iop->cmnd_len; ++k)
4302 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);
4303 if ((report > 1) &&
4304 (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
4305 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
4306
4307 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing "
4308 "data, len=%d%s:\n", (int)iop->dxfer_len,
4309 (trunc ? " [only first 256 bytes shown]" : ""));
4310 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
4311 }
4312 else
4313 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
4314 pout("%s", buff);
4315 }
4316
4317 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb;
4318 if (iop->cmnd_len > (int)sizeof(sb.spt.Cdb)) {
4319 return EINVAL;
4320 }
4321
4322 memset(&sb, 0, sizeof(sb));
4323 sb.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
4324 //sb.spt.PathId = 0;
4325 sb.spt.TargetId = 127;
4326 //sb.spt.Lun = 0;
4327 sb.spt.CdbLength = iop->cmnd_len;
4328 memcpy(sb.spt.Cdb, iop->cmnd, iop->cmnd_len);
4329 sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf);
4330 sb.spt.SenseInfoOffset =
4331 offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
4332 sb.spt.TimeOutValue = (iop->timeout ? iop->timeout : 60);
4333
4334 bool direct = true;
4335 switch (iop->dxfer_dir) {
4336 case DXFER_NONE:
4337 sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
4338 break;
4339 case DXFER_FROM_DEVICE:
4340 sb.spt.DataIn = SCSI_IOCTL_DATA_IN;
4341 sb.spt.DataTransferLength = iop->dxfer_len;
4342 sb.spt.DataBuffer = iop->dxferp;
4343 // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte
4344 // transfers (needed for SMART STATUS check of JMicron USB bridges)
4345 if (sb.spt.DataTransferLength == 1)
4346 direct = false;
4347 break;
4348 case DXFER_TO_DEVICE:
4349 sb.spt.DataIn = SCSI_IOCTL_DATA_OUT;
4350 sb.spt.DataTransferLength = iop->dxfer_len;
4351 sb.spt.DataBuffer = iop->dxferp;
4352 break;
4353 default:
4354 return EINVAL;
4355 }
4356
4357 long err = 0;
4358 if (direct) {
4359 DWORD num_out;
4360 if (!DeviceIoControl(fd, IOCTL_SCSI_PASS_THROUGH_DIRECT,
4361 &sb, sizeof(sb), &sb, sizeof(sb), &num_out, 0))
4362 err = GetLastError();
4363 }
4364 else
4365 err = scsi_pass_through_indirect(fd, &sb);
4366
4367 if (err)
4368 {
4369 return err;
4370 }
4371
4372 iop->scsi_status = sb.spt.ScsiStatus;
4373 if (SCSI_STATUS_CHECK_CONDITION & iop->scsi_status) {
4374 int slen = sb.ucSenseBuf[7] + 8;
4375
4376 if (slen > (int)sizeof(sb.ucSenseBuf))
4377 slen = sizeof(sb.ucSenseBuf);
4378 if (slen > (int)iop->max_sense_len)
4379 slen = iop->max_sense_len;
4380 memcpy(iop->sensep, sb.ucSenseBuf, slen);
4381 iop->resp_sense_len = slen;
4382 if (report) {
4383 if (report > 1) {
4384 pout(" >>> Sense buffer, len=%d:\n", slen);
4385 dStrHex(iop->sensep, slen , 1);
4386 }
4387 if ((iop->sensep[0] & 0x7f) > 0x71)
4388 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
4389 iop->scsi_status, iop->sensep[1] & 0xf,
4390 iop->sensep[2], iop->sensep[3]);
4391 else
4392 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
4393 iop->scsi_status, iop->sensep[2] & 0xf,
4394 iop->sensep[12], iop->sensep[13]);
4395 }
4396 } else
4397 iop->resp_sense_len = 0;
4398
4399 if ((iop->dxfer_len > 0) && (sb.spt.DataTransferLength > 0))
4400 iop->resid = iop->dxfer_len - sb.spt.DataTransferLength;
4401 else
4402 iop->resid = 0;
4403
4404 if ((iop->dxfer_dir == DXFER_FROM_DEVICE) && (report > 1)) {
4405 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
4406 pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
4407 (trunc ? " [only first 256 bytes shown]" : ""));
4408 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
4409 }
4410
4411 return 0;
4412 }
4413
4414
4415 #if 0 // For debugging areca code
4416
4417 static void dumpdata(unsigned char *block, int len)
4418 {
4419 int ln = (len / 16) + 1; // total line#
4420 unsigned char c;
4421 int pos = 0;
4422
4423 printf(" Address = %p, Length = (0x%x)%d\n", block, len, len);
4424 printf(" 0 1 2 3 4 5 6 7 8 9 A B C D E F ASCII \n");
4425 printf("=====================================================================\n");
4426
4427 for ( int l = 0; l < ln && len; l++ )
4428 {
4429 // printf the line# and the HEX data
4430 // if a line data length < 16 then append the space to the tail of line to reach 16 chars
4431 printf("%02X | ", l);
4432 for ( pos = 0; pos < 16 && len; pos++, len-- )
4433 {
4434 c = block[l*16+pos];
4435 printf("%02X ", c);
4436 }
4437
4438 if ( pos < 16 )
4439 {
4440 for ( int loop = pos; loop < 16; loop++ )
4441 {
4442 printf(" ");
4443 }
4444 }
4445
4446 // print ASCII char
4447 for ( int loop = 0; loop < pos; loop++ )
4448 {
4449 c = block[l*16+loop];
4450 if ( c >= 0x20 && c <= 0x7F )
4451 {
4452 printf("%c", c);
4453 }
4454 else
4455 {
4456 printf(".");
4457 }
4458 }
4459 printf("\n");
4460 }
4461 printf("=====================================================================\n");
4462 }
4463
4464 #endif
4465
4466 // PURPOSE
4467 // This is an interface routine meant to isolate the OS dependent
4468 // parts of the code, and to provide a debugging interface. Each
4469 // different port and OS needs to provide it's own interface. This
4470 // is the Windows interface to the Areca "arcmsr" driver. It allows ATA
4471 // commands to be passed through the SCSI driver.
4472 // DETAILED DESCRIPTION OF ARGUMENTS
4473 // fd: is the file descriptor provided by open()
4474 // disknum is the disk number (0 to 127) in the RAID array
4475 // command: defines the different operations.
4476 // select: additional input data if needed (which log, which type of
4477 // self-test).
4478 // data: location to write output data, if needed (512 bytes).
4479 // Note: not all commands use all arguments.
4480 // RETURN VALUES
4481 // -1 if the command failed
4482 // 0 if the command succeeded,
4483 // STATUS_CHECK routine:
4484 // -1 if the command failed
4485 // 0 if the command succeeded and disk SMART status is "OK"
4486 // 1 if the command succeeded and disk SMART status is "FAILING"
4487 int win_areca_device::arcmsr_command_handler(HANDLE fd, unsigned long arcmsr_cmd, unsigned char *data, int data_len)
4488 {
4489 int ioctlreturn = 0;
4490 sSRB_BUFFER sBuf;
4491 struct scsi_cmnd_io io_hdr;
4492 int dir = DXFER_TO_DEVICE;
4493
4494 UINT8 cdb[10];
4495 UINT8 sense[32];
4496
4497 unsigned char *areca_return_packet;
4498 int total = 0;
4499 int expected = -1;
4500 unsigned char return_buff[2048];
4501 unsigned char *ptr = &return_buff[0];
4502 memset(return_buff, 0, sizeof(return_buff));
4503
4504 memset((unsigned char *)&sBuf, 0, sizeof(sBuf));
4505 memset(&io_hdr, 0, sizeof(io_hdr));
4506 memset(cdb, 0, sizeof(cdb));
4507 memset(sense, 0, sizeof(sense));
4508
4509
4510 sBuf.srbioctl.HeaderLength = sizeof(sSRB_IO_CONTROL);
4511 memcpy(sBuf.srbioctl.Signature, ARECA_SIG_STR, strlen(ARECA_SIG_STR));
4512 sBuf.srbioctl.Timeout = 10000;
4513 sBuf.srbioctl.ControlCode = arcmsr_cmd;
4514
4515 switch ( arcmsr_cmd )
4516 {
4517 // command for writing data to driver
4518 case ARCMSR_IOCTL_WRITE_WQBUFFER:
4519 if ( data && data_len )
4520 {
4521 sBuf.srbioctl.Length = data_len;
4522 memcpy((unsigned char *)sBuf.ioctldatabuffer, (unsigned char *)data, data_len);
4523 }
4524 // commands for clearing related buffer of driver
4525 case ARCMSR_IOCTL_CLEAR_RQBUFFER:
4526 case ARCMSR_IOCTL_CLEAR_WQBUFFER:
4527 cdb[0] = 0x3B; //SCSI_WRITE_BUF command;
4528 break;
4529 // command for reading data from driver
4530 case ARCMSR_IOCTL_READ_RQBUFFER:
4531 // command for identifying driver
4532 case ARCMSR_IOCTL_RETURN_CODE_3F:
4533 cdb[0] = 0x3C; //SCSI_READ_BUF command;
4534 dir = DXFER_FROM_DEVICE;
4535 break;
4536 default:
4537 // unknown arcmsr commands
4538 return -1;
4539 }
4540
4541 cdb[1] = 0x01;
4542 cdb[2] = 0xf0;
4543
4544 io_hdr.dxfer_dir = dir;
4545 io_hdr.dxfer_len = sizeof(sBuf);
4546 io_hdr.dxferp = (unsigned char *)&sBuf;
4547 io_hdr.cmnd = cdb;
4548 io_hdr.cmnd_len = sizeof(cdb);
4549 io_hdr.sensep = sense;
4550 io_hdr.max_sense_len = sizeof(sense);
4551 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
4552
4553 while ( 1 )
4554 {
4555 ioctlreturn = scsi_pass_through_direct(fd, &io_hdr);
4556 if ( ioctlreturn || io_hdr.scsi_status )
4557 {
4558 // errors found
4559 break;
4560 }
4561
4562 if ( arcmsr_cmd != ARCMSR_IOCTL_READ_RQBUFFER )
4563 {
4564 // if succeeded, just returns the length of outgoing data
4565 return data_len;
4566 }
4567
4568 if ( sBuf.srbioctl.Length )
4569 {
4570 //dumpdata(&sBuf.ioctldatabuffer[0], sBuf.srbioctl.Length);
4571 memcpy(ptr, &sBuf.ioctldatabuffer[0], sBuf.srbioctl.Length);
4572 ptr += sBuf.srbioctl.Length;
4573 total += sBuf.srbioctl.Length;
4574 // the returned bytes enough to compute payload length ?
4575 if ( expected < 0 && total >= 5 )
4576 {
4577 areca_return_packet = (unsigned char *)&return_buff[0];
4578 if ( areca_return_packet[0] == 0x5E &&
4579 areca_return_packet[1] == 0x01 &&
4580 areca_return_packet[2] == 0x61 )
4581 {
4582 // valid header, let's compute the returned payload length,
4583 // we expected the total length is
4584 // payload + 3 bytes header + 2 bytes length + 1 byte checksum
4585 expected = areca_return_packet[4] * 256 + areca_return_packet[3] + 6;
4586 }
4587 }
4588
4589 if ( total >= 7 && total >= expected )
4590 {
4591 //printf("total bytes received = %d, expected length = %d\n", total, expected);
4592
4593 // ------ Okay! we received enough --------
4594 break;
4595 }
4596 }
4597 }
4598
4599 // Deal with the different error cases
4600 if ( arcmsr_cmd == ARCMSR_IOCTL_RETURN_CODE_3F )
4601 {
4602 // Silence the ARCMSR_IOCTL_RETURN_CODE_3F's error, no pout(...)
4603 return -4;
4604 }
4605
4606 if ( ioctlreturn )
4607 {
4608 pout("do_scsi_cmnd_io with write buffer failed code = %x\n", ioctlreturn);
4609 return -2;
4610 }
4611
4612 if ( io_hdr.scsi_status )
4613 {
4614 pout("io_hdr.scsi_status with write buffer failed code = %x\n", io_hdr.scsi_status);
4615 return -3;
4616 }
4617
4618 if ( data )
4619 {
4620 memcpy(data, return_buff, total);
4621 }
4622
4623 return total;
4624 }
4625
4626
4627 win_areca_device::win_areca_device(smart_interface * intf, const char * dev_name, HANDLE fh, int disknum, int encnum)
4628 : smart_device(intf, dev_name, "areca", "areca"),
4629 m_disknum(disknum),
4630 m_encnum(encnum)
4631 {
4632 set_fh(fh);
4633 set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);
4634 }
4635
4636 bool win_areca_device::open()
4637 {
4638 HANDLE hFh;
4639
4640 if( is_open() )
4641 {
4642 return true;
4643 }
4644
4645 hFh = CreateFile( get_dev_name(),
4646 GENERIC_READ|GENERIC_WRITE,
4647 FILE_SHARE_READ|FILE_SHARE_WRITE,
4648 NULL,
4649 OPEN_EXISTING,
4650 0,
4651 NULL );
4652 if(hFh == INVALID_HANDLE_VALUE)
4653 {
4654 return false;
4655 }
4656
4657 set_fh(hFh);
4658 return true;
4659 }
4660
4661 // Areca RAID Controller
4662 bool win_areca_device::arcmsr_ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
4663 {
4664 // ATA input registers
4665 typedef struct _ATA_INPUT_REGISTERS
4666 {
4667 unsigned char features;
4668 unsigned char sector_count;
4669 unsigned char sector_number;
4670 unsigned char cylinder_low;
4671 unsigned char cylinder_high;
4672 unsigned char device_head;
4673 unsigned char command;
4674 unsigned char reserved[8];
4675 unsigned char data[512]; // [in/out] buffer for outgoing/incoming data
4676 } sATA_INPUT_REGISTERS;
4677
4678 // ATA output registers
4679 // Note: The output registers is re-sorted for areca internal use only
4680 typedef struct _ATA_OUTPUT_REGISTERS
4681 {
4682 unsigned char error;
4683 unsigned char status;
4684 unsigned char sector_count;
4685 unsigned char sector_number;
4686 unsigned char cylinder_low;
4687 unsigned char cylinder_high;
4688 } sATA_OUTPUT_REGISTERS;
4689
4690 // Areca packet format for outgoing:
4691 // B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61
4692 // B[3~4] : 2 bytes command length + variant data length, little endian
4693 // B[5] : 1 bytes areca defined command code, ATA passthrough command code is 0x1c
4694 // B[6~last-1] : variant bytes payload data
4695 // B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1])
4696 //
4697 //
4698 // header 3 bytes length 2 bytes cmd 1 byte payload data x bytes cs 1 byte
4699 // +--------------------------------------------------------------------------------+
4700 // + 0x5E 0x01 0x61 | 0x00 0x00 | 0x1c | .................... | 0x00 |
4701 // +--------------------------------------------------------------------------------+
4702 //
4703
4704 //Areca packet format for incoming:
4705 // B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61
4706 // B[3~4] : 2 bytes payload length, little endian
4707 // B[5~last-1] : variant bytes returned payload data
4708 // B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1])
4709 //
4710 //
4711 // header 3 bytes length 2 bytes payload data x bytes cs 1 byte
4712 // +-------------------------------------------------------------------+
4713 // + 0x5E 0x01 0x61 | 0x00 0x00 | .................... | 0x00 |
4714 // +-------------------------------------------------------------------+
4715 unsigned char areca_packet[640];
4716 int areca_packet_len = sizeof(areca_packet);
4717 unsigned char cs = 0;
4718
4719 sATA_INPUT_REGISTERS *ata_cmd;
4720
4721 // For debugging
4722 #if 0
4723 memset(sInq, 0, sizeof(sInq));
4724 scsiStdInquiry(fd, (unsigned char *)sInq, (int)sizeof(sInq));
4725 dumpdata((unsigned char *)sInq, sizeof(sInq));
4726 #endif
4727 memset(areca_packet, 0, areca_packet_len);
4728
4729 // ----- BEGIN TO SETUP HEADERS -------
4730 areca_packet[0] = 0x5E;
4731 areca_packet[1] = 0x01;
4732 areca_packet[2] = 0x61;
4733 areca_packet[3] = (unsigned char)((areca_packet_len - 6) & 0xff);
4734 areca_packet[4] = (unsigned char)(((areca_packet_len - 6) >> 8) & 0xff);
4735 areca_packet[5] = 0x1c; // areca defined code for ATA passthrough command
4736
4737 // ----- BEGIN TO SETUP PAYLOAD DATA -----
4738 memcpy(&areca_packet[7], "SmrT", 4); // areca defined password
4739 ata_cmd = (sATA_INPUT_REGISTERS *)&areca_packet[12];
4740
4741 // Set registers
4742 {
4743 const ata_in_regs & r = in.in_regs;
4744 ata_cmd->features = r.features;
4745 ata_cmd->sector_count = r.sector_count;
4746 ata_cmd->sector_number = r.lba_low;
4747 ata_cmd->cylinder_low = r.lba_mid;
4748 ata_cmd->cylinder_high = r.lba_high;
4749 ata_cmd->device_head = r.device;
4750 ata_cmd->command = r.command;
4751 }
4752 bool readdata = false;
4753 if (in.direction == ata_cmd_in::data_in) {
4754 readdata = true;
4755 // the command will read data
4756 areca_packet[6] = 0x13;
4757 }
4758 else if ( in.direction == ata_cmd_in::no_data )
4759 {
4760 // the commands will return no data
4761 areca_packet[6] = 0x15;
4762 }
4763 else if (in.direction == ata_cmd_in::data_out)
4764 {
4765 // the commands will write data
4766 memcpy(ata_cmd->data, in.buffer, in.size);
4767 areca_packet[6] = 0x14;
4768 }
4769 else {
4770 // COMMAND NOT SUPPORTED VIA ARECA IOCTL INTERFACE
4771 return set_err(ENOSYS);
4772 }
4773
4774 areca_packet[11] = m_disknum - 1; // disk#
4775 areca_packet[19] = m_encnum - 1; // enc#
4776
4777 // ----- BEGIN TO SETUP CHECKSUM -----
4778 for ( int loop = 3; loop < areca_packet_len - 1; loop++ )
4779 {
4780 cs += areca_packet[loop];
4781 }
4782 areca_packet[areca_packet_len-1] = cs;
4783
4784 // ----- BEGIN TO SEND TO ARECA DRIVER ------
4785 int expected = 0;
4786 unsigned char return_buff[2048];
4787 memset(return_buff, 0, sizeof(return_buff));
4788
4789 expected = arcmsr_command_handler(get_fh(), ARCMSR_IOCTL_CLEAR_RQBUFFER, NULL, 0);
4790 if (expected==-3) {
4791 return set_err(EIO);
4792 }
4793
4794 expected = arcmsr_command_handler(get_fh(), ARCMSR_IOCTL_CLEAR_WQBUFFER, NULL, 0);
4795 expected = arcmsr_command_handler(get_fh(), ARCMSR_IOCTL_WRITE_WQBUFFER, areca_packet, areca_packet_len);
4796 if ( expected > 0 )
4797 {
4798 expected = arcmsr_command_handler(get_fh(), ARCMSR_IOCTL_READ_RQBUFFER, return_buff, sizeof(return_buff));
4799 }
4800 if ( expected < 0 )
4801 {
4802 return set_err(EIO);
4803 }
4804
4805 // ----- VERIFY THE CHECKSUM -----
4806 cs = 0;
4807 for ( int loop = 3; loop < expected - 1; loop++ )
4808 {
4809 cs += return_buff[loop];
4810 }
4811
4812 if ( return_buff[expected - 1] != cs )
4813 {
4814 return set_err(EIO);
4815 }
4816
4817 sATA_OUTPUT_REGISTERS *ata_out = (sATA_OUTPUT_REGISTERS *)&return_buff[5] ;
4818 if ( ata_out->status )
4819 {
4820 if ( in.in_regs.command == ATA_IDENTIFY_DEVICE
4821 && !nonempty((unsigned char *)in.buffer, in.size))
4822 {
4823 return set_err(ENODEV, "No drive on port %d", m_disknum);
4824 }
4825 }
4826
4827 // returns with data
4828 if (readdata)
4829 {
4830 memcpy(in.buffer, &return_buff[7], in.size);
4831 }
4832
4833 // Return register values
4834 {
4835 ata_out_regs & r = out.out_regs;
4836 r.error = ata_out->error;
4837 r.sector_count = ata_out->sector_count;
4838 r.lba_low = ata_out->sector_number;
4839 r.lba_mid = ata_out->cylinder_low;
4840 r.lba_high = ata_out->cylinder_high;
4841 r.status = ata_out->status;
4842 }
4843 return true;
4844 }
4845
4846
4847 bool win_areca_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
4848 {
4849 #define SYNCOBJNAME "Global\\SynIoctlMutex"
4850 int ctlrnum = -1;
4851 char mutexstr[64];
4852 SECURITY_ATTRIBUTES sa;
4853 PSECURITY_DESCRIPTOR pSD;
4854 HANDLE hmutex;
4855
4856 if (!ata_cmd_is_ok(in,
4857 true, // data_out_support
4858 false, // TODO: multi_sector_support
4859 true) // ata_48bit_support
4860 )
4861 return false;
4862
4863 // Support 48-bit commands with zero high bytes
4864 if (in.in_regs.is_real_48bit_cmd())
4865 return set_err(ENOSYS, "48-bit ATA commands not fully supported by Areca");
4866
4867 if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum) < 1)
4868 return set_err(EINVAL, "unable to parse device name");
4869
4870 memset(mutexstr, 0, sizeof(mutexstr));
4871 sprintf(mutexstr, "%s%d",SYNCOBJNAME, ctlrnum);
4872 pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
4873 if ( !InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION) )
4874 {
4875 LocalFree((HLOCAL)pSD);
4876 return set_err(EIO, "InitializeSecurityDescriptor failed");
4877 }
4878
4879 if ( !SetSecurityDescriptorDacl(pSD, TRUE, (PACL)NULL, FALSE) )
4880 {
4881 LocalFree((HLOCAL)pSD);
4882 return set_err(EIO, "SetSecurityDescriptor failed");
4883 }
4884
4885 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
4886 sa.lpSecurityDescriptor = pSD;
4887 sa.bInheritHandle = TRUE;
4888 hmutex = CreateMutex(&sa, FALSE, mutexstr);
4889 if ( hmutex == NULL )
4890 {
4891 LocalFree((HLOCAL)pSD);
4892 return set_err(EIO, "CreateMutex failed");
4893 }
4894
4895 // atomic access to driver
4896 WaitForSingleObject(hmutex, INFINITE);
4897 bool ok = arcmsr_ata_pass_through(in,out);
4898 ReleaseMutex(hmutex);
4899
4900 if(hmutex)
4901 {
4902 CloseHandle(hmutex);
4903 }
4904
4905 if ( (HLOCAL)pSD )
4906 {
4907 LocalFree((HLOCAL)pSD);
4908 }
4909
4910 return ok;
4911 }
4912
4913
4914 //////////////////////////////////////////////////////////////////////////////////////////////////
4915
4916
4917 } // namespace
4918
4919 /////////////////////////////////////////////////////////////////////////////
4920
4921 // Initialize platform interface and register with smi()
4922 void smart_interface::init()
4923 {
4924 {
4925 // Remove "." from DLL search path if supported
4926 // to prevent DLL preloading attacks
4927 BOOL (WINAPI * SetDllDirectoryA_p)(LPCSTR) = (BOOL (WINAPI *)(LPCSTR))
4928 GetProcAddress(GetModuleHandleA("kernel32.dll"), "SetDllDirectoryA");
4929 if (SetDllDirectoryA_p)
4930 SetDllDirectoryA_p("");
4931 }
4932
4933 // Select interface for Windows flavor
4934 if (GetVersion() & 0x80000000) {
4935 #if WIN9X_SUPPORT
4936 static os_win32::win9x_smart_interface the_win9x_interface;
4937 smart_interface::set(&the_win9x_interface);
4938 #else
4939 throw std::runtime_error("Win9x/ME not supported");
4940 #endif
4941 }
4942 else {
4943 static os_win32::winnt_smart_interface the_winnt_interface;
4944 smart_interface::set(&the_winnt_interface);
4945 }
4946 }
4947
4948
4949 #ifndef __CYGWIN__
4950
4951 // Get exe directory
4952 // (prototype in utiliy.h)
4953 std::string get_exe_dir()
4954 {
4955 char path[MAX_PATH];
4956 // Get path of this exe
4957 if (!GetModuleFileNameA(GetModuleHandleA(0), path, sizeof(path)))
4958 throw std::runtime_error("GetModuleFileName() failed");
4959 // Replace backslash by slash
4960 int sl = -1;
4961 for (int i = 0; path[i]; i++)
4962 if (path[i] == '\\') {
4963 path[i] = '/'; sl = i;
4964 }
4965 // Remove filename
4966 if (sl >= 0)
4967 path[sl] = 0;
4968 return path;
4969 }
4970
4971 #endif