Blame plugins/virtium/virtium-nvme.c

Packit Service b7b338
#include <fcntl.h>
Packit Service b7b338
#include <errno.h>
Packit Service b7b338
#include <stdio.h>
Packit Service b7b338
#include <stdlib.h>
Packit Service b7b338
#include <unistd.h>
Packit Service b7b338
#include <stddef.h>
Packit Service b7b338
#include <inttypes.h>
Packit Service b7b338
#include <stdbool.h>
Packit Service b7b338
#include <time.h>
Packit Service b7b338
#include <locale.h>
Packit Service b7b338
Packit Service b7b338
#include "linux/nvme_ioctl.h"
Packit Service b7b338
#include "nvme.h"
Packit Service b7b338
#include "nvme-print.h"
Packit Service b7b338
#include "nvme-ioctl.h"
Packit Service b7b338
#include "plugin.h"
Packit Service b7b338
#include "argconfig.h"
Packit Service b7b338
#include "suffix.h"
Packit Service b7b338
Packit Service b7b338
#define CREATE_CMD
Packit Service b7b338
#include "virtium-nvme.h"
Packit Service b7b338
Packit Service b7b338
#define MIN2(a, b) ( ((a) < (b))? (a) : (b))
Packit Service b7b338
Packit Service b7b338
#define HOUR_IN_SECONDS     3600
Packit Service b7b338
Packit Service b7b338
#define MAX_HEADER_BUFF     (20 * 1024)
Packit Service b7b338
#define MAX_LOG_BUFF        4096
Packit Service b7b338
#define DEFAULT_TEST_NAME   "Put the name of your test here"
Packit Service b7b338
Packit Service b7b338
static char vt_default_log_file_name[256];
Packit Service b7b338
Packit Service b7b338
struct vtview_log_header {
Packit Service b7b338
	char			path[256];
Packit Service b7b338
	char			test_name[256];
Packit Service b7b338
	long int		time_stamp;
Packit Service b7b338
	struct nvme_id_ctrl	raw_ctrl;
Packit Service b7b338
	struct nvme_firmware_log_page   raw_fw;
Packit Service b7b338
};
Packit Service b7b338
Packit Service b7b338
struct vtview_smart_log_entry {
Packit Service b7b338
	char	path[256];
Packit Service b7b338
	long int	time_stamp;
Packit Service b7b338
	struct nvme_id_ns	raw_ns;
Packit Service b7b338
	struct nvme_id_ctrl	raw_ctrl;
Packit Service b7b338
	struct nvme_smart_log	raw_smart;
Packit Service b7b338
};
Packit Service b7b338
Packit Service b7b338
struct vtview_save_log_settings {
Packit Service b7b338
	double	run_time_hrs;
Packit Service b7b338
	double	log_record_frequency_hrs;
Packit Service b7b338
	const char*	output_file;
Packit Service b7b338
	const char*	test_name;
Packit Service b7b338
};
Packit Service b7b338
Packit Service b7b338
static long double int128_to_double(__u8 *data)
Packit Service b7b338
{
Packit Service b7b338
	int i;
Packit Service b7b338
	long double result = 0;
Packit Service b7b338
Packit Service b7b338
	for (i = 0; i < 16; i++) {
Packit Service b7b338
		result *= 256;
Packit Service b7b338
		result += data[15 - i];
Packit Service b7b338
	}
Packit Service b7b338
	return result;
Packit Service b7b338
}
Packit Service b7b338
Packit Service b7b338
static void vt_initialize_header_buffer(struct vtview_log_header *pbuff)
Packit Service b7b338
{
Packit Service b7b338
	memset(pbuff->path, 0, sizeof(pbuff->path));
Packit Service b7b338
	memset(pbuff->test_name, 0, sizeof(pbuff->test_name));
Packit Service b7b338
}
Packit Service b7b338
Packit Service b7b338
static void vt_convert_data_buffer_to_hex_string(const unsigned char *bufPtr,
Packit Service b7b338
		const unsigned int size, const bool isReverted, char *output)
Packit Service b7b338
{
Packit Service b7b338
	unsigned int i, pos;
Packit Service b7b338
	const char hextable[16] = {
Packit Service b7b338
		'0', '1', '2', '3',
Packit Service b7b338
		'4', '5', '6', '7',
Packit Service b7b338
		'8', '9', 'A', 'B',
Packit Service b7b338
		'C', 'D', 'E', 'F',
Packit Service b7b338
	};
Packit Service b7b338
Packit Service b7b338
	memset(output, 0, (size * 2) + 1);
Packit Service b7b338
Packit Service b7b338
	for (i = 0; i < size; i++) {
Packit Service b7b338
		if(isReverted)
Packit Service b7b338
			pos = size - 1 - i;
Packit Service b7b338
		else
Packit Service b7b338
			pos = i;
Packit Service b7b338
		output[2 * i] = hextable[(bufPtr[pos] & 0xF0) >> 4];
Packit Service b7b338
		output[2 * i + 1] = hextable[(bufPtr[pos] & 0x0F)];
Packit Service b7b338
	}
Packit Service b7b338
}
Packit Service b7b338
Packit Service b7b338
/*
Packit Service b7b338
 * Generate log file name.
Packit Service b7b338
 * Log file name will be generated automatically if user leave log file option blank.
Packit Service b7b338
 * Log file name will be generated as vtView-Smart-log-date-time.txt
Packit Service b7b338
 */
Packit Service b7b338
static void vt_generate_vtview_log_file_name(char* fname)
Packit Service b7b338
{
Packit Service b7b338
	time_t     current;
Packit Service b7b338
	struct tm  tstamp;
Packit Service b7b338
	char       temp[256];
Packit Service b7b338
Packit Service b7b338
	time(¤t;;
Packit Service b7b338
Packit Service b7b338
	tstamp = *localtime(¤t;;
Packit Service b7b338
	snprintf(temp, sizeof(temp), "./vtView-Smart-log-");
Packit Service b7b338
	strcat(fname, temp);
Packit Service b7b338
	strftime(temp, sizeof(temp), "%Y-%m-%d", &tstamp);
Packit Service b7b338
	strcat(fname, temp);
Packit Service b7b338
	snprintf(temp, sizeof(temp), ".txt");
Packit Service b7b338
	strcat(fname, temp);
Packit Service b7b338
}
Packit Service b7b338
Packit Service b7b338
static void vt_convert_smart_data_to_human_readable_format(struct vtview_smart_log_entry *smart, char *text)
Packit Service b7b338
{
Packit Service b7b338
	char tempbuff[1024] = "";
Packit Service b7b338
	int i;
Packit Service b7b338
	int temperature = ((smart->raw_smart.temperature[1] << 8) | smart->raw_smart.temperature[0]) - 273;
Packit Service b7b338
	double capacity;
Packit Service b7b338
	char *curlocale;
Packit Service b7b338
	char *templocale;
Packit Service b7b338
Packit Service b7b338
	curlocale = setlocale(LC_ALL, NULL);
Packit Service b7b338
	templocale = strdup(curlocale);
Packit Service b7b338
Packit Service b7b338
	if (NULL == templocale)
Packit Service b7b338
		printf("Cannot malloc buffer\n");
Packit Service b7b338
Packit Service b7b338
	setlocale(LC_ALL, "C");
Packit Service b7b338
Packit Service b7b338
	long long int lba = 1 << smart->raw_ns.lbaf[(smart->raw_ns.flbas & 0x0f)].ds;
Packit Service b7b338
	capacity = le64_to_cpu(smart->raw_ns.nsze) * lba;
Packit Service b7b338
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "log;%s;%lu;%s;%s;%-.*s;", smart->raw_ctrl.sn, smart->time_stamp, smart->path,
Packit Service b7b338
		smart->raw_ctrl.mn, (int)sizeof(smart->raw_ctrl.fr), smart->raw_ctrl.fr);
Packit Service b7b338
	strcpy(text, tempbuff);
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "Capacity;%lf;", capacity / 1000000000);
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "Critical_Warning;%u;", smart->raw_smart.critical_warning);
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "Temperature;%u;", temperature);
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "Available_Spare;%u;", smart->raw_smart.avail_spare);
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "Available_Spare_Threshold;%u;", smart->raw_smart.spare_thresh);
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "Percentage_Used;%u;", smart->raw_smart.percent_used);
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "Data_Units_Read;%0.Lf;", int128_to_double(smart->raw_smart.data_units_read));
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "Data_Units_Written;%0.Lf;", int128_to_double(smart->raw_smart.data_units_written));
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "Host_Read_Commands;%0.Lf;", int128_to_double(smart->raw_smart.host_reads));
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "Host_Write_Commands;%0.Lf;", int128_to_double(smart->raw_smart.host_writes));
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "Controller_Busy_Time;%0.Lf;", int128_to_double(smart->raw_smart.ctrl_busy_time));
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "Power_Cycles;%0.Lf;", int128_to_double(smart->raw_smart.power_cycles));
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "Power_On_Hours;%0.Lf;", int128_to_double(smart->raw_smart.power_on_hours));
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "Unsafe_Shutdowns;%0.Lf;", int128_to_double(smart->raw_smart.unsafe_shutdowns));
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "Media_Errors;%0.Lf;", int128_to_double(smart->raw_smart.media_errors));
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "Num_Err_Log_Entries;%0.Lf;", int128_to_double(smart->raw_smart.num_err_log_entries));
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "Warning_Temperature_Time;%u;", le32_to_cpu(smart->raw_smart.warning_temp_time));
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "Critical_Composite_Temperature_Time;%u;", le32_to_cpu(smart->raw_smart.critical_comp_time));
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
Packit Service b7b338
	for (i = 0; i < 8; i++) {
Packit Service b7b338
		__s32 temp = le16_to_cpu(smart->raw_smart.temp_sensor[i]);
Packit Service b7b338
		if (0 == temp) {
Packit Service b7b338
			snprintf(tempbuff, sizeof(tempbuff), "Temperature_Sensor_%d;NC;", i);
Packit Service b7b338
			strcat(text, tempbuff);
Packit Service b7b338
			continue;
Packit Service b7b338
		}
Packit Service b7b338
		snprintf(tempbuff, sizeof(tempbuff), "Temperature_Sensor_%d;%d;", i, temp - 273);
Packit Service b7b338
		strcat(text, tempbuff);
Packit Service b7b338
	}
