Samsung NVMe 명령어 샘플 (C++)

이 글은 코드 샘플만을 담고 있습니다. 자세한 내용은 이 글을 참고해주세요.

#include <windows.h>
#include <Ntddscsi.h>
#include <tchar.h>

const TCHAR* SamsungTestPath = _T("\\\\.\\PhysicalDrive4");

struct SPTWith512Buffer {
    SCSI_PASS_THROUGH Spt;
    unsigned char SenseBuf[24];
    unsigned char DataBuf[512];
};

void SamsungNVMeIdentify(const TCHAR* Path) {
    SPTWith512Buffer sptwb;
    HANDLE hIoCtrl = CreateFile(Path, GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    DWORD dwReturned;
    size_t length;
    BOOL bRet;

    // ---- SENDING PART ---- //
    ZeroMemory(&sptwb, sizeof(SPTWith512Buffer));

    sptwb.Spt.Length = sizeof(SCSI_PASS_THROUGH);
    sptwb.Spt.PathId = 0;
    sptwb.Spt.TargetId = 0;
    sptwb.Spt.Lun = 0;
    sptwb.Spt.SenseInfoLength = 24;
    sptwb.Spt.DataTransferLength = IDENTIFY_BUFFER_SIZE;
    sptwb.Spt.TimeOutValue = 2;
    sptwb.Spt.DataBufferOffset = offsetof(SPTWith512Buffer, DataBuf);
    sptwb.Spt.SenseInfoOffset = offsetof(SPTWith512Buffer, SenseBuf);

    sptwb.Spt.CdbLength = 16;
    sptwb.Spt.Cdb[0] = 0xB5; // SECURITY PROTOCOL IN
    sptwb.Spt.Cdb[1] = 0xFE; // Samsung Protocol
    sptwb.Spt.Cdb[3] = 5;    // Identify
    sptwb.Spt.Cdb[9] = 0x40; // Transfer Length
    sptwb.Spt.DataIn = SCSI_IOCTL_DATA_OUT;
    sptwb.DataBuf[0] = 1;

    length = offsetof(SPTWith512Buffer, DataBuf)
        + sptwb.Spt.DataTransferLength;

    bRet = DeviceIoControl(hIoCtrl, IOCTL_SCSI_PASS_THROUGH,
        &sptwb, length, &sptwb, length, &dwReturned, NULL);

    // ---- RECEIVING PART ---- //
    ZeroMemory(&sptwb, sizeof(SPTWith512Buffer));

    sptwb.Spt.Length = sizeof(SCSI_PASS_THROUGH);
    sptwb.Spt.PathId = 0;
    sptwb.Spt.TargetId = 0;
    sptwb.Spt.Lun = 0;
    sptwb.Spt.SenseInfoLength = 24;
    sptwb.Spt.DataTransferLength = IDENTIFY_BUFFER_SIZE;
    sptwb.Spt.TimeOutValue = 2;
    sptwb.Spt.DataBufferOffset = offsetof(SPTWith512Buffer, DataBuf);
    sptwb.Spt.SenseInfoOffset = offsetof(SPTWith512Buffer, SenseBuf);

    sptwb.Spt.CdbLength = 16;
    sptwb.Spt.Cdb[0] = 0xA2; // SECURITY PROTOCOL IN
    sptwb.Spt.Cdb[1] = 0xFE; // Samsung Protocol
    sptwb.Spt.Cdb[3] = 5;    // Identify
    sptwb.Spt.Cdb[9] = 0x40; // Transfer Length
    sptwb.Spt.DataIn = SCSI_IOCTL_DATA_IN;

    length = offsetof(SPTWith512Buffer, DataBuf)
        + sptwb.Spt.DataTransferLength;

    bRet = DeviceIoControl(hIoCtrl, IOCTL_SCSI_PASS_THROUGH,
        &sptwb, length, &sptwb, length, &dwReturned, NULL);
}

int main() {
    SamsungNVMeIdentify(SamsungTestPath);
}

2 comments on “Samsung NVMe 명령어 샘플 (C++)

  1. So from what I understand from the code sample, the identify command is a security protocol command? I thought that the security protocols were for OPAL compliant devices. Is this unique to this device? NVMe 1.3 spec defines the identify command to be 6, and I thought that this was common to all NVMe devices.

    I have been successful in sending Identify command to NVMe devices, but I am using SCS to NVMe Translation, sending a SCSI Inquiry command.

    Thanks and I look forward to your reply.

    • As you know, SCSI inquiry command result contains only some part of the full NVMe identify information. Model number is not fully copied, serial is in different format(NVMe: original, NVMe-SCSI: EUI64), and many other fields are just omitted. So the article is for those people need real NVMe passthrough.

      Used protocol in this code sample is only for Samsung retail NVMe devices(other vendors and Samsung OEM devices don’t provide this).
      It’s a kind of backdoor that provides NVMe passthrough without any support from OS or driver. I think it’s implemented to keep compatible with their Magician tool on Windows 7 stock NVMe driver. So the protocol doesn’t follow the NVMe standard.

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다