diff --git a/sbin/nvmecontrol/modules/Makefile b/sbin/nvmecontrol/modules/Makefile --- a/sbin/nvmecontrol/modules/Makefile +++ b/sbin/nvmecontrol/modules/Makefile @@ -1,5 +1,5 @@ # $FreeBSD$ -SUBDIR= intel wdc +SUBDIR= intel wdc samsung .include diff --git a/sbin/nvmecontrol/modules/samsung/Makefile b/sbin/nvmecontrol/modules/samsung/Makefile new file mode 100644 --- /dev/null +++ b/sbin/nvmecontrol/modules/samsung/Makefile @@ -0,0 +1,6 @@ +# $FreeBSD$ + +LIB= samsung +SRCS= samsung.c + +.include diff --git a/sbin/nvmecontrol/modules/samsung/samsung.c b/sbin/nvmecontrol/modules/samsung/samsung.c new file mode 100644 --- /dev/null +++ b/sbin/nvmecontrol/modules/samsung/samsung.c @@ -0,0 +1,165 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (C) 2022 Wanpeng Qian + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nvmecontrol.h" + +struct samsung_log_extended_smart +{ + uint8_t kv[256];/* Key-Value pair */ + uint32_t lwaf; /* Lifetime Write Amplification */ + uint32_t thwaf; /* Trailing Hour Write Amplification Factor */ + uint64_t luw[2]; /* Lifetime User Writes */ + uint64_t lnw[2]; /* Lifetime NAND Writes */ + uint64_t lur[2]; /* Lifetime User Reads */ + uint32_t lrbc; /* Lifetime Retired Block Count */ + uint16_t ct; /* Current Temperature */ + uint16_t ch; /* Capacitor Health */ + uint32_t luurb; /* Lifetime Unused Reserved Block */ + uint64_t rrc; /* Read Reclaim Count */ + uint64_t lueccc; /* Lifetime Uncorrectable ECC count */ + uint32_t lurb; /* Lifetime Used Reserved Block */ + uint64_t poh[2]; /* Power on Hours */ + uint64_t npoc[2];/* Normal Power Off Count */ + uint64_t spoc[2];/* Sudden Power Off Count */ + uint32_t pi; /* Performance Indicator */ +} __packed; + +static void +print_samsung_extended_smart(const struct nvme_controller_data *cdata __unused, void *buf, uint32_t size __unused) +{ + struct samsung_log_extended_smart *temp = buf; + char cbuf[UINT128_DIG + 1]; + uint8_t *walker = buf; + uint8_t *end = walker + 150; + const char *name; + uint64_t raw; + uint8_t normalized; + + static struct kv_name kv[] = + { + { 0xab, "Lifetime Program Fail Count" }, + { 0xac, "Lifetime Erase Fail Count" }, + { 0xad, "Lifetime Wear Leveling Count" }, + { 0xb8, "Lifetime End to End Error Count" }, + { 0xc7, "Lifetime CRC Error Count" }, + { 0xe2, "Media Wear %" }, + { 0xe3, "Host Read %" }, + { 0xe4, "Workload Timer" }, + { 0xea, "Lifetime Thermal Throttle Status" }, + { 0xf4, "Lifetime Phy Pages Written Count" }, + { 0xf5, "Lifetime Data Units Written" }, + }; + + printf("Extended SMART Information\n"); + printf("=========================\n"); + /* + * walker[0] = Key + * walker[1,2] = reserved + * walker[3] = Normalized Value + * walker[4] = reserved + * walker[5..10] = Little Endian Raw value + * (or other represenations) + * walker[11] = reserved + */ + while (walker < end) { + name = kv_lookup(kv, nitems(kv), *walker); + normalized = walker[3]; + raw = le48dec(walker + 5); + switch (*walker){ + case 0: + break; + case 0xad: + printf("%2X %-41s: %3d min: %u max: %u ave: %u\n", + le16dec(walker), name, normalized, + le16dec(walker + 5), le16dec(walker + 7), le16dec(walker + 9)); + break; + case 0xe2: + printf("%2X %-41s: %3d %.3f%%\n", + le16dec(walker), name, normalized, + raw / 1024.0); + break; + case 0xea: + printf("%2X %-41s: %3d %d%% %d times\n", + le16dec(walker), name, normalized, + walker[5], le32dec(walker+6)); + break; + default: + printf("%2X %-41s: %3d %ju\n", + le16dec(walker), name, normalized, + (uintmax_t)raw); + break; + } + walker += 12; + } + + printf(" Lifetime Write Amplification Factor : %u\n", le32dec(&temp->lwaf)); + printf(" Trailing Hour Write Amplification Factor : %u\n", le32dec(&temp->thwaf)); + printf(" Lifetime User Writes : %s\n", + uint128_to_str(to128(temp->luw), cbuf, sizeof(cbuf))); + printf(" Lifetime NAND Writes : %s\n", + uint128_to_str(to128(temp->lnw), cbuf, sizeof(cbuf))); + printf(" Lifetime User Reads : %s\n", + uint128_to_str(to128(temp->lur), cbuf, sizeof(cbuf))); + printf(" Lifetime Retired Block Count : %u\n", le32dec(&temp->lrbc)); + printf(" Current Temperature : "); + print_temp(le16dec(&temp->ct)); + printf(" Capacitor Health : %u\n", le16dec(&temp->ch)); + printf(" Reserved Erase Block Count : %u\n", le32dec(&temp->luurb)); + printf(" Read Reclaim Count : %lu\n", le64dec(&temp->rrc)); + printf(" Lifetime Uncorrectable ECC Count : %lu\n", le64dec(&temp->lueccc)); + printf(" Reallocated Block Count : %u\n", le32dec(&temp->lurb)); + printf(" Power on Hours : %s\n", + uint128_to_str(to128(temp->poh), cbuf, sizeof(cbuf))); + printf(" Normal Power Off Count : %s\n", + uint128_to_str(to128(temp->npoc), cbuf, sizeof(cbuf))); + printf(" Sudden Power Off Count : %s\n", + uint128_to_str(to128(temp->spoc), cbuf, sizeof(cbuf))); + printf(" Performance Indicator : %u\n", le32dec(&temp->pi)); +} + +#define SAMSUNG_LOG_EXTEND_SMART 0xca + +NVME_LOGPAGE(samsung_extended_smart, + SAMSUNG_LOG_EXTEND_SMART, "samsung", "Extended SMART Information", + print_samsung_extended_smart, DEFAULT_SIZE); diff --git a/sbin/nvmecontrol/nvmecontrol.8 b/sbin/nvmecontrol/nvmecontrol.8 --- a/sbin/nvmecontrol/nvmecontrol.8 +++ b/sbin/nvmecontrol/nvmecontrol.8 @@ -244,7 +244,7 @@ .El .Ss logpage The logpage command knows how to print log pages of various types. -It also knows about vendor specific log pages from hgst/wdc and intel. +It also knows about vendor specific log pages from hgst/wdc, samsung and intel. Note that some vendors use the same log page numbers for different data. .Pp .Bl -tag -compact -width "Page 0x00" @@ -274,6 +274,8 @@ Temperature stats (Intel) .It Dv Page 0xca Advanced SMART information (Intel) +.It Dv Page 0xca +Extended SMART information (Samsung) .El .Pp Specifying