Packit Service b7b338
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "Thermal_Management_T1_Trans_Count;%u;", le32_to_cpu(smart->raw_smart.thm_temp1_trans_count));
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "Thermal_Management_T2_Trans_Count;%u;", le32_to_cpu(smart->raw_smart.thm_temp2_trans_count));
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "Thermal_Management_T1_Total_Time;%u;", le32_to_cpu(smart->raw_smart.thm_temp1_total_time));
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "Thermal_Management_T2_Total_Time;%u;", le32_to_cpu(smart->raw_smart.thm_temp2_total_time));
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
Packit Service b7b338
	snprintf(tempbuff, sizeof(tempbuff), "NandWrites;%d;\n", 0);
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
Packit Service b7b338
	setlocale(LC_ALL, templocale);
Packit Service b7b338
	free(templocale);
Packit Service b7b338
}
Packit Service b7b338
Packit Service b7b338
static void vt_header_to_string(const struct vtview_log_header *header, char *text)
Packit Service b7b338
{
Packit Service b7b338
	char timebuff[50] = "";
Packit Service b7b338
	char tempbuff[MAX_HEADER_BUFF] = "";
Packit Service b7b338
	char identext[16384] = "";
Packit Service b7b338
	char fwtext[2048] = "";
Packit Service b7b338
Packit Service b7b338
	strftime(timebuff, 50, "%Y-%m-%d %H:%M:%S", localtime(&(header->time_stamp)));
Packit Service b7b338
	snprintf(tempbuff, MAX_HEADER_BUFF, "header;{\"session\":{\"testName\":\"%s\",\"dateTime\":\"%s\"},",
Packit Service b7b338
		header->test_name, timebuff);
Packit Service b7b338
	strcpy(text, tempbuff);
Packit Service b7b338
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string((unsigned char *)&(header->raw_ctrl), sizeof(header->raw_ctrl), false, identext);
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string((unsigned char *)&(header->raw_fw), sizeof(header->raw_fw), false, fwtext);
Packit Service b7b338
	snprintf(tempbuff, MAX_HEADER_BUFF,
Packit Service b7b338
		"\"devices\":[{\"model\":\"%s\",\"port\":\"%s\",\"SN\":\"%s\",\"type\":\"NVMe\",\"identify\":\"%s\",\"firmwareSlot\":\"%s\"}]}\n",
Packit Service b7b338
		header->raw_ctrl.mn, header->path, header->raw_ctrl.sn, identext, fwtext);
Packit Service b7b338
	strcat(text, tempbuff);
Packit Service b7b338
}
Packit Service b7b338
Packit Service b7b338
static int vt_append_text_file(const char *text, const char *filename)
Packit Service b7b338
{
Packit Service b7b338
	FILE *f;
Packit Service b7b338
Packit Service b7b338
	f = fopen(filename, "a");
Packit Service b7b338
	if(NULL == f) {
Packit Service b7b338
		printf("Cannot open %s\n", filename);
Packit Service b7b338
		return -1;
Packit Service b7b338
	}
Packit Service b7b338
Packit Service b7b338
	fprintf(f, "%s", text);
Packit Service b7b338
	fclose(f);
Packit Service b7b338
	return 0;
Packit Service b7b338
}
Packit Service b7b338
Packit Service b7b338
static int vt_append_log(struct vtview_smart_log_entry *smart, const char *filename)
Packit Service b7b338
{
Packit Service b7b338
	char sm_log_text[MAX_LOG_BUFF] = "";
Packit Service b7b338
Packit Service b7b338
	vt_convert_smart_data_to_human_readable_format(smart, sm_log_text);
Packit Service b7b338
	return vt_append_text_file(sm_log_text, filename);
Packit Service b7b338
}
Packit Service b7b338
Packit Service b7b338
static int vt_append_header(const struct vtview_log_header *header, const char *filename)
Packit Service b7b338
{
Packit Service b7b338
	char header_text[MAX_HEADER_BUFF] = "";
Packit Service b7b338
Packit Service b7b338
	vt_header_to_string(header, header_text);
Packit Service b7b338
	return vt_append_text_file(header_text, filename);
Packit Service b7b338
}
Packit Service b7b338
Packit Service b7b338
static void vt_process_string(char *str, const size_t size)
Packit Service b7b338
{
Packit Service b7b338
	size_t i;
Packit Service b7b338
Packit Service b7b338
	if (size == 0)
Packit Service b7b338
		return;
Packit Service b7b338
Packit Service b7b338
	i = size - 1;
Packit Service b7b338
	while ((0 != i) && (' ' == str[i])) {
Packit Service b7b338
		str[i] = 0;
Packit Service b7b338
		i--;
Packit Service b7b338
	}
Packit Service b7b338
}
Packit Service b7b338
Packit Service b7b338
static int vt_add_entry_to_log(const int fd, const char *path, const struct vtview_save_log_settings *cfg)
Packit Service b7b338
{
Packit Service b7b338
	struct vtview_smart_log_entry smart;
Packit Service b7b338
	char filename[256] = "";
Packit Service b7b338
	int ret = 0;
Packit Service b7b338
	int nsid = 0;
Packit Service b7b338
Packit Service b7b338
	memset(smart.path, 0, sizeof(smart.path));
Packit Service b7b338
	strcpy(smart.path, path);
Packit Service b7b338
	if(NULL == cfg->output_file)
Packit Service b7b338
		strcpy(filename, vt_default_log_file_name);
Packit Service b7b338
	else
Packit Service b7b338
		strcpy(filename, cfg->output_file);
Packit Service b7b338
Packit Service b7b338
	smart.time_stamp = time(NULL);
Packit Service b7b338
	nsid = nvme_get_nsid(fd);
Packit Service b7b338
Packit Service b7b338
	if (nsid <= 0) {
Packit Service b7b338
		printf("Cannot read namespace-id\n");
Packit Service b7b338
		return -1;
Packit Service b7b338
	}
Packit Service b7b338
Packit Service b7b338
	ret = nvme_identify_ns(fd, nsid, 0, &smart.raw_ns);
Packit Service b7b338
	if (ret) {
Packit Service b7b338
		printf("Cannot read namespace identify\n");
Packit Service b7b338
		return -1;
Packit Service b7b338
	}
Packit Service b7b338
Packit Service b7b338
	ret = nvme_identify_ctrl(fd, &smart.raw_ctrl);
Packit Service b7b338
	if (ret) {
Packit Service b7b338
		printf("Cannot read device identify controller\n");
Packit Service b7b338
		return -1;
Packit Service b7b338
	}
Packit Service b7b338
Packit Service b7b338
	ret = nvme_smart_log(fd, NVME_NSID_ALL, &smart.raw_smart);
Packit Service b7b338
	if (ret) {
Packit Service b7b338
		printf("Cannot read device SMART log\n");
Packit Service b7b338
		return -1;
Packit Service b7b338
	}
Packit Service b7b338
Packit Service b7b338
	vt_process_string(smart.raw_ctrl.sn, sizeof(smart.raw_ctrl.sn));
Packit Service b7b338
	vt_process_string(smart.raw_ctrl.mn, sizeof(smart.raw_ctrl.mn));
Packit Service b7b338
Packit Service b7b338
	ret = vt_append_log(&smart, filename);
Packit Service b7b338
	return (ret);
Packit Service b7b338
}
Packit Service b7b338
Packit Service b7b338
static int vt_update_vtview_log_header(const int fd, const char *path, const struct vtview_save_log_settings *cfg)
Packit Service b7b338
{
Packit Service b7b338
	struct vtview_log_header header;
Packit Service b7b338
	char filename[256] = "";
Packit Service b7b338
	int ret = 0;
Packit Service b7b338
Packit Service b7b338
	vt_initialize_header_buffer(&header);
Packit Service b7b338
	strcpy(header.path, path);
Packit Service b7b338
Packit Service b7b338
	if (NULL == cfg->test_name)
Packit Service b7b338
		strcpy(header.test_name, DEFAULT_TEST_NAME);
Packit Service b7b338
	else
Packit Service b7b338
		strcpy(header.test_name, cfg->test_name);
Packit Service b7b338
Packit Service b7b338
	if(NULL == cfg->output_file)
Packit Service b7b338
		strcpy(filename, vt_default_log_file_name);
Packit Service b7b338
	else
Packit Service b7b338
		strcpy(filename, cfg->output_file);
Packit Service b7b338
Packit Service b7b338
	printf("Log file: %s\n", filename);
Packit Service b7b338
	header.time_stamp = time(NULL);
Packit Service b7b338
Packit Service b7b338
	ret = nvme_identify_ctrl(fd, &header.raw_ctrl);
Packit Service b7b338
	if (ret) {
Packit Service b7b338
		printf("Cannot read identify device\n");
Packit Service b7b338
		return -1;
Packit Service b7b338
	}
Packit Service b7b338
Packit Service b7b338
	ret = nvme_fw_log(fd, &header.raw_fw);
Packit Service b7b338
	if (ret) {
Packit Service b7b338
		printf("Cannot read device firmware log\n");
Packit Service b7b338
		return -1;
Packit Service b7b338
	}
Packit Service b7b338
Packit Service b7b338
	vt_process_string(header.raw_ctrl.sn, sizeof(header.raw_ctrl.sn));
Packit Service b7b338
	vt_process_string(header.raw_ctrl.mn, sizeof(header.raw_ctrl.mn));
Packit Service b7b338
Packit Service b7b338
	ret = vt_append_header(&header, filename);
Packit Service b7b338
	return (ret);
Packit Service b7b338
}
Packit Service b7b338
Packit Service b7b338
static void vt_build_identify_lv2(unsigned int data, unsigned int start,
Packit Service b7b338
				  unsigned int count, const char **table,
Packit Service b7b338
				  bool isEnd)
