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 317f0f1aceSKlaus Jensen static void nvme_ns_init(NvmeNamespace *ns) 327f0f1aceSKlaus Jensen { 337f0f1aceSKlaus Jensen NvmeIdNs *id_ns = &ns->id_ns; 34b865cabfSDmitry Fomichev int lba_index = NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas); 357f0f1aceSKlaus Jensen 367f0f1aceSKlaus Jensen if (blk_get_flags(ns->blkconf.blk) & BDRV_O_UNMAP) { 377f0f1aceSKlaus Jensen ns->id_ns.dlfeat = 0x9; 387f0f1aceSKlaus Jensen } 397f0f1aceSKlaus Jensen 40b865cabfSDmitry Fomichev id_ns->lbaf[lba_index].ds = 31 - clz32(ns->blkconf.logical_block_size); 417f0f1aceSKlaus Jensen 427f0f1aceSKlaus Jensen id_ns->nsze = cpu_to_le64(nvme_ns_nlbas(ns)); 437f0f1aceSKlaus Jensen 447f0f1aceSKlaus Jensen /* no thin provisioning */ 457f0f1aceSKlaus Jensen id_ns->ncap = id_ns->nsze; 467f0f1aceSKlaus Jensen id_ns->nuse = id_ns->ncap; 477f0f1aceSKlaus Jensen } 487f0f1aceSKlaus Jensen 497f0f1aceSKlaus Jensen static int nvme_ns_init_blk(NvmeCtrl *n, NvmeNamespace *ns, Error **errp) 507f0f1aceSKlaus Jensen { 51*86b1cf32SKevin Wolf bool read_only; 52*86b1cf32SKevin Wolf 537f0f1aceSKlaus Jensen if (!blkconf_blocksizes(&ns->blkconf, errp)) { 547f0f1aceSKlaus Jensen return -1; 557f0f1aceSKlaus Jensen } 567f0f1aceSKlaus Jensen 57*86b1cf32SKevin Wolf read_only = !blk_supports_write_perm(ns->blkconf.blk); 58*86b1cf32SKevin Wolf if (!blkconf_apply_backend_options(&ns->blkconf, read_only, false, errp)) { 597f0f1aceSKlaus Jensen return -1; 607f0f1aceSKlaus Jensen } 617f0f1aceSKlaus Jensen 627f0f1aceSKlaus Jensen ns->size = blk_getlength(ns->blkconf.blk); 637f0f1aceSKlaus Jensen if (ns->size < 0) { 647f0f1aceSKlaus Jensen error_setg_errno(errp, -ns->size, "could not get blockdev size"); 657f0f1aceSKlaus Jensen return -1; 667f0f1aceSKlaus Jensen } 677f0f1aceSKlaus Jensen 687f0f1aceSKlaus Jensen if (blk_enable_write_cache(ns->blkconf.blk)) { 697f0f1aceSKlaus Jensen n->features.vwc = 0x1; 707f0f1aceSKlaus Jensen } 717f0f1aceSKlaus Jensen 727f0f1aceSKlaus Jensen return 0; 737f0f1aceSKlaus Jensen } 747f0f1aceSKlaus Jensen 757f0f1aceSKlaus Jensen static int nvme_ns_check_constraints(NvmeNamespace *ns, Error **errp) 767f0f1aceSKlaus Jensen { 777f0f1aceSKlaus Jensen if (!ns->blkconf.blk) { 787f0f1aceSKlaus Jensen error_setg(errp, "block backend not configured"); 797f0f1aceSKlaus Jensen return -1; 807f0f1aceSKlaus Jensen } 817f0f1aceSKlaus Jensen 827f0f1aceSKlaus Jensen return 0; 837f0f1aceSKlaus Jensen } 847f0f1aceSKlaus Jensen 857f0f1aceSKlaus Jensen int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp) 867f0f1aceSKlaus Jensen { 877f0f1aceSKlaus Jensen if (nvme_ns_check_constraints(ns, errp)) { 887f0f1aceSKlaus Jensen return -1; 897f0f1aceSKlaus Jensen } 907f0f1aceSKlaus Jensen 917f0f1aceSKlaus Jensen if (nvme_ns_init_blk(n, ns, errp)) { 927f0f1aceSKlaus Jensen return -1; 937f0f1aceSKlaus Jensen } 947f0f1aceSKlaus Jensen 957f0f1aceSKlaus Jensen nvme_ns_init(ns); 967f0f1aceSKlaus Jensen if (nvme_register_namespace(n, ns, errp)) { 977f0f1aceSKlaus Jensen return -1; 987f0f1aceSKlaus Jensen } 997f0f1aceSKlaus Jensen 1007f0f1aceSKlaus Jensen return 0; 1017f0f1aceSKlaus Jensen } 1027f0f1aceSKlaus Jensen 1037f0f1aceSKlaus Jensen void nvme_ns_drain(NvmeNamespace *ns) 1047f0f1aceSKlaus Jensen { 1057f0f1aceSKlaus Jensen blk_drain(ns->blkconf.blk); 1067f0f1aceSKlaus Jensen } 1077f0f1aceSKlaus Jensen 1087f0f1aceSKlaus Jensen void nvme_ns_flush(NvmeNamespace *ns) 1097f0f1aceSKlaus Jensen { 1107f0f1aceSKlaus Jensen blk_flush(ns->blkconf.blk); 1117f0f1aceSKlaus Jensen } 1127f0f1aceSKlaus Jensen 1137f0f1aceSKlaus Jensen static void nvme_ns_realize(DeviceState *dev, Error **errp) 1147f0f1aceSKlaus Jensen { 1157f0f1aceSKlaus Jensen NvmeNamespace *ns = NVME_NS(dev); 1167f0f1aceSKlaus Jensen BusState *s = qdev_get_parent_bus(dev); 1177f0f1aceSKlaus Jensen NvmeCtrl *n = NVME(s->parent); 1187f0f1aceSKlaus Jensen Error *local_err = NULL; 1197f0f1aceSKlaus Jensen 1207f0f1aceSKlaus Jensen if (nvme_ns_setup(n, ns, &local_err)) { 1217f0f1aceSKlaus Jensen error_propagate_prepend(errp, local_err, 1227f0f1aceSKlaus Jensen "could not setup namespace: "); 1237f0f1aceSKlaus Jensen return; 1247f0f1aceSKlaus Jensen } 1257f0f1aceSKlaus Jensen } 1267f0f1aceSKlaus Jensen 1277f0f1aceSKlaus Jensen static Property nvme_ns_props[] = { 1287f0f1aceSKlaus Jensen DEFINE_BLOCK_PROPERTIES(NvmeNamespace, blkconf), 1297f0f1aceSKlaus Jensen DEFINE_PROP_UINT32("nsid", NvmeNamespace, params.nsid, 0), 1307f0f1aceSKlaus Jensen DEFINE_PROP_END_OF_LIST(), 1317f0f1aceSKlaus Jensen }; 1327f0f1aceSKlaus Jensen 1337f0f1aceSKlaus Jensen static void nvme_ns_class_init(ObjectClass *oc, void *data) 1347f0f1aceSKlaus Jensen { 1357f0f1aceSKlaus Jensen DeviceClass *dc = DEVICE_CLASS(oc); 1367f0f1aceSKlaus Jensen 1377f0f1aceSKlaus Jensen set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); 1387f0f1aceSKlaus Jensen 1397f0f1aceSKlaus Jensen dc->bus_type = TYPE_NVME_BUS; 1407f0f1aceSKlaus Jensen dc->realize = nvme_ns_realize; 1417f0f1aceSKlaus Jensen device_class_set_props(dc, nvme_ns_props); 1427f0f1aceSKlaus Jensen dc->desc = "Virtual NVMe namespace"; 1437f0f1aceSKlaus Jensen } 1447f0f1aceSKlaus Jensen 1457f0f1aceSKlaus Jensen static void nvme_ns_instance_init(Object *obj) 1467f0f1aceSKlaus Jensen { 1477f0f1aceSKlaus Jensen NvmeNamespace *ns = NVME_NS(obj); 1487f0f1aceSKlaus Jensen char *bootindex = g_strdup_printf("/namespace@%d,0", ns->params.nsid); 1497f0f1aceSKlaus Jensen 1507f0f1aceSKlaus Jensen device_add_bootindex_property(obj, &ns->bootindex, "bootindex", 1517f0f1aceSKlaus Jensen bootindex, DEVICE(obj)); 1527f0f1aceSKlaus Jensen 1537f0f1aceSKlaus Jensen g_free(bootindex); 1547f0f1aceSKlaus Jensen } 1557f0f1aceSKlaus Jensen 1567f0f1aceSKlaus Jensen static const TypeInfo nvme_ns_info = { 1577f0f1aceSKlaus Jensen .name = TYPE_NVME_NS, 1587f0f1aceSKlaus Jensen .parent = TYPE_DEVICE, 1597f0f1aceSKlaus Jensen .class_init = nvme_ns_class_init, 1607f0f1aceSKlaus Jensen .instance_size = sizeof(NvmeNamespace), 1617f0f1aceSKlaus Jensen .instance_init = nvme_ns_instance_init, 1627f0f1aceSKlaus Jensen }; 1637f0f1aceSKlaus Jensen 1647f0f1aceSKlaus Jensen static void nvme_ns_register_types(void) 1657f0f1aceSKlaus Jensen { 1667f0f1aceSKlaus Jensen type_register_static(&nvme_ns_info); 1677f0f1aceSKlaus Jensen } 1687f0f1aceSKlaus Jensen 1697f0f1aceSKlaus Jensen type_init(nvme_ns_register_types) 170