17f0f1aceSKlaus Jensen /* 27f0f1aceSKlaus Jensen * QEMU NVM Express Virtual Namespace 37f0f1aceSKlaus Jensen * 47f0f1aceSKlaus Jensen * Copyright (c) 2019 CNEX Labs 57f0f1aceSKlaus Jensen * Copyright (c) 2020 Samsung Electronics 67f0f1aceSKlaus Jensen * 77f0f1aceSKlaus Jensen * Authors: 87f0f1aceSKlaus Jensen * Klaus Jensen <k.jensen@samsung.com> 97f0f1aceSKlaus Jensen * 107f0f1aceSKlaus Jensen * This work is licensed under the terms of the GNU GPL, version 2. See the 117f0f1aceSKlaus Jensen * COPYING file in the top-level directory. 127f0f1aceSKlaus Jensen * 137f0f1aceSKlaus Jensen */ 147f0f1aceSKlaus Jensen 157f0f1aceSKlaus Jensen #include "qemu/osdep.h" 167f0f1aceSKlaus Jensen #include "qemu/units.h" 177f0f1aceSKlaus Jensen #include "qemu/cutils.h" 187f0f1aceSKlaus Jensen #include "qemu/log.h" 197f0f1aceSKlaus Jensen #include "hw/block/block.h" 207f0f1aceSKlaus Jensen #include "hw/pci/pci.h" 217f0f1aceSKlaus Jensen #include "sysemu/sysemu.h" 227f0f1aceSKlaus Jensen #include "sysemu/block-backend.h" 237f0f1aceSKlaus Jensen #include "qapi/error.h" 247f0f1aceSKlaus Jensen 257f0f1aceSKlaus Jensen #include "hw/qdev-properties.h" 267f0f1aceSKlaus Jensen #include "hw/qdev-core.h" 277f0f1aceSKlaus Jensen 287f0f1aceSKlaus Jensen #include "nvme.h" 297f0f1aceSKlaus Jensen #include "nvme-ns.h" 307f0f1aceSKlaus Jensen 312605257aSKlaus Jensen #define MIN_DISCARD_GRANULARITY (4 * KiB) 322605257aSKlaus Jensen 332605257aSKlaus Jensen static int nvme_ns_init(NvmeNamespace *ns, Error **errp) 347f0f1aceSKlaus Jensen { 352605257aSKlaus Jensen BlockDriverInfo bdi; 367f0f1aceSKlaus Jensen NvmeIdNs *id_ns = &ns->id_ns; 37b865cabfSDmitry Fomichev int lba_index = NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas); 382605257aSKlaus Jensen int npdg; 397f0f1aceSKlaus Jensen 407f0f1aceSKlaus Jensen ns->id_ns.dlfeat = 0x9; 417f0f1aceSKlaus Jensen 42b865cabfSDmitry Fomichev id_ns->lbaf[lba_index].ds = 31 - clz32(ns->blkconf.logical_block_size); 437f0f1aceSKlaus Jensen 447f0f1aceSKlaus Jensen id_ns->nsze = cpu_to_le64(nvme_ns_nlbas(ns)); 457f0f1aceSKlaus Jensen 467f0f1aceSKlaus Jensen /* no thin provisioning */ 477f0f1aceSKlaus Jensen id_ns->ncap = id_ns->nsze; 487f0f1aceSKlaus Jensen id_ns->nuse = id_ns->ncap; 4954064e51SKlaus Jensen 502605257aSKlaus Jensen /* support DULBE and I/O optimization fields */ 512605257aSKlaus Jensen id_ns->nsfeat |= (0x4 | 0x10); 522605257aSKlaus Jensen 532605257aSKlaus Jensen npdg = ns->blkconf.discard_granularity / ns->blkconf.logical_block_size; 542605257aSKlaus Jensen 552605257aSKlaus Jensen if (bdrv_get_info(blk_bs(ns->blkconf.blk), &bdi) >= 0 && 562605257aSKlaus Jensen bdi.cluster_size > ns->blkconf.discard_granularity) { 572605257aSKlaus Jensen npdg = bdi.cluster_size / ns->blkconf.logical_block_size; 582605257aSKlaus Jensen } 592605257aSKlaus Jensen 602605257aSKlaus Jensen id_ns->npda = id_ns->npdg = npdg - 1; 612605257aSKlaus Jensen 622605257aSKlaus Jensen return 0; 637f0f1aceSKlaus Jensen } 647f0f1aceSKlaus Jensen 657f0f1aceSKlaus Jensen static int nvme_ns_init_blk(NvmeCtrl *n, NvmeNamespace *ns, Error **errp) 667f0f1aceSKlaus Jensen { 6786b1cf32SKevin Wolf bool read_only; 6886b1cf32SKevin Wolf 697f0f1aceSKlaus Jensen if (!blkconf_blocksizes(&ns->blkconf, errp)) { 707f0f1aceSKlaus Jensen return -1; 717f0f1aceSKlaus Jensen } 727f0f1aceSKlaus Jensen 7386b1cf32SKevin Wolf read_only = !blk_supports_write_perm(ns->blkconf.blk); 7486b1cf32SKevin Wolf if (!blkconf_apply_backend_options(&ns->blkconf, read_only, false, errp)) { 757f0f1aceSKlaus Jensen return -1; 767f0f1aceSKlaus Jensen } 777f0f1aceSKlaus Jensen 782605257aSKlaus Jensen if (ns->blkconf.discard_granularity == -1) { 792605257aSKlaus Jensen ns->blkconf.discard_granularity = 802605257aSKlaus Jensen MAX(ns->blkconf.logical_block_size, MIN_DISCARD_GRANULARITY); 812605257aSKlaus Jensen } 822605257aSKlaus Jensen 837f0f1aceSKlaus Jensen ns->size = blk_getlength(ns->blkconf.blk); 847f0f1aceSKlaus Jensen if (ns->size < 0) { 857f0f1aceSKlaus Jensen error_setg_errno(errp, -ns->size, "could not get blockdev size"); 867f0f1aceSKlaus Jensen return -1; 877f0f1aceSKlaus Jensen } 887f0f1aceSKlaus Jensen 897f0f1aceSKlaus Jensen if (blk_enable_write_cache(ns->blkconf.blk)) { 907f0f1aceSKlaus Jensen n->features.vwc = 0x1; 917f0f1aceSKlaus Jensen } 927f0f1aceSKlaus Jensen 937f0f1aceSKlaus Jensen return 0; 947f0f1aceSKlaus Jensen } 957f0f1aceSKlaus Jensen 967f0f1aceSKlaus Jensen static int nvme_ns_check_constraints(NvmeNamespace *ns, Error **errp) 977f0f1aceSKlaus Jensen { 987f0f1aceSKlaus Jensen if (!ns->blkconf.blk) { 997f0f1aceSKlaus Jensen error_setg(errp, "block backend not configured"); 1007f0f1aceSKlaus Jensen return -1; 1017f0f1aceSKlaus Jensen } 1027f0f1aceSKlaus Jensen 1037f0f1aceSKlaus Jensen return 0; 1047f0f1aceSKlaus Jensen } 1057f0f1aceSKlaus Jensen 1067f0f1aceSKlaus Jensen int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp) 1077f0f1aceSKlaus Jensen { 1087f0f1aceSKlaus Jensen if (nvme_ns_check_constraints(ns, errp)) { 1097f0f1aceSKlaus Jensen return -1; 1107f0f1aceSKlaus Jensen } 1117f0f1aceSKlaus Jensen 1127f0f1aceSKlaus Jensen if (nvme_ns_init_blk(n, ns, errp)) { 1137f0f1aceSKlaus Jensen return -1; 1147f0f1aceSKlaus Jensen } 1157f0f1aceSKlaus Jensen 1162605257aSKlaus Jensen if (nvme_ns_init(ns, errp)) { 1172605257aSKlaus Jensen return -1; 1182605257aSKlaus Jensen } 11954064e51SKlaus Jensen 1207f0f1aceSKlaus Jensen if (nvme_register_namespace(n, ns, errp)) { 1217f0f1aceSKlaus Jensen return -1; 1227f0f1aceSKlaus Jensen } 1237f0f1aceSKlaus Jensen 1247f0f1aceSKlaus Jensen return 0; 1257f0f1aceSKlaus Jensen } 1267f0f1aceSKlaus Jensen 1277f0f1aceSKlaus Jensen void nvme_ns_drain(NvmeNamespace *ns) 1287f0f1aceSKlaus Jensen { 1297f0f1aceSKlaus Jensen blk_drain(ns->blkconf.blk); 1307f0f1aceSKlaus Jensen } 1317f0f1aceSKlaus Jensen 132ba69f224SDmitry Fomichev void nvme_ns_shutdown(NvmeNamespace *ns) 1337f0f1aceSKlaus Jensen { 1347f0f1aceSKlaus Jensen blk_flush(ns->blkconf.blk); 1357f0f1aceSKlaus Jensen } 1367f0f1aceSKlaus Jensen 1377f0f1aceSKlaus Jensen static void nvme_ns_realize(DeviceState *dev, Error **errp) 1387f0f1aceSKlaus Jensen { 1397f0f1aceSKlaus Jensen NvmeNamespace *ns = NVME_NS(dev); 1407f0f1aceSKlaus Jensen BusState *s = qdev_get_parent_bus(dev); 1417f0f1aceSKlaus Jensen NvmeCtrl *n = NVME(s->parent); 1427f0f1aceSKlaus Jensen Error *local_err = NULL; 1437f0f1aceSKlaus Jensen 1447f0f1aceSKlaus Jensen if (nvme_ns_setup(n, ns, &local_err)) { 1457f0f1aceSKlaus Jensen error_propagate_prepend(errp, local_err, 1467f0f1aceSKlaus Jensen "could not setup namespace: "); 1477f0f1aceSKlaus Jensen return; 1487f0f1aceSKlaus Jensen } 1497f0f1aceSKlaus Jensen } 1507f0f1aceSKlaus Jensen 1517f0f1aceSKlaus Jensen static Property nvme_ns_props[] = { 1527f0f1aceSKlaus Jensen DEFINE_BLOCK_PROPERTIES(NvmeNamespace, blkconf), 1537f0f1aceSKlaus Jensen DEFINE_PROP_UINT32("nsid", NvmeNamespace, params.nsid, 0), 154*b52f26cdSDmitry Fomichev DEFINE_PROP_UUID("uuid", NvmeNamespace, params.uuid), 1557f0f1aceSKlaus Jensen DEFINE_PROP_END_OF_LIST(), 1567f0f1aceSKlaus Jensen }; 1577f0f1aceSKlaus Jensen 1587f0f1aceSKlaus Jensen static void nvme_ns_class_init(ObjectClass *oc, void *data) 1597f0f1aceSKlaus Jensen { 1607f0f1aceSKlaus Jensen DeviceClass *dc = DEVICE_CLASS(oc); 1617f0f1aceSKlaus Jensen 1627f0f1aceSKlaus Jensen set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); 1637f0f1aceSKlaus Jensen 1647f0f1aceSKlaus Jensen dc->bus_type = TYPE_NVME_BUS; 1657f0f1aceSKlaus Jensen dc->realize = nvme_ns_realize; 1667f0f1aceSKlaus Jensen device_class_set_props(dc, nvme_ns_props); 1677f0f1aceSKlaus Jensen dc->desc = "Virtual NVMe namespace"; 1687f0f1aceSKlaus Jensen } 1697f0f1aceSKlaus Jensen 1707f0f1aceSKlaus Jensen static void nvme_ns_instance_init(Object *obj) 1717f0f1aceSKlaus Jensen { 1727f0f1aceSKlaus Jensen NvmeNamespace *ns = NVME_NS(obj); 1737f0f1aceSKlaus Jensen char *bootindex = g_strdup_printf("/namespace@%d,0", ns->params.nsid); 1747f0f1aceSKlaus Jensen 1757f0f1aceSKlaus Jensen device_add_bootindex_property(obj, &ns->bootindex, "bootindex", 1767f0f1aceSKlaus Jensen bootindex, DEVICE(obj)); 1777f0f1aceSKlaus Jensen 1787f0f1aceSKlaus Jensen g_free(bootindex); 1797f0f1aceSKlaus Jensen } 1807f0f1aceSKlaus Jensen 1817f0f1aceSKlaus Jensen static const TypeInfo nvme_ns_info = { 1827f0f1aceSKlaus Jensen .name = TYPE_NVME_NS, 1837f0f1aceSKlaus Jensen .parent = TYPE_DEVICE, 1847f0f1aceSKlaus Jensen .class_init = nvme_ns_class_init, 1857f0f1aceSKlaus Jensen .instance_size = sizeof(NvmeNamespace), 1867f0f1aceSKlaus Jensen .instance_init = nvme_ns_instance_init, 1877f0f1aceSKlaus Jensen }; 1887f0f1aceSKlaus Jensen 1897f0f1aceSKlaus Jensen static void nvme_ns_register_types(void) 1907f0f1aceSKlaus Jensen { 1917f0f1aceSKlaus Jensen type_register_static(&nvme_ns_info); 1927f0f1aceSKlaus Jensen } 1937f0f1aceSKlaus Jensen 1947f0f1aceSKlaus Jensen type_init(nvme_ns_register_types) 195