Statistics
| Branch: | Revision:

root / hw / block / nvme.c @ feature-archipelago

History | View | Annotate | Download (24.1 kB)

1 f3c507ad Keith Busch
/*
2 f3c507ad Keith Busch
 * QEMU NVM Express Controller
3 f3c507ad Keith Busch
 *
4 f3c507ad Keith Busch
 * Copyright (c) 2012, Intel Corporation
5 f3c507ad Keith Busch
 *
6 f3c507ad Keith Busch
 * Written by Keith Busch <keith.busch@intel.com>
7 f3c507ad Keith Busch
 *
8 f3c507ad Keith Busch
 * This code is licensed under the GNU GPL v2 or later.
9 f3c507ad Keith Busch
 */
10 f3c507ad Keith Busch
11 f3c507ad Keith Busch
/**
12 f3c507ad Keith Busch
 * Reference Specs: http://www.nvmexpress.org, 1.1, 1.0e
13 f3c507ad Keith Busch
 *
14 f3c507ad Keith Busch
 *  http://www.nvmexpress.org/resources/
15 f3c507ad Keith Busch
 */
16 f3c507ad Keith Busch
17 f3c507ad Keith Busch
/**
18 f3c507ad Keith Busch
 * Usage: add options:
19 f3c507ad Keith Busch
 *      -drive file=<file>,if=none,id=<drive_id>
20 f3c507ad Keith Busch
 *      -device nvme,drive=<drive_id>,serial=<serial>,id=<id[optional]>
21 f3c507ad Keith Busch
 */
22 f3c507ad Keith Busch
23 f3c507ad Keith Busch
#include <hw/block/block.h>
24 f3c507ad Keith Busch
#include <hw/hw.h>
25 f3c507ad Keith Busch
#include <hw/pci/msix.h>
26 f3c507ad Keith Busch
#include <hw/pci/pci.h>
27 f3c507ad Keith Busch
28 f3c507ad Keith Busch
#include "nvme.h"
29 f3c507ad Keith Busch
30 f3c507ad Keith Busch
static void nvme_process_sq(void *opaque);
31 f3c507ad Keith Busch
32 f3c507ad Keith Busch
static int nvme_check_sqid(NvmeCtrl *n, uint16_t sqid)
33 f3c507ad Keith Busch
{
34 f3c507ad Keith Busch
    return sqid < n->num_queues && n->sq[sqid] != NULL ? 0 : -1;
35 f3c507ad Keith Busch
}
36 f3c507ad Keith Busch
37 f3c507ad Keith Busch
static int nvme_check_cqid(NvmeCtrl *n, uint16_t cqid)
38 f3c507ad Keith Busch
{
39 f3c507ad Keith Busch
    return cqid < n->num_queues && n->cq[cqid] != NULL ? 0 : -1;
40 f3c507ad Keith Busch
}
41 f3c507ad Keith Busch
42 f3c507ad Keith Busch
static void nvme_inc_cq_tail(NvmeCQueue *cq)
43 f3c507ad Keith Busch
{
44 f3c507ad Keith Busch
    cq->tail++;
45 f3c507ad Keith Busch
    if (cq->tail >= cq->size) {
46 f3c507ad Keith Busch
        cq->tail = 0;
47 f3c507ad Keith Busch
        cq->phase = !cq->phase;
48 f3c507ad Keith Busch
    }
49 f3c507ad Keith Busch
}
50 f3c507ad Keith Busch
51 f3c507ad Keith Busch
static void nvme_inc_sq_head(NvmeSQueue *sq)
52 f3c507ad Keith Busch
{
53 f3c507ad Keith Busch
    sq->head = (sq->head + 1) % sq->size;
54 f3c507ad Keith Busch
}
55 f3c507ad Keith Busch
56 f3c507ad Keith Busch
static uint8_t nvme_cq_full(NvmeCQueue *cq)
57 f3c507ad Keith Busch
{
58 f3c507ad Keith Busch
    return (cq->tail + 1) % cq->size == cq->head;
59 f3c507ad Keith Busch
}
60 f3c507ad Keith Busch
61 f3c507ad Keith Busch
static uint8_t nvme_sq_empty(NvmeSQueue *sq)
62 f3c507ad Keith Busch
{
63 f3c507ad Keith Busch
    return sq->head == sq->tail;
64 f3c507ad Keith Busch
}
65 f3c507ad Keith Busch
66 f3c507ad Keith Busch
static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq)
67 f3c507ad Keith Busch
{
68 f3c507ad Keith Busch
    if (cq->irq_enabled) {
69 f3c507ad Keith Busch
        if (msix_enabled(&(n->parent_obj))) {
70 f3c507ad Keith Busch
            msix_notify(&(n->parent_obj), cq->vector);
71 f3c507ad Keith Busch
        } else {
72 9e64f8a3 Marcel Apfelbaum
            pci_irq_pulse(&n->parent_obj);
73 f3c507ad Keith Busch
        }
74 f3c507ad Keith Busch
    }
75 f3c507ad Keith Busch
}
76 f3c507ad Keith Busch
77 f3c507ad Keith Busch
static uint16_t nvme_map_prp(QEMUSGList *qsg, uint64_t prp1, uint64_t prp2,
78 f3c507ad Keith Busch
    uint32_t len, NvmeCtrl *n)
79 f3c507ad Keith Busch
{
80 f3c507ad Keith Busch
    hwaddr trans_len = n->page_size - (prp1 % n->page_size);
81 f3c507ad Keith Busch
    trans_len = MIN(len, trans_len);
82 f3c507ad Keith Busch
    int num_prps = (len >> n->page_bits) + 1;
83 f3c507ad Keith Busch
84 f3c507ad Keith Busch
    if (!prp1) {
85 f3c507ad Keith Busch
        return NVME_INVALID_FIELD | NVME_DNR;
86 f3c507ad Keith Busch
    }
87 f3c507ad Keith Busch
88 df32fd1c Paolo Bonzini
    pci_dma_sglist_init(qsg, &n->parent_obj, num_prps);
89 f3c507ad Keith Busch
    qemu_sglist_add(qsg, prp1, trans_len);
90 f3c507ad Keith Busch
    len -= trans_len;
91 f3c507ad Keith Busch
    if (len) {
92 f3c507ad Keith Busch
        if (!prp2) {
93 f3c507ad Keith Busch
            goto unmap;
94 f3c507ad Keith Busch
        }
95 f3c507ad Keith Busch
        if (len > n->page_size) {
96 f3c507ad Keith Busch
            uint64_t prp_list[n->max_prp_ents];
97 f3c507ad Keith Busch
            uint32_t nents, prp_trans;
98 f3c507ad Keith Busch
            int i = 0;
99 f3c507ad Keith Busch
100 f3c507ad Keith Busch
            nents = (len + n->page_size - 1) >> n->page_bits;
101 f3c507ad Keith Busch
            prp_trans = MIN(n->max_prp_ents, nents) * sizeof(uint64_t);
102 f3c507ad Keith Busch
            pci_dma_read(&n->parent_obj, prp2, (void *)prp_list, prp_trans);
103 f3c507ad Keith Busch
            while (len != 0) {
104 f3c507ad Keith Busch
                uint64_t prp_ent = le64_to_cpu(prp_list[i]);
105 f3c507ad Keith Busch
106 f3c507ad Keith Busch
                if (i == n->max_prp_ents - 1 && len > n->page_size) {
107 f3c507ad Keith Busch
                    if (!prp_ent || prp_ent & (n->page_size - 1)) {
108 f3c507ad Keith Busch
                        goto unmap;
109 f3c507ad Keith Busch
                    }
110 f3c507ad Keith Busch
111 f3c507ad Keith Busch
                    i = 0;
112 f3c507ad Keith Busch
                    nents = (len + n->page_size - 1) >> n->page_bits;
113 f3c507ad Keith Busch
                    prp_trans = MIN(n->max_prp_ents, nents) * sizeof(uint64_t);
114 f3c507ad Keith Busch
                    pci_dma_read(&n->parent_obj, prp_ent, (void *)prp_list,
115 f3c507ad Keith Busch
                        prp_trans);
116 f3c507ad Keith Busch
                    prp_ent = le64_to_cpu(prp_list[i]);
117 f3c507ad Keith Busch
                }
118 f3c507ad Keith Busch
119 f3c507ad Keith Busch
                if (!prp_ent || prp_ent & (n->page_size - 1)) {
120 f3c507ad Keith Busch
                    goto unmap;
121 f3c507ad Keith Busch
                }
122 f3c507ad Keith Busch
123 f3c507ad Keith Busch
                trans_len = MIN(len, n->page_size);
124 f3c507ad Keith Busch
                qemu_sglist_add(qsg, prp_ent, trans_len);
125 f3c507ad Keith Busch
                len -= trans_len;
126 f3c507ad Keith Busch
                i++;
127 f3c507ad Keith Busch
            }
128 f3c507ad Keith Busch
        } else {
129 f3c507ad Keith Busch
            if (prp2 & (n->page_size - 1)) {
130 f3c507ad Keith Busch
                goto unmap;
131 f3c507ad Keith Busch
            }
132 f3c507ad Keith Busch
            qemu_sglist_add(qsg, prp2, len);
133 f3c507ad Keith Busch
        }
134 f3c507ad Keith Busch
    }
135 f3c507ad Keith Busch
    return NVME_SUCCESS;
136 f3c507ad Keith Busch
137 f3c507ad Keith Busch
 unmap:
138 f3c507ad Keith Busch
    qemu_sglist_destroy(qsg);
139 f3c507ad Keith Busch
    return NVME_INVALID_FIELD | NVME_DNR;
140 f3c507ad Keith Busch
}
141 f3c507ad Keith Busch
142 f3c507ad Keith Busch
static uint16_t nvme_dma_read_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
143 f3c507ad Keith Busch
    uint64_t prp1, uint64_t prp2)
