2 * QEMU NVM Express Virtual Namespace
4 * Copyright (c) 2019 CNEX Labs
5 * Copyright (c) 2020 Samsung Electronics
8 * Klaus Jensen <k.jensen@samsung.com>
10 * This work is licensed under the terms of the GNU GPL, version 2. See the
11 * COPYING file in the top-level directory.
15 #include "qemu/osdep.h"
16 #include "qemu/units.h"
17 #include "qemu/cutils.h"
19 #include "hw/block/block.h"
20 #include "hw/pci/pci.h"
21 #include "sysemu/sysemu.h"
22 #include "sysemu/block-backend.h"
23 #include "qapi/error.h"
25 #include "hw/qdev-properties.h"
26 #include "hw/qdev-core.h"
31 #define MIN_DISCARD_GRANULARITY (4 * KiB)
33 static int nvme_ns_init(NvmeNamespace
*ns
, Error
**errp
)
36 NvmeIdNs
*id_ns
= &ns
->id_ns
;
37 int lba_index
= NVME_ID_NS_FLBAS_INDEX(ns
->id_ns
.flbas
);
40 ns
->id_ns
.dlfeat
= 0x9;
42 id_ns
->lbaf
[lba_index
].ds
= 31 - clz32(ns
->blkconf
.logical_block_size
);
44 id_ns
->nsze
= cpu_to_le64(nvme_ns_nlbas(ns
));
46 /* no thin provisioning */
47 id_ns
->ncap
= id_ns
->nsze
;
48 id_ns
->nuse
= id_ns
->ncap
;
50 /* support DULBE and I/O optimization fields */
51 id_ns
->nsfeat
|= (0x4 | 0x10);
53 npdg
= ns
->blkconf
.discard_granularity
/ ns
->blkconf
.logical_block_size
;
55 if (bdrv_get_info(blk_bs(ns
->blkconf
.blk
), &bdi
) >= 0 &&
56 bdi
.cluster_size
> ns
->blkconf
.discard_granularity
) {
57 npdg
= bdi
.cluster_size
/ ns
->blkconf
.logical_block_size
;
60 id_ns
->npda
= id_ns
->npdg
= npdg
- 1;
65 static int nvme_ns_init_blk(NvmeCtrl
*n
, NvmeNamespace
*ns
, Error
**errp
)
69 if (!blkconf_blocksizes(&ns
->blkconf
, errp
)) {
73 read_only
= !blk_supports_write_perm(ns
->blkconf
.blk
);
74 if (!blkconf_apply_backend_options(&ns
->blkconf
, read_only
, false, errp
)) {
78 if (ns
->blkconf
.discard_granularity
== -1) {
79 ns
->blkconf
.discard_granularity
=
80 MAX(ns
->blkconf
.logical_block_size
, MIN_DISCARD_GRANULARITY
);
83 ns
->size
= blk_getlength(ns
->blkconf
.blk
);
85 error_setg_errno(errp
, -ns
->size
, "could not get blockdev size");
89 if (blk_enable_write_cache(ns
->blkconf
.blk
)) {
90 n
->features
.vwc
= 0x1;
96 static int nvme_ns_check_constraints(NvmeNamespace
*ns
, Error
**errp
)
98 if (!ns
->blkconf
.blk
) {
99 error_setg(errp
, "block backend not configured");
106 int nvme_ns_setup(NvmeCtrl
*n
, NvmeNamespace
*ns
, Error
**errp
)
108 if (nvme_ns_check_constraints(ns
, errp
)) {
112 if (nvme_ns_init_blk(n
, ns
, errp
)) {
116 if (nvme_ns_init(ns
, errp
)) {
120 if (nvme_register_namespace(n
, ns
, errp
)) {
127 void nvme_ns_drain(NvmeNamespace
*ns
)
129 blk_drain(ns
->blkconf
.blk
);
132 void nvme_ns_flush(NvmeNamespace
*ns
)
134 blk_flush(ns
->blkconf
.blk
);
137 static void nvme_ns_realize(DeviceState
*dev
, Error
**errp
)
139 NvmeNamespace
*ns
= NVME_NS(dev
);
140 BusState
*s
= qdev_get_parent_bus(dev
);
141 NvmeCtrl
*n
= NVME(s
->parent
);
142 Error
*local_err
= NULL
;
144 if (nvme_ns_setup(n
, ns
, &local_err
)) {
145 error_propagate_prepend(errp
, local_err
,
146 "could not setup namespace: ");
151 static Property nvme_ns_props
[] = {
152 DEFINE_BLOCK_PROPERTIES(NvmeNamespace
, blkconf
),
153 DEFINE_PROP_UINT32("nsid", NvmeNamespace
, params
.nsid
, 0),
154 DEFINE_PROP_END_OF_LIST(),
157 static void nvme_ns_class_init(ObjectClass
*oc
, void *data
)
159 DeviceClass
*dc
= DEVICE_CLASS(oc
);
161 set_bit(DEVICE_CATEGORY_STORAGE
, dc
->categories
);
163 dc
->bus_type
= TYPE_NVME_BUS
;
164 dc
->realize
= nvme_ns_realize
;
165 device_class_set_props(dc
, nvme_ns_props
);
166 dc
->desc
= "Virtual NVMe namespace";
169 static void nvme_ns_instance_init(Object
*obj
)
171 NvmeNamespace
*ns
= NVME_NS(obj
);
172 char *bootindex
= g_strdup_printf("/namespace@%d,0", ns
->params
.nsid
);
174 device_add_bootindex_property(obj
, &ns
->bootindex
, "bootindex",
175 bootindex
, DEVICE(obj
));
180 static const TypeInfo nvme_ns_info
= {
181 .name
= TYPE_NVME_NS
,
182 .parent
= TYPE_DEVICE
,
183 .class_init
= nvme_ns_class_init
,
184 .instance_size
= sizeof(NvmeNamespace
),
185 .instance_init
= nvme_ns_instance_init
,
188 static void nvme_ns_register_types(void)
190 type_register_static(&nvme_ns_info
);
193 type_init(nvme_ns_register_types
)