기존의 SATA SSD들은 WMI를 이용해서 매우 쉽게 스마트 정보를 얻어올 수 있었는데, NVMe 제품들은 이 방식으로 정보를 얻어올 수가 없었다.


현재는 MSDN에 (https://msdn.microsoft.com/en-us/library/windows/desktop/mt718131(v=vs.85).aspx)

NVMe에서 정보를 얻어오는 방법을 소개하고 있기때문에 참고하면 된다. 



요약하면 DeviceIoControl API와 IoControlCode (IOCTL_STORAGE_QUERY_PROPERTY)를 사용해서 얻어올 수 있다고 한다. ( Windows7의 경우는 핫픽스 업데이트 이후부터 가능, WIndows 8.1, Windows 10)


* nvme.h는 WDK를 설치하면 된다. winioctl.h 필요



핵심은 


STORAGE_PROPERTY_QUERY 구조체에다가 

PropertyId = StorageDeviceProtocolSpecificProperty

QueryType =  PropertyStandardQuery,

로 셋팅하고 


STORAGE_PROTOCOL_SPECIFIC_DATA 포인터를 만들어서 

STORAGE_PROPERTY_QUERY->AdditionalParameters 주소를 가리키게 만든다.


 

그 담 STORAGE_PROPERTY_QUERY 구조체의 값을 설정해준다.


ProtocolType = ProtocolTypeNvme; // 프로토콜 타입은 NVMe

DataType = NVMeDataTypeLogPage; // 데이터 타입은 LogPage

ProtocolDataRequestValue = NVME_LOG_PAGE_HEALTH_INFO; // SMART, Health Information은 02h

ProtocolDataRequestSubValue = 0;

ProtocolDataOffset = sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA); // 40바이트

ProtocolDataLength = sizeof(NVME_HEALTH_INFO_LOG); // 512바이트


그 담 DeviceIoControl API를 호출해주면 output에 SMART 정보가 담겨나온다.

BOOL WINAPI DeviceIoControl(
  _In_        HANDLE       hDevice,
  _In_        DWORD        dwIoControlCode,
  _In_opt_    LPVOID       lpInBuffer,
  _In_        DWORD        nInBufferSize,
  _Out_opt_   LPVOID       lpOutBuffer,
  _In_        DWORD        nOutBufferSize,
  _Out_opt_   LPDWORD      lpBytesReturned,
  _Inout_opt_ LPOVERLAPPED lpOverlapped
);


NVME_HEALTH_INFO_LOG 구조체

