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