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 all. Valid options are 1, 2, 3.";
+ const size_t bs = 512;
struct nvme_telemetry_log_page_hdr *hdr;
+ size_t full_size, offset = bs;
+ int err = 0, fd, output;
void *page_log;
- size_t full_size, offset, num_blocks;
- int err = 0 , fd, output;
struct config {
char *file_name;
__u32 host_gen;
int ctrl_init;
+ int data_area;
};
struct config cfg = {
.file_name = NULL,
.host_gen = 1,
.ctrl_init = 0,
+ .data_area = 3,
};
const struct argconfig_commandline_options command_line_options[] = {
- {"output-file", 'o', "FILE", CFG_STRING, &cfg.file_name, required_argument, fname},
- {"host-generate", 'h', "NUM", CFG_POSITIVE, &cfg.host_gen, required_argument, hgen},
- {"controller-init", 'c', "", CFG_NONE, &cfg.ctrl_init, no_argument, cgen},
+ {"output-file", 'o', "FILE", CFG_STRING, &cfg.file_name, required_argument, fname},
+ {"host-generate", 'h', "NUM", CFG_POSITIVE, &cfg.host_gen, required_argument, hgen},
+ {"controller-init", 'c', "", CFG_NONE, &cfg.ctrl_init, no_argument, cgen},
+ {"data-area", 'd', "NUM", CFG_POSITIVE, &cfg.data_area, required_argument, dgen},
{NULL}
};
}
cfg.host_gen = !!cfg.host_gen;
+ hdr = malloc(bs);
+ page_log = malloc(bs);
+ if (!hdr || !page_log) {
+ fprintf(stderr, "Failed to allocate %zu bytes for log\n", bs);
+ err = ENOMEM;
+ goto free_mem;
+ }
- hdr = malloc(4096);
- memset(hdr, 0, 4096);
-
- err = nvme_get_telemetry_log(fd, hdr, cfg.host_gen, cfg.ctrl_init, 4096, 0);
+ memset(hdr, 0, bs);
+ err = nvme_get_telemetry_log(fd, hdr, cfg.host_gen, cfg.ctrl_init, bs, 0);
if (err) {
fprintf(stderr, "NVMe Status:%s(%x)\n",
nvme_status_to_string(err), err);
fprintf(stderr, "Failed to aquire telemetry header %d!\n", err);
- free(hdr);
- goto close_output;
+ close(output);
+ goto free_mem;
}
- err = write(output, (void *) hdr, 4096);
- if (err != 4096) {
+ err = write(output, (void *) hdr, bs);
+ if (err != bs) {
fprintf(stderr, "Failed to flush all data to file!");
- goto free_hdr;
+ goto free_mem;
}
- num_blocks = max(hdr->dalb1, max(hdr->dalb2, hdr->dalb3));
-
- full_size = num_blocks * 512;
- /* Round to page boundary */
- full_size += (4096 - (full_size % 4096));
- /* We've already pulled 1 page worth of data, lets remove that. */
- full_size -= 4096;
- offset = 4096;
-
- page_log = malloc(4096);
- if (!page_log) {
- fprintf(stderr, "Failed to allocate %zu bytes for log\n",
- full_size);
- err = ENOMEM;
- goto free_hdr;
+ switch (cfg.data_area) {
+ case 1:
+ full_size = (hdr->dalb1 * bs) + offset;
+ break;
+ case 2:
+ full_size = (hdr->dalb2 * bs) + offset;
+ break;
+ case 3:
+ full_size = (hdr->dalb3 * bs) + offset;
+ break;
+ default:
+ fprintf(stderr, "Invalid data area requested");
+ err = EINVAL;
+ goto free_mem;
}
- while (full_size) {
- err = nvme_get_telemetry_log(fd, page_log, 0, cfg.ctrl_init, 4096, offset);
+ /*
+ * Continuously pull data until the offset hits the end of the last
+ * block.
+ */
+ while (offset != full_size) {
+ err = nvme_get_telemetry_log(fd, page_log, 0, cfg.ctrl_init, bs, offset);
if (err) {
fprintf(stderr, "Failed to aquire full telemetry log!\n");
fprintf(stderr, "NVMe Status:%s(%x)\n",
break;
}
- err = write(output, (void *) page_log, 4096);
- if (err != 4096) {
+ err = write(output, (void *) page_log, bs);
+ if (err != bs) {
fprintf(stderr, "Failed to flush all data to file!");
break;
}
- full_size -= 4096;
- offset += 4096;
+ offset += bs;
}
-
- free(page_log);
- free_hdr:
+ free_mem:
free(hdr);
- close_output:
- close(output);
+ free(page_log);
close_fd:
close(fd);
return err;