C-program to Write LBAs of an NVMe Storage Drive

Here we will see how to write LBAs of an NVMe drive. I will be explaining it for Ubuntu 16.04 enviornment. As we are using the NVMe driver of linux.

For writing onto 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 (CDB) 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 Write.
Step3: Prepare the buffer with the data you want to write.

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. (example: sudo ./a.out /dev/nvme0n1)

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 and Step 3: Creating buffer and preparing it with data to be written.
You can fill anything inside the buffer; I would suggest something interpretable and human readable so that you can read it later (with READ CODE; See my Blog) and confirm the  success of the write code. I am filling it with alternate ‘A’ and ‘*’.

unsigned char buffer[SIZE];
for(register int i = 0;i<SIZE;buffer[i++]=(i%2)?’A’:’*’);

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

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

cmd.opcode = 0x01;/*opcode for Writing*/
cmd.addr =(int) buffer;/*address of the buffer from where data to be written will be taken*/
cmd.nsid = 1;/*namespace ID to which we want to write*/
cmd.data_len = SIZE;/*data length we want to write*/
cmd.cdw10 = lba;/*Lower significant Dword of LBA*/
cmd.cdw11 = 0;/*higher significant Dword of LBA; keeping it 0*/
cmd.cdw12 = SECTORS;/*no of blocks (LBAs) we want to write – assuming an LBA to be of 512 bytes long – as is the case most of the times; we are writting 4 LBAs*/
// 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(“IOCTL was successful\n”);
else printf(“IOCTL failed %d\n”,ret);

If successful then our buffer has been successfully written onto the drive. Use the READ CODE (See my Blog ) to confirm the success.

Below is the complete code for Writing LBAs of an NVMe drive.

GITHUB Link for downloading the Code:

NOTE: DO NOT WRITE ON YOUR OPERATING SYSTEM DRIVE – YOU KNOW THE REASON.

#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 /*number of LBAs to be written*/
#define SIZE 512*SECTORS
/*assumig an LBA to be of 512 BYtes long – as is the case most of the times*/
int main(int argc, char* argv[]){

int fd = 0;
unsigned char buffer[SIZE];
for(register int i = 0;i<SIZE;buffer[i++]=(i%2)?’A’:’*’);

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;/*defined in nvme_ioctl.h*/
memset(&cmd,0,sizeof(cmd));/*initializing not-needed fields*/
cmd.opcode = 0x01;/*opcode for Writing*/
cmd.addr =(int) buffer;/*address of the buffer from where data to be written will be taken*/
cmd.nsid = 1;/*namespace ID to which we want to write*/
cmd.data_len = SIZE;/*data length we want to write*/
cmd.cdw10 = lba;/*Lower significant Dword of LBA*/
cmd.cdw11 = 0;/*higher significant Dword of LBA; keeping it 0*/
cmd.cdw12 = SECTORS;/*no of blocks (LBAs) we want to write – assuming an LBA to be of 512 bytes long – as is the case most of the times*/
// cmd.cdw13 = ;
// cmd.cdw14 = ;

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

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

return 0;
}

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