NvmeStreamMux: Improvements.
[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 #include <stdarg.h>
51
52 #define VERSION         "0.0.1"
53
54 /// Overal program control class
55 class Control : public NvmeAccess {
56 public:
57                         Control();
58                         ~Control();
59
60         int             init();                                 ///< Initialise
61         void            setStartBlock(BUInt32 startBlock);      ///< Set the starting block number
62         void            setNumBlocks(BUInt32 numBlocks);        ///< Set the number of blocks to operate on
63         void            setFilename(const char* filename);      ///< Set the file name for read data
64
65         int             nvmeInit();                             ///< Reset and configure Nvme's for operation
66         int             nvmeConfigure();                        ///< Configure single Nvme for operation
67         void            nvmeDataPacket(NvmeRequestPacket& packet);      ///< Called when read data packet receiver
68
69         // Normal test functions
70         int             nvmeProcess();                          ///< Process FPGA datastream writing to Nvme
71         int             nvmeTrim();                             ///< Trim blocks on Nvme
72         int             nvmeWrite();                            ///< Write blocks to Nvme
73         int             nvmeRead();                             ///< Read blocks from Nvme
74
75         // Basic/Raw test functions
76         int             test1();                                ///< Run test1
77         int             test2();                                ///< Run test2
78         int             test3();                                ///< Run test3
79         int             test4();                                ///< Run test4
80         int             test5();                                ///< Run test5
81         int             test6();                                ///< Run test6
82         int             test7();                                ///< Run test7
83         int             test8();                                ///< Run test8
84         int             test9();                                ///< Run test9
85         int             test10();                               ///< Run test10
86         int             test_misc();                            ///< Collection of misc tests
87
88         // Support functions
89         void            uprintf(const char* fmt, ...);          ///< User verbose printf
90         int             validateBlock(BUInt32 blockNum, void* data);    ///< Validate a data block
91         void            dumpDataBlock(void* data, Bool full);   ///< Print out a data blocks contents
92         void            dumpNvmeRegisters();                    ///< Dump the Nvme registers to stdout
93
94 public:
95         // Params
96         Bool            overbose;                               ///< Verbose operation
97         Bool            ovalidate;                              ///< Validate data
98         BUInt32         ostartBlock;                            ///< The starting block number
99         BUInt32         onumBlocks;                             ///< The number of blocks
100         const char*     ofilename;                              ///< Output file name
101         
102         BFifoBytes      ofifo0;                                 ///< Fifo for Nvme0 read data
103         BFifoBytes      ofifo1;                                 ///< Fifo for Nvme1 read data
104         BUInt32         oblockNum;                              ///< The output block number
105         BUInt8          odataBlock[BlockSize];                  ///< Data block's from NVme's
106         BSemaphore      oreadComplete;                          ///< The read process is complete
107 };
108
109 Control::Control() : ofifo0(1024*1024), ofifo1(1024*1024){
110         overbose = 0;
111         ovalidate = 1;
112         ostartBlock = 0;
113         onumBlocks = 1;
114         ofilename = 0;
115         oblockNum = 0;
116 }
117
118 Control::~Control(){
119 }
120
121 int Control::init(){
122         return NvmeAccess::init();
123 }
124
125 void Control::setStartBlock(BUInt32 startBlock){
126         ostartBlock = startBlock;
127 }
128
129 void Control::setNumBlocks(BUInt32 numBlocks){
130         onumBlocks = numBlocks;
131 }
132
133 void Control::setFilename(const char* filename){
134         ofilename = filename;
135 }
136
137 int Control::nvmeInit(){
138         int     e;
139         
140         printf("Initialise Nvme's for operation\n");
141         
142         // Perform reset
143         reset();
144
145         if(!UseFpgaConfigure){
146                 if(onvmeNum == 2){
147                         setNvme(0);
148                         if(e = nvmeConfigure())
149                                 return e;
150
151                         setNvme(1);
152                         if(e = nvmeConfigure())
153                                 return e;
154
155                         setNvme(2);
156                 }
157                 else {
158                         e = nvmeConfigure();
159                 }
160         }
161         
162         return e;
163 }
164
165 int Control::nvmeConfigure(){
166         int     e;
167         BUInt32 data;
168         BUInt32 cmd0;
169
170         uprintf("nvmeConfigure: Configure Nvme %u for operation\n", onvmeNum);
171         
172 #ifdef ZAP
173         dumpNvmeRegisters();
174         return 0;
175 #endif
176
177         if(UseConfigEngine){    
178                 uprintf("Start configuration\n");
179                 writeNvmeStorageReg(4, 0x00000002);
180
181                 data = 2;
182                 while(data & 2){
183                         data = readNvmeStorageReg(8);
184                         usleep(1000);
185                 }
186                 uprintf("Configuration complete: Status: %8.8x\n", readNvmeStorageReg(RegStatus));
187         }
188         else {
189                 data = 0x06;
190                 pcieWrite(10, 4, 1, &data);                     ///< Set PCIe config command for memory accesses
191
192 #ifdef ZAP
193                 // Setup Max payload, hardcoded for Seagate Nvme
194                 pcieRead(8, 4, 1, &data);
195                 printf("CommandReg: %8.8x\n", data);
196                 pcieRead(8, 0x34, 1, &data);
197                 printf("CapReg: %8.8x\n", data);
198                 pcieRead(8, 0x80, 1, &data);
199                 printf("Cap0: %8.8x\n", data);
200                 pcieRead(8, 0x84, 1, &data);
201                 printf("Cap1: %8.8x\n", data);
202                 pcieRead(8, 0x88, 1, &data);
203                 printf("Cap2: %8.8x\n", data);
204                 pcieRead(8, 0x8C, 1, &data);
205                 printf("Cap3: %8.8x\n", data);
206                 pcieRead(8, 0x90, 1, &data);
207                 printf("Cap4: %8.8x\n", data);
208
209                 pcieRead(8, 0x84, 1, &data);
210                 printf("MaxPayloadSizeSupported: %d\n", data & 0x07);
211
212                 // This should set device for 256 byte payloads. It probably does but packets are not received from the Nvme.
213                 //  Perhaps the Xilinx Pcie Gen3 block is dropping them although it is set for 1024 byte max packets.
214                 pcieRead(8, 0x88, 1, &data);
215                 printf("MaxPayloadSize: %8.8x %d\n", data, (data >> 5) & 0x07);
216                 printf("MaxReadSize: %8.8x %d\n", data, (data >> 12) & 0x07);
217                 data = (data & 0xFFFFFF1F) | (1 << 5);
218                 pcieWrite(10, 0x88, 1, &data);
219                 pcieRead(8, 0x88, 1, &data);
220                 printf("MaxPayloadSize: %8.8x %d\n", data, (data >> 5) & 0x07);
221                 //exit(0);
222 #endif
223
224                 // Stop controller
225                 if(e = writeNvmeReg32(0x14, 0x00460000)){
226                         printf("Error: %d\n", e);
227                         return e;
228                 }
229                 usleep(10000);
230
231                 // Setup Nvme registers
232                 // Disable interrupts
233                 if(e = writeNvmeReg32(0x0C, 0xFFFFFFFF)){
234                         return e;
235                 }
236
237                 // Admin queue lengths
238                 if(e = writeNvmeReg32(0x24, ((oqueueNum - 1) << 16) | (oqueueNum - 1))){
239                         return e;
240                 }
241
242                 if(UseQueueEngine){
243                         // Admin request queue base address
244                         if(e = writeNvmeReg64(0x28, 0x02000000)){
245                                 return e;
246                         }
247
248                         // Admin reply queue base address
249                         //if(e = writeNvmeReg64(0x30, 0x01100000)){             // Get replies sent directly to host
250                         if(e = writeNvmeReg64(0x30, 0x02100000)){               // Get replies sent via QueueEngine
251                                 return e;
252                         }
253                 }
254                 else {
255                         // Admin request queue base address
256                         if(e = writeNvmeReg64(0x28, 0x01000000)){
257                                 return e;
258                         }
259
260                         // Admin reply queue base address
261                         if(e = writeNvmeReg64(0x30, 0x01100000)){
262                                 return e;
263                         }
264                 }
265
266                 // Start controller
267                 if(e = writeNvmeReg32(0x14, 0x00460001)){
268                         return e;
269                 }
270                 
271                 // Wait for Nvme to start
272                 usleep(100000);
273
274                 //dumpNvmeRegisters();
275
276                 cmd0 = ((oqueueNum - 1) << 16);
277
278                 if(UseQueueEngine){
279                         // Create an IO queue
280                         uprintf("Create IO queue 1 for replies\n");
281                         nvmeRequest(1, 0, 0x05, 0x02110000, cmd0 | 1, 0x00000001);
282
283                         // Create an IO queue
284                         uprintf("Create IO queue 1 for requests\n");
285                         nvmeRequest(1, 0, 0x01, 0x02010000, cmd0 | 1, 0x00010001);
286
287                         // Create an IO queue
288                         uprintf("Create IO queue 2 for replies\n");
289                         nvmeRequest(1, 0, 0x05, 0x02120000, cmd0 | 2, 0x00000001);
290
291                         // Create an IO queue
292                         uprintf("Create IO queue 2 for requests\n");
293                         nvmeRequest(1, 0, 0x01, 0x02020000, cmd0 | 2, 0x00020001);
294                 }
295                 else {
296                         // Create an IO queue
297                         uprintf("Create IO queue 1 for replies\n");
298                         nvmeRequest(1, 0, 0x05, 0x01110000, cmd0 | 1, 0x00000001);
299
300                         // Create an IO queue
301                         uprintf("Create IO queue 1 for requests\n");
302                         nvmeRequest(1, 0, 0x01, 0x01010000, cmd0 | 1, 0x00010001);
303
304                         // Create an IO queue
305                         uprintf("Create IO queue 2 for replies\n");
306                         nvmeRequest(1, 0, 0x05, 0x01120000, cmd0 | 2, 0x00000001);
307
308                         // Create an IO queue
309                         uprintf("Create IO queue 2 for requests\n");
310                         nvmeRequest(1, 0, 0x01, 0x01020000, cmd0 | 2, 0x00020001);
311                 }
312         }
313
314         // Make sure all is settled
315         usleep(100000);
316
317         //dumpNvmeRegisters();
318         
319         return 0;
320 }
321
322
323
324
325 void Control::nvmeDataPacket(NvmeRequestPacket& packet){
326         //printf("Control::nvmeDataPacket: Address: %x\n", packet.address);
327         //bhd32(packet.data, packet.numWords);
328
329         // This assumes the PcieWrites are in order
330         if(packet.address & 0xF0000000){
331                 // Nvme 1
332                 ofifo1.write(packet.data, packet.numWords * 4);
333         }
334         else {
335                 // Nvme 0
336                 ofifo0.write(packet.data, packet.numWords * 4);
337         }
338
339         // Output data blocks from FIFO's       
340         while((ofifo0.readAvailable() >= BlockSize) && (ofifo1.readAvailable() >= BlockSize)){
341                 ofifo0.read(odataBlock, BlockSize);
342                 if(overbose){
343                         printf("Block: %u\n", oblockNum);
344                         dumpDataBlock(odataBlock, 0);
345                 }
346                 if(ovalidate){
347                         if(validateBlock(oblockNum, odataBlock)){
348                                 printf("Error in block: %u startAddress(0x%8.8x)\n", oblockNum, (oblockNum * BlockSize / 4));
349                                 dumpDataBlock(odataBlock, 1);
350                                 exit(1);
351                         }
352                 }
353                 
354                 oblockNum++;
355
356                 ofifo1.read(odataBlock, BlockSize);
357                 if(overbose){
358                         printf("Block: %u\n", oblockNum);
359                         dumpDataBlock(odataBlock, 0);
360                 }
361                 if(ovalidate){
362                         if(validateBlock(oblockNum, odataBlock)){
363                                 printf("Error in block: %u startAddress(0x%8.8x)\n", oblockNum, (oblockNum * BlockSize / 4));
364                                 dumpDataBlock(odataBlock, 1);
365                                 exit(1);
366                         }
367                 }
368
369                 oblockNum++;
370         }
371         
372         if(oblockNum >= (ostartBlock + onumBlocks))
373                 oreadComplete.set();
374 }
375
376 int Control::nvmeProcess(){
377         int     e;
378         BUInt32 n;
379         BUInt32 t;
380         double  r;
381         double  ts;
382         
383         printf("nvmeProcess: Write FPGA data stream to Nvme devices\n");
384
385         // Initialise Nvme devices
386         if(e = nvmeInit())
387                 return e;
388
389         //dumpRegs();
390         
391         // Set number of blocks to write
392         writeNvmeStorageReg(RegDataChunkStart, ostartBlock);
393         writeNvmeStorageReg(RegDataChunkSize, onumBlocks);
394         //dumpRegs();
395         
396         // Start off NvmeWrite engine
397         uprintf("Start NvmeWrite engine\n");
398         writeNvmeStorageReg(4, 0x00000004);
399
400         ts = getTime();
401         n = 0;
402         while(n != onumBlocks){
403                 n = readNvmeStorageReg(RegWriteNumBlocks);
404                 uprintf("NvmeWrite: numBlocks: %u\n", n);
405                 usleep(100000);
406         }
407
408         printf("Time was: %f\n", getTime() - ts);
409         printf("Stats\n");
410         dumpRegs(0);
411         dumpRegs(1);
412
413         n = readNvmeStorageReg(RegWriteNumBlocks);
414         t = readNvmeStorageReg(RegWriteTime);
415         r = ((double(BlockSize) * n) / (1e-6 * t));
416         printf("NvmeWrite: rate:      %f MBytes/s\n", r / (1024 * 1024));
417
418         return 0;
419 }
420
421 int Control::nvmeRead(){
422         int     e;
423         BUInt32 block = 0;
424         BUInt32 numBlocks = 8;
425         double  r;
426         double  ts;
427         double  te;
428         
429         printf("NvmeRead: nvme: %u startBlock: %u numBlocks: %u\n",onvmeNum, ostartBlock, onumBlocks);
430         
431         if(e = nvmeInit())
432                 return e;
433
434         oblockNum = ostartBlock;
435         memset(odataBlock, 0x0, sizeof(odataBlock));
436
437         if(onvmeNum == 2){
438                 writeNvmeStorageReg(RegReadBlock, ostartBlock / 2);
439                 writeNvmeStorageReg(RegReadNumBlocks, onumBlocks / 2);
440         }
441         else {
442                 writeNvmeStorageReg(RegReadBlock, ostartBlock);
443                 writeNvmeStorageReg(RegReadNumBlocks, onumBlocks);
444         }
445         
446         if(overbose)
447                 dumpRegs();
448         
449         // Start off NvmeRead engine
450         uprintf("Start NvmeRead engine\n");
451         ts = getTime();
452         writeNvmeStorageReg(RegReadControl, 0x00000001);
453
454         if(overbose){
455                 setNvme(0);
456                 dumpRegs();
457                 setNvme(1);
458                 dumpRegs();
459         }
460
461         // Wait for complete
462         oreadComplete.wait();
463         te = getTime();
464         
465         printf("Time: %f\n", te - ts);
466
467         r = ((double(BlockSize) * onumBlocks) / (te - ts));
468         printf("NvmeRead: rate:      %f MBytes/s\n", r / (1024 * 1024));
469         
470         printf("Complete\n"); fflush(stdout);
471
472         return 0;
473 }
474
475 int Control::nvmeWrite(){
476         return 0;
477 }
478
479 int Control::nvmeTrim(){
480         int     e;
481         BUInt32 block;
482         BUInt   trimBlocks = 32768;
483
484         printf("NvmeTrim: nvme: %u startBlock: %u numBlocks: %u\n",onvmeNum, ostartBlock, onumBlocks);
485         
486         if(e = nvmeInit())
487                 return e;
488
489         for(block = 0; block < onumBlocks; block += (trimBlocks/8)){
490                 if(onvmeNum == 2){
491                         setNvme(0);
492                         nvmeRequest(1, 1, 0x08, 0x00000000, block * 8, 0x00000000, (1 << 25) | trimBlocks-1);   // Perform trim of 32k 512 Byte blocks
493                         setNvme(1);
494                         nvmeRequest(1, 1, 0x08, 0x00000000, block * 8, 0x00000000, (1 << 25) | trimBlocks-1);   // Perform trim of 32k 512 Byte blocks
495                 }
496                 else {
497                         nvmeRequest(1, 1, 0x08, 0x00000000, block * 8, 0x00000000, (1 << 25) | trimBlocks-1);   // Perform trim of 32k 512 Byte blocks
498                 }
499         }
500
501         return 0;
502 }
503
504
505 int Control::test1(){
506         BUInt32 data[8];
507
508         printf("Test1: Simple PCIe command register read, write and read.\n");
509
510         printf("Configure PCIe for memory accesses\n");
511         pcieRead(8, 4, 1, data);
512         dl1printf("Commandreg: %8.8x\n", data[0]);
513
514         data[0] |= 6;
515         pcieWrite(10, 4, 1, data);
516
517         pcieRead(8, 4, 1, data);
518         dl1printf("Commandreg: %8.8x\n", data[0]);
519
520         printf("Complete\n");
521
522         return 0;
523 }
524
525 int Control::test2(){
526         int     e;
527         
528         printf("Test2: Configure Nvme\n");
529         if(e = nvmeInit())
530                 return e;
531
532         //dumpNvmeRegisters();
533
534         return 0;
535 }
536
537 int Control::test3(){
538         int     e;
539         
540         printf("Test3: Get info from Nvme\n");
541
542         if(e = nvmeInit())
543                 return e;
544
545         printf("Get info\n");
546         //nvmeRequest(0, 0, 0x06, 0x01F00000, 0x00000000);              // Namespace info
547         nvmeRequest(0, 0, 0x06, 0x01F00000, 0x00000001);                // Controller info
548         printf("\n");
549         sleep(1);
550
551         return 0;
552 }
553
554 int Control::test4(){
555         int     e;
556         BUInt32 block = 0;
557         BUInt32 numBlocks = 8;
558         
559         printf("Test4: Read blocks\n");
560         //onvmeNum = 2;
561         
562         if(e = nvmeInit())
563                 return e;
564
565         printf("Perform block read\n");
566         memset(odataBlockMem, 0x01, sizeof(odataBlockMem));
567
568 #ifdef ZAP
569         // Test read of a single 512 byte block
570         numBlocks = 1;
571         nvmeRequest(1, 1, 0x02, 0x01800000, block, 0x00000000, numBlocks-1);    // Perform read
572
573         printf("DataBlock0:\n");
574         bhd32a(odataBlockMem, numBlocks*512/4);
575         return 0;
576 #endif
577
578         nvmeRequest(1, 1, 0x02, 0x01800000, block, 0x00000000, numBlocks-1);    // Perform read
579
580         printf("DataBlock0:\n");
581         bhd32a(odataBlockMem, numBlocks*512/4);
582
583 #ifndef ZAP     
584         nvmeRequest(1, 1, 0x02, 0x01800000, (block + 1) * 8, 0x00000000, numBlocks-1);  // Perform read
585
586         printf("DataBlock1: Data value: %8.8x\n", (block + 1) * 0x800);
587         bhd32a(odataBlockMem, numBlocks*512/4);
588 #endif
589         
590
591 #ifdef ZAP
592         block = (262144 * 8);
593         printf("Block (512): %u data value: %8.8x\n", block, (block * 512) / 4);
594         nvmeRequest(1, 1, 0x02, 0x01800000, block - 8, 0x00000000, numBlocks-1);        // Perform read
595
596         printf("DataBlocks at: %u\n", block - 1);
597         bhd32a(odataBlockMem, 2*512/4);
598 #endif
599
600 #ifndef ZAP
601         block = (262144 * 8);
602         printf("Block (512): %u data value: %8.8x\n", block, (block * 512) / 4);
603         nvmeRequest(1, 1, 0x02, 0x01800000, block - 1, 0x00000000, numBlocks-1);        // Perform read
604
605         printf("DataBlocks at: %u\n", block - 1);
606         bhd32a(odataBlockMem, 2*512/4);
607 #endif
608
609         return 0;
610 }
611
612 int Control::test5(){
613         int     e;
614         int     a;
615         BUInt32 r;
616         int     numBlocks = 8;
617         
618         printf("Test5: Write blocks\n");
619         
620         if(e = nvmeInit())
621                 return e;
622
623         srand(time(0));
624         r = rand();
625         printf("Perform block write with: 0x%2.2x\n", r & 0xFF);
626         for(a = 0; a < 8192; a++)
627                 odataBlockMem[a] = ((r & 0xFF) << 24) + a;
628
629         nvmeRequest(1, 1, 0x01, 0x01800000, 0x00000000, 0x00000000, numBlocks-1);       // Perform write
630
631         return 0;
632 }
633
634 int Control::test6(){
635         int     e;
636         int     a;
637         BUInt32 v;
638         BUInt32 n;
639         BUInt32 t;
640         double  r;
641         double  ts;
642         BUInt   numBlocks = 262144;             // 1 GByte
643         //BUInt numBlocks = 2621440;            // 10 GByte
644
645         //numBlocks = 8;
646         //numBlocks = 2621440;          // 10 GByte
647         
648         printf("Test6: Enable FPGA write blocks\n");
649
650         setNvme(0);
651         if(e = nvmeInit())
652                 return e;
653
654         setNvme(1);
655         if(e = nvmeInit())
656                 return e;
657
658         setNvme(2);
659
660         //dumpRegs();
661         
662         // Set number of blocks to write
663         writeNvmeStorageReg(RegDataChunkSize, numBlocks);
664         dumpRegs();
665         
666         // Start off NvmeWrite engine
667         printf("\nStart NvmeWrite engine\n");
668         writeNvmeStorageReg(4, 0x00000004);
669
670 #ifndef ZAP     
671         ts = getTime();
672         n = 0;
673         while(n != numBlocks){
674                 n = readNvmeStorageReg(RegWriteNumBlocks);
675                 printf("NvmeWrite: numBlocks: %u\n", n);
676                 usleep(100000);
677         }
678         printf("Time was: %f\n", getTime() - ts);
679 #else
680         sleep(2);
681 #endif
682
683 #ifdef ZAP
684         printf("\nPerform block read\n");
685         memset(odataBlockMem, 0x0, sizeof(odataBlockMem));
686         nvmeRequest(0, 1, 0x02, 0x01800000, 0x0000000, 0x00000000, 7);  // Four blocks
687         usleep(100000);
688
689         printf("DataBlock:\n");
690         bhd32(odataBlockMem, 8*512/4);
691 #endif
692
693
694 #ifdef ZAP
695         // Start off NvmeWrite engine
696         printf("\nStart NvmeWrite engine\n");
697         writeNvmeStorageReg(4, 0x00000000);
698         writeNvmeStorageReg(4, 0x00000004);
699
700 #ifndef ZAP     
701         ts = getTime();
702         n = 0;
703         while(n != numBlocks){
704                 n = readNvmeStorageReg(RegWriteNumBlocks);
705                 printf("NvmeWrite: numBlocks: %u\n", n);
706                 usleep(100000);
707         }
708         printf("Time was: %f\n", getTime() - ts);
709 #else
710         sleep(2);
711 #endif
712
713 #ifndef ZAP
714         printf("\nPerform block read\n");
715         memset(odataBlockMem, 0x0, sizeof(odataBlockMem));
716         nvmeRequest(0, 1, 0x02, 0x01800000, 0x0000000, 0x00000000, 7);  // Four blocks
717         usleep(100000);
718
719         printf("DataBlock:\n");
720         bhd32(odataBlockMem, 8*512/4);
721 #endif
722 #endif
723
724         printf("Stats\n");
725         dumpRegs(0);
726         dumpRegs(1);
727
728         n = readNvmeStorageReg(RegWriteNumBlocks);
729         t = readNvmeStorageReg(RegWriteTime);
730         r = (4096.0 * n / (1e-6 * t));
731         printf("NvmeWrite: rate:      %f MBytes/s\n", r / (1024 * 1024));
732
733         return 0;
734 }
735
736 int Control::test7(){
737         int     e;
738         int     a;
739         BUInt32 v;
740         BUInt32 i;
741         int     n;
742         //BUInt numBlocks = 262144;
743         BUInt   numBlocks = 10000;
744         
745         printf("Test7: Validate 4k blocks\n");
746         
747         if(e = nvmeInit())
748                 return e;
749
750         v = 0;
751         for(n = 0; n < numBlocks; n++){
752                 printf("Test Block: %u\n", n);
753                 memset(odataBlockMem, 0x01, sizeof(odataBlockMem));
754                 nvmeRequest(1, 1, 0x02, 0x01800000, n * 8, 0x00000000, 7);      // Perform read
755
756                 for(a = 0; a < 4096 / 4; a++, v++){
757                         if(odataBlockMem[a] != v){
758                                 printf("Error in Block: %u\n", n);
759                                 bhd32a(odataBlockMem, 8*512/4);
760                                 exit(1);
761                         }
762                 }
763         }
764         
765         return 0;
766 }
767
768 int Control::test8(){
769         int     e;
770         BUInt32 block;
771         BUInt   maxBlocks = 32768;
772         BUInt   numBlocks = 262144;             // 1 GByte
773         //BUInt numBlocks = 2621440;            // 10 GByte
774
775         printf("Test8: Trim Nvme\n");
776         
777         if(e = nvmeInit())
778                 return e;
779
780         for(block = 0; block < numBlocks; block += (maxBlocks/8)){
781                 nvmeRequest(1, 1, 0x08, 0x00000000, block * 8, 0x00000000, (1 << 25) | maxBlocks-1);    // Perform trim of 32k 512 Byte blocks
782         }
783
784
785         return 0;
786 }
787
788 int Control::test9(){
789         int     e;
790         BUInt32 nvmeNum = onvmeNum;
791         BUInt32 cmd0;
792
793         printf("Test dual Nvme\n");
794         
795         onvmeNum = 0;
796         nvmeNum = onvmeNum;
797
798         // Perform reset
799         reset();
800         
801         onvmeNum = 0;
802         writeNvmeStorageReg(4, 0x80000000);
803
804         onvmeNum = 1;
805         writeNvmeStorageReg(4, 0x88000000);
806
807         onvmeNum = 2;
808         //writeNvmeStorageReg(4, 0x88800000);
809
810         onvmeNum = 0;
811         dumpRegs();
812
813         onvmeNum = 1;
814         dumpRegs();
815
816         onvmeNum = 2;
817         dumpRegs();
818         
819         printf("NvmeRegisters\n");
820         onvmeNum = nvmeNum;
821         dumpNvmeRegisters();
822
823         return 0;
824 }
825
826 int Control::test10(){
827         int     e;
828         int     a;
829         BUInt32 v;
830         BUInt32 n;
831         BUInt32 t;
832         double  r;
833         double  ts;
834         BUInt   numBlocks = 2;                  // 
835         //BUInt numBlocks = 262144;             // 1 GByte
836         //BUInt numBlocks = 2621440;            // 10 GByte
837
838         //numBlocks = 8;
839         //numBlocks = 2621440;          // 10 GByte
840         
841         printf("Test10: Read blocks using NvmeRead functionality\n");
842
843         if(e = nvmeInit())
844                 return e;
845
846         //dumpRegs();
847         
848         // Set number of blocks to read
849         writeNvmeStorageReg(RegReadBlock, 0);
850         writeNvmeStorageReg(RegReadNumBlocks, numBlocks);
851         dumpRegs();
852         
853         // Start off NvmeRead engine
854         printf("\nStart NvmeRead engine\n");
855         writeNvmeStorageReg(RegReadControl, 0x00000001);
856
857         sleep(2);
858         dumpRegs();
859
860         return 0;
861 }
862
863
864
865 int Control::test_misc(){
866         BUInt32 address = 0;
867         BUInt32 data[8];
868         BUInt32 data32;
869         BUInt64 data64;
870         BUInt32 a;
871         int     e;
872         int     n;
873
874         printf("Test_misc: Collection of misc tests\n");
875         
876         if(e = nvmeInit())
877                 return e;
878
879         printf("Get info\n");
880         nvmeRequest(0, 0, 0x06, 0x01F00000, 0x00000001);
881         sleep(1);
882
883         printf("\nGet namespace list\n");
884         nvmeRequest(0, 0, 0x06, 0x01F00000, 0x00000002);
885         sleep(1);
886
887         printf("\nSet asynchonous feature\n");
888         nvmeRequest(0, 0, 0x09, 0x01F00000, 0x0000000b, 0xFFFFFFFF);
889         sleep(1);
890
891         printf("\nGet asynchonous feature\n");
892         nvmeRequest(0, 0, 0x0A, 0x01F00000, 0x0000000b);
893         sleep(1);
894
895
896         printf("\nGet log page\n");
897         nvmeRequest(0, 0, 0x02, 0x01F00000, 0x00100001, 0x00000000, 0);
898         sleep(1);
899
900         printf("\nGet asynchonous event\n");
901         nvmeRequest(0, 0, 0x0C, 0x00000000, 0x00000000, 0x00000000, 0);
902         sleep(1);
903
904         return 0;
905 }
906
907 void Control::uprintf(const char* fmt, ...){
908         va_list         args;
909         
910         if(overbose){
911                 va_start(args, fmt);
912                 
913                 vprintf(fmt, args);
914         }
915 }
916
917 int Control::validateBlock(BUInt32 blockNum, void* data){
918         BUInt32*        d = (BUInt32*)data;
919         BUInt           w;
920         
921         for(w = 0; w < BlockSize / 4; w++){
922                 if(d[w] != ((blockNum * BlockSize / 4) + w)){
923                         printf("Validate Error: Block: %u Position: %u 0x%8.8x !- 0x%8.8x\n", blockNum, w, d[w], ((blockNum * BlockSize / 4) + w));
924                         return 1;
925                 }
926         }
927         
928         return 0;
929 }
930
931 void Control::dumpDataBlock(void* data, Bool full){
932         char*   d = (char*)data;
933         
934         if(full){
935                 bhd32(data, BlockSize/4);
936         }
937         else {
938                 bhd32(data, 8);
939                 printf("...\n");
940                 bhd32(&d[BlockSize - (8*4)], 8);
941         }
942 }
943
944 void Control::dumpNvmeRegisters(){
945         int     e;
946         BUInt   a;
947         BUInt32 data;
948         
949         printf("Nvme regs\n");
950         for(a = 0; a < 16; a++){
951                 if(e = readNvmeReg32(a * 4, data)){
952                         printf("Read register Error: %d\n", e);
953                         return;
954                 }
955                 printf("Reg: 0x%3.3x 0x%8.8x\n", a * 4, data);
956         }
957 }
958
959 void usage(void) {
960         fprintf(stderr, "test_nvme: Version: %s\n", VERSION);
961         fprintf(stderr, "Usage: test_nvme [options] <testname>\n");
962         fprintf(stderr, "This program provides the ability perform access tests to an Nvme device on a FPGA development board\n");
963         fprintf(stderr, " -help,-h              - Help on command line parameters\n");
964         fprintf(stderr, " -v                    - Verbose\n");
965         fprintf(stderr, " -no-validate          - Disable data validation\n");
966         fprintf(stderr, " -l                    - List tests\n");
967         fprintf(stderr, " -d <nvmeNum>          - Nvme to operate on: 0: Nvme0, 1: Nvme1, 2: Both Nvme's (default)\n");
968         fprintf(stderr, " -s <block>            - The starting 4k block number (default is 0)\n");
969         fprintf(stderr, " -n <num>              - The number of blocks to read/write or trim (default is 1)\n");
970         fprintf(stderr, " -o <filename>         - The filename for output data.\n");
971 }
972
973 static struct option options[] = {
974                 { "h",                  0, NULL, 0 },
975                 { "help",               0, NULL, 0 },
976                 { "v",                  0, NULL, 0 },
977                 { "no-validate",        0, NULL, 0 },
978                 { "l",                  0, NULL, 0 },
979                 { "d",                  1, NULL, 0 },
980                 { "s",                  1, NULL, 0 },
981                 { "n",                  1, NULL, 0 },
982                 { "o",                  1, NULL, 0 },
983                 { 0,0,0,0 }
984 };
985 int main(int argc, char** argv){
986         int             err;
987         int             optIndex = 0;
988         const char*     s;
989         int             c;
990         Control         control;
991         Bool            listTests = 0;
992         const char*     test = 0;
993
994         while((c = getopt_long_only(argc, argv, "", options, &optIndex)) == 0){
995                 s = options[optIndex].name;
996                 if(!strcmp(s, "help") || !strcmp(s, "h")){
997                         usage();
998                         return 1;
999                 }
1000                 else if(!strcmp(s, "v")){
1001                         control.overbose = 1;
1002                 }
1003                 else if(!strcmp(s, "no-validate")){
1004                         control.ovalidate = 0;
1005                 }
1006                 else if(!strcmp(s, "l")){
1007                         listTests = 1;
1008                 }
1009                 else if(!strcmp(s, "d")){
1010                         control.setNvme(atoi(optarg));
1011                 }
1012                 else if(!strcmp(s, "s")){
1013                         control.setStartBlock(atoi(optarg));
1014                 }
1015                 else if(!strcmp(s, "n")){
1016                         control.setNumBlocks(atoi(optarg));
1017                 }
1018                 else if(!strcmp(s, "o")){
1019                         control.setFilename(optarg);
1020                 }
1021                 else {
1022                         fprintf(stderr, "Error: No option: %s\n", s);
1023                         usage();
1024                         return 1;
1025                 }
1026         }
1027         
1028         if(control.getNvme() == 2){
1029                 if(control.ostartBlock & 1){
1030                         fprintf(stderr, "Needs an even start block number when two Nvme's are being accessed\n");
1031                         return 1;
1032                 }
1033                 if(control.onumBlocks & 1){
1034                         fprintf(stderr, "Needs an even number of blocks when two Nvme's are being accessed\n");
1035                         return 1;
1036                 }
1037         }
1038         
1039         if(listTests){
1040                 printf("process: Perform data input from FPGA TestData source into Nvme's.\n");
1041                 printf("read: Read data from Vvme's\n");
1042                 printf("write: Write data to Nvme's\n");
1043                 printf("trim: Trim/deallocate blocks on Nvme's\n");
1044                 printf("test*: Collection of misc programmed tests. See source code.\n");
1045         }
1046         else {
1047                 if((argc - optind) != 1){
1048                         fprintf(stderr, "Requires the test name\n");
1049                         usage();
1050                         return 1;
1051                 }
1052                 test = argv[optind++];
1053
1054                 if(err = control.init()){
1055                         return err;
1056                 }
1057
1058                 if(!strcmp(test, "process")){
1059                         err = control.nvmeProcess();
1060                 }
1061                 else if(!strcmp(test, "read")){
1062                         err = control.nvmeRead();
1063                 }
1064                 else if(!strcmp(test, "write")){
1065                         err = control.nvmeWrite();
1066                 }
1067                 else if(!strcmp(test, "trim")){
1068                         err = control.nvmeTrim();
1069                 }
1070                 
1071                 // Basic programed tests
1072                 else if(!strcmp(test, "test1")){
1073                         err = control.test1();
1074                 }
1075                 else if(!strcmp(test, "test2")){
1076                         err = control.test2();
1077                 }
1078                 else if(!strcmp(test, "test3")){
1079                         err = control.test3();
1080                 }
1081                 else if(!strcmp(test, "test4")){
1082                         err = control.test4();
1083                 }
1084                 else if(!strcmp(test, "test5")){
1085                         err = control.test5();
1086                 }
1087                 else if(!strcmp(test, "test6")){
1088                         err = control.test6();
1089                 }
1090                 else if(!strcmp(test, "test7")){
1091                         err = control.test7();
1092                 }
1093                 else if(!strcmp(test, "test8")){
1094                         err = control.test8();
1095                 }
1096                 else if(!strcmp(test, "test9")){
1097                         err = control.test9();
1098                 }
1099                 else if(!strcmp(test, "test10")){
1100                         err = control.test10();
1101                 }
1102                 else if(!strcmp(test, "test_misc")){
1103                         err = control.test_misc();
1104                 }
1105                 else {
1106                         fprintf(stderr, "No such test: %s\n", test);
1107                 }
1108         }
1109
1110         return 0;
1111 }