Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  08:29[Войти] | [Зарегистрироваться]
Ответ на вопрос № 22629

25-05-2004 11:47
Народ как програмно прочитать SMART винта,
а именно температуру.
заранее благодарен за ответ.
MSW

[+] Добавить в избранные вопросы

Отслеживать ответы на этот вопрос по RSS

Ответы:


Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице.
Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.

11-07-2006 16:02
Пробрвал запустить, не работает....  а иммнео чтение смартов... DeviceIoControl с любой из DFP комманд даёт false и GetLastError() = 1 то есть unknown command. ( HDD поддерживает SMART так что предположение что драйвер не распознаёт комманду не верно).

26-05-2004 10:20 | Сообщение от автора вопроса
Все работает.
С уважением MSW
 

26-05-2004 10:17 | Сообщение от автора вопроса
Спасибо все работает.
с уважением MSW
 

25-05-2004 18:28
Вот пример, переделанный из VC++:

Модуль, который я когда-то скачал из нета:

// (c) Alex Konshin    12 jul 2000      mailto:alexk@mtgroup.ru

// Code based on C code from MSDN -> KB: Windows development
// -> SAMPLE: SmartApp.exe

// for mor information about S.M.A.R.T. ioctl see
//  http://www.microsoft.com/hwdev/respec/storspec.htm
//  http://www.microsoft.com/hwdev/download/respec/iocltapi.rtf

// see also sample SmartApp from MSDN Knowledge Base
//  Windows Development -> Win32 Device Driver Kit ->
//  SAMPLE: SmartApp.exe Accesses SMART stats in IDE drives


unit Ioctl;



interface

uses
           Windows;

type
           USHORT = Word;
           DEVICE_TYPE = ULONG;

//=============================================================
// Define the various device type values.
// Note that values used by Microsoft Corporation are in the range 0-32767,
// and 32768-65535 are reserved for use by customers.
const
  MAX_IDE_DRIVES = 8;
  NUM_ATTRIBUTE_STRUCTS = 30;

           FILE_DEVICE_BEEP                = $00000001;
           FILE_DEVICE_CD_ROM              = $00000002;
           FILE_DEVICE_CD_ROM_FILE_SYSTEM  = $00000003;
           FILE_DEVICE_CONTROLLER          = $00000004;
           FILE_DEVICE_DATALINK            = $00000005;
           FILE_DEVICE_DFS                = $00000006;
           FILE_DEVICE_DISK                = $00000007;
           FILE_DEVICE_DISK_FILE_SYSTEM    = $00000008;
           FILE_DEVICE_FILE_SYSTEM        = $00000009;
           FILE_DEVICE_INPORT_PORT        = $0000000a;
           FILE_DEVICE_KEYBOARD            = $0000000b;
           FILE_DEVICE_MAILSLOT            = $0000000c;
           FILE_DEVICE_MIDI_IN            = $0000000d;
           FILE_DEVICE_MIDI_OUT            = $0000000e;
           FILE_DEVICE_MOUSE              = $0000000f;
           FILE_DEVICE_MULTI_UNC_PROVIDER  = $00000010;
           FILE_DEVICE_NAMED_PIPE          = $00000011;
           FILE_DEVICE_NETWORK            = $00000012;
           FILE_DEVICE_NETWORK_BROWSER    = $00000013;
           FILE_DEVICE_NETWORK_FILE_SYSTEM = $00000014;
           FILE_DEVICE_NULL                = $00000015;
           FILE_DEVICE_PARALLEL_PORT      = $00000016;
           FILE_DEVICE_PHYSICAL_NETCARD    = $00000017;
           FILE_DEVICE_PRINTER            = $00000018;
           FILE_DEVICE_SCANNER            = $00000019;
           FILE_DEVICE_SERIAL_MOUSE_PORT  = $0000001a;
           FILE_DEVICE_SERIAL_PORT        = $0000001b;
           FILE_DEVICE_SCREEN              = $0000001c;
           FILE_DEVICE_SOUND              = $0000001d;
           FILE_DEVICE_STREAMS            = $0000001e;
           FILE_DEVICE_TAPE                = $0000001f;
           FILE_DEVICE_TAPE_FILE_SYSTEM    = $00000020;
           FILE_DEVICE_TRANSPORT          = $00000021;
           FILE_DEVICE_UNKNOWN            = $00000022;
           FILE_DEVICE_VIDEO              = $00000023;
           FILE_DEVICE_VIRTUAL_DISK        = $00000024;
           FILE_DEVICE_WAVE_IN            = $00000025;
           FILE_DEVICE_WAVE_OUT            = $00000026;
           FILE_DEVICE_8042_PORT          = $00000027;
           FILE_DEVICE_NETWORK_REDIRECTOR  = $00000028;
           FILE_DEVICE_BATTERY            = $00000029;
           FILE_DEVICE_BUS_EXTENDER        = $0000002a;
           FILE_DEVICE_MODEM              = $0000002b;
           FILE_DEVICE_VDM                = $0000002c;
           FILE_DEVICE_MASS_STORAGE        = $0000002d;
           FILE_DEVICE_SMB                = $0000002e;
           FILE_DEVICE_KS                  = $0000002f;
           FILE_DEVICE_CHANGER            = $00000030;
           FILE_DEVICE_SMARTCARD          = $00000031;
           FILE_DEVICE_ACPI                = $00000032;
           FILE_DEVICE_DVD                = $00000033;
           FILE_DEVICE_FULLSCREEN_VIDEO    = $00000034;
           FILE_DEVICE_DFS_FILE_SYSTEM    = $00000035;
           FILE_DEVICE_DFS_VOLUME          = $00000036;
           FILE_DEVICE_SERENUM            = $00000037;
           FILE_DEVICE_TERMSRV            = $00000038;
           FILE_DEVICE_KSEC                = $00000039;

const
           READ_ATTRIBUTE_BUFFER_SIZE = 512;
           IDENTIFY_BUFFER_SIZE      = 512;
           READ_THRESHOLD_BUFFER_SIZE = 512;


const
// SMART IOCTL commands
           DFP_GET_VERSION        = $00074080;
           DFP_SEND_DRIVE_COMMAND = $0007c084;
           DFP_RECEIVE_DRIVE_DATA = $0007c088;

const
           IOCTL_STORAGE_BASE = FILE_DEVICE_MASS_STORAGE;
           IOCTL_SCSI_BASE    = FILE_DEVICE_CONTROLLER;

// Define the method codes for how buffers are passed for I/O and FS controls
           METHOD_BUFFERED  = 0;
           METHOD_IN_DIRECT  = 1;
           METHOD_OUT_DIRECT = 2;
           METHOD_NEITHER    = 3;

// Define the access check value for any access
  FILE_ANY_ACCESS    = 0;
  FILE_SPECIAL_ACCESS = FILE_ANY_ACCESS;
  FILE_READ_ACCESS    = $0001; // file & pipe
  FILE_WRITE_ACCESS  = $0002; // file & pipe


//#define IOCTL_STORAGE_GET_MEDIA_TYPES  CTL_CODE(IOCTL_STORAGE_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS)
           IOCTL_STORAGE_GET_MEDIA_TYPES = (IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0300 shl 2) or (METHOD_BUFFERED);

//#define IOCTL_STORAGE_GET_MEDIA_TYPES_EX CTL_CODE(IOCTL_STORAGE_BASE, 0x0301, METHOD_BUFFERED, FILE_ANY_ACCESS)
           IOCTL_STORAGE_GET_MEDIA_TYPES_EX = (IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0301 shl 2) or (METHOD_BUFFERED);

//#define IOCTL_STORAGE_GET_DEVICE_NUMBER CTL_CODE(IOCTL_STORAGE_BASE, 0x0420, METHOD_BUFFERED, FILE_ANY_ACCESS)
           IOCTL_STORAGE_GET_DEVICE_NUMBER = (IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0420 shl 2) or (METHOD_BUFFERED);

//#define IOCTL_SCSI_PASS_THROUGH        CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
           IOCTL_SCSI_PASS_THROUGH = (IOCTL_SCSI_BASE shl 16) or ((FILE_READ_ACCESS or FILE_WRITE_ACCESS) shl 14) or ($0401 shl 2) or (METHOD_BUFFERED);

//#define IOCTL_SCSI_MINIPORT            CTL_CODE(IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
           IOCTL_SCSI_MINIPORT = (IOCTL_SCSI_BASE shl 16) or ((FILE_READ_ACCESS or FILE_WRITE_ACCESS) shl 14) or ($0402 shl 2) or (METHOD_BUFFERED);