//
// Information of log: NVME_LOG_PAGE_HEALTH_INFO. Size: 512 bytes
//
typedef struct {

    struct {
        UCHAR   AvailableSpaceLow   : 1;                    // If set to 1, then the available spare space has fallen below the threshold.
        UCHAR   TemperatureThreshold : 1;                   // If set to 1, then a temperature is above an over temperature threshold or below an under temperature threshold.
        UCHAR   ReliabilityDegraded : 1;                    // 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.
        UCHAR   ReadOnly            : 1;                    // If set to 1, then the media has been placed in read only mode
        UCHAR   VolatileMemoryBackupDeviceFailed    : 1;    // 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.
        UCHAR   Reserved                            : 3;
    } CriticalWarning;    // This field indicates critical warnings for the state of the  controller. Each bit corresponds to a critical warning type; multiple bits may be set.

    UCHAR   Temperature[2];                 // Temperature: Contains the temperature of the overall device (controller and NVM included) in units of Kelvin. If the temperature exceeds the temperature threshold, refer to section 5.12.1.4, then an asynchronous event completion may occur


	UCHAR   AvailableSpare;                 // Available Spare:  Contains a normalized percentage (0 to 100%) of the remaining spare capacity available
    UCHAR   AvailableSpareThreshold;        // 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%).
    UCHAR   PercentageUsed;                 // Percentage Used
    UCHAR   Reserved0[26];

	UCHAR  DataUnitRead[16];;               // 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.  When the LBA size is a value other than 512 bytes, the controller shall convert the amount of data read to 512 byte units. For the NVM command set, logical blocks read as part of Compare and Read operations shall be included in this value
	UCHAR DataUnitWritten[16];            // 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.  When the LBA size is a value other than 512 bytes, the controller shall convert the amount of data written to 512 byte units. For the NVM command set, logical blocks written as part of Write operations shall be included in this value. Write Uncorrectable commands shall not impact this value.
	UCHAR HostReadCommands[16];           // 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. 
	UCHAR HostWrittenCommands[16];         // 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.
    UCHAR   ControllerBusyTime[16];         // Controller Busy Time:  Contains the amount of time the controller is busy with I/O commands. The controller is busy when there is a command outstanding to an I/O Queue (specifically, a command was issued via an I/O Submission Queue Tail doorbell write and the corresponding  completion queue entry  has not been posted yet to the associated I/O Completion Queue). This value is reported in minutes.
    UCHAR   PowerCycle[16];                 // Power Cycles: Contains the number of power cycles.
    UCHAR   PowerOnHours[16];               // 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.
    UCHAR   UnsafeShutdowns[16];            // Unsafe Shutdowns: Contains the number of unsafe shutdowns. This count is incremented when a shutdown notification (CC.SHN) is not received prior to loss of power.
    UCHAR   MediaErrors[16];                // Media Errors:  Contains the number of occurrences where the controller detected an unrecovered data integrity error. Errors such as uncorrectable ECC, CRC checksum failure, or LBA tag mismatch are included in this field.
    UCHAR   ErrorInfoLogEntryCount[16];     // Number of Error Information Log Entries:  Contains the number of Error Information log entries over the life of the controller
    ULONG   WarningCompositeTemperatureTime;     // 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 (WCTEMP) field and less than the Critical Composite Temperature Threshold (CCTEMP) field in the Identify Controller data structure
    ULONG   CriticalCompositeTemperatureTime;    // Critical Composite Temperature Time: Contains the amount of time in minutes that the controller is operational and the Composite Temperature is greater the Critical Composite Temperature Threshold (CCTEMP) field in the Identify Controller data structure
    USHORT  TemperatureSensor1;          // Contains the current temperature reported by temperature sensor 1.
    USHORT  TemperatureSensor2;          // Contains the current temperature reported by temperature sensor 2.
    USHORT  TemperatureSensor3;          // Contains the current temperature reported by temperature sensor 3.
    USHORT  TemperatureSensor4;          // Contains the current temperature reported by temperature sensor 4.
    USHORT  TemperatureSensor5;          // Contains the current temperature reported by temperature sensor 5.
    USHORT  TemperatureSensor6;          // Contains the current temperature reported by temperature sensor 6.
    USHORT  TemperatureSensor7;          // Contains the current temperature reported by temperature sensor 7.
    USHORT  TemperatureSensor8;          // Contains the current temperature reported by temperature sensor 8.
    UCHAR   Reserved1[296];
} NVME_HEALTH_INFO_LOG, *PNVME_HEALTH_INFO_LOG;



