public NVMeHealthInfo(Kernel32.NVME_HEALTH_INFO_LOG log) { CriticalWarning = (Kernel32.NVME_CRITICAL_WARNING)log.CriticalWarning; Temperature = KelvinToCelsius(log.CompositeTemp); AvailableSpare = log.AvailableSpare; AvailableSpareThreshold = log.AvailableSpareThreshold; PercentageUsed = log.PercentageUsed; DataUnitRead = BitConverter.ToUInt64(log.DataUnitRead, 0); DataUnitWritten = BitConverter.ToUInt64(log.DataUnitWritten, 0); HostReadCommands = BitConverter.ToUInt64(log.HostReadCommands, 0); HostWriteCommands = BitConverter.ToUInt64(log.HostWriteCommands, 0); ControllerBusyTime = BitConverter.ToUInt64(log.ControllerBusyTime, 0); PowerCycle = BitConverter.ToUInt64(log.PowerCycles, 0); PowerOnHours = BitConverter.ToUInt64(log.PowerOnHours, 0); UnsafeShutdowns = BitConverter.ToUInt64(log.UnsafeShutdowns, 0); MediaErrors = BitConverter.ToUInt64(log.MediaAndDataIntegrityErrors, 0); ErrorInfoLogEntryCount = BitConverter.ToUInt64(log.NumberErrorInformationLogEntries, 0); WarningCompositeTemperatureTime = log.WarningCompositeTemperatureTime; CriticalCompositeTemperatureTime = log.CriticalCompositeTemperatureTime; TemperatureSensors = new short[log.TemperatureSensor.Length]; for (int i = 0; i < TemperatureSensors.Length; i++) { TemperatureSensors[i] = KelvinToCelsius(log.TemperatureSensor[i]); } }
public bool HealthInfoLog(SafeHandle hDevice, out Kernel32.NVME_HEALTH_INFO_LOG data) { data = Kernel32.CreateStruct <Kernel32.NVME_HEALTH_INFO_LOG>(); if (hDevice == null || hDevice.IsInvalid) { return(false); } bool result = false; IntPtr buffer; Kernel32.NVME_PASS_THROUGH_IOCTL passThrough = Kernel32.CreateStruct <Kernel32.NVME_PASS_THROUGH_IOCTL>(); passThrough.srb.HeaderLenght = (uint)Marshal.SizeOf <Kernel32.SRB_IO_CONTROL>(); passThrough.srb.Signature = Encoding.ASCII.GetBytes(Kernel32.IntelNVMeMiniPortSignature2); passThrough.srb.Timeout = 10; passThrough.srb.ControlCode = Kernel32.NVME_PASS_THROUGH_SRB_IO_CODE; passThrough.srb.ReturnCode = 0; passThrough.srb.Length = (uint)Marshal.SizeOf <Kernel32.NVME_PASS_THROUGH_IOCTL>() - (uint)Marshal.SizeOf <Kernel32.SRB_IO_CONTROL>(); passThrough.NVMeCmd[0] = (uint)Kernel32.STORAGE_PROTOCOL_NVME_DATA_TYPE.NVMeDataTypeLogPage; // GetLogPage passThrough.NVMeCmd[1] = 0xFFFFFFFF; // address passThrough.NVMeCmd[10] = 0x007f0002; // uint cdw10 = 0x000000002 | (((size / 4) - 1) << 16); passThrough.Direction = Kernel32.NVME_DIRECTION.NVME_FROM_DEV_TO_HOST; passThrough.QueueId = 0; passThrough.DataBufferLen = (uint)passThrough.DataBuffer.Length; passThrough.MetaDataLen = 0; passThrough.ReturnBufferLen = (uint)Marshal.SizeOf <Kernel32.NVME_PASS_THROUGH_IOCTL>(); int length = Marshal.SizeOf <Kernel32.NVME_PASS_THROUGH_IOCTL>(); buffer = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(passThrough, buffer, false); bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_MINIPORT, buffer, length, buffer, length, out _, IntPtr.Zero); if (validTransfer) { var offset = Marshal.OffsetOf <Kernel32.NVME_PASS_THROUGH_IOCTL>(nameof(Kernel32.NVME_PASS_THROUGH_IOCTL.DataBuffer)); IntPtr newPtr = IntPtr.Add(buffer, offset.ToInt32()); var item = Marshal.PtrToStructure <Kernel32.NVME_HEALTH_INFO_LOG>(newPtr); data = item; Marshal.FreeHGlobal(buffer); result = true; } else { Marshal.FreeHGlobal(buffer); } return(result); }
public bool HealthInfoLog(SafeHandle hDevice, out Kernel32.NVME_HEALTH_INFO_LOG data) { data = Kernel32.CreateStruct <Kernel32.NVME_HEALTH_INFO_LOG>(); if (hDevice == null || hDevice.IsInvalid) { return(false); } bool result = false; Kernel32.STORAGE_QUERY_BUFFER nptwb = Kernel32.CreateStruct <Kernel32.STORAGE_QUERY_BUFFER>(); nptwb.ProtocolSpecific.ProtocolType = Kernel32.STORAGE_PROTOCOL_TYPE.ProtocolTypeNvme; nptwb.ProtocolSpecific.DataType = (uint)Kernel32.STORAGE_PROTOCOL_NVME_DATA_TYPE.NVMeDataTypeLogPage; nptwb.ProtocolSpecific.ProtocolDataRequestValue = (uint)Kernel32.NVME_LOG_PAGES.NVME_LOG_PAGE_HEALTH_INFO; nptwb.ProtocolSpecific.ProtocolDataOffset = (uint)Marshal.SizeOf <Kernel32.STORAGE_PROTOCOL_SPECIFIC_DATA>(); nptwb.ProtocolSpecific.ProtocolDataLength = (uint)nptwb.Buffer.Length; nptwb.PropertyId = Kernel32.STORAGE_PROPERTY_ID.StorageAdapterProtocolSpecificProperty; nptwb.QueryType = Kernel32.STORAGE_QUERY_TYPE.PropertyStandardQuery; int length = Marshal.SizeOf <Kernel32.STORAGE_QUERY_BUFFER>(); IntPtr buffer = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(nptwb, buffer, false); bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_STORAGE_QUERY_PROPERTY, buffer, length, buffer, length, out _, IntPtr.Zero); if (validTransfer) { //map NVME_HEALTH_INFO_LOG to nptwb.Buffer var offset = Marshal.OffsetOf <Kernel32.STORAGE_QUERY_BUFFER>(nameof(Kernel32.STORAGE_QUERY_BUFFER.Buffer)); var newPtr = IntPtr.Add(buffer, offset.ToInt32()); var item = Marshal.PtrToStructure <Kernel32.NVME_HEALTH_INFO_LOG>(newPtr); data = item; Marshal.FreeHGlobal(buffer); result = true; } else { Marshal.FreeHGlobal(buffer); } return(result); }
public Storage.NVMeHealthInfo GetHealthInfo() { if (_handle == null || _handle.IsClosed) { return(null); } bool valid = false; var data = new Kernel32.NVME_HEALTH_INFO_LOG(); if (NVMeDrive != null) { valid = NVMeDrive.HealthInfoLog(_handle, out data); } if (!valid) { return(null); } return(new NVMeHealthInfo(data)); }
public bool HealthInfoLog(SafeHandle hDevice, out Kernel32.NVME_HEALTH_INFO_LOG data) { data = Kernel32.CreateStruct <Kernel32.NVME_HEALTH_INFO_LOG>(); if (hDevice == null || hDevice.IsInvalid) { return(false); } bool result = false; Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS buffers = Kernel32.CreateStruct <Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS>(); buffers.Spt.Length = (ushort)Marshal.SizeOf <Kernel32.SCSI_PASS_THROUGH>(); buffers.Spt.PathId = 0; buffers.Spt.TargetId = 0; buffers.Spt.Lun = 0; buffers.Spt.SenseInfoLength = 24; buffers.Spt.DataTransferLength = (uint)buffers.DataBuf.Length; buffers.Spt.TimeOutValue = 2; buffers.Spt.DataBufferOffset = Marshal.OffsetOf <Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS>(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf)); buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf <Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS>(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.SenseBuf)); buffers.Spt.CdbLength = 16; buffers.Spt.Cdb[0] = 0xB5; // SECURITY PROTOCOL IN buffers.Spt.Cdb[1] = 0xFE; // Samsung Protocol buffers.Spt.Cdb[3] = 6; // Log Data buffers.Spt.Cdb[8] = 0; // Transfer Length buffers.Spt.Cdb[9] = 0x40; // Transfer Length buffers.Spt.DataIn = (byte)Kernel32.SCSI_IOCTL_DATA.SCSI_IOCTL_DATA_OUT; buffers.DataBuf[0] = 2; buffers.DataBuf[4] = 0xff; buffers.DataBuf[5] = 0xff; buffers.DataBuf[6] = 0xff; buffers.DataBuf[7] = 0xff; int length = Marshal.SizeOf <Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS>(); IntPtr buffer = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(buffers, buffer, false); bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_PASS_THROUGH, buffer, length, buffer, length, out _, IntPtr.Zero); Marshal.FreeHGlobal(buffer); if (validTransfer) { //read data from samsung SSD buffers = Kernel32.CreateStruct <Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS>(); buffers.Spt.Length = (ushort)Marshal.SizeOf <Kernel32.SCSI_PASS_THROUGH>(); buffers.Spt.PathId = 0; buffers.Spt.TargetId = 0; buffers.Spt.Lun = 0; buffers.Spt.SenseInfoLength = 24; buffers.Spt.DataTransferLength = (uint)buffers.DataBuf.Length; buffers.Spt.TimeOutValue = 2; buffers.Spt.DataBufferOffset = Marshal.OffsetOf <Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS>(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf)); buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf <Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS>(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.SenseBuf)); buffers.Spt.CdbLength = 16; buffers.Spt.Cdb[0] = 0xA2; // SECURITY PROTOCOL IN buffers.Spt.Cdb[1] = 0xFE; // Samsung Protocol buffers.Spt.Cdb[3] = 6; // Log Data buffers.Spt.Cdb[8] = 2; // Transfer Length (high) buffers.Spt.Cdb[9] = 0; // Transfer Length (low) buffers.Spt.DataIn = (byte)Kernel32.SCSI_IOCTL_DATA.SCSI_IOCTL_DATA_IN; length = Marshal.SizeOf <Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS>(); buffer = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(buffers, buffer, false); validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_PASS_THROUGH, buffer, length, buffer, length, out _, IntPtr.Zero); if (validTransfer) { IntPtr offset = Marshal.OffsetOf <Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS>(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf)); IntPtr newPtr = IntPtr.Add(buffer, offset.ToInt32()); data = Marshal.PtrToStructure <Kernel32.NVME_HEALTH_INFO_LOG>(newPtr); Marshal.FreeHGlobal(buffer); result = true; } else { Marshal.FreeHGlobal(buffer); } } return(result); }