Packit Service b7b338
{
Packit Service b7b338
	unsigned int i, end, pos, sh = 1;
Packit Service b7b338
	unsigned int temp;
Packit Service b7b338
Packit Service b7b338
	end = start + count;
Packit Service b7b338
Packit Service b7b338
	for (i = start; i < end; i++) {
Packit Service b7b338
		temp = ((data & (sh << i)) >> i);
Packit Service b7b338
		pos = i * 2;
Packit Service b7b338
		printf("        \"bit %u\":\"%ub  %s\"\n", i, temp, table[pos]);
Packit Service b7b338
		printf("                     %s", table[pos + 1]);
Packit Service b7b338
Packit Service b7b338
		if((end - 1) != i || !isEnd)
Packit Service b7b338
			printf(",\n");
Packit Service b7b338
		else
Packit Service b7b338
			printf("\n");
Packit Service b7b338
	}
Packit Service b7b338
Packit Service b7b338
	if(isEnd)
Packit Service b7b338
		printf("    },\n");
Packit Service b7b338
}
Packit Service b7b338
Packit Service b7b338
static void vt_build_power_state_descriptor(const struct nvme_id_ctrl *ctrl)
Packit Service b7b338
{
Packit Service b7b338
	unsigned int i;
Packit Service b7b338
	unsigned char *buf;
Packit Service b7b338
Packit Service b7b338
	printf("{\n");
Packit Service b7b338
	printf("\"Power State Descriptors\":{\n");
Packit Service b7b338
	printf("    \"NOPS\":\"Non-Operational State,\"\n");
Packit Service b7b338
	printf("    \"MPS\":\"Max Power Scale (0: in 0.01 Watts; 1: in 0.0001 Watts),\"\n");
Packit Service b7b338
	printf("    \"ENLAT\":\"Entry Latency in microseconds,\"\n");
Packit Service b7b338
	printf("    \"RWL\":\"Relative Write Latency,\"\n");
Packit Service b7b338
	printf("    \"RRL\":\"Relative Read Latency,\"\n");
Packit Service b7b338
	printf("    \"IPS\":\"Idle Power Scale (00b: Not reported; 01b: 0.0001 W; 10b: 0.01 W; 11b: Reserved),\"\n");
Packit Service b7b338
	printf("    \"APS\":\"Active Power Scale (00b: Not reported; 01b: 0.0001 W; 10b: 0.01 W; 11b: Reserved),\"\n");
Packit Service b7b338
	printf("    \"ACTP\":\"Active Power,\"\n");
Packit Service b7b338
	printf("    \"MP\":\"Maximum Power,\"\n");
Packit Service b7b338
	printf("    \"EXLAT\":\"Exit Latency in microsecond,\"\n");
Packit Service b7b338
	printf("    \"RWT\":\"Relative Write Throughput,\"\n");
Packit Service b7b338
	printf("    \"RRT\":\"Relative Read Throughput,\"\n");
Packit Service b7b338
	printf("    \"IDLP\":\"Idle Power,\"\n");
Packit Service b7b338
	printf("    \"APW\":\"Active Power Workload,\"\n");
Packit Service b7b338
	printf("    \"Ofs\":\"BYTE Offset,\"\n");
Packit Service b7b338
Packit Service b7b338
	printf("    \"Power State Descriptors\":\"\n");
Packit Service b7b338
Packit Service b7b338
	printf("%6s%10s%5s%4s%6s%10s%10s%10s%4s%4s%4s%4s%10s%4s%6s%10s%4s%5s%6s\n", "Entry", "0fs 00-03", "NOPS", "MPS", "MP", "ENLAT", "EXLAT", "0fs 12-15",
Packit Service b7b338
			"RWL", "RWT", "RRL", "RRT", "0fs 16-19", "IPS", "IDLP", "0fs 20-23", "APS", "APW", "ACTP");
Packit Service b7b338
Packit Service b7b338
Packit Service b7b338
	printf("%6s%10s%5s%4s%6s%10s%10s%10s%4s%4s%4s%4s%10s%4s%6s%10s%4s%5s%6s\n", "=====", "=========", "====", "===", "=====", "=========", "=========",
Packit Service b7b338
			"=========", "===", "===", "===", "===", "=========", "===", "=====", "=========", "===", "====", "=====");
Packit Service b7b338
Packit Service b7b338
	for (i = 0; i < 32; i++) {
Packit Service b7b338
		char s[100];
Packit Service b7b338
		unsigned int temp;
Packit Service b7b338
Packit Service b7b338
		printf("%6d", i);
Packit Service b7b338
		buf = (unsigned char*) (&ctrl->psd[i]);
Packit Service b7b338
		vt_convert_data_buffer_to_hex_string(&buf[0], 4, true, s);
Packit Service b7b338
		printf("%9sh", s);
Packit Service b7b338
Packit Service b7b338
		temp = ctrl->psd[i].flags;
Packit Service b7b338
		printf("%4ub", ((unsigned char)temp & 0x02));
Packit Service b7b338
		printf("%3ub", ((unsigned char)temp & 0x01));
Packit Service b7b338
		vt_convert_data_buffer_to_hex_string(&buf[0], 2, true, s);
Packit Service b7b338
		printf("%5sh", s);
Packit Service b7b338
Packit Service b7b338
		vt_convert_data_buffer_to_hex_string(&buf[4], 4, true, s);
Packit Service b7b338
		printf("%9sh", s);
Packit Service b7b338
		vt_convert_data_buffer_to_hex_string(&buf[8], 4, true, s);
Packit Service b7b338
		printf("%9sh", s);
Packit Service b7b338
		vt_convert_data_buffer_to_hex_string(&buf[12], 4, true, s);
Packit Service b7b338
		printf("%9sh", s);
Packit Service b7b338
		vt_convert_data_buffer_to_hex_string(&buf[15], 1, true, s);
Packit Service b7b338
		printf("%3sh", s);
Packit Service b7b338
		vt_convert_data_buffer_to_hex_string(&buf[14], 1, true, s);
Packit Service b7b338
		printf("%3sh", s);
Packit Service b7b338
		vt_convert_data_buffer_to_hex_string(&buf[13], 1, true, s);
Packit Service b7b338
		printf("%3sh", s);
Packit Service b7b338
		vt_convert_data_buffer_to_hex_string(&buf[12], 1, true, s);
Packit Service b7b338
		printf("%3sh", s);
Packit Service b7b338
		vt_convert_data_buffer_to_hex_string(&buf[16], 4, true, s);
Packit Service b7b338
		printf("%9sh", s);
Packit Service b7b338
Packit Service b7b338
		temp = ctrl->psd[i].idle_scale;
Packit Service b7b338
		snprintf(s, sizeof(s), "%u%u", (((unsigned char)temp >> 6) & 0x01), (((unsigned char)temp >> 7) & 0x01));
Packit Service b7b338
		printf("%3sb", s);
Packit Service b7b338
Packit Service b7b338
		vt_convert_data_buffer_to_hex_string(&buf[16], 2, true, s);
Packit Service b7b338
		printf("%5sh", s);
Packit Service b7b338
		vt_convert_data_buffer_to_hex_string(&buf[20], 4, true, s);
Packit Service b7b338
		printf("%9sh", s);
Packit Service b7b338
Packit Service b7b338
		temp = ctrl->psd[i].active_work_scale;
Packit Service b7b338
		snprintf(s, sizeof(s), "%u%u", (((unsigned char)temp >> 6) & 0x01), (((unsigned char)temp >> 7) & 0x01));
Packit Service b7b338
		printf("%3sb", s);
Packit Service b7b338
		snprintf(s, sizeof(s), "%u%u%u", (((unsigned char)temp) & 0x01), (((unsigned char)temp >> 1) & 0x01), (((unsigned char)temp >> 2) & 0x01));
Packit Service b7b338
		printf("%4sb", s);
Packit Service b7b338
Packit Service b7b338
		vt_convert_data_buffer_to_hex_string(&buf[20], 2, true, s);
Packit Service b7b338
		printf("%5sh", s);
Packit Service b7b338
		printf("\n");
Packit Service b7b338
	}
Packit Service b7b338
Packit Service b7b338
	printf("    \"}\n}\n");
Packit Service b7b338
Packit Service b7b338
}
Packit Service b7b338
Packit Service b7b338
static void vt_dump_hex_data(const unsigned char *pbuff, size_t pbuffsize) {
Packit Service b7b338
Packit Service b7b338
	char textbuf[33];
Packit Service b7b338
	unsigned long int i, j;
Packit Service b7b338
Packit Service b7b338
	textbuf[32] = '\0';
Packit Service b7b338
	printf("[%08X] ", 0);
Packit Service b7b338
	for (i = 0; i < pbuffsize; i++) {
Packit Service b7b338
		printf("%02X ", pbuff[i]);
Packit Service b7b338
Packit Service b7b338
		if (pbuff[i] >= ' ' && pbuff[i] <= '~') 
Packit Service b7b338
			textbuf[i % 32] = pbuff[i];
Packit Service b7b338
		else 
Packit Service b7b338
			textbuf[i % 32] = '.';
Packit Service b7b338
Packit Service b7b338
		if ((((i + 1) % 8) == 0) || ((i + 1) == pbuffsize)) {
Packit Service b7b338
			printf(" ");
Packit Service b7b338
			if ((i + 1) % 32 == 0) {
Packit Service b7b338
				printf(" %s\n", textbuf);
Packit Service b7b338
				if((i + 1) != pbuffsize)
Packit Service b7b338
				    printf("[%08lX] ", (i + 1));
Packit Service b7b338
			} 
Packit Service b7b338
			else if (i + 1 == pbuffsize) {
Packit Service b7b338
				textbuf[(i + 1) % 32] = '\0';
Packit Service b7b338
				if(((i + 1) % 8) == 0)
Packit Service b7b338
					printf(" ");
Packit Service b7b338
Packit Service b7b338
				for (j = ((i + 1) % 32); j < 32; j++) {
Packit Service b7b338
					printf("   ");
Packit Service b7b338
					if(((j + 1) % 8) == 0)
Packit Service b7b338
						printf(" ");
Packit Service b7b338
				}
Packit Service b7b338
Packit Service b7b338
				printf("%s\n", textbuf);
Packit Service b7b338
			}
Packit Service b7b338
		}
Packit Service b7b338
	}
Packit Service b7b338
}
Packit Service b7b338
Packit Service b7b338
static void vt_parse_detail_identify(const struct nvme_id_ctrl *ctrl)
Packit Service b7b338
{
Packit Service b7b338
	unsigned char *buf;
Packit Service b7b338
	unsigned int temp, pos;
Packit Service b7b338
	char s[1024] = "";
Packit Service b7b338
Packit Service b7b338
	const char *CMICtable[6] = {"0 = the NVM subsystem contains only a single NVM subsystem port",
Packit Service b7b338
								"1 = the NVM subsystem may contain more than one subsystem ports",
Packit Service b7b338
								"0 = the NVM subsystem contains only a single controller",
Packit Service b7b338
								"1 = the NVM subsystem may contain two or more controllers (see section 1.4.1)",
Packit Service b7b338
								"0 = the controller is associated with a PCI Function or a Fabrics connection",
Packit Service b7b338
								"1 = the controller is associated with an SR-IOV Virtual Function"};
Packit Service b7b338
Packit Service b7b338
	const char *OAEStable[20] = {"Reserved",
Packit Service b7b338
								 "Reserved",
Packit Service b7b338
								 "Reserved",
Packit Service b7b338
								 "Reserved",
Packit Service b7b338
								 "Reserved",
Packit Service b7b338
								 "Reserved",
Packit Service b7b338
								 "Reserved",
Packit Service b7b338
								 "Reserved",
Packit Service b7b338
								 "Reserved",
Packit Service b7b338
								 "Reserved",
Packit Service b7b338
								 "Reserved",
Packit Service b7b338
								 "Reserved",
Packit Service b7b338
								 "Reserved",
Packit Service b7b338
								 "Reserved",
Packit Service b7b338
								 "Reserved",
Packit Service b7b338
								 "Reserved",
Packit Service b7b338
								 "0 = does not support sending the Namespace Attribute Notices event nor the associated Changed Namespace List log page",
Packit Service b7b338
								 "1 = supports sending the Namespace Attribute Notices  & the associated Changed Namespace List log page",
Packit Service b7b338
								 "0 = does not support sending Firmware Activation Notices event",
Packit Service b7b338
								 "1 = supports sending Firmware Activation Notices"};
Packit Service b7b338
Packit Service b7b338
	const char *CTRATTtable[4] = {"0 = does not support a 128-bit Host Identifier",
Packit Service b7b338
								  "1 = supports a 128-bit Host Identifier",
Packit Service b7b338
								  "0 = does not support Non-Operational Power State Permissive Mode",
Packit Service b7b338
								  "1 = supports Non-Operational Power State Permissive Mode"};
Packit Service b7b338
Packit Service b7b338
	const char *OACStable[18] = {"0 = does not support the Security Send and Security Receive commands",
Packit Service b7b338
								 "1 = supports the Security Send and Security Receive commands",
Packit Service b7b338
								 "0 = does not support the Format NVM command",
Packit Service b7b338
								 "1 = supports the Format NVM command",
Packit Service b7b338
								 "0 = does not support the Firmware Commit and Firmware Image Download commands",
Packit Service b7b338
								 "1 = supports the Firmware Commit and Firmware Image Download commands",
Packit Service b7b338
								 "0 = does not support the Namespace Management capability",
Packit Service b7b338
								 "1 = supports the Namespace Management capability",
Packit Service b7b338
								 "0 = does not support the Device Self-test command",
Packit Service b7b338
								 "1 = supports the Device Self-test command",
Packit Service b7b338
								 "0 = does not support Directives",
Packit Service b7b338
								 "1 = supports Directive Send & Directive Receive commands",
Packit Service b7b338
								 "0 = does not support the NVMe-MI Send and NVMe-MI Receive commands",
Packit Service b7b338
								 "1 = supports the NVMe-MI Send and NVMe-MI Receive commands",
Packit Service b7b338
								 "0 = does not support the Virtualization Management command",
Packit Service b7b338
								 "1 = supports the Virtualization Management command",
Packit Service b7b338
								 "0 = does not support the Doorbell Buffer Config command",
Packit Service b7b338
								 "1 = supports the Doorbell Buffer Config command"};
Packit Service b7b338
Packit Service b7b338
	const char *FRMWtable[10] = {"0 = the 1st firmware slot (slot 1) is read/write",
Packit Service b7b338
								 "1 = the 1st firmware slot (slot 1) is read only",
Packit Service b7b338
								 "Reserved",
Packit Service b7b338
								 "Reserved",
Packit Service b7b338
								 "Reserved",
Packit Service b7b338
								 "Reserved",
Packit Service b7b338
								 "Reserved",
Packit Service b7b338
								 "Reserved",
Packit Service b7b338
								 "0 = requires a reset for firmware to be activated",
Packit Service b7b338
								 "1 = supports firmware activation without a reset"};
Packit Service b7b338
Packit Service b7b338
	const char *LPAtable[8] = {"0 = does not support the SMART / Health information log page on a per namespace basis",
Packit Service b7b338
							   "1 = supports the SMART / Health information log page on a per namespace basis",
Packit Service b7b338
							   "0 = does not support the Commands Supported & Effects log page",
Packit Service b7b338
							   "1 = supports the Commands Supported Effects log page",
Packit Service b7b338
							   "0 = does not support extended data for Get Log Page",
Packit Service b7b338
							   "1 = supports extended data for Get Log Page (including extended Number of Dwords and Log Page Offset fields)",
Packit Service b7b338
							   "0 = does not support the Telemetry Host-Initiated and Telemetry Controller-Initiated log pages and Telemetry Log Notices events",
Packit Service b7b338
							   "1 = supports the Telemetry Host-Initiated and Telemetry Controller-Initiated log pages and sending Telemetry Log Notices"							   };
Packit Service b7b338
Packit Service b7b338
	const char *AVSCCtable[2] = {"0 = the format of all Admin Vendor Specific Commands are vendor specific",
Packit Service b7b338
								 "1 = all Admin Vendor Specific Commands use the format defined in NVM Express specification"};
Packit Service b7b338
Packit Service b7b338
	const char *APSTAtable[2] = {"0 = does not support autonomous power state transitions",
Packit Service b7b338
								 "1 = supports autonomous power state transitions"};
Packit Service b7b338
Packit Service b7b338
	const char *DSTOtable[2] =  {"0 = the NVM subsystem supports one device self-test operation per controller at a time",
Packit Service b7b338
								 "1 = the NVM subsystem supports only one device self-test operation in progress at a time"};
Packit Service b7b338
Packit Service b7b338
	const char *HCTMAtable[2] = {"0 = does not support host controlled thermal management",
Packit Service b7b338
								 "1 = supports host controlled thermal management. Supports Set Features & Get Features commands with the Feature Identifier field set to 10h"};
Packit Service b7b338
Packit Service b7b338
	const char *SANICAPtable[6] =  {"0 = does not support the Crypto Erase sanitize operation",
Packit Service b7b338
									"1 = supports the Crypto Erase sanitize operation",
Packit Service b7b338
									"0 = does not support the Block Erase sanitize operation",
Packit Service b7b338
									"1 = supports the Block Erase sanitize operation",
Packit Service b7b338
									"0 = does not support the Overwrite sanitize operation",
Packit Service b7b338
									"1 = supports the Overwrite sanitize operation"};
Packit Service b7b338
Packit Service b7b338
	const char *ONCStable[14] =  {"0 = does not support the Compare command",
Packit Service b7b338
								  "1 = supports the Compare command",
Packit Service b7b338
								  "0 = does not support the Write Uncorrectable command",
Packit Service b7b338
								  "1 = supports the Write Uncorrectable command",
Packit Service b7b338
								  "0 = does not support the Dataset Management command",
Packit Service b7b338
								  "1 = supports the Dataset Management command",
Packit Service b7b338
								  "0 = does not support the Write Zeroes command",
Packit Service b7b338
								  "1 = supports the Write Zeroes command",
Packit Service b7b338
								  "0 = does not support the Save field set to a non-zero value in the Set Features and the Get Features commands",
Packit Service b7b338
								  "1 = supports the Save field set to a non-zero value in the Set Features and the Get Features commands", \
Packit Service b7b338
								  "0 = does not support reservations",
Packit Service b7b338
								  "1 = supports reservations",
Packit Service b7b338
								  "0 = does not support the Timestamp feature (refer to section 5.21.1.14)",
Packit Service b7b338
								  "1 = supports the Timestamp feature"};
Packit Service b7b338
Packit Service b7b338
	const char *FUSEStable[2] = {"0 =  does not support the Compare and Write fused operation",
Packit Service b7b338
								 "1 =  supports the Compare and Write fused operation"};
Packit Service b7b338
Packit Service b7b338
	const char *FNAtable[6] = {"0 = supports format on a per namespace basis",
Packit Service b7b338
							   "1 = all namespaces shall be configured with the same attributes and a format (excluding secure erase) of any namespace results in a format of all namespaces in an NVM subsystem",
Packit Service b7b338
							   "0 = any secure erase performed as part of a format results in a secure erase of a particular namespace specified",
Packit Service b7b338
							   "1 = any secure erase performed as part of a format operation results in a secure erase of all namespaces in the NVM subsystem",
Packit Service b7b338
							   "0 = cryptographic erase is not supported",
Packit Service b7b338
							   "1 = cryptographic erase is supported as part of the secure erase functionality"};
Packit Service b7b338
Packit Service b7b338
	const char *VWCtable[2] = {"0 = a volatile write cache is not present",
Packit Service b7b338
							   "1 = a volatile write cache is present"};
Packit Service b7b338
Packit Service b7b338
	const char *NVSCCtable[2] = {"0 = the format of all NVM Vendor Specific Commands are vendor specific",
Packit Service b7b338
								 "1 = all NVM Vendor Specific Commands use the format defined in NVM Express specification"};
Packit Service b7b338
Packit Service b7b338
	const char *SGLSSubtable[4] =  {"00b = SGLs are not supported",
Packit Service b7b338
									"01b = SGLs are supported. There is no alignment nor granularity requirement for Data Blocks",
Packit Service b7b338
									"10b = SGLs are supported. There is a Dword alignment and granularity requirement for Data Blocks",
Packit Service b7b338
									"11b = Reserved"};
Packit Service b7b338
Packit Service b7b338
	const char *SGLStable[42] =  {"Used",
Packit Service b7b338
								  "Used",
Packit Service b7b338
								  "Used",
Packit Service b7b338
								  "Used",
Packit Service b7b338
								  "0 = does not support the Keyed SGL Data Block descriptor",
Packit Service b7b338
								  "1 = supports the Keyed SGL Data Block descriptor",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "Reserved",
Packit Service b7b338
								  "0 = the SGL Bit Bucket descriptor is not supported",
Packit Service b7b338
								  "1 = the SGL Bit Bucket descriptor is supported",
Packit Service b7b338
								  "0 = use of a byte aligned contiguous physical buffer of metadata is not supported",
Packit Service b7b338
								  "1 = use of a byte aligned contiguous physical buffer of metadata is supported",
Packit Service b7b338
								  "0 = the SGL length shall be equal to the amount of data to be transferred",
Packit Service b7b338
								  "1 = supports commands that contain a data or metadata SGL of a length larger than the amount of data to be transferred",
Packit Service b7b338
								  "0 = use of Metadata Pointer (MPTR) that contains an address of an SGL segment containing exactly one SGL Descriptor that is Qword aligned is not supported",
Packit Service b7b338
								  "1 = use of Metadata Pointer (MPTR) that contains an address of an SGL segment containing exactly one SGL Descriptor that is Qword aligned is supported",
Packit Service b7b338
								  "0 = the Address field specifying an offset is not supported",
Packit Service b7b338
	                              "1 = supports the Address field in SGL Data Block, SGL Segment, and SGL Last Segment descriptor types specifying an offset"};
Packit Service b7b338
Packit Service b7b338
	buf = (unsigned char *)(ctrl);
Packit Service b7b338
Packit Service b7b338
	printf("{\n");
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(buf, 2, true, s);
Packit Service b7b338
	printf("    \"PCI Vendor ID\":\"%sh\",\n", s);
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[2], 2, true, s);
Packit Service b7b338
	printf("    \"PCI Subsystem Vendor ID\":\"%sh\",\n",  s);
