xref: /freebsd/sbin/nvmecontrol/modules/samsung/samsung.c (revision ec965063070e5753c166cf592c9336444b74720a)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (C) 2022 Wanpeng Qian <wanpengqian@gmail.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include <sys/param.h>
32 #include <sys/ioccom.h>
33 
34 #include <ctype.h>
35 #include <err.h>
36 #include <fcntl.h>
37 #include <stdbool.h>
38 #include <stddef.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <sys/endian.h>
44 
45 #include "nvmecontrol.h"
46 
47 struct samsung_log_extended_smart
48 {
49 	uint8_t		kv[256];/* Key-Value pair */
50 	uint32_t	lwaf;	/* Lifetime Write Amplification */
51 	uint32_t	thwaf;	/* Trailing Hour Write Amplification Factor */
52 	uint64_t	luw[2];	/* Lifetime User Writes */
53 	uint64_t	lnw[2];	/* Lifetime NAND Writes */
54 	uint64_t	lur[2];	/* Lifetime User Reads */
55 	uint32_t	lrbc;	/* Lifetime Retired Block Count */
56 	uint16_t	ct;	/* Current Temperature */
57 	uint16_t	ch;	/* Capacitor Health */
58 	uint32_t	luurb;	/* Lifetime Unused Reserved Block */
59 	uint64_t	rrc;	/* Read Reclaim Count */
60 	uint64_t	lueccc;	/* Lifetime Uncorrectable ECC count */
61 	uint32_t	lurb;	/* Lifetime Used Reserved Block */
62 	uint64_t	poh[2];	/* Power on Hours */
63 	uint64_t	npoc[2];/* Normal Power Off Count */
64 	uint64_t	spoc[2];/* Sudden Power Off Count */
65 	uint32_t	pi;	/* Performance Indicator */
66 } __packed;
67 
68 static void
69 print_samsung_extended_smart(const struct nvme_controller_data *cdata __unused, void *buf, uint32_t size __unused)
70 {
71 	struct samsung_log_extended_smart *temp = buf;
72 	char cbuf[UINT128_DIG + 1];
73 	uint8_t *walker = buf;
74 	uint8_t *end = walker + 150;
75 	const char *name;
76 	uint64_t raw;
77 	uint8_t normalized;
78 
79 	static struct kv_name kv[] =
80 	{
81 		{ 0xab, "Lifetime Program Fail Count" },
82 		{ 0xac, "Lifetime Erase Fail Count" },
83 		{ 0xad, "Lifetime Wear Leveling Count" },
84 		{ 0xb8, "Lifetime End to End Error Count" },
85 		{ 0xc7, "Lifetime CRC Error Count" },
86 		{ 0xe2, "Media Wear %" },
87 		{ 0xe3, "Host Read %" },
88 		{ 0xe4, "Workload Timer" },
89 		{ 0xea, "Lifetime Thermal Throttle Status" },
90 		{ 0xf4, "Lifetime Phy Pages Written Count" },
91 		{ 0xf5, "Lifetime Data Units Written" },
92 	};
93 
94 	printf("Extended SMART Information\n");
95 	printf("=========================\n");
96 	/*
97 	 * walker[0] = Key
98 	 * walker[1,2] = reserved
99 	 * walker[3] = Normalized Value
100 	 * walker[4] = reserved
101 	 * walker[5..10] = Little Endian Raw value
102 	 *	(or other represenations)
103 	 * walker[11] = reserved
104 	 */
105 	while (walker < end) {
106 		name = kv_lookup(kv, nitems(kv), *walker);
107 		normalized = walker[3];
108 		raw = le48dec(walker + 5);
109 		switch (*walker){
110 		case 0:
111 			break;
112 		case 0xad:
113 			printf("%2X %-41s: %3d min: %u max: %u ave: %u\n",
114 			    le16dec(walker), name, normalized,
115 			    le16dec(walker + 5), le16dec(walker + 7), le16dec(walker + 9));
116 			break;
117 		case 0xe2:
118 			printf("%2X %-41s: %3d %.3f%%\n",
119 			    le16dec(walker), name, normalized,
120 			    raw / 1024.0);
121 			break;
122 		case 0xea:
123 			printf("%2X %-41s: %3d %d%% %d times\n",
124 			    le16dec(walker), name, normalized,
125 			    walker[5], le32dec(walker+6));
126 			break;
127 		default:
128 			printf("%2X %-41s: %3d %ju\n",
129 			    le16dec(walker), name, normalized,
130 			    (uintmax_t)raw);
131 			break;
132 		}
133 		walker += 12;
134 	}
135 
136 	printf("   Lifetime Write Amplification Factor      : %u\n", le32dec(&temp->lwaf));
137 	printf("   Trailing Hour Write Amplification Factor : %u\n", le32dec(&temp->thwaf));
138 	printf("   Lifetime User Writes                     : %s\n",
139 	    uint128_to_str(to128(temp->luw), cbuf, sizeof(cbuf)));
140 	printf("   Lifetime NAND Writes                     : %s\n",
141 	    uint128_to_str(to128(temp->lnw), cbuf, sizeof(cbuf)));
142 	printf("   Lifetime User Reads                      : %s\n",
143 	    uint128_to_str(to128(temp->lur), cbuf, sizeof(cbuf)));
144 	printf("   Lifetime Retired Block Count             : %u\n", le32dec(&temp->lrbc));
145 	printf("   Current Temperature                      : ");
146 	print_temp_K(le16dec(&temp->ct));
147 	printf("   Capacitor Health                         : %u\n", le16dec(&temp->ch));
148 	printf("   Reserved Erase Block Count               : %u\n", le32dec(&temp->luurb));
149 	printf("   Read Reclaim Count                       : %ju\n", (uintmax_t) le64dec(&temp->rrc));
150 	printf("   Lifetime Uncorrectable ECC Count         : %ju\n", (uintmax_t) le64dec(&temp->lueccc));
151 	printf("   Reallocated Block Count                  : %u\n", le32dec(&temp->lurb));
152 	printf("   Power on Hours                           : %s\n",
153 	    uint128_to_str(to128(temp->poh), cbuf, sizeof(cbuf)));
154 	printf("   Normal Power Off Count                   : %s\n",
155 	    uint128_to_str(to128(temp->npoc), cbuf, sizeof(cbuf)));
156 	printf("   Sudden Power Off Count                   : %s\n",
157 	    uint128_to_str(to128(temp->spoc), cbuf, sizeof(cbuf)));
158 	printf("   Performance Indicator                    : %u\n", le32dec(&temp->pi));
159 }
160 
161 #define SAMSUNG_LOG_EXTEND_SMART 0xca
162 
163 NVME_LOGPAGE(samsung_extended_smart,
164     SAMSUNG_LOG_EXTEND_SMART,		"samsung", "Extended SMART Information",
165     print_samsung_extended_smart,	DEFAULT_SIZE);
166