//#define IOCTL_SCSI_GET_INQUIRY_DATA    CTL_CODE(IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS)
           IOCTL_SCSI_GET_INQUIRY_DATA = (IOCTL_SCSI_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0403 shl 2) or (METHOD_BUFFERED);

//#define IOCTL_SCSI_GET_CAPABILITIES    CTL_CODE(IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS)
           IOCTL_SCSI_GET_CAPABILITIES = (IOCTL_SCSI_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0404 shl 2) or (METHOD_BUFFERED);

//#define IOCTL_SCSI_PASS_THROUGH_DIRECT  CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
           IOCTL_SCSI_PASS_THROUGH_DIRECT = (IOCTL_SCSI_BASE shl 16) or ((FILE_READ_ACCESS or FILE_WRITE_ACCESS) shl 14) or ($0405 shl 2) or (METHOD_BUFFERED);

//#define IOCTL_SCSI_GET_ADDRESS          CTL_CODE(IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS)
           IOCTL_SCSI_GET_ADDRESS = (IOCTL_SCSI_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0406 shl 2) or (METHOD_BUFFERED);

//#define IOCTL_SCSI_RESCAN_BUS          CTL_CODE(IOCTL_SCSI_BASE, 0x0407, METHOD_BUFFERED, FILE_ANY_ACCESS)
           IOCTL_SCSI_RESCAN_BUS = (IOCTL_SCSI_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0407 shl 2) or (METHOD_BUFFERED);

//#define IOCTL_SCSI_GET_DUMP_POINTERS    CTL_CODE(IOCTL_SCSI_BASE, 0x0408, METHOD_BUFFERED, FILE_ANY_ACCESS)
           IOCTL_SCSI_GET_DUMP_POINTERS = (IOCTL_SCSI_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0408 shl 2) or (METHOD_BUFFERED);

//#define IOCTL_SCSI_FREE_DUMP_POINTERS  CTL_CODE(IOCTL_SCSI_BASE, 0x0409, METHOD_BUFFERED, FILE_ANY_ACCESS)
           IOCTL_SCSI_GET_FREE_DUMP_POINTERS = (IOCTL_SCSI_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0409 shl 2) or (METHOD_BUFFERED);

//#define IOCTL_IDE_PASS_THROUGH          CTL_CODE(IOCTL_SCSI_BASE, 0x040a, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
           IOCTL_IDE_PASS_THROUGH = (IOCTL_SCSI_BASE shl 16) or ((FILE_READ_ACCESS or FILE_WRITE_ACCESS) shl 14) or ($040a shl 2) or (METHOD_BUFFERED);

//-------------------------------------------------------------
// GETVERSIONOUTPARAMS contains the data returned from the
// Get Driver Version function.
//-------------------------------------------------------------
type
           TGetVersionOutParams = packed record
                     bVersion      : BYTE;                // Binary driver version.
                     bRevision    : BYTE;                // Binary driver revision.
                     bReserved    : BYTE;                // Not used.
                     bIDEDeviceMap : BYTE;                // Bit map of IDE devices.
                     fCapabilities : DWORD;                // Bit mask of driver capabilities.
                     dwReserved    : Array[0..3] of DWORD; // For future use.
           end;
           GETVERSIONOUTPARAMS = TGetVersionOutParams;
           GETVERSIONINPARAMS = TGetVersionOutParams;
           PGetVersionOutParams = ^TGetVersionOutParams;
           LPGetVersionOutParams = ^TGetVersionOutParams;

// Bits returned in the fCapabilities member of GETVERSIONOUTPARAMS
// ATA ID command supported
const
           CAP_IDE_ID_FUNCTION            = 1; // ATAPI ID command supported
           CAP_IDE_ATAPI_ID              = 2; // SMART commannds supported
           CAP_IDE_EXECUTE_SMART_FUNCTION = 4;

//---------------------------------------------------------------------
// IDE registers
//---------------------------------------------------------------------
type
           TIDERegs = packed record
                     bFeaturesReg    : BYTE; // Used for specifying SMART "commands".
                     bSectorCountReg  : BYTE; // IDE sector count register
                     bSectorNumberReg : BYTE; // IDE sector number register
                     bCylLowReg      : BYTE; // IDE low order cylinder value
                     bCylHighReg      : BYTE; // IDE high order cylinder value
                     bDriveHeadReg    : BYTE; // IDE drive/head register
                     bCommandReg      : BYTE; // Actual IDE command.
                     bReserved        : BYTE; // reserved for future use.  Must be zero.
           end;
           IDEREGS  = TIDERegs;
           PIDERegs  = ^TIDERegs;
           LPIDERegs = PIDERegs;
           _IDEREGS  = TIDERegs;

// Valid values for the bCommandReg member of IDEREGS.
const
           IDE_ATAPI_ID              = $A1; // Returns ID sector for ATAPI.
           IDE_ID_FUNCTION            = $EC; // Returns ID sector for ATA.
           IDE_EXECUTE_SMART_FUNCTION = $B0; // Performs SMART cmd. Requires valid bFeaturesReg, bCylLowReg, and bCylHighReg

// Cylinder register values required when issuing SMART command
           SMART_CYL_LOW = $4F;
           SMART_CYL_HI  = $C2;

//---------------------------------------------------------------------
// SENDCMDINPARAMS contains the input parameters for the
// Send Command to Drive function.
//---------------------------------------------------------------------
type
           TSendCmdInParams = packed record
                     cBufferSize  : DWORD;                // Buffer size in bytes
                     irDriveRegs  : TIDERegs;            // Structure with drive register values.
                     bDriveNumber : BYTE;                // Physical drive number to send command to (0,1,2,3).
                     bReserved    : Array[0..2] of Byte;  // Reserved for future expansion.
                     dwReserved  : Array[0..3] of DWORD; // For future use.
                     bBuffer      : Array[0..0] of Byte;  // Input buffer.
           end;
           SENDCMDINPARAMS  = TSendCmdInParams;
           PSendCmdInParams  = ^TSendCmdInParams;
           LPSendCmdInParams = PSendCmdInParams;
           _SENDCMDINPARAMS  = TSendCmdInParams;

//---------------------------------------------------------------------
// Status returned from driver
//---------------------------------------------------------------------
type
           TDriverStatus = packed record
                     bDriverError : Byte;                // Error code from driver, or 0 if no error.
                     bIDEStatus  : Byte;                // Contents of IDE Error register. Only valid when bDriverError is SMART_IDE_ERROR.
                     bReserved    : Array[0..1] of Byte;  // Reserved for future expansion.
                     dwReserved  : Array[0..1] of DWORD; // Reserved for future expansion.
           end;
           DRIVERSTATUS  = TDriverStatus;
           PDriverStatus  = ^TDriverStatus;
           LPDriverStatus = TDriverStatus;
           _DRIVERSTATUS  = TDriverStatus;

// bDriverError values
const
           SMART_NO_ERROR        = 0; // No error
           SMART_IDE_ERROR        = 1; // Error from IDE controller
           SMART_INVALID_FLAG    = 2; // Invalid command flag
           SMART_INVALID_COMMAND  = 3; // Invalid command byte
           SMART_INVALID_BUFFER  = 4; // Bad buffer (null, invalid addr..)
           SMART_INVALID_DRIVE    = 5; // Drive number not valid
           SMART_INVALID_IOCTL    = 6; // Invalid IOCTL
           SMART_ERROR_NO_MEM    = 7; // Could not lock user's buffer
           SMART_INVALID_REGISTER = 8; // Some IDE Register not valid
           SMART_NOT_SUPPORTED    = 9; // Invalid cmd flag set
           SMART_NO_IDE_DEVICE    =10; // Cmd issued to device not present although drive number is valid
           // 11-255 reserved

//---------------------------------------------------------------------
// Structure returned by SMART IOCTL for several commands
//---------------------------------------------------------------------
type
           TSendCmdOutParams = packed record
                     cBufferSize  : DWORD;              // Size of bBuffer in bytes
                     DriverStatus : TDriverStatus;      // Driver status structure.
                     bBuffer      : Array[0..0] of BYTE; // Buffer of arbitrary length in which to store the data read from the drive.
           end;
           SENDCMDOUTPARAMS  = TSendCmdOutParams;
           PSendCmdOutParams  = ^TSendCmdOutParams;
           LPSendCmdOutParams = PSendCmdOutParams;
           _SENDCMDOUTPARAMS  = TSendCmdOutParams;