bool GetSMART::getSMARTattr(int idx, void* HEALTH_INFO) { HANDLE handle; STORAGE_PROPERTY_QUERY* spq; STORAGE_PROTOCOL_SPECIFIC_DATA* sppd; PSTORAGE_PROTOCOL_DATA_DESCRIPTOR ppdd; PNVME_HEALTH_INFO_LOG Health_Info; DWORD retbufSize; TCHAR path[100], sbuf2[100]; ULONG outputBufferLen = 4096; BYTE* outputBuffer; outputBuffer = new BYTE[outputBufferLen]; spq = new STORAGE_PROPERTY_QUERY[sizeof(STORAGE_PROPERTY_QUERY) + sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA)]; ZeroMemory(outputBuffer, outputBufferLen); sppd = (PSTORAGE_PROTOCOL_SPECIFIC_DATA)spq->AdditionalParameters; sppd->ProtocolType = ProtocolTypeNvme; sppd->DataType = NVMeDataTypeLogPage; sppd->ProtocolDataRequestValue = NVME_LOG_PAGE_HEALTH_INFO; sppd->ProtocolDataRequestSubValue = 0; sppd->ProtocolDataOffset = sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA); // 40바이트 sppd->ProtocolDataLength = sizeof(NVME_HEALTH_INFO_LOG); // 512바이트 sppd->FixedProtocolReturnData = 0; ZeroMemory((sppd->Reserved), sizeof(DWORD) * 3); spq->PropertyId = StorageDeviceProtocolSpecificProperty; spq->QueryType = PropertyStandardQuery; lstrcpyW(path, _T("\\\\.\\PHYSICALDRIVE")); wsprintf(sbuf2, _T("%d"), idx); lstrcat(path, sbuf2); handle = CreateFile(path, GENERIC_READ || GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); if (!handle) { wprintf_s(_T("핸들생성 실패")); return false; } else { if (!DeviceIoControl(handle, IOCTL_STORAGE_QUERY_PROPERTY, spq, sizeof(STORAGE_PROPERTY_QUERY) + sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA), outputBuffer, outputBufferLen, &retbufSize, NULL)) { CloseHandle(handle); return false; } ppdd = (PSTORAGE_PROTOCOL_DATA_DESCRIPTOR)outputBuffer; Health_Info = (PNVME_HEALTH_INFO_LOG)((DWORD)outputBuffer + ppdd->Size); memcpy(HEALTH_INFO, Health_Info, sizeof(NVME_HEALTH_INFO_LOG)); CloseHandle(handle); } delete spq; delete outputBuffer; return true; }

사용은



int main()
{
	GetSMART gs;
	NVME_HEALTH_INFO_LOG Health_Info;
	
	if (gs.getSMARTattr(4,&Health_Info)) { // 4번은 PHYSICALDRIVE4
		/* Power Cycle -> */
		int* PCCount;
		PCCount = (int*)Health_Info.PowerCycle;
		printf("Power Cycle: %d\n", *PCCount);
		/* ---------------- */

		/* Temperature -> Kelvin
		Celsius= Kelvin-273.15  */
		unsigned short* Temperature;
		Temperature = (unsigned short*)Health_Info.Temperature;
		printf("Temperature: %dC\n", (*Temperature - 273));
		/* ---------------- */
	}
	
	
	//gs.test();
    return 0;
}
트림 활성화체크는..
bool GetSMART::TrimEnabled(int idx) {

	HANDLE handle;

	STORAGE_PROPERTY_QUERY spq;
	DEVICE_TRIM_DESCRIPTOR dtd;

	DWORD retbufSize;
	TCHAR path[100], sbuf2[100];
	bool retValue = false;
	spq.PropertyId = StorageDeviceTrimProperty;
	spq.QueryType = PropertyStandardQuery;
	
	//'-- TRIM
	lstrcpyW(path, _T("\\\\.\\PHYSICALDRIVE"));
	wsprintf(sbuf2, _T("%d"), idx);
	lstrcat(path, sbuf2);

	handle = CreateFile(path, GENERIC_READ || GENERIC_WRITE,
		FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);

	if (!handle) {
		wprintf_s(_T("핸들생성 실패"));
		return false;
	}
	else {
		DeviceIoControl(handle, IOCTL_STORAGE_QUERY_PROPERTY, &spq, sizeof(STORAGE_PROPERTY_QUERY), &dtd, sizeof(DEVICE_TRIM_DESCRIPTOR), &retbufSize, NULL);
		wprintf_s(_T("%d"), dtd.Version);
		if (dtd.TrimEnabled == 1) {
			retValue = true;
		}
		else {
			retValue = false;
		}
		CloseHandle(handle);
		return retValue;
	}

}

이런식


NVMe에 대한 더 자세한 세부정보는 http://www.nvmexpress.org/wp-content/uploads/NVM_Express_1_2_1_Gold_20160603.pdf 파일에서 참고하면 된다.




