nvmecontrol: Add Samsung Extended SMART Information logpage support

Samsung PM983 SSD has a 0xca logpage. It has more information compared
to Intel's this patch tested on PM983 M2 SSD and works as expected.

Reviewed by:		imp@
Approved by:		kp@
Event:			Aberdeen Hackathon 2022
Differential revision:	https://reviews.freebsd.org/D33749
This commit is contained in:
Wanpeng Qian 2022-10-06 10:10:06 +00:00 committed by Benedict Reuschling
parent 4cb3cb2de2
commit 84e8678870
4 changed files with 175 additions and 2 deletions

View File

@ -1,5 +1,5 @@
# $FreeBSD$ # $FreeBSD$
SUBDIR= intel wdc SUBDIR= intel wdc samsung
.include <bsd.subdir.mk> .include <bsd.subdir.mk>

View File

@ -0,0 +1,6 @@
# $FreeBSD$
LIB= samsung
SRCS= samsung.c
.include <bsd.lib.mk>

View File

@ -0,0 +1,165 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (C) 2022 Wanpeng Qian <wanpengqian@gmail.org>
*
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/ioccom.h>
#include <ctype.h>
#include <err.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/endian.h>
#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);

View File

@ -244,7 +244,7 @@ data associated with that drive.
.El .El
.Ss logpage .Ss logpage
The logpage command knows how to print log pages of various types. 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. Note that some vendors use the same log page numbers for different data.
.Pp .Pp
.Bl -tag -compact -width "Page 0x00" .Bl -tag -compact -width "Page 0x00"
@ -274,6 +274,8 @@ Wite latency stats (Intel)
Temperature stats (Intel) Temperature stats (Intel)
.It Dv Page 0xca .It Dv Page 0xca
Advanced SMART information (Intel) Advanced SMART information (Intel)
.It Dv Page 0xca
Extended SMART information (Samsung)
.El .El
.Pp .Pp
Specifying Specifying