Packit Service b7b338
	printf("    \"Serial Number\":\"%s\",\n", ctrl->sn);
Packit Service b7b338
	printf("    \"Model Number\":\"%s\",\n", ctrl->mn);
Packit Service b7b338
	printf("    \"Firmware Revision\":\"%-.*s\",\n", (int)sizeof(ctrl->fr), ctrl->fr);
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[72], 1, true, s);
Packit Service b7b338
	printf("    \"Recommended Arbitration Burst\":\"%sh\",\n", s);
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[73], 3, true, s);
Packit Service b7b338
	printf("    \"IEEE OUI Identifier\":\"%sh\",\n", s);
Packit Service b7b338
Packit Service b7b338
	temp = ctrl->cmic;
Packit Service b7b338
	printf("    \"Controller Multi-Path I/O and Namespace Sharing Capabilities\":{\n");
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[76], 1, true, s);
Packit Service b7b338
	printf("        \"Value\":\"%sh\",\n", s);
Packit Service b7b338
	vt_build_identify_lv2(temp, 0, 3, CMICtable, true);
Packit Service b7b338
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[77], 1, true, s);
Packit Service b7b338
	printf("    \"Maximum Data Transfer Size\":\"%sh\",\n", s);
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[78], 2, true, s);
Packit Service b7b338
	printf("    \"Controller ID\":\"%sh\",\n", s);
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[80], 4, true, s);
Packit Service b7b338
	printf("    \"Version\":\"%sh\",\n", s);
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[84], 4, true, s);
Packit Service b7b338
	printf("    \"RTD3 Resume Latency\":\"%sh\",\n", s);
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[88], 4, true, s);
Packit Service b7b338
	printf("    \"RTD3 Entry Latency\":\"%sh\",\n", s);
