1*72170a41SWanpeng Qian /*-
2*72170a41SWanpeng Qian * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*72170a41SWanpeng Qian *
4*72170a41SWanpeng Qian * Copyright (c) 2022 Wanpeng Qian <wanpengqian@gmail.com>
5*72170a41SWanpeng Qian *
6*72170a41SWanpeng Qian * Redistribution and use in source and binary forms, with or without
7*72170a41SWanpeng Qian * modification, are permitted provided that the following conditions
8*72170a41SWanpeng Qian * are met:
9*72170a41SWanpeng Qian * 1. Redistributions of source code must retain the above copyright
10*72170a41SWanpeng Qian * notice, this list of conditions and the following disclaimer.
11*72170a41SWanpeng Qian * 2. Redistributions in binary form must reproduce the above copyright
12*72170a41SWanpeng Qian * notice, this list of conditions and the following disclaimer in the
13*72170a41SWanpeng Qian * documentation and/or other materials provided with the distribution.
14*72170a41SWanpeng Qian *
15*72170a41SWanpeng Qian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*72170a41SWanpeng Qian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*72170a41SWanpeng Qian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*72170a41SWanpeng Qian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*72170a41SWanpeng Qian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*72170a41SWanpeng Qian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*72170a41SWanpeng Qian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*72170a41SWanpeng Qian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*72170a41SWanpeng Qian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*72170a41SWanpeng Qian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*72170a41SWanpeng Qian * SUCH DAMAGE.
26*72170a41SWanpeng Qian */
27*72170a41SWanpeng Qian
28*72170a41SWanpeng Qian #include <sys/cdefs.h>
29*72170a41SWanpeng Qian __FBSDID("$FreeBSD$");
30*72170a41SWanpeng Qian
31*72170a41SWanpeng Qian #include <sys/param.h>
32*72170a41SWanpeng Qian #include <sys/ioccom.h>
33*72170a41SWanpeng Qian
34*72170a41SWanpeng Qian #include <ctype.h>
35*72170a41SWanpeng Qian #include <err.h>
36*72170a41SWanpeng Qian #include <fcntl.h>
37*72170a41SWanpeng Qian #include <stdbool.h>
38*72170a41SWanpeng Qian #include <stddef.h>
39*72170a41SWanpeng Qian #include <stdio.h>
40*72170a41SWanpeng Qian #include <stdlib.h>
41*72170a41SWanpeng Qian #include <string.h>
42*72170a41SWanpeng Qian #include <unistd.h>
43*72170a41SWanpeng Qian #include <sys/endian.h>
44*72170a41SWanpeng Qian
45*72170a41SWanpeng Qian #include "nvmecontrol.h"
46*72170a41SWanpeng Qian
47*72170a41SWanpeng Qian static void
print_micron_unique_smart(const struct nvme_controller_data * cdata __unused,void * buf,uint32_t size __unused)48*72170a41SWanpeng Qian print_micron_unique_smart(const struct nvme_controller_data *cdata __unused, void *buf, uint32_t size __unused)
49*72170a41SWanpeng Qian {
50*72170a41SWanpeng Qian uint8_t *walker = buf;
51*72170a41SWanpeng Qian uint8_t *end = walker + 150;
52*72170a41SWanpeng Qian const char *name;
53*72170a41SWanpeng Qian uint64_t raw;
54*72170a41SWanpeng Qian uint8_t normalized;
55*72170a41SWanpeng Qian
56*72170a41SWanpeng Qian static struct kv_name kv[] =
57*72170a41SWanpeng Qian {
58*72170a41SWanpeng Qian { 0xf9, "NAND Writes 1GiB" },
59*72170a41SWanpeng Qian { 0xfa, "NAND Reads 1GiB" },
60*72170a41SWanpeng Qian { 0xea, "Thermal Throttle Status" },
61*72170a41SWanpeng Qian { 0xe7, "Temperature" },
62*72170a41SWanpeng Qian { 0xe8, "Power Consumption" },
63*72170a41SWanpeng Qian { 0xaf, "Power Loss Protection" },
64*72170a41SWanpeng Qian };
65*72170a41SWanpeng Qian
66*72170a41SWanpeng Qian printf("Vendor Unique SMART Information\n");
67*72170a41SWanpeng Qian printf("=========================\n");
68*72170a41SWanpeng Qian /*
69*72170a41SWanpeng Qian * walker[0] = Key
70*72170a41SWanpeng Qian * walker[1,2] = reserved
71*72170a41SWanpeng Qian * walker[3] = Normalized Value
72*72170a41SWanpeng Qian * walker[4] = reserved
73*72170a41SWanpeng Qian * walker[5..10] = Little Endian Raw value
74*72170a41SWanpeng Qian * (or other represenations)
75*72170a41SWanpeng Qian * walker[11] = reserved
76*72170a41SWanpeng Qian */
77*72170a41SWanpeng Qian while (walker < end) {
78*72170a41SWanpeng Qian name = kv_lookup(kv, nitems(kv), *walker);
79*72170a41SWanpeng Qian normalized = walker[3];
80*72170a41SWanpeng Qian raw = le48dec(walker + 5);
81*72170a41SWanpeng Qian switch (*walker){
82*72170a41SWanpeng Qian case 0:
83*72170a41SWanpeng Qian break;
84*72170a41SWanpeng Qian case 0xf9:
85*72170a41SWanpeng Qian /* FALLTHOUGH */
86*72170a41SWanpeng Qian case 0xfa:
87*72170a41SWanpeng Qian printf("%2X %-24s: %ju GiB\n", *walker, name, (uintmax_t)raw);
88*72170a41SWanpeng Qian break;
89*72170a41SWanpeng Qian case 0xea:
90*72170a41SWanpeng Qian printf("%2X %-24s:", *walker, name);
91*72170a41SWanpeng Qian if (*(walker + 5) == 0)
92*72170a41SWanpeng Qian printf(" inactive\n");
93*72170a41SWanpeng Qian if (*(walker + 5) == 1)
94*72170a41SWanpeng Qian printf(" active, total throttling time %u mins\n", le32dec(walker + 6));
95*72170a41SWanpeng Qian break;
96*72170a41SWanpeng Qian case 0xe7:
97*72170a41SWanpeng Qian printf("%2X %-24s: max ", *walker, name);
98*72170a41SWanpeng Qian print_temp_C(le16dec(walker + 5));
99*72170a41SWanpeng Qian printf(" : min ");
100*72170a41SWanpeng Qian print_temp_C(le16dec(walker + 7));
101*72170a41SWanpeng Qian printf(" : cur ");
102*72170a41SWanpeng Qian print_temp_C(le16dec(walker + 9));
103*72170a41SWanpeng Qian break;
104*72170a41SWanpeng Qian case 0xe8:
105*72170a41SWanpeng Qian printf("%2X %-24s: max %u W, min %u W, ave %u W\n",
106*72170a41SWanpeng Qian *walker, name, le16dec(walker + 5), le16dec(walker + 7), le16dec(walker + 9));
107*72170a41SWanpeng Qian break;
108*72170a41SWanpeng Qian case 0xaf:
109*72170a41SWanpeng Qian printf("%2X %-24s:", *walker, name);
110*72170a41SWanpeng Qian if (normalized == 100)
111*72170a41SWanpeng Qian printf(" success");
112*72170a41SWanpeng Qian if (normalized == 0)
113*72170a41SWanpeng Qian printf(" failed");
114*72170a41SWanpeng Qian printf(" %3d\n", normalized);
115*72170a41SWanpeng Qian break;
116*72170a41SWanpeng Qian default:
117*72170a41SWanpeng Qian printf("%2X %-24s: %3d %ju\n",
118*72170a41SWanpeng Qian *walker, name, normalized, (uintmax_t)raw);
119*72170a41SWanpeng Qian break;
120*72170a41SWanpeng Qian }
121*72170a41SWanpeng Qian walker += 12;
122*72170a41SWanpeng Qian }
123*72170a41SWanpeng Qian }
124*72170a41SWanpeng Qian
125*72170a41SWanpeng Qian #define MICRON_LOG_UNIQUE_SMART 0xca
126*72170a41SWanpeng Qian
127*72170a41SWanpeng Qian NVME_LOGPAGE(micron_smart,
128*72170a41SWanpeng Qian MICRON_LOG_UNIQUE_SMART, "micron", "Vendor Unique SMART Information",
129*72170a41SWanpeng Qian print_micron_unique_smart, DEFAULT_SIZE);
130