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
44 struct 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
65 static void
print_samsung_extended_smart(const struct nvme_controller_data * cdata __unused,void * buf,uint32_t size __unused)66 print_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
160 NVME_LOGPAGE(samsung_extended_smart,
161 SAMSUNG_LOG_EXTEND_SMART, "samsung", "Extended SMART Information",
162 print_samsung_extended_smart, DEFAULT_SIZE);
163