git: 84e86788705c - main - nvmecontrol: Add Samsung Extended SMART Information logpage support

From: Benedict Reuschling <bcr_at_FreeBSD.org>
Date: Thu, 06 Oct 2022 10:37:22 UTC
The branch main has been updated by bcr (doc committer):

URL: https://cgit.FreeBSD.org/src/commit/?id=84e86788705c176cc195e4a9831c0be08dcece31

commit 84e86788705c176cc195e4a9831c0be08dcece31
Author:     Wanpeng Qian <wanpengqian@gmail.com>
AuthorDate: 2022-10-06 10:10:06 +0000
Commit:     Benedict Reuschling <bcr@FreeBSD.org>
CommitDate: 2022-10-06 10:24:02 +0000

    nvmecontrol: Add Samsung Extended SMART Information logpage support
    
    Samsung PM983 SSD has a 0xca logpage. It has more information compared
    to Intel's this patch tested on PM983 M2 SSD and works as expected.
    
    Reviewed by:            imp@
    Approved by:            kp@
    Event:                  Aberdeen Hackathon 2022
    Differential revision:  https://reviews.freebsd.org/D33749
---
 sbin/nvmecontrol/modules/Makefile          |   2 +-
 sbin/nvmecontrol/modules/samsung/Makefile  |   6 ++
 sbin/nvmecontrol/modules/samsung/samsung.c | 165 +++++++++++++++++++++++++++++
 sbin/nvmecontrol/nvmecontrol.8             |   4 +-
 4 files changed, 175 insertions(+), 2 deletions(-)

diff --git a/sbin/nvmecontrol/modules/Makefile b/sbin/nvmecontrol/modules/Makefile
index e615eaffb8c9..7bc9712e99e5 100644
--- a/sbin/nvmecontrol/modules/Makefile
+++ b/sbin/nvmecontrol/modules/Makefile
@@ -1,5 +1,5 @@
 # $FreeBSD$
 
-SUBDIR=	intel wdc
+SUBDIR=	intel wdc samsung
 
 .include <bsd.subdir.mk>