144 f3c507ad Keith Busch
{
145 f3c507ad Keith Busch
    QEMUSGList qsg;
146 f3c507ad Keith Busch
147 f3c507ad Keith Busch
    if (nvme_map_prp(&qsg, prp1, prp2, len, n)) {
148 f3c507ad Keith Busch
        return NVME_INVALID_FIELD | NVME_DNR;
149 f3c507ad Keith Busch
    }
150 f3c507ad Keith Busch
    if (dma_buf_read(ptr, len, &qsg)) {
151 f3c507ad Keith Busch
        qemu_sglist_destroy(&qsg);
152 f3c507ad Keith Busch
        return NVME_INVALID_FIELD | NVME_DNR;
153 f3c507ad Keith Busch
    }
154 f3c507ad Keith Busch
    return NVME_SUCCESS;
155 f3c507ad Keith Busch
}
156 f3c507ad Keith Busch
157 f3c507ad Keith Busch
static void nvme_post_cqes(void *opaque)
158 f3c507ad Keith Busch
{
159 f3c507ad Keith Busch
    NvmeCQueue *cq = opaque;
160 f3c507ad Keith Busch
    NvmeCtrl *n = cq->ctrl;
161 f3c507ad Keith Busch
    NvmeRequest *req, *next;
162 f3c507ad Keith Busch
163 f3c507ad Keith Busch
    QTAILQ_FOREACH_SAFE(req, &cq->req_list, entry, next) {
164 f3c507ad Keith Busch
        NvmeSQueue *sq;
165 f3c507ad Keith Busch
        hwaddr addr;
166 f3c507ad Keith Busch
167 f3c507ad Keith Busch
        if (nvme_cq_full(cq)) {
168 f3c507ad Keith Busch
            break;
169 f3c507ad Keith Busch
        }
170 f3c507ad Keith Busch
171 f3c507ad Keith Busch
        QTAILQ_REMOVE(&cq->req_list, req, entry);
172 f3c507ad Keith Busch
        sq = req->sq;
173 f3c507ad Keith Busch
        req->cqe.status = cpu_to_le16((req->status << 1) | cq->phase);
174 f3c507ad Keith Busch
        req->cqe.sq_id = cpu_to_le16(sq->sqid);
175 f3c507ad Keith Busch
        req->cqe.sq_head = cpu_to_le16(sq->head);
176 f3c507ad Keith Busch
        addr = cq->dma_addr + cq->tail * n->cqe_size;
177 f3c507ad Keith Busch
        nvme_inc_cq_tail(cq);
178 f3c507ad Keith Busch
        pci_dma_write(&n->parent_obj, addr, (void *)&req->cqe,
179 f3c507ad Keith Busch
            sizeof(req->cqe));
180 f3c507ad Keith Busch
        QTAILQ_INSERT_TAIL(&sq->req_list, req, entry);
181 f3c507ad Keith Busch
    }
182 f3c507ad Keith Busch
    nvme_isr_notify(n, cq);
183 f3c507ad Keith Busch
}
184 f3c507ad Keith Busch
185 f3c507ad Keith Busch
static void nvme_enqueue_req_completion(NvmeCQueue *cq, NvmeRequest *req)
186 f3c507ad Keith Busch
{
187 f3c507ad Keith Busch
    assert(cq->cqid == req->sq->cqid);
188 f3c507ad Keith Busch
    QTAILQ_REMOVE(&req->sq->out_req_list, req, entry);
189 f3c507ad Keith Busch
    QTAILQ_INSERT_TAIL(&cq->req_list, req, entry);
190 bc72ad67 Alex Bligh
    timer_mod(cq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500);
191 f3c507ad Keith Busch
}
192 f3c507ad Keith Busch
193 f3c507ad Keith Busch
static void nvme_rw_cb(void *opaque, int ret)
194 f3c507ad Keith Busch
{
195 f3c507ad Keith Busch
    NvmeRequest *req = opaque;
196 f3c507ad Keith Busch
    NvmeSQueue *sq = req->sq;
197 f3c507ad Keith Busch
    NvmeCtrl *n = sq->ctrl;
198 f3c507ad Keith Busch
    NvmeCQueue *cq = n->cq[sq->cqid];
199 f3c507ad Keith Busch
200 f3c507ad Keith Busch
    bdrv_acct_done(n->conf.bs, &req->acct);
201 f3c507ad Keith Busch
    if (!ret) {
202 f3c507ad Keith Busch
        req->status = NVME_SUCCESS;
203 f3c507ad Keith Busch
    } else {
204 f3c507ad Keith Busch
        req->status = NVME_INTERNAL_DEV_ERROR;
205 f3c507ad Keith Busch
    }
206 f3c507ad Keith Busch
207 f3c507ad Keith Busch
    qemu_sglist_destroy(&req->qsg);
208 f3c507ad Keith Busch
    nvme_enqueue_req_completion(cq, req);
209 f3c507ad Keith Busch
}
210 f3c507ad Keith Busch
211 f3c507ad Keith Busch
static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
212 f3c507ad Keith Busch
    NvmeRequest *req)
213 f3c507ad Keith Busch
{
214 f3c507ad Keith Busch
    NvmeRwCmd *rw = (NvmeRwCmd *)cmd;
215 f3c507ad Keith Busch
    uint32_t nlb  = le32_to_cpu(rw->nlb) + 1;
216 f3c507ad Keith Busch
    uint64_t slba = le64_to_cpu(rw->slba);
217 f3c507ad Keith Busch
    uint64_t prp1 = le64_to_cpu(rw->prp1);
218 f3c507ad Keith Busch
    uint64_t prp2 = le64_to_cpu(rw->prp2);
219 f3c507ad Keith Busch
220 f3c507ad Keith Busch
    uint8_t lba_index  = NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas);
221 f3c507ad Keith Busch
    uint8_t data_shift = ns->id_ns.lbaf[lba_index].ds;
222 f3c507ad Keith Busch
    uint64_t data_size = nlb << data_shift;
223 f3c507ad Keith Busch
    uint64_t aio_slba  = slba << (data_shift - BDRV_SECTOR_BITS);
224 f3c507ad Keith Busch
    int is_write = rw->opcode == NVME_CMD_WRITE ? 1 : 0;
225 f3c507ad Keith Busch
226 f3c507ad Keith Busch
    if ((slba + nlb) > ns->id_ns.nsze) {
227 f3c507ad Keith Busch
        return NVME_LBA_RANGE | NVME_DNR;
228 f3c507ad Keith Busch
    }
