Skip to content

Commit 6ccca4b

Browse files
committed
hw/nvme: rework csi handling
The controller incorrectly allows a zoned namespace to be attached even if CS.CSS is configured to only support the NVM command set for I/O queues. Rework handling of namespace command sets in general by attaching supported namespaces when the controller is started instead of, like now, statically when realized. Reviewed-by: Jesper Wendel Devantier <[email protected]> Signed-off-by: Klaus Jensen <[email protected]>
1 parent d96a32d commit 6ccca4b

File tree

4 files changed

+131
-111
lines changed

4 files changed

+131
-111
lines changed

hw/nvme/ctrl.c

Lines changed: 121 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -277,15 +277,14 @@ static const uint32_t nvme_cse_acs_default[256] = {
277277
[NVME_ADM_CMD_SET_FEATURES] = NVME_CMD_EFF_CSUPP,
278278
[NVME_ADM_CMD_GET_FEATURES] = NVME_CMD_EFF_CSUPP,
279279
[NVME_ADM_CMD_ASYNC_EV_REQ] = NVME_CMD_EFF_CSUPP,
280-
[NVME_ADM_CMD_NS_ATTACHMENT] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_NIC,
280+
[NVME_ADM_CMD_NS_ATTACHMENT] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_NIC |
281+
NVME_CMD_EFF_CCC,
281282
[NVME_ADM_CMD_FORMAT_NVM] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
282283
[NVME_ADM_CMD_DIRECTIVE_RECV] = NVME_CMD_EFF_CSUPP,
283284
[NVME_ADM_CMD_DIRECTIVE_SEND] = NVME_CMD_EFF_CSUPP,
284285
};
285286

