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 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