X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=block%2Fnvme.c;h=73ed5fa75f2e6c8833a9b7c09e8bcce93c9b8eee;hb=c4107e8208d0222f9b328691b519aaee4101db87;hp=75078022f6e3460fe43faa1879313d54787a028c;hpb=8cb340c613ee3e626b070e0429c589f8a60ac657;p=mirror_qemu.git diff --git a/block/nvme.c b/block/nvme.c index 75078022f6..73ed5fa75f 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -17,6 +17,7 @@ #include "qapi/qmp/qdict.h" #include "qapi/qmp/qstring.h" #include "qemu/error-report.h" +#include "qemu/module.h" #include "qemu/cutils.h" #include "qemu/option.h" #include "qemu/vfio-helpers.h" @@ -82,7 +83,7 @@ typedef volatile struct { uint8_t reserved1[0xec0]; uint8_t cmd_set_specfic[0x100]; uint32_t doorbells[]; -} QEMU_PACKED NVMeRegs; +} NVMeRegs; QEMU_BUILD_BUG_ON(offsetof(NVMeRegs, doorbells) != 0x1000); @@ -104,13 +105,16 @@ typedef struct { uint64_t nsze; /* Namespace size reported by identify command */ int nsid; /* The namespace id to read/write data. */ uint64_t max_transfer; - int plugged; + bool plugged; CoMutex dma_map_lock; CoQueue dma_flush_queue; /* Total size of mapped qiov, accessed under dma_map_lock */ int dma_map_count; + + /* PCI address (required for nvme_refresh_filename()) */ + char *device; } BDRVNVMeState; #define NVME_BLOCK_OPT_DEVICE "device" @@ -390,6 +394,7 @@ static void nvme_cmd_sync_cb(void *opaque, int ret) { int *pret = opaque; *pret = ret; + aio_wait_kick(); } static int nvme_cmd_sync(BlockDriverState *bs, NVMeQueuePair *q, @@ -489,10 +494,8 @@ static void nvme_handle_event(EventNotifier *n) BDRVNVMeState *s = container_of(n, BDRVNVMeState, irq_notifier); trace_nvme_handle_event(s); - aio_context_acquire(s->aio_context); event_notifier_test_and_clear(n); nvme_poll_queues(s); - aio_context_release(s->aio_context); } static bool nvme_add_io_queue(BlockDriverState *bs, Error **errp) @@ -558,6 +561,7 @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace, qemu_co_mutex_init(&s->dma_map_lock); qemu_co_queue_init(&s->dma_flush_queue); + s->device = g_strdup(device); s->nsid = namespace; s->aio_context = bdrv_get_aio_context(bs); ret = event_notifier_init(&s->irq_notifier, 0); @@ -569,13 +573,13 @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace, s->vfio = qemu_vfio_open_pci(device, errp); if (!s->vfio) { ret = -EINVAL; - goto fail; + goto out; } s->regs = qemu_vfio_pci_map_bar(s->vfio, 0, 0, NVME_BAR_SIZE, errp); if (!s->regs) { ret = -EINVAL; - goto fail; + goto out; } /* Perform initialize sequence as described in NVMe spec "7.6.1 @@ -585,7 +589,7 @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace, if (!(cap & (1ULL << 37))) { error_setg(errp, "Device doesn't support NVMe command set"); ret = -EINVAL; - goto fail; + goto out; } s->page_size = MAX(4096, 1 << (12 + ((cap >> 48) & 0xF))); @@ -603,7 +607,7 @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace, PRId64 " ms)", timeout_ms); ret = -ETIMEDOUT; - goto fail; + goto out; } } @@ -613,7 +617,7 @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace, s->queues[0] = nvme_create_queue_pair(bs, 0, NVME_QUEUE_SIZE, errp); if (!s->queues[0]) { ret = -EINVAL; - goto fail; + goto out; } QEMU_BUILD_BUG_ON(NVME_QUEUE_SIZE & 0xF000); s->regs->aqa = cpu_to_le32((NVME_QUEUE_SIZE << 16) | NVME_QUEUE_SIZE); @@ -633,14 +637,14 @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace, PRId64 " ms)", timeout_ms); ret = -ETIMEDOUT; - goto fail_queue; + goto out; } } ret = qemu_vfio_pci_init_irq(s->vfio, &s->irq_notifier, VFIO_PCI_MSIX_IRQ_INDEX, errp); if (ret) { - goto fail_queue; + goto out; } aio_set_event_notifier(bdrv_get_aio_context(bs), &s->irq_notifier, false, nvme_handle_event, nvme_poll_cb); @@ -649,30 +653,15 @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace, if (local_err) { error_propagate(errp, local_err); ret = -EIO; - goto fail_handler; + goto out; } /* Set up command queues. */ if (!nvme_add_io_queue(bs, errp)) { ret = -EIO; - goto fail_handler; - } - return 0; - -fail_handler: - aio_set_event_notifier(bdrv_get_aio_context(bs), &s->irq_notifier, - false, NULL, NULL); -fail_queue: - nvme_free_queue_pair(bs, s->queues[0]); -fail: - g_free(s->queues); - if (s->regs) { - qemu_vfio_pci_unmap_bar(s->vfio, 0, (void *)s->regs, 0, NVME_BAR_SIZE); } - if (s->vfio) { - qemu_vfio_close(s->vfio); - } - event_notifier_cleanup(&s->irq_notifier); +out: + /* Cleaning up is done in nvme_file_open() upon error. */ return ret; } @@ -695,12 +684,11 @@ static void nvme_parse_filename(const char *filename, QDict *options, unsigned long ns; const char *slash = strchr(tmp, '/'); if (!slash) { - qdict_put(options, NVME_BLOCK_OPT_DEVICE, - qstring_from_str(tmp)); + qdict_put_str(options, NVME_BLOCK_OPT_DEVICE, tmp); return; } device = g_strndup(tmp, slash - tmp); - qdict_put(options, NVME_BLOCK_OPT_DEVICE, qstring_from_str(device)); + qdict_put_str(options, NVME_BLOCK_OPT_DEVICE, device); g_free(device); namespace = slash + 1; if (*namespace && qemu_strtoul(namespace, NULL, 10, &ns)) { @@ -708,8 +696,8 @@ static void nvme_parse_filename(const char *filename, QDict *options, namespace); return; } - qdict_put(options, NVME_BLOCK_OPT_NAMESPACE, - qstring_from_str(*namespace ? namespace : "1")); + qdict_put_str(options, NVME_BLOCK_OPT_NAMESPACE, + *namespace ? namespace : "1"); } } @@ -740,10 +728,14 @@ static void nvme_close(BlockDriverState *bs) for (i = 0; i < s->nr_queues; ++i) { nvme_free_queue_pair(bs, s->queues[i]); } + g_free(s->queues); aio_set_event_notifier(bdrv_get_aio_context(bs), &s->irq_notifier, false, NULL, NULL); + event_notifier_cleanup(&s->irq_notifier); qemu_vfio_pci_unmap_bar(s->vfio, 0, (void *)s->regs, 0, NVME_BAR_SIZE); qemu_vfio_close(s->vfio); + + g_free(s->device); } static int nvme_file_open(BlockDriverState *bs, QDict *options, int flags, @@ -853,7 +845,7 @@ try_map: } for (j = 0; j < qiov->iov[i].iov_len / s->page_size; j++) { - pagelist[entries++] = iova + j * s->page_size; + pagelist[entries++] = cpu_to_le64(iova + j * s->page_size); } trace_nvme_cmd_map_qiov_iov(s, i, qiov->iov[i].iov_base, qiov->iov[i].iov_len / s->page_size); @@ -866,20 +858,16 @@ try_map: case 0: abort(); case 1: - cmd->prp1 = cpu_to_le64(pagelist[0]); + cmd->prp1 = pagelist[0]; cmd->prp2 = 0; break; case 2: - cmd->prp1 = cpu_to_le64(pagelist[0]); - cmd->prp2 = cpu_to_le64(pagelist[1]);; + cmd->prp1 = pagelist[0]; + cmd->prp2 = pagelist[1]; break; default: - cmd->prp1 = cpu_to_le64(pagelist[0]); - cmd->prp2 = cpu_to_le64(req->prp_list_iova); - for (i = 0; i < entries - 1; ++i) { - pagelist[i] = cpu_to_le64(pagelist[i + 1]); - } - pagelist[entries - 1] = 0; + cmd->prp1 = pagelist[0]; + cmd->prp2 = cpu_to_le64(req->prp_list_iova + sizeof(uint64_t)); break; } trace_nvme_cmd_map_qiov(s, cmd, req, qiov, entries); @@ -1072,30 +1060,12 @@ static int nvme_reopen_prepare(BDRVReopenState *reopen_state, return 0; } -static int64_t coroutine_fn nvme_co_get_block_status(BlockDriverState *bs, - int64_t sector_num, - int nb_sectors, int *pnum, - BlockDriverState **file) +static void nvme_refresh_filename(BlockDriverState *bs) { - *pnum = nb_sectors; - *file = bs; - - return BDRV_BLOCK_ALLOCATED | BDRV_BLOCK_OFFSET_VALID | - (sector_num << BDRV_SECTOR_BITS); -} - -static void nvme_refresh_filename(BlockDriverState *bs, QDict *opts) -{ - QINCREF(opts); - qdict_del(opts, "filename"); - - if (!qdict_size(opts)) { - snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://", - bs->drv->format_name); - } + BDRVNVMeState *s = bs->opaque; - qdict_put(opts, "driver", qstring_from_str(bs->drv->format_name)); - bs->full_open_options = opts; + snprintf(bs->exact_filename, sizeof(bs->exact_filename), "nvme://%s/%i", + s->device, s->nsid); } static void nvme_refresh_limits(BlockDriverState *bs, Error **errp) @@ -1128,7 +1098,8 @@ static void nvme_attach_aio_context(BlockDriverState *bs, static void nvme_aio_plug(BlockDriverState *bs) { BDRVNVMeState *s = bs->opaque; - s->plugged++; + assert(!s->plugged); + s->plugged = true; } static void nvme_aio_unplug(BlockDriverState *bs) @@ -1136,14 +1107,13 @@ static void nvme_aio_unplug(BlockDriverState *bs) int i; BDRVNVMeState *s = bs->opaque; assert(s->plugged); - if (!--s->plugged) { - for (i = 1; i < s->nr_queues; i++) { - NVMeQueuePair *q = s->queues[i]; - qemu_mutex_lock(&q->lock); - nvme_kick(s, q); - nvme_process_completion(s, q); - qemu_mutex_unlock(&q->lock); - } + s->plugged = false; + for (i = 1; i < s->nr_queues; i++) { + NVMeQueuePair *q = s->queues[i]; + qemu_mutex_lock(&q->lock); + nvme_kick(s, q); + nvme_process_completion(s, q); + qemu_mutex_unlock(&q->lock); } } @@ -1168,6 +1138,13 @@ static void nvme_unregister_buf(BlockDriverState *bs, void *host) qemu_vfio_dma_unmap(s->vfio, host); } +static const char *const nvme_strong_runtime_opts[] = { + NVME_BLOCK_OPT_DEVICE, + NVME_BLOCK_OPT_NAMESPACE, + + NULL +}; + static BlockDriver bdrv_nvme = { .format_name = "nvme", .protocol_name = "nvme", @@ -1183,10 +1160,9 @@ static BlockDriver bdrv_nvme = { .bdrv_co_flush_to_disk = nvme_co_flush, .bdrv_reopen_prepare = nvme_reopen_prepare, - .bdrv_co_get_block_status = nvme_co_get_block_status, - .bdrv_refresh_filename = nvme_refresh_filename, .bdrv_refresh_limits = nvme_refresh_limits, + .strong_runtime_opts = nvme_strong_runtime_opts, .bdrv_detach_aio_context = nvme_detach_aio_context, .bdrv_attach_aio_context = nvme_attach_aio_context,