//---------------------------------------------------------------------
// Feature register defines for SMART "sub commands"
//---------------------------------------------------------------------
const
           SMART_READ_ATTRIBUTE_VALUES            = $D0; // ATA4: Renamed
                                                         // SMART READ DATA
           SMART_READ_ATTRIBUTE_THRESHOLDS        = $D1; // Obsoleted in ATA4!
           SMART_ENABLE_DISABLE_ATTRIBUTE_AUTOSAVE = $D2;
           SMART_SAVE_ATTRIBUTE_VALUES            = $D3;
           SMART_EXECUTE_OFFLINE_IMMEDIATE        = $D4; // ATA4
           // Vendor specific commands:
           SMART_ENABLE_SMART_OPERATIONS          = $D8;
           SMART_DISABLE_SMART_OPERATIONS          = $D9;
           SMART_RETURN_SMART_STATUS              = $DA;

//---------------------------------------------------------------------
// The following structure defines the structure of a Drive Attribute
//---------------------------------------------------------------------
type
           TDriveAttribute = packed record
                     bAttrID      : BYTE;                // Identifies which attribute
                     wStatusFlags : WORD;                // see bit definitions below
                     bAttrValue  : BYTE;                // Current normalized value
                     bWorstValue  : BYTE;                // How bad has it ever been?
                     bRawValue    : Array[0..6] of BYTE; // Un-normalized value
                     bReserved    : BYTE;                // ...
           end;
           DRIVEATTRIBUTE  = TDriveAttribute;
           PDriveAttribute  = ^TDriveAttribute;
           LPDriveAttribute = PDriveAttribute;

//---------------------------------------------------------------------
// The following structure defines the structure of a Warranty Threshold
// Obsoleted in ATA4!
//---------------------------------------------------------------------
           TAttrThreshold = packed record
                     bAttrID : BYTE;                  // Identifies which attribute
                     bWarrantyThreshold : BYTE;      // Triggering value
                     bReserved : Array[0..9] of BYTE; // ...
           end;
           ATTRTHRESHOLD  = TAttrThreshold;
           PAttrThreshold  = ^TAttrThreshold;
           LPAttrThreshold = PAttrThreshold;

//---------------------------------------------------------------------
// The following struct defines the interesting part of the IDENTIFY buffer:
//---------------------------------------------------------------------
           TIdSector = packed record
                     wGenConfig                : USHORT;
                     wNumCyls                  : USHORT;
                     wReserved                  : USHORT;
                     wNumHeads                  : USHORT;
                     wBytesPerTrack            : USHORT;
                     wBytesPerSector            : USHORT;
                     wSectorsPerTrack          : USHORT;
                     wVendorUnique              : Array[0..2] of USHORT;
                     sSerialNumber              : Array[0..19] of CHAR;
                     wBufferType                : USHORT;
                     wBufferSize                : USHORT;
                     wECCSize                  : USHORT;
                     sFirmwareRev              : Array[0..7] of CHAR;
                     sModelNumber              : Array[0..39] of CHAR;
                     wMoreVendorUnique          : USHORT;
                     wDoubleWordIO              : USHORT;
                     wCapabilities              : USHORT;
                     wReserved1                : USHORT;
                     wPIOTiming                : USHORT;
                     wDMATiming                : USHORT;
                     wBS                        : USHORT;
                     wNumCurrentCyls            : USHORT;
                     wNumCurrentHeads          : USHORT;
                     wNumCurrentSectorsPerTrack : USHORT;
                     ulCurrentSectorCapacity    : ULONG;
                     wMultSectorStuff          : USHORT;
                     ulTotalAddressableSectors  : ULONG;
                     wSingleWordDMA            : USHORT;
                     wMultiWordDMA              : USHORT;
                     bReserved                  : Array[0..127] of BYTE;
           end;
           PIdSector = ^TIdSector;
           IDSECTOR  = TIdSector;
           _IDSECTOR = TIdSector;

//---------------------------------------------------------------------
// Valid Attribute IDs
//---------------------------------------------------------------------
const
           ATTR_INVALID                =  0;
           ATTR_READ_ERROR_RATE        =  1;
           ATTR_THROUGHPUT_PERF        =  2;
           ATTR_SPIN_UP_TIME            =  3;
           ATTR_START_STOP_COUNT        =  4;
           ATTR_REALLOC_SECTOR_COUNT    =  5;
           ATTR_READ_CHANNEL_MARGIN    =  6;
           ATTR_SEEK_ERROR_RATE        =  7;
           ATTR_SEEK_TIME_PERF          =  8;
           ATTR_POWER_ON_HRS_COUNT      =  9;
           ATTR_SPIN_RETRY_COUNT        = 10;
           ATTR_CALIBRATION_RETRY_COUNT = 11;
           ATTR_POWER_CYCLE_COUNT      = 12;
//---------------------------------------------------------------------
// Status Flags Values
//---------------------------------------------------------------------
           PRE_FAILURE_WARRANTY      = $1;
           ON_LINE_COLLECTION        = $2;
           PERFORMANCE_ATTRIBUTE    = $4;
           ERROR_RATE_ATTRIBUTE      = $8;
           EVENT_COUNT_ATTRIBUTE    = $10;
           SELF_PRESERVING_ATTRIBUTE = $20;

//=============================================================
// IOCTL_STORAGE_GET_DEVICE_NUMBER
//
// input - none
//
// output - STORAGE_DEVICE_NUMBER structure
//          The values in the STORAGE_DEVICE_NUMBER structure are guaranteed
//          to remain unchanged until the system is rebooted.  They are not
//          guaranteed to be persistant across boots.
type
           TStorageDeviceNumber = packed record
                     // The FILE_DEVICE_XXX type for this device.
                     DeviceType      : DEVICE_TYPE;

                     // The number of this device
                     DeviceNumber    : ULONG;

                     // If the device is partitionable, the partition number of the device.
                     // Otherwise -1
                     PartitionNumber : ULONG;
           end;
           STORAGE_DEVICE_NUMBER = TStorageDeviceNumber;
           PStorageDeviceNumber = ^TStorageDeviceNumber;


//=============================================================
// IOCTL_STORAGE_GET_MEDIA_TYPES_EX will return an array of DEVICE_MEDIA_INFO
// structures, one per supported type, embedded in the GET_MEDIA_TYPES struct.

type
           STORAGE_MEDIA_TYPE = DWORD;
const
// Following are defined in ntdddisk.h in the MEDIA_TYPE enum
           Unknown            =  0; // Format is unknown
           F5_1Pt2_512        =  1; // 5.25", 1.2MB,  512 bytes/sector
           F3_1Pt44_512      =  2; // 3.5",  1.44MB, 512 bytes/sector
           F3_2Pt88_512      =  3; // 3.5",  2.88MB, 512 bytes/sector
           F3_20Pt8_512      =  4; // 3.5",  20.8MB, 512 bytes/sector
           F3_720_512        =  5; // 3.5",  720KB,  512 bytes/sector
           F5_360_512        =  6; // 5.25", 360KB,  512 bytes/sector
           F5_320_512        =  7; // 5.25", 320KB,  512 bytes/sector
           F5_320_1024        =  8; // 5.25", 320KB,  1024 bytes/sector
           F5_180_512        =  9; // 5.25", 180KB,  512 bytes/sector
           F5_160_512        = 10; // 5.25", 160KB,  512 bytes/sector
           RemovableMedia    = 11; // Removable media other than floppy
           FixedMedia        = 12; // Fixed hard disk media
           F3_120M_512        = 13; // 3.5", 120M Floppy
           F3_640_512        = 14; // 3.5" ,  640KB,  512 bytes/sector
           F5_640_512        = 15; // 5.25",  640KB,  512 bytes/sector
           F5_720_512        = 16; // 5.25",  720KB,  512 bytes/sector
           F3_1Pt2_512        = 17; // 3.5" ,  1.2Mb,  512 bytes/sector
           F3_1Pt23_1024      = 18; // 3.5" ,  1.23Mb, 1024 bytes/sector
           F5_1Pt23_1024      = 19; // 5.25",  1.23MB, 1024 bytes/sector
           F3_128Mb_512      = 20; // 3.5" MO 128Mb  512 bytes/sector
           F3_230Mb_512      = 21; // 3.5" MO 230Mb  512 bytes/sector
           F8_256_128        = 22; // 8",    256KB,  128 bytes/sector

