xref: /qemu/hw/nvme/subsys.c (revision 99f48ae7aea70fb080f04bf1cc846cd6450bd11a)
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