From 4024fb4707f2b9566debaac2cab50f41ef9e7304 Mon Sep 17 00:00:00 2001
From: Scott Bauer <scott.bauer@intel.com>
Date: Tue, 16 Jan 2018 10:46:50 -0700
Subject: nvme/vendor: Add get log LSP/LSO fields from 1.3 spec

Git-commit: 722c71bb3246a46a784861a3874aa5017b919f49
References: bsc#1076004

Signed-off-by: Scott Bauer <scott.bauer@intel.com>
[Fixed param descriptions and short opt]
Signed-off-by: Keith Busch <keith.busch@intel.com>
---
 intel-nvme.c    | 17 ++++++++++++-----
 linux/nvme.h    |  5 +++++
 memblaze-nvme.c |  4 +++-
 nvme-ioctl.c    | 24 +++++++++++++++++++-----
 nvme-ioctl.h    |  3 ++-
 nvme.c          | 12 +++++++++++-
 wdc-nvme.c      |  4 +++-
 7 files changed, 55 insertions(+), 14 deletions(-)

diff --git a/intel-nvme.c b/intel-nvme.c
index 125e30b..e673fc8 100644
--- a/intel-nvme.c
+++ b/intel-nvme.c
@@ -161,8 +161,9 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
 
 	fd = parse_and_open(argc, argv, desc, command_line_options, &cfg, sizeof(cfg));
 
