Added Nvme trim/deallocate functionality.
[DuneNvme.git] / test / NvmeAccess.h
1 /*******************************************************************************
2  *      NvmeAccess.h    Provides access to an Nvme storage device on FpgaFabric
3  *      T.Barnaby,      Beam Ltd,       2020-04-10
4  *******************************************************************************
5  */
6 /**
7  * @class       NvmeAccess
8  * @author      Terry Barnaby <terry.barnaby@beam.ltd.uk>
9  * @date        2020-04-10
10  * @version     0.0.1
11  *
12  * @brief
13  * This is a simple class that provides access to an Nvme storage device on FpgaFabric.
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 class 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 class 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 #pragma once
46
47 #include <BeamLibBasic.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include <stdlib.h>
51 #include <errno.h>
52 #include <unistd.h>
53 #include <fcntl.h>
54 #include <sys/mman.h>
55 #include <arpa/inet.h>
56 #include <pthread.h>
57 #include <sys/ioctl.h>
58 #include <bfpga_driver/bfpga.h>
59
60 const Bool      UseQueueEngine = 1;                     ///< Use the FPGA queue engine implementation
61 const Bool      UseConfigEngine = 0;                    ///< Use the FPGA configuration engine
62 const BUInt     PcieMaxPayloadSize = 32;                ///< The Pcie maximim packet payload in 32bit DWords
63
64 const BUInt     RegIdent                = 0x000;        ///< The ident and version
65 const BUInt     RegControl              = 0x004;        ///< The control register
66 const BUInt     RegStatus               = 0x008;        ///< The status register
67 const BUInt     RegTotalBlocks          = 0x00C;        ///< The total number of blocks
68 const BUInt     RegLostBlocks           = 0x010;        ///< The number of blocks currently read
69
70 const BUInt     RegDataChunkStart       = 0x040;        ///< The data chunk start register
71 const BUInt     RegDataChunkSize        = 0x044;        ///< The data chunk size register
72 const BUInt     RegWriteError           = 0x048;        ///< The write error status
73 const BUInt     RegWriteNumBlocks       = 0x04C;        ///< The number of blocks written
74 const BUInt     RegWriteTime            = 0x050;        ///< The write time in microseconds
75 const BUInt     RegWritePeakLatency     = 0x054;        ///< The write peak block write latency in microseconds
76
77 const BUInt     RegReadControl          = 0x080;        ///< The read data control register
78 const BUInt     RegReadStatus           = 0x084;        ///< The read data status register
79 const BUInt     RegReadBlock            = 0x088;        ///< The read data starting block register
80 const BUInt     RegReadNumBlocks        = 0x08C;        ///< The read data number of blocks register
81
82 class NvmeRequestPacket {
83 public:
84                         NvmeRequestPacket(){
85                                 memset(this, 0, sizeof(*this));
86                         }
87
88         BUInt64         address;                ///< The 64bit read/write address
89         BUInt32         numWords:11;            ///< The number of 32bit data words to transfer
90         BUInt32         request:4;              ///< The request (0 - read, 1 - write etc.)
91         BUInt32         fill2:1;                ///< 
92         BUInt32         requesterId:16;         ///< The requestors ID used as the stream ID
93         BUInt32         tag:8;                  ///< A tag for this request, returned in the reply
94         BUInt32         completerId:16;         ///< The completers ID
95         BUInt32         requesterIdEnable:1;    ///< Enable the manual use of the requestorId field.
96         BUInt32         fill3:7;                ///< 
97         BUInt32         data[PcieMaxPayloadSize];       ///< The data words (Max of 1024 bytes but can be increased)
98 };
99
100 class NvmeReplyPacket {
101 public:
102                         NvmeReplyPacket(){
103                                 memset(this, 0, sizeof(*this));
104                         }
105
106         BUInt32         address:12;             ///< The lower 12 bits of the address
107         BUInt32         error:4;                ///< An error number
108         BUInt32         numBytes:13;            ///< The total number of bytes to be transfered
109         BUInt32         fill1:3;                ///< 
110         BUInt32         numWords:11;            ///< The number of 32bit words in this reply
111         BUInt32         status:3;               ///< The status for the request
112         BUInt32         fill2:2;                ///< 
113         BUInt32         requesterId:16;         ///< The requestors ID
114         BUInt32         tag:8;                  ///< The requests tag
115         BUInt32         completerId:16;         ///< The completer id
116         BUInt32         fill3:7;                ///< 
117         BUInt32         reply:1;                ///< This bit indicates a reply (we have used an unused bit for this)
118         BUInt32         data[PcieMaxPayloadSize];       ///< The data words (Max of 1024 bytes but can be increased)
119 };
120
121 const BUInt NvmeSglTypeData     = 0;
122
123 class NvmeSgl {
124         BUInt64         address;
125         BUInt32         length;
126         BUInt8          fill0[2];
127         BUInt8          subtype:4;
128         BUInt8          type:4;
129 };
130
131 /// Nvme access class
132 class NvmeAccess {
133 public:
134                         NvmeAccess();
135                         ~NvmeAccess();
136         
137         int             init();
138         void            close();
139
140         void            setNvme(BUInt n);
141         void            reset();
142
143         // Send a queued request to the NVMe
144         int             nvmeRequest(Bool wait, int queue, int opcode, BUInt32 address, BUInt32 arg10, BUInt32 arg11 = 0, BUInt32 arg12 = 0);
145         
146         // NVMe process received requests thread
147         int             nvmeProcess();
148         
149         // NvmeStorage units register access
150         BUInt32         readNvmeStorageReg(BUInt32 address);
151         void            writeNvmeStorageReg(BUInt32 address, BUInt32 data);
152         
153         // NVMe register access
154         int             readNvmeReg32(BUInt32 address, BUInt32& data);
155         int             writeNvmeReg32(BUInt32 address, BUInt32 data);
156         int             readNvmeReg64(BUInt32 address, BUInt64& data);
157         int             writeNvmeReg64(BUInt32 address, BUInt64 data);
158
159         // Perform register access over PCIe both config and NVMe registers
160         int             pcieWrite(BUInt8 request, BUInt32 address, BUInt32 num, BUInt32* data);
161         int             pcieRead(BUInt8 request, BUInt32 address, BUInt32 num, BUInt32* data);
162
163         // Packet send and receive
164         int             packetSend(const NvmeRequestPacket& packet);
165         int             packetSend(const NvmeReplyPacket& packet);
166         
167         // Debug
168         void            dumpRegs(int nvmeNum = -1);
169         void            dumpDmaRegs(bool c2h, int chan);
170         void            dumpStatus();
171
172         
173 protected:
174         int                     oregsFd;
175         int                     ohostSendFd;
176         int                     ohostRecvFd;
177         BFpgaInfo               oinfo;
178         volatile BUInt32*       oregs;
179         volatile BUInt32*       odmaRegs;
180
181         BUInt32*                obufTx1;
182         BUInt32*                obufTx2;
183         BUInt32*                obufRx;
184         BUInt8                  otag;
185
186         BSemaphore              opacketReplySem;                ///< Semaphore when a reply packet has been received
187         NvmeReplyPacket         opacketReply;                   ///< Reply to request
188         BSemaphore              oqueueReplySem;                 ///< Semaphore when a queue reply packet has been received
189
190         pthread_t               othread;
191         BUInt32                 onvmeNum;                       ///< The nvme to communicate with, 0 is both
192         BUInt32                 onvmeRegbase;                   ///< The register base address
193         BUInt32                 oqueueNum;
194
195         BUInt32                 oqueueAdminMem[4096];
196         BUInt32                 oqueueAdminRx;
197         BUInt32                 oqueueAdminTx;
198         BUInt32                 oqueueAdminId;
199         
200         BUInt32                 oqueueDataMem[4096];
201         BUInt32                 oqueueDataRx;
202         BUInt32                 oqueueDataTx;
203
204         BUInt32                 odataBlockMem[8192];
205 };