Packit Service b7b338
Packit Service b7b338
	temp = le32_to_cpu(ctrl->oaes);
Packit Service b7b338
	printf("    \"Optional Asynchronous Events Supported\":{\n");
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[92], 4, true, s);
Packit Service b7b338
	printf("        \"Value\":\"%sh\",\n", s);
Packit Service b7b338
	vt_build_identify_lv2(temp, 8, 2, OAEStable, true);
Packit Service b7b338
Packit Service b7b338
	temp = le32_to_cpu(ctrl->ctratt);
Packit Service b7b338
	printf("    \"Controller Attributes\":{\n");
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[96], 4, true, s);
Packit Service b7b338
	printf("        \"Value\":\"%sh\",\n", s);
Packit Service b7b338
	vt_build_identify_lv2(temp, 0, 2, CTRATTtable, true);
Packit Service b7b338
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[122], 16, true, s);
Packit Service b7b338
	printf("    \"FRU Globally Unique Identifier\":\"%sh\",\n", s);
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[240], 16, true, s);
Packit Service b7b338
	printf("    \"NVMe Management Interface Specification\":\"%sh\",\n", s);
Packit Service b7b338
Packit Service b7b338
	temp = le16_to_cpu(ctrl->oacs);
Packit Service b7b338
	printf("    \"Optional Admin Command Support\":{\n");
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[256], 2, true, s);
Packit Service b7b338
	printf("        \"Value\":\"%sh\",\n", s);