-	err = nvme_get_log(fd, cfg.namespace_id, 0xca, sizeof(smart_log),
-			&smart_log);
+	err = nvme_get_log(fd, cfg.namespace_id, 0xca,
+			   NVME_NO_LOG_LSP, NVME_NO_LOG_LPO,
+			   sizeof(smart_log), &smart_log);
 	if (!err) {
 		if (!cfg.raw_binary)
 			show_intel_smart_log(&smart_log, cfg.namespace_id, devicename);
@@ -196,7 +197,9 @@ static int get_market_log(int argc, char **argv, struct command *cmd, struct plu
 
 	fd = parse_and_open(argc, argv, desc, command_line_options, &cfg, sizeof(cfg));
 
-	err = nvme_get_log(fd, NVME_NSID_ALL, 0xdd, sizeof(log), log);
+	err = nvme_get_log(fd, NVME_NSID_ALL, 0xdd,
+			   NVME_NO_LOG_LSP, NVME_NO_LOG_LPO,
+			   sizeof(log), log);
 	if (!err) {
 		if (!cfg.raw_binary)
 			printf("Intel Marketing Name Log:\n%s\n", log);
@@ -256,7 +259,9 @@ static int get_temp_stats_log(int argc, char **argv, struct command *cmd, struct
 
 	fd = parse_and_open(argc, argv, desc, command_line_options, &cfg, sizeof(cfg));
 
-	err = nvme_get_log(fd, NVME_NSID_ALL, 0xc5, sizeof(stats), &stats);
+	err = nvme_get_log(fd, NVME_NSID_ALL, 0xc5,
+			   NVME_NO_LOG_LSP, NVME_NO_LOG_LPO,
+			   sizeof(stats), &stats);
 	if (!err) {
 		if (!cfg.raw_binary)
 			show_temp_stats(&stats);
@@ -322,7 +327,9 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct
 
 	fd = parse_and_open(argc, argv, desc, command_line_options, &cfg, sizeof(cfg));
 
-	err = nvme_get_log(fd, NVME_NSID_ALL, cfg.write ? 0xc2 : 0xc1, sizeof(stats), &stats);
+	err = nvme_get_log(fd, NVME_NSID_ALL, cfg.write ? 0xc2 : 0xc1,
+			   NVME_NO_LOG_LSP, NVME_NO_LOG_LPO,
+			   sizeof(stats), &stats);
 	if (!err) {
 		if (!cfg.raw_binary)
 			show_lat_stats(&stats, cfg.write);
diff --git a/linux/nvme.h b/linux/nvme.h
index c827804..4714f9a 100644
--- a/linux/nvme.h
+++ b/linux/nvme.h
@@ -677,6 +677,11 @@ enum {
 	NVME_FWACT_ACTV		= (2 << 3),
 };
 
+enum {
+	NVME_NO_LOG_LSP       = 0x0,
+	NVME_NO_LOG_LPO       = 0x0,
+};
+
 struct nvme_identify {
 	__u8			opcode;
 	__u8			flags;
diff --git a/memblaze-nvme.c b/memblaze-nvme.c
index 1e092db..863c8ff 100644
--- a/memblaze-nvme.c
+++ b/memblaze-nvme.c
@@ -223,7 +223,9 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
 
 	fd = parse_and_open(argc, argv, desc, command_line_options, &cfg, sizeof(cfg));
 
-	err = nvme_get_log(fd, cfg.namespace_id, 0xca, sizeof(smart_log), &smart_log);
+	err = nvme_get_log(fd, cfg.namespace_id, 0xca,
+			   NVME_NO_LOG_LSP, NVME_NO_LOG_LPO,
+			   sizeof(smart_log), &smart_log);
 	if (!err) {
 		if (!cfg.raw_binary)
 			err = show_memblaze_smart_log(fd, cfg.namespace_id, devicename, &smart_log);
diff --git a/nvme-ioctl.c b/nvme-ioctl.c
index 8e7b785..721d560 100644
--- a/nvme-ioctl.c
+++ b/nvme-ioctl.c
@@ -370,7 +370,8 @@ int nvme_identify_ns_descs(int fd, __u32 nsid, void *data)
 	return nvme_identify(fd, nsid, NVME_ID_CNS_NS_DESC_LIST, data);
 }
 
-int nvme_get_log(int fd, __u32 nsid, __u8 log_id, __u32 data_len, void *data)
+int nvme_get_log(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
+                 __u32 data_len, void *data)
 {
 	struct nvme_admin_cmd cmd = {
 		.opcode		= nvme_admin_get_log_page,
@@ -382,30 +383,43 @@ int nvme_get_log(int fd, __u32 nsid, __u8 log_id, __u32 data_len, void *data)
 	__u16 numdu = numd >> 16, numdl = numd & 0xffff;
 
 	cmd.cdw10 = log_id | (numdl << 16);
+	if (lsp)
+                cmd.cdw10 |= lsp << 8;
+
 	cmd.cdw11 = numdu;
+	cmd.cdw12 = lpo;
+	cmd.cdw13 = (lpo >> 32);
 
 	return nvme_submit_admin_passthru(fd, &cmd);
 }
 
 int nvme_fw_log(int fd, struct nvme_firmware_log_page *fw_log)
 {
-	return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_FW_SLOT, sizeof(*fw_log), fw_log);
+	return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_FW_SLOT,
+			    NVME_NO_LOG_LSP, NVME_NO_LOG_LPO,
+			    sizeof(*fw_log), fw_log);
 }
 
 int nvme_error_log(int fd, __u32 nsid, int entries,
 		   struct nvme_error_log_page *err_log)
 {
-	return nvme_get_log(fd, nsid, NVME_LOG_ERROR, entries * sizeof(*err_log), err_log);
+	return nvme_get_log(fd, 0, NVME_LOG_ERROR,
+			    NVME_NO_LOG_LSP, NVME_NO_LOG_LPO,
+			    entries * sizeof(*err_log), err_log);
 }
 
 int nvme_smart_log(int fd, __u32 nsid, struct nvme_smart_log *smart_log)
 {
-	return nvme_get_log(fd, nsid, NVME_LOG_SMART, sizeof(*smart_log), smart_log);
+	return nvme_get_log(fd, nsid, NVME_LOG_SMART,
+			    NVME_NO_LOG_LSP, NVME_NO_LOG_LPO,
+			    sizeof(*smart_log), smart_log);
 }
 
 int nvme_discovery_log(int fd, struct nvmf_disc_rsp_page_hdr *log, __u32 size)
 {
-	return nvme_get_log(fd, 0, NVME_LOG_DISC, size, log);
+	return nvme_get_log(fd, 0, NVME_LOG_DISC,
+			    NVME_NO_LOG_LSP, NVME_NO_LOG_LPO,
+			    size, log);
 }
 
 int nvme_feature(int fd, __u8 opcode, __u32 nsid, __u32 cdw10, __u32 cdw11,
diff --git a/nvme-ioctl.h b/nvme-ioctl.h
index 8faf345..6f5710f 100644
--- a/nvme-ioctl.h
+++ b/nvme-ioctl.h
@@ -78,8 +78,9 @@ int nvme_identify_ns(int fd, __u32 nsid, bool present, void *data);
 int nvme_identify_ns_list(int fd, __u32 nsid, bool all, void *data);
 int nvme_identify_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data);
 int nvme_identify_ns_descs(int fd, __u32 nsid, void *data);
+int nvme_get_log(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
+                 __u32 data_len, void *data);
 
-int nvme_get_log(int fd, __u32 nsid, __u8 log_id, __u32 data_len, void *data);
 int nvme_fw_log(int fd, struct nvme_firmware_log_page *fw_log);
 int nvme_error_log(int fd, __u32 nsid, int entries,
 		   struct nvme_error_log_page *err_log);
diff --git a/nvme.c b/nvme.c
index ad99e07..9d7c302 100644
--- a/nvme.c
+++ b/nvme.c
@@ -365,6 +365,8 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
 	const char *namespace_id = "desired namespace";
 	const char *log_id = "identifier of log to retrieve";
 	const char *log_len = "how many bytes to retrieve";
+	const char *lsp = "log specific field";
+	const char *lpo = "log page offset specifies the location within a log page from where to start returning data";
 	const char *raw_binary = "output in raw format";
 	int err, fd;
 
@@ -372,6 +374,8 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
 		__u32 namespace_id;
 		__u32 log_id;
 		__u32 log_len;
+		__u64 lpo;
+		__u8  lsp;
 		int   raw_binary;
 	};
 
@@ -379,6 +383,8 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
 		.namespace_id = NVME_NSID_ALL,
 		.log_id       = 0,
 		.log_len      = 0,
+		.lpo          = NVME_NO_LOG_LPO,
+		.lsp          = NVME_NO_LOG_LSP,
 	};
 
 	const struct argconfig_commandline_options command_line_options[] = {
@@ -386,6 +392,8 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
 		{"log-id",       'i', "NUM", CFG_POSITIVE, &cfg.log_id,       required_argument, log_id},
 		{"log-len",      'l', "NUM", CFG_POSITIVE, &cfg.log_len,      required_argument, log_len},
 		{"raw-binary",   'b', "",    CFG_NONE,     &cfg.raw_binary,   no_argument,       raw_binary},
+		{"lpo",          'o', "NUM", CFG_LONG,     &cfg.lpo,          required_argument, lpo},
+		{"lsp",          's', "NUM", CFG_BYTE,     &cfg.lsp,          required_argument, lsp},
 		{NULL}
 	};
 
@@ -405,7 +413,9 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
 			return EINVAL;
 		}
 
-		err = nvme_get_log(fd, cfg.namespace_id, cfg.log_id, cfg.log_len, log);
+		err = nvme_get_log(fd, cfg.namespace_id, cfg.log_id,
+				   cfg.lsp, cfg.lpo,
+				   cfg.log_len, log);
 		if (!err) {
 			if (!cfg.raw_binary) {
 				printf("Device:%s log-id:%d namespace-id:%#x\n",
diff --git a/wdc-nvme.c b/wdc-nvme.c
index 8028f61..8be3014 100644
--- a/wdc-nvme.c
+++ b/wdc-nvme.c
@@ -872,7 +872,9 @@ static int wdc_smart_log_add(int argc, char **argv, struct command *command,
 	}
 	memset(data, 0, sizeof (__u8) * WDC_ADD_LOG_BUF_LEN);
 
-	ret = nvme_get_log(fd, 0x01, WDC_NVME_ADD_LOG_OPCODE, WDC_ADD_LOG_BUF_LEN, data);
+	ret = nvme_get_log(fd, 0x01, WDC_NVME_ADD_LOG_OPCODE,
+			   NVME_NO_LOG_LSP, NVME_NO_LOG_LPO,
+			   WDC_ADD_LOG_BUF_LEN, data);
 	fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
 	if (ret == 0) {
 		l = (struct wdc_log_page_header*)data;
-- 
2.13.7

