From 7b538d0ca7fa5ae14fe51b7d5c027669e2f2705f Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Fri, 22 Aug 2025 16:02:13 +0200 Subject: [PATCH 1/2] build: bump libnvme wrap Get latest API additions. Signed-off-by: Daniel Wagner --- subprojects/libnvme.wrap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/libnvme.wrap b/subprojects/libnvme.wrap index 8aee6de194..d065a3ff7c 100644 --- a/subprojects/libnvme.wrap +++ b/subprojects/libnvme.wrap @@ -1,6 +1,6 @@ [wrap-git] url = https://github.com/linux-nvme/libnvme.git -revision = a6497f6e8cb3bc3607e4a772b648a7887b0ab875 +revision = fde6b1f51646f7f0b4a12f61f08e2bb621f01903 [provide] libnvme = libnvme_dep From 980c0f69243a59e41cc2b1471969ddd6719d3ca6 Mon Sep 17 00:00:00 2001 From: jeff-lien-sndk Date: Wed, 13 Aug 2025 15:13:27 -0500 Subject: [PATCH 2/2] nvme: Enable retrieving telemetry log data area 4 When retrieving telemetry log data area 4, the etdas bit in the host behavior changed feature must be set. This commit will change the code to use new functions added to libnvme to set and clear that bit before and after retrieving data area 4. Reviewed-by: brandon-paupore-sndk Signed-off-by: jeff-lien-sndk --- nvme.c | 80 +++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 26 deletions(-) diff --git a/nvme.c b/nvme.c index 4bc6e576f4..b3cd538b0c 100644 --- a/nvme.c +++ b/nvme.c @@ -715,28 +715,16 @@ static int get_ana_log(int argc, char **argv, struct command *cmd, static int parse_telemetry_da(struct nvme_dev *dev, enum nvme_telemetry_da da, struct nvme_telemetry_log *telem, - size_t *size) + size_t *size, + bool da4_support) { - _cleanup_free_ struct nvme_id_ctrl *id_ctrl = NULL; size_t dalb, da1lb = le16_to_cpu(telem->dalb1), da2lb = le16_to_cpu(telem->dalb2), da3lb = le16_to_cpu(telem->dalb3), da4lb = le32_to_cpu(telem->dalb4); - bool data_area_4_support; - - id_ctrl = nvme_alloc(sizeof(*id_ctrl)); - if (!id_ctrl) - return -ENOMEM; - - if (nvme_cli_identify_ctrl(dev, id_ctrl)) { - perror("identify-ctrl"); - return -errno; - } - - data_area_4_support = id_ctrl->lpa & 0x40; switch (da) { case NVME_TELEMETRY_DA_CTRL_DETERMINE: - if (data_area_4_support) + if (da4_support) dalb = da4lb; else dalb = da3lb; @@ -752,7 +740,7 @@ static int parse_telemetry_da(struct nvme_dev *dev, dalb = da3lb; break; case NVME_TELEMETRY_DA_4: - if (data_area_4_support) { + if (da4_support) { dalb = da4lb; } else { nvme_show_error( @@ -822,7 +810,8 @@ static int get_log_telemetry_host(struct nvme_dev *dev, size_t size, static int __create_telemetry_log_host(struct nvme_dev *dev, enum nvme_telemetry_da da, size_t *size, - struct nvme_telemetry_log **buf) + struct nvme_telemetry_log **buf, + bool da4_support) { _cleanup_free_ struct nvme_telemetry_log *log = NULL; int err; @@ -839,7 +828,7 @@ static int __create_telemetry_log_host(struct nvme_dev *dev, return err; } - err = parse_telemetry_da(dev, da, log, size); + err = parse_telemetry_da(dev, da, log, size, da4_support); if (err) return err; @@ -850,7 +839,8 @@ static int __get_telemetry_log_ctrl(struct nvme_dev *dev, bool rae, enum nvme_telemetry_da da, size_t *size, - struct nvme_telemetry_log **buf) + struct nvme_telemetry_log **buf, + bool da4_support) { struct nvme_telemetry_log *log; int err; @@ -884,7 +874,7 @@ static int __get_telemetry_log_ctrl(struct nvme_dev *dev, return 0; } - err = parse_telemetry_da(dev, da, log, size); + err = parse_telemetry_da(dev, da, log, size, da4_support); if (err) goto free; @@ -898,7 +888,8 @@ static int __get_telemetry_log_ctrl(struct nvme_dev *dev, static int __get_telemetry_log_host(struct nvme_dev *dev, enum nvme_telemetry_da da, size_t *size, - struct nvme_telemetry_log **buf) + struct nvme_telemetry_log **buf, + bool da4_support) { _cleanup_free_ struct nvme_telemetry_log *log = NULL; int err; @@ -913,7 +904,7 @@ static int __get_telemetry_log_host(struct nvme_dev *dev, if (err) return err; - err = parse_telemetry_da(dev, da, log, size); + err = parse_telemetry_da(dev, da, log, size, da4_support); if (err) return err; @@ -932,13 +923,16 @@ static int get_telemetry_log(int argc, char **argv, struct command *cmd, "If given, This option will override dgen. 0 : controller determines data area"; _cleanup_free_ struct nvme_telemetry_log *log = NULL; + _cleanup_free_ struct nvme_id_ctrl *id_ctrl = NULL; _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; _cleanup_fd_ int output = -1; int err = 0; - size_t total_size; + size_t total_size = 0; __u8 *data_ptr = NULL; int data_written = 0, data_remaining = 0; nvme_print_flags_t flags; + bool da4_support = false, + host_behavior_changed = false; struct config { char *file_name; @@ -990,6 +984,31 @@ static int get_telemetry_log(int argc, char **argv, struct command *cmd, cfg.data_area = cfg.mcda; } + if (cfg.data_area == 4) { + id_ctrl = nvme_alloc(sizeof(*id_ctrl)); + if (!id_ctrl) + return -ENOMEM; + + if (nvme_cli_identify_ctrl(dev, id_ctrl)) { + perror("identify-ctrl"); + return -errno; + } + + da4_support = id_ctrl->lpa & 0x40; + + if (!da4_support) { + fprintf(stderr, "%s: Telemetry data area 4 not supported by device\n", + __func__); + return -EINVAL; + } + + err = nvme_set_etdas(dev_fd(dev), &host_behavior_changed); + if (err) { + fprintf(stderr, "%s: Failed to set ETDAS bit\n", __func__); + return err; + } + } + output = open(cfg.file_name, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (output < 0) { nvme_show_error("Failed to open output file %s: %s!", @@ -1003,13 +1022,13 @@ static int get_telemetry_log(int argc, char **argv, struct command *cmd, if (cfg.ctrl_init) err = __get_telemetry_log_ctrl(dev, cfg.rae, cfg.data_area, - &total_size, &log); + &total_size, &log, da4_support); else if (cfg.host_gen) err = __create_telemetry_log_host(dev, cfg.data_area, - &total_size, &log); + &total_size, &log, da4_support); else err = __get_telemetry_log_host(dev, cfg.data_area, - &total_size, &log); + &total_size, &log, da4_support); if (err < 0) { nvme_show_error("get-telemetry-log: %s", nvme_strerror(errno)); @@ -1048,6 +1067,15 @@ static int get_telemetry_log(int argc, char **argv, struct command *cmd, return -1; } + if (host_behavior_changed) { + host_behavior_changed = false; + err = nvme_clear_etdas(dev_fd(dev), &host_behavior_changed); + if (err) { + fprintf(stderr, "%s: Failed to clear ETDAS bit\n", __func__); + return err; + } + } + return err; }