moel@1: /* moel@1: moel@1: Version: MPL 1.1/GPL 2.0/LGPL 2.1 moel@1: moel@1: The contents of this file are subject to the Mozilla Public License Version moel@1: 1.1 (the "License"); you may not use this file except in compliance with moel@1: the License. You may obtain a copy of the License at moel@1: moel@1: http://www.mozilla.org/MPL/ moel@1: moel@1: Software distributed under the License is distributed on an "AS IS" basis, moel@1: WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License moel@1: for the specific language governing rights and limitations under the License. moel@1: moel@1: The Original Code is the Open Hardware Monitor code. moel@1: moel@1: The Initial Developer of the Original Code is moel@1: Michael Möller . moel@1: Portions created by the Initial Developer are Copyright (C) 2009-2010 moel@1: the Initial Developer. All Rights Reserved. moel@1: paulwerelds@218: Contributor(s): Paul Werelds moel@1: moel@1: Alternatively, the contents of this file may be used under the terms of moel@1: either the GNU General Public License Version 2 or later (the "GPL"), or moel@1: the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), moel@1: in which case the provisions of the GPL or the LGPL are applicable instead moel@1: of those above. If you wish to allow use of your version of this file only moel@1: under the terms of either the GPL or the LGPL, and not to allow others to moel@1: use your version of this file under the terms of the MPL, indicate your moel@1: decision by deleting the provisions above and replace them with the notice moel@1: and other provisions required by the GPL or the LGPL. If you do not delete moel@1: the provisions above, a recipient may use your version of this file under moel@1: the terms of any one of the MPL, the GPL or the LGPL. moel@1: moel@1: */ moel@1: moel@1: using System; paulwerelds@218: using System.Collections.Generic; moel@1: using System.Runtime.InteropServices; moel@1: moel@1: namespace OpenHardwareMonitor.Hardware.HDD { moel@165: moel@165: internal class SMART { moel@1: moel@1: [Flags] moel@1: public enum Status : ushort { moel@1: PreFailureWarranty = 0x01, moel@1: OnLineCollection = 0x02, moel@1: Performance = 0x04, moel@1: ErrorRate = 0x08, moel@1: EventCount = 0x10, moel@1: SelfPreserving = 0x20 moel@1: } moel@1: moel@231: [StructLayout(LayoutKind.Sequential, Pack = 1)] moel@231: public struct AttributeID { moel@231: private byte value; moel@231: moel@231: public AttributeID(byte value) { moel@231: this.value = value; moel@231: } moel@231: moel@231: public override bool Equals(Object obj) { moel@231: return obj is AttributeID && this == (AttributeID)obj; moel@231: } moel@231: public override int GetHashCode() { moel@231: return value.GetHashCode() ^ value.GetHashCode(); moel@231: } moel@231: public static bool operator ==(AttributeID a, AttributeID b) { moel@231: return a.value == b.value; moel@231: } moel@231: public static bool operator !=(AttributeID a, AttributeID b) { moel@231: return !(a == b); moel@231: } moel@231: moel@231: public string ToString(string format) { moel@231: return value.ToString(format); moel@231: } moel@231: moel@231: public static readonly AttributeID None = new AttributeID(0x00); moel@1: } moel@1: paulwerelds@233: // These are the more-or-less standard S.M.A.R.T attributes paulwerelds@233: // TODO: Filter out unused/obscure ones; some are interpreted differently paulwerelds@233: // between manufacturers paulwerelds@233: public static class CommonAttributes { paulwerelds@233: public static readonly AttributeID paulwerelds@233: ReadErrorRate = new AttributeID(0x01), paulwerelds@233: ThroughputPerformance = new AttributeID(0x02), paulwerelds@233: SpinUpTime = new AttributeID(0x03), paulwerelds@233: StartStopCount = new AttributeID(0x04), paulwerelds@233: ReallocatedSectorsCount = new AttributeID(0x05), paulwerelds@233: ReadChannelMargin = new AttributeID(0x06), paulwerelds@233: SeekErrorRate = new AttributeID(0x07), paulwerelds@233: SeekTimePerformance = new AttributeID(0x08), paulwerelds@233: PowerOnHours = new AttributeID(0x09), paulwerelds@233: SpinRetryCount = new AttributeID(0x0A), paulwerelds@233: RecalibrationRetries = new AttributeID(0x0B), paulwerelds@233: PowerCycleCount = new AttributeID(0x0C), paulwerelds@233: SoftReadErrorRate = new AttributeID(0x0D), paulwerelds@233: SataDownshiftErrorCount = new AttributeID(0xB7), paulwerelds@233: EndToEndError = new AttributeID(0xB8), paulwerelds@233: HeadStability = new AttributeID(0xB9), paulwerelds@233: InducedOpVibrationDetection = new AttributeID(0xBA), paulwerelds@233: ReportedUncorrectableErrors = new AttributeID(0xBB), paulwerelds@233: CommandTimeout = new AttributeID(0xBC), paulwerelds@233: HighFlyWrites = new AttributeID(0xBD), paulwerelds@233: AirflowTemperature = new AttributeID(0xBE), paulwerelds@233: GSenseErrorRate = new AttributeID(0xBF), paulwerelds@233: PowerOffRetractCount = new AttributeID(0xC0), paulwerelds@233: LoadCycleCount = new AttributeID(0xC1), paulwerelds@233: Temperature = new AttributeID(0xC2), paulwerelds@233: HardwareEccRecovered = new AttributeID(0xC3), paulwerelds@233: ReallocationEventCount = new AttributeID(0xC4), paulwerelds@233: CurrentPendingSectorCount = new AttributeID(0xC5), paulwerelds@233: UncorrectableSectorCount = new AttributeID(0xC6), paulwerelds@233: UltraDmaCrcErrorCount = new AttributeID(0xC7), paulwerelds@233: WriteErrorRate = new AttributeID(0xC8), paulwerelds@233: DataAddressMarkerrors = new AttributeID(0xCA), paulwerelds@233: RunOutCancel = new AttributeID(0xCB), paulwerelds@233: SoftEccCorrection = new AttributeID(0xCC), paulwerelds@233: ThermalAsperityRate = new AttributeID(0xCD), paulwerelds@233: FlyingHeight = new AttributeID(0xCE), paulwerelds@233: SpinHighCurrent = new AttributeID(0xCF), paulwerelds@233: SpinBuzz = new AttributeID(0xD0), paulwerelds@233: OfflineSeekPerformance = new AttributeID(0xD1), paulwerelds@233: VibrationDuringWrite = new AttributeID(0xD3), paulwerelds@233: ShockDuringWrite = new AttributeID(0xD4), paulwerelds@233: DiskShift = new AttributeID(0xDC), paulwerelds@233: GSenseErrorRateAlt = new AttributeID(0xDD), // Alternative to 0xBF paulwerelds@233: LoadedHours = new AttributeID(0xDE), paulwerelds@233: LoadUnloadRetryCount = new AttributeID(0xDF), paulwerelds@233: LoadFriction = new AttributeID(0xE0), paulwerelds@233: LoadUnloadCycleCount = new AttributeID(0xE1), paulwerelds@233: LoadInTime = new AttributeID(0xE2), paulwerelds@233: TorqueAmplificationCount = new AttributeID(0xE3), paulwerelds@233: PowerOffRetractCycle = new AttributeID(0xE4), paulwerelds@233: GMRHeadAmplitude = new AttributeID(0xE6), paulwerelds@233: DriveTemperature = new AttributeID(0xE7), paulwerelds@233: HeadFlyingHours = new AttributeID(0xF0), paulwerelds@233: LBAsWrittenTotal = new AttributeID(0xF1), paulwerelds@233: LBAsReadTotal = new AttributeID(0xF2), paulwerelds@233: ReadErrorRetryRate = new AttributeID(0xFA), paulwerelds@233: FreeFallProtection = new AttributeID(0xFE) paulwerelds@233: ; moel@231: } moel@231: moel@231: // Indilinx SSD SMART attributes paulwerelds@233: // TODO: Find out the purpose of attribute 0xD2 paulwerelds@233: // Seems to be unique to Indilinx drives, hence its name of UnknownUnique. paulwerelds@233: public static class IndilinxAttributes { paulwerelds@233: public static readonly AttributeID paulwerelds@233: ReadErrorRate = CommonAttributes.ReadErrorRate, paulwerelds@233: PowerOnHours = CommonAttributes.PowerOnHours, paulwerelds@233: PowerCycleCount = CommonAttributes.PowerCycleCount, paulwerelds@233: InitialBadBlockCount = new AttributeID(0xB8), paulwerelds@233: RemainingLife = new AttributeID(0xD1), paulwerelds@233: ProgramFailure = new AttributeID(0xC3), paulwerelds@233: EraseFailure = new AttributeID(0xC4), paulwerelds@233: ReadFailure = new AttributeID(0xC5), paulwerelds@233: SectorsRead = new AttributeID(0xC6), paulwerelds@233: SectorsWritten = new AttributeID(0xC7), paulwerelds@233: ReadCommands = new AttributeID(0xC8), paulwerelds@233: WriteCommands = new AttributeID(0xC9), paulwerelds@233: BitErrors = new AttributeID(0xCA), paulwerelds@233: CorrectedErrors = new AttributeID(0xCB), paulwerelds@233: BadBlockFullFlag = new AttributeID(0xCC), paulwerelds@233: MaxCellcycles = new AttributeID(0xCD), paulwerelds@233: MinErase = new AttributeID(0xCE), paulwerelds@233: MaxErase = new AttributeID(0xCF), paulwerelds@233: AverageEraseCount = new AttributeID(0xD0), paulwerelds@233: UnknownUnique = new AttributeID(0xD2), paulwerelds@233: SataErrorCountCRC = new AttributeID(0xD3), paulwerelds@233: SataErrorCountHandshake = new AttributeID(0xD4) paulwerelds@233: ; moel@231: } moel@231: moel@231: // Intel SSD SMART attributes paulwerelds@233: // TODO: Find out the meaning behind 0xE2, 0xE3 and 0xE4 paulwerelds@233: public static class IntelAttributes { paulwerelds@233: public static readonly AttributeID paulwerelds@233: ReadErrorRate = CommonAttributes.ReadErrorRate, paulwerelds@233: SpinUpTime = CommonAttributes.SpinUpTime, paulwerelds@233: StartStopCount = CommonAttributes.StartStopCount, paulwerelds@233: ReallocatedSectorsCount = CommonAttributes.ReallocatedSectorsCount, paulwerelds@233: PowerOnHours = CommonAttributes.PowerOnHours, paulwerelds@233: PowerCycleCount = CommonAttributes.PowerCycleCount, paulwerelds@233: EndToEndError = CommonAttributes.EndToEndError, // Only on G2 drives! paulwerelds@233: paulwerelds@233: // Different from the common attribute PowerOffRetractCount, same ID paulwerelds@233: UnsafeShutdownCount = new AttributeID(0xC0), paulwerelds@233: HostWrites = new AttributeID(0xE1), paulwerelds@233: RemainingLife = new AttributeID(0xE8), paulwerelds@233: MediaWearOutIndicator = new AttributeID(0xE9) paulwerelds@233: ; moel@231: } moel@231: moel@231: // Samsung SSD SMART attributes paulwerelds@233: // TODO: AF, B0, B1, B5, B6, BB, C3, C6, C7, E8, E9 paulwerelds@233: public static class SamsungAttributes { paulwerelds@233: public static readonly AttributeID paulwerelds@233: PowerOnHours = CommonAttributes.PowerOnHours, paulwerelds@233: PowerCycleCount = CommonAttributes.PowerCycleCount, paulwerelds@233: UsedReservedBlockCountChip = new AttributeID(0xB2), // Unique paulwerelds@233: UsedReservedBlockCountTotal = new AttributeID(0xB3), // Unique paulwerelds@233: RemainingLife = new AttributeID(0xB4), // Unique paulwerelds@233: RuntimeBadBlockTotal = new AttributeID(0xB7) paulwerelds@233: ; moel@231: } moel@231: moel@231: // SandForce SSD SMART attributes paulwerelds@233: // Note: 0xE9 and 0xEA are reserved attributes and unique paulwerelds@233: public static class SandForceAttributes { paulwerelds@233: public static readonly AttributeID paulwerelds@233: ReadErrorRate = CommonAttributes.ReadErrorRate, paulwerelds@233: RetiredBlockCount = new AttributeID(0x05), paulwerelds@233: PowerOnHours = CommonAttributes.PowerOnHours, paulwerelds@233: PowerCycleCount = CommonAttributes.PowerCycleCount, paulwerelds@233: ProgramFailCount = new AttributeID(0xAB), // Unique paulwerelds@233: EraseFailCount = new AttributeID(0xAC), // Unique paulwerelds@233: UnexpectedPowerLossCount = new AttributeID(0xAE), // Unique paulwerelds@233: WearRangeDelta = new AttributeID(0xB1), // Unique paulwerelds@233: ProgramFailCountAlt = new AttributeID(0xB5), // Same as 0xAB paulwerelds@233: EraseFailCountAlt = new AttributeID(0xB6), // Same as 0xAC paulwerelds@233: ReportedUncorrectableErrors = paulwerelds@233: CommonAttributes.ReportedUncorrectableErrors, paulwerelds@233: paulwerelds@233: Temperature = CommonAttributes.Temperature, // SF-1500 only! paulwerelds@233: paulwerelds@233: // Opposite of the common attribute HardwareECCRecovered paulwerelds@233: UnrecoverableECC = new AttributeID(0xC3), paulwerelds@233: ReallocationEventCount = new AttributeID(0xC4), paulwerelds@233: RemainingLife = new AttributeID(0xE7), paulwerelds@233: LifetimeWrites = new AttributeID(0xF1), paulwerelds@233: LifetimeReads = new AttributeID(0xF2) paulwerelds@233: ; paulwerelds@218: } paulwerelds@218: moel@1: [StructLayout(LayoutKind.Sequential, Pack = 1)] moel@1: public struct DriveAttribute { moel@1: public AttributeID ID; moel@1: public Status StatusFlags; moel@1: public byte AttrValue; moel@1: public byte WorstValue; moel@1: [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] moel@1: public byte[] RawValue; moel@1: public byte Reserved; moel@1: }; moel@1: moel@1: [Flags] moel@195: protected enum AccessMode : uint { moel@1: Read = 0x80000000, moel@1: Write = 0x40000000, moel@1: Execute = 0x20000000, moel@1: All = 0x10000000 moel@1: } moel@1: moel@1: [Flags] moel@195: protected enum ShareMode : uint { moel@1: None = 0, moel@1: Read = 1, moel@1: Write = 2, moel@1: Delete = 4 moel@1: } moel@1: moel@195: protected enum CreationMode : uint { moel@1: New = 1, moel@1: CreateAlways = 2, moel@1: OpenExisting = 3, moel@1: OpenAlways = 4, moel@1: TruncateExisting = 5 moel@1: } moel@1: moel@1: [Flags] moel@195: protected enum FileAttribute : uint { moel@1: Readonly = 0x00000001, moel@1: Hidden = 0x00000002, moel@1: System = 0x00000004, moel@1: Directory = 0x00000010, moel@1: Archive = 0x00000020, moel@1: Device = 0x00000040, moel@1: Normal = 0x00000080, moel@1: Temporary = 0x00000100, moel@1: SparseFile = 0x00000200, moel@1: ReparsePoint = 0x00000400, moel@1: Compressed = 0x00000800, moel@1: Offline = 0x00001000, moel@1: NotContentIndexed = 0x00002000, moel@1: Encrypted = 0x00004000, moel@1: } moel@1: moel@195: protected enum DriveCommand : uint { moel@1: GetVersion = 0x00074080, moel@1: SendDriveCommand = 0x0007c084, moel@1: ReceiveDriveData = 0x0007c088 moel@1: } moel@1: moel@1: [StructLayout(LayoutKind.Sequential, Pack = 1)] moel@195: protected struct CommandBlockRegisters { moel@1: public byte Features; moel@1: public byte SectorCount; moel@1: public byte LBALow; moel@1: public byte LBAMid; moel@1: public byte LBAHigh; moel@1: public byte Device; moel@1: public byte Command; moel@1: public byte Reserved; moel@1: } moel@1: moel@1: [StructLayout(LayoutKind.Sequential, Pack = 1)] moel@195: protected struct DriveCommandParameter { moel@195: public uint BufferSize; moel@1: public CommandBlockRegisters Registers; moel@1: public byte DriveNumber; moel@188: [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] moel@1: public byte[] Reserved; moel@1: } moel@1: moel@1: [StructLayout(LayoutKind.Sequential, Pack = 1)] moel@195: protected struct DriverStatus { moel@1: public byte DriverError; moel@1: public byte IDEError; moel@1: [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] moel@1: public byte[] Reserved; moel@1: } moel@1: moel@1: [StructLayout(LayoutKind.Sequential, Pack = 1)] moel@195: protected struct DriveCommandResult { moel@1: public uint BufferSize; moel@1: public DriverStatus DriverStatus; moel@1: } moel@1: moel@1: [StructLayout(LayoutKind.Sequential, Pack = 1)] moel@195: protected struct DriveSmartReadResult { moel@1: public uint BufferSize; moel@1: public DriverStatus DriverStatus; moel@1: public byte Version; moel@1: public byte Reserved; moel@1: [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)] moel@1: public DriveAttribute[] Attributes; moel@1: } moel@1: moel@1: [StructLayout(LayoutKind.Sequential, Pack = 1)] moel@195: protected struct Identify { moel@1: public ushort GeneralConfiguration; moel@1: public ushort NumberOfCylinders; moel@1: public ushort Reserved; moel@1: public ushort NumberOfHeads; moel@1: public ushort UnformattedBytesPerTrack; moel@1: public ushort UnformattedBytesPerSector; moel@1: public ushort SectorsPerTrack; moel@1: [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] moel@1: public ushort[] VendorUnique; moel@1: [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] moel@1: public byte[] SerialNumber; moel@1: public ushort BufferType; moel@1: public ushort BufferSectorSize; moel@1: public ushort NumberOfEccBytes; moel@1: [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] moel@1: public byte[] FirmwareRevision; moel@1: [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)] moel@1: public byte[] ModelNumber; moel@1: public ushort MoreVendorUnique; moel@1: public ushort DoubleWordIo; moel@1: public ushort Capabilities; moel@1: public ushort MoreReserved; moel@1: public ushort PioCycleTimingMode; moel@1: public ushort DmaCycleTimingMode; moel@1: [MarshalAs(UnmanagedType.ByValArray, SizeConst = 406)] moel@1: public byte[] More; moel@1: } moel@1: moel@1: [StructLayout(LayoutKind.Sequential, Pack = 1)] moel@195: protected struct DriveIdentifyResult { moel@1: public uint BufferSize; moel@1: public DriverStatus DriverStatus; moel@1: public Identify Identify; moel@1: } moel@1: moel@1: public static readonly IntPtr INVALID_HANDLE_VALUE = (IntPtr)(-1); moel@1: moel@1: private const byte SMART_CMD = 0xB0; moel@1: private const byte ID_CMD = 0xEC; moel@1: moel@1: private const byte SMART_READ_DATA = 0xD0; moel@1: private const byte SMART_ENABLE_OPERATIONS = 0xD8; moel@1: moel@1: private const byte SMART_LBA_MID = 0x4F; moel@1: private const byte SMART_LBA_HI = 0xC2; moel@1: moel@1: private const int MAX_DRIVE_ATTRIBUTES = 512; moel@1: moel@167: private SMART() { } moel@1: moel@1: public static IntPtr OpenPhysicalDrive(int driveNumber) { moel@167: return NativeMethods.CreateFile(@"\\.\PhysicalDrive" + driveNumber, moel@1: AccessMode.Read | AccessMode.Write, ShareMode.Read | ShareMode.Write, moel@1: IntPtr.Zero, CreationMode.OpenExisting, FileAttribute.Device, moel@1: IntPtr.Zero); moel@1: } moel@1: moel@1: public static bool EnableSmart(IntPtr handle, int driveNumber) { moel@1: DriveCommandParameter parameter = new DriveCommandParameter(); moel@1: DriveCommandResult result; moel@1: uint bytesReturned; moel@1: moel@1: parameter.DriveNumber = (byte)driveNumber; moel@1: parameter.Registers.Features = SMART_ENABLE_OPERATIONS; moel@1: parameter.Registers.LBAMid = SMART_LBA_MID; moel@1: parameter.Registers.LBAHigh = SMART_LBA_HI; moel@1: parameter.Registers.Command = SMART_CMD; moel@1: moel@167: return NativeMethods.DeviceIoControl(handle, DriveCommand.SendDriveCommand, moel@167: ref parameter, Marshal.SizeOf(typeof(DriveCommandParameter)), out result, moel@1: Marshal.SizeOf(typeof(DriveCommandResult)), out bytesReturned, moel@1: IntPtr.Zero); moel@1: } moel@1: paulwerelds@233: public static DriveAttribute[] ReadSmart(IntPtr handle, paulwerelds@218: int driveNumber) paulwerelds@218: { moel@1: DriveCommandParameter parameter = new DriveCommandParameter(); moel@1: DriveSmartReadResult result; moel@1: uint bytesReturned; moel@1: moel@1: parameter.DriveNumber = (byte)driveNumber; moel@1: parameter.Registers.Features = SMART_READ_DATA; moel@1: parameter.Registers.LBAMid = SMART_LBA_MID; moel@1: parameter.Registers.LBAHigh = SMART_LBA_HI; moel@1: parameter.Registers.Command = SMART_CMD; moel@1: paulwerelds@218: bool isValid = NativeMethods.DeviceIoControl(handle, moel@167: DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter), moel@167: out result, Marshal.SizeOf(typeof(DriveSmartReadResult)), moel@167: out bytesReturned, IntPtr.Zero); moel@1: paulwerelds@233: return (isValid) ? result.Attributes : new DriveAttribute[0]; moel@1: } moel@1: moel@1: public static string ReadName(IntPtr handle, int driveNumber) { moel@1: DriveCommandParameter parameter = new DriveCommandParameter(); moel@1: DriveIdentifyResult result; moel@1: uint bytesReturned; moel@1: moel@1: parameter.DriveNumber = (byte)driveNumber; moel@1: parameter.Registers.Command = ID_CMD; moel@1: moel@167: bool valid = NativeMethods.DeviceIoControl(handle, moel@167: DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter), moel@167: out result, Marshal.SizeOf(typeof(DriveIdentifyResult)), moel@167: out bytesReturned, IntPtr.Zero); moel@1: moel@1: if (!valid) moel@1: return null; moel@1: else { moel@1: moel@1: byte[] bytes = result.Identify.ModelNumber; moel@1: char[] chars = new char[bytes.Length]; moel@1: for (int i = 0; i < bytes.Length; i += 2) { moel@1: chars[i] = (char)bytes[i + 1]; moel@1: chars[i + 1] = (char)bytes[i]; moel@1: } moel@1: moel@1: return new string(chars).Trim(); moel@1: } moel@1: } moel@1: moel@167: public static int CloseHandle(IntPtr handle) { moel@167: return NativeMethods.CloseHandle(handle); moel@167: } moel@167: moel@195: protected static class NativeMethods { moel@167: private const string KERNEL = "kernel32.dll"; moel@167: moel@167: [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi, moel@167: CharSet = CharSet.Unicode)] moel@167: public static extern IntPtr CreateFile(string fileName, moel@167: AccessMode desiredAccess, ShareMode shareMode, IntPtr securityAttributes, moel@167: CreationMode creationDisposition, FileAttribute flagsAndAttributes, moel@167: IntPtr templateFilehandle); moel@167: moel@167: [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)] moel@167: public static extern int CloseHandle(IntPtr handle); moel@167: moel@167: [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)] moel@167: [return: MarshalAsAttribute(UnmanagedType.Bool)] moel@167: public static extern bool DeviceIoControl(IntPtr handle, moel@167: DriveCommand command, ref DriveCommandParameter parameter, moel@167: int parameterSize, out DriveSmartReadResult result, int resultSize, moel@167: out uint bytesReturned, IntPtr overlapped); moel@167: moel@167: [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)] moel@167: [return: MarshalAsAttribute(UnmanagedType.Bool)] moel@167: public static extern bool DeviceIoControl(IntPtr handle, moel@167: DriveCommand command, ref DriveCommandParameter parameter, moel@167: int parameterSize, out DriveCommandResult result, int resultSize, moel@167: out uint bytesReturned, IntPtr overlapped); moel@167: moel@167: [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)] moel@167: [return: MarshalAsAttribute(UnmanagedType.Bool)] moel@167: public static extern bool DeviceIoControl(IntPtr handle, moel@167: DriveCommand command, ref DriveCommandParameter parameter, moel@167: int parameterSize, out DriveIdentifyResult result, int resultSize, moel@167: out uint bytesReturned, IntPtr overlapped); moel@167: } moel@1: } moel@1: }