229 f3c507ad Keith Busch
    if (nvme_map_prp(&req->qsg, prp1, prp2, data_size, n)) {
230 f3c507ad Keith Busch
        return NVME_INVALID_FIELD | NVME_DNR;
231 f3c507ad Keith Busch
    }
232 f3c507ad Keith Busch
    assert((nlb << data_shift) == req->qsg.size);
233 f3c507ad Keith Busch
234 f3c507ad Keith Busch
    dma_acct_start(n->conf.bs, &req->acct, &req->qsg, is_write ?
235 f3c507ad Keith Busch
        BDRV_ACCT_WRITE : BDRV_ACCT_READ);
236 f3c507ad Keith Busch
    req->aiocb = is_write ?
237 f3c507ad Keith Busch
        dma_bdrv_write(n->conf.bs, &req->qsg, aio_slba, nvme_rw_cb, req) :
238 f3c507ad Keith Busch
        dma_bdrv_read(n->conf.bs, &req->qsg, aio_slba, nvme_rw_cb, req);
239 f3c507ad Keith Busch
240 f3c507ad Keith Busch
    return NVME_NO_COMPLETE;
241 f3c507ad Keith Busch
}
242 f3c507ad Keith Busch
243 f3c507ad Keith Busch
static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
244 f3c507ad Keith Busch
{
245 f3c507ad Keith Busch
    NvmeNamespace *ns;
246 f3c507ad Keith Busch
    uint32_t nsid = le32_to_cpu(cmd->nsid);
247 f3c507ad Keith Busch
248 f3c507ad Keith Busch
    if (nsid == 0 || nsid > n->num_namespaces) {
249 f3c507ad Keith Busch
        return NVME_INVALID_NSID | NVME_DNR;
250 f3c507ad Keith Busch
    }
251 f3c507ad Keith Busch
252 f3c507ad Keith Busch
    ns = &n->namespaces[nsid - 1];
253 f3c507ad Keith Busch
    switch (cmd->opcode) {
254 f3c507ad Keith Busch
    case NVME_CMD_FLUSH:
255 f3c507ad Keith Busch
        return NVME_SUCCESS;
256 f3c507ad Keith Busch
    case NVME_CMD_WRITE:
257 f3c507ad Keith Busch
    case NVME_CMD_READ:
258 f3c507ad Keith Busch
        return nvme_rw(n, ns, cmd, req);
259 f3c507ad Keith Busch
    default:
260 f3c507ad Keith Busch
        return NVME_INVALID_OPCODE | NVME_DNR;
261 f3c507ad Keith Busch
    }
262 f3c507ad Keith Busch
}
263 f3c507ad Keith Busch
264 f3c507ad Keith Busch
static void nvme_free_sq(NvmeSQueue *sq, NvmeCtrl *n)
265 f3c507ad Keith Busch
{
266 f3c507ad Keith Busch
    n->sq[sq->sqid] = NULL;
267 bc72ad67 Alex Bligh
    timer_del(sq->timer);
268 bc72ad67 Alex Bligh
    timer_free(sq->timer);
269 f3c507ad Keith Busch
    g_free(sq->io_req);
270 f3c507ad Keith Busch
    if (sq->sqid) {
271 f3c507ad Keith Busch
        g_free(sq);
272 f3c507ad Keith Busch
    }
273 f3c507ad Keith Busch
}
274 f3c507ad Keith Busch
275 f3c507ad Keith Busch
static uint16_t nvme_del_sq(NvmeCtrl *n, NvmeCmd *cmd)
276 f3c507ad Keith Busch
{
277 f3c507ad Keith Busch
    NvmeDeleteQ *c = (NvmeDeleteQ *)cmd;
278 f3c507ad Keith Busch
    NvmeRequest *req, *next;
279 f3c507ad Keith Busch
    NvmeSQueue *sq;
280 f3c507ad Keith Busch
    NvmeCQueue *cq;
281 f3c507ad Keith Busch
    uint16_t qid = le16_to_cpu(c->qid);
282 f3c507ad Keith Busch
283 f3c507ad Keith Busch
    if (!qid || nvme_check_sqid(n, qid)) {
284 f3c507ad Keith Busch
        return NVME_INVALID_QID | NVME_DNR;
285 f3c507ad Keith Busch
    }
286 f3c507ad Keith Busch
287 f3c507ad Keith Busch
    sq = n->sq[qid];
288 f3c507ad Keith Busch
    while (!QTAILQ_EMPTY(&sq->out_req_list)) {
289 f3c507ad Keith Busch
        req = QTAILQ_FIRST(&sq->out_req_list);
290 f3c507ad Keith Busch
        assert(req->aiocb);
291 f3c507ad Keith Busch
        bdrv_aio_cancel(req->aiocb);
292 f3c507ad Keith Busch
    }
293 f3c507ad Keith Busch
    if (!nvme_check_cqid(n, sq->cqid)) {
294 f3c507ad Keith Busch
        cq = n->cq[sq->cqid];
295 f3c507ad Keith Busch
        QTAILQ_REMOVE(&cq->sq_list, sq, entry);
296 f3c507ad Keith Busch
297 f3c507ad Keith Busch
        nvme_post_cqes(cq);
298 f3c507ad Keith Busch
        QTAILQ_FOREACH_SAFE(req, &cq->req_list, entry, next) {
299 f3c507ad Keith Busch
            if (req->sq == sq) {
300 f3c507ad Keith Busch
                QTAILQ_REMOVE(&cq->req_list, req, entry);
301 f3c507ad Keith Busch
                QTAILQ_INSERT_TAIL(&sq->req_list, req, entry);
302 f3c507ad Keith Busch
            }
303 f3c507ad Keith Busch
        }
304 f3c507ad Keith Busch
    }
305 f3c507ad Keith Busch
306 f3c507ad Keith Busch
    nvme_free_sq(sq, n);
307 f3c507ad Keith Busch
    return NVME_SUCCESS;
308 f3c507ad Keith Busch
}
309 f3c507ad Keith Busch
310 f3c507ad Keith Busch
static void nvme_init_sq(NvmeSQueue *sq, NvmeCtrl *n, uint64_t dma_addr,
311 f3c507ad Keith Busch
    uint16_t sqid, uint16_t cqid, uint16_t size)
312 f3c507ad Keith Busch
{
313 f3c507ad Keith Busch
    int i;
314 f3c507ad Keith Busch
    NvmeCQueue *cq;
315 f3c507ad Keith Busch
316 f3c507ad Keith Busch
    sq->ctrl = n;
317 f3c507ad Keith Busch
    sq->dma_addr = dma_addr;
318 f3c507ad Keith Busch
    sq->sqid = sqid;
319 f3c507ad Keith Busch
    sq->size = size;
320 f3c507ad Keith Busch
    sq->cqid = cqid;
321 f3c507ad Keith Busch
    sq->head = sq->tail = 0;
322 f3c507ad Keith Busch
    sq->io_req = g_malloc(sq->size * sizeof(*sq->io_req));
323 f3c507ad Keith Busch
324 f3c507ad Keith Busch
    QTAILQ_INIT(&sq->req_list);
325 f3c507ad Keith Busch
    QTAILQ_INIT(&sq->out_req_list);
326 f3c507ad Keith Busch
    for (i = 0; i < sq->size; i++) {
327 f3c507ad Keith Busch
        sq->io_req[i].sq = sq;
328 f3c507ad Keith Busch
        QTAILQ_INSERT_TAIL(&(sq->req_list), &sq->io_req[i], entry);
329 f3c507ad Keith Busch
    }
330 bc72ad67 Alex Bligh
    sq->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, nvme_process_sq, sq);
331 f3c507ad Keith Busch
332 f3c507ad Keith Busch
    assert(n->cq[cqid]);
333 f3c507ad Keith Busch
    cq = n->cq[cqid];
334 f3c507ad Keith Busch
    QTAILQ_INSERT_TAIL(&(cq->sq_list), sq, entry);
335 f3c507ad Keith Busch
    n->sq[sqid] = sq;
