@@ -42,6 +42,7 @@ static void nvme_ns_init(NvmeNamespace *ns)
id_ns->nsze = cpu_to_le64(nvme_ns_nlbas(ns));
ns->csi = NVME_CSI_NVM;
+ ns->attached = true;
/* no thin provisioning */
id_ns->ncap = id_ns->nsze;
@@ -31,6 +31,7 @@ typedef struct NvmeNamespace {
int64_t size;
NvmeIdNs id_ns;
const uint32_t *iocs;
+ bool attached;
uint8_t csi;
NvmeNamespaceParams params;
@@ -1084,6 +1084,9 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req)
if (unlikely(!req->ns)) {
return NVME_INVALID_FIELD | NVME_DNR;
}
+ if (!req->ns->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);
@@ -1245,6 +1248,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;
@@ -1255,15 +1259,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->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->attached) {
+ continue;
+ }
nvme_set_blk_stats(ns, &stats);
}
}
@@ -1560,7 +1567,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;
@@ -1577,11 +1585,16 @@ static uint16_t nvme_identify_ns(NvmeCtrl *n, NvmeRequest *req)
return nvme_rpt_empty_id_struct(n, req);
}
+ if (only_active && !ns->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;
@@ -1598,6 +1611,10 @@ static uint16_t nvme_identify_ns_csi(NvmeCtrl *n, NvmeRequest *req)
return nvme_rpt_empty_id_struct(n, req);
}
+ if (only_active && !ns->attached) {
+ return nvme_rpt_empty_id_struct(n, req);
+ }
+
if (c->csi == NVME_CSI_NVM) {
return nvme_rpt_empty_id_struct(n, req);
}
@@ -1605,7 +1622,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;
@@ -1635,6 +1653,9 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeRequest *req)
if (ns->params.nsid <= min_nsid) {
continue;
}
+ if (only_active && !ns->attached) {
+ continue;
+ }
list_ptr[j++] = cpu_to_le32(ns->params.nsid);
if (j == data_len / sizeof(uint32_t)) {
break;
@@ -1644,7 +1665,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;
@@ -1675,6 +1697,9 @@ static uint16_t nvme_identify_nslist_csi(NvmeCtrl *n, NvmeRequest *req)
if (ns->params.nsid <= min_nsid) {
continue;
}
+ if (only_active && !ns->attached) {
+ continue;
+ }
list_ptr[j++] = cpu_to_le32(ns->params.nsid);
if (j == data_len / sizeof(uint32_t)) {
break;
@@ -1748,17 +1773,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:
@@ -1831,6 +1864,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);
@@ -1862,7 +1896,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->attached) {
return NVME_INVALID_FIELD | NVME_DNR;
}
}
@@ -2004,6 +2042,9 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req)
if (unlikely(!ns)) {
return NVME_INVALID_FIELD | NVME_DNR;
}
+ if (!ns->attached) {
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
}
} else if (nsid && nsid != NVME_NSID_BROADCAST) {
if (!nvme_nsid_valid(n, nsid)) {
@@ -2051,6 +2092,9 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req)
if (!ns) {
continue;
}
+ if (!ns->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 {