Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
11-07-2006 16:02
Пробрвал запустить, не работает.... а иммнео чтение смартов... DeviceIoControl с любой из DFP комманд даёт false и GetLastError() = 1 то есть unknown command. ( HDD поддерживает SMART так что предположение что драйвер не распознаёт комманду не верно).
// 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;
// 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
//---------------------------------------------------------------------
// 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;
//---------------------------------------------------------------------
// 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;
//=============================================================
// 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.
//-------------------------------------------------------------
// 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;
// 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;
// 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 );
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;
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 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( 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.
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.