336 f3c507ad Keith Busch
}
337 f3c507ad Keith Busch
338 f3c507ad Keith Busch
static uint16_t nvme_create_sq(NvmeCtrl *n, NvmeCmd *cmd)
339 f3c507ad Keith Busch
{
340 f3c507ad Keith Busch
    NvmeSQueue *sq;
341 f3c507ad Keith Busch
    NvmeCreateSq *c = (NvmeCreateSq *)cmd;
342 f3c507ad Keith Busch
343 f3c507ad Keith Busch
    uint16_t cqid = le16_to_cpu(c->cqid);
344 f3c507ad Keith Busch
    uint16_t sqid = le16_to_cpu(c->sqid);
345 f3c507ad Keith Busch
    uint16_t qsize = le16_to_cpu(c->qsize);
346 f3c507ad Keith Busch
    uint16_t qflags = le16_to_cpu(c->sq_flags);
347 f3c507ad Keith Busch
    uint64_t prp1 = le64_to_cpu(c->prp1);
348 f3c507ad Keith Busch
349 f3c507ad Keith Busch
    if (!cqid || nvme_check_cqid(n, cqid)) {
350 f3c507ad Keith Busch
        return NVME_INVALID_CQID | NVME_DNR;
351 f3c507ad Keith Busch
    }
352 f3c507ad Keith Busch
    if (!sqid || (sqid && !nvme_check_sqid(n, sqid))) {
353 f3c507ad Keith Busch
        return NVME_INVALID_QID | NVME_DNR;
354 f3c507ad Keith Busch
    }
355 f3c507ad Keith Busch
    if (!qsize || qsize > NVME_CAP_MQES(n->bar.cap)) {
356 f3c507ad Keith Busch
        return NVME_MAX_QSIZE_EXCEEDED | NVME_DNR;
357 f3c507ad Keith Busch
    }
358 f3c507ad Keith Busch
    if (!prp1 || prp1 & (n->page_size - 1)) {
359 f3c507ad Keith Busch
        return NVME_INVALID_FIELD | NVME_DNR;
360 f3c507ad Keith Busch
    }
361 f3c507ad Keith Busch
    if (!(NVME_SQ_FLAGS_PC(qflags))) {
362 f3c507ad Keith Busch
        return NVME_INVALID_FIELD | NVME_DNR;
363 f3c507ad Keith Busch
    }
364 f3c507ad Keith Busch
    sq = g_malloc0(sizeof(*sq));
365 f3c507ad Keith Busch
    nvme_init_sq(sq, n, prp1, sqid, cqid, qsize + 1);
366 f3c507ad Keith Busch
    return NVME_SUCCESS;
367 f3c507ad Keith Busch
}
368 f3c507ad Keith Busch
369 f3c507ad Keith Busch
static void nvme_free_cq(NvmeCQueue *cq, NvmeCtrl *n)
370 f3c507ad Keith Busch
{
371 f3c507ad Keith Busch
    n->cq[cq->cqid] = NULL;
372 bc72ad67 Alex Bligh
    timer_del(cq->timer);
373 bc72ad67 Alex Bligh
    timer_free(cq->timer);
374 f3c507ad Keith Busch
    msix_vector_unuse(&n->parent_obj, cq->vector);
375 f3c507ad Keith Busch
    if (cq->cqid) {
376 f3c507ad Keith Busch
        g_free(cq);
377 f3c507ad Keith Busch
    }
378 f3c507ad Keith Busch
}
379 f3c507ad Keith Busch
380 f3c507ad Keith Busch
static uint16_t nvme_del_cq(NvmeCtrl *n, NvmeCmd *cmd)
381 f3c507ad Keith Busch
{
382 f3c507ad Keith Busch
    NvmeDeleteQ *c = (NvmeDeleteQ *)cmd;
383 f3c507ad Keith Busch
    NvmeCQueue *cq;
384 f3c507ad Keith Busch
    uint16_t qid = le16_to_cpu(c->qid);
385 f3c507ad Keith Busch
386 f3c507ad Keith Busch
    if (!qid || nvme_check_cqid(n, qid)) {
387 f3c507ad Keith Busch
        return NVME_INVALID_CQID | NVME_DNR;
388 f3c507ad Keith Busch
    }
389 f3c507ad Keith Busch
390 f3c507ad Keith Busch
    cq = n->cq[qid];
391 f3c507ad Keith Busch
    if (!QTAILQ_EMPTY(&cq->sq_list)) {
392 f3c507ad Keith Busch
        return NVME_INVALID_QUEUE_DEL;
393 f3c507ad Keith Busch
    }
394 f3c507ad Keith Busch
    nvme_free_cq(cq, n);
395 f3c507ad Keith Busch
    return NVME_SUCCESS;
396 f3c507ad Keith Busch
}
397 f3c507ad Keith Busch
398 f3c507ad Keith Busch
static void nvme_init_cq(NvmeCQueue *cq, NvmeCtrl *n, uint64_t dma_addr,
399 f3c507ad Keith Busch
    uint16_t cqid, uint16_t vector, uint16_t size, uint16_t irq_enabled)
400 f3c507ad Keith Busch
{
401 f3c507ad Keith Busch
    cq->ctrl = n;
402 f3c507ad Keith Busch
    cq->cqid = cqid;
403 f3c507ad Keith Busch
    cq->size = size;
404 f3c507ad Keith Busch
    cq->dma_addr = dma_addr;
405 f3c507ad Keith Busch
    cq->phase = 1;
406 f3c507ad Keith Busch
    cq->irq_enabled = irq_enabled;
407 f3c507ad Keith Busch
    cq->vector = vector;
408 f3c507ad Keith Busch
    cq->head = cq->tail = 0;
409 f3c507ad Keith Busch
    QTAILQ_INIT(&cq->req_list);
410 f3c507ad Keith Busch
    QTAILQ_INIT(&cq->sq_list);
411 f3c507ad Keith Busch
    msix_vector_use(&n->parent_obj, cq->vector);
412 f3c507ad Keith Busch
    n->cq[cqid] = cq;
413 bc72ad67 Alex Bligh
    cq->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, nvme_post_cqes, cq);
