return nvme_status_to_errno(err, false);
}
-static int get_telemetry_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+static int get_telemetry_log_total_size_dalb4(int fd,
+ struct nvme_telemetry_log *log,
+ unsigned int *total_size)
+{
+ const size_t bs = 512;
+ int err;
+ int block_size = NVME_LOG_TELEM_BLOCK_SIZE;
+ __u32 result, len;
+ void *buf = NULL;
+ struct nvme_id_ctrl ctrl;
+ struct nvme_get_features_args args = {
+ .args_size = sizeof(args),
+ .fd = fd,
+ .fid = NVME_FEAT_FID_HOST_BEHAVIOR,
+ .nsid = NVME_NSID_ALL,
+ .sel = 0,
+ .cdw11 = 0,
+ .uuidx = 0,
+ .data = buf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ err = nvme_identify_ctrl(fd, &ctrl);
+ if (err) {
+ perror("identify-ctrl");
+ return err;
+ }
+
+ len = nvme_get_feature_length(NVME_FEAT_FID_HOST_BEHAVIOR, 0,
+ &len);
+ if (posix_memalign(&buf, getpagesize(), len)) {
+ fprintf(stderr, "can not allocate feature payload\n");
+ errno = ENOMEM;
+ return -1;
+ }
+ memset(buf, 0, len);
+
+ args.data_len = len,
+
+ err = nvme_get_features(&args);
+ if (err > 0) {
+ nvme_show_status(err);
+ } else if (err < 0) {
+ perror("get-feature");
+ } else {
+ if (ctrl.lpa & 0x40) {
+ if (((unsigned char *)buf)[1] == 1) {
+ *total_size = le32_to_cpu(log->dalb4) * bs + block_size;
+ } else {
+ fprintf(stderr,
+ "Data area 4 unsupported, Host Behavior Support ETDAS not set to 1\n");
+ err = -1;
+ }
+ } else {
+ fprintf(stderr,
+ "Data area 4 unsupported, bit 6 of Log Page Attributes not set\n");
+ err = -1;
+ }
+ if (err)
+ errno = EINVAL;
+ }
+ free(buf);
+ return err;
+}
+
+static int get_telemetry_log_total_size(int fd, int data_area,
+ struct nvme_telemetry_log *log,
+ unsigned int *total_size)
+{
+ int err = 0;
+ int block_size = NVME_LOG_TELEM_BLOCK_SIZE;
+
+ switch (data_area) {
+ case 1:
+ *total_size = (le16_to_cpu(log->dalb1) + 1) * block_size;
+ break;
+ case 2:
+ *total_size = (le16_to_cpu(log->dalb2) + 1) * block_size;
+ break;
+ case 3:
+ fallthrough;
+ default:
+ *total_size = (le16_to_cpu(log->dalb3) + 1) * block_size;
+ break;
+ case 4:
+ err = get_telemetry_log_total_size_dalb4(fd, log, total_size);
+ break;
+ }
+
+ return err;
+}
+
+static int get_telemetry_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
{
const char *desc = "Retrieve telemetry log and write to binary file";
const char *fname = "File name to save raw binary, includes header";
const char *hgen = "Have the host tell the controller to generate the report";
const char *cgen = "Gather report generated by the controller.";
const char *dgen = "Pick which telemetry data area to report. Default is 3 to fetch areas 1-3. Valid options are 1, 2, 3, 4.";
- const size_t bs = 512;
struct nvme_telemetry_log *log;
- struct nvme_id_ctrl ctrl;
int err = 0, fd, output;
- unsigned total_size;
- __u32 result, len;
- void *buf = NULL;
+ unsigned int total_size = 0;
struct config {
char *file_name;
else
err = nvme_get_host_telemetry(fd, &log);
- if (err < 0)
+ if (err < 0) {
perror("get-telemetry-log");
- else if (err > 0) {
+ } else if (err > 0) {
nvme_show_status(err);
fprintf(stderr, "Failed to acquire telemetry log %d!\n", err);
goto close_output;
}
- switch (cfg.data_area) {
- case 1:
- total_size = (le16_to_cpu(log->dalb1) + 1) * NVME_LOG_TELEM_BLOCK_SIZE;
- break;
- case 2:
- total_size = (le16_to_cpu(log->dalb2) + 1) * NVME_LOG_TELEM_BLOCK_SIZE;
- break;
- case 3:
- default:
- total_size = (le16_to_cpu(log->dalb3) + 1) * NVME_LOG_TELEM_BLOCK_SIZE;
- break;
- case 4:
- err = nvme_identify_ctrl(fd, &ctrl);
- if (err) {
- perror("identify-ctrl");
- goto close_output;
- }
-
- len = nvme_get_feature_length(NVME_FEAT_FID_HOST_BEHAVIOR, 0, &len);
- if (posix_memalign(&buf, getpagesize(), len)) {
- fprintf(stderr, "can not allocate feature payload\n");
- errno = ENOMEM;
- err = -1;
- goto close_output;
- }
- memset(buf, 0, len);
-
- struct nvme_get_features_args args = {
- .args_size = sizeof(args),
- .fd = fd,
- .fid = NVME_FEAT_FID_HOST_BEHAVIOR,
- .nsid = NVME_NSID_ALL,
- .sel = 0,
- .cdw11 = 0,
- .uuidx = 0,
- .data_len = len,
- .data = buf,
- .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
- .result = &result,
- };
- err = nvme_get_features(&args);
- if (err > 0) {
- nvme_show_status(err);
- } else if (err < 0) {
- perror("get-feature");
- } else {
- if ((ctrl.lpa & 0x40)) {
- if (((unsigned char *)buf)[1] == 1)
- total_size = (le32_to_cpu(log->dalb4) * bs) + NVME_LOG_TELEM_BLOCK_SIZE;
- else {
- fprintf(stderr, "Data area 4 unsupported, Host Behavior Support ETDAS not set to 1\n");
- errno = EINVAL;
- err = -1;
- }
- } else {
- fprintf(stderr, "Data area 4 unsupported, bit 6 of Log Page Attributes not set\n");
- errno = EINVAL;
- err = -1;
- }
- }
- free(buf);
- if (err)
- goto close_output;
- break;
- }
-
- err = write(output, (void *)log, total_size);
- if (err != total_size) {
- fprintf(stderr, "Failed to flush all data to file!\n");
- goto close_output;
+ err = get_telemetry_log_total_size(fd, cfg.data_area, log, &total_size);
+ if (total_size) {
+ err = write(output, (void *)log, total_size);
+ if (err < 0 || err != total_size)
+ fprintf(stderr, "Failed to flush all data to file!\n");
}
close_output: