@@ -132,6 +132,7 @@ static Property nvme_ns_props[] = {
DEFINE_BLOCK_PROPERTIES(NvmeNamespace, blkconf),
DEFINE_PROP_UINT32("nsid", NvmeNamespace, params.nsid, 0),
DEFINE_PROP_UUID("uuid", NvmeNamespace, params.uuid),
+ DEFINE_PROP_BOOL("attached", NvmeNamespace, params.attached, true),
DEFINE_PROP_END_OF_LIST(),
};
@@ -21,6 +21,7 @@
typedef struct NvmeNamespaceParams {
uint32_t nsid;
+ bool attached;
QemuUUID uuid;
} NvmeNamespaceParams;
@@ -1062,6 +1062,9 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req)
if (unlikely(!req->ns)) {
return NVME_INVALID_FIELD | NVME_DNR;
}
+ if (!req->ns->params.attached) {
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
if (!(req->ns->iocs[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) {
trace_pci_nvme_err_invalid_opc(req->cmd.opcode);
@@ -1222,6 +1225,7 @@ static uint16_t nvme_smart_info(NvmeCtrl *n, uint8_t rae, uint32_t buf_len,
uint32_t trans_len;
NvmeNamespace *ns;
time_t current_ms;
+ int i;
if (off >= sizeof(smart)) {
return NVME_INVALID_FIELD | NVME_DNR;
@@ -1232,15 +1236,18 @@ static uint16_t nvme_smart_info(NvmeCtrl *n, uint8_t rae, uint32_t buf_len,
if (!ns) {
return NVME_INVALID_NSID | NVME_DNR;
}
- nvme_set_blk_stats(ns, &stats);
+ if (ns->params.attached) {
+ nvme_set_blk_stats(ns, &stats);
+ }
} else {
- int i;
-
for (i = 1; i <= n->num_namespaces; i++) {
ns = nvme_ns(n, i);
if (!ns) {
continue;
}
+ if (!ns->params.attached) {
+ continue;
+ }
nvme_set_blk_stats(ns, &stats);
}
}
@@ -1529,7 +1536,8 @@ static uint16_t nvme_identify_ctrl_csi(NvmeCtrl *n, NvmeRequest *req)
return NVME_INVALID_FIELD | NVME_DNR;
}
-static uint16_t nvme_identify_ns(NvmeCtrl *n, NvmeRequest *req)
+static uint16_t nvme_identify_ns(NvmeCtrl *n, NvmeRequest *req,
+ bool only_active)
{
NvmeNamespace *ns;
NvmeIdentify *c = (NvmeIdentify *)&req->cmd;
@@ -1546,11 +1554,16 @@ static uint16_t nvme_identify_ns(NvmeCtrl *n, NvmeRequest *req)
return nvme_rpt_empty_id_struct(n, req);
}
+ if (only_active && !ns->params.attached) {
+ return nvme_rpt_empty_id_struct(n, req);
+ }
+
return nvme_dma(n, (uint8_t *)&ns->id_ns, sizeof(NvmeIdNs),
DMA_DIRECTION_FROM_DEVICE, req);
}
-static uint16_t nvme_identify_ns_csi(NvmeCtrl *n, NvmeRequest *req)
+static uint16_t nvme_identify_ns_csi(NvmeCtrl *n, NvmeRequest *req,
+ bool only_active)
{
NvmeNamespace *ns;
NvmeIdentify *c = (NvmeIdentify *)&req->cmd;
@@ -1567,6 +1580,10 @@ static uint16_t nvme_identify_ns_csi(NvmeCtrl *n, NvmeRequest *req)
return nvme_rpt_empty_id_struct(n, req);
}
+ if (only_active && !ns->params.attached) {
+ return nvme_rpt_empty_id_struct(n, req);
+ }
+
if (c->csi == NVME_CSI_NVM) {
return nvme_rpt_empty_id_struct(n, req);
}
@@ -1574,7 +1591,8 @@ static uint16_t nvme_identify_ns_csi(NvmeCtrl *n, NvmeRequest *req)
return NVME_INVALID_FIELD | NVME_DNR;
}
-static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeRequest *req)
+static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeRequest *req,
+ bool only_active)
{
NvmeNamespace *ns;
NvmeIdentify *c = (NvmeIdentify *)&req->cmd;
@@ -1604,6 +1622,9 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeRequest *req)
if (ns->params.nsid < min_nsid) {
continue;
}
+ if (only_active && !ns->params.attached) {
+ continue;
+ }
list_ptr[j++] = cpu_to_le32(ns->params.nsid);
if (j == data_len / sizeof(uint32_t)) {
break;
@@ -1613,7 +1634,8 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeRequest *req)
return nvme_dma(n, list, data_len, DMA_DIRECTION_FROM_DEVICE, req);
}
-static uint16_t nvme_identify_nslist_csi(NvmeCtrl *n, NvmeRequest *req)
+static uint16_t nvme_identify_nslist_csi(NvmeCtrl *n, NvmeRequest *req,
+ bool only_active)
{
NvmeNamespace *ns;
NvmeIdentify *c = (NvmeIdentify *)&req->cmd;
@@ -1637,6 +1659,9 @@ static uint16_t nvme_identify_nslist_csi(NvmeCtrl *n, NvmeRequest *req)
if (ns->params.nsid < min_nsid) {
continue;
}
+ if (only_active && !ns->params.attached) {
+ continue;
+ }
list_ptr[j++] = cpu_to_le32(ns->params.nsid);
if (j == data_len / sizeof(uint32_t)) {
break;
@@ -1710,17 +1735,25 @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeRequest *req)
switch (le32_to_cpu(c->cns)) {
case NVME_ID_CNS_NS:
- return nvme_identify_ns(n, req);
+ return nvme_identify_ns(n, req, true);
case NVME_ID_CNS_CS_NS:
- return nvme_identify_ns_csi(n, req);
+ return nvme_identify_ns_csi(n, req, true);
+ case NVME_ID_CNS_NS_PRESENT:
+ return nvme_identify_ns(n, req, false);
+ case NVME_ID_CNS_CS_NS_PRESENT:
+ return nvme_identify_ns_csi(n, req, false);
case NVME_ID_CNS_CTRL:
return nvme_identify_ctrl(n, req);
case NVME_ID_CNS_CS_CTRL:
return nvme_identify_ctrl_csi(n, req);
case NVME_ID_CNS_NS_ACTIVE_LIST:
- return nvme_identify_nslist(n, req);
+ return nvme_identify_nslist(n, req, true);
case NVME_ID_CNS_CS_NS_ACTIVE_LIST:
- return nvme_identify_nslist_csi(n, req);
+ return nvme_identify_nslist_csi(n, req, true);
+ case NVME_ID_CNS_NS_PRESENT_LIST:
+ return nvme_identify_nslist(n, req, false);
+ case NVME_ID_CNS_CS_NS_PRESENT_LIST:
+ return nvme_identify_nslist_csi(n, req, false);
case NVME_ID_CNS_NS_DESCR_LIST:
return nvme_identify_ns_descr_list(n, req);
case NVME_ID_CNS_IO_COMMAND_SET:
@@ -1793,6 +1826,7 @@ static uint16_t nvme_get_feature_timestamp(NvmeCtrl *n, NvmeRequest *req)
static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeRequest *req)
{
+ NvmeNamespace *ns;
NvmeCmd *cmd = &req->cmd;
uint32_t dw10 = le32_to_cpu(cmd->cdw10);
uint32_t dw11 = le32_to_cpu(cmd->cdw11);
@@ -1824,7 +1858,11 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeRequest *req)
return NVME_INVALID_NSID | NVME_DNR;
}
- if (!nvme_ns(n, nsid)) {
+ ns = nvme_ns(n, nsid);
+ if (!ns) {
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+ if (!ns->params.attached) {
return NVME_INVALID_FIELD | NVME_DNR;
}
}
@@ -1966,6 +2004,9 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req)
if (unlikely(!ns)) {
return NVME_INVALID_FIELD | NVME_DNR;
}
+ if (!ns->params.attached) {
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
}
} else if (nsid && nsid != NVME_NSID_BROADCAST) {
if (!nvme_nsid_valid(n, nsid)) {
@@ -2013,6 +2054,9 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req)
if (!ns) {
continue;
}
+ if (!ns->params.attached) {
+ continue;
+ }
if (!(dw11 & 0x1) && blk_enable_write_cache(ns->blkconf.blk)) {
blk_flush(ns->blkconf.blk);
@@ -805,14 +805,18 @@ typedef struct QEMU_PACKED NvmePSD {
#define NVME_IDENTIFY_DATA_SIZE 4096
enum NvmeIdCns {
- NVME_ID_CNS_NS = 0x00,
- NVME_ID_CNS_CTRL = 0x01,
- NVME_ID_CNS_NS_ACTIVE_LIST = 0x02,
- NVME_ID_CNS_NS_DESCR_LIST = 0x03,
- NVME_ID_CNS_CS_NS = 0x05,
- NVME_ID_CNS_CS_CTRL = 0x06,
- NVME_ID_CNS_CS_NS_ACTIVE_LIST = 0x07,
- NVME_ID_CNS_IO_COMMAND_SET = 0x1c,
+ NVME_ID_CNS_NS = 0x00,
+ NVME_ID_CNS_CTRL = 0x01,
+ NVME_ID_CNS_NS_ACTIVE_LIST = 0x02,
+ NVME_ID_CNS_NS_DESCR_LIST = 0x03,
+ NVME_ID_CNS_CS_NS = 0x05,
+ NVME_ID_CNS_CS_CTRL = 0x06,
+ NVME_ID_CNS_CS_NS_ACTIVE_LIST = 0x07,
+ NVME_ID_CNS_NS_PRESENT_LIST = 0x10,
+ NVME_ID_CNS_NS_PRESENT = 0x11,
+ NVME_ID_CNS_CS_NS_PRESENT_LIST = 0x1a,
+ NVME_ID_CNS_CS_NS_PRESENT = 0x1b,
+ NVME_ID_CNS_IO_COMMAND_SET = 0x1c,
};
typedef struct QEMU_PACKED NvmeIdCtrl {