414 f3c507ad Keith Busch
}
415 f3c507ad Keith Busch
416 f3c507ad Keith Busch
static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeCmd *cmd)
417 f3c507ad Keith Busch
{
418 f3c507ad Keith Busch
    NvmeCQueue *cq;
419 f3c507ad Keith Busch
    NvmeCreateCq *c = (NvmeCreateCq *)cmd;
420 f3c507ad Keith Busch
    uint16_t cqid = le16_to_cpu(c->cqid);
421 f3c507ad Keith Busch
    uint16_t vector = le16_to_cpu(c->irq_vector);
422 f3c507ad Keith Busch
    uint16_t qsize = le16_to_cpu(c->qsize);
423 f3c507ad Keith Busch
    uint16_t qflags = le16_to_cpu(c->cq_flags);
424 f3c507ad Keith Busch
    uint64_t prp1 = le64_to_cpu(c->prp1);
425 f3c507ad Keith Busch
426 f3c507ad Keith Busch
    if (!cqid || (cqid && !nvme_check_cqid(n, cqid))) {
427 f3c507ad Keith Busch
        return NVME_INVALID_CQID | NVME_DNR;
428 f3c507ad Keith Busch
    }
429 f3c507ad Keith Busch
    if (!qsize || qsize > NVME_CAP_MQES(n->bar.cap)) {
430 f3c507ad Keith Busch
        return NVME_MAX_QSIZE_EXCEEDED | NVME_DNR;
431 f3c507ad Keith Busch
    }
432 f3c507ad Keith Busch
    if (!prp1) {
433 f3c507ad Keith Busch
        return NVME_INVALID_FIELD | NVME_DNR;
434 f3c507ad Keith Busch
    }
435 f3c507ad Keith Busch
    if (vector > n->num_queues) {
436 f3c507ad Keith Busch
        return NVME_INVALID_IRQ_VECTOR | NVME_DNR;
437 f3c507ad Keith Busch
    }
438 f3c507ad Keith Busch
    if (!(NVME_CQ_FLAGS_PC(qflags))) {
439 f3c507ad Keith Busch
        return NVME_INVALID_FIELD | NVME_DNR;
440 f3c507ad Keith Busch
    }
441 f3c507ad Keith Busch
442 f3c507ad Keith Busch
    cq = g_malloc0(sizeof(*cq));
443 f3c507ad Keith Busch
    nvme_init_cq(cq, n, prp1, cqid, vector, qsize + 1,
444 f3c507ad Keith Busch
        NVME_CQ_FLAGS_IEN(qflags));
445 f3c507ad Keith Busch
    return NVME_SUCCESS;
446 f3c507ad Keith Busch
}
447 f3c507ad Keith Busch
448 f3c507ad Keith Busch
static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd)
449 f3c507ad Keith Busch
{
450 f3c507ad Keith Busch
    NvmeNamespace *ns;
451 f3c507ad Keith Busch
    NvmeIdentify *c = (NvmeIdentify *)cmd;
452 f3c507ad Keith Busch
    uint32_t cns  = le32_to_cpu(c->cns);
453 f3c507ad Keith Busch
    uint32_t nsid = le32_to_cpu(c->nsid);
454 f3c507ad Keith Busch
    uint64_t prp1 = le64_to_cpu(c->prp1);
455 f3c507ad Keith Busch
    uint64_t prp2 = le64_to_cpu(c->prp2);
456 f3c507ad Keith Busch
457 f3c507ad Keith Busch
    if (cns) {
458 f3c507ad Keith Busch
        return nvme_dma_read_prp(n, (uint8_t *)&n->id_ctrl, sizeof(n->id_ctrl),
459 f3c507ad Keith Busch
            prp1, prp2);
460 f3c507ad Keith Busch
    }
461 f3c507ad Keith Busch
    if (nsid == 0 || nsid > n->num_namespaces) {
462 f3c507ad Keith Busch
        return NVME_INVALID_NSID | NVME_DNR;
463 f3c507ad Keith Busch
    }
464 f3c507ad Keith Busch
465 f3c507ad Keith Busch
    ns = &n->namespaces[nsid - 1];
466 f3c507ad Keith Busch
    return nvme_dma_read_prp(n, (uint8_t *)&ns->id_ns, sizeof(ns->id_ns),
467 f3c507ad Keith Busch
        prp1, prp2);
468 f3c507ad Keith Busch
}
469 f3c507ad Keith Busch
470 f3c507ad Keith Busch
static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
471 f3c507ad Keith Busch
{
472 f3c507ad Keith Busch
    uint32_t dw10 = le32_to_cpu(cmd->cdw10);
473 f3c507ad Keith Busch
474 f3c507ad Keith Busch
    switch (dw10) {
475 f3c507ad Keith Busch
    case NVME_NUMBER_OF_QUEUES:
476 f3c507ad Keith Busch
        req->cqe.result = cpu_to_le32(n->num_queues);
477 f3c507ad Keith Busch
        break;
478 f3c507ad Keith Busch
    default:
479 f3c507ad Keith Busch
        return NVME_INVALID_FIELD | NVME_DNR;
480 f3c507ad Keith Busch
    }
481 f3c507ad Keith Busch
    return NVME_SUCCESS;
482 f3c507ad Keith Busch
}
483 f3c507ad Keith Busch
484 f3c507ad Keith Busch
static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
485 f3c507ad Keith Busch
{
486 f3c507ad Keith Busch
    uint32_t dw10 = le32_to_cpu(cmd->cdw10);
487 f3c507ad Keith Busch
488 f3c507ad Keith Busch
    switch (dw10) {
489 f3c507ad Keith Busch
    case NVME_NUMBER_OF_QUEUES:
490 f3c507ad Keith Busch
        req->cqe.result = cpu_to_le32(n->num_queues);
491 f3c507ad Keith Busch
        break;
492 f3c507ad Keith Busch
    default:
493 f3c507ad Keith Busch
        return NVME_INVALID_FIELD | NVME_DNR;
494 f3c507ad Keith Busch
    }
495 f3c507ad Keith Busch
    return NVME_SUCCESS;
496 f3c507ad Keith Busch
}
497 f3c507ad Keith Busch
498 f3c507ad Keith Busch
static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
499 f3c507ad Keith Busch
{
500 f3c507ad Keith Busch
    switch (cmd->opcode) {
501 f3c507ad Keith Busch
    case NVME_ADM_CMD_DELETE_SQ:
502 f3c507ad Keith Busch
        return nvme_del_sq(n, cmd);
503 f3c507ad Keith Busch
    case NVME_ADM_CMD_CREATE_SQ:
504 f3c507ad Keith Busch
        return nvme_create_sq(n, cmd);
505 f3c507ad Keith Busch
    case NVME_ADM_CMD_DELETE_CQ:
506 f3c507ad Keith Busch
        return nvme_del_cq(n, cmd);
507 f3c507ad Keith Busch
    case NVME_ADM_CMD_CREATE_CQ:
508 f3c507ad Keith Busch
        return nvme_create_cq(n, cmd);
509 f3c507ad Keith Busch
    case NVME_ADM_CMD_IDENTIFY:
510 f3c507ad Keith Busch
        return nvme_identify(n, cmd);
511 f3c507ad Keith Busch
    case NVME_ADM_CMD_SET_FEATURES:
512 f3c507ad Keith Busch
        return nvme_set_feature(n, cmd, req);
513 f3c507ad Keith Busch
    case NVME_ADM_CMD_GET_FEATURES:
514 f3c507ad Keith Busch
        return nvme_get_feature(n, cmd, req);
515 f3c507ad Keith Busch
    default:
516 f3c507ad Keith Busch
        return NVME_INVALID_OPCODE | NVME_DNR;
517 f3c507ad Keith Busch
    }
518 f3c507ad Keith Busch
}
519 f3c507ad Keith Busch
520 f3c507ad Keith Busch
static void nvme_process_sq(void *opaque)
521 f3c507ad Keith Busch
{
522 f3c507ad Keith Busch
    NvmeSQueue *sq = opaque;
523 f3c507ad Keith Busch
    NvmeCtrl *n = sq->ctrl;
524 f3c507ad Keith Busch
    NvmeCQueue *cq = n->cq[sq->cqid];
525 f3c507ad Keith Busch
526 f3c507ad Keith Busch
    uint16_t status;
527 f3c507ad Keith Busch
    hwaddr addr;
528 f3c507ad Keith Busch
    NvmeCmd cmd;
529 f3c507ad Keith Busch
    NvmeRequest *req;
530 f3c507ad Keith Busch
531 f3c507ad Keith Busch
    while (!(nvme_sq_empty(sq) || QTAILQ_EMPTY(&sq->req_list))) {
532 f3c507ad Keith Busch
        addr = sq->dma_addr + sq->head * n->sqe_size;
533 f3c507ad Keith Busch
        pci_dma_read(&n->parent_obj, addr, (void *)&cmd, sizeof(cmd));
534 f3c507ad Keith Busch
        nvme_inc_sq_head(sq);
535 f3c507ad Keith Busch
536 f3c507ad Keith Busch
        req = QTAILQ_FIRST(&sq->req_list);
537 f3c507ad Keith Busch
        QTAILQ_REMOVE(&sq->req_list, req, entry);
538 f3c507ad Keith Busch
        QTAILQ_INSERT_TAIL(&sq->out_req_list, req, entry);
539 f3c507ad Keith Busch
        memset(&req->cqe, 0, sizeof(req->cqe));
540 f3c507ad Keith Busch
        req->cqe.cid = cmd.cid;
541 f3c507ad Keith Busch
542 f3c507ad Keith Busch
        status = sq->sqid ? nvme_io_cmd(n, &cmd, req) :
543 f3c507ad Keith Busch
            nvme_admin_cmd(n, &cmd, req);
544 f3c507ad Keith Busch
        if (status != NVME_NO_COMPLETE) {
545 f3c507ad Keith Busch
            req->status = status;
546 f3c507ad Keith Busch
            nvme_enqueue_req_completion(cq, req);
547 f3c507ad Keith Busch
        }
548 f3c507ad Keith Busch
    }
549 f3c507ad Keith Busch
}
550 f3c507ad Keith Busch
551 f3c507ad Keith Busch
static void nvme_clear_ctrl(NvmeCtrl *n)
552 f3c507ad Keith Busch
{
553 f3c507ad Keith Busch
    int i;
554 f3c507ad Keith Busch
555 f3c507ad Keith Busch
    for (i = 0; i < n->num_queues; i++) {
556 f3c507ad Keith Busch
        if (n->sq[i] != NULL) {
557 f3c507ad Keith Busch
            nvme_free_sq(n->sq[i], n);
558 f3c507ad Keith Busch
        }
559 f3c507ad Keith Busch
    }
560 f3c507ad Keith Busch
    for (i = 0; i < n->num_queues; i++) {
561 f3c507ad Keith Busch
        if (n->cq[i] != NULL) {
562 f3c507ad Keith Busch
            nvme_free_cq(n->cq[i], n);
563 f3c507ad Keith Busch
        }
564 f3c507ad Keith Busch
    }
565 f3c507ad Keith Busch
566 f3c507ad Keith Busch
    bdrv_flush(n->conf.bs);
567 f3c507ad Keith Busch
    n->bar.cc = 0;
568 f3c507ad Keith Busch
}
569 f3c507ad Keith Busch
570 f3c507ad Keith Busch
static int nvme_start_ctrl(NvmeCtrl *n)
571 f3c507ad Keith Busch
{
572 f3c507ad Keith Busch
    uint32_t page_bits = NVME_CC_MPS(n->bar.cc) + 12;
573 f3c507ad Keith Busch
    uint32_t page_size = 1 << page_bits;
574 f3c507ad Keith Busch
575 f3c507ad Keith Busch
    if (n->cq[0] || n->sq[0] || !n->bar.asq || !n->bar.acq ||
576 f3c507ad Keith Busch
            n->bar.asq & (page_size - 1) || n->bar.acq & (page_size - 1) ||
577 f3c507ad Keith Busch
            NVME_CC_MPS(n->bar.cc) < NVME_CAP_MPSMIN(n->bar.cap) ||
578 f3c507ad Keith Busch
            NVME_CC_MPS(n->bar.cc) > NVME_CAP_MPSMAX(n->bar.cap) ||
579 f3c507ad Keith Busch
            NVME_CC_IOCQES(n->bar.cc) < NVME_CTRL_CQES_MIN(n->id_ctrl.cqes) ||
580 f3c507ad Keith Busch
            NVME_CC_IOCQES(n->bar.cc) > NVME_CTRL_CQES_MAX(n->id_ctrl.cqes) ||
581 f3c507ad Keith Busch
            NVME_CC_IOSQES(n->bar.cc) < NVME_CTRL_SQES_MIN(n->id_ctrl.sqes) ||
582 f3c507ad Keith Busch
            NVME_CC_IOSQES(n->bar.cc) > NVME_CTRL_SQES_MAX(n->id_ctrl.sqes) ||
583 f3c507ad Keith Busch
            !NVME_AQA_ASQS(n->bar.aqa) || NVME_AQA_ASQS(n->bar.aqa) > 4095 ||
584 f3c507ad Keith Busch
            !NVME_AQA_ACQS(n->bar.aqa) || NVME_AQA_ACQS(n->bar.aqa) > 4095) {
585 f3c507ad Keith Busch
        return -1;
586 f3c507ad Keith Busch
    }
587 f3c507ad Keith Busch
588 f3c507ad Keith Busch
    n->page_bits = page_bits;
589 f3c507ad Keith Busch
    n->page_size = page_size;
590 f3c507ad Keith Busch
    n->max_prp_ents = n->page_size / sizeof(uint64_t);
591 f3c507ad Keith Busch
    n->cqe_size = 1 << NVME_CC_IOCQES(n->bar.cc);
592 f3c507ad Keith Busch
    n->sqe_size = 1 << NVME_CC_IOSQES(n->bar.cc);
593 f3c507ad Keith Busch
    nvme_init_cq(&n->admin_cq, n, n->bar.acq, 0, 0,
594 f3c507ad Keith Busch
        NVME_AQA_ACQS(n->bar.aqa) + 1, 1);
595 f3c507ad Keith Busch
    nvme_init_sq(&n->admin_sq, n, n->bar.asq, 0, 0,
596 f3c507ad Keith Busch
        NVME_AQA_ASQS(n->bar.aqa) + 1);
597 f3c507ad Keith Busch
598 f3c507ad Keith Busch
    return 0;
599 f3c507ad Keith Busch
}
600 f3c507ad Keith Busch
601 f3c507ad Keith Busch
static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
602 f3c507ad Keith Busch
    unsigned size)
