C-program to Read from an NVMe drive

This blog will explain the method to read LBAs of an NVMe drive. The method will be for Ubuntu 16.04 environment as we are using NVMe drivers defined in there. It is quite easy compared to reading LBAs from an SATA Drive.

To read from an NVMe drive we have to prepare the requisite fields of the nvme_passthru_cmd structure and then call IOCTL for the NVMe device file. The nvme_passthru_cmd is an abstraction of command descriptor block for NVMe IO (input/output) commands.

Steps involved in reading LBAs from an NVMe drive:
Step 1: Open the device file corresponding to your NVMe drive in O_RDWR mode.
Step 2: Create a buffer of the size you want to read.
Step 3: Prepare the nvme_passthru_cmd structure (defined in “nvme_ioctl.h”).
Step 4: Call the IOCTL with the magic number NVME_IOCTL_IO_CMD (defined in “nvme_ioctl.h”).

Step1: Opening the device file.
Here in my code, I am sending the name of the device file from the terminal as an argument. ( sudo ./a.out  /dev/nvme0n1 )

int fd =  0;
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”);

Step2: Creating a buffer.

unsigned char buffer[SIZE];

Step 3: Preparing the nvme_passthru_cmd structure.
There are many fields in this structure but we need, only few, for reading purpose. See the comments in the code below to understand the fields.

struct nvme_passthru_cmd cmd;/*structure defined in nvme_ioctl.h*/
memset(&cmd,0,sizeof(cmd));/*initializing not so needed fields*/

cmd.opcode = 0x02; /*opcode for reading*/
cmd.addr =(int) buffer;/*address of the buffer*/
cmd.nsid = 1;/*namespace ID from where we want to read – default is 1*/
cmd.data_len = SIZE;/*data length to be read*/
cmd.cdw10 = lba;/* Logical Block Address we want to read*/
cmd.cdw11 = 0; /* higher significant double word of LBA*/
cmd.cdw12 = SECTORS;/*number of LBAs we want to read – SECTORS = 4 here*/
// cmd.cdw13 = ;
// cmd.cdw14 = ;

Step 4: Calling the IOCTL
Here we will call the IOCTL of our open device file with the magic number NVME_IOCTL_IO_CMD. We also need to send the address of  the nvme_passthru_cmd object.

int ret;
ret = ioctl(fd, NVME_IOCTL_IO_CMD, &cmd);

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

If successful then we have our data in our buffer.

Below is the complete code for reading LBAs from an NVMe drive: 

GITHUB Link for download the Code:

#include<stdio.h>
#include<stdlib.h>
#include<linux/nvme_ioctl.h>
#include<sys/ioctl.h>
#include<fcntl.h>
#include<time.h>
#include<string.h>

#define SECTORS 4
#define SIZE 512*SECTORS
/*I am assuming LBA size to be 512 bytes which is always the case*/
int main(int argc, char* argv[]){
int fd = 0;/*file descriptor*/

unsigned char buffer[SIZE];/*our data will be stored in here*/

/*initializing the buffer*/
for(register int i = 0;i<SIZE;buffer[i++]=0);

int lba;
printf(“what will be the lba:”);
scanf(“%d”,&lba);

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”);

struct nvme_passthru_cmd cmd;/*structure defined in nvme_ioctl.h*/
memset(&cmd,0,sizeof(cmd));/*initializing not so needed fields*/

cmd.opcode = 0x02; /*opcode for reading*/
cmd.addr =(int) buffer;/*address of the buffer*/
cmd.nsid = 1;/*namespace ID from where we want to read – default is 1*/
cmd.data_len = SIZE;/*data length to be read*/
cmd.cdw10 = lba;/* Logical Block Address we want to read*/
cmd.cdw11 = 0; /* higher significant double word of LBA*/
cmd.cdw12 = SECTORS;/*number of LBAs we want to read – SECTORS = 4 here*/
// cmd.cdw13 = ;
// cmd.cdw14 = ;

int ret;
ret = ioctl(fd,NVME_IOCTL_IO_CMD,&cmd);

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

printf(“buffer after the read\n”);
//for(register int i=0;i<SIZE;printf(“%c”,buffer[i++]));

return 0;
}

TRY THE CODE IF YOU HAVE AN NVME DRIVE; IT DOES NOT DISTURB YOUR FILE SYSTEM, etc.

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