// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright (c) 2023-2024 Solidigm.
 *
 * Author: leonardo.da.cunha@solidigm.com
 */

#include <errno.h>

#include "common.h"
#include "nvme-print.h"
#include "solidigm-util.h"

#define SLDGM_LEGACY_TEMP_STATS_LID 0xC5
#define SLDGM_TEMP_STATS_LID 0xD5

struct temp_stats {
	__le64	curr;
	__le64	last_overtemp;
	__le64	life_overtemp;
	__le64	highest_temp;
	__le64	lowest_temp;
	__u8	rsvd[40];
	__le64	max_operating_temp;
	__le64	min_operating_temp;
	__le64	est_offset;
};

static void show_temp_stats(struct temp_stats *stats)
{
	printf("Current temperature         : %"PRIu64"\n", le64_to_cpu(stats->curr));
	printf("Last critical overtemp flag : %"PRIu64"\n", le64_to_cpu(stats->last_overtemp));
	printf("Life critical overtemp flag : %"PRIu64"\n", le64_to_cpu(stats->life_overtemp));
	printf("Highest temperature         : %"PRIu64"\n", le64_to_cpu(stats->highest_temp));
	printf("Lowest temperature          : %"PRIu64"\n", le64_to_cpu(stats->lowest_temp));
	printf("Max operating temperature   : %"PRIu64"\n", le64_to_cpu(stats->max_operating_temp));
	printf("Min operating temperature   : %"PRIu64"\n", le64_to_cpu(stats->min_operating_temp));
	printf("Estimated offset            : %"PRIu64"\n", le64_to_cpu(stats->est_offset));
}

int sldgm_get_temp_stats_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
	unsigned char buffer[4096] = {0};
	_cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
	__u8 uuid_idx;
	int err;

	const char *desc = "Get/show Temperature Statistics log.";
	const char *raw = "dump output in binary format";
	struct config {
		bool  raw_binary;
	};

	struct config cfg = {
		.raw_binary = false,
	};

	OPT_ARGS(opts) = {
		OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
		OPT_END()
	};

	err = parse_and_open(&dev, argc, argv, desc, opts);
	if (err)
		return err;

	sldgm_get_uuid_index(dev, &uuid_idx);

	struct nvme_get_log_args args = {
		.lpo	= 0,
		.result = NULL,
		.log	= buffer,
		.args_size = sizeof(args),
		.fd	= dev_fd(dev),
		.uuidx	= uuid_idx,
		.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
		.lid	= SLDGM_TEMP_STATS_LID,
		.len	= sizeof(buffer),
		.nsid	= NVME_NSID_ALL,
		.csi	= NVME_CSI_NVM,
		.lsi	= NVME_LOG_LSI_NONE,
		.lsp	= NVME_LOG_LSP_NONE,
		.rae	= false,
		.ot	= false,
	};

	err = nvme_get_log(&args);
	if (err > 0) {
		args.lid = SLDGM_LEGACY_TEMP_STATS_LID;
		err = nvme_get_log(&args);
		if (!err) {
			uint64_t *guid = (uint64_t *)&buffer[4080];

			if (guid[1] == 0xC7BB98B7D0324863 && guid[0] == 0xBB2C23990E9C722F) {
				fprintf(stderr,
					"Error: Log page has OCP unsupported Requirements GUID\n");
				return -EBADMSG;
			}
		}
	}
	if (!err) {
		if (!cfg.raw_binary)
			show_temp_stats((struct temp_stats *) buffer);
		else
			d_raw(buffer, sizeof(struct temp_stats));
	} else if (err > 0)
		nvme_show_status(err);

	return err;
}
