tests/avocado: add RISC-V OpenSBI boot test
[qemu.git] / hw / nvme / subsys.c
blob9d2643678b531aa8fd19e20b1228dd3452e4b088
1 /*
2 * QEMU NVM Express Subsystem: nvme-subsys
4 * Copyright (c) 2021 Minwoo Im <minwoo.im.dev@gmail.com>
6 * This code is licensed under the GNU GPL v2. Refer COPYING.
7 */
9 #include "qemu/osdep.h"
10 #include "qapi/error.h"
12 #include "nvme.h"
14 static int nvme_subsys_reserve_cntlids(NvmeCtrl *n, int start, int num)
16 NvmeSubsystem *subsys = n->subsys;
17 NvmeSecCtrlList *list = &n->sec_ctrl_list;
18 NvmeSecCtrlEntry *sctrl;
19 int i, cnt = 0;
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++;
30 return cnt;
33 static void nvme_subsys_unreserve_cntlids(NvmeCtrl *n)
35 NvmeSubsystem *subsys = n->subsys;
36 NvmeSecCtrlList *list = &n->sec_ctrl_list;
37 NvmeSecCtrlEntry *sctrl;
38 int i, cntlid;
40 for (i = 0; i < n->params.sriov_max_vfs; i++) {
41 sctrl = &list->sec[i];
42 cntlid = le16_to_cpu(sctrl->scid);
44 if (cntlid) {
45 assert(subsys->ctrls[cntlid] == SUBSYS_SLOT_RSVD);
46 subsys->ctrls[cntlid] = NULL;
47 sctrl->scid = 0;
52 int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp)
54 NvmeSubsystem *subsys = n->subsys;
55 NvmeSecCtrlEntry *sctrl = nvme_sctrl(n);
56 int cntlid, nsid, num_rsvd, num_vfs = n->params.sriov_max_vfs;
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;
67 if (cntlid == ARRAY_SIZE(subsys->ctrls)) {
68 error_setg(errp, "no more free controller id");
69 return -1;
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;
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;
88 subsys->ctrls[cntlid] = n;
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);
97 return cntlid;
100 void nvme_subsys_unregister_ctrl(NvmeSubsystem *subsys, NvmeCtrl *n)
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);
109 n->cntlid = -1;
112 static void nvme_subsys_setup(NvmeSubsystem *subsys)
114 const char *nqn = subsys->params.nqn ?
115 subsys->params.nqn : subsys->parent_obj.id;
117 snprintf((char *)subsys->subnqn, sizeof(subsys->subnqn),
118 "nqn.2019-08.org.qemu:%s", nqn);
121 static void nvme_subsys_realize(DeviceState *dev, Error **errp)
123 NvmeSubsystem *subsys = NVME_SUBSYS(dev);
125 qbus_init(&subsys->bus, sizeof(NvmeBus), TYPE_NVME_BUS, dev, dev->id);
127 nvme_subsys_setup(subsys);
130 static Property nvme_subsystem_props[] = {
131 DEFINE_PROP_STRING("nqn", NvmeSubsystem, params.nqn),
132 DEFINE_PROP_END_OF_LIST(),
135 static void nvme_subsys_class_init(ObjectClass *oc, void *data)
137 DeviceClass *dc = DEVICE_CLASS(oc);
139 set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
141 dc->realize = nvme_subsys_realize;
142 dc->desc = "Virtual NVMe subsystem";
143 dc->hotpluggable = false;
145 device_class_set_props(dc, nvme_subsystem_props);
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),
155 static void nvme_subsys_register_types(void)
157 type_register_static(&nvme_subsys_info);
160 type_init(nvme_subsys_register_types)