Packit Service b7b338
	vt_build_identify_lv2(temp, 0, 9, OACStable, true);
Packit Service b7b338
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[258], 1, true, s);
Packit Service b7b338
	printf("    \"Abort Command Limit\":\"%sh\",\n", s);
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[259], 1, true, s);
Packit Service b7b338
	printf("    \"Asynchronous Event Request Limit\":\"%sh\",\n", s);
Packit Service b7b338
Packit Service b7b338
	temp = ctrl->frmw;
Packit Service b7b338
	printf("    \"Firmware Updates\":{\n");
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[260], 1, true, s);
Packit Service b7b338
	printf("        \"Value\":\"%sh\",\n", s);
Packit Service b7b338
	vt_build_identify_lv2(temp, 0, 1, FRMWtable, false);
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[260], 1, true, s);
Packit Service b7b338
	printf("        \"Firmware Slot\":\"%uh\",\n", ((ctrl->frmw >> 1) & 0x07));
Packit Service b7b338
	vt_build_identify_lv2(temp, 4, 1, FRMWtable, true);
Packit Service b7b338
Packit Service b7b338
	temp = ctrl->lpa;
Packit Service b7b338
	printf("    \"Log Page Attributes\":{\n");
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[261], 1, true, s);
Packit Service b7b338
	printf("        \"Value\":\"%sh\",\n", s);
Packit Service b7b338
	vt_build_identify_lv2(temp, 0, 4, LPAtable, true);
Packit Service b7b338
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[262], 1, true, s);
Packit Service b7b338
	printf("    \"Error Log Page Entries\":\"%sh\",\n", s);
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[263], 1, true, s);
Packit Service b7b338
	printf("    \"Number of Power States Support\":\"%sh\",\n", s);
Packit Service b7b338
Packit Service b7b338
	temp = ctrl->avscc;
Packit Service b7b338
	printf("    \"Admin Vendor Specific Command Configuration\":{\n");
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[264], 1, true, s);
Packit Service b7b338
	printf("        \"Value\":\"%sh\",\n", s);
Packit Service b7b338
	vt_build_identify_lv2(temp, 0, 1, AVSCCtable, true);
Packit Service b7b338
Packit Service b7b338
	temp = ctrl->apsta;
Packit Service b7b338
	printf("    \"Autonomous Power State Transition Attributes\":{\n");
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[265], 1, true, s);
Packit Service b7b338
	printf("        \"Value\":\"%sh\",\n", s);
Packit Service b7b338
	vt_build_identify_lv2(temp, 0, 1, APSTAtable, true);
Packit Service b7b338
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[266], 2, true, s);
Packit Service b7b338
	printf("    \"Warning Composite Temperature Threshold\":\"%sh\",\n", s);
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[268], 2, true, s);
Packit Service b7b338
	printf("    \"Critical Composite Temperature Threshold\":\"%sh\",\n", s);
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[270], 2, true, s);
Packit Service b7b338
	printf("    \"Maximum Time for Firmware Activation\":\"%sh\",\n", s);
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[272], 4, true, s);
Packit Service b7b338
	printf("    \"Host Memory Buffer Preferred Size\":\"%sh\",\n", s);
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[276], 4, true, s);
Packit Service b7b338
	printf("    \"Host Memory Buffer Minimum Size\":\"%sh\",\n", s);
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[280], 16, true, s);
Packit Service b7b338
	printf("    \"Total NVM Capacity\":\"%sh\",\n", s);
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[296], 16, true, s);
Packit Service b7b338
	printf("    \"Unallocated NVM Capacity\":\"%sh\",\n", s);
