nvme queue

-----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEUigzqnXi3OaiR2bATeGvMW1PDekFAmfAMFEACgkQTeGvMW1P
 DenstAf9GuLVxVUhKDlAJwyRl9Z3lrPMkKwoYF2B75fmqJhW0wZh5VSh6z/s5Qx7
 h/5soFrAMlcZPg5FO0OkY9d4psPlDHBPnuGqX2zLxx0zZnpC/QThSa6hzmETDwfv
 mXEMA/AnXar9MqjrbeR2QjVRphP9mzWpaK7JLmvX9KYvMVxqXSEq5TuylbIeyBQ5
 rSWlVnuKvVLRVtavDpZjHAk5q6CgO1nQ0N3IyIjZmllphCgrJVX5PMtiLur3dPSF
 nYv2TR3uZJmlHR9qsFEc1aIBKNSBhwBJljRuIJe+yFTI8rxCClNlqMQOfgBJp4z6
 GYHm0w0p0NLn/V5dTqLsJoHs20u46A==
 =703u
 -----END PGP SIGNATURE-----

Merge tag 'pull-nvme-20250227' of https://gitlab.com/birkelund/qemu into staging

nvme queue

# -----BEGIN PGP SIGNATURE-----
#
# iQEzBAABCgAdFiEEUigzqnXi3OaiR2bATeGvMW1PDekFAmfAMFEACgkQTeGvMW1P
# DenstAf9GuLVxVUhKDlAJwyRl9Z3lrPMkKwoYF2B75fmqJhW0wZh5VSh6z/s5Qx7
# h/5soFrAMlcZPg5FO0OkY9d4psPlDHBPnuGqX2zLxx0zZnpC/QThSa6hzmETDwfv
# mXEMA/AnXar9MqjrbeR2QjVRphP9mzWpaK7JLmvX9KYvMVxqXSEq5TuylbIeyBQ5
# rSWlVnuKvVLRVtavDpZjHAk5q6CgO1nQ0N3IyIjZmllphCgrJVX5PMtiLur3dPSF
# nYv2TR3uZJmlHR9qsFEc1aIBKNSBhwBJljRuIJe+yFTI8rxCClNlqMQOfgBJp4z6
# GYHm0w0p0NLn/V5dTqLsJoHs20u46A==
# =703u
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 27 Feb 2025 17:28:49 HKT
# gpg:                using RSA key 522833AA75E2DCE6A24766C04DE1AF316D4F0DE9
# gpg: Good signature from "Klaus Jensen <its@irrelevant.dk>" [unknown]
# gpg:                 aka "Klaus Jensen <k.jensen@samsung.com>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: DDCA 4D9C 9EF9 31CC 3468  4272 63D5 6FC5 E55D A838
#      Subkey fingerprint: 5228 33AA 75E2 DCE6 A247  66C0 4DE1 AF31 6D4F 0DE9

* tag 'pull-nvme-20250227' of https://gitlab.com/birkelund/qemu:
  hw/nvme: remove nvme_aio_err()
  hw/nvme: set error status code explicitly for misc commands
  hw/nvme: only set command abort requested when cancelled due to Abort
  hw/nvme: rework csi handling
  hw/nvme: be compliant wrt. dsm processing limits
  nvme: fix iocs status code values
  hw/nvme: add knob for doorbell buffer config support
  hw/nvme: make oacs dynamic
  hw/nvme: always initialize a subsystem
  hw/nvme: Add OCP SMART / Health Information Extended Log Page

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2025-03-03 10:20:48 +08:00
commit 70fc2bde91
5 changed files with 373 additions and 230 deletions

View File

@ -53,6 +53,13 @@ parameters.
Vendor ID. Set this to ``on`` to revert to the unallocated Intel ID Vendor ID. Set this to ``on`` to revert to the unallocated Intel ID
previously used. previously used.
``ocp`` (default: ``off``)
The Open Compute Project defines the Datacenter NVMe SSD Specification that
sits on top of NVMe. It describes additional commands and NVMe behaviors
specific for the Datacenter. When this option is ``on`` OCP features such as
the SMART / Health information extended log become available in the
controller. We emulate version 5 of this log page.
Additional Namespaces Additional Namespaces
--------------------- ---------------------

View File

@ -266,7 +266,7 @@ static const uint32_t nvme_feature_cap[NVME_FID_MAX] = {
[NVME_FDP_EVENTS] = NVME_FEAT_CAP_CHANGE | NVME_FEAT_CAP_NS, [NVME_FDP_EVENTS] = NVME_FEAT_CAP_CHANGE | NVME_FEAT_CAP_NS,
}; };
static const uint32_t nvme_cse_acs[256] = { static const uint32_t nvme_cse_acs_default[256] = {
[NVME_ADM_CMD_DELETE_SQ] = NVME_CMD_EFF_CSUPP, [NVME_ADM_CMD_DELETE_SQ] = NVME_CMD_EFF_CSUPP,
[NVME_ADM_CMD_CREATE_SQ] = NVME_CMD_EFF_CSUPP, [NVME_ADM_CMD_CREATE_SQ] = NVME_CMD_EFF_CSUPP,
[NVME_ADM_CMD_GET_LOG_PAGE] = NVME_CMD_EFF_CSUPP, [NVME_ADM_CMD_GET_LOG_PAGE] = NVME_CMD_EFF_CSUPP,
@ -277,17 +277,14 @@ static const uint32_t nvme_cse_acs[256] = {
[NVME_ADM_CMD_SET_FEATURES] = NVME_CMD_EFF_CSUPP, [NVME_ADM_CMD_SET_FEATURES] = NVME_CMD_EFF_CSUPP,
[NVME_ADM_CMD_GET_FEATURES] = NVME_CMD_EFF_CSUPP, [NVME_ADM_CMD_GET_FEATURES] = NVME_CMD_EFF_CSUPP,
[NVME_ADM_CMD_ASYNC_EV_REQ] = NVME_CMD_EFF_CSUPP, [NVME_ADM_CMD_ASYNC_EV_REQ] = NVME_CMD_EFF_CSUPP,
[NVME_ADM_CMD_NS_ATTACHMENT] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_NIC, [NVME_ADM_CMD_NS_ATTACHMENT] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_NIC |
[NVME_ADM_CMD_VIRT_MNGMT] = NVME_CMD_EFF_CSUPP, NVME_CMD_EFF_CCC,
[NVME_ADM_CMD_DBBUF_CONFIG] = NVME_CMD_EFF_CSUPP,
[NVME_ADM_CMD_FORMAT_NVM] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, [NVME_ADM_CMD_FORMAT_NVM] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
[NVME_ADM_CMD_DIRECTIVE_RECV] = NVME_CMD_EFF_CSUPP, [NVME_ADM_CMD_DIRECTIVE_RECV] = NVME_CMD_EFF_CSUPP,
[NVME_ADM_CMD_DIRECTIVE_SEND] = NVME_CMD_EFF_CSUPP, [NVME_ADM_CMD_DIRECTIVE_SEND] = NVME_CMD_EFF_CSUPP,
}; };
static const uint32_t nvme_cse_iocs_none[256]; static const uint32_t nvme_cse_iocs_nvm_default[256] = {
static const uint32_t nvme_cse_iocs_nvm[256] = {
[NVME_CMD_FLUSH] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, [NVME_CMD_FLUSH] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
[NVME_CMD_WRITE_ZEROES] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, [NVME_CMD_WRITE_ZEROES] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
[NVME_CMD_WRITE] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, [NVME_CMD_WRITE] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
@ -300,7 +297,7 @@ static const uint32_t nvme_cse_iocs_nvm[256] = {
[NVME_CMD_IO_MGMT_SEND] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, [NVME_CMD_IO_MGMT_SEND] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
}; };
static const uint32_t nvme_cse_iocs_zoned[256] = { static const uint32_t nvme_cse_iocs_zoned_default[256] = {
[NVME_CMD_FLUSH] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, [NVME_CMD_FLUSH] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
[NVME_CMD_WRITE_ZEROES] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, [NVME_CMD_WRITE_ZEROES] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
[NVME_CMD_WRITE] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, [NVME_CMD_WRITE] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
@ -309,6 +306,9 @@ static const uint32_t nvme_cse_iocs_zoned[256] = {
[NVME_CMD_VERIFY] = NVME_CMD_EFF_CSUPP, [NVME_CMD_VERIFY] = NVME_CMD_EFF_CSUPP,
[NVME_CMD_COPY] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, [NVME_CMD_COPY] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
[NVME_CMD_COMPARE] = NVME_CMD_EFF_CSUPP, [NVME_CMD_COMPARE] = NVME_CMD_EFF_CSUPP,
[NVME_CMD_IO_MGMT_RECV] = NVME_CMD_EFF_CSUPP,
[NVME_CMD_IO_MGMT_SEND] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
[NVME_CMD_ZONE_APPEND] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, [NVME_CMD_ZONE_APPEND] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
[NVME_CMD_ZONE_MGMT_SEND] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, [NVME_CMD_ZONE_MGMT_SEND] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
[NVME_CMD_ZONE_MGMT_RECV] = NVME_CMD_EFF_CSUPP, [NVME_CMD_ZONE_MGMT_RECV] = NVME_CMD_EFF_CSUPP,
@ -1762,47 +1762,6 @@ static uint16_t nvme_check_dulbe(NvmeNamespace *ns, uint64_t slba,
return NVME_SUCCESS; return NVME_SUCCESS;
} }
static void nvme_aio_err(NvmeRequest *req, int ret)
{
uint16_t status = NVME_SUCCESS;
Error *local_err = NULL;
switch (req->cmd.opcode) {
case NVME_CMD_READ:
status = NVME_UNRECOVERED_READ;
break;
case NVME_CMD_FLUSH:
case NVME_CMD_WRITE:
case NVME_CMD_WRITE_ZEROES:
case NVME_CMD_ZONE_APPEND:
case NVME_CMD_COPY:
status = NVME_WRITE_FAULT;
break;
default:
status = NVME_INTERNAL_DEV_ERROR;
break;
}
if (ret == -ECANCELED) {
status = NVME_CMD_ABORT_REQ;
}
trace_pci_nvme_err_aio(nvme_cid(req), strerror(-ret), status);
error_setg_errno(&local_err, -ret, "aio failed");
error_report_err(local_err);
/*
* Set the command status code to the first encountered error but allow a
* subsequent Internal Device Error to trump it.
*/
if (req->status && status != NVME_INTERNAL_DEV_ERROR) {
return;
}
req->status = status;
}
static inline uint32_t nvme_zone_idx(NvmeNamespace *ns, uint64_t slba) static inline uint32_t nvme_zone_idx(NvmeNamespace *ns, uint64_t slba)
{ {
return ns->zone_size_log2 > 0 ? slba >> ns->zone_size_log2 : return ns->zone_size_log2 > 0 ? slba >> ns->zone_size_log2 :
@ -2161,11 +2120,16 @@ static inline bool nvme_is_write(NvmeRequest *req)
static void nvme_misc_cb(void *opaque, int ret) static void nvme_misc_cb(void *opaque, int ret)
{ {
NvmeRequest *req = opaque; NvmeRequest *req = opaque;
uint16_t cid = nvme_cid(req);
trace_pci_nvme_misc_cb(nvme_cid(req)); trace_pci_nvme_misc_cb(cid);
if (ret) { if (ret) {
nvme_aio_err(req, ret); if (!req->status) {
req->status = NVME_INTERNAL_DEV_ERROR;
}
trace_pci_nvme_err_aio(cid, strerror(-ret), req->status);
} }
nvme_enqueue_req_completion(nvme_cq(req), req); nvme_enqueue_req_completion(nvme_cq(req), req);
@ -2182,8 +2146,30 @@ void nvme_rw_complete_cb(void *opaque, int ret)
trace_pci_nvme_rw_complete_cb(nvme_cid(req), blk_name(blk)); trace_pci_nvme_rw_complete_cb(nvme_cid(req), blk_name(blk));
if (ret) { if (ret) {
Error *err = NULL;
block_acct_failed(stats, acct); block_acct_failed(stats, acct);
nvme_aio_err(req, ret);
switch (req->cmd.opcode) {
case NVME_CMD_READ:
req->status = NVME_UNRECOVERED_READ;
break;
case NVME_CMD_WRITE:
case NVME_CMD_WRITE_ZEROES:
case NVME_CMD_ZONE_APPEND:
req->status = NVME_WRITE_FAULT;
break;
default:
req->status = NVME_INTERNAL_DEV_ERROR;
break;
}
trace_pci_nvme_err_aio(nvme_cid(req), strerror(-ret), req->status);
error_setg_errno(&err, -ret, "aio failed");
error_report_err(err);
} else { } else {
block_acct_done(stats, acct); block_acct_done(stats, acct);
} }
@ -2268,7 +2254,10 @@ static void nvme_verify_cb(void *opaque, int ret)
if (ret) { if (ret) {
block_acct_failed(stats, acct); block_acct_failed(stats, acct);
nvme_aio_err(req, ret); req->status = NVME_UNRECOVERED_READ;
trace_pci_nvme_err_aio(nvme_cid(req), strerror(-ret), req->status);
goto out; goto out;
} }
@ -2367,7 +2356,10 @@ static void nvme_compare_mdata_cb(void *opaque, int ret)
if (ret) { if (ret) {
block_acct_failed(stats, acct); block_acct_failed(stats, acct);
nvme_aio_err(req, ret); req->status = NVME_UNRECOVERED_READ;
trace_pci_nvme_err_aio(nvme_cid(req), strerror(-ret), req->status);
goto out; goto out;
} }
@ -2449,7 +2441,10 @@ static void nvme_compare_data_cb(void *opaque, int ret)
if (ret) { if (ret) {
block_acct_failed(stats, acct); block_acct_failed(stats, acct);
nvme_aio_err(req, ret); req->status = NVME_UNRECOVERED_READ;
trace_pci_nvme_err_aio(nvme_cid(req), strerror(-ret), req->status);
goto out; goto out;
} }
@ -2928,6 +2923,7 @@ static void nvme_copy_out_completed_cb(void *opaque, int ret)
if (ret < 0) { if (ret < 0) {
iocb->ret = ret; iocb->ret = ret;
req->status = NVME_WRITE_FAULT;
goto out; goto out;
} else if (iocb->ret < 0) { } else if (iocb->ret < 0) {
goto out; goto out;
@ -2992,6 +2988,7 @@ static void nvme_copy_in_completed_cb(void *opaque, int ret)
if (ret < 0) { if (ret < 0) {
iocb->ret = ret; iocb->ret = ret;
req->status = NVME_UNRECOVERED_READ;
goto out; goto out;
} else if (iocb->ret < 0) { } else if (iocb->ret < 0) {
goto out; goto out;
@ -3514,6 +3511,7 @@ static void nvme_flush_ns_cb(void *opaque, int ret)
if (ret < 0) { if (ret < 0) {
iocb->ret = ret; iocb->ret = ret;
iocb->req->status = NVME_WRITE_FAULT;
goto out; goto out;
} else if (iocb->ret < 0) { } else if (iocb->ret < 0) {
goto out; goto out;
@ -4605,6 +4603,61 @@ static uint16_t nvme_io_mgmt_send(NvmeCtrl *n, NvmeRequest *req)
}; };
} }
static uint16_t __nvme_io_cmd_nvm(NvmeCtrl *n, NvmeRequest *req)
{
switch (req->cmd.opcode) {
case NVME_CMD_WRITE:
return nvme_write(n, req);
case NVME_CMD_READ:
return nvme_read(n, req);
case NVME_CMD_COMPARE:
return nvme_compare(n, req);
case NVME_CMD_WRITE_ZEROES:
return nvme_write_zeroes(n, req);
case NVME_CMD_DSM:
return nvme_dsm(n, req);
case NVME_CMD_VERIFY:
return nvme_verify(n, req);
case NVME_CMD_COPY:
return nvme_copy(n, req);
case NVME_CMD_IO_MGMT_RECV:
return nvme_io_mgmt_recv(n, req);
case NVME_CMD_IO_MGMT_SEND:
return nvme_io_mgmt_send(n, req);
}
g_assert_not_reached();
}
static uint16_t nvme_io_cmd_nvm(NvmeCtrl *n, NvmeRequest *req)
{
if (!(n->cse.iocs.nvm[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) {
trace_pci_nvme_err_invalid_opc(req->cmd.opcode);
return NVME_INVALID_OPCODE | NVME_DNR;
}
return __nvme_io_cmd_nvm(n, req);
}
static uint16_t nvme_io_cmd_zoned(NvmeCtrl *n, NvmeRequest *req)
{
if (!(n->cse.iocs.zoned[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) {
trace_pci_nvme_err_invalid_opc(req->cmd.opcode);
return NVME_INVALID_OPCODE | NVME_DNR;
}
switch (req->cmd.opcode) {
case NVME_CMD_ZONE_APPEND:
return nvme_zone_append(n, req);
case NVME_CMD_ZONE_MGMT_SEND:
return nvme_zone_mgmt_send(n, req);
case NVME_CMD_ZONE_MGMT_RECV:
return nvme_zone_mgmt_recv(n, req);
}
return __nvme_io_cmd_nvm(n, req);
}
static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req) static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req)
{ {
NvmeNamespace *ns; NvmeNamespace *ns;
@ -4646,11 +4699,6 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req)
return NVME_INVALID_FIELD | NVME_DNR; return NVME_INVALID_FIELD | NVME_DNR;
} }
if (!(ns->iocs[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) {
trace_pci_nvme_err_invalid_opc(req->cmd.opcode);
return NVME_INVALID_OPCODE | NVME_DNR;
}
if (ns->status) { if (ns->status) {
return ns->status; return ns->status;
} }
@ -4661,36 +4709,14 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req)
req->ns = ns; req->ns = ns;
switch (req->cmd.opcode) { switch (ns->csi) {
case NVME_CMD_WRITE_ZEROES: case NVME_CSI_NVM:
return nvme_write_zeroes(n, req); return nvme_io_cmd_nvm(n, req);
case NVME_CMD_ZONE_APPEND: case NVME_CSI_ZONED:
return nvme_zone_append(n, req); return nvme_io_cmd_zoned(n, req);
case NVME_CMD_WRITE:
return nvme_write(n, req);
case NVME_CMD_READ:
return nvme_read(n, req);
case NVME_CMD_COMPARE:
return nvme_compare(n, req);
case NVME_CMD_DSM:
return nvme_dsm(n, req);
case NVME_CMD_VERIFY:
return nvme_verify(n, req);
case NVME_CMD_COPY:
return nvme_copy(n, req);
case NVME_CMD_ZONE_MGMT_SEND:
return nvme_zone_mgmt_send(n, req);
case NVME_CMD_ZONE_MGMT_RECV:
return nvme_zone_mgmt_recv(n, req);
case NVME_CMD_IO_MGMT_RECV:
return nvme_io_mgmt_recv(n, req);
case NVME_CMD_IO_MGMT_SEND:
return nvme_io_mgmt_send(n, req);
default:
g_assert_not_reached();
} }
return NVME_INVALID_OPCODE | NVME_DNR; g_assert_not_reached();
} }
static void nvme_cq_notifier(EventNotifier *e) static void nvme_cq_notifier(EventNotifier *e)
@ -4799,6 +4825,7 @@ static uint16_t nvme_del_sq(NvmeCtrl *n, NvmeRequest *req)
while (!QTAILQ_EMPTY(&sq->out_req_list)) { while (!QTAILQ_EMPTY(&sq->out_req_list)) {
r = QTAILQ_FIRST(&sq->out_req_list); r = QTAILQ_FIRST(&sq->out_req_list);
assert(r->aiocb); assert(r->aiocb);
r->status = NVME_CMD_ABORT_SQ_DEL;
blk_aio_cancel(r->aiocb); blk_aio_cancel(r->aiocb);
} }
@ -4917,6 +4944,45 @@ static void nvme_set_blk_stats(NvmeNamespace *ns, struct nvme_stats *stats)
stats->write_commands += s->nr_ops[BLOCK_ACCT_WRITE]; stats->write_commands += s->nr_ops[BLOCK_ACCT_WRITE];
} }
static uint16_t nvme_ocp_extended_smart_info(NvmeCtrl *n, uint8_t rae,
uint32_t buf_len, uint64_t off,
NvmeRequest *req)
{
NvmeNamespace *ns = NULL;
NvmeSmartLogExtended smart_l = { 0 };
struct nvme_stats stats = { 0 };
uint32_t trans_len;
if (off >= sizeof(smart_l)) {
return NVME_INVALID_FIELD | NVME_DNR;
}
/* accumulate all stats from all namespaces */
for (int i = 1; i <= NVME_MAX_NAMESPACES; i++) {
ns = nvme_ns(n, i);
if (ns) {
nvme_set_blk_stats(ns, &stats);
}
}
smart_l.physical_media_units_written[0] = cpu_to_le64(stats.units_written);
smart_l.physical_media_units_read[0] = cpu_to_le64(stats.units_read);
smart_l.log_page_version = 0x0005;
static const uint8_t guid[16] = {
0xC5, 0xAF, 0x10, 0x28, 0xEA, 0xBF, 0xF2, 0xA4,
0x9C, 0x4F, 0x6F, 0x7C, 0xC9, 0x14, 0xD5, 0xAF
};
memcpy(smart_l.log_page_guid, guid, sizeof(smart_l.log_page_guid));
if (!rae) {
nvme_clear_events(n, NVME_AER_TYPE_SMART);
}
trans_len = MIN(sizeof(smart_l) - off, buf_len);
return nvme_c2h(n, (uint8_t *) &smart_l + off, trans_len, req);
}
static uint16_t nvme_smart_info(NvmeCtrl *n, uint8_t rae, uint32_t buf_len, static uint16_t nvme_smart_info(NvmeCtrl *n, uint8_t rae, uint32_t buf_len,
uint64_t off, NvmeRequest *req) uint64_t off, NvmeRequest *req)
{ {
@ -5110,7 +5176,7 @@ static uint16_t nvme_cmd_effects(NvmeCtrl *n, uint8_t csi, uint32_t buf_len,
uint64_t off, NvmeRequest *req) uint64_t off, NvmeRequest *req)
{ {
NvmeEffectsLog log = {}; NvmeEffectsLog log = {};
const uint32_t *src_iocs = NULL; const uint32_t *iocs = NULL;
uint32_t trans_len; uint32_t trans_len;
if (off >= sizeof(log)) { if (off >= sizeof(log)) {
@ -5120,25 +5186,26 @@ static uint16_t nvme_cmd_effects(NvmeCtrl *n, uint8_t csi, uint32_t buf_len,
switch (NVME_CC_CSS(ldl_le_p(&n->bar.cc))) { switch (NVME_CC_CSS(ldl_le_p(&n->bar.cc))) {
case NVME_CC_CSS_NVM: case NVME_CC_CSS_NVM:
src_iocs = nvme_cse_iocs_nvm; iocs = n->cse.iocs.nvm;
/* fall through */
case NVME_CC_CSS_ADMIN_ONLY:
break; break;
case NVME_CC_CSS_CSI:
case NVME_CC_CSS_ALL:
switch (csi) { switch (csi) {
case NVME_CSI_NVM: case NVME_CSI_NVM:
src_iocs = nvme_cse_iocs_nvm; iocs = n->cse.iocs.nvm;
break; break;
case NVME_CSI_ZONED: case NVME_CSI_ZONED:
src_iocs = nvme_cse_iocs_zoned; iocs = n->cse.iocs.zoned;
break; break;
} }
break;
} }
memcpy(log.acs, nvme_cse_acs, sizeof(nvme_cse_acs)); memcpy(log.acs, n->cse.acs, sizeof(log.acs));
if (src_iocs) { if (iocs) {
memcpy(log.iocs, src_iocs, sizeof(log.iocs)); memcpy(log.iocs, iocs, sizeof(log.iocs));
} }
trans_len = MIN(sizeof(log) - off, buf_len); trans_len = MIN(sizeof(log) - off, buf_len);
@ -5146,6 +5213,23 @@ static uint16_t nvme_cmd_effects(NvmeCtrl *n, uint8_t csi, uint32_t buf_len,
return nvme_c2h(n, ((uint8_t *)&log) + off, trans_len, req); return nvme_c2h(n, ((uint8_t *)&log) + off, trans_len, req);
} }
static uint16_t nvme_vendor_specific_log(NvmeCtrl *n, uint8_t rae,
uint32_t buf_len, uint64_t off,
NvmeRequest *req, uint8_t lid)
{
switch (lid) {
case NVME_OCP_EXTENDED_SMART_INFO:
if (n->params.ocp) {
return nvme_ocp_extended_smart_info(n, rae, buf_len, off, req);
}
break;
/* add a case for each additional vendor specific log id */
}
trace_pci_nvme_err_invalid_log_page(nvme_cid(req), lid);
return NVME_INVALID_FIELD | NVME_DNR;
}
static size_t sizeof_fdp_conf_descr(size_t nruh, size_t vss) static size_t sizeof_fdp_conf_descr(size_t nruh, size_t vss)
{ {
size_t entry_siz = sizeof(NvmeFdpDescrHdr) + nruh * sizeof(NvmeRuhDescr) size_t entry_siz = sizeof(NvmeFdpDescrHdr) + nruh * sizeof(NvmeRuhDescr)
@ -5396,6 +5480,8 @@ static uint16_t nvme_get_log(NvmeCtrl *n, NvmeRequest *req)
return nvme_smart_info(n, rae, len, off, req); return nvme_smart_info(n, rae, len, off, req);
case NVME_LOG_FW_SLOT_INFO: case NVME_LOG_FW_SLOT_INFO:
return nvme_fw_log_info(n, len, off, req); return nvme_fw_log_info(n, len, off, req);
case NVME_LOG_VENDOR_START...NVME_LOG_VENDOR_END:
return nvme_vendor_specific_log(n, rae, len, off, req, lid);
case NVME_LOG_CHANGED_NSLIST: case NVME_LOG_CHANGED_NSLIST:
return nvme_changed_nslist(n, rae, len, off, req); return nvme_changed_nslist(n, rae, len, off, req);
case NVME_LOG_CMD_EFFECTS: case NVME_LOG_CMD_EFFECTS:
@ -5583,7 +5669,9 @@ static uint16_t nvme_identify_ctrl_csi(NvmeCtrl *n, NvmeRequest *req)
switch (c->csi) { switch (c->csi) {
case NVME_CSI_NVM: case NVME_CSI_NVM:
id_nvm->vsl = n->params.vsl; id_nvm->vsl = n->params.vsl;
id_nvm->dmrl = NVME_ID_CTRL_NVM_DMRL_MAX;
id_nvm->dmrsl = cpu_to_le32(n->dmrsl); id_nvm->dmrsl = cpu_to_le32(n->dmrsl);
id_nvm->dmsl = NVME_ID_CTRL_NVM_DMRL_MAX * n->dmrsl;
break; break;
case NVME_CSI_ZONED: case NVME_CSI_ZONED:
@ -5625,7 +5713,7 @@ static uint16_t nvme_identify_ns(NvmeCtrl *n, NvmeRequest *req, bool active)
return nvme_c2h(n, (uint8_t *)&ns->id_ns, sizeof(NvmeIdNs), req); return nvme_c2h(n, (uint8_t *)&ns->id_ns, sizeof(NvmeIdNs), req);
} }
return NVME_INVALID_CMD_SET | NVME_DNR; return NVME_INVALID_IOCS | NVME_DNR;
} }
static uint16_t nvme_identify_ctrl_list(NvmeCtrl *n, NvmeRequest *req, static uint16_t nvme_identify_ctrl_list(NvmeCtrl *n, NvmeRequest *req,
@ -6048,6 +6136,7 @@ static uint16_t nvme_abort(NvmeCtrl *n, NvmeRequest *req)
QTAILQ_FOREACH_SAFE(r, &sq->out_req_list, entry, next) { QTAILQ_FOREACH_SAFE(r, &sq->out_req_list, entry, next) {
if (r->cqe.cid == cid) { if (r->cqe.cid == cid) {
if (r->aiocb) { if (r->aiocb) {
r->status = NVME_CMD_ABORT_REQ;
blk_aio_cancel_async(r->aiocb); blk_aio_cancel_async(r->aiocb);
} }
break; break;
@ -6591,7 +6680,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req)
case NVME_COMMAND_SET_PROFILE: case NVME_COMMAND_SET_PROFILE:
if (dw11 & 0x1ff) { if (dw11 & 0x1ff) {
trace_pci_nvme_err_invalid_iocsci(dw11 & 0x1ff); trace_pci_nvme_err_invalid_iocsci(dw11 & 0x1ff);
return NVME_CMD_SET_CMB_REJECTED | NVME_DNR; return NVME_IOCS_COMBINATION_REJECTED | NVME_DNR;
} }
break; break;
case NVME_FDP_MODE: case NVME_FDP_MODE:
@ -6640,40 +6729,49 @@ static uint16_t nvme_aer(NvmeCtrl *n, NvmeRequest *req)
return NVME_NO_COMPLETE; return NVME_NO_COMPLETE;
} }
static void nvme_update_dmrsl(NvmeCtrl *n) static void nvme_update_dsm_limits(NvmeCtrl *n, NvmeNamespace *ns)
{ {
int nsid; if (ns) {
n->dmrsl =
MIN_NON_ZERO(n->dmrsl, BDRV_REQUEST_MAX_BYTES / nvme_l2b(ns, 1));
for (nsid = 1; nsid <= NVME_MAX_NAMESPACES; nsid++) { return;
NvmeNamespace *ns = nvme_ns(n, nsid); }
for (uint32_t nsid = 1; nsid <= NVME_MAX_NAMESPACES; nsid++) {
ns = nvme_ns(n, nsid);
if (!ns) { if (!ns) {
continue; continue;
} }
n->dmrsl = MIN_NON_ZERO(n->dmrsl, n->dmrsl =
BDRV_REQUEST_MAX_BYTES / nvme_l2b(ns, 1)); MIN_NON_ZERO(n->dmrsl, BDRV_REQUEST_MAX_BYTES / nvme_l2b(ns, 1));
} }
} }
static void nvme_select_iocs_ns(NvmeCtrl *n, NvmeNamespace *ns) static bool nvme_csi_supported(NvmeCtrl *n, uint8_t csi)
{ {
uint32_t cc = ldl_le_p(&n->bar.cc); uint32_t cc;
ns->iocs = nvme_cse_iocs_none; switch (csi) {
switch (ns->csi) {
case NVME_CSI_NVM: case NVME_CSI_NVM:
if (NVME_CC_CSS(cc) != NVME_CC_CSS_ADMIN_ONLY) { return true;
ns->iocs = nvme_cse_iocs_nvm;
}
break;
case NVME_CSI_ZONED: case NVME_CSI_ZONED:
if (NVME_CC_CSS(cc) == NVME_CC_CSS_CSI) { cc = ldl_le_p(&n->bar.cc);
ns->iocs = nvme_cse_iocs_zoned;
} else if (NVME_CC_CSS(cc) == NVME_CC_CSS_NVM) { return NVME_CC_CSS(cc) == NVME_CC_CSS_ALL;
ns->iocs = nvme_cse_iocs_nvm;
} }
break;
g_assert_not_reached();
} }
static void nvme_detach_ns(NvmeCtrl *n, NvmeNamespace *ns)
{
assert(ns->attached > 0);
n->namespaces[ns->params.nsid] = NULL;
ns->attached--;
} }
static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req) static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req)
@ -6718,7 +6816,7 @@ static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req)
switch (sel) { switch (sel) {
case NVME_NS_ATTACHMENT_ATTACH: case NVME_NS_ATTACHMENT_ATTACH:
if (nvme_ns(ctrl, nsid)) { if (nvme_ns(n, nsid)) {
return NVME_NS_ALREADY_ATTACHED | NVME_DNR; return NVME_NS_ALREADY_ATTACHED | NVME_DNR;
} }
@ -6726,20 +6824,18 @@ static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req)
return NVME_NS_PRIVATE | NVME_DNR; return NVME_NS_PRIVATE | NVME_DNR;
} }
if (!nvme_csi_supported(n, ns->csi)) {
return NVME_IOCS_NOT_SUPPORTED | NVME_DNR;
}
nvme_attach_ns(ctrl, ns); nvme_attach_ns(ctrl, ns);
nvme_select_iocs_ns(ctrl, ns); nvme_update_dsm_limits(ctrl, ns);
break; break;
case NVME_NS_ATTACHMENT_DETACH: case NVME_NS_ATTACHMENT_DETACH:
if (!nvme_ns(ctrl, nsid)) { nvme_detach_ns(ctrl, ns);
return NVME_NS_NOT_ATTACHED | NVME_DNR; nvme_update_dsm_limits(ctrl, NULL);
}
ctrl->namespaces[nsid] = NULL;
ns->attached--;
nvme_update_dmrsl(ctrl);
break; break;
@ -7242,7 +7338,7 @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeRequest *req)
trace_pci_nvme_admin_cmd(nvme_cid(req), nvme_sqid(req), req->cmd.opcode, trace_pci_nvme_admin_cmd(nvme_cid(req), nvme_sqid(req), req->cmd.opcode,
nvme_adm_opc_str(req->cmd.opcode)); nvme_adm_opc_str(req->cmd.opcode));
if (!(nvme_cse_acs[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) { if (!(n->cse.acs[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) {
trace_pci_nvme_err_invalid_admin_opc(req->cmd.opcode); trace_pci_nvme_err_invalid_admin_opc(req->cmd.opcode);
return NVME_INVALID_OPCODE | NVME_DNR; return NVME_INVALID_OPCODE | NVME_DNR;
} }
@ -7589,21 +7685,6 @@ static void nvme_ctrl_shutdown(NvmeCtrl *n)
} }
} }
static void nvme_select_iocs(NvmeCtrl *n)
{
NvmeNamespace *ns;
int i;
for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
ns = nvme_ns(n, i);
if (!ns) {
continue;
}
nvme_select_iocs_ns(n, ns);
}
}
static int nvme_start_ctrl(NvmeCtrl *n) static int nvme_start_ctrl(NvmeCtrl *n)
{ {
uint64_t cap = ldq_le_p(&n->bar.cap); uint64_t cap = ldq_le_p(&n->bar.cap);
@ -7670,7 +7751,18 @@ static int nvme_start_ctrl(NvmeCtrl *n)
nvme_set_timestamp(n, 0ULL); nvme_set_timestamp(n, 0ULL);
nvme_select_iocs(n); /* verify that the command sets of attached namespaces are supported */
for (int i = 1; i <= NVME_MAX_NAMESPACES; i++) {
NvmeNamespace *ns = nvme_subsys_ns(n->subsys, i);
if (ns && nvme_csi_supported(n, ns->csi) && !ns->params.detached) {
if (!ns->attached || ns->params.shared) {
nvme_attach_ns(n, ns);
}
}
}
nvme_update_dsm_limits(n, NULL);
return 0; return 0;
} }
@ -8682,6 +8774,12 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
uint64_t cap = ldq_le_p(&n->bar.cap); uint64_t cap = ldq_le_p(&n->bar.cap);
NvmeSecCtrlEntry *sctrl = nvme_sctrl(n); NvmeSecCtrlEntry *sctrl = nvme_sctrl(n);
uint32_t ctratt; uint32_t ctratt;
uint16_t oacs;
memcpy(n->cse.acs, nvme_cse_acs_default, sizeof(n->cse.acs));
memcpy(n->cse.iocs.nvm, nvme_cse_iocs_nvm_default, sizeof(n->cse.iocs.nvm));
memcpy(n->cse.iocs.zoned, nvme_cse_iocs_zoned_default,
sizeof(n->cse.iocs.zoned));
id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID)); id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID));
id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID)); id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID));
@ -8712,9 +8810,23 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
id->mdts = n->params.mdts; id->mdts = n->params.mdts;
id->ver = cpu_to_le32(NVME_SPEC_VER); id->ver = cpu_to_le32(NVME_SPEC_VER);
id->oacs =
cpu_to_le16(NVME_OACS_NS_MGMT | NVME_OACS_FORMAT | NVME_OACS_DBBUF | oacs = NVME_OACS_NMS | NVME_OACS_FORMAT | NVME_OACS_DIRECTIVES;
NVME_OACS_DIRECTIVES);
if (n->params.dbcs) {
oacs |= NVME_OACS_DBCS;
n->cse.acs[NVME_ADM_CMD_DBBUF_CONFIG] = NVME_CMD_EFF_CSUPP;
}
if (n->params.sriov_max_vfs) {
oacs |= NVME_OACS_VMS;
n->cse.acs[NVME_ADM_CMD_VIRT_MNGMT] = NVME_CMD_EFF_CSUPP;
}
id->oacs = cpu_to_le16(oacs);
id->cntrltype = 0x1; id->cntrltype = 0x1;
/* /*
@ -8765,7 +8877,6 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
id->psd[0].enlat = cpu_to_le32(0x10); id->psd[0].enlat = cpu_to_le32(0x10);
id->psd[0].exlat = cpu_to_le32(0x4); id->psd[0].exlat = cpu_to_le32(0x4);
if (n->subsys) {
id->cmic |= NVME_CMIC_MULTI_CTRL; id->cmic |= NVME_CMIC_MULTI_CTRL;
ctratt |= NVME_CTRATT_ENDGRPS; ctratt |= NVME_CTRATT_ENDGRPS;
@ -8774,16 +8885,14 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
if (n->subsys->endgrp.fdp.enabled) { if (n->subsys->endgrp.fdp.enabled) {
ctratt |= NVME_CTRATT_FDPS; ctratt |= NVME_CTRATT_FDPS;
} }
}
id->ctratt = cpu_to_le32(ctratt); id->ctratt = cpu_to_le32(ctratt);
NVME_CAP_SET_MQES(cap, n->params.mqes); NVME_CAP_SET_MQES(cap, n->params.mqes);
NVME_CAP_SET_CQR(cap, 1); NVME_CAP_SET_CQR(cap, 1);
NVME_CAP_SET_TO(cap, 0xf); NVME_CAP_SET_TO(cap, 0xf);
NVME_CAP_SET_CSS(cap, NVME_CAP_CSS_NVM); NVME_CAP_SET_CSS(cap, NVME_CAP_CSS_NCSS);
NVME_CAP_SET_CSS(cap, NVME_CAP_CSS_CSI_SUPP); NVME_CAP_SET_CSS(cap, NVME_CAP_CSS_IOCSS);
NVME_CAP_SET_CSS(cap, NVME_CAP_CSS_ADMIN_ONLY);
NVME_CAP_SET_MPSMAX(cap, 4); NVME_CAP_SET_MPSMAX(cap, 4);
NVME_CAP_SET_CMBS(cap, n->params.cmb_size_mb ? 1 : 0); NVME_CAP_SET_CMBS(cap, n->params.cmb_size_mb ? 1 : 0);
NVME_CAP_SET_PMRS(cap, n->pmr.dev ? 1 : 0); NVME_CAP_SET_PMRS(cap, n->pmr.dev ? 1 : 0);
@ -8802,7 +8911,15 @@ static int nvme_init_subsys(NvmeCtrl *n, Error **errp)
int cntlid; int cntlid;
if (!n->subsys) { if (!n->subsys) {
return 0; DeviceState *dev = qdev_new(TYPE_NVME_SUBSYS);
qdev_prop_set_string(dev, "nqn", n->params.serial);
if (!qdev_realize(dev, NULL, errp)) {
return -1;
}
n->subsys = NVME_SUBSYS(dev);
} }
cntlid = nvme_subsys_register_ctrl(n, errp); cntlid = nvme_subsys_register_ctrl(n, errp);
@ -8822,9 +8939,6 @@ void nvme_attach_ns(NvmeCtrl *n, NvmeNamespace *ns)
n->namespaces[nsid] = ns; n->namespaces[nsid] = ns;
ns->attached++; ns->attached++;
n->dmrsl = MIN_NON_ZERO(n->dmrsl,
BDRV_REQUEST_MAX_BYTES / nvme_l2b(ns, 1));
} }
static void nvme_realize(PCIDevice *pci_dev, Error **errp) static void nvme_realize(PCIDevice *pci_dev, Error **errp)
@ -8880,7 +8994,7 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
return; return;
} }
nvme_attach_ns(n, ns); n->subsys->namespaces[ns->params.nsid] = ns;
} }
} }
@ -8892,7 +9006,6 @@ static void nvme_exit(PCIDevice *pci_dev)
nvme_ctrl_reset(n, NVME_RESET_FUNCTION); nvme_ctrl_reset(n, NVME_RESET_FUNCTION);
if (n->subsys) {
for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
ns = nvme_ns(n, i); ns = nvme_ns(n, i);
if (ns) { if (ns) {
@ -8901,7 +9014,6 @@ static void nvme_exit(PCIDevice *pci_dev)
} }
nvme_subsys_unregister_ctrl(n->subsys, n); nvme_subsys_unregister_ctrl(n->subsys, n);
}
g_free(n->cq); g_free(n->cq);
g_free(n->sq); g_free(n->sq);
@ -8951,6 +9063,7 @@ static const Property nvme_props[] = {
DEFINE_PROP_BOOL("use-intel-id", NvmeCtrl, params.use_intel_id, false), DEFINE_PROP_BOOL("use-intel-id", NvmeCtrl, params.use_intel_id, false),
DEFINE_PROP_BOOL("legacy-cmb", NvmeCtrl, params.legacy_cmb, false), DEFINE_PROP_BOOL("legacy-cmb", NvmeCtrl, params.legacy_cmb, false),
DEFINE_PROP_BOOL("ioeventfd", NvmeCtrl, params.ioeventfd, false), DEFINE_PROP_BOOL("ioeventfd", NvmeCtrl, params.ioeventfd, false),
DEFINE_PROP_BOOL("dbcs", NvmeCtrl, params.dbcs, true),
DEFINE_PROP_UINT8("zoned.zasl", NvmeCtrl, params.zasl, 0), DEFINE_PROP_UINT8("zoned.zasl", NvmeCtrl, params.zasl, 0),
DEFINE_PROP_BOOL("zoned.auto_transition", NvmeCtrl, DEFINE_PROP_BOOL("zoned.auto_transition", NvmeCtrl,
params.auto_transition_zones, true), params.auto_transition_zones, true),
@ -8971,6 +9084,7 @@ static const Property nvme_props[] = {
DEFINE_PROP_BOOL("atomic.dn", NvmeCtrl, params.atomic_dn, 0), DEFINE_PROP_BOOL("atomic.dn", NvmeCtrl, params.atomic_dn, 0),
DEFINE_PROP_UINT16("atomic.awun", NvmeCtrl, params.atomic_awun, 0), DEFINE_PROP_UINT16("atomic.awun", NvmeCtrl, params.atomic_awun, 0),
DEFINE_PROP_UINT16("atomic.awupf", NvmeCtrl, params.atomic_awupf, 0), DEFINE_PROP_UINT16("atomic.awupf", NvmeCtrl, params.atomic_awupf, 0),
DEFINE_PROP_BOOL("ocp", NvmeCtrl, params.ocp, false),
}; };
static void nvme_get_smart_warning(Object *obj, Visitor *v, const char *name, static void nvme_get_smart_warning(Object *obj, Visitor *v, const char *name,

View File

@ -727,25 +727,14 @@ static void nvme_ns_realize(DeviceState *dev, Error **errp)
uint32_t nsid = ns->params.nsid; uint32_t nsid = ns->params.nsid;
int i; int i;
if (!n->subsys) { assert(subsys);
/* If no subsys, the ns cannot be attached to more than one ctrl. */
ns->params.shared = false; /* reparent to subsystem bus */
if (ns->params.detached) {
error_setg(errp, "detached requires that the nvme device is "
"linked to an nvme-subsys device");
return;
}
} else {
/*
* If this namespace belongs to a subsystem (through a link on the
* controller device), reparent the device.
*/
if (!qdev_set_parent_bus(dev, &subsys->bus.parent_bus, errp)) { if (!qdev_set_parent_bus(dev, &subsys->bus.parent_bus, errp)) {
return; return;
} }
ns->subsys = subsys; ns->subsys = subsys;
ns->endgrp = &subsys->endgrp; ns->endgrp = &subsys->endgrp;
}
if (nvme_ns_setup(ns, errp)) { if (nvme_ns_setup(ns, errp)) {
return; return;
@ -753,7 +742,7 @@ static void nvme_ns_realize(DeviceState *dev, Error **errp)
if (!nsid) { if (!nsid) {
for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
if (nvme_ns(n, i) || nvme_subsys_ns(subsys, i)) { if (nvme_subsys_ns(subsys, i)) {
continue; continue;
} }
@ -765,38 +754,15 @@ static void nvme_ns_realize(DeviceState *dev, Error **errp)
error_setg(errp, "no free namespace id"); error_setg(errp, "no free namespace id");
return; return;
} }
} else { } else if (nvme_subsys_ns(subsys, nsid)) {
if (nvme_ns(n, nsid) || nvme_subsys_ns(subsys, nsid)) {
error_setg(errp, "namespace id '%d' already allocated", nsid); error_setg(errp, "namespace id '%d' already allocated", nsid);
return; return;
} }
}
if (subsys) {
subsys->namespaces[nsid] = ns; subsys->namespaces[nsid] = ns;
ns->id_ns.endgid = cpu_to_le16(0x1); ns->id_ns.endgid = cpu_to_le16(0x1);
ns->id_ns_ind.endgrpid = cpu_to_le16(0x1); ns->id_ns_ind.endgrpid = cpu_to_le16(0x1);
if (ns->params.detached) {
return;
}
if (ns->params.shared) {
for (i = 0; i < ARRAY_SIZE(subsys->ctrls); i++) {
NvmeCtrl *ctrl = subsys->ctrls[i];
if (ctrl && ctrl != SUBSYS_SLOT_RSVD) {
nvme_attach_ns(ctrl, ns);
}
}
return;
}
}
nvme_attach_ns(n, ns);
} }
static const Property nvme_ns_props[] = { static const Property nvme_ns_props[] = {

View File

@ -237,7 +237,6 @@ typedef struct NvmeNamespace {
NvmeLBAF lbaf; NvmeLBAF lbaf;
unsigned int nlbaf; unsigned int nlbaf;
size_t lbasz; size_t lbasz;
const uint32_t *iocs;
uint8_t csi; uint8_t csi;
uint16_t status; uint16_t status;
int attached; int attached;
@ -539,12 +538,14 @@ typedef struct NvmeParams {
bool auto_transition_zones; bool auto_transition_zones;
bool legacy_cmb; bool legacy_cmb;
bool ioeventfd; bool ioeventfd;
bool dbcs;
uint16_t sriov_max_vfs; uint16_t sriov_max_vfs;
uint16_t sriov_vq_flexible; uint16_t sriov_vq_flexible;
uint16_t sriov_vi_flexible; uint16_t sriov_vi_flexible;
uint32_t sriov_max_vq_per_vf; uint32_t sriov_max_vq_per_vf;
uint32_t sriov_max_vi_per_vf; uint32_t sriov_max_vi_per_vf;
bool msix_exclusive_bar; bool msix_exclusive_bar;
bool ocp;
struct { struct {
bool mem; bool mem;
@ -583,6 +584,14 @@ typedef struct NvmeCtrl {
uint64_t dbbuf_eis; uint64_t dbbuf_eis;
bool dbbuf_enabled; bool dbbuf_enabled;
struct {
uint32_t acs[256];
struct {
uint32_t nvm[256];
uint32_t zoned[256];
} iocs;
} cse;
struct { struct {
MemoryRegion mem; MemoryRegion mem;
uint8_t *buf; uint8_t *buf;

View File

@ -142,9 +142,9 @@ enum NvmeCapMask {
((cap) |= (uint64_t)((val) & CAP_CMBS_MASK) << CAP_CMBS_SHIFT) ((cap) |= (uint64_t)((val) & CAP_CMBS_MASK) << CAP_CMBS_SHIFT)
enum NvmeCapCss { enum NvmeCapCss {
NVME_CAP_CSS_NVM = 1 << 0, NVME_CAP_CSS_NCSS = 1 << 0,
NVME_CAP_CSS_CSI_SUPP = 1 << 6, NVME_CAP_CSS_IOCSS = 1 << 6,
NVME_CAP_CSS_ADMIN_ONLY = 1 << 7, NVME_CAP_CSS_NOIOCSS = 1 << 7,
}; };
enum NvmeCcShift { enum NvmeCcShift {
@ -177,7 +177,7 @@ enum NvmeCcMask {
enum NvmeCcCss { enum NvmeCcCss {
NVME_CC_CSS_NVM = 0x0, NVME_CC_CSS_NVM = 0x0,
NVME_CC_CSS_CSI = 0x6, NVME_CC_CSS_ALL = 0x6,
NVME_CC_CSS_ADMIN_ONLY = 0x7, NVME_CC_CSS_ADMIN_ONLY = 0x7,
}; };
@ -906,8 +906,7 @@ enum NvmeStatusCodes {
NVME_SGL_DESCR_TYPE_INVALID = 0x0011, NVME_SGL_DESCR_TYPE_INVALID = 0x0011,
NVME_INVALID_USE_OF_CMB = 0x0012, NVME_INVALID_USE_OF_CMB = 0x0012,
NVME_INVALID_PRP_OFFSET = 0x0013, NVME_INVALID_PRP_OFFSET = 0x0013,
NVME_CMD_SET_CMB_REJECTED = 0x002b, NVME_COMMAND_INTERRUPTED = 0x0021,
NVME_INVALID_CMD_SET = 0x002c,
NVME_FDP_DISABLED = 0x0029, NVME_FDP_DISABLED = 0x0029,
NVME_INVALID_PHID_LIST = 0x002a, NVME_INVALID_PHID_LIST = 0x002a,
NVME_LBA_RANGE = 0x0080, NVME_LBA_RANGE = 0x0080,
@ -940,6 +939,10 @@ enum NvmeStatusCodes {
NVME_INVALID_SEC_CTRL_STATE = 0x0120, NVME_INVALID_SEC_CTRL_STATE = 0x0120,
NVME_INVALID_NUM_RESOURCES = 0x0121, NVME_INVALID_NUM_RESOURCES = 0x0121,
NVME_INVALID_RESOURCE_ID = 0x0122, NVME_INVALID_RESOURCE_ID = 0x0122,
NVME_IOCS_NOT_SUPPORTED = 0x0129,
NVME_IOCS_NOT_ENABLED = 0x012a,
NVME_IOCS_COMBINATION_REJECTED = 0x012b,
NVME_INVALID_IOCS = 0x012c,
NVME_CONFLICTING_ATTRS = 0x0180, NVME_CONFLICTING_ATTRS = 0x0180,
NVME_INVALID_PROT_INFO = 0x0181, NVME_INVALID_PROT_INFO = 0x0181,
NVME_WRITE_TO_RO = 0x0182, NVME_WRITE_TO_RO = 0x0182,
@ -1015,6 +1018,40 @@ typedef struct QEMU_PACKED NvmeSmartLog {
uint8_t reserved2[320]; uint8_t reserved2[320];
} NvmeSmartLog; } NvmeSmartLog;
typedef struct QEMU_PACKED NvmeSmartLogExtended {
uint64_t physical_media_units_written[2];
uint64_t physical_media_units_read[2];
uint64_t bad_user_blocks;
uint64_t bad_system_nand_blocks;
uint64_t xor_recovery_count;
uint64_t uncorrectable_read_error_count;
uint64_t soft_ecc_error_count;
uint64_t end2end_correction_counts;
uint8_t system_data_percent_used;
uint8_t refresh_counts[7];
uint64_t user_data_erase_counts;
uint16_t thermal_throttling_stat_and_count;
uint16_t dssd_spec_version[3];
uint64_t pcie_correctable_error_count;
uint32_t incomplete_shutdowns;
uint32_t rsvd116;
uint8_t percent_free_blocks;
uint8_t rsvd121[7];
uint16_t capacity_health;
uint8_t nvme_errata_ver;
uint8_t rsvd131[5];
uint64_t unaligned_io;
uint64_t security_ver_num;
uint64_t total_nuse;
uint64_t plp_start_count[2];
uint64_t endurance_estimate[2];
uint64_t pcie_retraining_count;
uint64_t power_state_change_count;
uint8_t rsvd208[286];
uint16_t log_page_version;
uint64_t log_page_guid[2];
} NvmeSmartLogExtended;
#define NVME_SMART_WARN_MAX 6 #define NVME_SMART_WARN_MAX 6
enum NvmeSmartWarn { enum NvmeSmartWarn {
NVME_SMART_SPARE = 1 << 0, NVME_SMART_SPARE = 1 << 0,
@ -1052,6 +1089,12 @@ enum NvmeLogIdentifier {
NVME_LOG_FDP_RUH_USAGE = 0x21, NVME_LOG_FDP_RUH_USAGE = 0x21,
NVME_LOG_FDP_STATS = 0x22, NVME_LOG_FDP_STATS = 0x22,
NVME_LOG_FDP_EVENTS = 0x23, NVME_LOG_FDP_EVENTS = 0x23,
NVME_LOG_VENDOR_START = 0xc0,
NVME_LOG_VENDOR_END = 0xff,
};
enum NvmeOcpLogIdentifier {
NVME_OCP_EXTENDED_SMART_INFO = 0xc0,
}; };
typedef struct QEMU_PACKED NvmePSD { typedef struct QEMU_PACKED NvmePSD {
@ -1167,6 +1210,8 @@ typedef struct NvmeIdCtrlZoned {
uint8_t rsvd1[4095]; uint8_t rsvd1[4095];
} NvmeIdCtrlZoned; } NvmeIdCtrlZoned;
#define NVME_ID_CTRL_NVM_DMRL_MAX 255
typedef struct NvmeIdCtrlNvm { typedef struct NvmeIdCtrlNvm {
uint8_t vsl; uint8_t vsl;
uint8_t wzsl; uint8_t wzsl;
@ -1192,9 +1237,10 @@ enum NvmeIdCtrlOacs {
NVME_OACS_SECURITY = 1 << 0, NVME_OACS_SECURITY = 1 << 0,
NVME_OACS_FORMAT = 1 << 1, NVME_OACS_FORMAT = 1 << 1,
NVME_OACS_FW = 1 << 2, NVME_OACS_FW = 1 << 2,
NVME_OACS_NS_MGMT = 1 << 3, NVME_OACS_NMS = 1 << 3,
NVME_OACS_DIRECTIVES = 1 << 5, NVME_OACS_DIRECTIVES = 1 << 5,
NVME_OACS_DBBUF = 1 << 8, NVME_OACS_VMS = 1 << 7,
NVME_OACS_DBCS = 1 << 8,
}; };
enum NvmeIdCtrlOncs { enum NvmeIdCtrlOncs {
@ -1899,6 +1945,7 @@ static inline void _nvme_check_size(void)
QEMU_BUILD_BUG_ON(sizeof(NvmeErrorLog) != 64); QEMU_BUILD_BUG_ON(sizeof(NvmeErrorLog) != 64);
QEMU_BUILD_BUG_ON(sizeof(NvmeFwSlotInfoLog) != 512); QEMU_BUILD_BUG_ON(sizeof(NvmeFwSlotInfoLog) != 512);
QEMU_BUILD_BUG_ON(sizeof(NvmeSmartLog) != 512); QEMU_BUILD_BUG_ON(sizeof(NvmeSmartLog) != 512);
QEMU_BUILD_BUG_ON(sizeof(NvmeSmartLogExtended) != 512);
QEMU_BUILD_BUG_ON(sizeof(NvmeEffectsLog) != 4096); QEMU_BUILD_BUG_ON(sizeof(NvmeEffectsLog) != 4096);
QEMU_BUILD_BUG_ON(sizeof(NvmeIdCtrl) != 4096); QEMU_BUILD_BUG_ON(sizeof(NvmeIdCtrl) != 4096);
QEMU_BUILD_BUG_ON(sizeof(NvmeIdCtrlZoned) != 4096); QEMU_BUILD_BUG_ON(sizeof(NvmeIdCtrlZoned) != 4096);