1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
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/param.h>
29#include <sys/ioccom.h>
30
31#include <ctype.h>
32#include <err.h>
33#include <fcntl.h>
34#include <stdbool.h>
35#include <stddef.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
40#include <sys/endian.h>
41
42#include "nvmecontrol.h"
43
44struct samsung_log_extended_smart
45{
46	uint8_t		kv[256];/* Key-Value pair */
47	uint32_t	lwaf;	/* Lifetime Write Amplification */
48	uint32_t	thwaf;	/* Trailing Hour Write Amplification Factor */
49	uint64_t	luw[2];	/* Lifetime User Writes */
50	uint64_t	lnw[2];	/* Lifetime NAND Writes */
51	uint64_t	lur[2];	/* Lifetime User Reads */
52	uint32_t	lrbc;	/* Lifetime Retired Block Count */
53	uint16_t	ct;	/* Current Temperature */
54	uint16_t	ch;	/* Capacitor Health */
55	uint32_t	luurb;	/* Lifetime Unused Reserved Block */
56	uint64_t	rrc;	/* Read Reclaim Count */
57	uint64_t	lueccc;	/* Lifetime Uncorrectable ECC count */
58	uint32_t	lurb;	/* Lifetime Used Reserved Block */
59	uint64_t	poh[2];	/* Power on Hours */
60	uint64_t	npoc[2];/* Normal Power Off Count */
61	uint64_t	spoc[2];/* Sudden Power Off Count */
62	uint32_t	pi;	/* Performance Indicator */
63} __packed;
64
65static void
66print_samsung_extended_smart(const struct nvme_controller_data *cdata __unused, void *buf, uint32_t size __unused)
67{
68	struct samsung_log_extended_smart *temp = buf;
69	char cbuf[UINT128_DIG + 1];
70	uint8_t *walker = buf;
71	uint8_t *end = walker + 150;
72	const char *name;
73	uint64_t raw;
74	uint8_t normalized;
75
76	static struct kv_name kv[] =
77	{
78		{ 0xab, "Lifetime Program Fail Count" },
79		{ 0xac, "Lifetime Erase Fail Count" },
80		{ 0xad, "Lifetime Wear Leveling Count" },
81		{ 0xb8, "Lifetime End to End Error Count" },
82		{ 0xc7, "Lifetime CRC Error Count" },
83		{ 0xe2, "Media Wear %" },
84		{ 0xe3, "Host Read %" },
85		{ 0xe4, "Workload Timer" },
86		{ 0xea, "Lifetime Thermal Throttle Status" },
87		{ 0xf4, "Lifetime Phy Pages Written Count" },
88		{ 0xf5, "Lifetime Data Units Written" },
89	};
90
91	printf("Extended SMART Information\n");
92	printf("=========================\n");
93	/*
94	 * walker[0] = Key
95	 * walker[1,2] = reserved
96	 * walker[3] = Normalized Value
97	 * walker[4] = reserved
98	 * walker[5..10] = Little Endian Raw value
99	 *	(or other represenations)
100	 * walker[11] = reserved
101	 */
102	while (walker < end) {
103		name = kv_lookup(kv, nitems(kv), *walker);
104		normalized = walker[3];
105		raw = le48dec(walker + 5);
106		switch (*walker){
107		case 0:
108			break;
109		case 0xad:
110			printf("%2X %-41s: %3d min: %u max: %u ave: %u\n",
111			    le16dec(walker), name, normalized,
112			    le16dec(walker + 5), le16dec(walker + 7), le16dec(walker + 9));
113			break;
114		case 0xe2:
115			printf("%2X %-41s: %3d %.3f%%\n",
116			    le16dec(walker), name, normalized,
117			    raw / 1024.0);
118			break;
119		case 0xea:
120			printf("%2X %-41s: %3d %d%% %d times\n",
121			    le16dec(walker), name, normalized,
122			    walker[5], le32dec(walker+6));
123			break;
124		default:
125			printf("%2X %-41s: %3d %ju\n",
126			    le16dec(walker), name, normalized,
127			    (uintmax_t)raw);
128			break;
129		}
130		walker += 12;
131	}
132
133	printf("   Lifetime Write Amplification Factor      : %u\n", le32dec(&temp->lwaf));
134	printf("   Trailing Hour Write Amplification Factor : %u\n", le32dec(&temp->thwaf));
135	printf("   Lifetime User Writes                     : %s\n",
136	    uint128_to_str(to128(temp->luw), cbuf, sizeof(cbuf)));
137	printf("   Lifetime NAND Writes                     : %s\n",
138	    uint128_to_str(to128(temp->lnw), cbuf, sizeof(cbuf)));
139	printf("   Lifetime User Reads                      : %s\n",
140	    uint128_to_str(to128(temp->lur), cbuf, sizeof(cbuf)));
141	printf("   Lifetime Retired Block Count             : %u\n", le32dec(&temp->lrbc));
142	printf("   Current Temperature                      : ");
143	print_temp_K(le16dec(&temp->ct));
144	printf("   Capacitor Health                         : %u\n", le16dec(&temp->ch));
145	printf("   Reserved Erase Block Count               : %u\n", le32dec(&temp->luurb));
146	printf("   Read Reclaim Count                       : %ju\n", (uintmax_t) le64dec(&temp->rrc));
147	printf("   Lifetime Uncorrectable ECC Count         : %ju\n", (uintmax_t) le64dec(&temp->lueccc));
148	printf("   Reallocated Block Count                  : %u\n", le32dec(&temp->lurb));
149	printf("   Power on Hours                           : %s\n",
150	    uint128_to_str(to128(temp->poh), cbuf, sizeof(cbuf)));
151	printf("   Normal Power Off Count                   : %s\n",
152	    uint128_to_str(to128(temp->npoc), cbuf, sizeof(cbuf)));
153	printf("   Sudden Power Off Count                   : %s\n",
154	    uint128_to_str(to128(temp->spoc), cbuf, sizeof(cbuf)));
155	printf("   Performance Indicator                    : %u\n", le32dec(&temp->pi));
156}
157
158#define SAMSUNG_LOG_EXTEND_SMART 0xca
159
160NVME_LOGPAGE(samsung_extended_smart,
161    SAMSUNG_LOG_EXTEND_SMART,		"samsung", "Extended SMART Information",
162    print_samsung_extended_smart,	DEFAULT_SIZE);
163