286-
static const uint32_t nvme_cse_iocs_none[256];
287-
288-
static const uint32_t nvme_cse_iocs_nvm[256] = {
287+
static const uint32_t nvme_cse_iocs_nvm_default[256] = {
289288
[NVME_CMD_FLUSH] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
290289
[NVME_CMD_WRITE_ZEROES] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
291290
[NVME_CMD_WRITE] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
@@ -298,7 +297,7 @@ static const uint32_t nvme_cse_iocs_nvm[256] = {
298297
[NVME_CMD_IO_MGMT_SEND] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
299298
};
300299

301-
static const uint32_t nvme_cse_iocs_zoned[256] = {
300+
static const uint32_t nvme_cse_iocs_zoned_default[256] = {
302301
[NVME_CMD_FLUSH] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
303302
[NVME_CMD_WRITE_ZEROES] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
304303
[NVME_CMD_WRITE] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
@@ -307,6 +306,9 @@ static const uint32_t nvme_cse_iocs_zoned[256] = {
307306
[NVME_CMD_VERIFY] = NVME_CMD_EFF_CSUPP,
308307
[NVME_CMD_COPY] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
309308
[NVME_CMD_COMPARE] = NVME_CMD_EFF_CSUPP,
309+
[NVME_CMD_IO_MGMT_RECV] = NVME_CMD_EFF_CSUPP,
310+
[NVME_CMD_IO_MGMT_SEND] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
311+
310312
[NVME_CMD_ZONE_APPEND] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
311313
[NVME_CMD_ZONE_MGMT_SEND] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
312314
[NVME_CMD_ZONE_MGMT_RECV] = NVME_CMD_EFF_CSUPP,
@@ -4603,6 +4605,61 @@ static uint16_t nvme_io_mgmt_send(NvmeCtrl *n, NvmeRequest *req)
46034605
};
46044606
}
46054607

4608+
static uint16_t __nvme_io_cmd_nvm(NvmeCtrl *n, NvmeRequest *req)
4609+
{
4610+
switch (req->cmd.opcode) {
4611+
case NVME_CMD_WRITE:
4612+
return nvme_write(n, req);
4613+
case NVME_CMD_READ:
4614+
return nvme_read(n, req);
4615+
case NVME_CMD_COMPARE:
4616+
return nvme_compare(n, req);
4617+
case NVME_CMD_WRITE_ZEROES:
4618+
return nvme_write_zeroes(n, req);
4619+
case NVME_CMD_DSM:
4620+
return nvme_dsm(n, req);
4621+
case NVME_CMD_VERIFY:
4622+
return nvme_verify(n, req);
4623+
case NVME_CMD_COPY:
4624+
return nvme_copy(n, req);
4625+
case NVME_CMD_IO_MGMT_RECV:
4626+
return nvme_io_mgmt_recv(n, req);
4627+
case NVME_CMD_IO_MGMT_SEND:
4628+
return nvme_io_mgmt_send(n, req);
4629+
}
4630+
4631+
g_assert_not_reached();
4632+
}
4633+
4634+
static uint16_t nvme_io_cmd_nvm(NvmeCtrl *n, NvmeRequest *req)
4635+
{
4636+
if (!(n->cse.iocs.nvm[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) {
4637+
trace_pci_nvme_err_invalid_opc(req->cmd.opcode);
4638+
return NVME_INVALID_OPCODE | NVME_DNR;
4639+
}
4640+
4641+
return __nvme_io_cmd_nvm(n, req);
4642+
}
4643+
4644+
static uint16_t nvme_io_cmd_zoned(NvmeCtrl *n, NvmeRequest *req)
4645+
{
4646+
if (!(n->cse.iocs.zoned[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) {
4647+
trace_pci_nvme_err_invalid_opc(req->cmd.opcode);
4648+
return NVME_INVALID_OPCODE | NVME_DNR;
4649+
}
4650+
4651+
switch (req->cmd.opcode) {
4652+
case NVME_CMD_ZONE_APPEND:
4653+
return nvme_zone_append(n, req);
4654+
case NVME_CMD_ZONE_MGMT_SEND:
4655+
return nvme_zone_mgmt_send(n, req);
4656+
case NVME_CMD_ZONE_MGMT_RECV:
4657+
return nvme_zone_mgmt_recv(n, req);
4658+
}
4659+
4660+
return __nvme_io_cmd_nvm(n, req);
4661+
}
4662+
46064663
static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req)
46074664
{
46084665
NvmeNamespace *ns;
@@ -4644,11 +4701,6 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req)
46444701
return NVME_INVALID_FIELD | NVME_DNR;
46454702
}
46464703

4647-
if (!(ns->iocs[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) {
4648-
trace_pci_nvme_err_invalid_opc(req->cmd.opcode);
4649-
return NVME_INVALID_OPCODE | NVME_DNR;
4650-
}
4651-
46524704
if (ns->status) {
46534705
return ns->status;
46544706
}
@@ -4659,36 +4711,14 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req)
46594711

46604712
req->ns = ns;
46614713

4662-
switch (req->cmd.opcode) {
4663-
case NVME_CMD_WRITE_ZEROES:
4664-
return nvme_write_zeroes(n, req);
4665-
case NVME_CMD_ZONE_APPEND:
4666-
return nvme_zone_append(n, req);
4667-
case NVME_CMD_WRITE:
4668-
return nvme_write(n, req);
4669-
case NVME_CMD_READ:
4670-
return nvme_read(n, req);
4671-
case NVME_CMD_COMPARE:
4672-
return nvme_compare(n, req);
4673-
case NVME_CMD_DSM:
4674-
return nvme_dsm(n, req);
4675-
case NVME_CMD_VERIFY:
4676-
return nvme_verify(n, req);
4677-
case NVME_CMD_COPY:
4678-
return nvme_copy(n, req);
4679-
case NVME_CMD_ZONE_MGMT_SEND:
4680-
return nvme_zone_mgmt_send(n, req);
4681-
case NVME_CMD_ZONE_MGMT_RECV:
4682-
return nvme_zone_mgmt_recv(n, req);
4683-
case NVME_CMD_IO_MGMT_RECV:
4684-
return nvme_io_mgmt_recv(n, req);
4685-
case NVME_CMD_IO_MGMT_SEND:
4686-
return nvme_io_mgmt_send(n, req);
4687-
default:
4688-
g_assert_not_reached();
4714+
switch (ns->csi) {
4715+
case NVME_CSI_NVM:
4716+
return nvme_io_cmd_nvm(n, req);
4717+
case NVME_CSI_ZONED:
4718+
return nvme_io_cmd_zoned(n, req);
46894719
}
46904720

4691-
return NVME_INVALID_OPCODE | NVME_DNR;
4721+
g_assert_not_reached();
46924722
}
46934723

46944724
static void nvme_cq_notifier(EventNotifier *e)
@@ -5147,7 +5177,7 @@ static uint16_t nvme_cmd_effects(NvmeCtrl *n, uint8_t csi, uint32_t buf_len,
51475177
uint64_t off, NvmeRequest *req)
51485178
{
51495179
NvmeEffectsLog log = {};
5150-
const uint32_t *src_iocs = NULL;
5180+
const uint32_t *iocs = NULL;
51515181
uint32_t trans_len;
51525182

51535183
if (off >= sizeof(log)) {
@@ -5157,25 +5187,26 @@ static uint16_t nvme_cmd_effects(NvmeCtrl *n, uint8_t csi, uint32_t buf_len,
51575187

51585188
switch (NVME_CC_CSS(ldl_le_p(&n->bar.cc))) {
51595189
case NVME_CC_CSS_NVM:
5160-
src_iocs = nvme_cse_iocs_nvm;
5161-
/* fall through */
5162-
case NVME_CC_CSS_ADMIN_ONLY:
5190+
iocs = n->cse.iocs.nvm;
51635191
break;
5164-
case NVME_CC_CSS_CSI:
5192+
5193+
case NVME_CC_CSS_ALL:
51655194
switch (csi) {
51665195
case NVME_CSI_NVM:
5167-
src_iocs = nvme_cse_iocs_nvm;
5196+
iocs = n->cse.iocs.nvm;
51685197
break;
51695198
case NVME_CSI_ZONED:
5170-
src_iocs = nvme_cse_iocs_zoned;
5199+
iocs = n->cse.iocs.zoned;
51715200
break;
51725201
}
5202+
5203+
break;
51735204
}
51745205

51755206
memcpy(log.acs, n->cse.acs, sizeof(log.acs));
51765207

5177-
if (src_iocs) {
5178-
memcpy(log.iocs, src_iocs, sizeof(log.iocs));
5208+
if (iocs) {
5209+
memcpy(log.iocs, iocs, sizeof(log.iocs));
51795210
}
51805211

51815212
trans_len = MIN(sizeof(log) - off, buf_len);
@@ -6718,25 +6749,29 @@ static void nvme_update_dsm_limits(NvmeCtrl *n, NvmeNamespace *ns)
67186749
}
67196750
}
67206751

6721-
static void nvme_select_iocs_ns(NvmeCtrl *n, NvmeNamespace *ns)
6752+
static bool nvme_csi_supported(NvmeCtrl *n, uint8_t csi)
67226753
{
6723-
uint32_t cc = ldl_le_p(&n->bar.cc);
6754+
uint32_t cc;
67246755

6725-
ns->iocs = nvme_cse_iocs_none;
6726-
switch (ns->csi) {
6756+
switch (csi) {
67276757
case NVME_CSI_NVM:
6728-
if (NVME_CC_CSS(cc) != NVME_CC_CSS_ADMIN_ONLY) {
6729-
ns->iocs = nvme_cse_iocs_nvm;
6730-
}
6731-
break;
6758+
return true;
6759+
67326760
case NVME_CSI_ZONED:
6733-
if (NVME_CC_CSS(cc) == NVME_CC_CSS_CSI) {
6734-
ns->iocs = nvme_cse_iocs_zoned;
6735-
} else if (NVME_CC_CSS(cc) == NVME_CC_CSS_NVM) {
6736-
ns->iocs = nvme_cse_iocs_nvm;
6737-
}
6738-
break;
6761+
cc = ldl_le_p(&n->bar.cc);
6762+
6763+
return NVME_CC_CSS(cc) == NVME_CC_CSS_ALL;
67396764
}
6765+
6766+
g_assert_not_reached();
6767+
}
6768+
6769+
static void nvme_detach_ns(NvmeCtrl *n, NvmeNamespace *ns)
6770+
{
6771+
assert(ns->attached > 0);
6772+
6773+
n->namespaces[ns->params.nsid] = NULL;
6774+
ns->attached--;
67406775
}
67416776

67426777
static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req)
@@ -6781,27 +6816,25 @@ static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req)
67816816

67826817
switch (sel) {
67836818
case NVME_NS_ATTACHMENT_ATTACH:
6784-
if (nvme_ns(ctrl, nsid)) {
6819+
if (nvme_ns(n, nsid)) {
67856820
return NVME_NS_ALREADY_ATTACHED | NVME_DNR;
67866821
}
67876822

67886823
if (ns->attached && !ns->params.shared) {
67896824
return NVME_NS_PRIVATE | NVME_DNR;
67906825
}
67916826

6827+
if (!nvme_csi_supported(n, ns->csi)) {
6828+
return NVME_IOCS_NOT_SUPPORTED | NVME_DNR;
6829+
}
6830+
67926831
nvme_attach_ns(ctrl, ns);
6793-
nvme_select_iocs_ns(ctrl, ns);
6832+
nvme_update_dsm_limits(ctrl, ns);
67946833

67956834
break;
67966835

67976836
case NVME_NS_ATTACHMENT_DETACH:
6798-
if (!nvme_ns(ctrl, nsid)) {
6799-
return NVME_NS_NOT_ATTACHED | NVME_DNR;
6800-
}
6801-
6802-
ctrl->namespaces[nsid] = NULL;
6803-
ns->attached--;
6804-
6837+
nvme_detach_ns(ctrl, ns);
68056838
nvme_update_dsm_limits(ctrl, NULL);
68066839

68076840
break;
@@ -7652,21 +7685,6 @@ static void nvme_ctrl_shutdown(NvmeCtrl *n)
76527685
}
76537686
}
76547687

7655-
static void nvme_select_iocs(NvmeCtrl *n)
7656-
{
7657-
NvmeNamespace *ns;
7658-
int i;
7659-
7660-
for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
7661-
ns = nvme_ns(n, i);
7662-
if (!ns) {
7663-
continue;
7664-
}
7665-
7666-
nvme_select_iocs_ns(n, ns);
7667-
}
7668-
}
7669-
76707688
static int nvme_start_ctrl(NvmeCtrl *n)
76717689
{
76727690
uint64_t cap = ldq_le_p(&n->bar.cap);
@@ -7733,7 +7751,18 @@ static int nvme_start_ctrl(NvmeCtrl *n)
77337751

77347752
nvme_set_timestamp(n, 0ULL);
77357753

7736-
nvme_select_iocs(n);
7754+
/* verify that the command sets of attached namespaces are supported */
7755+
for (int i = 1; i <= NVME_MAX_NAMESPACES; i++) {
7756+
NvmeNamespace *ns = nvme_subsys_ns(n->subsys, i);
7757+
7758+
if (ns && nvme_csi_supported(n, ns->csi) && !ns->params.detached) {
7759+
if (!ns->attached || ns->params.shared) {
7760+
nvme_attach_ns(n, ns);
7761+
}
7762+
}
7763+
}
7764+
7765+
nvme_update_dsm_limits(n, NULL);
77377766

77387767
return 0;
77397768
}
@@ -8748,6 +8777,9 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
87488777
uint16_t oacs;
87498778

87508779
memcpy(n->cse.acs, nvme_cse_acs_default, sizeof(n->cse.acs));
8780+
memcpy(n->cse.iocs.nvm, nvme_cse_iocs_nvm_default, sizeof(n->cse.iocs.nvm));
8781+
memcpy(n->cse.iocs.zoned, nvme_cse_iocs_zoned_default,
8782+
sizeof(n->cse.iocs.zoned));
87518783

87528784
id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID));
87538785
id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID));
@@ -8859,9 +8891,8 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
88598891
NVME_CAP_SET_MQES(cap, n->params.mqes);
88608892
NVME_CAP_SET_CQR(cap, 1);
88618893
NVME_CAP_SET_TO(cap, 0xf);
8862-
NVME_CAP_SET_CSS(cap, NVME_CAP_CSS_NVM);
8863-
NVME_CAP_SET_CSS(cap, NVME_CAP_CSS_CSI_SUPP);
8864-
NVME_CAP_SET_CSS(cap, NVME_CAP_CSS_ADMIN_ONLY);
8894+
NVME_CAP_SET_CSS(cap, NVME_CAP_CSS_NCSS);
8895+
NVME_CAP_SET_CSS(cap, NVME_CAP_CSS_IOCSS);
88658896
NVME_CAP_SET_MPSMAX(cap, 4);
88668897
NVME_CAP_SET_CMBS(cap, n->params.cmb_size_mb ? 1 : 0);
88678898
NVME_CAP_SET_PMRS(cap, n->pmr.dev ? 1 : 0);
@@ -8908,8 +8939,6 @@ void nvme_attach_ns(NvmeCtrl *n, NvmeNamespace *ns)
89088939

89098940
n->namespaces[nsid] = ns;
89108941
ns->attached++;
8911-
8912-
nvme_update_dsm_limits(n, ns);
89138942
}
89148943

89158944
static void nvme_realize(PCIDevice *pci_dev, Error **errp)
@@ -8965,7 +8994,7 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
89658994
return;
89668995
}
89678996