Packit Service b7b338
Packit Service b7b338
	temp = le32_to_cpu(ctrl->rpmbs); 
Packit Service b7b338
	printf("    \"Replay Protected Memory Block Support\":{\n");
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[312], 4, true, s);
Packit Service b7b338
	printf("        \"Value\":\"%sh\",\n", s);
Packit Service b7b338
	printf("        \"Number of RPMB Units\":\"%u\",\n", (temp & 0x00000003));
Packit Service b7b338
	snprintf(s, sizeof(s), ((temp >> 3) & 0x00000007)? "Reserved" : "HMAC SHA-256");
Packit Service b7b338
	printf("        \"Authentication Method\":\"%u: %s\",\n", ((temp >> 3) & 0x00000007), s);
Packit Service b7b338
	printf("        \"Total Size\":\"%u\",\n", ((temp >> 16) & 0x000000FF));
Packit Service b7b338
	printf("        \"Access Size\":\"%u\",\n", ((temp >> 24) & 0x000000FF));
Packit Service b7b338
	printf("    },\n");
Packit Service b7b338
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[316], 2, true, s);
Packit Service b7b338
	printf("    \"Extended Device Self-test Time\":\"%sh\",\n", s);
Packit Service b7b338
Packit Service b7b338
	temp = ctrl->dsto;
Packit Service b7b338
	printf("    \"Device Self-test Options\":{\n");
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[318], 1, true, s);
Packit Service b7b338
	printf("        \"Value\":\"%sh\",\n", s);
Packit Service b7b338
	vt_build_identify_lv2(temp, 0, 1, DSTOtable, true);
Packit Service b7b338
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[319], 1, true, s);
Packit Service b7b338
	printf("    \"Firmware Update Granularity\":\"%sh\",\n", s);
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[320], 1, true, s);
Packit Service b7b338
	printf("    \"Keep Alive Support\":\"%sh\",\n", s);
Packit Service b7b338
Packit Service b7b338
	temp = le16_to_cpu(ctrl->hctma);
Packit Service b7b338
	printf("    \"Host Controlled Thermal Management Attributes\":{\n");
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[322], 2, true, s);
Packit Service b7b338
	printf("        \"Value\":\"%sh\",\n", s);
Packit Service b7b338
	vt_build_identify_lv2(temp, 0, 1, HCTMAtable, true);
Packit Service b7b338
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[324], 2, true, s);
Packit Service b7b338
	printf("    \"Minimum Thermal Management Temperature\":\"%sh\",\n", s);
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[326], 2, true, s);
Packit Service b7b338
	printf("    \"Maximum Thermal Management Temperature\":\"%sh\",\n", s);
Packit Service b7b338
Packit Service b7b338
	temp = le16_to_cpu(ctrl->sanicap);
Packit Service b7b338
	printf("    \"Sanitize Capabilities\":{\n");
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[328], 2, true, s);
Packit Service b7b338
	printf("        \"Value\":\"%sh\",\n", s);
Packit Service b7b338
	vt_build_identify_lv2(temp, 0, 3, SANICAPtable, true);
Packit Service b7b338
Packit Service b7b338
	temp = ctrl->sqes;
Packit Service b7b338
	printf("    \"Submission Queue Entry Size\":{\n");
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[512], 1, true, s);
Packit Service b7b338
	printf("        \"Value\":\"%sh\",\n", s);
Packit Service b7b338
	printf("        \"Maximum Size\":\"%u\",\n", (temp & 0x0000000F));
Packit Service b7b338
	printf("        \"Required Size\":\"%u\",\n", ((temp >> 4) & 0x0000000F));
Packit Service b7b338
	printf("    }\n");
Packit Service b7b338
Packit Service b7b338
	temp = ctrl->cqes;
Packit Service b7b338
	printf("    \"Completion Queue Entry Size\":{\n");
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[513], 1, true, s);
Packit Service b7b338
	printf("        \"Value\":\"%sh\",\n", s);
Packit Service b7b338
	printf("        \"Maximum Size\":\"%u\",\n", (temp & 0x0000000F));
Packit Service b7b338
	printf("        \"Required Size\":\"%u\",\n", ((temp >> 4) & 0x0000000F));
Packit Service b7b338
	printf("    }\n");
Packit Service b7b338
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[514], 2, true, s);
Packit Service b7b338
	printf("    \"Maximum Outstanding Commands\":\"%sh\",\n", s);
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[516], 4, true, s);
Packit Service b7b338
	printf("    \"Number of Namespaces\":\"%sh\",\n", s);
Packit Service b7b338
Packit Service b7b338
	temp = le16_to_cpu(ctrl->oncs);
Packit Service b7b338
	printf("    \"Optional NVM Command Support\":{\n");
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[520], 2, true, s);
Packit Service b7b338
	printf("        \"Value\":\"%sh\",\n", s);
Packit Service b7b338
	vt_build_identify_lv2(temp, 0, 7, ONCStable, true);
Packit Service b7b338
Packit Service b7b338
	temp = le16_to_cpu(ctrl->fuses);
Packit Service b7b338
	printf("    \"Fused Operation Support\":{\n");
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[522], 2, true, s);
Packit Service b7b338
	printf("        \"Value\":\"%sh\",\n", s);
Packit Service b7b338
	vt_build_identify_lv2(temp, 0, 1, FUSEStable, true);
Packit Service b7b338
Packit Service b7b338
	temp = ctrl->fna;
Packit Service b7b338
	printf("    \"Format NVM Attributes\":{\n");
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[524], 1, true, s);
Packit Service b7b338
	printf("        \"Value\":\"%sh\",\n", s);
Packit Service b7b338
	vt_build_identify_lv2(temp, 0, 3, FNAtable, true);
Packit Service b7b338
Packit Service b7b338
	temp = ctrl->vwc;
Packit Service b7b338
	printf("    \"Volatile Write Cache\":{\n");
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[525], 1, true, s);
Packit Service b7b338
	printf("        \"Value\":\"%sh\",\n", s);
Packit Service b7b338
	vt_build_identify_lv2(temp, 0, 1, VWCtable, true);
Packit Service b7b338
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[526], 2, true, s);
Packit Service b7b338
	printf("    \"Atomic Write Unit Normal\":\"%sh\",\n", s);
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[528], 2, true, s);
Packit Service b7b338
	printf("    \"Atomic Write Unit Power Fail\":\"%sh\",\n", s);
Packit Service b7b338
Packit Service b7b338
	temp = ctrl->nvscc;
Packit Service b7b338
	printf("    \"NVM Vendor Specific Command Configuration\":{\n");
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[530], 1, true, s);
Packit Service b7b338
	printf("        \"Value\":\"%sh\",\n", s);
Packit Service b7b338
	vt_build_identify_lv2(temp, 0, 1, NVSCCtable, true);
Packit Service b7b338
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[532], 2, true, s);
Packit Service b7b338
	printf("    \"Atomic Compare 0 Write Unit\":\"%sh\",\n", s);
Packit Service b7b338
Packit Service b7b338
	temp = le32_to_cpu(ctrl->sgls);
Packit Service b7b338
	printf("    \"SGL Support\":{\n");
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[536], 4, true, s);
Packit Service b7b338
	printf("        \"Value\":\"%sh\",\n", s);
Packit Service b7b338
	pos = (temp & 0x00000003);
Packit Service b7b338
	printf("        \"bit 1:0\":\"%s\",\n", SGLSSubtable[pos]);
Packit Service b7b338
	vt_build_identify_lv2(temp, 2, 1, SGLStable, false);
Packit Service b7b338
	vt_build_identify_lv2(temp, 16, 5, SGLStable, true);
Packit Service b7b338
Packit Service b7b338
	vt_convert_data_buffer_to_hex_string(&buf[768], 256, false, s);
Packit Service b7b338
	printf("    \"NVM Subsystem NVMe Qualified Name\":\"%s\",\n", s);
Packit Service b7b338
	printf("}\n\n");
