1eb2e8974SMinwoo Im /* 2eb2e8974SMinwoo Im * QEMU NVM Express Subsystem: nvme-subsys 3eb2e8974SMinwoo Im * 4eb2e8974SMinwoo Im * Copyright (c) 2021 Minwoo Im <minwoo.im.dev@gmail.com> 5eb2e8974SMinwoo Im * 6eb2e8974SMinwoo Im * This code is licensed under the GNU GPL v2. Refer COPYING. 7eb2e8974SMinwoo Im */ 8eb2e8974SMinwoo Im 9eb2e8974SMinwoo Im #include "qemu/osdep.h" 10eb2e8974SMinwoo Im #include "qapi/error.h" 117ef37c1cSKlaus Jensen 12eb2e8974SMinwoo Im #include "nvme.h" 13eb2e8974SMinwoo Im 14*99f48ae7SLukasz Maniak static int nvme_subsys_reserve_cntlids(NvmeCtrl *n, int start, int num) 15*99f48ae7SLukasz Maniak { 16*99f48ae7SLukasz Maniak NvmeSubsystem *subsys = n->subsys; 17*99f48ae7SLukasz Maniak NvmeSecCtrlList *list = &n->sec_ctrl_list; 18*99f48ae7SLukasz Maniak NvmeSecCtrlEntry *sctrl; 19*99f48ae7SLukasz Maniak int i, cnt = 0; 20*99f48ae7SLukasz Maniak 21*99f48ae7SLukasz Maniak for (i = start; i < ARRAY_SIZE(subsys->ctrls) && cnt < num; i++) { 22*99f48ae7SLukasz Maniak if (!subsys->ctrls[i]) { 23*99f48ae7SLukasz Maniak sctrl = &list->sec[cnt]; 24*99f48ae7SLukasz Maniak sctrl->scid = cpu_to_le16(i); 25*99f48ae7SLukasz Maniak subsys->ctrls[i] = SUBSYS_SLOT_RSVD; 26*99f48ae7SLukasz Maniak cnt++; 27*99f48ae7SLukasz Maniak } 28*99f48ae7SLukasz Maniak } 29*99f48ae7SLukasz Maniak 30*99f48ae7SLukasz Maniak return cnt; 31*99f48ae7SLukasz Maniak } 32*99f48ae7SLukasz Maniak 33*99f48ae7SLukasz Maniak static void nvme_subsys_unreserve_cntlids(NvmeCtrl *n) 34*99f48ae7SLukasz Maniak { 35*99f48ae7SLukasz Maniak NvmeSubsystem *subsys = n->subsys; 36*99f48ae7SLukasz Maniak NvmeSecCtrlList *list = &n->sec_ctrl_list; 37*99f48ae7SLukasz Maniak NvmeSecCtrlEntry *sctrl; 38*99f48ae7SLukasz Maniak int i, cntlid; 39*99f48ae7SLukasz Maniak 40*99f48ae7SLukasz Maniak for (i = 0; i < n->params.sriov_max_vfs; i++) { 41*99f48ae7SLukasz Maniak sctrl = &list->sec[i]; 42*99f48ae7SLukasz Maniak cntlid = le16_to_cpu(sctrl->scid); 43*99f48ae7SLukasz Maniak 44*99f48ae7SLukasz Maniak if (cntlid) { 45*99f48ae7SLukasz Maniak assert(subsys->ctrls[cntlid] == SUBSYS_SLOT_RSVD); 46*99f48ae7SLukasz Maniak subsys->ctrls[cntlid] = NULL; 47*99f48ae7SLukasz Maniak sctrl->scid = 0; 48*99f48ae7SLukasz Maniak } 49*99f48ae7SLukasz Maniak } 50*99f48ae7SLukasz Maniak } 51*99f48ae7SLukasz Maniak 52e36a261dSMinwoo Im int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp) 53e36a261dSMinwoo Im { 54e36a261dSMinwoo Im NvmeSubsystem *subsys = n->subsys; 55*99f48ae7SLukasz Maniak NvmeSecCtrlEntry *sctrl = nvme_sctrl(n); 56*99f48ae7SLukasz Maniak int cntlid, nsid, num_rsvd, num_vfs = n->params.sriov_max_vfs; 57e36a261dSMinwoo Im 58*99f48ae7SLukasz Maniak if (pci_is_vf(&n->parent_obj)) { 59*99f48ae7SLukasz Maniak cntlid = le16_to_cpu(sctrl->scid); 60*99f48ae7SLukasz Maniak } else { 61e36a261dSMinwoo Im for (cntlid = 0; cntlid < ARRAY_SIZE(subsys->ctrls); cntlid++) { 62e36a261dSMinwoo Im if (!subsys->ctrls[cntlid]) { 63e36a261dSMinwoo Im break; 64e36a261dSMinwoo Im } 65e36a261dSMinwoo Im } 66e36a261dSMinwoo Im 67e36a261dSMinwoo Im if (cntlid == ARRAY_SIZE(subsys->ctrls)) { 68e36a261dSMinwoo Im error_setg(errp, "no more free controller id"); 69e36a261dSMinwoo Im return -1; 70e36a261dSMinwoo Im } 71e36a261dSMinwoo Im 72*99f48ae7SLukasz Maniak num_rsvd = nvme_subsys_reserve_cntlids(n, cntlid + 1, num_vfs); 73*99f48ae7SLukasz Maniak if (num_rsvd != num_vfs) { 74*99f48ae7SLukasz Maniak nvme_subsys_unreserve_cntlids(n); 75*99f48ae7SLukasz Maniak error_setg(errp, 76*99f48ae7SLukasz Maniak "no more free controller ids for secondary controllers"); 77*99f48ae7SLukasz Maniak return -1; 78*99f48ae7SLukasz Maniak } 79*99f48ae7SLukasz Maniak } 80*99f48ae7SLukasz Maniak 81a859eb9fSKlaus Jensen if (!subsys->serial) { 82a859eb9fSKlaus Jensen subsys->serial = g_strdup(n->params.serial); 83a859eb9fSKlaus Jensen } else if (strcmp(subsys->serial, n->params.serial)) { 84a859eb9fSKlaus Jensen error_setg(errp, "invalid controller serial"); 85a859eb9fSKlaus Jensen return -1; 86a859eb9fSKlaus Jensen } 87a859eb9fSKlaus Jensen 88e36a261dSMinwoo Im subsys->ctrls[cntlid] = n; 89e36a261dSMinwoo Im 909fc6e86eSHannes Reinecke for (nsid = 1; nsid < ARRAY_SIZE(subsys->namespaces); nsid++) { 919fc6e86eSHannes Reinecke NvmeNamespace *ns = subsys->namespaces[nsid]; 929fc6e86eSHannes Reinecke if (ns && ns->params.shared && !ns->params.detached) { 939fc6e86eSHannes Reinecke nvme_attach_ns(n, ns); 949fc6e86eSHannes Reinecke } 959fc6e86eSHannes Reinecke } 969fc6e86eSHannes Reinecke 97e36a261dSMinwoo Im return cntlid; 98e36a261dSMinwoo Im } 99e36a261dSMinwoo Im 100b0fde9e8SKlaus Jensen void nvme_subsys_unregister_ctrl(NvmeSubsystem *subsys, NvmeCtrl *n) 101b0fde9e8SKlaus Jensen { 102*99f48ae7SLukasz Maniak if (pci_is_vf(&n->parent_obj)) { 103*99f48ae7SLukasz Maniak subsys->ctrls[n->cntlid] = SUBSYS_SLOT_RSVD; 104*99f48ae7SLukasz Maniak } else { 105b0fde9e8SKlaus Jensen subsys->ctrls[n->cntlid] = NULL; 106*99f48ae7SLukasz Maniak nvme_subsys_unreserve_cntlids(n); 107*99f48ae7SLukasz Maniak } 108*99f48ae7SLukasz Maniak 1099fc6e86eSHannes Reinecke n->cntlid = -1; 110b0fde9e8SKlaus Jensen } 111b0fde9e8SKlaus Jensen 112eb2e8974SMinwoo Im static void nvme_subsys_setup(NvmeSubsystem *subsys) 113eb2e8974SMinwoo Im { 114eb2e8974SMinwoo Im const char *nqn = subsys->params.nqn ? 115eb2e8974SMinwoo Im subsys->params.nqn : subsys->parent_obj.id; 116eb2e8974SMinwoo Im 117eb2e8974SMinwoo Im snprintf((char *)subsys->subnqn, sizeof(subsys->subnqn), 118eb2e8974SMinwoo Im "nqn.2019-08.org.qemu:%s", nqn); 119eb2e8974SMinwoo Im } 120eb2e8974SMinwoo Im 121eb2e8974SMinwoo Im static void nvme_subsys_realize(DeviceState *dev, Error **errp) 122eb2e8974SMinwoo Im { 123eb2e8974SMinwoo Im NvmeSubsystem *subsys = NVME_SUBSYS(dev); 124eb2e8974SMinwoo Im 125d637e1dcSPeter Maydell qbus_init(&subsys->bus, sizeof(NvmeBus), TYPE_NVME_BUS, dev, dev->id); 1265ffbaeedSKlaus Jensen 127eb2e8974SMinwoo Im nvme_subsys_setup(subsys); 128eb2e8974SMinwoo Im } 129eb2e8974SMinwoo Im 130eb2e8974SMinwoo Im static Property nvme_subsystem_props[] = { 131eb2e8974SMinwoo Im DEFINE_PROP_STRING("nqn", NvmeSubsystem, params.nqn), 132eb2e8974SMinwoo Im DEFINE_PROP_END_OF_LIST(), 133eb2e8974SMinwoo Im }; 134eb2e8974SMinwoo Im 135eb2e8974SMinwoo Im static void nvme_subsys_class_init(ObjectClass *oc, void *data) 136eb2e8974SMinwoo Im { 137eb2e8974SMinwoo Im DeviceClass *dc = DEVICE_CLASS(oc); 138eb2e8974SMinwoo Im 139eb2e8974SMinwoo Im set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); 140eb2e8974SMinwoo Im 141eb2e8974SMinwoo Im dc->realize = nvme_subsys_realize; 142eb2e8974SMinwoo Im dc->desc = "Virtual NVMe subsystem"; 143cc6fb6bcSKlaus Jensen dc->hotpluggable = false; 144eb2e8974SMinwoo Im 145eb2e8974SMinwoo Im device_class_set_props(dc, nvme_subsystem_props); 146eb2e8974SMinwoo Im } 147eb2e8974SMinwoo Im 148eb2e8974SMinwoo Im static const TypeInfo nvme_subsys_info = { 149eb2e8974SMinwoo Im .name = TYPE_NVME_SUBSYS, 150eb2e8974SMinwoo Im .parent = TYPE_DEVICE, 151eb2e8974SMinwoo Im .class_init = nvme_subsys_class_init, 152eb2e8974SMinwoo Im .instance_size = sizeof(NvmeSubsystem), 153eb2e8974SMinwoo Im }; 154eb2e8974SMinwoo Im 155eb2e8974SMinwoo Im static void nvme_subsys_register_types(void) 156eb2e8974SMinwoo Im { 157eb2e8974SMinwoo Im type_register_static(&nvme_subsys_info); 158eb2e8974SMinwoo Im } 159eb2e8974SMinwoo Im 160eb2e8974SMinwoo Im type_init(nvme_subsys_register_types) 161