1eac8e827SWarner Losh /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 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/param.h> 33eac8e827SWarner Losh #include <sys/ioccom.h> 34eac8e827SWarner Losh 35eac8e827SWarner Losh #include <ctype.h> 36eac8e827SWarner Losh #include <err.h> 37eac8e827SWarner Losh #include <fcntl.h> 38eac8e827SWarner Losh #include <stdbool.h> 39eac8e827SWarner Losh #include <stddef.h> 40eac8e827SWarner Losh #include <stdio.h> 41eac8e827SWarner Losh #include <stdlib.h> 42eac8e827SWarner Losh #include <string.h> 43eac8e827SWarner Losh #include <unistd.h> 44eac8e827SWarner Losh #include <sys/endian.h> 45eac8e827SWarner Losh 46eac8e827SWarner Losh #include "nvmecontrol.h" 47eac8e827SWarner Losh 48eac8e827SWarner Losh /* 49eac8e827SWarner Losh * Intel specific log pages from 50eac8e827SWarner Losh * http://www.intel.com/content/dam/www/public/us/en/documents/product-specifications/ssd-dc-p3700-spec.pdf 51eac8e827SWarner Losh * 52eac8e827SWarner Losh * Though the version as of this date has a typo for the size of log page 0xca, 53eac8e827SWarner Losh * offset 147: it is only 1 byte, not 6. 54eac8e827SWarner Losh */ 55eac8e827SWarner Losh static void 56eac8e827SWarner Losh print_intel_temp_stats(const struct nvme_controller_data *cdata __unused, void *buf, uint32_t size __unused) 57eac8e827SWarner Losh { 58eac8e827SWarner Losh struct intel_log_temp_stats *temp = buf; 59eac8e827SWarner Losh 60eac8e827SWarner Losh printf("Intel Temperature Log\n"); 61eac8e827SWarner Losh printf("=====================\n"); 62eac8e827SWarner Losh 63eac8e827SWarner Losh printf("Current: "); 64*f0f7e961SWarner Losh print_temp_C(letoh(temp->current)); 65*f0f7e961SWarner Losh printf("Overtemp Last Flags %#jx\n", 66*f0f7e961SWarner Losh (uintmax_t)letoh(temp->overtemp_flag_last)); 67*f0f7e961SWarner Losh printf("Overtemp Lifetime Flags %#jx\n", 68*f0f7e961SWarner Losh (uintmax_t)letoh(temp->overtemp_flag_life)); 69eac8e827SWarner Losh printf("Max Temperature "); 70*f0f7e961SWarner Losh print_temp_C(letoh(temp->max_temp)); 71eac8e827SWarner Losh printf("Min Temperature "); 72*f0f7e961SWarner Losh print_temp_C(letoh(temp->min_temp)); 73eac8e827SWarner Losh printf("Max Operating Temperature "); 74*f0f7e961SWarner Losh print_temp_C(letoh(temp->max_oper_temp)); 75eac8e827SWarner Losh printf("Min Operating Temperature "); 76*f0f7e961SWarner Losh print_temp_C(letoh(temp->min_oper_temp)); 77*f0f7e961SWarner Losh printf("Estimated Temperature Offset: %ju C/K\n", 78*f0f7e961SWarner Losh (uintmax_t)letoh(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 */ 122e4aa091bSWarner 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