저작자 표시 비영리
신고
  1. 2016.11.18 18:11

    비밀댓글입니다

    • BlogIcon lee하이 2016.11.18 19:48 신고

      안녕하세요. Nvme.h 헤더파일은 제 기억으로 C:\Program Files (x86)\Windows Kits\10\Include 폴더에 있었던 걸로 알고있어요. ^^

    • BlogIcon lee하이 2016.11.18 22:17 신고

      c:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.10586.0\\shared\\nvme.h

  2. hyuk 2016.11.21 09:14 신고

    감사합니다. 그런데 제가 받은 툴킷에는 없는데 혹시 메일로 보내주실수 있으신가요??
    tophyuk@nate.com
    다시한번 감사합니다.

Visual Studio 6.0 버전에서 디버그하는 상황에서 Linking... 멈춤현상이 나타나는 경우


http://www.microsoft.com/ko-kr/download/details.aspx?id=9183 에 접속하시고 Visual Basic 6.0, Visual C++ 6.0 및 Visual Source Safe 6.0d용 서비스 팩 6을  설치하면 됩니다.



설치 지침


다운로드를 시작하기 전에 컴퓨터에 다운로드 디렉터리를 생성한 다음, "지금 다운로드"를 클릭합니다.



"다운로드"를 클릭하여 다운로드를 시작합니다. 소프트웨어 다운로드 대화 상자가 나타나면 "이 프로그램을 디스크에 저장" 옵션을 선택하고 "확인"을 클릭합니다. 그런 다음, 컴퓨터에 생성해 놓은 디렉터리를 선택합니다.



다운로드 디렉터리에서 파일을 실행합니다. 대화 상자가 나타나면 컴퓨터에 생성해 놓은 해당 디렉터리를 다시 선택합니다. EXE 파일의 컨텐트가 이 디렉터리에 열립니다.



다운로드 디렉터리에서 SetupSP6.exe 파일을 실행합니다. 온라인 최종 사용자 사용권 계약(EULA)의 조건에 동의하면, 설치 소프트웨어에서 사용자가 설치한 Visual Basic 6.0, Visual C++ 6.0 및 Visual Source Safe의 해당 파일을 대체하게 됩니다. 



https://www.microsoft.com/ko-KR/download/details.aspx?id=7030


업뎃 후 누적 보안패치도.


Microsoft Visual Basic 6.0 서비스 팩 6 누적 업데이트

언어 선택:


다운로드

Close

공격자가 Microsoft Visual Basic 6.0 서비스 팩 6을 실행 중인 Windows 기반 시스템을 손상시킬 수 있는 보안 문제가 확인되었습니다.

저작자 표시 비영리
신고


MySQL Workbench query 1000개 제한 없애는 방법


mysql workbench에서 select * from aaa라고 적어놓고 사용하면 select * from aaa limit 0,1000 이런식으로 처리됩니다.


해결방법

1. Edit -> Preferences에 들어갑니다.



2. SQL Editor 탭에 들어갑니다.



3. 여기서 SQL Queries 를 누르면 Query Results 부분에 Limit Rows라고 체크되어 있을텐데 이 부분 체크를 해제합니다.



이제 1000개 제한 없이 select 문을 사용할 수 있습니다.


저작자 표시 비영리
신고

Tip. * 연산자 보다 ++ 연산자 순위가 높다.


32비트 운영체제의 경우에 주소가 0x4씩 커지네요.


*p++ = (p가 가진 주소가 0x10인 경우, 0x14로 바뀜) 

(*p)++ = (p가 가진 주소가 0x10인 경우, 0x10에 1이라는 값을 가지는 경우,  주소 0x10의 값이 2로 바뀜)

*(p++) = *p++


int main(int argc, char* argv[])
{
     int
 a=1;
     int
 *p=&a;
     printf("*p:%x p:%x\n",*p,p);
     *p++;
     printf("*p:%x p:%x\n",*p,p);
     *p--;
     (*p)++;
     printf("*p:%x p:%x\n",*p,p);
     (*p)--;
     *(p++);
     printf("*p:%x p:%x\n",*p,p);
     *(p--);
    
     return
 0;
}


결과




신고

+ Recent posts