summaryrefslogtreecommitdiffstats
path: root/plugins/solidigm/solidigm-internal-logs.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/solidigm/solidigm-internal-logs.c')
-rw-r--r--plugins/solidigm/solidigm-internal-logs.c116
1 files changed, 84 insertions, 32 deletions
diff --git a/plugins/solidigm/solidigm-internal-logs.c b/plugins/solidigm/solidigm-internal-logs.c
index 236652a..c604761 100644
--- a/plugins/solidigm/solidigm-internal-logs.c
+++ b/plugins/solidigm/solidigm-internal-logs.c
@@ -13,6 +13,7 @@
#include <unistd.h>
#include <inttypes.h>
#include <linux/limits.h>
+#include <time.h>
#include "common.h"
#include "nvme.h"
@@ -122,7 +123,7 @@ struct nlog_dump_header4_1 {
struct config {
__u32 namespace_id;
- char *file_prefix;
+ char *dir_prefix;
char *type;
bool verbose;
};
@@ -222,6 +223,7 @@ static int dump_assert_logs(struct nvme_dev *dev, struct config cfg)
__u8 buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
__u8 head_buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
char file_path[PATH_MAX];
+ char file_name[] = "AssertLog.bin";
struct assert_dump_header *ad = (struct assert_dump_header *) head_buf;
struct nvme_passthru_cmd cmd = {
.opcode = 0xd2,
@@ -236,7 +238,8 @@ static int dump_assert_logs(struct nvme_dev *dev, struct config cfg)
if (err)
return err;
- sprintf(file_path, "%s_AssertLog.bin", cfg.file_prefix);
+ snprintf(file_path, sizeof(file_path), "%.*s/%s",
+ (int) (sizeof(file_path) - sizeof(file_name) - 1), cfg.dir_prefix, file_name);
output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (output < 0)
return -errno;
@@ -291,7 +294,7 @@ static int dump_event_logs(struct nvme_dev *dev, struct config cfg)
err = read_header(&cmd, dev_fd(dev));
if (err)
return err;
- sprintf(file_path, "%s_EventLog.bin", cfg.file_prefix);
+ snprintf(file_path, sizeof(file_path), "%s/EventLog.bin", cfg.dir_prefix);
output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (output < 0)
return -errno;
@@ -387,7 +390,8 @@ static int dump_nlogs(struct nvme_dev *dev, struct config cfg, int core)
count = nlog_header->totalnlogs;
core_num = core < 0 ? nlog_header->corecount : 0;
if (!header_size) {
- sprintf(file_path, "%s_NLog.bin", cfg.file_prefix);
+ snprintf(file_path, sizeof(file_path), "%s/NLog.bin",
+ cfg.dir_prefix);
output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (output < 0)
return -errno;
@@ -423,25 +427,32 @@ enum telemetry_type {
static int dump_telemetry(struct nvme_dev *dev, struct config cfg, enum telemetry_type ttype)
{
- struct nvme_telemetry_log *log = NULL;
+ _cleanup_free_ struct nvme_telemetry_log *log = NULL;
size_t log_size = 0;
- int err = 0, output;
+ int err = 0;
__u8 *buffer = NULL;
size_t bytes_remaining = 0;
enum nvme_telemetry_da da;
size_t max_data_tx;
char file_path[PATH_MAX];
- char *log_name;
+ char *file_name;
+ char *log_descr;
+ struct stat sb;
+
+ _cleanup_file_ int output = -1;
switch (ttype) {
case HOSTGENNEW:
- log_name = "TelemetryHostGenNew";
+ file_name = "lid_0x07_lsp_0x01_lsi_0x0000.bin";
+ log_descr = "Generated Host Initiated";
break;
case HOSTGENOLD:
- log_name = "TelemetryHostGenOld";
+ file_name = "lid_0x07_lsp_0x00_lsi_0x0000.bin";
+ log_descr = "Existing Host Initiated";
break;
case CONTROLLER:
- log_name = "TelemetryController";
+ file_name = "lid_0x08_lsp_0x00_lsi_0x0000.bin";
+ log_descr = "Controller Initiated";
break;
default:
return -EINVAL;
@@ -453,11 +464,6 @@ static int dump_telemetry(struct nvme_dev *dev, struct config cfg, enum telemetr
if (max_data_tx > DRIVER_MAX_TX_256K)
max_data_tx = DRIVER_MAX_TX_256K;
- sprintf(file_path, "%s_%s.bin", cfg.file_prefix, log_name);
- output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- if (output < 0)
- return -errno;
-
switch (ttype) {
case HOSTGENNEW:
err = nvme_get_telemetry_log(dev_fd(dev), true, false, false, max_data_tx, da,
@@ -474,7 +480,20 @@ static int dump_telemetry(struct nvme_dev *dev, struct config cfg, enum telemetr
}
if (err)
- goto tele_close_output;
+ return err;
+
+ snprintf(file_path, sizeof(file_path), "%s/log_pages", cfg.dir_prefix);
+ if (!(stat(file_path, &sb) == 0 && S_ISDIR(sb.st_mode))) {
+ if (mkdir(file_path, 777) != 0) {
+ perror(file_path);
+ return -errno;
+ }
+ }
+
+ snprintf(file_path, sizeof(file_path), "%s/log_pages/%s", cfg.dir_prefix, file_name);
+ output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (output < 0)
+ return -errno;
bytes_remaining = log_size;
buffer = (__u8 *)log;
@@ -486,45 +505,49 @@ static int dump_telemetry(struct nvme_dev *dev, struct config cfg, enum telemetr
err = -errno;
goto tele_close_output;
}
+
bytes_remaining -= bytes_written;
buffer += bytes_written;
}
- printf("Successfully wrote log to %s\n", file_path);
+ printf("Successfully wrote %s Telemetry log to %s\n", log_descr, file_path);
tele_close_output:
- free(log);
close(output);
-
return err;
}
int solidigm_get_internal_log(int argc, char **argv, struct command *command,
struct plugin *plugin)
{
+ char folder[PATH_MAX];
+ char zip_name[PATH_MAX];
+ char *output_path;
char sn_prefix[sizeof(((struct nvme_id_ctrl *)0)->sn)+1];
int log_count = 0;
int err;
- struct nvme_dev *dev;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
bool all = false;
+ time_t t;
+ struct tm tm;
const char *desc = "Get Debug Firmware Logs and save them.";
const char *type =
"Log type: ALL, CONTROLLERINITTELEMETRY, HOSTINITTELEMETRY, HOSTINITTELEMETRYNOGEN, NLOG, ASSERT, EVENT. Defaults to ALL.";
- const char *prefix = "Output file prefix; defaults to device serial number.";
+ const char *prefix = "Output dir prefix; defaults to device serial number.";
const char *verbose = "To print out verbose info.";
const char *namespace_id = "Namespace to get logs from.";
struct config cfg = {
.namespace_id = NVME_NSID_ALL,
- .file_prefix = NULL,
+ .dir_prefix = NULL,
.type = NULL,
};
OPT_ARGS(opts) = {
OPT_STR("type", 't', &cfg.type, type),
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
- OPT_FILE("file-prefix", 'p', &cfg.file_prefix, prefix),
+ OPT_FILE("dir-prefix", 'p', &cfg.dir_prefix, prefix),
OPT_FLAG("verbose", 'v', &cfg.verbose, verbose),
OPT_END()
};
@@ -533,12 +556,22 @@ int solidigm_get_internal_log(int argc, char **argv, struct command *command,
if (err)
return err;
- if (!cfg.file_prefix) {
+ if (!cfg.dir_prefix) {
err = get_serial_number(sn_prefix, dev_fd(dev));
if (err)
- goto out_dev;
- cfg.file_prefix = sn_prefix;
+ return err;
+ cfg.dir_prefix = sn_prefix;
+ }
+ t = time(NULL);
+ tm = *localtime(&t);
+ snprintf(folder, sizeof(folder), "%s-%d%02d%02d%02d%02d%02d", cfg.dir_prefix,
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
+ if (mkdir(folder, 0777) != 0) {
+ perror("mkdir");
+ return -errno;
}
+ cfg.dir_prefix = folder;
+ output_path = folder;
if (!cfg.type)
cfg.type = "ALL";
@@ -547,8 +580,9 @@ int solidigm_get_internal_log(int argc, char **argv, struct command *command,
*p = toupper(*p);
}
- if (!strcmp(cfg.type, "ALL"))
+ if (!strcmp(cfg.type, "ALL")) {
all = true;
+ }
if (all || !strcmp(cfg.type, "ASSERT")) {
err = dump_assert_logs(dev, cfg);
if (err == 0)
@@ -592,14 +626,32 @@ int solidigm_get_internal_log(int argc, char **argv, struct command *command,
perror("Error retrieving Telemetry Host Initiated");
}
+ if (log_count > 0) {
+ int ret_cmd;
+ char cmd[ARG_MAX];
+ char *where_err = cfg.verbose ? "" : ">/dev/null 2>&1";
+
+ snprintf(zip_name, sizeof(zip_name), "%s.zip", cfg.dir_prefix);
+ snprintf(cmd, sizeof(cmd), "cd \"%s\" && zip -r \"../%s\" ./* %s", cfg.dir_prefix,
+ zip_name, where_err);
+ printf("Compressing logs to %s\n", zip_name);
+ ret_cmd = system(cmd);
+ if (ret_cmd == -1)
+ perror(cmd);
+ else {
+ output_path = zip_name;
+ snprintf(cmd, sizeof(cmd), "rm -rf %s", cfg.dir_prefix);
+ printf("Removing %s\n", cfg.dir_prefix);
+ if (system(cmd) != 0)
+ perror("Failed removing logs folder");
+ }
+ }
+
if (log_count == 0) {
if (err > 0)
nvme_show_status(err);
} else if ((log_count > 1) || cfg.verbose)
- printf("Total: %d log files with prefix: %s\n", log_count, cfg.file_prefix);
-out_dev:
- /* Redundant close() to make static code analysis happy */
- close(dev->direct.fd);
- dev_close(dev);
+ printf("Total: %d log files in %s\n", log_count, output_path);
+
return err;
}