// STORAGE_MEDIA_TYPE
           DDS_4mm            = 32; // Tape - DAT DDS1,2,... (all vendors)
           MiniQic            = 33; // Tape - miniQIC Tape
           Travan            = 34; // Tape - Travan TR-1,2,3,...
           QIC                = 35; // Tape - QIC
           MP_8mm            = 36; // Tape - 8mm Exabyte Metal Particle
           AME_8mm            = 37; // Tape - 8mm Exabyte Advanced Metal Evap
           AIT1_8mm          = 38; // Tape - 8mm Sony AIT1
           DLT                = 39; // Tape - DLT Compact IIIxt, IV
           NCTP              = 40; // Tape - Philips NCTP
           IBM_3480          = 41; // Tape - IBM 3480
           IBM_3490E          = 42; // Tape - IBM 3490E
           IBM_Magstar_3590  = 43; // Tape - IBM Magstar 3590
           IBM_Magstar_MP    = 44; // Tape - IBM Magstar MP
           STK_DATA_D3        = 45; // Tape - STK Data D3
           SONY_DTF          = 46; // Tape - Sony DTF
           DV_6mm            = 47; // Tape - 6mm Digital Video
           DMI                = 48; // Tape - Exabyte DMI and compatibles
           SONY_D2            = 49; // Tape - Sony D2S and D2L
           CLEANER_CARTRIDGE  = 50; // Cleaner - All Drive types that support Drive Cleaners
           CD_ROM            = 51; // Opt_Disk - CD
           CD_R              = 52; // Opt_Disk - CD-Recordable (Write Once)
           CD_RW              = 53; // Opt_Disk - CD-Rewriteable
           DVD_ROM            = 54; // Opt_Disk - DVD-ROM
           DVD_R              = 55; // Opt_Disk - DVD-Recordable (Write Once)
           DVD_RW            = 56; // Opt_Disk - DVD-Rewriteable
           MO_3_RW            = 57; // Opt_Disk - 3.5" Rewriteable MO Disk
           MO_5_WO            = 58; // Opt_Disk - MO 5.25" Write Once
           MO_5_RW            = 59; // Opt_Disk - MO 5.25" Rewriteable (not LIMDOW)
           MO_5_LIMDOW        = 60; // Opt_Disk - MO 5.25" Rewriteable (LIMDOW)
           PC_5_WO            = 61; // Opt_Disk - Phase Change 5.25" Write Once Optical
           PC_5_RW            = 62; // Opt_Disk - Phase Change 5.25" Rewriteable
           PD_5_RW            = 63; // Opt_Disk - PhaseChange Dual Rewriteable
           ABL_5_WO          = 64; // Opt_Disk - Ablative 5.25" Write Once Optical
           PINNACLE_APEX_5_RW = 65; // Opt_Disk - Pinnacle Apex 4.6GB Rewriteable Optical
           SONY_12_WO        = 66; // Opt_Disk - Sony 12" Write Once
           PHILIPS_12_WO      = 67; // Opt_Disk - Philips/LMS 12" Write Once
           HITACHI_12_WO      = 68; // Opt_Disk - Hitachi 12" Write Once
           CYGNET_12_WO      = 69; // Opt_Disk - Cygnet/ATG 12" Write Once
           KODAK_14_WO        = 70; // Opt_Disk - Kodak 14" Write Once
           MO_NFR_525        = 71; // Opt_Disk - Near Field Recording (Terastor)
           NIKON_12_RW        = 72; // Opt_Disk - Nikon 12" Rewriteable
           IOMEGA_ZIP        = 73; // Mag_Disk - Iomega Zip
           IOMEGA_JAZ        = 74; // Mag_Disk - Iomega Jaz
           SYQUEST_EZ135      = 75; // Mag_Disk - Syquest EZ135
           SYQUEST_EZFLYER    = 76; // Mag_Disk - Syquest EzFlyer
           SYQUEST_SYJET      = 77; // Mag_Disk - Syquest SyJet
           AVATAR_F2          = 78; // Mag_Disk - 2.5" Floppy
           MP2_8mm            = 79; // Tape - 8mm Hitachi
           DST_S              = 80; // Ampex DST Small Tapes
           DST_M              = 81; // Ampex DST Medium Tapes
           DST_L              = 82; // Ampex DST Large Tapes
           VXATape_1          = 83; // Ecrix 8mm Tape
           VXATape_2          = 84; // Ecrix 8mm Tape
           STK_EAGLE          = 85; // STK Eagle
           LTO_Ultrium        = 86; // IBM, HP, Seagate LTO Ultrium
           LTO_Accelis        = 87; // IBM, HP, Seagate LTO Accelis

//-------------------------------------------------------------
           MEDIA_ERASEABLE        = $00000001;
           MEDIA_WRITE_ONCE        = $00000002;
           MEDIA_READ_ONLY        = $00000004;
           MEDIA_READ_WRITE        = $00000008;
           MEDIA_WRITE_PROTECTED  = $00000100;
           MEDIA_CURRENTLY_MOUNTED = $80000000;

//-------------------------------------------------------------
// Define the different storage bus types
// Bus types below 128 (0x80) are reserved for Microsoft use
type
           TStorageBusType = ( BusTypeUnknown, BusTypeScsi, BusTypeAtapi, BusTypeAta,
                     BusType1394, BusTypeSsa, BusTypeFibre, BusTypeUsb, BusTypeRAID );
//  BusTypeMaxReserved = 0x7F
           STORAGE_BUS_TYPE = TStorageBusType;
           PStorageBusType = ^TStorageBusType;

           TDeviceMediaInfo = packed record
                     DeviceSpecific : packed record
                     case byte of
                     0 :
                               ( DiskInfo : packed record
                                                   Cylinders            : LARGE_INTEGER;
                                                   MediaType            : STORAGE_MEDIA_TYPE;
                                                   TracksPerCylinder    : ULONG;
                                                   SectorsPerTrack      : ULONG;
                                                   BytesPerSector      : ULONG;
                                                   NumberMediaSides    : ULONG;
                                                   MediaCharacteristics : ULONG; // Bitmask of MEDIA_XXX values.
                                         end );
                     1 :
                               ( RemovableDiskInfo : packed record
                                                   Cylinders            : LARGE_INTEGER;
                                                   MediaType            : STORAGE_MEDIA_TYPE;
                                                   TracksPerCylinder    : ULONG;
                                                   SectorsPerTrack      : ULONG;
                                                   BytesPerSector      : ULONG;
                                                   NumberMediaSides    : ULONG;
                                                   MediaCharacteristics : ULONG; // Bitmask of MEDIA_XXX values.
                                         end );
                     2 :
                               ( TapeInfo : packed record
                                                   MediaType            : STORAGE_MEDIA_TYPE;
                                                   MediaCharacteristics : ULONG; // Bitmask of MEDIA_XXX values.
                                                   CurrentBlockSize    : ULONG;
                                                   BusType              : STORAGE_BUS_TYPE;
                                                   BusSpecificData : packed record // Bus specific information describing the medium supported.
                                                             case longint of
                                                             0 :
                                                                       ( ScsiInformation : packed record
                                                                                           MediumType : UCHAR;
                                                                                           DensityCode : UCHAR;
                                                                                 end );
                                                             end;
                                         end );
                     end;
           end;
           DEVICE_MEDIA_INFO = TDeviceMediaInfo;
           PDeviceMediaInfo = ^TDeviceMediaInfo;

           TGetMediaTypes = packed record
                     DeviceType    : DEVICE_TYPE; // FILE_DEVICE_XXX values
                     MediaInfoCount : ULONG;
                     MediaInfo      : Array[0..0] of DEVICE_MEDIA_INFO;
           end;
           GET_MEDIA_TYPES = TGetMediaTypes;
           PGetMediaTypes  = ^TGetMediaTypes;


//=============================================================
// IOCTL_SCSI_MINIPORT

// Define header for I/O control SRB. }
type
           TSrbIoControl = packed record
                     HeaderLength : ULONG;  // Is sizeof(SRB_IO_CONTROL).

                     // Identifies the application-dedicated, target HBA for this request.
                     // This signature is used to prevent conflicts in ControlCode values between vendors.
                     // It should be a string of ASCII characters.
                     // If a miniport driver does not recognize the input Signature value,
                     // it must complete the request with a status of SRB_STATUS_INVALID_REQUEST.
                     Signature    : Array[0..7] of Char;

                     // Indicates the interval in seconds that the request can execute
                     // before the OS-specific port driver might consider it timed out.
                     // Miniport drivers are not required to time requests because the port driver does.
                     Timeout      : ULONG;

                     // Indicates the operation to be performed. There are no system-defined operations.
                     // Values must be defined by the driver as a set of private I/O control codes
                     // with which the application can make requests by calling the Win32R DeviceIoControl function.
                     ControlCode  : ULONG;

                     // Returns a status code for examination by the requesting application.
                     ReturnCode  : ULONG;

                     // Indicates the size in bytes of the immediately following data area.
                     // This area can be divided for the particular operation into input and output areas.
                     // For input requests, the contents of the DataBuffer will be copied
                       // to the requestor up to the returned value of DataTransferLength.
                     Length      : ULONG;
           end;
           SRB_IO_CONTROL = TSrbIoControl;
           PSrbIoControl = ^TSrbIoControl;

