// 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.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

// ReSharper disable InconsistentNaming

namespace LibreHardwareMonitor.Interop;

public class Kernel32
{
    public const int ERROR_SERVICE_ALREADY_RUNNING = unchecked((int)0x80070420);

    public const int ERROR_SERVICE_EXISTS = unchecked((int)0x80070431);

    internal const uint BATTERY_UNKNOWN_CAPACITY = 0xFFFFFFFF;
    internal const uint BATTERY_UNKNOWN_VOLTAGE = 0xFFFFFFFF;
    internal const int BATTERY_UNKNOWN_RATE = unchecked((int)0x80000000);
    internal const uint BATTERY_UNKNOWN_TIME = 0xFFFFFFFF;

    internal const string IntelNVMeMiniPortSignature1 = "NvmeMini";
    internal const string IntelNVMeMiniPortSignature2 = "IntelNvm";

    internal const uint LPTR = 0x0000 | 0x0040;

    internal const int MAX_DRIVE_ATTRIBUTES = 512;
    internal const uint NVME_PASS_THROUGH_SRB_IO_CODE = 0xe0002000;
    internal const byte SMART_LBA_HI = 0xC2;
    internal const byte SMART_LBA_HI_EXCEEDED = 0x2C;
    internal const byte SMART_LBA_MID = 0x4F;
    internal const byte SMART_LBA_MID_EXCEEDED = 0xF4;

    private const string DllName = "kernel32.dll";

    [Flags]
    public enum NVME_CRITICAL_WARNING
    {
        None = 0x00,

        /// <summary>
        /// If set to 1, then the available spare space has fallen below the threshold.
        /// </summary>
        AvailableSpaceLow = 0x01,

        /// <summary>
        /// If set to 1, then a temperature is above an over temperature threshold or below an under temperature threshold.
        /// </summary>
        TemperatureThreshold = 0x02,

        /// <summary>
        /// If set to 1, then the device reliability has been degraded due to significant media related errors or any internal error that degrades device reliability.
        /// </summary>
        ReliabilityDegraded = 0x04,

        /// <summary>
        /// If set to 1, then the media has been placed in read only mode
        /// </summary>
        ReadOnly = 0x08,

        /// <summary>
        /// If set to 1, then the volatile memory backup device has failed. This field is only valid if the controller has a volatile memory backup solution.
        /// </summary>
        VolatileMemoryBackupDeviceFailed = 0x10
    }

    /// <summary>
    /// Create a instance from a struct with zero initialized memory arrays
    /// no need to init every inner array with the correct sizes
    /// </summary>
    /// <typeparam name="T">type of struct that is needed</typeparam>
    /// <returns></returns>
    internal static T CreateStruct<T>()
    {
        int size = Marshal.SizeOf<T>();
        IntPtr ptr = Marshal.AllocHGlobal(size);
        RtlZeroMemory(ptr, size);
        T result = Marshal.PtrToStructure<T>(ptr);
        Marshal.FreeHGlobal(ptr);
        return result;
    }

    internal static SafeFileHandle OpenDevice(string devicePath)
    {
        SafeFileHandle hDevice = CreateFile(devicePath, FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero);
        if (hDevice.IsInvalid || hDevice.IsClosed)
            hDevice = null;

        return hDevice;
    }

