first commit
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
// Copyright (C) LibreHardwareMonitor and Contributors.
|
||||
// All Rights Reserved.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using LibreHardwareMonitor.Interop;
|
||||
|
||||
namespace LibreHardwareMonitor.Hardware.Storage;
|
||||
|
||||
public class NVMeSmart : IDisposable
|
||||
{
|
||||
private readonly int _driveNumber;
|
||||
private readonly SafeHandle _handle;
|
||||
|
||||
internal NVMeSmart(StorageInfo storageInfo)
|
||||
{
|
||||
_driveNumber = storageInfo.Index;
|
||||
NVMeDrive = null;
|
||||
string name = storageInfo.Name;
|
||||
|
||||
// Test Samsung protocol.
|
||||
if (NVMeDrive == null && name.IndexOf("Samsung", StringComparison.OrdinalIgnoreCase) > -1)
|
||||
{
|
||||
_handle = NVMeSamsung.IdentifyDevice(storageInfo);
|
||||
if (_handle != null)
|
||||
{
|
||||
NVMeDrive = new NVMeSamsung();
|
||||
if (!NVMeDrive.IdentifyController(_handle, out _))
|
||||
{
|
||||
NVMeDrive = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test Intel protocol.
|
||||
if (NVMeDrive == null && name.IndexOf("Intel", StringComparison.OrdinalIgnoreCase) > -1)
|
||||
{
|
||||
_handle = NVMeIntel.IdentifyDevice(storageInfo);
|
||||
if (_handle != null)
|
||||
{
|
||||
NVMeDrive = new NVMeIntel();
|
||||
}
|
||||
}
|
||||
|
||||
// Test Intel raid protocol.
|
||||
if (NVMeDrive == null && name.IndexOf("Intel", StringComparison.OrdinalIgnoreCase) > -1)
|
||||
{
|
||||
_handle = NVMeIntelRst.IdentifyDevice(storageInfo);
|
||||
if (_handle != null)
|
||||
{
|
||||
NVMeDrive = new NVMeIntelRst();
|
||||
}
|
||||
}
|
||||
|
||||
// Test Windows generic driver protocol.
|
||||
if (NVMeDrive == null)
|
||||
{
|
||||
_handle = NVMeWindows.IdentifyDevice(storageInfo);
|
||||
if (_handle != null)
|
||||
{
|
||||
NVMeDrive = new NVMeWindows();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsValid
|
||||
{
|
||||
get
|
||||
{
|
||||
return _handle is { IsInvalid: false };
|
||||
}
|
||||
}
|
||||
|
||||
internal INVMeDrive NVMeDrive { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private static string GetString(byte[] s)
|
||||
{
|
||||
return Encoding.ASCII.GetString(s).Trim('\t', '\n', '\r', ' ', '\0');
|
||||
}
|
||||
|
||||
private static short KelvinToCelsius(ushort k)
|
||||
{
|
||||
return (short)(k > 0 ? k - 273 : short.MinValue);
|
||||
}
|
||||
|
||||
private static short KelvinToCelsius(byte[] k)
|
||||
{
|
||||
return KelvinToCelsius(BitConverter.ToUInt16(k, 0));
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && _handle is { IsClosed: false })
|
||||
{
|
||||
_handle.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public Storage.NVMeInfo GetInfo()
|
||||
{
|
||||
if (_handle?.IsClosed != false)
|
||||
return null;
|
||||
|
||||
bool valid = false;
|
||||
var data = new Kernel32.NVME_IDENTIFY_CONTROLLER_DATA();
|
||||
if (NVMeDrive != null)
|
||||
valid = NVMeDrive.IdentifyController(_handle, out data);
|
||||
|
||||
if (!valid)
|
||||
return null;
|
||||
|
||||
return new NVMeInfo(_driveNumber, data);
|
||||
}
|
||||
|
||||
public Storage.NVMeHealthInfo GetHealthInfo()
|
||||
{
|
||||
if (_handle?.IsClosed != false)
|
||||
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);
|
||||
}
|
||||
|
||||
private class NVMeInfo : Storage.NVMeInfo
|
||||
{
|
||||
public NVMeInfo(int index, Kernel32.NVME_IDENTIFY_CONTROLLER_DATA data)
|
||||
{
|
||||
Index = index;
|
||||
VID = data.VID;
|
||||
SSVID = data.SSVID;
|
||||
Serial = GetString(data.SN);
|
||||
Model = GetString(data.MN);
|
||||
Revision = GetString(data.FR);
|
||||
IEEE = data.IEEE;
|
||||
TotalCapacity = BitConverter.ToUInt64(data.TNVMCAP, 0); // 128bit little endian
|
||||
UnallocatedCapacity = BitConverter.ToUInt64(data.UNVMCAP, 0);
|
||||
ControllerId = data.CNTLID;
|
||||
NumberNamespaces = data.NN;
|
||||
}
|
||||
}
|
||||
|
||||
private class NVMeHealthInfo : Storage.NVMeHealthInfo
|
||||
{
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user