See the question and my original answer on StackOverflow

You can use the AdapterUsesPio member from the STORAGE_ADAPTER_DESCRIPTOR structure. Here is a C++ example that demonstrates how to query a disk for it:

#include "stdafx.h"

int main()
{
    wchar_t path[1024];
    wsprintf(path, L"\\\\?\\C:"); // or L"\\\\.\\PhysicalDrive0"

    // note we use 0, not GENERIC_READ to avoid the need for admin rights
    // 0 is ok if you only need to query for characteristics
    HANDLE device = CreateFile(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);
    if (device == INVALID_HANDLE_VALUE)
        return 0;

    STORAGE_PROPERTY_QUERY query = {};
    query.PropertyId = StorageAdapterProperty;
    query.QueryType = PropertyStandardQuery;

    STORAGE_ADAPTER_DESCRIPTOR descriptor = {};

    DWORD read;
    if (!DeviceIoControl(device, IOCTL_STORAGE_QUERY_PROPERTY,
        &query,
        sizeof(query),
        &descriptor,
        sizeof(descriptor),
        &read,
        NULL
        ))
    {
        wprintf(L"DeviceIoControl error: %i\n", GetLastError());
    }
    else
    {
        wprintf(L"AdapterUsesPio: %i\n", descriptor.AdapterUsesPio);
    }

    CloseHandle(device);
    return 0;
}