diff --git a/LibreHardwareMonitorLib/Hardware/Storage/ATAStorage.cs b/LibreHardwareMonitorLib/Hardware/Storage/ATAStorage.cs index eeed96f..42cf0d6 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/ATAStorage.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/ATAStorage.cs @@ -51,7 +51,7 @@ public abstract class AtaStorage : AbstractStorage ISmart smart = new WindowsSmart(storageInfo.Index); string name = null; string firmwareRevision = null; - AtaSmart.SMART_ATTRIBUTE[] smartAttributes = { }; + AtaSmart.SMART_ATTRIBUTE[] smartAttributes = []; if (smart.IsValid) { @@ -149,7 +149,7 @@ public abstract class AtaStorage : AbstractStorage { const BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance; - return Activator.CreateInstance(type, flags, null, new object[] { storageInfo, smart, name, firmwareRevision, storageInfo.Index, settings }, null) as AtaStorage; + return Activator.CreateInstance(type, flags, null, [storageInfo, smart, name, firmwareRevision, storageInfo.Index, settings], null) as AtaStorage; } } } diff --git a/LibreHardwareMonitorLib/Hardware/Storage/WindowsSmart.cs b/LibreHardwareMonitorLib/Hardware/Storage/WindowsSmart.cs index b369ca7..4d8f034 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/WindowsSmart.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/WindowsSmart.cs @@ -12,6 +12,7 @@ using LibreHardwareMonitor.Interop; using Windows.Win32; using Windows.Win32.Storage.FileSystem; using Windows.Win32.System.Ioctl; +using static LibreHardwareMonitor.Interop.AtaSmart; namespace LibreHardwareMonitor.Hardware.Storage; @@ -50,8 +51,8 @@ internal class WindowsSmart : ISmart irDriveRegs = { bFeaturesReg = 0xD8, - bCylLowReg = AtaSmart.SMART_LBA_MID, - bCylHighReg = AtaSmart.SMART_LBA_HI, + bCylLowReg = (byte)PInvoke.SMART_CYL_LOW, + bCylHighReg = (byte)PInvoke.SMART_CYL_HI, bCommandReg = (byte) PInvoke.SMART_CMD } }; @@ -68,7 +69,7 @@ internal class WindowsSmart : ISmart null); } - public unsafe AtaSmart.SMART_ATTRIBUTE[] ReadSmartData() + public unsafe SMART_ATTRIBUTE[] ReadSmartData() { if (_handle.IsClosed) throw new ObjectDisposedException(nameof(WindowsSmart)); @@ -78,14 +79,14 @@ internal class WindowsSmart : ISmart bDriveNumber = (byte)_driveNumber, irDriveRegs = { - bFeaturesReg = 0xD0, - bCylLowReg = AtaSmart.SMART_LBA_MID, - bCylHighReg = AtaSmart.SMART_LBA_HI, + bFeaturesReg = (byte)PInvoke.READ_ATTRIBUTES, + bCylLowReg = (byte)PInvoke.SMART_CYL_LOW, + bCylHighReg = (byte)PInvoke.SMART_CYL_HI, bCommandReg = (byte) PInvoke.SMART_CMD } }; - int cb = sizeof(SENDCMDOUTPARAMS) + 2 + 512; // 2 bytes padding + 512 bytes buffer. + int cb = sizeof(SENDCMDOUTPARAMS) + 512; // 512 bytes buffer. IntPtr buffer = Marshal.AllocHGlobal(cb); bool isValid = PInvoke.DeviceIoControl(_handle, @@ -99,11 +100,16 @@ internal class WindowsSmart : ISmart if (isValid) { - AtaSmart.SMART_ATTRIBUTE[] attributes = new AtaSmart.SMART_ATTRIBUTE[512 / sizeof(AtaSmart.SMART_ATTRIBUTE)]; - AtaSmart.SMART_ATTRIBUTE* pAttributes = (AtaSmart.SMART_ATTRIBUTE*)((byte*)buffer + (int)Marshal.OffsetOf(nameof(SENDCMDOUTPARAMS.bBuffer)) + 2); + var attributes = new SMART_ATTRIBUTE[30]; // A maximum of 30 are returned. - for (int i = 0; i < attributes.Length; i++) - attributes[i] = pAttributes[i]; + var sendCmdOutParams = (SENDCMDOUTPARAMS*)buffer; + fixed (byte* pBuffer = &sendCmdOutParams->bBuffer[0]) + { + var pAttribute = (SMART_ATTRIBUTE*)(pBuffer + 2); // + 2 padding. + + for (int i = 0; i < attributes.Length; i++) + attributes[i] = pAttribute[i]; + } Marshal.FreeHGlobal(buffer); return attributes; @@ -113,7 +119,7 @@ internal class WindowsSmart : ISmart return null; } - public unsafe AtaSmart.SMART_THRESHOLD[] ReadSmartThresholds() + public unsafe SMART_THRESHOLD[] ReadSmartThresholds() { if (_handle.IsClosed) throw new ObjectDisposedException(nameof(WindowsSmart)); @@ -123,14 +129,14 @@ internal class WindowsSmart : ISmart bDriveNumber = (byte)_driveNumber, irDriveRegs = { - bFeaturesReg = 0xD1, - bCylLowReg = AtaSmart.SMART_LBA_MID, - bCylHighReg = AtaSmart.SMART_LBA_HI, + bFeaturesReg = (byte)PInvoke.READ_THRESHOLDS, + bCylLowReg = (byte)PInvoke.SMART_CYL_LOW, + bCylHighReg = (byte)PInvoke.SMART_CYL_HI, bCommandReg = (byte) PInvoke.SMART_CMD } }; - int cb = sizeof(SENDCMDOUTPARAMS) + 2 + 512; // 2 bytes padding + 512 bytes buffer. + int cb = sizeof(SENDCMDOUTPARAMS) + 512; // 2 bytes padding + 512 bytes buffer. IntPtr buffer = Marshal.AllocHGlobal(cb); bool isValid = PInvoke.DeviceIoControl(_handle, PInvoke.SMART_RCV_DRIVE_DATA, @@ -143,11 +149,16 @@ internal class WindowsSmart : ISmart if (isValid) { - AtaSmart.SMART_THRESHOLD[] thresholds = new AtaSmart.SMART_THRESHOLD[512 / sizeof(AtaSmart.SMART_THRESHOLD)]; - AtaSmart.SMART_THRESHOLD* pThresholds = (AtaSmart.SMART_THRESHOLD*) ((byte*)buffer + (int)Marshal.OffsetOf(nameof(SENDCMDOUTPARAMS.bBuffer)) + 2); + var thresholds = new SMART_THRESHOLD[30]; // A maximum of 30 are returned. - for (int i = 0; i < thresholds.Length; i++) - thresholds[i] = pThresholds[i]; + var sendCmdOutParams = (SENDCMDOUTPARAMS*)buffer; + fixed (byte* pBuffer = &sendCmdOutParams->bBuffer[0]) + { + var pThreshold = (SMART_THRESHOLD*)(pBuffer + 2); // + 2 padding. + + for (int i = 0; i < thresholds.Length; i++) + thresholds[i] = pThreshold[i]; + } Marshal.FreeHGlobal(buffer); return thresholds; @@ -171,7 +182,7 @@ internal class WindowsSmart : ISmart } }; - int cb = sizeof(SENDCMDOUTPARAMS) + sizeof(AtaSmart.IDENTIFY_DEVICE_DATA); + int cb = sizeof(SENDCMDOUTPARAMS) + sizeof(IDENTIFY_DEVICE_DATA); IntPtr buffer = Marshal.AllocHGlobal(cb); bool valid = PInvoke.DeviceIoControl(_handle, @@ -191,7 +202,7 @@ internal class WindowsSmart : ISmart return false; } - AtaSmart.IDENTIFY_DEVICE_DATA identity = *(AtaSmart.IDENTIFY_DEVICE_DATA*)((byte*)buffer + (int)Marshal.OffsetOf(nameof(SENDCMDOUTPARAMS.bBuffer))); + IDENTIFY_DEVICE_DATA identity = *(IDENTIFY_DEVICE_DATA*)((byte*)buffer + (int)Marshal.OffsetOf(nameof(SENDCMDOUTPARAMS.bBuffer))); byte* p = identity.ModelNumber; for (int i = 0; i < 40; i += 2) diff --git a/LibreHardwareMonitorLib/Interop/AtaSmart.cs b/LibreHardwareMonitorLib/Interop/AtaSmart.cs index 8b4d7d1..2a9b18f 100644 --- a/LibreHardwareMonitorLib/Interop/AtaSmart.cs +++ b/LibreHardwareMonitorLib/Interop/AtaSmart.cs @@ -3,13 +3,14 @@ // Copyright (C) LibreHardwareMonitor and Contributors. // All Rights Reserved. +using System.Runtime.InteropServices; using Windows.Win32.Storage.IscsiDisc; // ReSharper disable InconsistentNaming namespace LibreHardwareMonitor.Interop; -public class AtaSmart +public unsafe class AtaSmart { internal const int IOCTL_BUFFER_SIZE = 4096; internal const int SCSI_IOCTL_SENSE_SIZE = 24; @@ -25,24 +26,26 @@ public class AtaSmart internal const byte SMART_LBA_HI = 0xC2; internal const byte SMART_LBA_MID = 0x4F; - public unsafe struct SMART_ATTRIBUTE + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct SMART_ATTRIBUTE { - public byte Id; - public short Flags; - public byte CurrentValue; - public byte WorstValue; - public fixed byte RawValue[6]; - public byte Reserved; + internal byte Id; + internal ushort Flags; + internal byte CurrentValue; + internal byte WorstValue; + internal fixed byte RawValue[6]; + internal byte Reserved; } - public unsafe struct SMART_THRESHOLD + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct SMART_THRESHOLD { public byte Id; public byte Threshold; public fixed byte Reserved[10]; } - internal unsafe struct IDENTIFY_DEVICE_DATA + internal struct IDENTIFY_DEVICE_DATA { public ushort GeneralConfiguration; public ushort NumberOfCylinders; @@ -75,7 +78,7 @@ public class AtaSmart public fixed ushort Reserved3[197]; } - internal unsafe struct NVME_PASS_THROUGH_IOCTL + internal struct NVME_PASS_THROUGH_IOCTL { public SRB_IO_CONTROL SrbIoCtrl; public fixed uint VendorSpecific[NVME_IOCTL_VENDOR_SPECIFIC_DW_SIZE]; @@ -89,7 +92,7 @@ public class AtaSmart public fixed byte DataBuffer[IOCTL_BUFFER_SIZE]; } - internal unsafe struct SCSI_PASS_THROUGH + internal struct SCSI_PASS_THROUGH { public Windows.Win32.Storage.IscsiDisc.SCSI_PASS_THROUGH Spt; public fixed byte SenseBuf[SCSI_IOCTL_SENSE_SIZE]; diff --git a/LibreHardwareMonitorLib/NativeMethods.txt b/LibreHardwareMonitorLib/NativeMethods.txt index 5ab08d8..338bbda 100644 --- a/LibreHardwareMonitorLib/NativeMethods.txt +++ b/LibreHardwareMonitorLib/NativeMethods.txt @@ -67,3 +67,7 @@ GetProcAddress SCSI_IOCTL_* SMART_CMD BATTERY_UNKNOWN_* +SMART_CYL_LOW +SMART_CYL_HI +READ_ATTRIBUTES +READ_THRESHOLDS