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