603 f3c507ad Keith Busch
{
604 f3c507ad Keith Busch
    switch (offset) {
605 f3c507ad Keith Busch
    case 0xc:
606 f3c507ad Keith Busch
        n->bar.intms |= data & 0xffffffff;
607 f3c507ad Keith Busch
        n->bar.intmc = n->bar.intms;
608 f3c507ad Keith Busch
        break;
609 f3c507ad Keith Busch
    case 0x10:
610 f3c507ad Keith Busch
        n->bar.intms &= ~(data & 0xffffffff);
611 f3c507ad Keith Busch
        n->bar.intmc = n->bar.intms;
612 f3c507ad Keith Busch
        break;
613 f3c507ad Keith Busch
    case 0x14:
614 f3c507ad Keith Busch
        if (NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc)) {
615 f3c507ad Keith Busch
            n->bar.cc = data;
616 f3c507ad Keith Busch
            if (nvme_start_ctrl(n)) {
617 f3c507ad Keith Busch
                n->bar.csts = NVME_CSTS_FAILED;
618 f3c507ad Keith Busch
            } else {
619 f3c507ad Keith Busch
                n->bar.csts = NVME_CSTS_READY;
620 f3c507ad Keith Busch
            }
621 f3c507ad Keith Busch
        } else if (!NVME_CC_EN(data) && NVME_CC_EN(n->bar.cc)) {
622 f3c507ad Keith Busch
            nvme_clear_ctrl(n);
623 f3c507ad Keith Busch
            n->bar.csts &= ~NVME_CSTS_READY;
624 f3c507ad Keith Busch
        }
625 f3c507ad Keith Busch
        if (NVME_CC_SHN(data) && !(NVME_CC_SHN(n->bar.cc))) {
626 f3c507ad Keith Busch
                nvme_clear_ctrl(n);
627 f3c507ad Keith Busch
                n->bar.cc = data;
628 f3c507ad Keith Busch
                n->bar.csts |= NVME_CSTS_SHST_COMPLETE;
629 f3c507ad Keith Busch
        } else if (!NVME_CC_SHN(data) && NVME_CC_SHN(n->bar.cc)) {
630 f3c507ad Keith Busch
                n->bar.csts &= ~NVME_CSTS_SHST_COMPLETE;
631 f3c507ad Keith Busch
                n->bar.cc = data;
632 f3c507ad Keith Busch
        }
633 f3c507ad Keith Busch
        break;
634 f3c507ad Keith Busch
    case 0x24:
635 f3c507ad Keith Busch
        n->bar.aqa = data & 0xffffffff;
636 f3c507ad Keith Busch
        break;
637 f3c507ad Keith Busch
    case 0x28:
638 f3c507ad Keith Busch
        n->bar.asq = data;
639 f3c507ad Keith Busch
        break;
640 f3c507ad Keith Busch
    case 0x2c:
641 f3c507ad Keith Busch
        n->bar.asq |= data << 32;
642 f3c507ad Keith Busch
        break;
643 f3c507ad Keith Busch
    case 0x30:
644 f3c507ad Keith Busch
        n->bar.acq = data;
645 f3c507ad Keith Busch
        break;
646 f3c507ad Keith Busch
    case 0x34:
647 f3c507ad Keith Busch
        n->bar.acq |= data << 32;
648 f3c507ad Keith Busch
        break;
649 f3c507ad Keith Busch
    default:
650 f3c507ad Keith Busch
        break;
651 f3c507ad Keith Busch
    }
