@@ -922,6 +922,19 @@ typedef struct NvmeEffectsLog {
uint8_t resv[2048];
} NvmeEffectsLog;
+typedef struct NvmeTelemetry {
+ uint8_t lid;
+ uint8_t rsvd1[4];
+ uint8_t ieee[3];
+ uint16_t tda1lb;
+ uint16_t tda2lb;
+ uint16_t tda3lb;
+ uint8_t rsvd14[368];
+ uint8_t tda;
+ uint8_t tdgn;
+ uint8_t ri[128];
+} NvmeTelemetry;
+
enum {
NVME_CMD_EFF_CSUPP = 1 << 0,
NVME_CMD_EFF_LBCC = 1 << 1,
@@ -937,6 +950,8 @@ enum NvmeLogIdentifier {
NVME_LOG_SMART_INFO = 0x02,
NVME_LOG_FW_SLOT_INFO = 0x03,
NVME_LOG_CMD_EFFECTS = 0x05,
+ NVME_LOG_TEL_HOST_INIT = 0x07,
+ NVME_LOG_TEL_CTRL_INIT = 0x08,
};
typedef struct QEMU_PACKED NvmePSD {
@@ -1067,9 +1082,10 @@ enum NvmeIdCtrlFrmw {
};
enum NvmeIdCtrlLpa {
- NVME_LPA_NS_SMART = 1 << 0,
- NVME_LPA_CSE = 1 << 1,
- NVME_LPA_EXTENDED = 1 << 2,
+ NVME_LPA_NS_SMART = 1 << 0,
+ NVME_LPA_CSE = 1 << 1,
+ NVME_LPA_EXTENDED = 1 << 2,
+ NVME_LPA_TELEMETRY = 1 << 3,
};
enum NvmeIdCtrlCmic {
@@ -1395,5 +1411,6 @@ static inline void _nvme_check_size(void)
QEMU_BUILD_BUG_ON(sizeof(NvmeSglDescriptor) != 16);
QEMU_BUILD_BUG_ON(sizeof(NvmeIdNsDescr) != 4);
QEMU_BUILD_BUG_ON(sizeof(NvmeZoneDescr) != 64);
+ QEMU_BUILD_BUG_ON(sizeof(NvmeTelemetry) != 512);
}
#endif
@@ -2908,6 +2908,33 @@ static uint16_t nvme_cmd_effects(NvmeCtrl *n, uint8_t csi, uint32_t buf_len,
DMA_DIRECTION_FROM_DEVICE, req);
}
+static uint16_t nvme_telemetry(NvmeCtrl *n, uint8_t lid, uint32_t buf_len,
+ uint64_t off, NvmeRequest *req)
+{
+ NvmeTelemetry telemetry = {
+ .lid = lid,
+ .ieee[0] = 0x00,
+ .ieee[1] = 0x54,
+ .ieee[2] = 0x52,
+ };
+
+ uint32_t trans_len;
+
+ if (buf_len & 0x1ff || off & 0x1ff) {
+ trace_pci_nvme_telemetry_log_invalid(buf_len, off);
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+
+ if (off >= sizeof(telemetry)) {
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+
+ trans_len = MIN(sizeof(telemetry) - off, buf_len);
+
+ return nvme_dma(n, (uint8_t *)&telemetry + off, trans_len,
+ DMA_DIRECTION_FROM_DEVICE, req);
+}
+
static uint16_t nvme_get_log(NvmeCtrl *n, NvmeRequest *req)
{
NvmeCmd *cmd = &req->cmd;
@@ -2954,6 +2981,9 @@ static uint16_t nvme_get_log(NvmeCtrl *n, NvmeRequest *req)
return nvme_fw_log_info(n, len, off, req);
case NVME_LOG_CMD_EFFECTS:
return nvme_cmd_effects(n, csi, len, off, req);
+ case NVME_LOG_TEL_HOST_INIT:
+ case NVME_LOG_TEL_CTRL_INIT:
+ return nvme_telemetry(n, lid, len, off, req);
default:
trace_pci_nvme_err_invalid_log_page(nvme_cid(req), lid);
return NVME_INVALID_FIELD | NVME_DNR;
@@ -4707,7 +4737,8 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
id->acl = 3;
id->aerl = n->params.aerl;
id->frmw = (NVME_NUM_FW_SLOTS << 1) | NVME_FRMW_SLOT1_RO;
- id->lpa = NVME_LPA_NS_SMART | NVME_LPA_CSE | NVME_LPA_EXTENDED;
+ id->lpa = NVME_LPA_NS_SMART | NVME_LPA_CSE | NVME_LPA_EXTENDED |
+ NVME_LPA_TELEMETRY;
/* recommended default value (~70 C) */
id->wctemp = cpu_to_le16(NVME_TEMPERATURE_WARNING);
@@ -110,6 +110,7 @@ pci_nvme_set_descriptor_extension(uint64_t slba, uint32_t zone_idx) "set zone de
pci_nvme_zd_extension_set(uint32_t zone_idx) "set descriptor extension for zone_idx=%"PRIu32""
pci_nvme_clear_ns_close(uint32_t state, uint64_t slba) "zone state=%"PRIu32", slba=%"PRIu64" transitioned to Closed state"
pci_nvme_clear_ns_reset(uint32_t state, uint64_t slba) "zone state=%"PRIu32", slba=%"PRIu64" transitioned to Empty state"
+pci_nvme_telemetry_log_invalid(size_t len, uint64_t offset) "len %zu offset %"PRIu64""
# nvme traces for error conditions
pci_nvme_err_mdts(uint16_t cid, size_t len) "cid %"PRIu16" len %zu"