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.
9 #include "qemu/osdep.h"
10 #include "qapi/error.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
;
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
;
33 static void nvme_subsys_unreserve_cntlids(NvmeCtrl
*n
)
35 NvmeSubsystem
*subsys
= n
->subsys
;
36 NvmeSecCtrlList
*list
= &n
->sec_ctrl_list
;
37 NvmeSecCtrlEntry
*sctrl
;
40 for (i
= 0; i
< n
->params
.sriov_max_vfs
; i
++) {
41 sctrl
= &list
->sec
[i
];
42 cntlid
= le16_to_cpu(sctrl
->scid
);
45 assert(subsys
->ctrls
[cntlid
] == SUBSYS_SLOT_RSVD
);
46 subsys
->ctrls
[cntlid
] = NULL
;
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
);
61 for (cntlid
= 0; cntlid
< ARRAY_SIZE(subsys
->ctrls
); cntlid
++) {
62 if (!subsys
->ctrls
[cntlid
]) {
67 if (cntlid
== ARRAY_SIZE(subsys
->ctrls
)) {
68 error_setg(errp
, "no more free controller id");
72 num_rsvd
= nvme_subsys_reserve_cntlids(n
, cntlid
+ 1, num_vfs
);
73 if (num_rsvd
!= num_vfs
) {
74 nvme_subsys_unreserve_cntlids(n
);
76 "no more free controller ids for secondary controllers");
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");
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
);
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
;
105 subsys
->ctrls
[n
->cntlid
] = NULL
;
106 nvme_subsys_unreserve_cntlids(n
);
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
)