1#ifndef HW_NVME_H
2#define HW_NVME_H
3
4#include "block/nvme.h"
5#include "hw/pci/pci.h"
6#include "nvme-subsys.h"
7#include "nvme-ns.h"
8
9#define NVME_DEFAULT_ZONE_SIZE (128 * MiB)
10#define NVME_DEFAULT_MAX_ZA_SIZE (128 * KiB)
11
12typedef struct NvmeParams {
13 char *serial;
14 uint32_t num_queues;
15 uint32_t max_ioqpairs;
16 uint16_t msix_qsize;
17 uint32_t cmb_size_mb;
18 uint8_t aerl;
19 uint32_t aer_max_queued;
20 uint8_t mdts;
21 uint8_t vsl;
22 bool use_intel_id;
23 uint8_t zasl;
24 bool legacy_cmb;
25} NvmeParams;
26
27typedef struct NvmeAsyncEvent {
28 QTAILQ_ENTRY(NvmeAsyncEvent) entry;
29 NvmeAerResult result;
30} NvmeAsyncEvent;
31
32enum {
33 NVME_SG_ALLOC = 1 << 0,
34 NVME_SG_DMA = 1 << 1,
35};
36
37typedef struct NvmeSg {
38 int flags;
39
40 union {
41 QEMUSGList qsg;
42 QEMUIOVector iov;
43 };
44} NvmeSg;
45
46typedef struct NvmeRequest {
47 struct NvmeSQueue *sq;
48 struct NvmeNamespace *ns;
49 BlockAIOCB *aiocb;
50 uint16_t status;
51 void *opaque;
52 NvmeCqe cqe;
53 NvmeCmd cmd;
54 BlockAcctCookie acct;
55 NvmeSg sg;
56 QTAILQ_ENTRY(NvmeRequest)entry;
57} NvmeRequest;
58
59typedef struct NvmeBounceContext {
60 NvmeRequest *req;
61
62 struct {
63 QEMUIOVector iov;
64 uint8_t *bounce;
65 } data, mdata;
66} NvmeBounceContext;
67
68static inline const char *nvme_adm_opc_str(uint8_t opc)
69{
70 switch (opc) {
71 case NVME_ADM_CMD_DELETE_SQ: return "NVME_ADM_CMD_DELETE_SQ";
72 case NVME_ADM_CMD_CREATE_SQ: return "NVME_ADM_CMD_CREATE_SQ";
73 case NVME_ADM_CMD_GET_LOG_PAGE: return "NVME_ADM_CMD_GET_LOG_PAGE";
74 case NVME_ADM_CMD_DELETE_CQ: return "NVME_ADM_CMD_DELETE_CQ";
75 case NVME_ADM_CMD_CREATE_CQ: return "NVME_ADM_CMD_CREATE_CQ";
76 case NVME_ADM_CMD_IDENTIFY: return "NVME_ADM_CMD_IDENTIFY";
77 case NVME_ADM_CMD_ABORT: return "NVME_ADM_CMD_ABORT";
78 case NVME_ADM_CMD_SET_FEATURES: return "NVME_ADM_CMD_SET_FEATURES";
79 case NVME_ADM_CMD_GET_FEATURES: return "NVME_ADM_CMD_GET_FEATURES";
80 case NVME_ADM_CMD_ASYNC_EV_REQ: return "NVME_ADM_CMD_ASYNC_EV_REQ";
81 case NVME_ADM_CMD_NS_ATTACHMENT: return "NVME_ADM_CMD_NS_ATTACHMENT";
82 case NVME_ADM_CMD_FORMAT_NVM: return "NVME_ADM_CMD_FORMAT_NVM";
83 default: return "NVME_ADM_CMD_UNKNOWN";
84 }
85}
86
87static inline const char *nvme_io_opc_str(uint8_t opc)
88{
89 switch (opc) {
90 case NVME_CMD_FLUSH: return "NVME_NVM_CMD_FLUSH";
91 case NVME_CMD_WRITE: return "NVME_NVM_CMD_WRITE";
92 case NVME_CMD_READ: return "NVME_NVM_CMD_READ";
93 case NVME_CMD_COMPARE: return "NVME_NVM_CMD_COMPARE";
94 case NVME_CMD_WRITE_ZEROES: return "NVME_NVM_CMD_WRITE_ZEROES";
95 case NVME_CMD_DSM: return "NVME_NVM_CMD_DSM";
96 case NVME_CMD_VERIFY: return "NVME_NVM_CMD_VERIFY";
97 case NVME_CMD_COPY: return "NVME_NVM_CMD_COPY";
98 case NVME_CMD_ZONE_MGMT_SEND: return "NVME_ZONED_CMD_MGMT_SEND";
99 case NVME_CMD_ZONE_MGMT_RECV: return "NVME_ZONED_CMD_MGMT_RECV";
100 case NVME_CMD_ZONE_APPEND: return "NVME_ZONED_CMD_ZONE_APPEND";
101 default: return "NVME_NVM_CMD_UNKNOWN";
102 }
103}
104
105typedef struct NvmeSQueue {
106 struct NvmeCtrl *ctrl;
107 uint16_t sqid;
108 uint16_t cqid;
109 uint32_t head;
110 uint32_t tail;
111 uint32_t size;
112 uint64_t dma_addr;
113 QEMUTimer *timer;
114 NvmeRequest *io_req;
115 QTAILQ_HEAD(, NvmeRequest) req_list;
116 QTAILQ_HEAD(, NvmeRequest) out_req_list;
117 QTAILQ_ENTRY(NvmeSQueue) entry;
118} NvmeSQueue;
119
120typedef struct NvmeCQueue {
121 struct NvmeCtrl *ctrl;
122 uint8_t phase;
123 uint16_t cqid;
124 uint16_t irq_enabled;
125 uint32_t head;
126 uint32_t tail;
127 uint32_t vector;
128 uint32_t size;
129 uint64_t dma_addr;
130 QEMUTimer *timer;
131 QTAILQ_HEAD(, NvmeSQueue) sq_list;
132 QTAILQ_HEAD(, NvmeRequest) req_list;
133} NvmeCQueue;
134
135#define TYPE_NVME_BUS "nvme-bus"
136#define NVME_BUS(obj) OBJECT_CHECK(NvmeBus, (obj), TYPE_NVME_BUS)
137
138typedef struct NvmeBus {
139 BusState parent_bus;
140} NvmeBus;
141
142#define TYPE_NVME "nvme"
143#define NVME(obj) \
144 OBJECT_CHECK(NvmeCtrl, (obj), TYPE_NVME)
145
146typedef struct NvmeFeatureVal {
147 struct {
148 uint16_t temp_thresh_hi;
149 uint16_t temp_thresh_low;
150 };
151 uint32_t async_config;
152} NvmeFeatureVal;
153
154typedef struct NvmeCtrl {
155 PCIDevice parent_obj;
156 MemoryRegion bar0;
157 MemoryRegion iomem;
158 NvmeBar bar;
159 NvmeParams params;
160 NvmeBus bus;
161
162 uint16_t cntlid;
163 bool qs_created;
164 uint32_t page_size;
165 uint16_t page_bits;
166 uint16_t max_prp_ents;
167 uint16_t cqe_size;
168 uint16_t sqe_size;
169 uint32_t reg_size;
170 uint32_t num_namespaces;
171 uint32_t max_q_ents;
172 uint8_t outstanding_aers;
173 uint32_t irq_status;
174 uint64_t host_timestamp;
175 uint64_t timestamp_set_qemu_clock_ms;
176 uint64_t starttime_ms;
177 uint16_t temperature;
178 uint8_t smart_critical_warning;
179
180 struct {
181 MemoryRegion mem;
182 uint8_t *buf;
183 bool cmse;
184 hwaddr cba;
185 } cmb;
186
187 struct {
188 HostMemoryBackend *dev;
189 bool cmse;
190 hwaddr cba;
191 } pmr;
192
193 uint8_t aer_mask;
194 NvmeRequest **aer_reqs;
195 QTAILQ_HEAD(, NvmeAsyncEvent) aer_queue;
196 int aer_queued;
197
198 uint32_t dmrsl;
199
200
201#define NVME_CHANGED_NSID_SIZE (NVME_MAX_NAMESPACES + 1)
202 DECLARE_BITMAP(changed_nsids, NVME_CHANGED_NSID_SIZE);
203
204 NvmeSubsystem *subsys;
205
206 NvmeNamespace namespace;
207
208
209
210
211 NvmeNamespace *namespaces[NVME_MAX_NAMESPACES];
212 NvmeSQueue **sq;
213 NvmeCQueue **cq;
214 NvmeSQueue admin_sq;
215 NvmeCQueue admin_cq;
216 NvmeIdCtrl id_ctrl;
217 NvmeFeatureVal features;
218} NvmeCtrl;
219
220static inline NvmeNamespace *nvme_ns(NvmeCtrl *n, uint32_t nsid)
221{
222 if (!nsid || nsid > n->num_namespaces) {
223 return NULL;
224 }
225
226 return n->namespaces[nsid - 1];
227}
228
229static inline NvmeCQueue *nvme_cq(NvmeRequest *req)
230{
231 NvmeSQueue *sq = req->sq;
232 NvmeCtrl *n = sq->ctrl;
233
234 return n->cq[sq->cqid];
235}
236
237static inline NvmeCtrl *nvme_ctrl(NvmeRequest *req)
238{
239 NvmeSQueue *sq = req->sq;
240 return sq->ctrl;
241}
242
243static inline uint16_t nvme_cid(NvmeRequest *req)
244{
245 if (!req) {
246 return 0xffff;
247 }
248
249 return le16_to_cpu(req->cqe.cid);
250}
251
252typedef enum NvmeTxDirection {
253 NVME_TX_DIRECTION_TO_DEVICE = 0,
254 NVME_TX_DIRECTION_FROM_DEVICE = 1,
255} NvmeTxDirection;
256
257void nvme_attach_ns(NvmeCtrl *n, NvmeNamespace *ns);
258uint16_t nvme_bounce_data(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
259 NvmeTxDirection dir, NvmeRequest *req);
260uint16_t nvme_bounce_mdata(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
261 NvmeTxDirection dir, NvmeRequest *req);
262void nvme_rw_complete_cb(void *opaque, int ret);
263uint16_t nvme_map_dptr(NvmeCtrl *n, NvmeSg *sg, size_t len,
264 NvmeCmd *cmd);
265
266#endif
267