Packit Service b7b338
Packit Service b7b338
	vt_build_power_state_descriptor(ctrl);
Packit Service b7b338
Packit Service b7b338
Packit Service b7b338
	printf("\n{\n");
Packit Service b7b338
	printf("\"Vendor Specific\":\"\n");
Packit Service b7b338
	vt_dump_hex_data(&buf[3072], 1024);
Packit Service b7b338
	printf("\"}\n");
Packit Service b7b338
}
Packit Service b7b338
Packit Service b7b338
static int vt_save_smart_to_vtview_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
Packit Service b7b338
{
Packit Service b7b338
	int err = 0;
Packit Service b7b338
	int fd, ret;
Packit Service b7b338
	long int total_time = 0;
Packit Service b7b338
	long int freq_time = 0;
Packit Service b7b338
	long int cur_time = 0;
Packit Service b7b338
	long int remain_time = 0;
Packit Service b7b338
	long int start_time = 0;
Packit Service b7b338
	long int end_time = 0;
Packit Service b7b338
	char path[256] = "";
Packit Service b7b338
	char *desc = "Save SMART data into log file with format that is easy to analyze (comma delimited). Maximum log file will be 4K.\n\n"
Packit Service b7b338
		"Typical usages:\n\n"
Packit Service b7b338
		"Temperature characterization: \n"
Packit Service b7b338
		"\tvirtium save-smart-to-vtview-log /dev/yourDevice --run-time=100 --record-frequency=0.25 --test-name=burn-in-at-(-40)\n\n"
Packit Service b7b338
		"Endurance testing : \n"
Packit Service b7b338
		"\tvirtium save-smart-to-vtview-log /dev/yourDevice --run-time=100 --record-frequency=1 --test-name=Endurance-test-JEDEG-219-workload\n\n"
Packit Service b7b338
		"Just logging :\n"
Packit Service b7b338
		"\tvirtium save-smart-to-vtview-log /dev/yourDevice";
Packit Service b7b338
Packit Service b7b338
	const char *run_time = "(optional) Number of hours to log data (default = 20 hours)";
Packit Service b7b338
	const char *freq = "(optional) How often you want to log SMART data (0.25 = 15' , 0.5 = 30' , 1 = 1 hour, 2 = 2 hours, etc.). Default = 10 hours.";
Packit Service b7b338
	const char *output_file = "(optional) Name of the log file (give it a name that easy for you to remember what the test is). You can leave it blank too, we will take care it for you.";
Packit Service b7b338
	const char *test_name = "(optional) Name of the test you are doing. We use this as part of the name of the log file.";
Packit Service b7b338
Packit Service b7b338
	struct vtview_save_log_settings cfg = {
Packit Service b7b338
		.run_time_hrs = 20,
Packit Service b7b338
		.log_record_frequency_hrs = 10,
Packit Service b7b338
		.output_file = NULL,
Packit Service b7b338
		.test_name = NULL,
Packit Service b7b338
	};
Packit Service b7b338
Packit Service b7b338
	OPT_ARGS(opts) = {
Packit Service b7b338
		OPT_DOUBLE("run-time",  'r', &cfg.run_time_hrs,             run_time),
Packit Service b7b338
		OPT_DOUBLE("freq",      'f', &cfg.log_record_frequency_hrs, freq),
Packit Service b7b338
		OPT_FILE("output-file", 'o', &cfg.output_file,              output_file),
Packit Service b7b338
		OPT_STRING("test-name", 'n', "NAME", &cfg.test_name,        test_name),
Packit Service b7b338
		OPT_END()
Packit Service b7b338
	};
Packit Service b7b338
Packit Service b7b338
	vt_generate_vtview_log_file_name(vt_default_log_file_name);
Packit Service b7b338
Packit Service b7b338
	if (argc >= 2)
Packit Service b7b338
		strcpy(path, argv[1]);
Packit Service b7b338
Packit Service b7b338
	fd = parse_and_open(argc, argv, desc, opts);
Packit Service b7b338
	if (fd < 0) {
Packit Service b7b338
		printf("Error parse and open (fd = %d)\n", fd);
Packit Service b7b338
		return (fd);
Packit Service b7b338
	}
Packit Service b7b338
Packit Service b7b338
	printf("Running...\n");
Packit Service b7b338
	printf("Collecting data for device %s\n", path);
Packit Service b7b338
	printf("Running for %lf hour(s)\n", cfg.run_time_hrs);
Packit Service b7b338
	printf("Logging SMART data for every %lf hour(s)\n", cfg.log_record_frequency_hrs);
Packit Service b7b338
Packit Service b7b338
	ret = vt_update_vtview_log_header(fd, path, &cfg;;
Packit Service b7b338
	if (ret) {
Packit Service b7b338
		err = EINVAL;
Packit Service b7b338
		close(fd);
Packit Service b7b338
		return (err);
Packit Service b7b338
	}
Packit Service b7b338
Packit Service b7b338
	total_time = cfg.run_time_hrs * (float)HOUR_IN_SECONDS;
Packit Service b7b338
	freq_time = cfg.log_record_frequency_hrs * (float)HOUR_IN_SECONDS;
Packit Service b7b338
Packit Service b7b338
	if(freq_time == 0)
Packit Service b7b338
		freq_time = 1;
Packit Service b7b338
Packit Service b7b338
	start_time = time(NULL);
Packit Service b7b338
	end_time = start_time + total_time;
Packit Service b7b338
Packit Service b7b338
	fflush(stdout);
Packit Service b7b338
Packit Service b7b338
	while (1) {
Packit Service b7b338
		cur_time = time(NULL);
Packit Service b7b338
		if(cur_time >= end_time)
Packit Service b7b338
			break;
Packit Service b7b338
Packit Service b7b338
		ret = vt_add_entry_to_log(fd, path, &cfg;;
Packit Service b7b338
		if (ret) {
Packit Service b7b338
			printf("Cannot update driver log\n");
Packit Service b7b338
			break;
Packit Service b7b338
		}
Packit Service b7b338
Packit Service b7b338
		remain_time = end_time - cur_time;
Packit Service b7b338
		freq_time = MIN2(freq_time, remain_time);
Packit Service b7b338
		sleep(freq_time);
Packit Service b7b338
		fflush(stdout);
Packit Service b7b338
	}
Packit Service b7b338
Packit Service b7b338
	close (fd);
Packit Service b7b338
	return (err);
Packit Service b7b338
}
Packit Service b7b338
Packit Service b7b338
static int vt_show_identify(int argc, char **argv, struct command *cmd, struct plugin *plugin)
Packit Service b7b338
{
Packit Service b7b338
	int err = 0;
Packit Service b7b338
	int fd ,ret;
Packit Service b7b338
	struct nvme_id_ctrl ctrl;
Packit Service b7b338
	char *desc = "Parse identify data to json format\n\n"
Packit Service b7b338
		"Typical usages:\n\n"
Packit Service b7b338
		"virtium show-identify /dev/yourDevice\n";
Packit Service b7b338
Packit Service b7b338
	OPT_ARGS(opts) = {
Packit Service b7b338
		OPT_END()
Packit Service b7b338
	};
Packit Service b7b338
Packit Service b7b338
	fd = parse_and_open(argc, argv, desc, opts);
Packit Service b7b338
	if (fd < 0) {
Packit Service b7b338
		printf("Error parse and open (fd = %d)\n", fd);
Packit Service b7b338
		return (fd);
Packit Service b7b338
	}
Packit Service b7b338
Packit Service b7b338
	ret = nvme_identify_ctrl(fd, &ctrl);
Packit Service b7b338
	if (ret) {
Packit Service b7b338
		printf("Cannot read identify device\n");
Packit Service b7b338
		close (fd);
Packit Service b7b338
		return (-1);
Packit Service b7b338
	}
Packit Service b7b338
Packit Service b7b338
	vt_process_string(ctrl.sn, sizeof(ctrl.sn));
Packit Service b7b338
	vt_process_string(ctrl.mn, sizeof(ctrl.mn));
Packit Service b7b338
	vt_parse_detail_identify(&ctrl);
Packit Service b7b338
Packit Service b7b338
	close(fd);
Packit Service b7b338
	return (err);
Packit Service b7b338
}