Skip to content
Permalink
Browse files

CrystalDiskInfo 8.1.0 Beta2

- Added Intel RST NVMe support
  • Loading branch information
hiyohiyo committed Apr 21, 2019
1 parent 0f9481c commit 902b40829362e002027f14ef637b94aa000e432f
Showing with 275 additions and 4 deletions.
  1. +147 −1 AtaSmart.cpp
  2. +126 −1 AtaSmart.h
  3. +2 −2 stdafx.h
@@ -39,6 +39,7 @@ static const TCHAR *commandTypeString[] =
_T("nj"), // NVMe JMicron
_T("na"), // NVMe ASMedia
_T("nr"), // NVMe Realtek
_T("nt"), // NVMe Intel RST
};

static const TCHAR *ssdVendorString[] =
@@ -140,6 +141,7 @@ DWORD CAtaSmart::UpdateSmartInfo(DWORD i)

if ((m_FlagNVMeStorageQuery && vars[i].CommandType == CMD_TYPE_NVME_STORAGE_QUERY && GetSmartAttributeNVMeStorageQuery(vars[i].PhysicalDriveId, vars[i].ScsiPort, vars[i].ScsiTargetId, &(vars[i])))
|| (vars[i].CommandType == CMD_TYPE_NVME_INTEL && GetSmartAttributeNVMeIntel(vars[i].PhysicalDriveId, vars[i].ScsiPort, vars[i].ScsiTargetId, &(vars[i])))
|| (vars[i].CommandType == CMD_TYPE_NVME_INTEL_RST && GetSmartAttributeNVMeIntelRst(vars[i].PhysicalDriveId, vars[i].ScsiPort, vars[i].ScsiTargetId, &(vars[i])))
|| (vars[i].CommandType == CMD_TYPE_NVME_SAMSUNG && GetSmartAttributeNVMeSamsung(vars[i].PhysicalDriveId, vars[i].ScsiPort, vars[i].ScsiTargetId, &(vars[i])))
|| (vars[i].CommandType == CMD_TYPE_NVME_SAMSUNG && GetSmartAttributeNVMeSamsung951(vars[i].PhysicalDriveId, vars[i].ScsiPort, vars[i].ScsiTargetId, &(vars[i])))
|| (vars[i].CommandType == CMD_TYPE_NVME_JMICRON && GetSmartAttributeNVMeJMicron(vars[i].PhysicalDriveId, vars[i].ScsiPort, vars[i].ScsiTargetId, &(vars[i])))
@@ -3034,7 +3036,7 @@ BOOL CAtaSmart::AddDiskNVMe(INT physicalDriveId, INT scsiPort, INT scsiTargetId,
asi.AlarmTemperature = 0;
asi.IsNVMe = TRUE;

if (commandType >= CMD_TYPE_NVME_JMICRON)
if (commandType == CMD_TYPE_NVME_JMICRON || commandType == CMD_TYPE_NVME_ASMEDIA || commandType == CMD_TYPE_NVME_JMICRON)
{
asi.InterfaceType = INTERFACE_TYPE_USB;
}
@@ -3107,6 +3109,7 @@ BOOL CAtaSmart::AddDiskNVMe(INT physicalDriveId, INT scsiPort, INT scsiTargetId,
if (
(m_FlagNVMeStorageQuery && commandType == CMD_TYPE_NVME_STORAGE_QUERY && GetSmartAttributeNVMeStorageQuery(physicalDriveId, scsiPort, scsiTargetId, &asi))
|| (commandType == CMD_TYPE_NVME_INTEL && GetSmartAttributeNVMeIntel(physicalDriveId, scsiPort, scsiTargetId, &asi))
|| (commandType == CMD_TYPE_NVME_INTEL_RST && GetSmartAttributeNVMeIntelRst(physicalDriveId, scsiPort, scsiTargetId, &asi))
|| (commandType == CMD_TYPE_NVME_SAMSUNG && GetSmartAttributeNVMeSamsung(physicalDriveId, scsiPort, scsiTargetId, &asi))
|| (commandType == CMD_TYPE_NVME_SAMSUNG && GetSmartAttributeNVMeSamsung951(physicalDriveId, scsiPort, scsiTargetId, &asi))
|| (commandType == CMD_TYPE_NVME_JMICRON && GetSmartAttributeNVMeJMicron(physicalDriveId, scsiPort, scsiTargetId, &asi))
@@ -4558,6 +4561,16 @@ BOOL CAtaSmart::GetDiskInfo(INT physicalDriveId, INT scsiPort, INT scsiTargetId,
DebugPrint(debug);
if (AddDiskNVMe(physicalDriveId, scsiPort, scsiTargetId, scsiBus, scsiTargetId, CMD_TYPE_NVME_INTEL, &identify)){return TRUE; }
}

debug.Format(_T("DoIdentifyDeviceNVMeIntelRst"));
DebugPrint(debug);

if (DoIdentifyDeviceNVMeIntelRst(physicalDriveId, scsiPort, scsiTargetId, &identify))
{
debug.Format(_T("AddDiskNVMe - CMD_TYPE_NVME_INTEL_RST"));
DebugPrint(debug);
if (AddDiskNVMe(physicalDriveId, scsiPort, scsiTargetId, scsiBus, scsiTargetId, CMD_TYPE_NVME_INTEL_RST, &identify)) { return TRUE; }
}
}

if(physicalDriveId >= 0)
@@ -6119,6 +6132,139 @@ BOOL CAtaSmart::GetSmartAttributeNVMeIntel(INT physicalDriveId, INT scsiPort, IN
return bRet;
}

/*---------------------------------------------------------------------------*/
// NVMe Intel RST
/*---------------------------------------------------------------------------*/

BOOL CAtaSmart::GetScsiAddress(const TCHAR* Path, BYTE* PortNumber, BYTE* PathId, BYTE* TargetId, BYTE* Lun)
{
HANDLE hDevice = CreateFile(Path,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
nullptr);
DWORD dwReturned;
SCSI_ADDRESS ScsiAddr;
BOOL bRet = DeviceIoControl(hDevice, IOCTL_SCSI_GET_ADDRESS,
nullptr, 0, &ScsiAddr, sizeof(ScsiAddr), &dwReturned, NULL);

CloseHandle(hDevice);

*PortNumber = ScsiAddr.PortNumber;
*PathId = ScsiAddr.PathId;
*TargetId = ScsiAddr.TargetId;
*Lun = ScsiAddr.Lun;

return bRet == TRUE;
}

BOOL CAtaSmart::DoIdentifyDeviceNVMeIntelRst(INT physicalDriveId, INT scsiPort, INT scsiTargetId, IDENTIFY_DEVICE* data)
{
CString path;
path.Format(L"\\\\.\\PhysicalDrive%d", physicalDriveId);

BYTE portNumber, pathId, targetId, lun;
GetScsiAddress(path, &portNumber, &pathId, &targetId, &lun);
CString drive;
drive.Format(L"\\\\.\\Scsi%d:", portNumber);

HANDLE hIoCtrl = CreateFile(drive,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
OPEN_EXISTING, 0, nullptr);

if (hIoCtrl != INVALID_HANDLE_VALUE)
{
INTEL_NVME_PASS_THROUGH NVMeData;
memset(&NVMeData, 0, sizeof(NVMeData));

NVMeData.SRB.HeaderLength = sizeof(SRB_IO_CONTROL);
memcpy(NVMeData.SRB.Signature, "IntelNvm", 8);
NVMeData.SRB.Timeout = 10;
NVMeData.SRB.ControlCode = IOCTL_INTEL_NVME_PASS_THROUGH;
NVMeData.SRB.Length = sizeof(INTEL_NVME_PASS_THROUGH) - sizeof(SRB_IO_CONTROL);

NVMeData.Payload.Version = 1;
NVMeData.Payload.PathId = pathId;
NVMeData.Payload.Cmd.CDW0.Opcode = 0x06; // ADMIN_IDENTIFY
NVMeData.Payload.Cmd.NSID = 0;
NVMeData.Payload.Cmd.u.IDENTIFY.CDW10.CNS = 1;
NVMeData.Payload.ParamBufLen = sizeof(INTEL_NVME_PAYLOAD) + sizeof(SRB_IO_CONTROL); //0xA4;
NVMeData.Payload.ReturnBufferLen = 0x1000;
NVMeData.Payload.CplEntry[0] = 0;

DWORD dummy;
if (DeviceIoControl(hIoCtrl, IOCTL_SCSI_MINIPORT,
&NVMeData,
sizeof(NVMeData),
&NVMeData,
sizeof(NVMeData),
&dummy, nullptr))
{
memcpy_s(data, sizeof(IDENTIFY_DEVICE), NVMeData.DataBuffer, sizeof(IDENTIFY_DEVICE));

return TRUE;
}

CloseHandle(hIoCtrl);
}
return FALSE;
}

BOOL CAtaSmart::GetSmartAttributeNVMeIntelRst(INT physicalDriveId, INT scsiPort, INT scsiTargetId, ATA_SMART_INFO* asi)
{
CString path;
path.Format(L"\\\\.\\PhysicalDrive%d", physicalDriveId);

BYTE portNumber, pathId, targetId, lun;
GetScsiAddress(path, &portNumber, &pathId, &targetId, &lun);
CString drive;
drive.Format(L"\\\\.\\Scsi%d:", portNumber);

HANDLE hIoCtrl = CreateFile(drive,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
OPEN_EXISTING, 0, nullptr);

if (hIoCtrl != INVALID_HANDLE_VALUE)
{
INTEL_NVME_PASS_THROUGH NVMeData;
memset(&NVMeData, 0, sizeof(NVMeData));

NVMeData.SRB.HeaderLength = sizeof(SRB_IO_CONTROL);
memcpy(NVMeData.SRB.Signature, "IntelNvm", 8);
NVMeData.SRB.Timeout = 10;
NVMeData.SRB.ControlCode = IOCTL_INTEL_NVME_PASS_THROUGH;
NVMeData.SRB.Length = sizeof(INTEL_NVME_PASS_THROUGH) - sizeof(SRB_IO_CONTROL);

NVMeData.Payload.Version = 1;
NVMeData.Payload.PathId = pathId;
NVMeData.Payload.Cmd.CDW0.Opcode = 0x02; // ADMIN_GET_LOG_PAGE
NVMeData.Payload.Cmd.NSID = 0xFFFFFFFF; // NVME_NAMESPACE_ALL;
NVMeData.Payload.Cmd.u.GET_LOG_PAGE.CDW10.LID = 2; // = 0x7f0002;
NVMeData.Payload.Cmd.u.GET_LOG_PAGE.CDW10.NUMD = 0x7F;
NVMeData.Payload.ParamBufLen = sizeof(INTEL_NVME_PAYLOAD) + sizeof(SRB_IO_CONTROL); //0xA4;
NVMeData.Payload.ReturnBufferLen = 0x1000;
NVMeData.Payload.CplEntry[0] = 0;

DWORD dummy;
if (DeviceIoControl(hIoCtrl, IOCTL_SCSI_MINIPORT,
&NVMeData,
sizeof(NVMeData),
&NVMeData,
sizeof(NVMeData),
&dummy, nullptr))
{
memcpy_s(&(asi->SmartReadData), 512, NVMeData.DataBuffer, 512);
return TRUE;
}
CloseHandle(hIoCtrl);
}
return FALSE;
}

/*---------------------------------------------------------------------------*/
// NVMe Storage Query
// Reference: http://naraeon.net/en/archives/1338
@@ -109,6 +109,7 @@ class CAtaSmart
CMD_TYPE_NVME_JMICRON,
CMD_TYPE_NVME_ASMEDIA,
CMD_TYPE_NVME_REALTEK,
CMD_TYPE_NVME_INTEL_RST,
CMD_TYPE_DEBUG
};

@@ -1301,9 +1302,129 @@ typedef struct _CSMI_SAS_RAID_CONFIG_BUFFER {
} CSMI_SAS_RAID_CONFIG_BUFFER,
*PCSMI_SAS_RAID_CONFIG_BUFFER;


#pragma pack()

//////////////////////////////////////////////////////////////////
// for Intel RST NVMe
//////////////////////////////////////////////////////////////////
#pragma pack(push, 1)

typedef union
{
struct
{
ULONG Opcode : 8;
ULONG FUSE : 2;
ULONG _Rsvd : 4;
ULONG PSDT : 2;
ULONG CID : 16;
} DUMMYSTRUCTNAME;
ULONG AsDWord;
} NVME_CDW0, * PNVME_CDW0;

// NVMe Command Format
// See NVMe specification 1.3c Section 4.2, Figure 10
typedef union
{
struct
{
ULONG CNS : 2;
ULONG _Rsvd : 30;
} DUMMYSTRUCTNAME;
ULONG AsDWord;
} NVME_IDENTIFY_CDW10, * PNVME_IDENTIFY_CDW10;

// NVMe Specification < 1.3
typedef union
{
struct
{
ULONG LID : 8;
ULONG _Rsvd1 : 8;
ULONG NUMD : 12;
ULONG _Rsvd2 : 4;
} DUMMYSTRUCTNAME;
ULONG AsDWord;
} NVME_GET_LOG_PAGE_CDW10, * PNVME_GET_LOG_PAGE_CDW10;

// NVMe Specification >= 1.3
typedef union
{
struct
{
ULONG LID : 8;
ULONG LSP : 4;
ULONG Reserved0 : 3;
ULONG RAE : 1;
ULONG NUMDL : 16;
} DUMMYSTRUCTNAME;
ULONG AsDWord;
} NVME_GET_LOG_PAGE_CDW10_V13, * PNVME_GET_LOG_PAGE_CDW10_V13;

typedef struct
{
// Common fields for all commands
NVME_CDW0 CDW0;

ULONG NSID;
ULONG _Rsvd[2];
ULONGLONG MPTR;
ULONGLONG PRP1;
ULONGLONG PRP2;

// Command independent fields from CDW10 to CDW15
union
{
// Admin Command: Identify (6)
struct
{
NVME_IDENTIFY_CDW10 CDW10;
ULONG CDW11;
ULONG CDW12;
ULONG CDW13;
ULONG CDW14;
ULONG CDW15;
} IDENTIFY;

// Admin Command: Get Log Page (2)
struct
{
NVME_GET_LOG_PAGE_CDW10 CDW10;
//NVME_GET_LOG_PAGE_CDW10_V13 CDW10;
ULONG CDW11;
ULONG CDW12;
ULONG CDW13;
ULONG CDW14;
ULONG CDW15;
} GET_LOG_PAGE;
} u;
} NVME_CMD, * PNVME_CMD;

typedef struct _INTEL_NVME_PAYLOAD
{
BYTE Version; // 0x001C
BYTE PathId; // 0x001D
BYTE TargetID; // 0x001E
BYTE Lun; // 0x001F
NVME_CMD Cmd; // 0x0020 ~ 0x005F
DWORD CplEntry[4]; // 0x0060 ~ 0x006F
DWORD QueueId; // 0x0070 ~ 0x0073
DWORD ParamBufLen; // 0x0074
DWORD ReturnBufferLen;// 0x0078
BYTE __rsvd2[0x28]; // 0x007C ~ 0xA3
} INTEL_NVME_PAYLOAD, * PINTEL_NVME_PAYLOAD;

typedef struct _INTEL_NVME_PASS_THROUGH
{
SRB_IO_CONTROL SRB; // 0x0000 ~ 0x001B
INTEL_NVME_PAYLOAD Payload;
BYTE DataBuffer[0x1000];
} INTEL_NVME_PASS_THROUGH, * PINTEL_NVME_PASS_THROUGH;
#pragma pack(pop)

#define IOCTL_INTEL_NVME_PASS_THROUGH CTL_CODE(0xf000, 0xA02, METHOD_BUFFERED, FILE_ANY_ACCESS);


public:
DWORD UpdateSmartInfo(DWORD index);
BOOL UpdateIdInfo(DWORD index);
@@ -1562,6 +1683,10 @@ typedef struct _CSMI_SAS_RAID_CONFIG_BUFFER {
BOOL DoIdentifyDeviceNVMeIntel(INT physicalDriveId, INT scsiPort, INT scsiTargetId, IDENTIFY_DEVICE* data);
BOOL GetSmartAttributeNVMeIntel(INT physicalDriveId, INT scsiPort, INT scsiTargetId, ATA_SMART_INFO* asi);

BOOL GetScsiAddress(const TCHAR* Path, BYTE* PortNumber, BYTE* PathId, BYTE* TargetId, BYTE* Lun);
BOOL DoIdentifyDeviceNVMeIntelRst(INT physicalDriveId, INT scsiPort, INT scsiTargetId, IDENTIFY_DEVICE* data);
BOOL GetSmartAttributeNVMeIntelRst(INT physicalDriveId, INT scsiPort, INT scsiTargetId, ATA_SMART_INFO* asi);

BOOL DoIdentifyDeviceNVMeStorageQuery(INT physicalDriveId, INT scsiPort, INT scsiTargetId, IDENTIFY_DEVICE* data);
BOOL GetSmartAttributeNVMeStorageQuery(INT physicalDriveId, INT scsiPort, INT scsiTargetId, ATA_SMART_INFO* asi);

@@ -104,8 +104,8 @@ static void ControlBarCleanUp() {}
#endif
#endif

#define PRODUCT_VERSION _T("8.1.0 Beta1")
#define PRODUCT_RELEASE _T("2019/04/13")
#define PRODUCT_VERSION _T("8.1.0 Beta2")
#define PRODUCT_RELEASE _T("2019/04/21")
#define PRODUCT_COPY_YEAR _T("2008-2019")
#define PRODUCT_COPYRIGHT _T("© 2008-2019 hiyohiyo")
#define PRODUCT_LICENSE _T("The MIT License")

0 comments on commit 902b408

Please sign in to comment.
You can’t perform that action at this time.