Annotation of embedaddon/smartmontools/os_win32.cpp, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>