652 f3c507ad Keith Busch
}
653 f3c507ad Keith Busch
654 f3c507ad Keith Busch
static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size)
655 f3c507ad Keith Busch
{
656 f3c507ad Keith Busch
    NvmeCtrl *n = (NvmeCtrl *)opaque;
657 f3c507ad Keith Busch
    uint8_t *ptr = (uint8_t *)&n->bar;
658 f3c507ad Keith Busch
    uint64_t val = 0;
659 f3c507ad Keith Busch
660 f3c507ad Keith Busch
    if (addr < sizeof(n->bar)) {
661 f3c507ad Keith Busch
        memcpy(&val, ptr + addr, size);
662 f3c507ad Keith Busch
    }
663 f3c507ad Keith Busch
    return val;
664 f3c507ad Keith Busch
}
665 f3c507ad Keith Busch
666 f3c507ad Keith Busch
static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
667 f3c507ad Keith Busch
{
668 f3c507ad Keith Busch
    uint32_t qid;
669 f3c507ad Keith Busch
670 f3c507ad Keith Busch
    if (addr & ((1 << 2) - 1)) {
671 f3c507ad Keith Busch
        return;
672 f3c507ad Keith Busch
    }
673 f3c507ad Keith Busch
674 f3c507ad Keith Busch
    if (((addr - 0x1000) >> 2) & 1) {
675 f3c507ad Keith Busch
        uint16_t new_head = val & 0xffff;
676 f3c507ad Keith Busch
        int start_sqs;
677 f3c507ad Keith Busch
        NvmeCQueue *cq;
678 f3c507ad Keith Busch
679 f3c507ad Keith Busch
        qid = (addr - (0x1000 + (1 << 2))) >> 3;
680 f3c507ad Keith Busch
        if (nvme_check_cqid(n, qid)) {
681 f3c507ad Keith Busch
            return;
682 f3c507ad Keith Busch
        }
683 f3c507ad Keith Busch
684 f3c507ad Keith Busch
        cq = n->cq[qid];
685 f3c507ad Keith Busch
        if (new_head >= cq->size) {
686 f3c507ad Keith Busch
            return;
687 f3c507ad Keith Busch
        }
688 f3c507ad Keith Busch
689 f3c507ad Keith Busch
        start_sqs = nvme_cq_full(cq) ? 1 : 0;
690 f3c507ad Keith Busch
        cq->head = new_head;
691 f3c507ad Keith Busch
        if (start_sqs) {
692 f3c507ad Keith Busch
            NvmeSQueue *sq;
693 f3c507ad Keith Busch
            QTAILQ_FOREACH(sq, &cq->sq_list, entry) {
694 bc72ad67 Alex Bligh
                timer_mod(sq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500);
695 f3c507ad Keith Busch
            }
696 bc72ad67 Alex Bligh
            timer_mod(cq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500);
697 f3c507ad Keith Busch
        }
698 f3c507ad Keith Busch
699 f3c507ad Keith Busch
        if (cq->tail != cq->head) {
700 f3c507ad Keith Busch
            nvme_isr_notify(n, cq);
701 f3c507ad Keith Busch
        }
702 f3c507ad Keith Busch
    } else {
703 f3c507ad Keith Busch
        uint16_t new_tail = val & 0xffff;
704 f3c507ad Keith Busch
        NvmeSQueue *sq;
705 f3c507ad Keith Busch
706 f3c507ad Keith Busch
        qid = (addr - 0x1000) >> 3;
707 f3c507ad Keith Busch
        if (nvme_check_sqid(n, qid)) {
708 f3c507ad Keith Busch
            return;
709 f3c507ad Keith Busch
        }
710 f3c507ad Keith Busch
711 f3c507ad Keith Busch
        sq = n->sq[qid];
712 f3c507ad Keith Busch
        if (new_tail >= sq->size) {
713 f3c507ad Keith Busch
            return;
714 f3c507ad Keith Busch
        }
715 f3c507ad Keith Busch
716 f3c507ad Keith Busch
        sq->tail = new_tail;
717 bc72ad67 Alex Bligh
        timer_mod(sq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500);
718 f3c507ad Keith Busch
    }
719 f3c507ad Keith Busch
}
720 f3c507ad Keith Busch
721 f3c507ad Keith Busch
static void nvme_mmio_write(void *opaque, hwaddr addr, uint64_t data,
722 f3c507ad Keith Busch
    unsigned size)
723 f3c507ad Keith Busch
{
724 f3c507ad Keith Busch
    NvmeCtrl *n = (NvmeCtrl *)opaque;
725 f3c507ad Keith Busch
    if (addr < sizeof(n->bar)) {
726 f3c507ad Keith Busch
        nvme_write_bar(n, addr, data, size);
727 f3c507ad Keith Busch
    } else if (addr >= 0x1000) {
728 f3c507ad Keith Busch
        nvme_process_db(n, addr, data);
729 f3c507ad Keith Busch
    }
730 f3c507ad Keith Busch
}
731 f3c507ad Keith Busch
732 f3c507ad Keith Busch
static const MemoryRegionOps nvme_mmio_ops = {
733 f3c507ad Keith Busch
    .read = nvme_mmio_read,
734 f3c507ad Keith Busch
    .write = nvme_mmio_write,
735 f3c507ad Keith Busch
    .endianness = DEVICE_LITTLE_ENDIAN,
736 f3c507ad Keith Busch
    .impl = {
737 f3c507ad Keith Busch
        .min_access_size = 2,
738 f3c507ad Keith Busch
        .max_access_size = 8,
739 f3c507ad Keith Busch
    },
740 f3c507ad Keith Busch
};
741 f3c507ad Keith Busch
742 f3c507ad Keith Busch
static int nvme_init(PCIDevice *pci_dev)
743 f3c507ad Keith Busch
{
744 f3c507ad Keith Busch
    NvmeCtrl *n = NVME(pci_dev);
745 f3c507ad Keith Busch
    NvmeIdCtrl *id = &n->id_ctrl;
746 f3c507ad Keith Busch
747 f3c507ad Keith Busch
    int i;
748 f3c507ad Keith Busch
    int64_t bs_size;
749 f3c507ad Keith Busch
    uint8_t *pci_conf;
750 f3c507ad Keith Busch
751 f3c507ad Keith Busch
    if (!(n->conf.bs)) {
752 f3c507ad Keith Busch
        return -1;
753 f3c507ad Keith Busch
    }
754 f3c507ad Keith Busch
755 f3c507ad Keith Busch
    bs_size =  bdrv_getlength(n->conf.bs);
756 f3c507ad Keith Busch
    if (bs_size <= 0) {
757 f3c507ad Keith Busch
        return -1;
758 f3c507ad Keith Busch
    }
759 f3c507ad Keith Busch
760 f3c507ad Keith Busch
    blkconf_serial(&n->conf, &n->serial);
761 f3c507ad Keith Busch
    if (!n->serial) {
762 f3c507ad Keith Busch
        return -1;
763 f3c507ad Keith Busch
    }
764 f3c507ad Keith Busch
765 f3c507ad Keith Busch
    pci_conf = pci_dev->config;
766 f3c507ad Keith Busch
    pci_conf[PCI_INTERRUPT_PIN] = 1;
767 f3c507ad Keith Busch
    pci_config_set_prog_interface(pci_dev->config, 0x2);
768 f3c507ad Keith Busch
    pci_config_set_class(pci_dev->config, PCI_CLASS_STORAGE_EXPRESS);
769 f3c507ad Keith Busch
    pcie_endpoint_cap_init(&n->parent_obj, 0x80);
770 f3c507ad Keith Busch
771 f3c507ad Keith Busch
    n->num_namespaces = 1;
772 f3c507ad Keith Busch
    n->num_queues = 64;
773 f3c507ad Keith Busch
    n->reg_size = 1 << qemu_fls(0x1004 + 2 * (n->num_queues + 1) * 4);
774 f3c507ad Keith Busch
    n->ns_size = bs_size / (uint64_t)n->num_namespaces;
775 f3c507ad Keith Busch
776 f3c507ad Keith Busch
    n->namespaces = g_malloc0(sizeof(*n->namespaces)*n->num_namespaces);
777 f3c507ad Keith Busch
    n->sq = g_malloc0(sizeof(*n->sq)*n->num_queues);
778 f3c507ad Keith Busch
    n->cq = g_malloc0(sizeof(*n->cq)*n->num_queues);
779 f3c507ad Keith Busch
780 2d256e6f Paolo Bonzini
    memory_region_init_io(&n->iomem, OBJECT(n), &nvme_mmio_ops, n,
781 2d256e6f Paolo Bonzini
                          "nvme", n->reg_size);
782 f3c507ad Keith Busch
    pci_register_bar(&n->parent_obj, 0,
783 f3c507ad Keith Busch
        PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64,
784 f3c507ad Keith Busch
        &n->iomem);
785 f3c507ad Keith Busch
    msix_init_exclusive_bar(&n->parent_obj, n->num_queues, 4);
786 f3c507ad Keith Busch
787 f3c507ad Keith Busch
    id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID));