8968-
nvme_attach_ns(n, ns);
8997+
n->subsys->namespaces[ns->params.nsid] = ns;
89698998
}
89708999
}
89719000

hw/nvme/ns.c

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -763,20 +763,6 @@ static void nvme_ns_realize(DeviceState *dev, Error **errp)
763763

764764
ns->id_ns.endgid = cpu_to_le16(0x1);
765765
ns->id_ns_ind.endgrpid = cpu_to_le16(0x1);
766-
767-
if (ns->params.detached) {
768-
return;
769-
}
770-
771-
if (ns->params.shared) {
772-
for (i = 0; i < ARRAY_SIZE(subsys->ctrls); i++) {
773-
NvmeCtrl *ctrl = subsys->ctrls[i];
774-
775-
if (ctrl && ctrl != SUBSYS_SLOT_RSVD) {
776-
nvme_attach_ns(ctrl, ns);
777-
}
778-
}
779-
}
780766
}
781767

782768
static const Property nvme_ns_props[] = {

hw/nvme/nvme.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,6 @@ typedef struct NvmeNamespace {
237237
NvmeLBAF lbaf;
238238
unsigned int nlbaf;
239239
size_t lbasz;
240-
const uint32_t *iocs;
241240
uint8_t csi;
242241
uint16_t status;
243242
int attached;
@@ -587,6 +586,10 @@ typedef struct NvmeCtrl {
587586

588587
struct {
589588
uint32_t acs[256];
589+
struct {
590+
uint32_t nvm[256];
591+
uint32_t zoned[256];
592+
} iocs;
590593
} cse;
591594

592595
struct {

0 commit comments

Comments
 (0)