C-program to send Identify-Controller command to an NVMe Storage Drive

Here in this blog, we will learn to send Identify Controller command to an NVMe drive. I have used Ubuntu 16.04 and drivers in there for sending the command. We will also try to interpret some of the basic fields in the data returned by the command.

Identify-controller command gives us following information about an NVMe command:
1.  Model number – it helps us in identifying our NVMe SSD.
2. Submission Queue Entry Size – number of commands that can be queued
3. Completion Queue Entry Size – command completion queue depth
4. Number of Namespace Supported
5.  Number of Power States Supported and etc.

A Namespace is memory partition of the Flash Memory. It gives us various benefits like we can have a separate queue for different namespaces; thus, minimising the use of arbitration over the submission queues. We can set different LBA size for different Namespaces. A drive must support at least one namespace spanning whole drive size.  Sum of the sizes of all the namespaces must be equal to the total drive size.

Power States lets the user control the drive’s IO (input/output) performance and power consumption. If we want better performance we will have to give up on power and vice versa; Power States selection let us do that. That’s enough of NVMe SSDs!

In Ubuntu (or Linux machines) nvme driver helps us in communicating with NVMe Drive. And we will use the same drivers to send the Identify Controller Command. Identify Controller command is one of the two Identify Command supported by all  NVMe drives. Another is Identify-namespace. Identify Controller command gives the controller capabilities and Identify Namespace command gives the namespace capabilities. The Identify data structure is 4096 bytes in size.

You can read this NVMe document for the further information.

Steps involved in getting Identify-controller data.
step1: Open the device file corresponding to your drive in O_RDWR mode.
step2: Allocate a buffer of 4096 bytes.
step3: Prepare the nvme_admin_cmd structure.
step 4: Call the IOCTL with NVME_IOCTL_ADMIN_CMD as magic number.
step 5: Interpret the data in the buffer.

Step 1: Opening the device file in O_RDWR mode.
Everything is a file in Linux even your storage drives and to communicate with it, we must open it in a suitable mode. The name of the device file is passed into the code from the terminal as an argument to the executable.

int fd;
fd = open(argv[1],O_RDWR);
if(fd == 0){
printf(“could not open device file\n”);
return 1;
}else printf(“device file opened successfully\n”);

Step 2: Alocating a buffer of 4096 bytes. We can use char array or we can malloc it.

char data[IDENTIFY_LEN];

Step 3: Prepare the nvme_admin_cmd.
This structure is defined in nvme_ioctl.h and it eases up admin commands sending(admin commands like Identify, Set-Feature and Get-Log). There are few fields in nvme_admin_cmd structure that we need to initialize to prepare the Identify command. Command DWord 10 is one of them it decides which identify data to be returned for identify command i.e data for controller-identify or namespace-identify. So, CWD10 decides the type of identify command.

struct nvme_admin_cmd cmd = {

.opcode = 0x06, /*to identify the command type – 0x06 for identify*/
.nsid = 0, /*since identify-controller command no namespace ID*/
.addr = (int)data, /*buffer address*/
.data_len = IDENTIFY_LEN,/*identify data length in bytes – 0x1000*/
.cdw10 = 1,/*Command DWord 10 decides which identify data to return – 01b for controller and 00b for namespace identify; see the NVMe document*/

};

Step 4: Call the IOCTL.
To launch the command we need to call the IOCTL with NVME_IOCTL_ADMIN_CMD as the magic number. To the IOCTL we also need to pass the nvme_admin_cmd structure object.

ret = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);

if(ret==0) printf(“successful \n”);
else printf(“failed %d\n”,ret);

Below is the complete code to get the controller-identify data and interpret it.

GITHUB Link for downloading the Code.

#include<stdio.h>
#include<stdlib.h>
#include<sys/ioctl.h>
#include<unistd.h>
#include<linux/nvme_ioctl.h>
#include<fcntl.h>
#include<linux/types.h>

#define IDENTIFY_LEN 0x1000

int main(int argc, char* argv[]){
if(argc < 2){
printf(“kindly give the device file name\n”);
return 1;

}
int fd;
fd = open(argv[1],O_RDWR);
if(fd == 0){
printf(“could not open device file\n”);
return 1;
}else printf(“device file opened successfully\n”);

char data[IDENTIFY_LEN];
for(register int i=0; i<IDENTIFY_LEN;data[i++]=0);
struct nvme_admin_cmd cmd = {
.opcode = 0x06, /*to identify the command type – 0x06 for identify*/
.nsid = 0, /*since identify-controller command no namespace ID*/
.addr = (int)data, /*buffer address*/
.data_len = IDENTIFY_LEN,/*identify data length in bytes – 0x1000*/
.cdw10 = 1,/*Command DWord 10 decides which identify data to return – 01b for controller and 00b for namespace identify; see the NVMe document*/

};

int ret;

ret= ioctl(fd,NVME_IOCTL_ADMIN_CMD,&cmd);

if(ret==0) printf(“successful \n”);
else printf(“failed %d\n”,ret);

printf(“IDENTIFY DETAILS\n”);
printf(“Serial Number: “);
for(int i =0; i<20; printf(“%c”,data[(i++)+4]));
printf(“\n”);
printf(“Model Number: “);
for(int i=0; i<40; printf(“%c”,data[(i++)+24]) );
printf(“\n”);
printf(“Firmware Revision: “);
for(int i = 0;i<8; printf(“%c”,data[(i++)+64]));
printf(“\n”);
printf(“Maximum data transfer size 2^(in units of CAP.MPSMIN): %d\n”, (int)data[77] );
printf(“Submission Queue Entry Size 2^:\n”);
printf(“–maximum: %d\t”, (int)(data[512]>>4));
printf(“–required: %d\n”,(int)(data[512]&0x0f));
printf(“Completion Queue Entry Size 2^:\n”);
printf(“–maximum: %d\t”, (int)(data[513]>>4));
printf(“–required: %d\n”,(int)(data[513]&0x0f));
printf(“Number of Namespaces: %d\n”, *( (int* )(data+516)));
if(data[525]&0x1)
printf(“Volatile Write Cache present\n”);

printf(“Number of Power States supported: %d\n”,(int)data[263]);

return 0;
}

Below is the screen-shot of the output for a SAMSUNG and INTEL Drive.

Screenshot from 2017-06-14 19-25-27

Screenshot from 2017-06-19 17-15-10

 

GOOD DAY; GOOD PEOPLE;

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s