788 f3c507ad Keith Busch
    id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID));
789 f3c507ad Keith Busch
    strpadcpy((char *)id->mn, sizeof(id->mn), "QEMU NVMe Ctrl", ' ');
790 f3c507ad Keith Busch
    strpadcpy((char *)id->fr, sizeof(id->fr), "1.0", ' ');
791 f3c507ad Keith Busch
    strpadcpy((char *)id->sn, sizeof(id->sn), n->serial, ' ');
792 f3c507ad Keith Busch
    id->rab = 6;
793 f3c507ad Keith Busch
    id->ieee[0] = 0x00;
794 f3c507ad Keith Busch
    id->ieee[1] = 0x02;
795 f3c507ad Keith Busch
    id->ieee[2] = 0xb3;
796 f3c507ad Keith Busch
    id->oacs = cpu_to_le16(0);
797 f3c507ad Keith Busch
    id->frmw = 7 << 1;
798 f3c507ad Keith Busch
    id->lpa = 1 << 0;
799 f3c507ad Keith Busch
    id->sqes = (0x6 << 4) | 0x6;
800 f3c507ad Keith Busch
    id->cqes = (0x4 << 4) | 0x4;
801 f3c507ad Keith Busch
    id->nn = cpu_to_le32(n->num_namespaces);
802 f3c507ad Keith Busch
    id->psd[0].mp = cpu_to_le16(0x9c4);
803 f3c507ad Keith Busch
    id->psd[0].enlat = cpu_to_le32(0x10);
804 f3c507ad Keith Busch
    id->psd[0].exlat = cpu_to_le32(0x4);
805 f3c507ad Keith Busch
806 f3c507ad Keith Busch
    n->bar.cap = 0;
807 f3c507ad Keith Busch
    NVME_CAP_SET_MQES(n->bar.cap, 0x7ff);
808 f3c507ad Keith Busch
    NVME_CAP_SET_CQR(n->bar.cap, 1);
809 f3c507ad Keith Busch
    NVME_CAP_SET_AMS(n->bar.cap, 1);
810 f3c507ad Keith Busch
    NVME_CAP_SET_TO(n->bar.cap, 0xf);
811 f3c507ad Keith Busch
    NVME_CAP_SET_CSS(n->bar.cap, 1);
812 f3c507ad Keith Busch
813 f3c507ad Keith Busch
    n->bar.vs = 0x00010001;
814 f3c507ad Keith Busch
    n->bar.intmc = n->bar.intms = 0;
815 f3c507ad Keith Busch
816 f3c507ad Keith Busch
    for (i = 0; i < n->num_namespaces; i++) {
817 f3c507ad Keith Busch
        NvmeNamespace *ns = &n->namespaces[i];
818 f3c507ad Keith Busch
        NvmeIdNs *id_ns = &ns->id_ns;
819 f3c507ad Keith Busch
        id_ns->nsfeat = 0;
820 f3c507ad Keith Busch
        id_ns->nlbaf = 0;
821 f3c507ad Keith Busch
        id_ns->flbas = 0;
822 f3c507ad Keith Busch
        id_ns->mc = 0;
823 f3c507ad Keith Busch
        id_ns->dpc = 0;
824 f3c507ad Keith Busch
        id_ns->dps = 0;
825 f3c507ad Keith Busch
        id_ns->lbaf[0].ds = BDRV_SECTOR_BITS;
826 f3c507ad Keith Busch
        id_ns->ncap  = id_ns->nuse = id_ns->nsze =
827 f3c507ad Keith Busch
            cpu_to_le64(n->ns_size >>
828 f3c507ad Keith Busch
                id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas)].ds);
829 f3c507ad Keith Busch
    }
830 f3c507ad Keith Busch
    return 0;
831 f3c507ad Keith Busch
}
832 f3c507ad Keith Busch
833 f3c507ad Keith Busch
static void nvme_exit(PCIDevice *pci_dev)
834 f3c507ad Keith Busch
{
835 f3c507ad Keith Busch
    NvmeCtrl *n = NVME(pci_dev);
836 f3c507ad Keith Busch
837 f3c507ad Keith Busch
    nvme_clear_ctrl(n);
838 f3c507ad Keith Busch
    g_free(n->namespaces);
839 f3c507ad Keith Busch
    g_free(n->cq);
840 f3c507ad Keith Busch
    g_free(n->sq);
841 f3c507ad Keith Busch
    msix_uninit_exclusive_bar(pci_dev);
842 f3c507ad Keith Busch
    memory_region_destroy(&n->iomem);
843 f3c507ad Keith Busch
}
844 f3c507ad Keith Busch
845 f3c507ad Keith Busch
static Property nvme_props[] = {
846 f3c507ad Keith Busch
    DEFINE_BLOCK_PROPERTIES(NvmeCtrl, conf),
847 f3c507ad Keith Busch
    DEFINE_PROP_STRING("serial", NvmeCtrl, serial),
848 f3c507ad Keith Busch
    DEFINE_PROP_END_OF_LIST(),
849 f3c507ad Keith Busch
};
850 f3c507ad Keith Busch
851 f3c507ad Keith Busch
static const VMStateDescription nvme_vmstate = {
852 f3c507ad Keith Busch
    .name = "nvme",
853 f3c507ad Keith Busch
    .unmigratable = 1,
854 f3c507ad Keith Busch
};
855 f3c507ad Keith Busch
856 f3c507ad Keith Busch
static void nvme_class_init(ObjectClass *oc, void *data)
857 f3c507ad Keith Busch
{
858 f3c507ad Keith Busch
    DeviceClass *dc = DEVICE_CLASS(oc);
859 f3c507ad Keith Busch
    PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
860 f3c507ad Keith Busch
861 f3c507ad Keith Busch
    pc->init = nvme_init;
862 f3c507ad Keith Busch
    pc->exit = nvme_exit;
863 f3c507ad Keith Busch
    pc->class_id = PCI_CLASS_STORAGE_EXPRESS;
864 f3c507ad Keith Busch
    pc->vendor_id = PCI_VENDOR_ID_INTEL;
865 f3c507ad Keith Busch
    pc->device_id = 0x5845;
866 f3c507ad Keith Busch
    pc->revision = 1;
867 f3c507ad Keith Busch
    pc->is_express = 1;
868 f3c507ad Keith Busch
869 125ee0ed Marcel Apfelbaum
    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
870 f3c507ad Keith Busch
    dc->desc = "Non-Volatile Memory Express";
871 f3c507ad Keith Busch
    dc->props = nvme_props;
872 f3c507ad Keith Busch
    dc->vmsd = &nvme_vmstate;
873 f3c507ad Keith Busch
}
874 f3c507ad Keith Busch
875 f3c507ad Keith Busch
static const TypeInfo nvme_info = {
876 f3c507ad Keith Busch
    .name          = "nvme",
877 f3c507ad Keith Busch
    .parent        = TYPE_PCI_DEVICE,
878 f3c507ad Keith Busch
    .instance_size = sizeof(NvmeCtrl),
879 f3c507ad Keith Busch
    .class_init    = nvme_class_init,
880 f3c507ad Keith Busch
};
881 f3c507ad Keith Busch
882 f3c507ad Keith Busch
static void nvme_register_types(void)
883 f3c507ad Keith Busch
{
884 f3c507ad Keith Busch
    type_register_static(&nvme_info);
885 f3c507ad Keith Busch
}
886 f3c507ad Keith Busch
887 f3c507ad Keith Busch
type_init(nvme_register_types)