    [DllImport(DllName, CharSet = CharSet.Auto, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    internal static extern SafeFileHandle CreateFile
    (
        [MarshalAs(UnmanagedType.LPTStr)] string lpFileName,
        [MarshalAs(UnmanagedType.U4)] FileAccess dwDesiredAccess,
        [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode,
        IntPtr lpSecurityAttributes,
        [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition,
        [MarshalAs(UnmanagedType.U4)] FileAttributes dwFlagsAndAttributes,
        IntPtr hTemplateFile);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool DeviceIoControl
    (
        SafeHandle hDevice,
        DFP dwIoControlCode,
        ref SENDCMDINPARAMS lpInBuffer,
        int nInBufferSize,
        out ATTRIBUTECMDOUTPARAMS lpOutBuffer,
        int nOutBufferSize,
        out uint lpBytesReturned,
        IntPtr lpOverlapped);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool DeviceIoControl
    (
        SafeHandle hDevice,
        DFP dwIoControlCode,
        ref SENDCMDINPARAMS lpInBuffer,
        int nInBufferSize,
        out THRESHOLDCMDOUTPARAMS lpOutBuffer,
        int nOutBufferSize,
        out uint lpBytesReturned,
        IntPtr lpOverlapped);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool DeviceIoControl
    (
        SafeHandle hDevice,
        DFP dwIoControlCode,
        ref SENDCMDINPARAMS lpInBuffer,
        int nInBufferSize,
        out SENDCMDOUTPARAMS lpOutBuffer,
        int nOutBufferSize,
        out uint lpBytesReturned,
        IntPtr lpOverlapped);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool DeviceIoControl
    (
        SafeHandle hDevice,
        DFP dwIoControlCode,
        ref SENDCMDINPARAMS lpInBuffer,
        int nInBufferSize,
        out IDENTIFYCMDOUTPARAMS lpOutBuffer,
        int nOutBufferSize,
        out uint lpBytesReturned,
        IntPtr lpOverlapped);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool DeviceIoControl
    (
        SafeHandle hDevice,
        DFP dwIoControlCode,
        ref SENDCMDINPARAMS lpInBuffer,
        int nInBufferSize,
        out STATUSCMDOUTPARAMS lpOutBuffer,
        int nOutBufferSize,
        out uint lpBytesReturned,
        IntPtr lpOverlapped);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool DeviceIoControl
    (
        SafeHandle hDevice,
        IOCTL dwIoControlCode,
        ref STORAGE_PROPERTY_QUERY lpInBuffer,
        int nInBufferSize,
        out STORAGE_DEVICE_DESCRIPTOR_HEADER lpOutBuffer,
        int nOutBufferSize,
        out uint lpBytesReturned,
        IntPtr lpOverlapped);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool DeviceIoControl
    (
        SafeHandle hDevice,
        IOCTL dwIoControlCode,
        ref STORAGE_PROPERTY_QUERY lpInBuffer,
        int nInBufferSize,
        IntPtr lpOutBuffer,
        uint nOutBufferSize,
        out uint lpBytesReturned,
        IntPtr lpOverlapped);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool DeviceIoControl
    (
        SafeHandle hDevice,
        IOCTL dwIoControlCode,
        IntPtr lpInBuffer,
        int nInBufferSize,
        IntPtr lpOutBuffer,
        int nOutBufferSize,
        out uint lpBytesReturned,
        IntPtr lpOverlapped);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool DeviceIoControl
    (
        SafeHandle hDevice,
        IOCTL dwIoControlCode,
        IntPtr lpInBuffer,
        int nInBufferSize,
        out DISK_PERFORMANCE lpOutBuffer,
        int nOutBufferSize,
        out uint lpBytesReturned,
        IntPtr lpOverlapped);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool DeviceIoControl
    (
        SafeFileHandle hDevice,
        IOCTL dwIoControlCode,
        ref BATTERY_QUERY_INFORMATION lpInBuffer,
        int nInBufferSize,
        ref BATTERY_INFORMATION lpOutBuffer,
        int nOutBufferSize,
        out uint lpBytesReturned,
        IntPtr lpOverlapped);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool DeviceIoControl
    (
        SafeFileHandle hDevice,
        IOCTL dwIoControlCode,
        ref uint lpInBuffer,
        int nInBufferSize,
        ref uint lpOutBuffer,
        int nOutBufferSize,
        out uint lpBytesReturned,
        IntPtr lpOverlapped);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool DeviceIoControl
    (
        SafeFileHandle hDevice,
        IOCTL dwIoControlCode,
        ref BATTERY_WAIT_STATUS lpInBuffer,
        int nInBufferSize,
        ref BATTERY_STATUS lpOutBuffer,
        int nOutBufferSize,
        out uint lpBytesReturned,
        IntPtr lpOverlapped);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool DeviceIoControl
    (
        SafeFileHandle hDevice,
        IOCTL dwIoControlCode,
        ref BATTERY_QUERY_INFORMATION lpInBuffer,
        int nInBufferSize,
        IntPtr lpOutBuffer,
        int nOutBufferSize,
        out uint lpBytesReturned,
        IntPtr lpOverlapped);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool DeviceIoControl
    (
        SafeFileHandle hDevice,
        IOCTL dwIoControlCode,
        ref BATTERY_QUERY_INFORMATION lpInBuffer,
        int nInBufferSize,
        ref uint lpOutBuffer,
        int nOutBufferSize,
        out uint lpBytesReturned,
        IntPtr lpOverlapped);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    internal static extern IntPtr LocalAlloc(uint uFlags, ulong uBytes);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    internal static extern IntPtr LocalFree(IntPtr hMem);

    [DllImport(DllName, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    internal static extern void RtlZeroMemory(IntPtr Destination, int Length);

    [DllImport(DllName, SetLastError = false)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    internal static extern void RtlCopyMemory(IntPtr Destination, IntPtr Source, uint Length);

    [DllImport(DllName, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    internal static extern IntPtr LoadLibrary(string lpFileName);

    [DllImport(DllName, ExactSpelling = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    internal static extern IntPtr GetProcAddress(IntPtr module, string methodName);

    [DllImport(DllName)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool FreeLibrary(IntPtr module);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    internal static extern IntPtr GetCurrentThread();

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    internal static extern ushort GetActiveProcessorGroupCount();

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    internal static extern bool SetThreadGroupAffinity(IntPtr thread, ref GROUP_AFFINITY groupAffinity, out GROUP_AFFINITY previousGroupAffinity);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    internal static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize, MEM flAllocationType, PAGE flProtect);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    internal static extern bool VirtualFree(IntPtr lpAddress, UIntPtr dwSize, MEM dwFreeType);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    internal static extern bool DeviceIoControl
    (
        SafeFileHandle device,
        IOControlCode ioControlCode,
        [MarshalAs(UnmanagedType.AsAny)] [In] object inBuffer,
        uint inBufferSize,
        [MarshalAs(UnmanagedType.AsAny)] [Out] object outBuffer,
        uint nOutBufferSize,
        out uint bytesReturned,
        IntPtr overlapped);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    internal static extern IntPtr CreateFile
    (
        string lpFileName,
        uint dwDesiredAccess,
        FileShare dwShareMode,
        IntPtr lpSecurityAttributes,
        FileMode dwCreationDisposition,
        FileAttributes dwFlagsAndAttributes,
        IntPtr hTemplateFile);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    internal static extern int EnumSystemFirmwareTables(Provider firmwareTableProviderSignature, IntPtr firmwareTableBuffer, int bufferSize);

    [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    internal static extern int GetSystemFirmwareTable(Provider firmwareTableProviderSignature, int firmwareTableID, IntPtr firmwareTableBuffer, int bufferSize);

    [StructLayout(LayoutKind.Sequential, Pack = 4)]
    public struct GROUP_AFFINITY
    {
        public UIntPtr Mask;

        [MarshalAs(UnmanagedType.U2)]
        public ushort Group;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3, ArraySubType = UnmanagedType.U2)]
        public ushort[] Reserved;
    }

    internal enum DFP : uint
    {
        DFP_GET_VERSION = 0x00074080,
        DFP_SEND_DRIVE_COMMAND = 0x0007c084,
        DFP_RECEIVE_DRIVE_DATA = 0x0007c088
    }

    internal enum IOCTL : uint
    {
        IOCTL_SCSI_PASS_THROUGH = 0x04d004,
        IOCTL_SCSI_MINIPORT = 0x04d008,
        IOCTL_SCSI_PASS_THROUGH_DIRECT = 0x04d014,
        IOCTL_SCSI_GET_ADDRESS = 0x41018,
        IOCTL_DISK_PERFORMANCE = 0x70020,
        IOCTL_STORAGE_QUERY_PROPERTY = 0x2D1400,
        IOCTL_BATTERY_QUERY_TAG = 0x294040,
        IOCTL_BATTERY_QUERY_INFORMATION = 0x294044,
        IOCTL_BATTERY_QUERY_STATUS = 0x29404C
    }

    [Flags]
    internal enum BatteryCapabilities : uint
    {
        BATTERY_CAPACITY_RELATIVE = 0x40000000,
        BATTERY_IS_SHORT_TERM = 0x20000000,
        BATTERY_SET_CHARGE_SUPPORTED = 0x00000001,
        BATTERY_SET_DISCHARGE_SUPPORTED = 0x00000002,
        BATTERY_SYSTEM_BATTERY = 0x80000000
    }

    internal enum BATTERY_QUERY_INFORMATION_LEVEL
    {
        BatteryInformation,
        BatteryGranularityInformation,
        BatteryTemperature,
        BatteryEstimatedTime,
        BatteryDeviceName,
        BatteryManufactureDate,
        BatteryManufactureName,
        BatteryUniqueID,
        BatterySerialNumber
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct BATTERY_QUERY_INFORMATION
    {
        public uint BatteryTag;
        public BATTERY_QUERY_INFORMATION_LEVEL InformationLevel;
        public uint AtRate;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct BATTERY_INFORMATION
    {
        public BatteryCapabilities Capabilities;
        public byte Technology;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
        public byte[] Reserved;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
        public char[] Chemistry;

        public uint DesignedCapacity;
        public uint FullChargedCapacity;
        public uint DefaultAlert1;
        public uint DefaultAlert2;
        public uint CriticalBias;
        public uint CycleCount;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct BATTERY_WAIT_STATUS
    {
        public uint BatteryTag;
        public uint Timeout;
        public uint PowerState;
        public uint LowCapacity;
        public uint HighCapacity;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct BATTERY_STATUS
    {
        public uint PowerState;
        public uint Capacity;
        public uint Voltage;
        public int Rate;
    }

    [Flags]
    internal enum NVME_DIRECTION : uint
    {
        NVME_FROM_HOST_TO_DEV = 1,
        NVME_FROM_DEV_TO_HOST = 2,
        NVME_BI_DIRECTION = NVME_FROM_DEV_TO_HOST | NVME_FROM_HOST_TO_DEV
    }

    internal enum NVME_LOG_PAGES
    {
        NVME_LOG_PAGE_ERROR_INFO = 0x01,
        NVME_LOG_PAGE_HEALTH_INFO = 0x02,
        NVME_LOG_PAGE_FIRMWARE_SLOT_INFO = 0x03,
        NVME_LOG_PAGE_CHANGED_NAMESPACE_LIST = 0x04,
        NVME_LOG_PAGE_COMMAND_EFFECTS = 0x05,
        NVME_LOG_PAGE_DEVICE_SELF_TEST = 0x06,
        NVME_LOG_PAGE_TELEMETRY_HOST_INITIATED = 0x07,
        NVME_LOG_PAGE_TELEMETRY_CTLR_INITIATED = 0x08,
        NVME_LOG_PAGE_RESERVATION_NOTIFICATION = 0x80,
        NVME_LOG_PAGE_SANITIZE_STATUS = 0x81
    }

    internal enum ATA_COMMAND : byte
    {
        /// <summary>
        /// SMART data requested.
        /// </summary>
        ATA_SMART = 0xB0,

        /// <summary>
        /// Identify data is requested.
        /// </summary>
        ATA_IDENTIFY_DEVICE = 0xEC
    }

    internal enum SCSI_IOCTL_DATA
    {
        SCSI_IOCTL_DATA_OUT = 0,
        SCSI_IOCTL_DATA_IN = 1,
        SCSI_IOCTL_DATA_UNSPECIFIED = 2
    }

    internal enum SMART_FEATURES : byte
    {
        /// <summary>
        /// Read SMART data.
        /// </summary>
        SMART_READ_DATA = 0xD0,

        /// <summary>
        /// Read SMART thresholds.
        /// obsolete
        /// </summary>
        READ_THRESHOLDS = 0xD1,

        /// <summary>
        /// Autosave SMART data.
        /// </summary>
        ENABLE_DISABLE_AUTOSAVE = 0xD2,

        /// <summary>
        /// Save SMART attributes.
        /// </summary>
        SAVE_ATTRIBUTE_VALUES = 0xD3,

        /// <summary>
        /// Set SMART to offline immediately.
        /// </summary>
        EXECUTE_OFFLINE_DIAGS = 0xD4,

        /// <summary>
        /// Read SMART log.
        /// </summary>
        SMART_READ_LOG = 0xD5,

        /// <summary>
        /// Write SMART log.
        /// </summary>
        SMART_WRITE_LOG = 0xD6,

        /// <summary>
        /// Write SMART thresholds.
        /// obsolete
        /// </summary>
        WRITE_THRESHOLDS = 0xD7,

        /// <summary>
        /// Enable SMART.
        /// </summary>
        ENABLE_SMART = 0xD8,

        /// <summary>
        /// Disable SMART.
        /// </summary>
        DISABLE_SMART = 0xD9,

        /// <summary>
        /// Get SMART status.
        /// </summary>
        RETURN_SMART_STATUS = 0xDA,

        /// <summary>
        /// Set SMART to offline automatically.
        /// </summary>
        ENABLE_DISABLE_AUTO_OFFLINE = 0xDB /* obsolete */
    }

    internal enum STORAGE_BUS_TYPE
    {
        BusTypeUnknown = 0x00,
        BusTypeScsi,
        BusTypeAtapi,
        BusTypeAta,
        BusType1394,
        BusTypeSsa,
        BusTypeFibre,
        BusTypeUsb,
        BusTypeRAID,
        BusTypeiScsi,
        BusTypeSas,
        BusTypeSata,
        BusTypeSd,
        BusTypeMmc,
        BusTypeVirtual,
        BusTypeFileBackedVirtual,
        BusTypeSpaces,
        BusTypeNvme,
        BusTypeSCM,
        BusTypeMax,
        BusTypeMaxReserved = 0x7F
    }

    internal enum STORAGE_PROPERTY_ID
    {
        StorageDeviceProperty = 0,
        StorageAdapterProperty,
        StorageDeviceIdProperty,
        StorageDeviceUniqueIdProperty,
        StorageDeviceWriteCacheProperty,
        StorageMiniportProperty,
        StorageAccessAlignmentProperty,
        StorageDeviceSeekPenaltyProperty,
        StorageDeviceTrimProperty,
        StorageDeviceWriteAggregationProperty,
        StorageDeviceDeviceTelemetryProperty,
        StorageDeviceLBProvisioningProperty,
        StorageDevicePowerProperty,
        StorageDeviceCopyOffloadProperty,
        StorageDeviceResiliencyProperty,
        StorageDeviceMediumProductType,
        StorageAdapterRpmbProperty,
        StorageDeviceIoCapabilityProperty = 48,
        StorageAdapterProtocolSpecificProperty,
        StorageDeviceProtocolSpecificProperty,
        StorageAdapterTemperatureProperty,
        StorageDeviceTemperatureProperty,
        StorageAdapterPhysicalTopologyProperty,
        StorageDevicePhysicalTopologyProperty,
        StorageDeviceAttributesProperty,
        StorageDeviceManagementStatus,
        StorageAdapterSerialNumberProperty,
        StorageDeviceLocationProperty
    }

    internal enum STORAGE_PROTOCOL_NVME_DATA_TYPE
    {
        NVMeDataTypeUnknown = 0,
        NVMeDataTypeIdentify,
        NVMeDataTypeLogPage,
        NVMeDataTypeFeature
    }

    internal enum STORAGE_PROTOCOL_NVME_PROTOCOL_DATA_REQUEST_VALUE
    {
        NVMeIdentifyCnsSpecificNamespace = 0,
        NVMeIdentifyCnsController = 1,
        NVMeIdentifyCnsActiveNamespaces = 2
    }

    internal enum STORAGE_PROTOCOL_TYPE
    {
        ProtocolTypeUnknown = 0x00,
        ProtocolTypeScsi,
        ProtocolTypeAta,
        ProtocolTypeNvme,
        ProtocolTypeSd,
        ProtocolTypeProprietary = 0x7E,
        ProtocolTypeMaxReserved = 0x7F
    }

    internal enum STORAGE_QUERY_TYPE
    {
        PropertyStandardQuery = 0,
        PropertyExistsQuery,
        PropertyMaskQuery,
        PropertyQueryMaxDefined
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct MEMORYSTATUSEX
    {
        public uint dwLength;
        public uint dwMemoryLoad;
        public ulong ullTotalPhys;
        public ulong ullAvailPhys;
        public ulong ullTotalPageFile;
        public ulong ullAvailPageFile;
        public ulong ullTotalVirtual;
        public ulong ullAvailVirtual;
        public ulong ullAvailExtendedVirtual;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct SMART_ATTRIBUTE
    {
        public byte Id;
        public short Flags;
        public byte CurrentValue;
        public byte WorstValue;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
        public byte[] RawValue;

        public byte Reserved;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct SMART_THRESHOLD
    {
        public byte Id;
        public byte Threshold;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
        public byte[] Reserved;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    internal struct SENDCMDINPARAMS
    {
        public uint cBufferSize;
        public IDEREGS irDriveRegs;
        public byte bDriveNumber;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
        public byte[] bReserved;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
        public uint[] dwReserved;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
        public byte[] bBuffer;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    internal struct IDEREGS
    {
        public SMART_FEATURES bFeaturesReg;
        public byte bSectorCountReg;
        public byte bSectorNumberReg;
        public byte bCylLowReg;
        public byte bCylHighReg;
        public byte bDriveHeadReg;
        public ATA_COMMAND bCommandReg;
        public byte bReserved;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    internal struct DRIVERSTATUS
    {
        public byte bDriverError;
        public byte bIDEError;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
        public byte[] Reserved;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    internal struct SENDCMDOUTPARAMS
    {
        public uint cBufferSize;
        public DRIVERSTATUS DriverStatus;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
        public byte[] bBuffer;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    internal struct ATTRIBUTECMDOUTPARAMS
    {
        public uint cBufferSize;
        public DRIVERSTATUS DriverStatus;
        public byte Version;
        public byte Reserved;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
        public SMART_ATTRIBUTE[] Attributes;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    internal struct THRESHOLDCMDOUTPARAMS
    {
        public uint cBufferSize;
        public DRIVERSTATUS DriverStatus;
        public byte Version;
        public byte Reserved;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
        public SMART_THRESHOLD[] Thresholds;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    internal struct STATUSCMDOUTPARAMS
    {
        public uint cBufferSize;
        public DRIVERSTATUS DriverStatus;
        public IDEREGS irDriveRegs;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    internal struct IDENTIFY_DATA
    {
        public ushort GeneralConfiguration;
        public ushort NumberOfCylinders;
        public ushort Reserved1;
        public ushort NumberOfHeads;
        public ushort UnformattedBytesPerTrack;
        public ushort UnformattedBytesPerSector;
        public ushort SectorsPerTrack;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
        public ushort[] VendorUnique;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
        public byte[] SerialNumber;

        public ushort BufferType;
        public ushort BufferSectorSize;
        public ushort NumberOfEccBytes;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public byte[] FirmwareRevision;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
        public byte[] ModelNumber;

        public byte MaximumBlockTransfer;
        public byte VendorUnique2;
        public ushort DoubleWordIo;
        public ushort Capabilities;
        public ushort Reserved2;
        public byte VendorUnique3;
        public byte PioCycleTimingMode;
        public byte VendorUnique4;
        public byte DmaCycleTimingMode;
        public ushort TranslationFieldsValid;
        public ushort NumberOfCurrentCylinders;
        public ushort NumberOfCurrentHeads;
        public ushort CurrentSectorsPerTrack;
        public uint CurrentSectorCapacity;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 197)]
        public ushort[] Reserved3;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    internal struct IDENTIFYCMDOUTPARAMS
    {
        public uint cBufferSize;
        public DRIVERSTATUS DriverStatus;
        public IDENTIFY_DATA Identify;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct STORAGE_PROPERTY_QUERY
    {
        public STORAGE_PROPERTY_ID PropertyId;
        public STORAGE_QUERY_TYPE QueryType;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
        public byte[] AdditionalParameters;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct STORAGE_DEVICE_DESCRIPTOR_HEADER
    {
        public uint Version;
        public uint Size;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct STORAGE_DEVICE_DESCRIPTOR
    {
        public uint Version;
        public uint Size;
        public byte DeviceType;
        public byte DeviceTypeModifier;

        [MarshalAs(UnmanagedType.U1)]
        public bool RemovableMedia;

        [MarshalAs(UnmanagedType.U1)]
        public bool CommandQueueing;

        public uint VendorIdOffset;
        public uint ProductIdOffset;
        public uint ProductRevisionOffset;
        public uint SerialNumberOffset;
        public STORAGE_BUS_TYPE BusType;
        public uint RawPropertiesLength;
    }
    
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct DISK_PERFORMANCE
    {
        /// <nodoc />
        public ulong BytesRead;

        /// <nodoc />
        public ulong BytesWritten;

        /// <nodoc />
        public ulong ReadTime;

        /// <nodoc />
        public ulong WriteTime;

        /// <nodoc />
        public ulong IdleTime;

        /// <nodoc />
        public uint ReadCount;

        /// <nodoc />
        public uint WriteCount;

        /// <nodoc />
        public uint QueueDepth;

        /// <nodoc />
        public uint SplitCount;

        /// <nodoc />
        public ulong QueryTime;

        /// <nodoc />
        public int StorageDeviceNumber;

        /// <nodoc />
        public long StorageManagerName0;

        /// <nodoc />
        public long StorageManagerName1;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct SRB_IO_CONTROL
    {
        public uint HeaderLenght;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public byte[] Signature;

        public uint Timeout;
        public uint ControlCode;
        public uint ReturnCode;
        public uint Length;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct NVME_PASS_THROUGH_IOCTL
    {
        public SRB_IO_CONTROL srb;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
        public uint[] VendorSpecific;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        public uint[] NVMeCmd;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
        public uint[] CplEntry;

        public NVME_DIRECTION Direction;
        public uint QueueId;
        public uint DataBufferLen;
        public uint MetaDataLen;
        public uint ReturnBufferLen;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4096)]
        public byte[] DataBuffer;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct SCSI_PASS_THROUGH
    {
        [MarshalAs(UnmanagedType.U2)]
        public ushort Length;

        public byte ScsiStatus;
        public byte PathId;
        public byte TargetId;
        public byte Lun;
        public byte CdbLength;
        public byte SenseInfoLength;
        public byte DataIn;
        public uint DataTransferLength;
        public uint TimeOutValue;
        public IntPtr DataBufferOffset;
        public uint SenseInfoOffset;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        public byte[] Cdb;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct SCSI_PASS_THROUGH_WITH_BUFFERS
    {
        public SCSI_PASS_THROUGH Spt;

        public uint Filler;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
        public byte[] SenseBuf;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4096)]
        public byte[] DataBuf;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct NVME_POWER_STATE_DESC
    {
        /// <summary>
        /// bit 0:15 Maximum  Power (MP) in centiwatts
        /// </summary>
        public ushort MP;

        /// <summary>
        /// bit 16:23
        /// </summary>
        public byte Reserved0;

        /// <summary>
        /// bit 24 Max Power Scale (MPS), bit 25 Non-Operational State (NOPS)
        /// </summary>
        public byte MPS_NOPS;

        /// <summary>
        /// bit 32:63 Entry Latency (ENLAT) in microseconds
        /// </summary>
        public uint ENLAT;

        /// <summary>
        /// bit 64:95 Exit Latency (EXLAT) in microseconds
        /// </summary>
        public uint EXLAT;

        /// <summary>
        /// bit 96:100 Relative Read Throughput (RRT)
        /// </summary>
        public byte RRT;

        /// <summary>
        /// bit 104:108 Relative Read Latency (RRL)
        /// </summary>
        public byte RRL;

        /// <summary>
        /// bit 112:116 Relative Write Throughput (RWT)
        /// </summary>
        public byte RWT;

        /// <summary>
        /// bit 120:124 Relative Write Latency (RWL)
        /// </summary>
        public byte RWL;

        /// <summary>
        /// bit 128:143 Idle Power (IDLP)
        /// </summary>
        public ushort IDLP;

        /// <summary>
        /// bit 150:151 Idle Power Scale (IPS)
        /// </summary>
        public byte IPS;

        /// <summary>
        /// bit 152:159
        /// </summary>
        public byte Reserved7;

        /// <summary>
        /// bit 160:175 Active Power (ACTP)
        /// </summary>
        public ushort ACTP;

        /// <summary>
        /// bit 176:178 Active Power Workload (APW), bit 182:183  Active Power Scale (APS)
        /// </summary>
        public byte APW_APS;

        /// <summary>
        /// bit 184:255.
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)]
        public byte[] Reserved9;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct NVME_IDENTIFY_CONTROLLER_DATA
    {
        /// <summary>
        /// byte 0:1 M - PCI Vendor ID (VID)
        /// </summary>
        public ushort VID;

        /// <summary>
        /// byte 2:3 M - PCI Subsystem Vendor ID (SSVID)
        /// </summary>
        public ushort SSVID;

        /// <summary>
        /// byte 4: 23 M - Serial Number (SN)
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
        public byte[] SN;

        /// <summary>
        /// byte 24:63 M - Model Number (MN)
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
        public byte[] MN;

        /// <summary>
        /// byte 64:71 M - Firmware Revision (FR)
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public byte[] FR;

        /// <summary>
        /// byte 72 M - Recommended Arbitration Burst (RAB)
        /// </summary>
        public byte RAB;

        /// <summary>
        /// byte 73:75 M - IEEE OUI Identifier (IEEE). Controller Vendor code.
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
        public byte[] IEEE;

        /// <summary>
        /// byte 76 O - Controller Multi-Path I/O and Namespace Sharing Capabilities (CMIC)
        /// </summary>
        public byte CMIC;

        /// <summary>
        /// byte 77 M - Maximum Data Transfer Size (MDTS)
        /// </summary>
        public byte MDTS;

        /// <summary>
        /// byte 78:79 M - Controller ID (CNTLID)
        /// </summary>
        public ushort CNTLID;

        /// <summary>
        /// byte 80:83 M - Version (VER)
        /// </summary>
        public uint VER;

        /// <summary>
        /// byte 84:87 M - RTD3 Resume Latency (RTD3R)
        /// </summary>
        public uint RTD3R;

        /// <summary>
        /// byte 88:91 M - RTD3 Entry Latency (RTD3E)
        /// </summary>
        public uint RTD3E;

        /// <summary>
        /// byte 92:95 M - Optional Asynchronous Events Supported (OAES)
        /// </summary>
        public uint OAES;

        /// <summary>
        /// byte 96:239.
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 144)]
        public byte[] Reserved0;

        /// <summary>
        /// byte 240:255.  Refer to the NVMe Management Interface Specification for definition.
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        public byte[] ReservedForManagement;

        /// <summary>
        /// byte 256:257 M - Optional Admin Command Support (OACS)
        /// </summary>
        public ushort OACS;

        /// <summary>
        /// byte 258 M - Abort Command Limit (ACL)
        /// </summary>
        public byte ACL;

        /// <summary>
        /// byte 259 M - Asynchronous Event Request Limit (AERL)
        /// </summary>
        public byte AERL;

        /// <summary>
        /// byte 260 M - Firmware Updates (FRMW)
        /// </summary>
        public byte FRMW;

        /// <summary>
        /// byte 261 M - Log Page Attributes (LPA)
        /// </summary>
        public byte LPA;

        /// <summary>
        /// byte 262 M - Error Log Page Entries (ELPE)
        /// </summary>
        public byte ELPE;

        /// <summary>
        /// byte 263 M - Number of Power States Support (NPSS)
        /// </summary>
        public byte NPSS;

        /// <summary>
        /// byte 264 M - Admin Vendor Specific Command Configuration (AVSCC)
        /// </summary>
        public byte AVSCC;

        /// <summary>
        /// byte 265 O - Autonomous Power State Transition Attributes (APSTA)
        /// </summary>
        public byte APSTA;

        /// <summary>
        /// byte 266:267 M - Warning Composite Temperature Threshold (WCTEMP)
        /// </summary>
        public ushort WCTEMP;

        /// <summary>
        /// byte 268:269 M - Critical Composite Temperature Threshold (CCTEMP)
        /// </summary>
        public ushort CCTEMP;

        /// <summary>
        /// byte 270:271 O - Maximum Time for Firmware Activation (MTFA)
        /// </summary>
        public ushort MTFA;

        /// <summary>
        /// byte 272:275 O - Host Memory Buffer Preferred Size (HMPRE)
        /// </summary>
        public uint HMPRE;

        /// <summary>
        /// byte 276:279 O - Host Memory Buffer Minimum Size (HMMIN)
        /// </summary>
        public uint HMMIN;

        /// <summary>
        /// byte 280:295 O - Total NVM Capacity (TNVMCAP)
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        public byte[] TNVMCAP;

        /// <summary>
        /// byte 296:311 O - Unallocated NVM Capacity (UNVMCAP)
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        public byte[] UNVMCAP;

        /// <summary>
        /// byte 312:315 O - Replay Protected Memory Block Support (RPMBS)
        /// </summary>
        public uint RPMBS;

        /// <summary>
        /// byte 316:511
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 196)]
        public byte[] Reserved1;

        /// <summary>
        /// byte 512 M - Submission Queue Entry Size (SQES)
        /// </summary>
        public byte SQES;

        /// <summary>
        /// byte 513 M - Completion Queue Entry Size (CQES)
        /// </summary>
        public byte CQES;

        /// <summary>
        /// byte 514:515
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        public byte[] Reserved2;

        /// <summary>
        /// byte 516:519 M - Number of Namespaces (NN)
        /// </summary>
        public uint NN;

        /// <summary>
        /// byte 520:521 M - Optional NVM Command Support (ONCS)
        /// </summary>
        public ushort ONCS;

        /// <summary>
        /// byte 522:523 M - Fused Operation Support (FUSES)
        /// </summary>
        public ushort FUSES;

        /// <summary>
        /// byte 524 M - Format NVM Attributes (FNA)
        /// </summary>
        public byte FNA;

        /// <summary>
        /// byte 525 M - Volatile Write Cache (VWC)
        /// </summary>
        public byte VWC;

        /// <summary>
        /// byte 526:527 M - Atomic Write Unit Normal (AWUN)
        /// </summary>
        public ushort AWUN;

        /// <summary>
        /// byte 528:529 M - Atomic Write Unit Power Fail (AWUPF)
        /// </summary>
        public ushort AWUPF;

        /// <summary>
        /// byte 530 M - NVM Vendor Specific Command Configuration (NVSCC)
        /// </summary>
        public byte NVSCC;

        /// <summary>
        /// byte 531
        /// </summary>
        public byte Reserved3;

        /// <summary>
        /// byte 532:533 O - Atomic Compare and Write Unit (ACWU)
        /// </summary>
        public ushort ACWU;

        /// <summary>
        /// byte 534:535
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        public byte[] Reserved4;

        /// <summary>
        /// byte 536:539 O - SGL Support (SGLS)
        /// </summary>
        public uint SGLS;

        /// <summary>
        /// byte 540:703
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 164)]
        public byte[] Reserved5;

        /// <summary>
        /// byte 704:2047
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1344)]
        public byte[] Reserved6;

        /// <summary>
        /// byte 2048:3071 Power State Descriptors
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
        public NVME_POWER_STATE_DESC[] PDS;

        /// <summary>
        /// byte 3072:4095 Vendor Specific
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]
        public byte[] VS;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct NVME_HEALTH_INFO_LOG
    {
        /// <summary>
        /// This field indicates critical warnings for the state of the  controller.
        /// Each bit corresponds to a critical warning type; multiple bits may be set.
        /// </summary>
        public byte CriticalWarning;

        /// <summary>
        /// Composite Temperature:  Contains the temperature of the overall device (controller and NVM included) in units of Kelvin.
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        public byte[] CompositeTemp;

        /// <summary>
        /// Available Spare:  Contains a normalized percentage (0 to 100%) of the remaining spare capacity available
        /// </summary>
        public byte AvailableSpare;

        /// <summary>
        /// Available Spare Threshold:  When the Available Spare falls below the threshold indicated in this field,
        /// an asynchronous event completion may occur. The value is indicated as a normalized percentage (0 to 100%).
        /// </summary>
        public byte AvailableSpareThreshold;

        /// <summary>
        /// Percentage Used:  Contains a vendor specific estimate of the percentage of NVM subsystem life used based on
        /// the actual usage and the manufacturer’s prediction of NVM life. A value of 100 indicates that the estimated endurance of
        /// the NVM in the NVM subsystem has been consumed, but may not indicate an NVM subsystem failure. The value is allowed to exceed 100.
        /// </summary>
        public byte PercentageUsed;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)]
        public byte[] Reserved1;

        /// <summary>
        /// Data Units Read:  Contains the number of 512 byte data units the host has read from the controller;
        /// this value does not include metadata. This value is reported in thousands
        /// (i.e., a value of 1 corresponds to 1000 units of 512 bytes read) and is rounded up.
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        public byte[] DataUnitRead;

        /// <summary>
        /// Data Units Written:  Contains the number of 512 byte data units the host has written to the controller;
        /// this value does not include metadata. This value is reported in thousands
        /// (i.e., a value of 1 corresponds to 1000 units of 512 bytes written) and is rounded up.
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        public byte[] DataUnitWritten;

        /// <summary>
        /// Host Read Commands:  Contains the number of read commands completed by the controller.
        /// For the NVM command set, this is the number of Compare and Read commands.
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        public byte[] HostReadCommands;

        /// <summary>
        /// Host Write Commands:  Contains the number of write commands completed by the controller.
        /// For the NVM command set, this is the number of Write commands.
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        public byte[] HostWriteCommands;

        /// <summary>
        /// Controller Busy Time:  Contains the amount of time the controller is busy with I/O commands.
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        public byte[] ControllerBusyTime;

        /// <summary>
        /// Power Cycles:  Contains the number of power cycles.
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        public byte[] PowerCycles;

        /// <summary>
        /// Power On Hours:  Contains the number of power-on hours.
        /// This does not include time that the controller was powered and in a low power state condition.
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        public byte[] PowerOnHours;

        /// <summary>
        /// Unsafe Shutdowns:  Contains the number of unsafe shutdowns.
        /// This count is incremented when a shutdown notification is not received prior to loss of power.
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        public byte[] UnsafeShutdowns;

        /// <summary>
        /// Media Errors:  Contains the number of occurrences where the controller detected an unrecoverable data integrity error.
        /// Errors such as uncorrectable ECC, CRC checksum failure, or LBA tag mismatch are included in this field.
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        public byte[] MediaAndDataIntegrityErrors;

        /// <summary>
        /// Number of Error Information Log Entries:  Contains the number of Error Information log entries over the life of the controller
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        public byte[] NumberErrorInformationLogEntries;

        /// <summary>
        /// Warning Composite Temperature Time:  Contains the amount of time in minutes that the controller is operational and the Composite Temperature is greater than or equal to the Warning Composite
        /// Temperature Threshold.
        /// </summary>
        public uint WarningCompositeTemperatureTime;

        /// <summary>
        /// Critical Composite Temperature Time:  Contains the amount of time in minutes that the controller is operational and the Composite Temperature is greater than the Critical Composite Temperature
        /// Threshold.
        /// </summary>
        public uint CriticalCompositeTemperatureTime;

        /// <summary>
        /// Contains the current temperature reported by temperature sensor 1-8.
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public ushort[] TemperatureSensor;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 296)]
        internal byte[] Reserved2;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct STORAGE_PROTOCOL_SPECIFIC_DATA
    {
        public STORAGE_PROTOCOL_TYPE ProtocolType;
        public uint DataType;
        public uint ProtocolDataRequestValue;
        public uint ProtocolDataRequestSubValue;
        public uint ProtocolDataOffset;
        public uint ProtocolDataLength;
        public uint FixedProtocolReturnData;
        public uint ProtocolDataRequestSubValue2;
        public uint ProtocolDataRequestSubValue3;
        public uint Reserved;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct STORAGE_QUERY_BUFFER
    {
        public STORAGE_PROPERTY_ID PropertyId;
        public STORAGE_QUERY_TYPE QueryType;
        public STORAGE_PROTOCOL_SPECIFIC_DATA ProtocolSpecific;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4096)]
        internal byte[] Buffer;
    }

    [Flags]
    internal enum MEM : uint
    {
        MEM_COMMIT = 0x1000,
        MEM_RESERVE = 0x2000,
        MEM_DECOMMIT = 0x4000,
        MEM_RELEASE = 0x8000,
        MEM_RESET = 0x80000,
        MEM_LARGE_PAGES = 0x20000000,
        MEM_PHYSICAL = 0x400000,
        MEM_TOP_DOWN = 0x100000,
        MEM_WRITE_WATCH = 0x200000
    }

    [Flags]
    internal enum PAGE : uint
    {
        PAGE_EXECUTE = 0x10,
        PAGE_EXECUTE_READ = 0x20,
        PAGE_EXECUTE_READWRITE = 0x40,
        PAGE_EXECUTE_WRITECOPY = 0x80,
        PAGE_NOACCESS = 0x01,
        PAGE_READONLY = 0x02,
        PAGE_READWRITE = 0x04,
        PAGE_WRITECOPY = 0x08,
        PAGE_GUARD = 0x100,
        PAGE_NOCACHE = 0x200,
        PAGE_WRITECOMBINE = 0x400
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    internal struct IOControlCode
    {
        /// <summary>
        /// Gets the resulting IO control code.
        /// </summary>
        public uint Code { get; }

        /// <summary>
        /// Initializes a new instance of the <see cref="IOControlCode" /> struct.
        /// </summary>
        /// <param name="deviceType">Type of the device.</param>
        /// <param name="function">The function.</param>
        /// <param name="access">The access.</param>
        public IOControlCode(uint deviceType, uint function, Access access) : this(deviceType, function, Method.Buffered, access)
        { }

        /// <summary>
        /// Initializes a new instance of the <see cref="IOControlCode" /> struct.
        /// </summary>
        /// <param name="deviceType">Type of the device.</param>
        /// <param name="function">The function.</param>
        /// <param name="method">The method.</param>
        /// <param name="access">The access.</param>
        public IOControlCode(uint deviceType, uint function, Method method, Access access)
        {
            Code = (deviceType << 16) | ((uint)access << 14) | (function << 2) | (uint)method;
        }

        public enum Method : uint
        {
            Buffered = 0,
            InDirect = 1,
            OutDirect = 2,
            Neither = 3
        }

        public enum Access : uint
        {
            Any = 0,
            Read = 1,
            Write = 2
        }
    }

    internal enum Provider
    {
        ACPI = (byte)'A' << 24 | (byte)'C' << 16 | (byte)'P' << 8 | (byte)'I',
        FIRM = (byte)'F' << 24 | (byte)'I' << 16 | (byte)'R' << 8 | (byte)'M',
        RSMB = (byte)'R' << 24 | (byte)'S' << 16 | (byte)'M' << 8 | (byte)'B'
    }
}