// SCSI IO Device Control Codes
const
           FILE_DEVICE_SCSI = $0000001b;

           IOCTL_SCSI_EXECUTE_IN  = (FILE_DEVICE_SCSI shl 16) or $0011;
           IOCTL_SCSI_EXECUTE_OUT  = (FILE_DEVICE_SCSI shl 16) or $0012;
           IOCTL_SCSI_EXECUTE_NONE = (FILE_DEVICE_SCSI shl 16) or $0013;

// SMART support in atapi
           IOCTL_SCSI_MINIPORT_SMART_VERSION              = (FILE_DEVICE_SCSI shl 16) or $0500;
           IOCTL_SCSI_MINIPORT_IDENTIFY                    = (FILE_DEVICE_SCSI shl 16) or $0501;
           IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS          = (FILE_DEVICE_SCSI shl 16) or $0502;
           IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS      = (FILE_DEVICE_SCSI shl 16) or $0503;
           IOCTL_SCSI_MINIPORT_ENABLE_SMART                = (FILE_DEVICE_SCSI shl 16) or $0504;
           IOCTL_SCSI_MINIPORT_DISABLE_SMART              = (FILE_DEVICE_SCSI shl 16) or $0505;
           IOCTL_SCSI_MINIPORT_RETURN_STATUS              = (FILE_DEVICE_SCSI shl 16) or $0506;
           IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE    = (FILE_DEVICE_SCSI shl 16) or $0507;
           IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES      = (FILE_DEVICE_SCSI shl 16) or $0508;
           IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS      = (FILE_DEVICE_SCSI shl 16) or $0509;
           IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE = (FILE_DEVICE_SCSI shl 16) or $050a;

//=============================================================
// Used with the IOCTL_SCSI_GET_INQUIRY_DATA IOCTL.
type
           // Define SCSI adapter bus information.
{$ALIGN ON}
           TScsiBusData = record  // warning! dword alignment
                     NumberOfLogicalUnits : Byte;
                     InitiatorBusId      : Byte;
                     InquiryDataOffset    : ULONG;
           end;
           SCSI_BUS_DATA = TScsiBusData;
           PScsiBusData = ^TScsiBusData;

           // Define SCSI adapter bus information structure..
           TScsiAdapterBusInfo = record // warning! dword alignment
                     NumberOfBuses : Byte;
                     BusData : Array[0..0] of SCSI_BUS_DATA;
           end;
           SCSI_ADAPTER_BUS_INFO = TScsiAdapterBusInfo;
           PScsiAdapterBusInfo = ^TScsiAdapterBusInfo;

           TScsiInquiryData = record // warning! dword alignment
                     PathId                : Byte;
                     TargetId              : Byte;
                     Lun                  : Byte;
                     DeviceClaimed        : Boolean;
                     InquiryDataLength    : ULONG;
                     NextInquiryDataOffset : ULONG;
                     InquiryData          : Array[0..0] of Byte;
           end;
           SCSI_INQUIRY_DATA = TScsiInquiryData;
           PScsiInquiryData = ^TScsiInquiryData;
{$ALIGN OFF}


//=============================================================

// Open device to allow DeviceIoControl communications.
function GetPhysicalDriveHandle( DriveNum : Byte; DesireAccess : ACCESS_MASK ) : THandle;

// Get SCSI/IDE port handle.
function GetScsiPortHandle( PortNum : Byte; DesireAccess : ACCESS_MASK ) : THandle;

function GetScsiInquiryData( hDevice : THandle; var InquiryData : TScsiAdapterBusInfo; var dwSize : DWORD ) : BOOL;

function GetMediaType( hDevice : THandle ) : DEVICE_TYPE;

function GetMediaTypes( hDevice : THandle; var MediaTypes : TGetMediaTypes; var dwSize : DWORD ) : BOOL;

// Send an IDENTIFY command to the drive bDriveNum = 0-3
// bIDCmd = IDE_ID_FUNCTION or IDE_ATAPI_ID
function SmartIdentifyDirect(hDevice: THandle; bDriveNum: Byte;
  bIDCmd: Byte; var IdSector: TIdSector; SCIP: TSendCmdInParams;
  SCOP: TSendCmdOutParams; var IdSectorSize: LongInt; var dwBytesReturned: DWORD): BOOL;
function SmartIdentifyMiniport( hDevice : THandle; bTargetId : Byte; bIDCmd : Byte; var IdSector : TIdSector; var IdSectorSize : LongInt ) : BOOL;

// Send a SMART_ENABLE_SMART_OPERATIONS command to the drive bDriveNum = 0-3
function DoEnableSMART( hDevice : THandle; bDriveNum : Byte; var SCOP : TSendCmdOutParams; var dwBytesReturned : DWORD ) : BOOL;

// Send a SMART_READ_ATTRIBUTE_VALUES command to the drive bDriveNum = 0-3
function DoReadAttributesCmd(hDevice: THandle; SCIP: TSendCmdInParams;
  var SCOP: TSendCmdOutParams;           bDriveNum: Byte): BOOL;
function DoReadThresholdsCmd(hDevice: THandle; SCIP: TSendCmdInParams;
  var SCOP: TSendCmdOutParams; bDriveNum: Byte): BOOL;
var dwBytesReturned : DWORD;

// Change the WORD array to a BYTE array
procedure ChangeByteOrder( var Data; Size : Integer );


//=============================================================
implementation

var OSVersionInfo: TOSVersionInfo;
//---------------------------------------------------------------------
// Return INVALID_HANDLE_VALUE on error.
// Note: under NT/2000 Administrative priveleges are required
function GetPhysicalDriveHandle( DriveNum : Byte; DesireAccess : ACCESS_MASK ) : THandle;
var s : String;
begin
           OSVersionInfo.dwOSVersionInfoSize := SizeOf(OSVersionInfo);
           GetVersionEx(OSVersionInfo);
           if OSVersionInfo.dwPlatformId=VER_PLATFORM_WIN32_NT then // Windows NT, Windows 2000
                     begin
                               Str(DriveNum,s); // avoid SysUtils
                               Result := CreateFile( PChar('\\.\PhysicalDrive'+s), DesireAccess, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0 );
                     end
           else // Windows 95 OSR2, Windows 98
                     Result := CreateFile( '\\.\SMARTVSD', 0, 0, nil, CREATE_NEW, 0, 0 );
end;
//-------------------------------------------------------------
// Get SCSI/IDE port handle.
// Windows NT/2000 only.
// Note: Administrative priveleges are NOT required
function GetScsiPortHandle( PortNum : Byte; DesireAccess : ACCESS_MASK ) : THandle;
var s : String;
begin
           Str(PortNum,s); // avoid SysUtils
           Result := CreateFile( PChar('\\.\Scsi'+s+':'), DesireAccess, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0 );
