xref: /freebsd/sbin/nvmecontrol/modules/intel/intel.c (revision e4aa091bd16f02a41eaaaafe32fc169375706238)
1eac8e827SWarner Losh /*-
2eac8e827SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3eac8e827SWarner Losh  *
4eac8e827SWarner Losh  * Copyright (c) 2013 EMC Corp.
5eac8e827SWarner Losh  * All rights reserved.
6eac8e827SWarner Losh  *
7eac8e827SWarner Losh  * Copyright (C) 2012-2013 Intel Corporation
8eac8e827SWarner Losh  * All rights reserved.
9eac8e827SWarner Losh  *
10eac8e827SWarner Losh  * Redistribution and use in source and binary forms, with or without
11eac8e827SWarner Losh  * modification, are permitted provided that the following conditions
12eac8e827SWarner Losh  * are met:
13eac8e827SWarner Losh  * 1. Redistributions of source code must retain the above copyright
14eac8e827SWarner Losh  *    notice, this list of conditions and the following disclaimer.
15eac8e827SWarner Losh  * 2. Redistributions in binary form must reproduce the above copyright
16eac8e827SWarner Losh  *    notice, this list of conditions and the following disclaimer in the
17eac8e827SWarner Losh  *    documentation and/or other materials provided with the distribution.
18eac8e827SWarner Losh  *
19eac8e827SWarner Losh  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20eac8e827SWarner Losh  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21eac8e827SWarner Losh  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22eac8e827SWarner Losh  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23eac8e827SWarner Losh  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24eac8e827SWarner Losh  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25eac8e827SWarner Losh  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26eac8e827SWarner Losh  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27eac8e827SWarner Losh  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28eac8e827SWarner Losh  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29eac8e827SWarner Losh  * SUCH DAMAGE.
30eac8e827SWarner Losh  */
31eac8e827SWarner Losh 
32eac8e827SWarner Losh #include <sys/cdefs.h>
33eac8e827SWarner Losh __FBSDID("$FreeBSD$");
34eac8e827SWarner Losh 
35eac8e827SWarner Losh #include <sys/param.h>
36eac8e827SWarner Losh #include <sys/ioccom.h>
37eac8e827SWarner Losh 
38eac8e827SWarner Losh #include <ctype.h>
39eac8e827SWarner Losh #include <err.h>
40eac8e827SWarner Losh #include <fcntl.h>
41eac8e827SWarner Losh #include <stdbool.h>
42eac8e827SWarner Losh #include <stddef.h>
43eac8e827SWarner Losh #include <stdio.h>
44eac8e827SWarner Losh #include <stdlib.h>
45eac8e827SWarner Losh #include <string.h>
46eac8e827SWarner Losh #include <unistd.h>
47eac8e827SWarner Losh #include <sys/endian.h>
48eac8e827SWarner Losh 
49eac8e827SWarner Losh #include "nvmecontrol.h"
50eac8e827SWarner Losh 
51eac8e827SWarner Losh /*
52eac8e827SWarner Losh  * Intel specific log pages from
53eac8e827SWarner Losh  * http://www.intel.com/content/dam/www/public/us/en/documents/product-specifications/ssd-dc-p3700-spec.pdf
54eac8e827SWarner Losh  *
55eac8e827SWarner Losh  * Though the version as of this date has a typo for the size of log page 0xca,
56eac8e827SWarner Losh  * offset 147: it is only 1 byte, not 6.
57eac8e827SWarner Losh  */
58eac8e827SWarner Losh static void
59eac8e827SWarner Losh print_intel_temp_stats(const struct nvme_controller_data *cdata __unused, void *buf, uint32_t size __unused)
60eac8e827SWarner Losh {
61eac8e827SWarner Losh 	struct intel_log_temp_stats	*temp = buf;
62eac8e827SWarner Losh 
63eac8e827SWarner Losh 	printf("Intel Temperature Log\n");
64eac8e827SWarner Losh 	printf("=====================\n");
65eac8e827SWarner Losh 
66eac8e827SWarner Losh 	printf("Current:                        ");
67eac8e827SWarner Losh 	print_temp(temp->current);
68eac8e827SWarner Losh 	printf("Overtemp Last Flags             %#jx\n", (uintmax_t)temp->overtemp_flag_last);
69eac8e827SWarner Losh 	printf("Overtemp Lifetime Flags         %#jx\n", (uintmax_t)temp->overtemp_flag_life);
70eac8e827SWarner Losh 	printf("Max Temperature                 ");
71eac8e827SWarner Losh 	print_temp(temp->max_temp);
72eac8e827SWarner Losh 	printf("Min Temperature                 ");
73eac8e827SWarner Losh 	print_temp(temp->min_temp);
74eac8e827SWarner Losh 	printf("Max Operating Temperature       ");
75eac8e827SWarner Losh 	print_temp(temp->max_oper_temp);
76eac8e827SWarner Losh 	printf("Min Operating Temperature       ");
77eac8e827SWarner Losh 	print_temp(temp->min_oper_temp);
78eac8e827SWarner Losh 	printf("Estimated Temperature Offset:   %ju C/K\n", (uintmax_t)temp->est_offset);
79eac8e827SWarner Losh }
80eac8e827SWarner Losh 
81eac8e827SWarner Losh /*
82eac8e827SWarner Losh  * Format from Table 22, section 5.7 IO Command Latency Statistics.
83eac8e827SWarner Losh  * Read and write stats pages have identical encoding.
84eac8e827SWarner Losh  */
85eac8e827SWarner Losh static void
86eac8e827SWarner Losh print_intel_read_write_lat_log(const struct nvme_controller_data *cdata __unused, void *buf, uint32_t size __unused)
87eac8e827SWarner Losh {
88eac8e827SWarner Losh 	const char *walker = buf;
89eac8e827SWarner Losh 	int i;
90eac8e827SWarner Losh 
91eac8e827SWarner Losh 	printf("Major:                         %d\n", le16dec(walker + 0));
92eac8e827SWarner Losh 	printf("Minor:                         %d\n", le16dec(walker + 2));
93eac8e827SWarner Losh 	for (i = 0; i < 32; i++)
94eac8e827SWarner Losh 		printf("%4dus-%4dus:                 %ju\n", i * 32, (i + 1) * 32, (uintmax_t)le32dec(walker + 4 + i * 4));
95eac8e827SWarner Losh 	for (i = 1; i < 32; i++)
96eac8e827SWarner Losh 		printf("%4dms-%4dms:                 %ju\n", i, i + 1, (uintmax_t)le32dec(walker + 132 + i * 4));
97eac8e827SWarner Losh 	for (i = 1; i < 32; i++)
98eac8e827SWarner Losh 		printf("%4dms-%4dms:                 %ju\n", i * 32, (i + 1) * 32, (uintmax_t)le32dec(walker + 256 + i * 4));
99eac8e827SWarner Losh }
100eac8e827SWarner Losh 
101eac8e827SWarner Losh static void
102eac8e827SWarner Losh print_intel_read_lat_log(const struct nvme_controller_data *cdata __unused, void *buf, uint32_t size)
103eac8e827SWarner Losh {
104eac8e827SWarner Losh 
105eac8e827SWarner Losh 	printf("Intel Read Latency Log\n");
106eac8e827SWarner Losh 	printf("======================\n");
107eac8e827SWarner Losh 	print_intel_read_write_lat_log(cdata, buf, size);
108eac8e827SWarner Losh }
109eac8e827SWarner Losh 
110eac8e827SWarner Losh static void
111eac8e827SWarner Losh print_intel_write_lat_log(const struct nvme_controller_data *cdata __unused, void *buf, uint32_t size)
112eac8e827SWarner Losh {
113eac8e827SWarner Losh 
114eac8e827SWarner Losh 	printf("Intel Write Latency Log\n");
115eac8e827SWarner Losh 	printf("=======================\n");
116eac8e827SWarner Losh 	print_intel_read_write_lat_log(cdata, buf, size);
117eac8e827SWarner Losh }
118eac8e827SWarner Losh 
119eac8e827SWarner Losh /*
12087754599SWarner Losh  * Table 19. 5.4 SMART Attributes. Others also implement this and some extra data not documented.
121eac8e827SWarner Losh  */
122*e4aa091bSWarner Losh void
123eac8e827SWarner Losh print_intel_add_smart(const struct nvme_controller_data *cdata __unused, void *buf, uint32_t size __unused)
124eac8e827SWarner Losh {
125eac8e827SWarner Losh 	uint8_t *walker = buf;
126eac8e827SWarner Losh 	uint8_t *end = walker + 150;
127eac8e827SWarner Losh 	const char *name;
128eac8e827SWarner Losh 	uint64_t raw;
129eac8e827SWarner Losh 	uint8_t normalized;
130eac8e827SWarner Losh 
131eac8e827SWarner Losh 	static struct kv_name kv[] =
132eac8e827SWarner Losh 	{
133eac8e827SWarner Losh 		{ 0xab, "Program Fail Count" },
134eac8e827SWarner Losh 		{ 0xac, "Erase Fail Count" },
135eac8e827SWarner Losh 		{ 0xad, "Wear Leveling Count" },
136eac8e827SWarner Losh 		{ 0xb8, "End to End Error Count" },
137eac8e827SWarner Losh 		{ 0xc7, "CRC Error Count" },
138eac8e827SWarner Losh 		{ 0xe2, "Timed: Media Wear" },
139eac8e827SWarner Losh 		{ 0xe3, "Timed: Host Read %" },
140eac8e827SWarner Losh 		{ 0xe4, "Timed: Elapsed Time" },
141eac8e827SWarner Losh 		{ 0xea, "Thermal Throttle Status" },
142eac8e827SWarner Losh 		{ 0xf0, "Retry Buffer Overflows" },
143eac8e827SWarner Losh 		{ 0xf3, "PLL Lock Loss Count" },
144eac8e827SWarner Losh 		{ 0xf4, "NAND Bytes Written" },
145eac8e827SWarner Losh 		{ 0xf5, "Host Bytes Written" },
146eac8e827SWarner Losh 	};
147eac8e827SWarner Losh 
148eac8e827SWarner Losh 	printf("Additional SMART Data Log\n");
149eac8e827SWarner Losh 	printf("=========================\n");
150eac8e827SWarner Losh 	/*
151eac8e827SWarner Losh 	 * walker[0] = Key
152eac8e827SWarner Losh 	 * walker[1,2] = reserved
153eac8e827SWarner Losh 	 * walker[3] = Normalized Value
154eac8e827SWarner Losh 	 * walker[4] = reserved
155eac8e827SWarner Losh 	 * walker[5..10] = Little Endian Raw value
156eac8e827SWarner Losh 	 *	(or other represenations)
157eac8e827SWarner Losh 	 * walker[11] = reserved
158eac8e827SWarner Losh 	 */
159eac8e827SWarner Losh 	while (walker < end) {
160eac8e827SWarner Losh 		name = kv_lookup(kv, nitems(kv), *walker);
161eac8e827SWarner Losh 		normalized = walker[3];
162eac8e827SWarner Losh 		raw = le48dec(walker + 5);
163eac8e827SWarner Losh 		switch (*walker){
164eac8e827SWarner Losh 		case 0:
165eac8e827SWarner Losh 			break;
166eac8e827SWarner Losh 		case 0xad:
167eac8e827SWarner Losh 			printf("%-32s: %3d min: %u max: %u ave: %u\n", name, normalized,
168eac8e827SWarner Losh 			    le16dec(walker + 5), le16dec(walker + 7), le16dec(walker + 9));
169eac8e827SWarner Losh 			break;
170eac8e827SWarner Losh 		case 0xe2:
171eac8e827SWarner Losh 			printf("%-32s: %3d %.3f%%\n", name, normalized, raw / 1024.0);
172eac8e827SWarner Losh 			break;
173eac8e827SWarner Losh 		case 0xea:
174eac8e827SWarner Losh 			printf("%-32s: %3d %d%% %d times\n", name, normalized, walker[5], le32dec(walker+6));
175eac8e827SWarner Losh 			break;
176eac8e827SWarner Losh 		default:
177eac8e827SWarner Losh 			printf("%-32s: %3d %ju\n", name, normalized, (uintmax_t)raw);
178eac8e827SWarner Losh 			break;
179eac8e827SWarner Losh 		}
180eac8e827SWarner Losh 		walker += 12;
181eac8e827SWarner Losh 	}
182eac8e827SWarner Losh }
183eac8e827SWarner Losh 
184eac8e827SWarner Losh NVME_LOGPAGE(intel_temp,
185eac8e827SWarner Losh     INTEL_LOG_TEMP_STATS,		"intel", "Temperature Stats",
186eac8e827SWarner Losh     print_intel_temp_stats,		sizeof(struct intel_log_temp_stats));
187eac8e827SWarner Losh NVME_LOGPAGE(intel_rlat,
188eac8e827SWarner Losh     INTEL_LOG_READ_LAT_LOG,		"intel", "Read Latencies",
189eac8e827SWarner Losh     print_intel_read_lat_log,		DEFAULT_SIZE);
190eac8e827SWarner Losh NVME_LOGPAGE(intel_wlat,
191eac8e827SWarner Losh     INTEL_LOG_WRITE_LAT_LOG,		"intel", "Write Latencies",
192eac8e827SWarner Losh     print_intel_write_lat_log,		DEFAULT_SIZE);
193eac8e827SWarner Losh NVME_LOGPAGE(intel_smart,
194eac8e827SWarner Losh     INTEL_LOG_ADD_SMART,		"intel", "Extra Health/SMART Data",
195eac8e827SWarner Losh     print_intel_add_smart,		DEFAULT_SIZE);
196