6f302f7abadf158bcd1cebb800accc7c5dadb8ba
[DuneNvme.git] / test / test_nvme.cpp
1 /*******************************************************************************
2  *      test_nvme.cpp   Test of FPGA NVME access over PCIe DMA channels
3  *      T.Barnaby,      Beam Ltd,       2020-03-01
4  *******************************************************************************
5  */
6 /**
7  * @file        test_nvme.cpp
8  * @author      Terry Barnaby <terry.barnaby@beam.ltd.uk>
9  * @date        2020-03-13
10  * @version     0.0.1
11  *
12  * @brief
13  * This is a simple test program that uses the Xilinx xdma Linux driver to access
14  *
15  * @details
16  * This requires an Nvme device on a KCU105 with the DuneNvmeStorageTest bit file running.
17  * The system allows an NVMe situtated on the Xilinx KCU105 to be accessed and experimented with. It implements the following:
18  *  - Configuration of the NVMe PCIe configuration space registers.
19  *  - Accessing the NVMe registers.
20  *  - Configuration of the NVMe's registers.
21  *  - Sending Admin commands to the NVMe via the admin request/completion shared memory queues. This includes configuration commands.
22  *  - Sending of read and write IO commands to the NVMe via IO request/completion shared memory queues.
23  *
24  * There is access to the memory mappend NvmeStorage registers and there is one bi-directional DMA stream used for communication.
25  * The send and receive DMA streams are multiplexed between requests from the host and replies from the Nvme and also
26  * requests from the Nvme and replies from the host.
27  * The packets sent have a 128bit multiplexing stream number headerand are then encapsulated in the Xilinx PCIe DMA IP's headers.
28  *
29  * The program accesses the FPGA system over the hosts PCIe bus using the Beam bfpga Linux driver. This interfaces with the Xilinx PCIe DMA IP.
30  * The program uses a thread to respond to Nvme requests.
31  *
32  * @copyright GNU GPL License
33  * Copyright (c) Beam Ltd, All rights reserved. <br>
34  * This code is free software: you can redistribute it and/or modify
35  * it under the terms of the GNU General Public License as published by
36  * the Free Software Foundation, either version 3 of the License, or
37  * (at your option) any later version.
38  * This program is distributed in the hope that it will be useful,
39  * but WITHOUT ANY WARRANTY; without even the implied warranty of
40  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
41  * GNU General Public License for more details. <br>
42  * You should have received a copy of the GNU General Public License
43  * along with this code. If not, see <https://www.gnu.org/licenses/>.
44  */
45 #define LDEBUG1         0               // High level debug
46
47 #include <NvmeAccess.h>
48 #include <stdio.h>
49 #include <getopt.h>
50
51 #define VERSION         "0.0.1"
52
53 /// Overal program control class
54 class Control : public NvmeAccess {
55 public:
56                         Control();
57                         ~Control();
58
59         int             init();                                 ///< Initialise
60
61         int             test1();                                ///< Run test1
62         int             configureNvme();                        ///< Configure Nvme for operation
63         int             test2();                                ///< Run test2
64         int             test3();                                ///< Run test3
65         int             test4();                                ///< Run test4
66         int             test5();                                ///< Run test5
67         int             test6();                                ///< Run test6
68         int             test7();                                ///< Run test7
69         int             test8();                                ///< Run test8
70         int             test9();                                ///< Run test9
71         int             test10();                               ///< Run test10
72
73         int             test_misc();                            ///< Collection of misc tests
74
75         void            dumpNvmeRegisters();                    ///< Dump the Nvme registers to stdout
76
77 public:
78         // Params
79         Bool            overbose;
80         NvmeAccess      onvmeAccess;
81 };
82
83 Control::Control(){
84         overbose = 0;
85 }
86
87 Control::~Control(){
88 }
89
90 int Control::init(){
91         return NvmeAccess::init();
92 }
93
94 int Control::test1(){
95         BUInt32 data[8];
96
97         printf("Test1: Simple PCIe command register read, write and read.\n");
98
99         printf("Configure PCIe for memory accesses\n");
100         pcieRead(8, 4, 1, data);
101         dl1printf("Commandreg: %8.8x\n", data[0]);
102
103         data[0] |= 6;
104         pcieWrite(10, 4, 1, data);
105
106         pcieRead(8, 4, 1, data);
107         dl1printf("Commandreg: %8.8x\n", data[0]);
108
109         printf("Complete\n");
110
111         return 0;
112 }
113
114 int Control::configureNvme(){
115         int     e;
116         BUInt32 data;
117         BUInt32 cmd0;
118
119         printf("Configure Nvme for operation\n");
120         
121         // Perform reset
122         reset();
123
124 #ifdef ZAP
125         dumpNvmeRegisters();
126         return 0;
127 #endif
128
129 #ifndef ZAP
130         if(UseConfigEngine){    
131                 printf("Start configuration\n");
132                 writeNvmeStorageReg(4, 0x00000002);
133                 usleep(100000);
134                 printf("Waited 100ms: Status: %8.8x\n", readNvmeStorageReg(RegStatus));
135         }
136         else {
137 #ifdef ZAP
138                 // Setup Max payload, hardcoded for Seagate Nvme
139                 pcieRead(8, 4, 1, &data);
140                 printf("CommandReg: %8.8x\n", data);
141                 pcieRead(8, 0x34, 1, &data);
142                 printf("CapReg: %8.8x\n", data);
143                 pcieRead(8, 0x80, 1, &data);
144                 printf("Cap0: %8.8x\n", data);
145                 pcieRead(8, 0x84, 1, &data);
146                 printf("Cap1: %8.8x\n", data);
147                 pcieRead(8, 0x88, 1, &data);
148                 printf("Cap2: %8.8x\n", data);
149                 pcieRead(8, 0x8C, 1, &data);
150                 printf("Cap3: %8.8x\n", data);
151                 pcieRead(8, 0x90, 1, &data);
152                 printf("Cap4: %8.8x\n", data);
153
154                 pcieRead(8, 0x84, 1, &data);
155                 printf("MaxPayloadSizeSupported: %d\n", data & 0x07);
156
157                 // This should set device for 256 byte payloads. It probably does but packets are not received from the Nvme.
158                 //  Perhaps the Xilinx Pcie Gen3 block is dropping them although it is set for 1024 byte max packets.
159                 pcieRead(8, 0x88, 1, &data);
160                 printf("MaxPayloadSize: %8.8x %d\n", data, (data >> 5) & 0x07);
161                 printf("MaxReadSize: %8.8x %d\n", data, (data >> 12) & 0x07);
162                 data = (data & 0xFFFFFF1F) | (1 << 5);
163                 pcieWrite(10, 0x88, 1, &data);
164                 pcieRead(8, 0x88, 1, &data);
165                 printf("MaxPayloadSize: %8.8x %d\n", data, (data >> 5) & 0x07);
166                 //exit(0);
167 #endif
168
169                 // Stop controller
170                 if(e = writeNvmeReg32(0x14, 0x00460000)){
171                         printf("Error: %d\n", e);
172                         return 1;
173                 }
174                 usleep(10000);
175
176                 // Setup Nvme registers
177                 // Disable interrupts
178                 if(e = writeNvmeReg32(0x0C, 0xFFFFFFFF)){
179                         printf("Error: %d\n", e);
180                         return 1;
181                 }
182
183                 // Admin queue lengths
184                 if(e = writeNvmeReg32(0x24, ((oqueueNum - 1) << 16) | (oqueueNum - 1))){
185                         printf("Error: %d\n", e);
186                         return 1;
187                 }
188
189                 if(UseQueueEngine){
190                         // Admin request queue base address
191                         if(e = writeNvmeReg64(0x28, 0x02000000)){
192                                 printf("Error: %d\n", e);
193                                 return 1;
194                         }
195
196                         // Admin reply queue base address
197                         //if(e = writeNvmeReg64(0x30, 0x01100000)){             // Get replies sent directly to host
198                         if(e = writeNvmeReg64(0x30, 0x02100000)){               // Get replies sent via QueueEngine
199                                 printf("Error: %d\n", e);
200                                 return 1;
201                         }
202                 }
203                 else {
204                         // Admin request queue base address
205                         if(e = writeNvmeReg64(0x28, 0x01000000)){
206                                 printf("Error: %d\n", e);
207                                 return 1;
208                         }
209
210                         // Admin reply queue base address
211                         if(e = writeNvmeReg64(0x30, 0x01100000)){
212                                 printf("Error: %d\n", e);
213                                 return 1;
214                         }
215                 }
216
217                 // Start controller
218                 if(e = writeNvmeReg32(0x14, 0x00460001)){
219                         printf("Error: %d\n", e);
220                         return 1;
221                 }
222                 usleep(100000);
223
224                 //dumpNvmeRegisters();
225
226                 cmd0 = ((oqueueNum - 1) << 16);
227
228 #ifdef ZAP
229                 // Test the queue engine
230                 printf("Create/delete IO queue 1 for replies repeatidly\n");
231
232                 if(UseQueueEngine){
233                         for(int c = 0; c < 10; c++){
234                                 printf("Do: %d\n", c);
235
236                                 nvmeRequest(0, 0, 0x05, 0x02110000, cmd0 | 1, 0x00000001);
237                                 sleep(1);
238
239                                 nvmeRequest(0, 0, 0x04, 0x02110000, cmd0 | 1, 0x00000001);
240                                 sleep(1);
241                         }
242                 }
243                 else {
244                         for(int c = 0; c < 10; c++){
245                                 printf("Do: %d\n", c);
246
247                                 nvmeRequest(0, 0, 0x05, 0x00110000, cmd0 | 1, 0x00000001);
248                                 sleep(1);
249
250                                 nvmeRequest(0, 0, 0x04, 0x00110000, cmd0 | 1, 0x00000001);
251                                 sleep(1);
252                         }
253                 }
254                 return 0;
255 #endif
256
257                 if(UseQueueEngine){
258                         // Create an IO queue
259                         if(overbose)
260                                 printf("Create IO queue 1 for replies\n");
261
262                         nvmeRequest(1, 0, 0x05, 0x02110000, cmd0 | 1, 0x00000001);
263
264                         // Create an IO queue
265                         if(overbose)
266                                 printf("Create IO queue 1 for requests\n");
267
268                         nvmeRequest(1, 0, 0x01, 0x02010000, cmd0 | 1, 0x00010001);
269
270                         // Create an IO queue
271                         if(overbose)
272                                 printf("Create IO queue 2 for replies\n");
273
274                         nvmeRequest(1, 0, 0x05, 0x02120000, cmd0 | 2, 0x00000001);
275
276                         // Create an IO queue
277                         if(overbose)
278                                 printf("Create IO queue 1 for requests\n");
279
280                         nvmeRequest(1, 0, 0x01, 0x02020000, cmd0 | 2, 0x00020001);
281                 }
282                 else {
283                         // Create an IO queue
284                         if(overbose)
285                                 printf("Create IO queue 1 for replies\n");
286
287                         nvmeRequest(1, 0, 0x05, 0x01110000, cmd0 | 1, 0x00000001);
288
289                         // Create an IO queue
290                         if(overbose)
291                                 printf("Create IO queue 1 for requests\n");
292
293                         nvmeRequest(1, 0, 0x01, 0x01010000, cmd0 | 1, 0x00010001);
294
295                         // Create an IO queue
296                         if(overbose)
297                                 printf("Create IO queue 2 for replies\n");
298
299                         nvmeRequest(1, 0, 0x05, 0x01120000, cmd0 | 2, 0x00000001);
300
301                         // Create an IO queue
302                         if(overbose)
303                                 printf("Create IO queue 2 for requests\n");
304
305                         nvmeRequest(1, 0, 0x01, 0x01020000, cmd0 | 2, 0x00020001);
306                 }
307         }
308 #endif
309         usleep(100000);
310
311         //dumpNvmeRegisters();
312         
313         return 0;
314 }
315
316 int Control::test2(){
317         int     e;
318         
319         printf("Test2: Configure Nvme\n");
320         if(e = configureNvme())
321                 return e;
322
323         //dumpNvmeRegisters();
324
325         return 0;
326 }
327
328 int Control::test3(){
329         int     e;
330         
331         printf("Test3: Get info from Nvme\n");
332
333         if(e = configureNvme())
334                 return e;
335
336         printf("Get info\n");
337         //nvmeRequest(0, 0, 0x06, 0x01F00000, 0x00000000);              // Namespace info
338         nvmeRequest(0, 0, 0x06, 0x01F00000, 0x00000001);                // Controller info
339         printf("\n");
340         sleep(1);
341
342         return 0;
343 }
344
345 int Control::test4(){
346         int     e;
347         BUInt32 block = 0;
348         BUInt32 numBlocks = 8;
349         
350         printf("Test4: Read blocks\n");
351         //onvmeNum = 2;
352         
353         if(e = configureNvme())
354                 return e;
355
356         printf("Perform block read\n");
357         memset(odataBlockMem, 0x01, sizeof(odataBlockMem));
358
359 #ifdef ZAP
360         // Test read of a single 512 byte block
361         numBlocks = 1;
362         nvmeRequest(1, 1, 0x02, 0x01800000, block, 0x00000000, numBlocks-1);    // Perform read
363
364         printf("DataBlock0:\n");
365         bhd32a(odataBlockMem, numBlocks*512/4);
366         return 0;
367 #endif
368
369         nvmeRequest(1, 1, 0x02, 0x01800000, block, 0x00000000, numBlocks-1);    // Perform read
370
371         printf("DataBlock0:\n");
372         bhd32a(odataBlockMem, numBlocks*512/4);
373
374 #ifndef ZAP     
375         nvmeRequest(1, 1, 0x02, 0x01800000, (block + 1) * 8, 0x00000000, numBlocks-1);  // Perform read
376
377         printf("DataBlock1: Data value: %8.8x\n", (block + 1) * 0x800);
378         bhd32a(odataBlockMem, numBlocks*512/4);
379 #endif
380         
381
382 #ifdef ZAP
383         block = (262144 * 8);
384         printf("Block (512): %u data value: %8.8x\n", block, (block * 512) / 4);
385         nvmeRequest(1, 1, 0x02, 0x01800000, block - 8, 0x00000000, numBlocks-1);        // Perform read
386
387         printf("DataBlocks at: %u\n", block - 1);
388         bhd32a(odataBlockMem, 2*512/4);
389 #endif
390
391 #ifndef ZAP
392         block = (262144 * 8);
393         printf("Block (512): %u data value: %8.8x\n", block, (block * 512) / 4);
394         nvmeRequest(1, 1, 0x02, 0x01800000, block - 1, 0x00000000, numBlocks-1);        // Perform read
395
396         printf("DataBlocks at: %u\n", block - 1);
397         bhd32a(odataBlockMem, 2*512/4);
398 #endif
399
400         return 0;
401 }
402
403 int Control::test5(){
404         int     e;
405         int     a;
406         BUInt32 r;
407         int     numBlocks = 8;
408         
409         printf("Test5: Write blocks\n");
410         
411         if(e = configureNvme())
412                 return e;
413
414         srand(time(0));
415         r = rand();
416         printf("Perform block write with: 0x%2.2x\n", r & 0xFF);
417         for(a = 0; a < 8192; a++)
418                 odataBlockMem[a] = ((r & 0xFF) << 24) + a;
419
420         nvmeRequest(1, 1, 0x01, 0x01800000, 0x00000000, 0x00000000, numBlocks-1);       // Perform write
421
422         return 0;
423 }
424
425 int Control::test6(){
426         int     e;
427         int     a;
428         BUInt32 v;
429         BUInt32 n;
430         BUInt32 t;
431         double  r;
432         double  ts;
433         BUInt   numBlocks = 262144;             // 1 GByte
434         //BUInt numBlocks = 2621440;            // 10 GByte
435
436         //numBlocks = 8;
437         //numBlocks = 2621440;          // 10 GByte
438         
439         printf("Test6: Enable FPGA write blocks\n");
440
441         setNvme(0);
442         if(e = configureNvme())
443                 return e;
444
445         setNvme(1);
446         if(e = configureNvme())
447                 return e;
448
449         setNvme(2);
450
451         //dumpRegs();
452         
453         // Set number of blocks to write
454         writeNvmeStorageReg(RegDataChunkSize, numBlocks);
455         dumpRegs();
456         
457         // Start off NvmeWrite engine
458         printf("\nStart NvmeWrite engine\n");
459         writeNvmeStorageReg(4, 0x00000004);
460
461 #ifndef ZAP     
462         ts = getTime();
463         n = 0;
464         while(n != numBlocks){
465                 n = readNvmeStorageReg(RegWriteNumBlocks);
466                 printf("NvmeWrite: numBlocks: %u\n", n);
467                 usleep(100000);
468         }
469         printf("Time was: %f\n", getTime() - ts);
470 #else
471         sleep(2);
472 #endif
473
474 #ifdef ZAP
475         printf("\nPerform block read\n");
476         memset(odataBlockMem, 0x0, sizeof(odataBlockMem));
477         nvmeRequest(0, 1, 0x02, 0x01800000, 0x0000000, 0x00000000, 7);  // Four blocks
478         usleep(100000);
479
480         printf("DataBlock:\n");
481         bhd32(odataBlockMem, 8*512/4);
482 #endif
483
484
485 #ifdef ZAP
486         // Start off NvmeWrite engine
487         printf("\nStart NvmeWrite engine\n");
488         writeNvmeStorageReg(4, 0x00000000);
489         writeNvmeStorageReg(4, 0x00000004);
490
491 #ifndef ZAP     
492         ts = getTime();
493         n = 0;
494         while(n != numBlocks){
495                 n = readNvmeStorageReg(RegWriteNumBlocks);
496                 printf("NvmeWrite: numBlocks: %u\n", n);
497                 usleep(100000);
498         }
499         printf("Time was: %f\n", getTime() - ts);
500 #else
501         sleep(2);
502 #endif
503
504 #ifndef ZAP
505         printf("\nPerform block read\n");
506         memset(odataBlockMem, 0x0, sizeof(odataBlockMem));
507         nvmeRequest(0, 1, 0x02, 0x01800000, 0x0000000, 0x00000000, 7);  // Four blocks
508         usleep(100000);
509
510         printf("DataBlock:\n");
511         bhd32(odataBlockMem, 8*512/4);
512 #endif
513 #endif
514
515         printf("Stats\n");
516         dumpRegs(0);
517         dumpRegs(1);
518
519         n = readNvmeStorageReg(RegWriteNumBlocks);
520         t = readNvmeStorageReg(RegWriteTime);
521         r = (4096.0 * n / (1e-6 * t));
522         printf("NvmeWrite: rate:      %f MBytes/s\n", r / (1024 * 1024));
523
524         return 0;
525 }
526
527 int Control::test7(){
528         int     e;
529         int     a;
530         BUInt32 v;
531         BUInt32 i;
532         int     n;
533         //BUInt numBlocks = 262144;
534         BUInt   numBlocks = 10000;
535         
536         printf("Test7: Validate 4k blocks\n");
537         
538         if(e = configureNvme())
539                 return e;
540
541         v = 0;
542         for(n = 0; n < numBlocks; n++){
543                 printf("Test Block: %u\n", n);
544                 memset(odataBlockMem, 0x01, sizeof(odataBlockMem));
545                 nvmeRequest(1, 1, 0x02, 0x01800000, n * 8, 0x00000000, 7);      // Perform read
546
547                 for(a = 0; a < 4096 / 4; a++, v++){
548                         if(odataBlockMem[a] != v){
549                                 printf("Error in Block: %u\n", n);
550                                 bhd32a(odataBlockMem, 8*512/4);
551                                 exit(1);
552                         }
553                 }
554         }
555         
556         return 0;
557 }
558
559 int Control::test8(){
560         int     e;
561         BUInt32 block;
562         BUInt   maxBlocks = 32768;
563         BUInt   numBlocks = 262144;             // 1 GByte
564         //BUInt numBlocks = 2621440;            // 10 GByte
565
566         printf("Test8: Trim Nvme\n");
567         
568         if(e = configureNvme())
569                 return e;
570
571         for(block = 0; block < numBlocks; block += (maxBlocks/8)){
572                 nvmeRequest(1, 1, 0x08, 0x00000000, block * 8, 0x00000000, (1 << 25) | maxBlocks-1);    // Perform trim of 32k 512 Byte blocks
573         }
574
575
576         return 0;
577 }
578
579 int Control::test9(){
580         int     e;
581         BUInt32 nvmeNum = onvmeNum;
582         BUInt32 cmd0;
583
584         printf("Test dual Nvme\n");
585         
586         onvmeNum = 0;
587         nvmeNum = onvmeNum;
588
589         // Perform reset
590         reset();
591         
592         onvmeNum = 0;
593         writeNvmeStorageReg(4, 0x80000000);
594
595         onvmeNum = 1;
596         writeNvmeStorageReg(4, 0x88000000);
597
598         onvmeNum = 2;
599         //writeNvmeStorageReg(4, 0x88800000);
600
601         onvmeNum = 0;
602         dumpRegs();
603
604         onvmeNum = 1;
605         dumpRegs();
606
607         onvmeNum = 2;
608         dumpRegs();
609         
610         printf("NvmeRegisters\n");
611         onvmeNum = nvmeNum;
612         dumpNvmeRegisters();
613
614         return 0;
615 }
616
617 int Control::test10(){
618         int     e;
619         int     a;
620         BUInt32 v;
621         BUInt32 n;
622         BUInt32 t;
623         double  r;
624         double  ts;
625         BUInt   numBlocks = 2;                  // 
626         //BUInt numBlocks = 262144;             // 1 GByte
627         //BUInt numBlocks = 2621440;            // 10 GByte
628
629         //numBlocks = 8;
630         //numBlocks = 2621440;          // 10 GByte
631         
632         printf("Test10: Read blocks using NvmeRead functionality\n");
633
634         if(e = configureNvme())
635                 return e;
636
637         //dumpRegs();
638         
639         // Set number of blocks to write
640         writeNvmeStorageReg(RegReadBlock, 0);
641         writeNvmeStorageReg(RegReadNumBlocks, numBlocks);
642         dumpRegs();
643         
644         // Start off NvmeRead engine
645         printf("\nStart NvmeRead engine\n");
646         writeNvmeStorageReg(RegReadControl, 0x00000001);
647
648         sleep(2);
649         dumpRegs();
650
651         return 0;
652 }
653
654
655
656 int Control::test_misc(){
657         BUInt32 address = 0;
658         BUInt32 data[8];
659         BUInt32 data32;
660         BUInt64 data64;
661         BUInt32 a;
662         int     e;
663         int     n;
664
665         printf("Test_misc: Collection of misc tests\n");
666         
667         if(e = configureNvme())
668                 return e;
669
670         printf("Get info\n");
671         nvmeRequest(0, 0, 0x06, 0x01F00000, 0x00000001);
672         sleep(1);
673
674         printf("\nGet namespace list\n");
675         nvmeRequest(0, 0, 0x06, 0x01F00000, 0x00000002);
676         sleep(1);
677
678         printf("\nSet asynchonous feature\n");
679         nvmeRequest(0, 0, 0x09, 0x01F00000, 0x0000000b, 0xFFFFFFFF);
680         sleep(1);
681
682         printf("\nGet asynchonous feature\n");
683         nvmeRequest(0, 0, 0x0A, 0x01F00000, 0x0000000b);
684         sleep(1);
685
686
687         printf("\nGet log page\n");
688         nvmeRequest(0, 0, 0x02, 0x01F00000, 0x00100001, 0x00000000, 0);
689         sleep(1);
690
691         printf("\nGet asynchonous event\n");
692         nvmeRequest(0, 0, 0x0C, 0x00000000, 0x00000000, 0x00000000, 0);
693         sleep(1);
694
695         return 0;
696 }
697
698 void Control::dumpNvmeRegisters(){
699         int     e;
700         BUInt   a;
701         BUInt32 data;
702         
703         printf("Nvme regs\n");
704         for(a = 0; a < 16; a++){
705                 if(e = readNvmeReg32(a * 4, data)){
706                         printf("Read register Error: %d\n", e);
707                         return;
708                 }
709                 printf("Reg: 0x%3.3x 0x%8.8x\n", a * 4, data);
710         }
711 }
712
713
714
715 void usage(void) {
716         fprintf(stderr, "test_nvme: Version: %s\n", VERSION);
717         fprintf(stderr, "Usage: test_nvme [options] <testname>\n");
718         fprintf(stderr, "This program provides the ability perform access tests to an Nvme device on a FPGA development board\n");
719         fprintf(stderr, " -help,-h              - Help on command line parameters\n");
720         fprintf(stderr, " -v                    - Verbose\n");
721         fprintf(stderr, " -l                    - List tests\n");
722         fprintf(stderr, " -n <nvmeNum>          - Operate on: 0: Nvme0, 1: Nvme1, 2: Both Nvme's\n");
723 }
724
725 static struct option options[] = {
726                 { "h",                  0, NULL, 0 },
727                 { "help",               0, NULL, 0 },
728                 { "v",                  0, NULL, 0 },
729                 { "l",                  0, NULL, 0 },
730                 { "n",                  1, NULL, 0 },
731                 { 0,0,0,0 }
732 };
733 int main(int argc, char** argv){
734         int             err;
735         int             optIndex = 0;
736         const char*     s;
737         int             c;
738         Control         control;
739         Bool            listTests = 0;
740         const char*     test = 0;
741
742         while((c = getopt_long_only(argc, argv, "", options, &optIndex)) == 0){
743                 s = options[optIndex].name;
744                 if(!strcmp(s, "help") || !strcmp(s, "h")){
745                         usage();
746                         return 1;
747                 }
748                 else if(!strcmp(s, "v")){
749                         control.overbose = 1;
750                 }
751                 else if(!strcmp(s, "l")){
752                         listTests = 1;
753                 }
754                 else if(!strcmp(s, "n")){
755                         control.setNvme(atoi(optarg));
756                 }
757                 else {
758                         fprintf(stderr, "Error: No option: %s\n", s);
759                         usage();
760                         return 1;
761                 }
762         }
763         
764         if(listTests){
765                 printf("test1: Simple PCIe command register read, write and read.\n");
766                 printf("test2: Configure Nvme\n");
767                 printf("test3: Get info from Nvme\n");
768                 printf("test4: Read block\n");
769                 printf("test5: Write block\n");
770                 printf("test_misc: Collection of misc tests\n");
771         }
772         else {
773                 if((argc - optind) != 1){
774                         fprintf(stderr, "Requires the test name\n");
775                         usage();
776                         return 1;
777                 }
778                 test = argv[optind++];
779
780                 if(err = control.init()){
781                         return err;
782                 }
783
784                 if(!strcmp(test, "test1")){
785                         err = control.test1();
786                 }
787                 else if(!strcmp(test, "test2")){
788                         err = control.test2();
789                 }
790                 else if(!strcmp(test, "test3")){
791                         err = control.test3();
792                 }
793                 else if(!strcmp(test, "test4")){
794                         err = control.test4();
795                 }
796                 else if(!strcmp(test, "test5")){
797                         err = control.test5();
798                 }
799                 else if(!strcmp(test, "test6")){
800                         err = control.test6();
801                 }
802                 else if(!strcmp(test, "test7")){
803                         err = control.test7();
804                 }
805                 else if(!strcmp(test, "test8")){
806                         err = control.test8();
807                 }
808                 else if(!strcmp(test, "test9")){
809                         err = control.test9();
810                 }
811                 else if(!strcmp(test, "test10")){
812                         err = control.test10();
813                 }
814                 else if(!strcmp(test, "test_misc")){
815                         err = control.test_misc();
816                 }
817                 else {
818                         fprintf(stderr, "No such test: %s\n", test);
819                 }
820         }
821
822         return 0;
823 }