end;
//-------------------------------------------------------------
function GetScsiInquiryData( hDevice : THandle; var InquiryData : TScsiAdapterBusInfo; var dwSize : DWORD ) : BOOL;
begin
           FillChar(InquiryData,dwSize,#0);
           Result := DeviceIoControl( hDevice, IOCTL_SCSI_GET_INQUIRY_DATA, nil, 0, @InquiryData, dwSize, dwSize, nil );
end;
//-------------------------------------------------------------
function GetMediaTypes( hDevice : THandle; var MediaTypes : TGetMediaTypes; var dwSize : DWORD ) : BOOL;
begin
           FillChar(MediaTypes,dwSize,#0);
           Result := DeviceIoControl( hDevice, IOCTL_STORAGE_GET_MEDIA_TYPES_EX, nil, 0, @MediaTypes, dwSize, dwSize, nil );
end;
//-------------------------------------------------------------
function GetMediaType( hDevice : THandle ) : STORAGE_MEDIA_TYPE;
const Size = 1024;
var dwBytesReturned : DWORD;
                     bMediaTypes : Array[0..Size-1] of Byte;
                     rMediaTypes : TGetMediaTypes absolute bMediaTypes;
begin
           FillChar(bMediaTypes,Size,#0);
           Result := 0;
           if DeviceIoControl( hDevice, IOCTL_STORAGE_GET_MEDIA_TYPES_EX, nil, 0, @bMediaTypes, Size, dwBytesReturned, nil ) then with rMediaTypes do
                     if MediaInfoCount>0 then with MediaInfo[0].DeviceSpecific do
                               case DeviceType of
                               FILE_DEVICE_CD_ROM,
                               FILE_DEVICE_DVD:
                                         Result := RemovableDiskInfo.MediaType;
                               FILE_DEVICE_DISK:
                                         Result := DiskInfo.MediaType;
                               FILE_DEVICE_TAPE:
                                         Result := TapeInfo.MediaType;
                               end;
end;
//-------------------------------------------------------------
// SmartIdentifyDirect
//
// FUNCTION: Send an IDENTIFY command to the drive bDriveNum = 0-3
// bIDCmd = IDE_ID_FUNCTION or IDE_ATAPI_ID
//
// Note: work only with IDE device handle.

function SmartIdentifyDirect(hDevice: THandle; bDriveNum: Byte;
  bIDCmd: Byte; var IdSector: TIdSector; SCIP: TSendCmdInParams;
  SCOP: TSendCmdOutParams; var IdSectorSize: LongInt; var dwBytesReturned: DWORD): BOOL;
const
  BufferSize = SizeOf(TSendCmdOutParams) + IDENTIFY_BUFFER_SIZE - 1;
var
                     Buffer: Array [0..BufferSize-1] of Byte;
                     MCOP: TSendCmdOutParams absolute Buffer;
                     //dwBytesReturned: DWORD;
begin
           FillChar(SCIP,SizeOf(TSendCmdInParams)-1,#0);
           FillChar(Buffer,BufferSize,#0);
           dwBytesReturned := 0;
           IdSectorSize := 0;
           // Set up data structures for IDENTIFY command.
           with SCIP do
           begin
                     cBufferSize  := IDENTIFY_BUFFER_SIZE;
                     bDriveNumber := bDriveNum;
                     with irDriveRegs do
                     begin
                               bFeaturesReg    := 0;
                               bSectorCountReg  := 1;
                               bSectorNumberReg := 1;
                               bCylLowReg      := 0;
                               bCylHighReg      := 0;
                               bDriveHeadReg := $A0 or ((bDriveNum and 1) shl 4);
                               bCommandReg      := bIDCmd;           // The command can either be IDE identify or ATAPI identify.
                     end;
           end;
           Result:= DeviceIoControl(hDevice, DFP_RECEIVE_DRIVE_DATA, @SCIP,
    SizeOf(TSendCmdInParams)-1, @MCOP, BufferSize, dwBytesReturned, nil);
           if Result then
           begin
                     IdSectorSize:= dwBytesReturned-SizeOf(TSendCmdOutParams)+1;
                     if (IdSectorSize <= 0) then
      IdSectorSize:= 0
    else
      System.Move(MCOP.bBuffer, IdSector, IdSectorSize);
           end;
  SCOP:= MCOP;
end;
//-------------------------------------------------------------
// Same as above but
//  - work only NT;
//  - work with cotroller or device handle.
// Note: Administrator priveleges are not required to open controller handle.
function SmartIdentifyMiniport( hDevice : THandle; bTargetId : Byte; bIDCmd : Byte; var IdSector : TIdSector; var IdSectorSize : LongInt ) : BOOL;
const
           DataLength = sizeof(TSendCmdInParams)-1+IDENTIFY_BUFFER_SIZE;
           BufferLength = SizeOf(SRB_IO_CONTROL)+DataLength;
var           cbBytesReturned : DWORD;
                     pData : PSendCmdInParams;
                     Buffer : Array[0..BufferLength] of Byte;
                     srbControl : TSrbIoControl absolute Buffer;
begin
           // fill in srbControl fields
           FillChar(Buffer,BufferLength,#0);
           srbControl.HeaderLength := SizeOf(SRB_IO_CONTROL);
           System.Move('SCSIDISK',srbControl.Signature,8);
           srbControl.Timeout      := 2;
           srbControl.Length      := DataLength;
           srbControl.ControlCode  := IOCTL_SCSI_MINIPORT_IDENTIFY;
           pData := PSendCmdInParams(PChar(@Buffer)+SizeOf(SRB_IO_CONTROL));
           with pData^ do
           begin
                     cBufferSize  := IDENTIFY_BUFFER_SIZE;
                     bDriveNumber := bTargetId;
                     with irDriveRegs do
                     begin
                               bFeaturesReg    := 0;
                               bSectorCountReg  := 1;
                               bSectorNumberReg := 1;
                               bCylLowReg      := 0;
                               bCylHighReg      := 0;
                               bDriveHeadReg := $A0 or ((bTargetId and 1) shl 4);
                               bCommandReg      := bIDCmd;           // The command can either be IDE identify or ATAPI identify.
                     end;
           end;
           Result := DeviceIoControl( hDevice, IOCTL_SCSI_MINIPORT, @Buffer, BufferLength, @Buffer, BufferLength, cbBytesReturned, nil );
           if Result then
           begin
                     IdSectorSize := cbBytesReturned-SizeOf(SRB_IO_CONTROL)-SizeOf(TSendCmdOutParams)+1;
                     if IdSectorSize<=0 then IdSectorSize := 0
                     else
                               begin
                                         if IdSectorSize>IDENTIFY_BUFFER_SIZE then IdSectorSize := IDENTIFY_BUFFER_SIZE;
                                         System.Move( PSendCmdOutParams(pData)^.bBuffer,IdSector,IdSectorSize);
                               end;
           end;
end;
//-------------------------------------------------------------
// DoEnableSMART
//
// FUNCTION: Send a SMART_ENABLE_SMART_OPERATIONS command to the drive bDriveNum = 0-3
//
function DoEnableSMART(hDevice: THandle; bDriveNum : Byte; var SCOP : TSendCmdOutParams; var dwBytesReturned : DWORD ) : BOOL;
var SCIP : TSendCmdInParams;
begin
           FillChar(SCIP,SizeOf(TSendCmdInParams)-1,#0);
           FillChar(SCOP,SizeOf(TSendCmdOutParams)-1,#0);
           dwBytesReturned := 0;

           // Set up data structures for Enable SMART Command.
           with SCIP do
           begin
                     cBufferSize  := 0;
                     bDriveNumber := bDriveNum;
                     with irDriveRegs do
                     begin
                               bFeaturesReg    := SMART_ENABLE_SMART_OPERATIONS;
                               bSectorCountReg  := 1;
                               bSectorNumberReg := 1;
                               bCylLowReg      := SMART_CYL_LOW;
                               bCylHighReg      := SMART_CYL_HI;
                               bDriveHeadReg    := $A0 or ((bDriveNum and 1) shl 4); // Compute the drive number.
                               bCommandReg      := IDE_EXECUTE_SMART_FUNCTION;
                     end;
           end;
           Result := DeviceIoControl( hDevice, DFP_SEND_DRIVE_COMMAND, @SCIP, SizeOf(TSendCmdInParams)-1,
                                                                       @SCOP, SizeOf(TSendCmdOutParams)-1, dwBytesReturned, nil );
end;
//-------------------------------------------------------------
// DoReadAttributesCmd
//
// FUNCTION: Send a SMART_READ_ATTRIBUTE_VALUES command to the drive bDriveNum = 0-3
//
function DoReadAttributesCmd(hDevice : THandle;
  SCIP: TSendCmdInParams; var SCOP: TSendCmdOutParams;
  bDriveNum: Byte): BOOL;
var
  dwBytesReturned: DWORD;
begin
           // Set up data structures for Read Attributes SMART Command.
           with SCIP do
           begin
                     cBufferSize:= READ_ATTRIBUTE_BUFFER_SIZE;
                     bDriveNumber:= bDriveNum;
                     with irDriveRegs do
                     begin
                               bFeaturesReg:= SMART_READ_ATTRIBUTE_VALUES;
                               bSectorCountReg:= 1;
                               bSectorNumberReg:= 1;
                               bCylLowReg:= SMART_CYL_LOW;
                               bCylHighReg:= SMART_CYL_HI;
                               bDriveHeadReg:= $A0 or ((bDriveNum and 1) shl 4); // Compute the drive number.
                               bCommandReg:= IDE_EXECUTE_SMART_FUNCTION;
                     end;
           end;
           Result:= DeviceIoControl(hDevice, DFP_RECEIVE_DRIVE_DATA,
    @SCIP, SizeOf(TSendCmdInParams)-1, @SCOP,
    SizeOf(TSendCmdOutParams) + READ_ATTRIBUTE_BUFFER_SIZE-1,
    dwBytesReturned, nil);
end;
//-------------------------------------------------------------
// DoReadThresholdsCmd
//
// FUNCTION: Send a SMART_READ_ATTRIBUTE_THRESHOLDS command to the drive bDriveNum = 0-3
//
function DoReadThresholdsCmd( hDevice: THandle; SCIP: TSendCmdInParams;
  var SCOP: TSendCmdOutParams; bDriveNum: Byte): BOOL;
var
  dwBytesReturned: DWORD;
begin
           // Set up data structures for Read Thresholds SMART Command.
           with SCIP do
           begin
                     cBufferSize:= READ_THRESHOLD_BUFFER_SIZE;
                     bDriveNumber:= bDriveNum;
                     with irDriveRegs do
                     begin
                               bFeaturesReg    := SMART_READ_ATTRIBUTE_THRESHOLDS;
                               bSectorCountReg  := 1;
                               bSectorNumberReg := 1;
                               bCylLowReg      := SMART_CYL_LOW;
                               bCylHighReg      := SMART_CYL_HI;
                               bDriveHeadReg    := $A0 or ((bDriveNum and 1) shl 4); // Compute the drive number.
                               bCommandReg      := IDE_EXECUTE_SMART_FUNCTION;
                     end;
           end;
           Result := DeviceIoControl(hDevice, DFP_RECEIVE_DRIVE_DATA, @SCIP,
    SizeOf(TSendCmdInParams)-1, @SCOP, SizeOf(TSendCmdOutParams) +
    READ_THRESHOLD_BUFFER_SIZE - 1, dwBytesReturned, nil );
end;
//---------------------------------------------------------------------
// Change the WORD array to a BYTE array
//---------------------------------------------------------------------
procedure ChangeByteOrder( var Data; Size : Integer );
var ptr : PChar;
                     i : Integer;
                     c : Char;
begin
           ptr := @Data;
           for i := 0 to (Size shr 1)-1 do
           begin
                     c := ptr^;
                     ptr^ := (ptr+1)^;
                     (ptr+1)^ := c;
                     Inc(ptr,2);
           end;
end;


end.


Сама программа:

program SmartApp;

{$APPTYPE CONSOLE}

uses
  SysUtils, IoCtl, Windows, Math;

const
  MAX_KNOWN_ATTRIBUTES = 30;
  pAttrNames: array [0..31] of string = (
           'No Attribute Here          ', //0          0
           'Raw Read Error Rate        ', //1          1
           'Throughput Performance      ', //2          2
           'Spin Up Time                ', //3          3
           'Start/Stop Count            ', //4          4
           'Reallocated Sector Count    ', //5          5
           'Read Channel Margin        ', //6          6
           'Seek Error Rate            ', //7          7
           'Seek Time Performance      ', //8          8
           'Power On Hours Count        ', //9          9
           'Spin Retry Count            ', //10        10
           'Calibration Retry Count    ', //11        11
           'Power Cycle Count          ', //12        12
  'Soft Read Error Rate        ', //13        13
  'Load/Unload Cycle Count    ', //193        14
  'Realocation Events Count    ', //196        15
  'Current Pending Sector Count', //197        16
  'Uncorrectable Sector Count  ', //198        17
  'UltraDMA CRC Error Count    ', //199        18
  'Write Error Rate            ', //200        19
  'Disk Shift                  ', //220        20
  'G-Sence Error Rate          ', //221, 191  21
  'Loaded Hours                ', //222        22
  'Load/Unload Retry Count    ', //223        23
  'Load Friction              ', //224        24
  'Load/Unload Cycle Count    ', //225        25
  'Load-in Time                ', //226        26
  'Torque Amplification Count  ', //227        27
  'Power-off Retract Count    ', //228        28
  'GMR Head Amplitude          ', //230        29
  'Temperature                ', //231        30
           '(Unknown attribute)    ');    //Unknown    31
  AttrLength = sizeof(TSENDCMDOUTPARAMS) + READ_ATTRIBUTE_BUFFER_SIZE - 1;
  TresHoldLength = sizeof(TSENDCMDOUTPARAMS) + READ_THRESHOLD_BUFFER_SIZE - 1;

var

  AttrOutCmd: array[0..AttrLength - 1] of BYTE;
  ThreshOutCmd:array[0..TresHoldLength - 1] of BYTE;
  IdOutCmd: TSendCmdOutParams;

function AttrtoStr(const Attr: BYTE): string;
begin
  if (Attr < 14) then
    Result:= pAttrNames[Attr]
  else
  if (Attr > 195) and (Attr < 201) then
    Result:= pAttrNames[Attr - 181]
  else
  if (Attr > 219) and (Attr < 229) then
    Result:= pAttrNames[Attr - 200]
  else
  if (Attr > 229) and (Attr < 232) then
    Result:= pAttrNames[Attr - 201]
  else
  if (Attr = 191) then
    Result:= pAttrNames[21]
  else
  if (Attr = 193) then
    Result:= pAttrNames[14]
  else
    Result:= pAttrNames[31];
end;

function OpenSmart: THandle;
var
  hSMARTIOCTL: THandle;
begin
  writeln('');
  writeln('Smartapp interpretation from C++ to Delphi');
  writeln('by Denisss');
  writeln('');
  writeln('Programed by Denisss');
  writeln('Use Denis'' Soft');
  writeln('');
  if (Win32Platform = VER_PLATFORM_WIN32_NT) then
  begin
    hSMARTIOCTL:= CreateFile('\\.\PhysicalDrive0', GENERIC_READ or
      GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil,
      OPEN_EXISTING, 0, 0);
    if (hSMARTIOCTL = INVALID_HANDLE_VALUE) then
      writeln(Format('Unable to open physical drive, error code: 0x%lX',
        [GetLastError]))
    else
      writeln('Physical drive opened successfully');
  end
  else
  begin
    hSMARTIOCTL:= CreateFile('\\.\SMARTVSD', 0, 0, nil, CREATE_NEW, 0, 0);
    if (hSMARTIOCTL = INVALID_HANDLE_VALUE) then
      writeln(Format('Unable to open SMARTVSD, error code: 0x%lX',
        [GetLastError]))
    else
      writeln('SMARTVSD opened successfully');
  end;
  writeln('');
  Result:= hSMARTIOCTL;
end;

procedure PrintIDERegs(pscip: TSENDCMDINPARAMS);
begin
  writeln('IDE TASK FILE REGISTERS:');
           writeln(Format('  bFeaturesReg    = 0x%X',
    [pscip.irDriveRegs.bFeaturesReg]));
  writeln(Format('  bSectorCountReg  = 0x%X',
    [pscip.irDriveRegs.bSectorNumberReg]));
  writeln(Format('  bCylLowReg      = 0x%X',
    [pscip.irDriveRegs.bCylLowReg]));
  writeln(Format('  bCylHighReg      = 0x%X', [pscip.irDriveRegs.bCylHighReg]));
  writeln(Format('  bDriveHeadReg    = 0x%X',
    [pscip.irDriveRegs.bDriveHeadReg]));
  writeln(Format('  Status          = 0x%X', [pscip.irDriveRegs.bCommandReg]));
end;

procedure DisplayIdInfo(pids: TIdSector; pSCIP: TSendCmdInParams; bIDCmd,
  bDfpDriveMap, bDriveNum:  BYTE);
var
  szOutBuffer: Array [0..40] of Char;
  pc: PChar;
  ss: shortstring;
begin
  writeln('');
  if (bIDCmd = IDE_ID_FUNCTION) then
  begin
    write(Format('Drive %d is an IDE Hard drive', [bDriveNum]));
    if ((bDfpDriveMap shr bDriveNum and 1) = 1) then
      writeln(' that supports SMART');
    writeln('');
    writeln(Format('Cylinders: %d, Heads: %d, Sectors per Track: %d', [
      pids.wNumCyls, pids.wNumHeads, pids.wSectorsPerTrack]));
    PrintIDERegs(pSCIP);
  end
  else
    writeln(Format('Drive %d is an ATAPI device', [bDriveNum]));

  pc := @szOutBuffer[0];
  with pids do
    begin
    // Change the WORD array to a BYTE array
      ChangeByteOrder( sModelNumber, SizeOf(sModelNumber) );
      szOutBuffer[SizeOf(sModelNumber)]:= #0;
      StrLCopy( szOutBuffer, sModelNumber, SizeOf(sModelNumber) );
      ss:= String(pc); // model number
      writeln('Model number : ',Trim(ss));

      ChangeByteOrder( sFirmwareRev, SizeOf(sFirmwareRev) );
      szOutBuffer[SizeOf(sFirmwareRev)] := #0;
      StrLCopy( szOutBuffer, sFirmwareRev, SizeOf(sFirmwareRev) );
      ss := String(pc); // firmware rev.
      writeln('Firmware rev : ',Trim(ss));

      ChangeByteOrder( sSerialNumber, SizeOf(sSerialNumber) );
      szOutBuffer[SizeOf(sSerialNumber)] := #0;
      StrLCopy( szOutBuffer, sSerialNumber, SizeOf(sSerialNumber) );
      ss := String(pc); // serial number
      writeln('Serial number: ',Trim(ss));
    end;
end;

procedure DoPrintData(pAttrBuffer, pThrsBuffer: array of BYTE;
  bDriveNum: BYTE);

type
  TDrvAttr = packed record
    AttrID: BYTE;
    Dummy1: WORD;
    Value, Worst: BYTE;
    Dummy2: array[0..6] of BYTE;
  end;
  PDrvAttr = ^TDrvAttr;
  TAttrTres = packed record
    AttrID, WarrantyTresHold: BYTE;
    Reserved: array[0..9] of BYTE;
  end;
  PAttrTres = ^TAttrTres;

var
           pDA: PDrvAttr;
           pAT: PAttrTres;
  i: BYTE;
const
  s = 6;
begin
  writeln('');
  writeln(Format('Data for Drive Number %d', [bDriveNum]));
  writeln('');
  writeln('Attribute Structure Revision          Threshold Structure Revision');
  writeln(Format('            %d                                      %d',
    [WORD(pAttrBuffer[16]), WORD(pThrsBuffer[16])]));
  writeln('');
  writeln('  -Attribute Name              -Value--Threshold--Worst-');

  pDA:= @pAttrBuffer[s];
           pAT:= @pThrsBuffer[s];
  for i:= 0 to NUM_ATTRIBUTE_STRUCTS do
  begin
    if (pDA^.AttrID > 0) then
    begin
      writeln(Format('%2X-%s- %3d --  %3d  -- %3d -',
        [pDA^.AttrID, AttrtoStr(pDA^.AttrID), pDA^.Value,
        pAT^.WarrantyTresHold, pDA^.Worst]));{}
    end;
    inc(pDA);
    inc(pAT);
  end;
end;

var
  hSMARTIOCTL: THandle;
  cbBytesReturned: DWORD;
  VersionParams: GETVERSIONOUTPARAMS;
  scip: TSendCmdInParams;
  OutCmd: TSendCmdOutParams;
  bDfpDriveMap, i, bIDCmd: BYTE;
  idSector: TIdSector;
  idSectorSize: Integer;
  bSuccess: Boolean;
  AttrSCOP: TSendCmdOutParams absolute AttrOutCmd;
  ThresSCOP: TSendCmdOutParams absolute ThreshOutCmd;
begin
  bDfpDriveMap:= 0;
  hSMARTIOCTL:= OpenSmart;
  writeln('');
  if not (hSMARTIOCTL = INVALID_HANDLE_VALUE) then
  begin
    ZeroMemory(@VersionParams, sizeof(VersionParams));
    if DeviceIoControl(hSMARTIOCTL, DFP_GET_VERSION, nil, 0, @VersionParams,
      sizeof(VersionParams), cbBytesReturned, nil) then
      begin
        writeln('DFP_GET_VERSION returned:');
        writeln(format('  bVersion        = %d', [VersionParams.bVersion]));
        writeln(format('  bRevision      = %d', [VersionParams.bRevision]));
        writeln(format('  fCapabilities  = 0x%x',
          [VersionParams.fCapabilities]));
        writeln(format('  bReserved      = 0x%x', [VersionParams.bReserved]));
        writeln(format('  bIDEDeviceMap  = 0x%x',
          [VersionParams.bIDEDeviceMap]));
        writeln(format('  cbBytesReturned = %d', [cbBytesReturned]));
      end
      else
        writeln('DFP_GET_VERSION failed.');
      for i:= 0 to (MAX_IDE_DRIVES - 1) do
      begin
        if (((VersionParams.bIDEDeviceMap shr i) and $1) > 0) then
        begin
          if not ((VersionParams.bIDEDeviceMap shr i) and $10 > 0) then
          begin
            ZeroMemory(@scip, sizeof(scip));
            ZeroMemory(@OutCmd, sizeof(OutCmd));
            if (DoEnableSMART(hSMARTIOCTL, i, OutCmd,
              cbBytesReturned)) then
            begin
              writeln(Format('SMART Enabled on Drive: %d', [i]));
              bDfpDriveMap:= bDfpDriveMap or (1 shl i);
            end
            else
            begin
              writeln(Format('SMART Enable Command Failed, Drive: %d.',[i]));
              writeln(Format('DriverStatus: bDriverError=0x%X, bIDEStatus=0x%X',
              [OutCmd.DriverStatus.bDriverError,
              OutCmd.DriverStatus.bIDEStatus]));
            end;
            writeln(Format('  cbBytesReturned: %d',[cbBytesReturned]));
          end;
{          bIDCmd:= IfThen((VersionParams.bIDEDeviceMap shr i and $10) > 10,
            IDE_ATAPI_ID, IDE_ID_FUNCTION);{}
          if ((VersionParams.bIDEDeviceMap shr i and $10) > 10) then
            bIDCmd:= IDE_ATAPI_ID
          else
            bIDCmd:= IDE_ID_FUNCTION;
          ZeroMemory(@scip, sizeof(scip));
                                   ZeroMemory(@IdOutCmd, sizeof(IdOutCmd));
          if SmartIdentifyDirect(hSMARTIOCTL, i, bIDCmd, idSector, scip,
            IdOutCmd, idSectorSize, cbBytesReturned) then
          begin
            DisplayIdInfo(IdSector, scip, bIDCmd, bDfpDriveMap, i);{}
          end
          else
          begin
            writeln(Format('Identify Command Failed on Drive: %d', [i]));
            writeln(Format('  DriverStatus: bDriverError=0x%X, bIDEStatus=0x%X',
              [IdOutCmd.DriverStatus.bDriverError,
              IdOutCmd.DriverStatus.bIDEStatus]));
          end;
          writeln(Format('  cbBytesReturned: %d', [cbBytesReturned]));
          writeln('');
        end;
      end;
      for i:= 0 to MAX_IDE_DRIVES do
      begin
        if ((bDfpDriveMap shr i and 1) = 1) then
        begin
          ZeroMemory(@AttrOutCmd, sizeof(AttrOutCmd));
          ZeroMemory(@ThreshOutCmd, sizeof(ThreshOutCmd));
          with scip.irDriveRegs do
          begin
            bSectorCountReg:= 1;
            bSectorNumberReg:= 1;
            bDriveHeadReg:= $A0;
            bCommandReg:= $EC;
          end;
          writeln('');
          bSuccess:= DoReadAttributesCmd(hSMARTIOCTL, scip, AttrSCOP, i);
          if not bSuccess then
          begin
            writeln(Format('SMART Read Attr Command Failed on Drive: %d.',
              [i]));
                                            writeln(Format('  DriverStatus: bDriverError=0x%X, bIDEStatus=0x%X',
                                                      [AttrSCOP.DriverStatus.bDriverError,
              AttrSCOP.DriverStatus.bIDEStatus]));
            CloseHandle(hSMARTIOCTL);
            Exit;
          end
          else
          if not DoReadThresholdsCmd(hSMARTIOCTL, scip, ThresSCOP, i) then
          begin
            writeln(Format('SMART Read Thrsh Command Failed on Drive: %d.',
              [i]));
                                             writeln(Format('  DriverStatus: bDriverError=0x%X, bIDEStatus=0x%X',
              [ThresSCOP.DriverStatus.bDriverError,
              ThresSCOP.DriverStatus.bIDEStatus]));
            CloseHandle(hSMARTIOCTL);
            exit;
          end;
          DoPrintData(AttrOutCmd, ThreshOutCmd, i);
        end;
      end;
  end;
  CloseHandle(hSMARTIOCTL);
  writeln('');
end.

Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
Раз дощечка, два дощечка будет лесенка. Раз словечко, два словечко, будет ЧТО?
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
Тип сообщения:
Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Страница избранных вопросов Круглого стола.
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования