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:
commit
70fc2bde91
@ -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
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
|
436
hw/nvme/ctrl.c
436
hw/nvme/ctrl.c
@ -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,
|
||||||
|
44
hw/nvme/ns.c
44
hw/nvme/ns.c
@ -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[] = {
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user