mirror of
http://gitlab.expertsoft.com.ua/git/expertcad
synced 2026-01-11 17:25:39 +02:00
962 lines
50 KiB
ObjectPascal
962 lines
50 KiB
ObjectPascal
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.
|