Share via

How to access UFS_DEVICE_HEALTH_DESCRIPTOR

Ruben 40 Reputation points
2026-04-21T11:53:22.28+00:00

Has anyone a working example of how to access UFS_DEVICE_HEALTH_DESCRIPTOR data https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ufs/ns-ufs-ufs_device_health_descriptor via IOCTL_STORAGE_QUERY_PROPERTY in a similar way like for NVMe controller ? I struggle a bit to get build up the correct request

Windows development | Windows API - Win32
0 comments No comments

Answer accepted by question author

Taki Ly (WICLOUD CORPORATION) 1,500 Reputation points Microsoft External Staff Moderator
2026-04-22T04:18:43.7866667+00:00

Hello @Ruben ,

To get the UFS_DEVICE_HEALTH_DESCRIPTOR, you need to use IOCTL_STORAGE_QUERY_PROPERTY with StorageAdapterProtocolSpecificProperty (or StorageDeviceProtocolSpecificProperty), and carefully set up the STORAGE_PROTOCOL_SPECIFIC_DATA appended to your STORAGE_PROPERTY_QUERY.

For UFS, the key parameters are:

  • ProtocolType = ProtocolTypeUfs
  • DataType = UfsDataTypeDescriptor
  • ProtocolDataRequestValue = UFS_DESC_HEALTH_ID (which is 0x09)

Below is a workaround with C++ example of how to build the request and parse the response. Since this requires direct hardware access, make sure to run the compiled executable as an Administrator on the target device equipped with the UFS storage.

#include <windows.h>
#include <winioctl.h>
#include <ntddstor.h>
#include <ufs.h>
#include <iostream>

int main()
{
    // Replace with your actual physical drive path
    const char* drivePath = "\\\\.\\PhysicalDrive0"; 
    HANDLE hDevice = CreateFileA(
        drivePath,
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        0,
        NULL
    );

    if (hDevice == INVALID_HANDLE_VALUE) {
        std::cerr << "Failed to open device. Error: " << GetLastError() << "\n";
        return 1;
    }

    // Allocate a buffer large enough for the query, the protocol specific data, and the expected output descriptor
    const DWORD BUFFER_SIZE = 1024;
    BYTE buffer[BUFFER_SIZE] = { 0 };

    // 1. Setup the query structure
    PSTORAGE_PROPERTY_QUERY query = (PSTORAGE_PROPERTY_QUERY)buffer;
    query->PropertyId = StorageAdapterProtocolSpecificProperty; 
    query->QueryType = PropertyStandardQuery;

    // 2. Setup the protocol specific data
    PSTORAGE_PROTOCOL_SPECIFIC_DATA protocolData = (PSTORAGE_PROTOCOL_SPECIFIC_DATA)query->AdditionalParameters;
    protocolData->ProtocolType = ProtocolTypeUfs;
    protocolData->DataType = UfsDataTypeDescriptor;
    protocolData->ProtocolDataRequestValue = UFS_DESC_HEALTH_ID; // 0x09
    protocolData->ProtocolDataRequestSubValue = 0;
    protocolData->ProtocolDataOffset = sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA);
    protocolData->ProtocolDataLength = sizeof(UFS_DEVICE_HEALTH_DESCRIPTOR);
    // Calculate the input size (Query header + Protocol specific data header)
    DWORD inputSize = offsetof(STORAGE_PROPERTY_QUERY, AdditionalParameters) + sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA);
    DWORD bytesReturned = 0;

    // 3. Send the request
    BOOL result = DeviceIoControl(
        hDevice,
        IOCTL_STORAGE_QUERY_PROPERTY,
        buffer,
        inputSize,
        buffer,
        BUFFER_SIZE,
        &bytesReturned,
        NULL
    );

    if (!result) {
        DWORD err = GetLastError();
        std::cerr << "DeviceIoControl failed. Error: " << err << "\n";

        if (err == ERROR_NOT_SUPPORTED || err == ERROR_INVALID_FUNCTION) {
            std::cerr << "Note: The driver or device does not support this UFS protocol request (Are you sure it's a UFS drive?).\n";
        }

        CloseHandle(hDevice);
        return 1;
    }

    // 4. Parse the response
    PSTORAGE_PROTOCOL_DATA_DESCRIPTOR desc = (PSTORAGE_PROTOCOL_DATA_DESCRIPTOR)buffer;
    PSTORAGE_PROTOCOL_SPECIFIC_DATA outProtocolData = &desc->ProtocolSpecificData;
    // The actual health descriptor is located at the specified offset
    PUFS_DEVICE_HEALTH_DESCRIPTOR healthData = (PUFS_DEVICE_HEALTH_DESCRIPTOR)((PBYTE)outProtocolData + outProtocolData->ProtocolDataOffset);

    // 5. Print out the Health info
    std::cout << "--- UFS Health Descriptor ---\n";
    std::cout << "Descriptor ID: 0x" << std::hex << (int)healthData->bDescriptorID << std::dec << "\n";
    std::cout << "Pre EOL Info (0x01=Normal, 0x02=Warning, 0x03=Critical): 0x" << std::hex << (int)healthData->bPreEOLInfo << std::dec << "\n";
    std::cout << "Device Life Time Est A (SLC): " << (int)healthData->bDeviceLifeTimeEstA * 10 << "%\n";
    std::cout << "Device Life Time Est B (MLC/TLC): " << (int)healthData->bDeviceLifeTimeEstB * 10 << "%\n";
    CloseHandle(hDevice);
    return 0;
}

If the DeviceIoControl fails, check the returned System Error Codes:

  1. ERROR_NOT_SUPPORTED (50) or ERROR_INVALID_FUNCTION (1): This usually means the request structure is correct, but the underlying storage controller driver doesn't recognize the UFS protocol command. Ensure you are targeting the correct PhysicalDriveX that corresponds to the UFS device, and that the OEM driver supports pass-through.
  2. ERROR_INVALID_PARAMETER (87): This implies the buffer size, offset, or PropertyId was set up incorrectly. Sometimes switching StorageAdapterProtocolSpecificProperty to StorageDeviceProtocolSpecificProperty works depending on how the miniport driver handles the IOCTL.

Hope this helps with your question. If you found my response helpful, you could follow this guide to provide feedback.

Thank you.

Was this answer helpful?


0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.