diff --git a/sbin/nvmecontrol/modules/samsung/Makefile b/sbin/nvmecontrol/modules/samsung/Makefile
new file mode 100644
index 000000000000..c22e8b2b4fdf
--- /dev/null
+++ b/sbin/nvmecontrol/modules/samsung/Makefile
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+LIB=	samsung
+SRCS=	samsung.c
+
+.include <bsd.lib.mk>
diff --git a/sbin/nvmecontrol/modules/samsung/samsung.c b/sbin/nvmecontrol/modules/samsung/samsung.c
new file mode 100644
index 000000000000..50f0a89db13b
--- /dev/null
+++ b/sbin/nvmecontrol/modules/samsung/samsung.c
@@ -0,0 +1,165 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (C) 2022 Wanpeng Qian <wanpengqian@gmail.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/ioccom.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/endian.h>
+
+#include "nvmecontrol.h"
+
+struct samsung_log_extended_smart
+{
+	uint8_t		kv[256];/* Key-Value pair */
+	uint32_t	lwaf;	/* Lifetime Write Amplification */
+	uint32_t	thwaf;	/* Trailing Hour Write Amplification Factor */
+	uint64_t	luw[2];	/* Lifetime User Writes */
+	uint64_t	lnw[2];	/* Lifetime NAND Writes */
+	uint64_t	lur[2];	/* Lifetime User Reads */
+	uint32_t	lrbc;	/* Lifetime Retired Block Count */
+	uint16_t	ct;	/* Current Temperature */
+	uint16_t	ch;	/* Capacitor Health */
+	uint32_t	luurb;	/* Lifetime Unused Reserved Block */
+	uint64_t	rrc;	/* Read Reclaim Count */
+	uint64_t	lueccc;	/* Lifetime Uncorrectable ECC count */
+	uint32_t	lurb;	/* Lifetime Used Reserved Block */
+	uint64_t	poh[2];	/* Power on Hours */
+	uint64_t	npoc[2];/* Normal Power Off Count */
+	uint64_t	spoc[2];/* Sudden Power Off Count */
+	uint32_t	pi;	/* Performance Indicator */
+} __packed;
+
+static void
+print_samsung_extended_smart(const struct nvme_controller_data *cdata __unused, void *buf, uint32_t size __unused)
+{
+	struct samsung_log_extended_smart *temp = buf;
+	char cbuf[UINT128_DIG + 1];
+	uint8_t *walker = buf;
+	uint8_t *end = walker + 150;
+	const char *name;
+	uint64_t raw;
+	uint8_t normalized;
+
+	static struct kv_name kv[] =
+	{
+		{ 0xab, "Lifetime Program Fail Count" },
+		{ 0xac, "Lifetime Erase Fail Count" },
+		{ 0xad, "Lifetime Wear Leveling Count" },
+		{ 0xb8, "Lifetime End to End Error Count" },
+		{ 0xc7, "Lifetime CRC Error Count" },
+		{ 0xe2, "Media Wear %" },
+		{ 0xe3, "Host Read %" },
+		{ 0xe4, "Workload Timer" },
+		{ 0xea, "Lifetime Thermal Throttle Status" },
+		{ 0xf4, "Lifetime Phy Pages Written Count" },
+		{ 0xf5, "Lifetime Data Units Written" },
+	};
+
+	printf("Extended SMART Information\n");
+	printf("=========================\n");
+	/*
+	 * walker[0] = Key
+	 * walker[1,2] = reserved
+	 * walker[3] = Normalized Value
+	 * walker[4] = reserved
+	 * walker[5..10] = Little Endian Raw value
+	 *	(or other represenations)
+	 * walker[11] = reserved
+	 */
+	while (walker < end) {
+		name = kv_lookup(kv, nitems(kv), *walker);
+		normalized = walker[3];
+		raw = le48dec(walker + 5);
+		switch (*walker){
+		case 0:
+			break;
+		case 0xad:
+			printf("%2X %-41s: %3d min: %u max: %u ave: %u\n",
+			    le16dec(walker), name, normalized,
+			    le16dec(walker + 5), le16dec(walker + 7), le16dec(walker + 9));
+			break;
+		case 0xe2:
+			printf("%2X %-41s: %3d %.3f%%\n",
+			    le16dec(walker), name, normalized,
+			    raw / 1024.0);
+			break;
+		case 0xea:
+			printf("%2X %-41s: %3d %d%% %d times\n",
+			    le16dec(walker), name, normalized,
+			    walker[5], le32dec(walker+6));
+			break;
+		default:
+			printf("%2X %-41s: %3d %ju\n",
+			    le16dec(walker), name, normalized,
+			    (uintmax_t)raw);
+			break;
+		}
+		walker += 12;
+	}
+
+	printf("   Lifetime Write Amplification Factor      : %u\n", le32dec(&temp->lwaf));
+	printf("   Trailing Hour Write Amplification Factor : %u\n", le32dec(&temp->thwaf));
+	printf("   Lifetime User Writes                     : %s\n",
+	    uint128_to_str(to128(temp->luw), cbuf, sizeof(cbuf)));
+	printf("   Lifetime NAND Writes                     : %s\n",
+	    uint128_to_str(to128(temp->lnw), cbuf, sizeof(cbuf)));
+	printf("   Lifetime User Reads                      : %s\n",
+	    uint128_to_str(to128(temp->lur), cbuf, sizeof(cbuf)));
+	printf("   Lifetime Retired Block Count             : %u\n", le32dec(&temp->lrbc));
+	printf("   Current Temperature                      : ");
+	print_temp(le16dec(&temp->ct));
+	printf("   Capacitor Health                         : %u\n", le16dec(&temp->ch));
+	printf("   Reserved Erase Block Count               : %u\n", le32dec(&temp->luurb));
+	printf("   Read Reclaim Count                       : %lu\n", le64dec(&temp->rrc));
+	printf("   Lifetime Uncorrectable ECC Count         : %lu\n", le64dec(&temp->lueccc));
+	printf("   Reallocated Block Count                  : %u\n", le32dec(&temp->lurb));
+	printf("   Power on Hours                           : %s\n",
+	    uint128_to_str(to128(temp->poh), cbuf, sizeof(cbuf)));
+	printf("   Normal Power Off Count                   : %s\n",
+	    uint128_to_str(to128(temp->npoc), cbuf, sizeof(cbuf)));
+	printf("   Sudden Power Off Count                   : %s\n",
+	    uint128_to_str(to128(temp->spoc), cbuf, sizeof(cbuf)));
+	printf("   Performance Indicator                    : %u\n", le32dec(&temp->pi));
+}
+
+#define SAMSUNG_LOG_EXTEND_SMART 0xca
+
+NVME_LOGPAGE(samsung_extended_smart,
+    SAMSUNG_LOG_EXTEND_SMART,		"samsung", "Extended SMART Information",
+    print_samsung_extended_smart,	DEFAULT_SIZE);
diff --git a/sbin/nvmecontrol/nvmecontrol.8 b/sbin/nvmecontrol/nvmecontrol.8
index 7d70e1762f73..d6b41889a727 100644
--- a/sbin/nvmecontrol/nvmecontrol.8
+++ b/sbin/nvmecontrol/nvmecontrol.8
@@ -244,7 +244,7 @@ data associated with that drive.
 .El
 .Ss logpage
 The logpage command knows how to print log pages of various types.
-It also knows about vendor specific log pages from hgst/wdc and intel.
+It also knows about vendor specific log pages from hgst/wdc, samsung and intel.
 Note that some vendors use the same log page numbers for different data.
 .Pp
 .Bl -tag -compact -width "Page 0x00"
@@ -274,6 +274,8 @@ Wite latency stats (Intel)
 Temperature stats (Intel)
 .It Dv Page 0xca
 Advanced SMART information (Intel)
+.It Dv Page 0xca
+Extended SMART information (Samsung)
 .El
 .Pp
 Specifying