184e86788SWanpeng Qian /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
384e86788SWanpeng Qian *
484e86788SWanpeng Qian * Copyright (C) 2022 Wanpeng Qian <wanpengqian@gmail.org>
584e86788SWanpeng Qian *
684e86788SWanpeng Qian * Redistribution and use in source and binary forms, with or without
784e86788SWanpeng Qian * modification, are permitted provided that the following conditions
884e86788SWanpeng Qian * are met:
984e86788SWanpeng Qian * 1. Redistributions of source code must retain the above copyright
1084e86788SWanpeng Qian * notice, this list of conditions and the following disclaimer.
1184e86788SWanpeng Qian * 2. Redistributions in binary form must reproduce the above copyright
1284e86788SWanpeng Qian * notice, this list of conditions and the following disclaimer in the
1384e86788SWanpeng Qian * documentation and/or other materials provided with the distribution.
1484e86788SWanpeng Qian *
1584e86788SWanpeng Qian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1684e86788SWanpeng Qian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1784e86788SWanpeng Qian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1884e86788SWanpeng Qian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1984e86788SWanpeng Qian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2084e86788SWanpeng Qian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2184e86788SWanpeng Qian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2284e86788SWanpeng Qian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2384e86788SWanpeng Qian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2484e86788SWanpeng Qian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2584e86788SWanpeng Qian * SUCH DAMAGE.
2684e86788SWanpeng Qian */
2784e86788SWanpeng Qian
2884e86788SWanpeng Qian #include <sys/param.h>
2984e86788SWanpeng Qian #include <sys/ioccom.h>
3084e86788SWanpeng Qian
3184e86788SWanpeng Qian #include <ctype.h>
3284e86788SWanpeng Qian #include <err.h>
3384e86788SWanpeng Qian #include <fcntl.h>
3484e86788SWanpeng Qian #include <stdbool.h>
3584e86788SWanpeng Qian #include <stddef.h>
3684e86788SWanpeng Qian #include <stdio.h>
3784e86788SWanpeng Qian #include <stdlib.h>
3884e86788SWanpeng Qian #include <string.h>
3984e86788SWanpeng Qian #include <unistd.h>
4084e86788SWanpeng Qian #include <sys/endian.h>
4184e86788SWanpeng Qian
4284e86788SWanpeng Qian #include "nvmecontrol.h"
4384e86788SWanpeng Qian
4484e86788SWanpeng Qian struct samsung_log_extended_smart
4584e86788SWanpeng Qian {
4684e86788SWanpeng Qian uint8_t kv[256];/* Key-Value pair */
4784e86788SWanpeng Qian uint32_t lwaf; /* Lifetime Write Amplification */
4884e86788SWanpeng Qian uint32_t thwaf; /* Trailing Hour Write Amplification Factor */
4984e86788SWanpeng Qian uint64_t luw[2]; /* Lifetime User Writes */
5084e86788SWanpeng Qian uint64_t lnw[2]; /* Lifetime NAND Writes */
5184e86788SWanpeng Qian uint64_t lur[2]; /* Lifetime User Reads */
5284e86788SWanpeng Qian uint32_t lrbc; /* Lifetime Retired Block Count */
5384e86788SWanpeng Qian uint16_t ct; /* Current Temperature */
5484e86788SWanpeng Qian uint16_t ch; /* Capacitor Health */
5584e86788SWanpeng Qian uint32_t luurb; /* Lifetime Unused Reserved Block */
5684e86788SWanpeng Qian uint64_t rrc; /* Read Reclaim Count */
5784e86788SWanpeng Qian uint64_t lueccc; /* Lifetime Uncorrectable ECC count */
5884e86788SWanpeng Qian uint32_t lurb; /* Lifetime Used Reserved Block */
5984e86788SWanpeng Qian uint64_t poh[2]; /* Power on Hours */
6084e86788SWanpeng Qian uint64_t npoc[2];/* Normal Power Off Count */
6184e86788SWanpeng Qian uint64_t spoc[2];/* Sudden Power Off Count */
6284e86788SWanpeng Qian uint32_t pi; /* Performance Indicator */
6384e86788SWanpeng Qian } __packed;
6484e86788SWanpeng Qian
6584e86788SWanpeng Qian static void
print_samsung_extended_smart(const struct nvme_controller_data * cdata __unused,void * buf,uint32_t size __unused)6684e86788SWanpeng Qian print_samsung_extended_smart(const struct nvme_controller_data *cdata __unused, void *buf, uint32_t size __unused)
6784e86788SWanpeng Qian {
6884e86788SWanpeng Qian struct samsung_log_extended_smart *temp = buf;
6984e86788SWanpeng Qian char cbuf[UINT128_DIG + 1];
7084e86788SWanpeng Qian uint8_t *walker = buf;
7184e86788SWanpeng Qian uint8_t *end = walker + 150;
7284e86788SWanpeng Qian const char *name;
7384e86788SWanpeng Qian uint64_t raw;
7484e86788SWanpeng Qian uint8_t normalized;
7584e86788SWanpeng Qian
7684e86788SWanpeng Qian static struct kv_name kv[] =
7784e86788SWanpeng Qian {
7884e86788SWanpeng Qian { 0xab, "Lifetime Program Fail Count" },
7984e86788SWanpeng Qian { 0xac, "Lifetime Erase Fail Count" },
8084e86788SWanpeng Qian { 0xad, "Lifetime Wear Leveling Count" },
8184e86788SWanpeng Qian { 0xb8, "Lifetime End to End Error Count" },
8284e86788SWanpeng Qian { 0xc7, "Lifetime CRC Error Count" },
8384e86788SWanpeng Qian { 0xe2, "Media Wear %" },
8484e86788SWanpeng Qian { 0xe3, "Host Read %" },
8584e86788SWanpeng Qian { 0xe4, "Workload Timer" },
8684e86788SWanpeng Qian { 0xea, "Lifetime Thermal Throttle Status" },
8784e86788SWanpeng Qian { 0xf4, "Lifetime Phy Pages Written Count" },
8884e86788SWanpeng Qian { 0xf5, "Lifetime Data Units Written" },
8984e86788SWanpeng Qian };
9084e86788SWanpeng Qian
9184e86788SWanpeng Qian printf("Extended SMART Information\n");
9284e86788SWanpeng Qian printf("=========================\n");
9384e86788SWanpeng Qian /*
9484e86788SWanpeng Qian * walker[0] = Key
9584e86788SWanpeng Qian * walker[1,2] = reserved
9684e86788SWanpeng Qian * walker[3] = Normalized Value
9784e86788SWanpeng Qian * walker[4] = reserved
9884e86788SWanpeng Qian * walker[5..10] = Little Endian Raw value
9984e86788SWanpeng Qian * (or other represenations)
10084e86788SWanpeng Qian * walker[11] = reserved
10184e86788SWanpeng Qian */
10284e86788SWanpeng Qian while (walker < end) {
10384e86788SWanpeng Qian name = kv_lookup(kv, nitems(kv), *walker);
10484e86788SWanpeng Qian normalized = walker[3];
10584e86788SWanpeng Qian raw = le48dec(walker + 5);
10684e86788SWanpeng Qian switch (*walker){
10784e86788SWanpeng Qian case 0:
10884e86788SWanpeng Qian break;
10984e86788SWanpeng Qian case 0xad:
11084e86788SWanpeng Qian printf("%2X %-41s: %3d min: %u max: %u ave: %u\n",
11184e86788SWanpeng Qian le16dec(walker), name, normalized,
11284e86788SWanpeng Qian le16dec(walker + 5), le16dec(walker + 7), le16dec(walker + 9));
11384e86788SWanpeng Qian break;
11484e86788SWanpeng Qian case 0xe2:
11584e86788SWanpeng Qian printf("%2X %-41s: %3d %.3f%%\n",
11684e86788SWanpeng Qian le16dec(walker), name, normalized,
11784e86788SWanpeng Qian raw / 1024.0);
11884e86788SWanpeng Qian break;
11984e86788SWanpeng Qian case 0xea:
12084e86788SWanpeng Qian printf("%2X %-41s: %3d %d%% %d times\n",
12184e86788SWanpeng Qian le16dec(walker), name, normalized,
12284e86788SWanpeng Qian walker[5], le32dec(walker+6));
12384e86788SWanpeng Qian break;
12484e86788SWanpeng Qian default:
12584e86788SWanpeng Qian printf("%2X %-41s: %3d %ju\n",
12684e86788SWanpeng Qian le16dec(walker), name, normalized,
12784e86788SWanpeng Qian (uintmax_t)raw);
12884e86788SWanpeng Qian break;
12984e86788SWanpeng Qian }
13084e86788SWanpeng Qian walker += 12;
13184e86788SWanpeng Qian }
13284e86788SWanpeng Qian
13384e86788SWanpeng Qian printf(" Lifetime Write Amplification Factor : %u\n", le32dec(&temp->lwaf));
13484e86788SWanpeng Qian printf(" Trailing Hour Write Amplification Factor : %u\n", le32dec(&temp->thwaf));
13584e86788SWanpeng Qian printf(" Lifetime User Writes : %s\n",
13684e86788SWanpeng Qian uint128_to_str(to128(temp->luw), cbuf, sizeof(cbuf)));
13784e86788SWanpeng Qian printf(" Lifetime NAND Writes : %s\n",
13884e86788SWanpeng Qian uint128_to_str(to128(temp->lnw), cbuf, sizeof(cbuf)));
13984e86788SWanpeng Qian printf(" Lifetime User Reads : %s\n",
14084e86788SWanpeng Qian uint128_to_str(to128(temp->lur), cbuf, sizeof(cbuf)));
14184e86788SWanpeng Qian printf(" Lifetime Retired Block Count : %u\n", le32dec(&temp->lrbc));
14284e86788SWanpeng Qian printf(" Current Temperature : ");
1433a194eacSWanpeng Qian print_temp_K(le16dec(&temp->ct));
14484e86788SWanpeng Qian printf(" Capacitor Health : %u\n", le16dec(&temp->ch));
14584e86788SWanpeng Qian printf(" Reserved Erase Block Count : %u\n", le32dec(&temp->luurb));
146142c3c7fSCy Schubert printf(" Read Reclaim Count : %ju\n", (uintmax_t) le64dec(&temp->rrc));
147142c3c7fSCy Schubert printf(" Lifetime Uncorrectable ECC Count : %ju\n", (uintmax_t) le64dec(&temp->lueccc));
14884e86788SWanpeng Qian printf(" Reallocated Block Count : %u\n", le32dec(&temp->lurb));
14984e86788SWanpeng Qian printf(" Power on Hours : %s\n",
15084e86788SWanpeng Qian uint128_to_str(to128(temp->poh), cbuf, sizeof(cbuf)));
15184e86788SWanpeng Qian printf(" Normal Power Off Count : %s\n",
15284e86788SWanpeng Qian uint128_to_str(to128(temp->npoc), cbuf, sizeof(cbuf)));
15384e86788SWanpeng Qian printf(" Sudden Power Off Count : %s\n",
15484e86788SWanpeng Qian uint128_to_str(to128(temp->spoc), cbuf, sizeof(cbuf)));
15584e86788SWanpeng Qian printf(" Performance Indicator : %u\n", le32dec(&temp->pi));
15684e86788SWanpeng Qian }
15784e86788SWanpeng Qian
15884e86788SWanpeng Qian #define SAMSUNG_LOG_EXTEND_SMART 0xca
15984e86788SWanpeng Qian
16084e86788SWanpeng Qian NVME_LOGPAGE(samsung_extended_smart,
16184e86788SWanpeng Qian SAMSUNG_LOG_EXTEND_SMART, "samsung", "Extended SMART Information",
16284e86788SWanpeng Qian print_samsung_extended_smart, DEFAULT_SIZE);
163