2025-02-16 12:16:19 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2025-02-16 11:09:01 +01:00
|
|
|
/*
|
|
|
|
* Do NOT modify or remove this copyright and license
|
|
|
|
*
|
|
|
|
* Copyright (c) 2017-2018 Seagate Technology LLC and/or its Affiliates, All Rights Reserved
|
|
|
|
*
|
|
|
|
* ******************************************************************************************
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* \file seagate-nvme.c
|
|
|
|
* \brief This file defines the functions and macros to make building a nvme-cli seagate plug-in.
|
2025-02-16 12:18:36 +01:00
|
|
|
*
|
|
|
|
* Author: Debabrata Bardhan <debabrata.bardhan@seagate.com>
|
2025-02-16 11:09:01 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2025-02-16 12:18:36 +01:00
|
|
|
#include <string.h>
|
2025-02-16 11:09:01 +01:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <ctype.h>
|
2025-02-16 12:15:45 +01:00
|
|
|
#include "common.h"
|
2025-02-16 11:09:01 +01:00
|
|
|
#include "nvme.h"
|
2025-02-16 12:15:45 +01:00
|
|
|
#include "libnvme.h"
|
2025-02-16 11:09:01 +01:00
|
|
|
#include "plugin.h"
|
2025-02-16 12:15:45 +01:00
|
|
|
#include "linux/types.h"
|
|
|
|
#include "nvme-print.h"
|
2025-02-16 12:18:36 +01:00
|
|
|
#include <time.h>
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
#define CREATE_CMD
|
|
|
|
|
|
|
|
#include "seagate-nvme.h"
|
|
|
|
#include "seagate-diag.h"
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************
|
2025-02-16 12:18:36 +01:00
|
|
|
* Command for "log-pages-supp"
|
|
|
|
***************************************/
|
2025-02-16 11:09:01 +01:00
|
|
|
static char *log_pages_supp_print(__u32 pageID)
|
|
|
|
{
|
2025-02-16 12:18:36 +01:00
|
|
|
switch (pageID) {
|
2025-02-16 11:09:01 +01:00
|
|
|
case 0x01:
|
|
|
|
return "ERROR_INFORMATION";
|
|
|
|
break;
|
|
|
|
case 0x02:
|
|
|
|
return "SMART_INFORMATION";
|
|
|
|
break;
|
|
|
|
case 0x03:
|
|
|
|
return "FW_SLOT_INFORMATION";
|
|
|
|
break;
|
|
|
|
case 0x04:
|
|
|
|
return "CHANGED_NAMESPACE_LIST";
|
|
|
|
break;
|
|
|
|
case 0x05:
|
|
|
|
return "COMMANDS_SUPPORTED_AND_EFFECTS";
|
|
|
|
break;
|
|
|
|
case 0x06:
|
|
|
|
return "DEVICE_SELF_TEST";
|
|
|
|
break;
|
|
|
|
case 0x07:
|
|
|
|
return "TELEMETRY_HOST_INITIATED";
|
|
|
|
break;
|
|
|
|
case 0x08:
|
|
|
|
return "TELEMETRY_CONTROLLER_INITIATED";
|
|
|
|
break;
|
|
|
|
case 0xC0:
|
|
|
|
return "VS_MEDIA_SMART_LOG";
|
|
|
|
break;
|
|
|
|
case 0xC1:
|
|
|
|
return "VS_DEBUG_LOG1";
|
|
|
|
break;
|
|
|
|
case 0xC2:
|
|
|
|
return "VS_SEC_ERROR_LOG_PAGE";
|
|
|
|
break;
|
|
|
|
case 0xC3:
|
|
|
|
return "VS_LIFE_TIME_DRIVE_HISTORY";
|
|
|
|
break;
|
|
|
|
case 0xC4:
|
|
|
|
return "VS_EXTENDED_SMART_INFO";
|
|
|
|
break;
|
|
|
|
case 0xC5:
|
|
|
|
return "VS_LIST_SUPPORTED_LOG_PAGE";
|
|
|
|
break;
|
|
|
|
case 0xC6:
|
|
|
|
return "VS_POWER_MONITOR_LOG_PAGE";
|
|
|
|
break;
|
|
|
|
case 0xC7:
|
|
|
|
return "VS_CRITICAL_EVENT_LOG_PAGE";
|
|
|
|
break;
|
|
|
|
case 0xC8:
|
|
|
|
return "VS_RECENT_DRIVE_HISTORY";
|
|
|
|
break;
|
|
|
|
case 0xC9:
|
|
|
|
return "VS_SEC_ERROR_LOG_PAGE";
|
|
|
|
break;
|
|
|
|
case 0xCA:
|
|
|
|
return "VS_LIFE_TIME_DRIVE_HISTORY";
|
|
|
|
break;
|
|
|
|
case 0xCB:
|
|
|
|
return "VS_PCIE_ERROR_LOG_PAGE";
|
|
|
|
break;
|
|
|
|
case 0xCF:
|
|
|
|
return "DRAM Supercap SMART Attributes";
|
|
|
|
break;
|
|
|
|
case 0xD6:
|
|
|
|
return "VS_OEM2_WORK_LOAD";
|
|
|
|
break;
|
|
|
|
case 0xD7:
|
|
|
|
return "VS_OEM2_FW_SECURITY";
|
|
|
|
break;
|
|
|
|
case 0xD8:
|
|
|
|
return "VS_OEM2_REVISION";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return "UNKNOWN";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
static int stx_is_jag_pan(char *devMN)
|
|
|
|
{
|
|
|
|
int match_found = 1; /* found = 0, not_found = 1 */
|
|
|
|
|
|
|
|
for (int i = 0; i < STX_NUM_LEGACY_DRV; i++) {
|
|
|
|
match_found = strncmp(devMN, stx_jag_pan_mn[i], strlen(stx_jag_pan_mn[i]));
|
|
|
|
if (match_found == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return match_found;
|
|
|
|
}
|
|
|
|
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
static void json_log_pages_supp(log_page_map *logPageMap)
|
|
|
|
{
|
|
|
|
struct json_object *root;
|
2025-02-16 11:31:10 +01:00
|
|
|
struct json_object *logPages;
|
2025-02-16 11:09:01 +01:00
|
|
|
__u32 i = 0;
|
|
|
|
|
|
|
|
root = json_create_object();
|
|
|
|
logPages = json_create_array();
|
|
|
|
json_object_add_value_array(root, "supported_log_pages", logPages);
|
|
|
|
|
|
|
|
for (i = 0; i < le32_to_cpu(logPageMap->NumLogPages); i++) {
|
|
|
|
struct json_object *lbaf = json_create_object();
|
|
|
|
json_object_add_value_int(lbaf, "logpage_id",
|
|
|
|
le32_to_cpu(logPageMap->LogPageEntry[i].LogPageID));
|
|
|
|
json_object_add_value_string(lbaf, "logpage_name",
|
|
|
|
log_pages_supp_print(le32_to_cpu(logPageMap->LogPageEntry[i].LogPageID)));
|
|
|
|
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
}
|
|
|
|
json_print_object(root, NULL);
|
2025-02-16 12:16:19 +01:00
|
|
|
json_free_object(root);
|
2025-02-16 11:09:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int log_pages_supp(int argc, char **argv, struct command *cmd,
|
2025-02-16 12:18:36 +01:00
|
|
|
struct plugin *plugin)
|
2025-02-16 11:09:01 +01:00
|
|
|
{
|
|
|
|
int err = 0;
|
|
|
|
__u32 i = 0;
|
|
|
|
log_page_map logPageMap;
|
|
|
|
const char *desc = "Retrieve Seagate Supported Log-Page information for the given device ";
|
|
|
|
const char *output_format = "output in binary format";
|
2025-02-16 12:18:36 +01:00
|
|
|
struct nvme_dev *dev;
|
2025-02-16 11:09:01 +01:00
|
|
|
int fmt;
|
|
|
|
|
|
|
|
struct config {
|
|
|
|
char *output_format;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct config cfg = {
|
|
|
|
.output_format = "normal",
|
|
|
|
};
|
|
|
|
|
|
|
|
OPT_ARGS(opts) = {
|
|
|
|
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
|
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
err = parse_and_open(&dev, argc, argv, desc, opts);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
err = nvme_get_log_simple(dev_fd(dev), 0xc5,
|
|
|
|
sizeof(logPageMap), &logPageMap);
|
2025-02-16 11:09:01 +01:00
|
|
|
if (!err) {
|
2025-02-16 12:18:36 +01:00
|
|
|
if (strcmp(cfg.output_format, "json")) {
|
2025-02-16 11:09:01 +01:00
|
|
|
printf ("Seagate Supported Log-pages count :%d\n",
|
|
|
|
le32_to_cpu(logPageMap.NumLogPages));
|
|
|
|
printf ("%-15s %-30s\n", "LogPage-Id", "LogPage-Name");
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
for (fmt = 0; fmt < 45; fmt++)
|
|
|
|
printf("-");
|
2025-02-16 11:09:01 +01:00
|
|
|
printf("\n");
|
|
|
|
} else
|
|
|
|
json_log_pages_supp(&logPageMap);
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
for (i = 0; i < le32_to_cpu(logPageMap.NumLogPages); i++) {
|
|
|
|
if (strcmp(cfg.output_format, "json")) {
|
2025-02-16 11:09:01 +01:00
|
|
|
printf("0x%-15X",
|
2025-02-16 12:18:36 +01:00
|
|
|
le32_to_cpu(logPageMap.LogPageEntry[i].LogPageID));
|
2025-02-16 11:09:01 +01:00
|
|
|
printf("%-30s\n",
|
2025-02-16 12:18:36 +01:00
|
|
|
log_pages_supp_print(le32_to_cpu(logPageMap.LogPageEntry[i].LogPageID)));
|
2025-02-16 11:09:01 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err > 0)
|
2025-02-16 12:15:45 +01:00
|
|
|
nvme_show_status(err);
|
2025-02-16 12:18:36 +01:00
|
|
|
dev_close(dev);
|
2025-02-16 11:09:01 +01:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* EOF Command for "log-pages-supp" */
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************
|
|
|
|
* Extended-SMART Information
|
|
|
|
***************************************/
|
|
|
|
static char *print_ext_smart_id(__u8 attrId)
|
|
|
|
{
|
2025-02-16 12:18:36 +01:00
|
|
|
switch (attrId) {
|
2025-02-16 11:09:01 +01:00
|
|
|
case VS_ATTR_ID_SOFT_READ_ERROR_RATE:
|
|
|
|
return "Soft ECC error count";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_REALLOCATED_SECTOR_COUNT:
|
|
|
|
return "Bad NAND block count";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_POWER_ON_HOURS:
|
|
|
|
return "Power On Hours";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_POWER_FAIL_EVENT_COUNT:
|
|
|
|
return "Power Fail Event Count";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_DEVICE_POWER_CYCLE_COUNT:
|
|
|
|
return "Device Power Cycle Count";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_RAW_READ_ERROR_RATE:
|
|
|
|
return "Raw Read Error Count";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_GROWN_BAD_BLOCK_COUNT:
|
|
|
|
return "Bad NAND block count";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_END_2_END_CORRECTION_COUNT:
|
|
|
|
return "SSD End to end correction counts";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_MIN_MAX_WEAR_RANGE_COUNT:
|
|
|
|
return "User data erase counts";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_REFRESH_COUNT:
|
|
|
|
return "Refresh count";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_BAD_BLOCK_COUNT_USER:
|
|
|
|
return "User data erase fail count";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_BAD_BLOCK_COUNT_SYSTEM:
|
|
|
|
return "System area erase fail count";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_THERMAL_THROTTLING_STATUS:
|
|
|
|
return "Thermal throttling status and count";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_ALL_PCIE_CORRECTABLE_ERROR_COUNT:
|
|
|
|
return "PCIe Correctable Error count";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_ALL_PCIE_UNCORRECTABLE_ERROR_COUNT:
|
|
|
|
return "PCIe Uncorrectable Error count";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_INCOMPLETE_SHUTDOWN_COUNT:
|
|
|
|
return "Incomplete shutdowns";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_GB_ERASED_LSB:
|
|
|
|
return "LSB of Flash GB erased";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_GB_ERASED_MSB:
|
|
|
|
return "MSB of Flash GB erased";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_LIFETIME_DEVSLEEP_EXIT_COUNT:
|
|
|
|
return "LIFETIME_DEV_SLEEP_EXIT_COUNT";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_LIFETIME_ENTERING_PS4_COUNT:
|
|
|
|
return "LIFETIME_ENTERING_PS4_COUNT";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_LIFETIME_ENTERING_PS3_COUNT:
|
|
|
|
return "LIFETIME_ENTERING_PS3_COUNT";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_RETIRED_BLOCK_COUNT:
|
2025-02-16 12:18:36 +01:00
|
|
|
return "Retired block count";
|
2025-02-16 11:09:01 +01:00
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_PROGRAM_FAILURE_COUNT:
|
|
|
|
return "Program fail count";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_ERASE_FAIL_COUNT:
|
|
|
|
return "Erase Fail Count";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_AVG_ERASE_COUNT:
|
|
|
|
return "System data % used";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_UNEXPECTED_POWER_LOSS_COUNT:
|
|
|
|
return "Unexpected power loss count";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_WEAR_RANGE_DELTA:
|
|
|
|
return "Wear range delta";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_SATA_INTERFACE_DOWNSHIFT_COUNT:
|
|
|
|
return "PCIE_INTF_DOWNSHIFT_COUNT";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_END_TO_END_CRC_ERROR_COUNT:
|
|
|
|
return "E2E_CRC_ERROR_COUNT";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_UNCORRECTABLE_READ_ERRORS:
|
|
|
|
return "Uncorrectable Read Error Count";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_MAX_LIFE_TEMPERATURE:
|
2025-02-16 12:18:36 +01:00
|
|
|
return "Max lifetime temperature";
|
2025-02-16 11:09:01 +01:00
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_RAISE_ECC_CORRECTABLE_ERROR_COUNT:
|
|
|
|
return "RAIS_ECC_CORRECT_ERR_COUNT";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_UNCORRECTABLE_RAISE_ERRORS:
|
2025-02-16 12:18:36 +01:00
|
|
|
return "Uncorrectable RAISE error count";
|
2025-02-16 11:09:01 +01:00
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_DRIVE_LIFE_PROTECTION_STATUS:
|
|
|
|
return "DRIVE_LIFE_PROTECTION_STATUS";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_REMAINING_SSD_LIFE:
|
|
|
|
return "Remaining SSD life";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_LSB:
|
|
|
|
return "LSB of Physical (NAND) bytes written";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_MSB:
|
|
|
|
return "MSB of Physical (NAND) bytes written";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_LSB:
|
|
|
|
return "LSB of Physical (HOST) bytes written";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_MSB:
|
|
|
|
return "MSB of Physical (HOST) bytes written";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_LIFETIME_READS_TO_HOST_LSB:
|
|
|
|
return "LSB of Physical (NAND) bytes read";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_LIFETIME_READS_TO_HOST_MSB:
|
|
|
|
return "MSB of Physical (NAND) bytes read";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_FREE_SPACE:
|
|
|
|
return "Free Space";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_TRIM_COUNT_LSB:
|
|
|
|
return "LSB of Trim count";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_TRIM_COUNT_MSB:
|
|
|
|
return "MSB of Trim count";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_OP_PERCENTAGE:
|
|
|
|
return "OP percentage";
|
|
|
|
break;
|
|
|
|
case VS_ATTR_ID_MAX_SOC_LIFE_TEMPERATURE:
|
|
|
|
return "Max lifetime SOC temperature";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return "Un-Known";
|
2025-02-16 12:18:36 +01:00
|
|
|
}
|
2025-02-16 11:09:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static __u64 smart_attribute_vs(__u16 verNo, SmartVendorSpecific attr)
|
|
|
|
{
|
|
|
|
__u64 val = 0;
|
|
|
|
vendor_smart_attribute_data *attrVendor;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* These are all Vendor A specific attributes.
|
|
|
|
*/
|
|
|
|
if (verNo >= EXTENDED_SMART_VERSION_VENDOR1) {
|
|
|
|
attrVendor = (vendor_smart_attribute_data *)&attr;
|
|
|
|
memcpy(&val, &(attrVendor->LSDword), sizeof(val));
|
|
|
|
return val;
|
|
|
|
} else
|
|
|
|
return le32_to_cpu(attr.Raw0_3);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void print_smart_log(__u16 verNo, SmartVendorSpecific attr, int lastAttr)
|
|
|
|
{
|
|
|
|
static __u64 lsbGbErased = 0, msbGbErased = 0, lsbLifWrtToFlash = 0, msbLifWrtToFlash = 0,
|
|
|
|
lsbLifWrtFrmHost = 0, msbLifWrtFrmHost = 0, lsbLifRdToHost = 0, msbLifRdToHost = 0, lsbTrimCnt = 0, msbTrimCnt = 0;
|
|
|
|
char buf[40] = {0};
|
|
|
|
char strBuf[35] = {0};
|
|
|
|
int hideAttr = 0;
|
|
|
|
|
|
|
|
if (attr.AttributeNumber == VS_ATTR_ID_GB_ERASED_LSB) {
|
|
|
|
lsbGbErased = smart_attribute_vs(verNo, attr);
|
|
|
|
hideAttr = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attr.AttributeNumber == VS_ATTR_ID_GB_ERASED_MSB) {
|
|
|
|
msbGbErased = smart_attribute_vs(verNo, attr);
|
|
|
|
hideAttr = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attr.AttributeNumber == VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_LSB) {
|
|
|
|
lsbLifWrtToFlash = smart_attribute_vs(verNo, attr);
|
|
|
|
hideAttr = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attr.AttributeNumber == VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_MSB) {
|
|
|
|
msbLifWrtToFlash = smart_attribute_vs(verNo, attr);
|
|
|
|
hideAttr = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attr.AttributeNumber == VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_LSB) {
|
|
|
|
lsbLifWrtFrmHost = smart_attribute_vs(verNo, attr);
|
|
|
|
hideAttr = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attr.AttributeNumber == VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_MSB) {
|
|
|
|
msbLifWrtFrmHost = smart_attribute_vs(verNo, attr);
|
|
|
|
hideAttr = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attr.AttributeNumber == VS_ATTR_ID_LIFETIME_READS_TO_HOST_LSB) {
|
|
|
|
lsbLifRdToHost = smart_attribute_vs(verNo, attr);
|
|
|
|
hideAttr = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attr.AttributeNumber == VS_ATTR_ID_LIFETIME_READS_TO_HOST_MSB) {
|
|
|
|
msbLifRdToHost = smart_attribute_vs(verNo, attr);
|
|
|
|
hideAttr = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attr.AttributeNumber == VS_ATTR_ID_TRIM_COUNT_LSB) {
|
|
|
|
lsbTrimCnt = smart_attribute_vs(verNo, attr);
|
|
|
|
hideAttr = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attr.AttributeNumber == VS_ATTR_ID_TRIM_COUNT_MSB) {
|
|
|
|
msbTrimCnt = smart_attribute_vs(verNo, attr);
|
|
|
|
hideAttr = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((attr.AttributeNumber != 0) && (hideAttr != 1)) {
|
|
|
|
printf("%-40s", print_ext_smart_id(attr.AttributeNumber));
|
2025-02-16 12:18:36 +01:00
|
|
|
printf("%-15d", attr.AttributeNumber);
|
|
|
|
printf(" 0x%016"PRIx64"\n", (uint64_t)smart_attribute_vs(verNo, attr));
|
2025-02-16 11:09:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (lastAttr == 1) {
|
|
|
|
|
|
|
|
sprintf(strBuf, "%s", (print_ext_smart_id(VS_ATTR_ID_GB_ERASED_LSB) + 7));
|
|
|
|
printf("%-40s", strBuf);
|
|
|
|
|
|
|
|
printf("%-15d", VS_ATTR_ID_GB_ERASED_MSB << 8 | VS_ATTR_ID_GB_ERASED_LSB);
|
|
|
|
|
|
|
|
sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", (uint64_t)msbGbErased, (uint64_t)lsbGbErased);
|
2025-02-16 12:18:36 +01:00
|
|
|
printf(" %s\n", buf);
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
sprintf(strBuf, "%s", (print_ext_smart_id(VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_LSB) + 7));
|
|
|
|
printf("%-40s", strBuf);
|
|
|
|
|
|
|
|
printf("%-15d", VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_MSB << 8 | VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_LSB);
|
|
|
|
|
|
|
|
sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", (uint64_t)msbLifWrtToFlash, (uint64_t)lsbLifWrtToFlash);
|
2025-02-16 12:18:36 +01:00
|
|
|
printf(" %s\n", buf);
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
sprintf(strBuf, "%s", (print_ext_smart_id(VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_LSB) + 7));
|
|
|
|
printf("%-40s", strBuf);
|
|
|
|
|
|
|
|
printf("%-15d", VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_MSB << 8 | VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_LSB);
|
|
|
|
|
|
|
|
sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", (uint64_t)msbLifWrtFrmHost, (uint64_t)lsbLifWrtFrmHost);
|
2025-02-16 12:18:36 +01:00
|
|
|
printf(" %s\n", buf);
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
sprintf(strBuf, "%s", (print_ext_smart_id(VS_ATTR_ID_LIFETIME_READS_TO_HOST_LSB) + 7));
|
|
|
|
printf("%-40s", strBuf);
|
|
|
|
|
|
|
|
printf("%-15d", VS_ATTR_ID_LIFETIME_READS_TO_HOST_MSB << 8 | VS_ATTR_ID_LIFETIME_READS_TO_HOST_LSB);
|
|
|
|
|
|
|
|
sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", (uint64_t)msbLifRdToHost, (uint64_t)lsbLifRdToHost);
|
2025-02-16 12:18:36 +01:00
|
|
|
printf(" %s\n", buf);
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
sprintf(strBuf, "%s", (print_ext_smart_id(VS_ATTR_ID_TRIM_COUNT_LSB) + 7));
|
|
|
|
printf("%-40s", strBuf);
|
|
|
|
|
|
|
|
printf("%-15d", VS_ATTR_ID_TRIM_COUNT_MSB << 8 | VS_ATTR_ID_TRIM_COUNT_LSB);
|
|
|
|
|
|
|
|
sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", (uint64_t)msbTrimCnt, (uint64_t)lsbTrimCnt);
|
2025-02-16 12:18:36 +01:00
|
|
|
printf(" %s\n", buf);
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
static void json_print_smart_log(struct json_object *root, EXTENDED_SMART_INFO_T *ExtdSMARTInfo)
|
2025-02-16 11:09:01 +01:00
|
|
|
{
|
2025-02-16 11:31:10 +01:00
|
|
|
struct json_object *lbafs;
|
2025-02-16 11:09:01 +01:00
|
|
|
int index = 0;
|
|
|
|
|
|
|
|
static __u64 lsbGbErased = 0, msbGbErased = 0, lsbLifWrtToFlash = 0, msbLifWrtToFlash = 0,
|
|
|
|
lsbLifWrtFrmHost = 0, msbLifWrtFrmHost = 0, lsbLifRdToHost = 0, msbLifRdToHost = 0, lsbTrimCnt = 0, msbTrimCnt = 0;
|
|
|
|
char buf[40] = {0};
|
|
|
|
|
|
|
|
lbafs = json_create_array();
|
|
|
|
json_object_add_value_array(root, "Extended-SMART-Attributes", lbafs);
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
for (index = 0; index < NUMBER_EXTENDED_SMART_ATTRIBUTES; index++) {
|
2025-02-16 11:09:01 +01:00
|
|
|
struct json_object *lbaf = json_create_object();
|
|
|
|
if (ExtdSMARTInfo->vendorData[index].AttributeNumber != 0) {
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", print_ext_smart_id(ExtdSMARTInfo->vendorData[index].AttributeNumber));
|
2025-02-16 12:18:36 +01:00
|
|
|
json_object_add_value_int(lbaf, "attribute_id", ExtdSMARTInfo->vendorData[index].AttributeNumber);
|
2025-02-16 11:09:01 +01:00
|
|
|
json_object_add_value_int(lbaf, "attribute_value", smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]));
|
|
|
|
json_array_add_value_object(lbafs, lbaf);
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
if (ExtdSMARTInfo->vendorData[index].AttributeNumber == VS_ATTR_ID_GB_ERASED_LSB)
|
2025-02-16 11:09:01 +01:00
|
|
|
lsbGbErased = smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]);
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
if (ExtdSMARTInfo->vendorData[index].AttributeNumber == VS_ATTR_ID_GB_ERASED_MSB)
|
2025-02-16 11:09:01 +01:00
|
|
|
msbGbErased = smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]);
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
if (ExtdSMARTInfo->vendorData[index].AttributeNumber == VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_LSB)
|
2025-02-16 11:09:01 +01:00
|
|
|
lsbLifWrtToFlash = smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]);
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
if (ExtdSMARTInfo->vendorData[index].AttributeNumber == VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_MSB)
|
2025-02-16 11:09:01 +01:00
|
|
|
msbLifWrtToFlash = smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]);
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
if (ExtdSMARTInfo->vendorData[index].AttributeNumber == VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_LSB)
|
2025-02-16 11:09:01 +01:00
|
|
|
lsbLifWrtFrmHost = smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]);
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
if (ExtdSMARTInfo->vendorData[index].AttributeNumber == VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_MSB)
|
2025-02-16 11:09:01 +01:00
|
|
|
msbLifWrtFrmHost = smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]);
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
if (ExtdSMARTInfo->vendorData[index].AttributeNumber == VS_ATTR_ID_LIFETIME_READS_TO_HOST_LSB)
|
2025-02-16 11:09:01 +01:00
|
|
|
lsbLifRdToHost = smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]);
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
if (ExtdSMARTInfo->vendorData[index].AttributeNumber == VS_ATTR_ID_LIFETIME_READS_TO_HOST_MSB)
|
2025-02-16 11:09:01 +01:00
|
|
|
msbLifRdToHost = smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]);
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
if (ExtdSMARTInfo->vendorData[index].AttributeNumber == VS_ATTR_ID_TRIM_COUNT_LSB)
|
2025-02-16 11:09:01 +01:00
|
|
|
lsbTrimCnt = smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]);
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
if (ExtdSMARTInfo->vendorData[index].AttributeNumber == VS_ATTR_ID_TRIM_COUNT_MSB)
|
2025-02-16 11:09:01 +01:00
|
|
|
msbTrimCnt = smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct json_object *lbaf = json_create_object();
|
|
|
|
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", (print_ext_smart_id(VS_ATTR_ID_GB_ERASED_LSB) + 7));
|
|
|
|
|
|
|
|
json_object_add_value_int(lbaf, "attribute_id", VS_ATTR_ID_GB_ERASED_MSB << 8 | VS_ATTR_ID_GB_ERASED_LSB);
|
|
|
|
|
|
|
|
sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", (uint64_t)msbGbErased, (uint64_t)lsbGbErased);
|
|
|
|
json_object_add_value_string(lbaf, "attribute_value", buf);
|
|
|
|
json_array_add_value_object(lbafs, lbaf);
|
|
|
|
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", (print_ext_smart_id(VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_LSB) + 7));
|
|
|
|
|
|
|
|
json_object_add_value_int(lbaf, "attribute_id", VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_MSB << 8 | VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_LSB);
|
|
|
|
|
|
|
|
sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", (uint64_t)msbLifWrtToFlash, (uint64_t)lsbLifWrtToFlash);
|
|
|
|
json_object_add_value_string(lbaf, "attribute_value", buf);
|
|
|
|
json_array_add_value_object(lbafs, lbaf);
|
|
|
|
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", (print_ext_smart_id(VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_LSB) + 7));
|
|
|
|
|
|
|
|
json_object_add_value_int(lbaf, "attribute_id", VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_MSB << 8 | VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_LSB);
|
|
|
|
|
|
|
|
sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", (uint64_t)msbLifWrtFrmHost, (uint64_t)lsbLifWrtFrmHost);
|
|
|
|
json_object_add_value_string(lbaf, "attribute_value", buf);
|
|
|
|
json_array_add_value_object(lbafs, lbaf);
|
|
|
|
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", (print_ext_smart_id(VS_ATTR_ID_LIFETIME_READS_TO_HOST_LSB) + 7));
|
|
|
|
|
|
|
|
json_object_add_value_int(lbaf, "attribute_id", VS_ATTR_ID_LIFETIME_READS_TO_HOST_MSB << 8 | VS_ATTR_ID_LIFETIME_READS_TO_HOST_LSB);
|
|
|
|
|
|
|
|
sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", (uint64_t)msbLifRdToHost, (uint64_t)lsbLifRdToHost);
|
|
|
|
json_object_add_value_string(lbaf, "attribute_value", buf);
|
|
|
|
json_array_add_value_object(lbafs, lbaf);
|
|
|
|
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", (print_ext_smart_id(VS_ATTR_ID_TRIM_COUNT_LSB) + 7));
|
|
|
|
|
|
|
|
json_object_add_value_int(lbaf, "attribute_id", VS_ATTR_ID_TRIM_COUNT_MSB << 8 | VS_ATTR_ID_TRIM_COUNT_LSB);
|
|
|
|
|
|
|
|
sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", (uint64_t)msbTrimCnt, (uint64_t)lsbTrimCnt);
|
|
|
|
json_object_add_value_string(lbaf, "attribute_value", buf);
|
|
|
|
json_array_add_value_object(lbafs, lbaf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void print_smart_log_CF(vendor_log_page_CF *pLogPageCF)
|
|
|
|
{
|
|
|
|
__u64 currentTemp, maxTemp;
|
|
|
|
printf("\n\nSeagate DRAM Supercap SMART Attributes :\n");
|
|
|
|
printf("%-39s %-19s \n", "Description", "Supercap Attributes");
|
|
|
|
|
|
|
|
printf("%-40s", "Super-cap current temperature");
|
|
|
|
currentTemp = pLogPageCF->AttrCF.SuperCapCurrentTemperature;
|
2025-02-16 12:18:36 +01:00
|
|
|
printf(" 0x%016"PRIx64"\n", le64_to_cpu(currentTemp));
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
maxTemp = pLogPageCF->AttrCF.SuperCapMaximumTemperature;
|
|
|
|
printf("%-40s", "Super-cap maximum temperature");
|
2025-02-16 12:18:36 +01:00
|
|
|
printf(" 0x%016"PRIx64"\n", le64_to_cpu(maxTemp));
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
printf("%-40s", "Super-cap status");
|
2025-02-16 12:18:36 +01:00
|
|
|
printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageCF->AttrCF.SuperCapStatus));
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
printf("%-40s", "Data units read to DRAM namespace");
|
2025-02-16 12:18:36 +01:00
|
|
|
printf(" 0x%016"PRIx64"%016"PRIx64"\n", le64_to_cpu(pLogPageCF->AttrCF.DataUnitsReadToDramNamespace.MS__u64),
|
|
|
|
le64_to_cpu(pLogPageCF->AttrCF.DataUnitsReadToDramNamespace.LS__u64));
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
printf("%-40s", "Data units written to DRAM namespace");
|
2025-02-16 12:18:36 +01:00
|
|
|
printf(" 0x%016"PRIx64"%016"PRIx64"\n", le64_to_cpu(pLogPageCF->AttrCF.DataUnitsWrittenToDramNamespace.MS__u64),
|
|
|
|
le64_to_cpu(pLogPageCF->AttrCF.DataUnitsWrittenToDramNamespace.LS__u64));
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
printf("%-40s", "DRAM correctable error count");
|
2025-02-16 12:18:36 +01:00
|
|
|
printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageCF->AttrCF.DramCorrectableErrorCount));
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
printf("%-40s", "DRAM uncorrectable error count");
|
2025-02-16 12:18:36 +01:00
|
|
|
printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageCF->AttrCF.DramUncorrectableErrorCount));
|
2025-02-16 11:09:01 +01:00
|
|
|
}
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
static void json_print_smart_log_CF(struct json_object *root, vendor_log_page_CF *pLogPageCF)
|
2025-02-16 11:09:01 +01:00
|
|
|
{
|
2025-02-16 11:31:10 +01:00
|
|
|
struct json_object *logPages;
|
2025-02-16 11:09:01 +01:00
|
|
|
unsigned int currentTemp, maxTemp;
|
|
|
|
char buf[40];
|
|
|
|
|
|
|
|
logPages = json_create_array();
|
|
|
|
json_object_add_value_array(root, "DRAM Supercap SMART Attributes", logPages);
|
|
|
|
struct json_object *lbaf = json_create_object();
|
|
|
|
|
|
|
|
currentTemp = pLogPageCF->AttrCF.SuperCapCurrentTemperature;
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "Super-cap current temperature");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", currentTemp);
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
maxTemp = pLogPageCF->AttrCF.SuperCapMaximumTemperature;
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "Super-cap maximum temperature");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", maxTemp);
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "Super-cap status");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", pLogPageCF->AttrCF.SuperCapStatus);
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "Data units read to DRAM namespace");
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", le64_to_cpu(pLogPageCF->AttrCF.DataUnitsReadToDramNamespace.MS__u64),
|
|
|
|
le64_to_cpu(pLogPageCF->AttrCF.DataUnitsReadToDramNamespace.LS__u64));
|
|
|
|
json_object_add_value_string(lbaf, "attribute_value", buf);
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "Data units written to DRAM namespace");
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", le64_to_cpu(pLogPageCF->AttrCF.DataUnitsWrittenToDramNamespace.MS__u64),
|
|
|
|
le64_to_cpu(pLogPageCF->AttrCF.DataUnitsWrittenToDramNamespace.LS__u64));
|
|
|
|
json_object_add_value_string(lbaf, "attribute_value", buf);
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "DRAM correctable error count");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", pLogPageCF->AttrCF.DramCorrectableErrorCount);
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "DRAM uncorrectable error count");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", pLogPageCF->AttrCF.DramUncorrectableErrorCount);
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
2025-02-16 12:18:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void print_stx_smart_log_C0(STX_EXT_SMART_LOG_PAGE_C0 *pLogPageC0)
|
|
|
|
{
|
|
|
|
printf("\n\nSeagate SMART Health Attributes :\n");
|
|
|
|
printf("%-39s %-19s \n", "Description", "Health Attributes");
|
|
|
|
|
|
|
|
printf("%-40s", "Physical Media Units Written");
|
|
|
|
printf(" 0x%016"PRIx64"%016"PRIx64"\n", le64_to_cpu(pLogPageC0->phyMediaUnitsWrt.MS__u64),
|
|
|
|
le64_to_cpu(pLogPageC0->phyMediaUnitsWrt.LS__u64));
|
|
|
|
|
|
|
|
printf("%-40s", "Physical Media Units Read");
|
|
|
|
printf(" 0x%016"PRIx64"%016"PRIx64"\n", le64_to_cpu(pLogPageC0->phyMediaUnitsRd.MS__u64),
|
|
|
|
le64_to_cpu(pLogPageC0->phyMediaUnitsRd.LS__u64));
|
|
|
|
|
|
|
|
printf("%-40s", "Bad User NAND Blocks");
|
|
|
|
printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->badUsrNandBlocks));
|
|
|
|
|
|
|
|
printf("%-40s", "Bad System NAND Blocks");
|
|
|
|
printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->badSysNandBlocks));
|
|
|
|
|
|
|
|
printf("%-40s", "XOR Recovery Count");
|
|
|
|
printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->xorRecoveryCnt));
|
|
|
|
|
|
|
|
printf("%-40s", "Uncorrectable Read Error Count");
|
|
|
|
printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->ucRdEc));
|
|
|
|
|
|
|
|
printf("%-40s", "Soft ECC Error Count");
|
|
|
|
printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->softEccEc));
|
|
|
|
|
|
|
|
printf("%-40s", "End to End Correction Counts");
|
|
|
|
printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->etoeCrrCnt));
|
|
|
|
|
|
|
|
printf("%-40s", "System Data Used in Parcent");
|
|
|
|
printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->sysDataUsed));
|
|
|
|
|
|
|
|
printf("%-40s", "Refresh Counts");
|
|
|
|
printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->refreshCount));
|
|
|
|
|
|
|
|
printf("%-40s", "User Data Erase Counts");
|
|
|
|
printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->usrDataEraseCnt));
|
|
|
|
|
|
|
|
printf("%-40s", "Thermal Throttling Status and Count");
|
|
|
|
printf(" 0x%04x\n", le16_to_cpu(pLogPageC0->thermalThrottling));
|
|
|
|
|
|
|
|
printf("%-40s", "DSSD Specification Version");
|
|
|
|
printf(" %d.%d.%d.%d\n", pLogPageC0->dssdSpecVerMajor,
|
|
|
|
le16_to_cpu(pLogPageC0->dssdSpecVerMinor),
|
|
|
|
le16_to_cpu(pLogPageC0->dssdSpecVerPoint),
|
|
|
|
pLogPageC0->dssdSpecVerErrata);
|
|
|
|
|
|
|
|
printf("%-40s", "PCIe Correctable Error Count");
|
|
|
|
printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->pcieCorrEc));
|
|
|
|
|
|
|
|
printf("%-40s", "Incomplete Shutdowns");
|
|
|
|
printf(" 0x%08x\n", le32_to_cpu(pLogPageC0->incompleteShutdowns));
|
|
|
|
|
|
|
|
printf("%-40s", "Free Blocks in Percent");
|
|
|
|
printf(" %d\n", pLogPageC0->freeBlocks);
|
|
|
|
|
|
|
|
printf("%-40s", "Capacitor Health");
|
|
|
|
printf(" 0x%04x\n", le16_to_cpu(pLogPageC0->capHealth));
|
|
|
|
|
|
|
|
printf("%-40s", "NVMe Errata Version");
|
|
|
|
printf(" %c\n", pLogPageC0->nvmeErrataVer);
|
|
|
|
|
|
|
|
printf("%-40s", "Unaligned IO");
|
|
|
|
printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->unalignedIO));
|
|
|
|
|
|
|
|
printf("%-40s", "Security Version Number");
|
|
|
|
printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->secVerNum));
|
|
|
|
|
|
|
|
printf("%-40s", "Total Namespace Utilization");
|
|
|
|
printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->totalNUSE));
|
|
|
|
|
|
|
|
printf("%-40s", "PLP Start Count");
|
|
|
|
printf(" 0x%016"PRIx64"%016"PRIx64"\n", le64_to_cpu(pLogPageC0->plpStartCnt.MS__u64),
|
|
|
|
le64_to_cpu(pLogPageC0->plpStartCnt.LS__u64));
|
|
|
|
|
|
|
|
printf("%-40s", "Endurance Estimate");
|
|
|
|
printf(" 0x%016"PRIx64"%016"PRIx64"\n", le64_to_cpu(pLogPageC0->enduranceEstimate.MS__u64),
|
|
|
|
le64_to_cpu(pLogPageC0->enduranceEstimate.LS__u64));
|
|
|
|
|
|
|
|
printf("%-40s", "PCIe Link Retraining Count");
|
|
|
|
printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->pcieLinkRetCnt));
|
|
|
|
|
|
|
|
printf("%-40s", "Power State Change Count");
|
|
|
|
printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->powStateChangeCnt));
|
|
|
|
|
|
|
|
printf("%-40s", "Log Page Version");
|
|
|
|
printf(" 0x%04x\n", le16_to_cpu(pLogPageC0->logPageVer));
|
|
|
|
|
|
|
|
printf("%-40s", "Log Page GUID");
|
|
|
|
printf(" 0x%016"PRIx64"%016"PRIx64"\n", le64_to_cpu(pLogPageC0->logPageGUID.MS__u64),
|
|
|
|
le64_to_cpu(pLogPageC0->logPageGUID.LS__u64));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void json_print_stx_smart_log_C0(struct json_object *root, STX_EXT_SMART_LOG_PAGE_C0 *pLogPageC0)
|
|
|
|
{
|
|
|
|
struct json_object *logPages;
|
|
|
|
char buf[40];
|
|
|
|
|
|
|
|
logPages = json_create_array();
|
|
|
|
json_object_add_value_array(root, "Seagate SMART Health Attributes", logPages);
|
|
|
|
|
|
|
|
struct json_object *lbaf = json_create_object();
|
|
|
|
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "Physical Media Units Written");
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", le64_to_cpu(pLogPageC0->phyMediaUnitsWrt.MS__u64),
|
|
|
|
le64_to_cpu(pLogPageC0->phyMediaUnitsWrt.LS__u64));
|
|
|
|
json_object_add_value_string(lbaf, "attribute_value", buf);
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "Physical Media Units Read");
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", le64_to_cpu(pLogPageC0->phyMediaUnitsRd.MS__u64),
|
|
|
|
le64_to_cpu(pLogPageC0->phyMediaUnitsRd.LS__u64));
|
|
|
|
json_object_add_value_string(lbaf, "attribute_value", buf);
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "Bad User NAND Blocks");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->badUsrNandBlocks));
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "Bad System NAND Blocks");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->badSysNandBlocks));
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "XOR Recovery Count");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->xorRecoveryCnt));
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "Uncorrectable Read Error Count");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->ucRdEc));
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "Soft ECC Error Count");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->softEccEc));
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "End to End Correction Counts");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->etoeCrrCnt));
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "System Data Used in Parcent");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->sysDataUsed));
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "Refresh Counts");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->refreshCount));
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "User Data Erase Counts");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->usrDataEraseCnt));
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "Thermal Throttling Status and Count");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", le16_to_cpu(pLogPageC0->thermalThrottling));
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "DSSD Specification Version");
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
sprintf(buf, "%d.%d.%d.%d", pLogPageC0->dssdSpecVerMajor,
|
|
|
|
le16_to_cpu(pLogPageC0->dssdSpecVerMinor),
|
|
|
|
le16_to_cpu(pLogPageC0->dssdSpecVerPoint),
|
|
|
|
pLogPageC0->dssdSpecVerErrata);
|
|
|
|
json_object_add_value_string(lbaf, "attribute_value", buf);
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "PCIe Correctable Error Count");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->pcieCorrEc));
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "Incomplete Shutdowns");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", le32_to_cpu(pLogPageC0->incompleteShutdowns));
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "Free Blocks in Percent");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", pLogPageC0->freeBlocks);
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "Capacitor Health");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", le16_to_cpu(pLogPageC0->capHealth));
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "NVMe Errata Version");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", pLogPageC0->nvmeErrataVer);
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "Unaligned IO");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->unalignedIO));
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "Security Version Number");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->secVerNum));
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "Total Namespace Utilization");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->totalNUSE));
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "PLP Start Count");
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", le64_to_cpu(pLogPageC0->plpStartCnt.MS__u64),
|
|
|
|
le64_to_cpu(pLogPageC0->plpStartCnt.LS__u64));
|
|
|
|
json_object_add_value_string(lbaf, "attribute_value", buf);
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "Endurance Estimate");
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", le64_to_cpu(pLogPageC0->enduranceEstimate.MS__u64),
|
|
|
|
le64_to_cpu(pLogPageC0->enduranceEstimate.LS__u64));
|
|
|
|
json_object_add_value_string(lbaf, "attribute_value", buf);
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "PCIe Link Retraining Count");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->pcieLinkRetCnt));
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "Power State Change Count");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->powStateChangeCnt));
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
|
|
|
|
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "Log Page Version");
|
|
|
|
json_object_add_value_int(lbaf, "attribute_value", le16_to_cpu(pLogPageC0->logPageVer));
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
2025-02-16 11:09:01 +01:00
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
lbaf = json_create_object();
|
|
|
|
json_object_add_value_string(lbaf, "attribute_name", "Log Page GUID");
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", le64_to_cpu(pLogPageC0->logPageGUID.MS__u64),
|
|
|
|
le64_to_cpu(pLogPageC0->logPageGUID.LS__u64));
|
|
|
|
json_object_add_value_string(lbaf, "attribute_value", buf);
|
|
|
|
json_array_add_value_object(logPages, lbaf);
|
2025-02-16 11:09:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
|
|
|
{
|
2025-02-16 12:18:36 +01:00
|
|
|
struct nvme_id_ctrl ctrl;
|
|
|
|
char modelNo[40];
|
|
|
|
STX_EXT_SMART_LOG_PAGE_C0 ehExtSmart;
|
2025-02-16 11:09:01 +01:00
|
|
|
EXTENDED_SMART_INFO_T ExtdSMARTInfo;
|
|
|
|
vendor_log_page_CF logPageCF;
|
2025-02-16 11:31:10 +01:00
|
|
|
struct json_object *root = json_create_object();
|
|
|
|
struct json_object *lbafs = json_create_array();
|
2025-02-16 11:09:01 +01:00
|
|
|
struct json_object *lbafs_ExtSmart, *lbafs_DramSmart;
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
const char *desc = "Retrieve the Firmware Activation History for Seagate NVMe drives";
|
2025-02-16 11:09:01 +01:00
|
|
|
const char *output_format = "output in binary format";
|
2025-02-16 12:18:36 +01:00
|
|
|
struct nvme_dev *dev;
|
|
|
|
int err, index = 0;
|
2025-02-16 11:09:01 +01:00
|
|
|
struct config {
|
|
|
|
char *output_format;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct config cfg = {
|
|
|
|
.output_format = "normal",
|
|
|
|
};
|
|
|
|
|
|
|
|
OPT_ARGS(opts) = {
|
|
|
|
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
|
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
err = parse_and_open(&dev, argc, argv, desc, opts);
|
|
|
|
if (err) {
|
2025-02-16 12:16:19 +01:00
|
|
|
printf ("\nDevice not found \n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
if (strcmp(cfg.output_format, "json"))
|
2025-02-16 11:09:01 +01:00
|
|
|
printf("Seagate Extended SMART Information :\n");
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Here we should identify if the drive is a Panthor or Jaguar.
|
|
|
|
* Here we need to extract the model no from ctrl-id abd use it
|
|
|
|
* to deternine drive family.
|
|
|
|
*/
|
|
|
|
|
|
|
|
err = nvme_identify_ctrl(dev_fd(dev), &ctrl);
|
2025-02-16 11:09:01 +01:00
|
|
|
if (!err) {
|
2025-02-16 12:18:36 +01:00
|
|
|
memcpy(modelNo, ctrl.mn, sizeof(modelNo));
|
|
|
|
} else {
|
|
|
|
nvme_show_status(err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stx_is_jag_pan(modelNo) == 0) {
|
|
|
|
|
|
|
|
err = nvme_get_log_simple(dev_fd(dev), 0xC4, sizeof(ExtdSMARTInfo), &ExtdSMARTInfo);
|
|
|
|
if (!err) {
|
|
|
|
if (strcmp(cfg.output_format, "json")) {
|
|
|
|
printf("%-39s %-15s %-19s \n", "Description", "Ext-Smart-Id", "Ext-Smart-Value");
|
|
|
|
for (index = 0; index < 80; index++)
|
|
|
|
printf("-");
|
|
|
|
printf("\n");
|
|
|
|
for (index = 0; index < NUMBER_EXTENDED_SMART_ATTRIBUTES; index++)
|
|
|
|
print_smart_log(ExtdSMARTInfo.Version, ExtdSMARTInfo.vendorData[index], index == (NUMBER_EXTENDED_SMART_ATTRIBUTES - 1));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
lbafs_ExtSmart = json_create_object();
|
|
|
|
json_print_smart_log(lbafs_ExtSmart, &ExtdSMARTInfo);
|
|
|
|
|
|
|
|
json_object_add_value_array(root, "SMART-Attributes", lbafs);
|
|
|
|
json_array_add_value_object(lbafs, lbafs_ExtSmart);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Next get Log Page 0xCF
|
|
|
|
*/
|
|
|
|
|
|
|
|
err = nvme_get_log_simple(dev_fd(dev), 0xCF, sizeof(logPageCF), &logPageCF);
|
|
|
|
if (!err) {
|
|
|
|
if (strcmp(cfg.output_format, "json")) {
|
|
|
|
print_smart_log_CF(&logPageCF);
|
|
|
|
} else {
|
|
|
|
lbafs_DramSmart = json_create_object();
|
|
|
|
json_print_smart_log_CF(lbafs_DramSmart, &logPageCF);
|
|
|
|
json_array_add_value_object(lbafs, lbafs_DramSmart);
|
|
|
|
json_print_object(root, NULL);
|
|
|
|
}
|
|
|
|
} else if (!strcmp(cfg.output_format, "json")) {
|
|
|
|
json_print_object(root, NULL);
|
|
|
|
json_free_object(root);
|
|
|
|
}
|
|
|
|
} else if (err > 0)
|
|
|
|
nvme_show_status(err);
|
|
|
|
} else {
|
|
|
|
err = nvme_get_log_simple(dev_fd(dev), 0xC0, sizeof(ehExtSmart), &ehExtSmart);
|
|
|
|
|
|
|
|
if (!err) {
|
|
|
|
if (strcmp(cfg.output_format, "json")) {
|
|
|
|
print_stx_smart_log_C0(&ehExtSmart);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
lbafs_ExtSmart = json_create_object();
|
|
|
|
json_print_stx_smart_log_C0(lbafs_ExtSmart, &ehExtSmart);
|
|
|
|
|
|
|
|
json_object_add_value_array(root, "SMART-Attributes", lbafs);
|
|
|
|
json_array_add_value_object(lbafs, lbafs_ExtSmart);
|
|
|
|
|
|
|
|
json_print_object(root, NULL);
|
|
|
|
json_free_object(root);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err > 0)
|
|
|
|
nvme_show_status(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
err = nvme_get_log_simple(dev_fd(dev), 0xC4,
|
|
|
|
sizeof(ExtdSMARTInfo), &ExtdSMARTInfo);
|
|
|
|
if (!err) {
|
|
|
|
if (strcmp(cfg.output_format, "json")) {
|
2025-02-16 11:09:01 +01:00
|
|
|
printf("%-39s %-15s %-19s \n", "Description", "Ext-Smart-Id", "Ext-Smart-Value");
|
2025-02-16 12:18:36 +01:00
|
|
|
for (index = 0; index < 80; index++)
|
2025-02-16 11:09:01 +01:00
|
|
|
printf("-");
|
|
|
|
printf("\n");
|
2025-02-16 12:18:36 +01:00
|
|
|
for (index = 0; index < NUMBER_EXTENDED_SMART_ATTRIBUTES; index++)
|
2025-02-16 11:09:01 +01:00
|
|
|
print_smart_log(ExtdSMARTInfo.Version, ExtdSMARTInfo.vendorData[index], index == (NUMBER_EXTENDED_SMART_ATTRIBUTES - 1));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
lbafs_ExtSmart = json_create_object();
|
|
|
|
json_print_smart_log(lbafs_ExtSmart, &ExtdSMARTInfo);
|
|
|
|
|
|
|
|
json_object_add_value_array(root, "SMART-Attributes", lbafs);
|
|
|
|
json_array_add_value_object(lbafs, lbafs_ExtSmart);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Next get Log Page 0xCF
|
|
|
|
*/
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
err = nvme_get_log_simple(dev_fd(dev), 0xCF,
|
|
|
|
sizeof(logPageCF), &logPageCF);
|
2025-02-16 11:09:01 +01:00
|
|
|
if (!err) {
|
2025-02-16 12:18:36 +01:00
|
|
|
if (strcmp(cfg.output_format, "json")) {
|
2025-02-16 11:09:01 +01:00
|
|
|
print_smart_log_CF(&logPageCF);
|
|
|
|
} else {
|
|
|
|
lbafs_DramSmart = json_create_object();
|
|
|
|
json_print_smart_log_CF(lbafs_DramSmart, &logPageCF);
|
|
|
|
json_array_add_value_object(lbafs, lbafs_DramSmart);
|
|
|
|
json_print_object(root, NULL);
|
|
|
|
}
|
|
|
|
} else if (!strcmp(cfg.output_format, "json"))
|
|
|
|
json_print_object(root, NULL);
|
|
|
|
} else if (err > 0)
|
2025-02-16 12:15:45 +01:00
|
|
|
nvme_show_status(err);
|
2025-02-16 11:09:01 +01:00
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
dev_close(dev);
|
|
|
|
|
2025-02-16 11:09:01 +01:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*EOF Extended-SMART Information */
|
|
|
|
|
|
|
|
/***************************************
|
|
|
|
* Temperature-Stats information
|
|
|
|
***************************************/
|
|
|
|
static void json_temp_stats(__u32 temperature, __u32 PcbTemp, __u32 SocTemp, __u32 maxTemperature,
|
2025-02-16 12:18:36 +01:00
|
|
|
__u32 MaxSocTemp, __u32 cf_err, __u32 scCurrentTemp, __u32 scMaxTem)
|
2025-02-16 11:09:01 +01:00
|
|
|
{
|
|
|
|
struct json_object *root;
|
|
|
|
root = json_create_object();
|
|
|
|
|
|
|
|
json_object_add_value_int(root, "Current temperature", temperature);
|
|
|
|
json_object_add_value_int(root, "Current PCB temperature", PcbTemp);
|
|
|
|
json_object_add_value_int(root, "Current SOC temperature", SocTemp);
|
|
|
|
json_object_add_value_int(root, "Highest temperature", maxTemperature);
|
|
|
|
json_object_add_value_int(root, "Max SOC temperature", MaxSocTemp);
|
2025-02-16 12:18:36 +01:00
|
|
|
if (!cf_err) {
|
2025-02-16 11:09:01 +01:00
|
|
|
json_object_add_value_int(root, "SuperCap Current temperature", scCurrentTemp);
|
|
|
|
json_object_add_value_int(root, "SuperCap Max temperature", scMaxTem);
|
|
|
|
}
|
|
|
|
|
|
|
|
json_print_object(root, NULL);
|
|
|
|
}
|
2025-02-16 12:18:36 +01:00
|
|
|
|
2025-02-16 11:09:01 +01:00
|
|
|
static int temp_stats(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
|
|
|
{
|
|
|
|
struct nvme_smart_log smart_log;
|
|
|
|
EXTENDED_SMART_INFO_T ExtdSMARTInfo;
|
|
|
|
vendor_log_page_CF logPageCF;
|
|
|
|
|
|
|
|
int err, cf_err;
|
|
|
|
int index;
|
|
|
|
const char *desc = "Retrieve Seagate Temperature Stats information for the given device ";
|
|
|
|
const char *output_format = "output in binary format";
|
|
|
|
unsigned int temperature = 0, PcbTemp = 0, SocTemp = 0, scCurrentTemp = 0, scMaxTemp = 0;
|
|
|
|
unsigned long long maxTemperature = 0, MaxSocTemp = 0;
|
2025-02-16 12:18:36 +01:00
|
|
|
struct nvme_dev *dev;
|
2025-02-16 11:09:01 +01:00
|
|
|
struct config {
|
|
|
|
char *output_format;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct config cfg = {
|
|
|
|
.output_format = "normal",
|
|
|
|
};
|
|
|
|
|
|
|
|
OPT_ARGS(opts) = {
|
|
|
|
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
|
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
err = parse_and_open(&dev, argc, argv, desc, opts);
|
|
|
|
if (err) {
|
2025-02-16 11:09:01 +01:00
|
|
|
printf ("\nDevice not found \n");;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
if (strcmp(cfg.output_format, "json"))
|
2025-02-16 11:09:01 +01:00
|
|
|
printf("Seagate Temperature Stats Information :\n");
|
|
|
|
/*STEP-1 : Get Current Temperature from SMART */
|
2025-02-16 12:18:36 +01:00
|
|
|
err = nvme_get_log_smart(dev_fd(dev), 0xffffffff, false, &smart_log);
|
2025-02-16 11:09:01 +01:00
|
|
|
if (!err) {
|
|
|
|
temperature = ((smart_log.temperature[1] << 8) | smart_log.temperature[0]);
|
|
|
|
temperature = temperature ? temperature - 273 : 0;
|
|
|
|
PcbTemp = le16_to_cpu(smart_log.temp_sensor[0]);
|
|
|
|
PcbTemp = PcbTemp ? PcbTemp - 273 : 0;
|
|
|
|
SocTemp = le16_to_cpu(smart_log.temp_sensor[1]);
|
|
|
|
SocTemp = SocTemp ? SocTemp - 273 : 0;
|
2025-02-16 12:18:36 +01:00
|
|
|
if (strcmp(cfg.output_format, "json")) {
|
2025-02-16 11:09:01 +01:00
|
|
|
printf("%-20s : %u C\n", "Current Temperature", temperature);
|
|
|
|
printf("%-20s : %u C\n", "Current PCB Temperature", PcbTemp);
|
|
|
|
printf("%-20s : %u C\n", "Current SOC Temperature", SocTemp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* STEP-2 : Get Max temperature form Ext SMART-id 194 */
|
2025-02-16 12:18:36 +01:00
|
|
|
err = nvme_get_log_simple(dev_fd(dev), 0xC4,
|
|
|
|
sizeof(ExtdSMARTInfo), &ExtdSMARTInfo);
|
2025-02-16 11:09:01 +01:00
|
|
|
if (!err) {
|
2025-02-16 12:18:36 +01:00
|
|
|
for (index = 0; index < NUMBER_EXTENDED_SMART_ATTRIBUTES; index++) {
|
2025-02-16 11:09:01 +01:00
|
|
|
if (ExtdSMARTInfo.vendorData[index].AttributeNumber == VS_ATTR_ID_MAX_LIFE_TEMPERATURE) {
|
|
|
|
maxTemperature = smart_attribute_vs(ExtdSMARTInfo.Version, ExtdSMARTInfo.vendorData[index]);
|
|
|
|
maxTemperature = maxTemperature ? maxTemperature - 273 : 0;
|
2025-02-16 12:18:36 +01:00
|
|
|
if (strcmp(cfg.output_format, "json"))
|
2025-02-16 11:09:01 +01:00
|
|
|
printf("%-20s : %d C\n", "Highest Temperature", (unsigned int)maxTemperature);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ExtdSMARTInfo.vendorData[index].AttributeNumber == VS_ATTR_ID_MAX_SOC_LIFE_TEMPERATURE) {
|
|
|
|
MaxSocTemp = smart_attribute_vs(ExtdSMARTInfo.Version, ExtdSMARTInfo.vendorData[index]);
|
|
|
|
MaxSocTemp = MaxSocTemp ? MaxSocTemp - 273 : 0;
|
2025-02-16 12:18:36 +01:00
|
|
|
if (strcmp(cfg.output_format, "json"))
|
2025-02-16 11:09:01 +01:00
|
|
|
printf("%-20s : %d C\n", "Max SOC Temperature", (unsigned int)MaxSocTemp);
|
|
|
|
}
|
|
|
|
}
|
2025-02-16 12:18:36 +01:00
|
|
|
} else {
|
|
|
|
if (err > 0)
|
|
|
|
nvme_show_status(err);
|
2025-02-16 11:09:01 +01:00
|
|
|
}
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
cf_err = nvme_get_log_simple(dev_fd(dev), 0xCF,
|
|
|
|
sizeof(ExtdSMARTInfo), &logPageCF);
|
2025-02-16 11:09:01 +01:00
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
if (!cf_err) {
|
2025-02-16 11:09:01 +01:00
|
|
|
scCurrentTemp = logPageCF.AttrCF.SuperCapCurrentTemperature;
|
|
|
|
scCurrentTemp = scCurrentTemp ? scCurrentTemp - 273 : 0;
|
|
|
|
printf("%-20s : %d C\n", "Super-cap Current Temperature", scCurrentTemp);
|
|
|
|
|
|
|
|
scMaxTemp = logPageCF.AttrCF.SuperCapMaximumTemperature;
|
|
|
|
scMaxTemp = scMaxTemp ? scMaxTemp - 273 : 0;
|
|
|
|
printf("%-20s : %d C\n", "Super-cap Max Temperature", scMaxTemp);
|
|
|
|
}
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
if (!strcmp(cfg.output_format, "json"))
|
2025-02-16 11:09:01 +01:00
|
|
|
json_temp_stats(temperature, PcbTemp, SocTemp, maxTemperature, MaxSocTemp, cf_err, scCurrentTemp, scMaxTemp);
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
dev_close(dev);
|
2025-02-16 11:09:01 +01:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
/* EOF Temperature Stats information */
|
|
|
|
|
|
|
|
/***************************************
|
|
|
|
* PCIe error-log information
|
|
|
|
***************************************/
|
|
|
|
static void print_vs_pcie_error_log(pcie_error_log_page pcieErrorLog)
|
|
|
|
{
|
|
|
|
__u32 correctPcieEc = 0;
|
|
|
|
__u32 uncorrectPcieEc = 0;
|
|
|
|
correctPcieEc = pcieErrorLog.BadDllpErrCnt + pcieErrorLog.BadTlpErrCnt
|
|
|
|
+ pcieErrorLog.RcvrErrCnt + pcieErrorLog.ReplayTOErrCnt
|
|
|
|
+ pcieErrorLog.ReplayNumRolloverErrCnt;
|
|
|
|
|
|
|
|
uncorrectPcieEc = pcieErrorLog.FCProtocolErrCnt + pcieErrorLog.DllpProtocolErrCnt
|
|
|
|
+ pcieErrorLog.CmpltnTOErrCnt + pcieErrorLog.RcvrQOverflowErrCnt
|
|
|
|
+ pcieErrorLog.UnexpectedCplTlpErrCnt + pcieErrorLog.CplTlpURErrCnt
|
|
|
|
+ pcieErrorLog.CplTlpCAErrCnt + pcieErrorLog.ReqCAErrCnt
|
|
|
|
+ pcieErrorLog.ReqURErrCnt + pcieErrorLog.EcrcErrCnt
|
|
|
|
+ pcieErrorLog.MalformedTlpErrCnt + pcieErrorLog.CplTlpPoisonedErrCnt
|
|
|
|
+ pcieErrorLog.MemRdTlpPoisonedErrCnt;
|
|
|
|
|
|
|
|
printf("%-45s : %u\n", "PCIe Correctable Error Count", correctPcieEc);
|
|
|
|
printf("%-45s : %u\n", "PCIe Un-Correctable Error Count", uncorrectPcieEc);
|
|
|
|
printf("%-45s : %u\n", "Unsupported Request Error Status (URES)", pcieErrorLog.ReqURErrCnt);
|
|
|
|
printf("%-45s : %u\n", "ECRC Error Status (ECRCES)", pcieErrorLog.EcrcErrCnt);
|
|
|
|
printf("%-45s : %u\n", "Malformed TLP Status (MTS)", pcieErrorLog.MalformedTlpErrCnt);
|
|
|
|
printf("%-45s : %u\n", "Receiver Overflow Status (ROS)", pcieErrorLog.RcvrQOverflowErrCnt);
|
|
|
|
printf("%-45s : %u\n", "Unexpected Completion Status(UCS)", pcieErrorLog.UnexpectedCplTlpErrCnt);
|
|
|
|
printf("%-45s : %u\n", "Completion Timeout Status (CTS)", pcieErrorLog.CmpltnTOErrCnt);
|
|
|
|
printf("%-45s : %u\n", "Flow Control Protocol Error Status (FCPES)", pcieErrorLog.FCProtocolErrCnt);
|
|
|
|
printf("%-45s : %u\n", "Poisoned TLP Status (PTS)", pcieErrorLog.MemRdTlpPoisonedErrCnt);
|
|
|
|
printf("%-45s : %u\n", "Data Link Protocol Error Status(DLPES)", pcieErrorLog.DllpProtocolErrCnt);
|
|
|
|
printf("%-45s : %u\n", "Replay Timer Timeout Status(RTS)", pcieErrorLog.ReplayTOErrCnt);
|
|
|
|
printf("%-45s : %u\n", "Replay_NUM Rollover Status(RRS)", pcieErrorLog.ReplayNumRolloverErrCnt);
|
|
|
|
printf("%-45s : %u\n", "Bad DLLP Status (BDS)", pcieErrorLog.BadDllpErrCnt);
|
|
|
|
printf("%-45s : %u\n", "Bad TLP Status (BTS)", pcieErrorLog.BadTlpErrCnt);
|
|
|
|
printf("%-45s : %u\n", "Receiver Error Status (RES)", pcieErrorLog.RcvrErrCnt);
|
|
|
|
printf("%-45s : %u\n", "Cpl TLP Unsupported Request Error Count", pcieErrorLog.CplTlpURErrCnt);
|
|
|
|
printf("%-45s : %u\n", "Cpl TLP Completion Abort Error Count", pcieErrorLog.CplTlpCAErrCnt);
|
|
|
|
printf("%-45s : %u\n", "Cpl TLP Poisoned Error Count", pcieErrorLog.CplTlpPoisonedErrCnt);
|
|
|
|
printf("%-45s : %u\n", "Request Completion Abort Error Count", pcieErrorLog.ReqCAErrCnt);
|
|
|
|
printf("%-45s : %s\n", "Advisory Non-Fatal Error Status(ANFES)", "Not Supported");
|
|
|
|
printf("%-45s : %s\n", "Completer Abort Status (CAS)", "Not Supported");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void json_vs_pcie_error_log(pcie_error_log_page pcieErrorLog)
|
|
|
|
{
|
|
|
|
struct json_object *root;
|
|
|
|
root = json_create_object();
|
|
|
|
__u32 correctPcieEc = 0;
|
|
|
|
__u32 uncorrectPcieEc = 0;
|
|
|
|
correctPcieEc = pcieErrorLog.BadDllpErrCnt + pcieErrorLog.BadTlpErrCnt
|
|
|
|
+ pcieErrorLog.RcvrErrCnt + pcieErrorLog.ReplayTOErrCnt
|
|
|
|
+ pcieErrorLog.ReplayNumRolloverErrCnt;
|
|
|
|
|
|
|
|
uncorrectPcieEc = pcieErrorLog.FCProtocolErrCnt + pcieErrorLog.DllpProtocolErrCnt
|
|
|
|
+ pcieErrorLog.CmpltnTOErrCnt + pcieErrorLog.RcvrQOverflowErrCnt
|
|
|
|
+ pcieErrorLog.UnexpectedCplTlpErrCnt + pcieErrorLog.CplTlpURErrCnt
|
|
|
|
+ pcieErrorLog.CplTlpCAErrCnt + pcieErrorLog.ReqCAErrCnt
|
|
|
|
+ pcieErrorLog.ReqURErrCnt + pcieErrorLog.EcrcErrCnt
|
|
|
|
+ pcieErrorLog.MalformedTlpErrCnt + pcieErrorLog.CplTlpPoisonedErrCnt
|
|
|
|
+ pcieErrorLog.MemRdTlpPoisonedErrCnt;
|
|
|
|
|
|
|
|
json_object_add_value_int(root, "PCIe Correctable Error Count", correctPcieEc);
|
|
|
|
json_object_add_value_int(root, "PCIe Un-Correctable Error Count", uncorrectPcieEc);
|
|
|
|
json_object_add_value_int(root, "Unsupported Request Error Status (URES)", pcieErrorLog.ReqURErrCnt);
|
|
|
|
json_object_add_value_int(root, "ECRC Error Status (ECRCES)", pcieErrorLog.EcrcErrCnt);
|
|
|
|
json_object_add_value_int(root, "Malformed TLP Status (MTS)", pcieErrorLog.MalformedTlpErrCnt);
|
|
|
|
json_object_add_value_int(root, "Receiver Overflow Status (ROS)", pcieErrorLog.RcvrQOverflowErrCnt);
|
|
|
|
json_object_add_value_int(root, "Unexpected Completion Status(UCS)", pcieErrorLog.UnexpectedCplTlpErrCnt);
|
|
|
|
json_object_add_value_int(root, "Completion Timeout Status (CTS)", pcieErrorLog.CmpltnTOErrCnt);
|
|
|
|
json_object_add_value_int(root, "Flow Control Protocol Error Status (FCPES)", pcieErrorLog.FCProtocolErrCnt);
|
|
|
|
json_object_add_value_int(root, "Poisoned TLP Status (PTS)", pcieErrorLog.MemRdTlpPoisonedErrCnt);
|
|
|
|
json_object_add_value_int(root, "Data Link Protocol Error Status(DLPES)", pcieErrorLog.DllpProtocolErrCnt);
|
|
|
|
json_object_add_value_int(root, "Replay Timer Timeout Status(RTS)", pcieErrorLog.ReplayTOErrCnt);
|
|
|
|
json_object_add_value_int(root, "Replay_NUM Rollover Status(RRS)", pcieErrorLog.ReplayNumRolloverErrCnt);
|
|
|
|
json_object_add_value_int(root, "Bad DLLP Status (BDS)", pcieErrorLog.BadDllpErrCnt);
|
|
|
|
json_object_add_value_int(root, "Bad TLP Status (BTS)", pcieErrorLog.BadTlpErrCnt);
|
|
|
|
json_object_add_value_int(root, "Receiver Error Status (RES)", pcieErrorLog.RcvrErrCnt);
|
|
|
|
json_object_add_value_int(root, "Cpl TLP Unsupported Request Error Count", pcieErrorLog.CplTlpURErrCnt);
|
|
|
|
json_object_add_value_int(root, "Cpl TLP Completion Abort Error Count", pcieErrorLog.CplTlpCAErrCnt);
|
|
|
|
json_object_add_value_int(root, "Cpl TLP Poisoned Error Count", pcieErrorLog.CplTlpPoisonedErrCnt);
|
|
|
|
json_object_add_value_int(root, "Request Completion Abort Error Count", pcieErrorLog.ReqCAErrCnt);
|
|
|
|
json_print_object(root, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vs_pcie_error_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
|
|
|
{
|
|
|
|
pcie_error_log_page pcieErrorLog;
|
2025-02-16 12:18:36 +01:00
|
|
|
struct nvme_dev *dev;
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
const char *desc = "Retrieve Seagate PCIe error counters for the given device ";
|
|
|
|
const char *output_format = "output in binary format";
|
|
|
|
int err;
|
|
|
|
struct config {
|
|
|
|
char *output_format;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct config cfg = {
|
|
|
|
.output_format = "normal",
|
|
|
|
};
|
|
|
|
|
|
|
|
OPT_ARGS(opts) = {
|
|
|
|
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
|
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
err = parse_and_open(&dev, argc, argv, desc, opts);
|
|
|
|
if (err) {
|
2025-02-16 12:16:19 +01:00
|
|
|
printf ("\nDevice not found \n");;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
if (strcmp(cfg.output_format, "json"))
|
2025-02-16 11:09:01 +01:00
|
|
|
printf("Seagate PCIe error counters Information :\n");
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
err = nvme_get_log_simple(dev_fd(dev), 0xCB,
|
|
|
|
sizeof(pcieErrorLog), &pcieErrorLog);
|
2025-02-16 11:09:01 +01:00
|
|
|
if (!err) {
|
2025-02-16 12:18:36 +01:00
|
|
|
if (strcmp(cfg.output_format, "json")) {
|
2025-02-16 11:09:01 +01:00
|
|
|
print_vs_pcie_error_log(pcieErrorLog);
|
|
|
|
} else
|
|
|
|
json_vs_pcie_error_log(pcieErrorLog);
|
|
|
|
|
|
|
|
} else if (err > 0)
|
2025-02-16 12:15:45 +01:00
|
|
|
nvme_show_status(err);
|
2025-02-16 11:09:01 +01:00
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
dev_close(dev);
|
2025-02-16 11:09:01 +01:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
/* EOF PCIE error-log information */
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
|
|
|
|
/***************************************
|
|
|
|
* FW Activation History log
|
|
|
|
***************************************/
|
|
|
|
static void print_stx_vs_fw_activate_history(stx_fw_activ_history_log_page fwActivHis)
|
|
|
|
{
|
|
|
|
__u32 i;
|
|
|
|
char prev_fw[9] = {0};
|
|
|
|
char new_fw[9] = {0};
|
|
|
|
char buf[80];
|
|
|
|
|
|
|
|
if (fwActivHis.numValidFwActHisEnt > 0) {
|
|
|
|
printf("\n\nSeagate FW Activation Histry :\n");
|
|
|
|
printf("%-9s %-21s %-7s %-13s %-9s %-5s %-15s %-9s\n", "Counter ", " Timestamp ", " PCC ", "Previous FW ", "New FW ", "Slot", "Commit Action", "Result");
|
|
|
|
|
|
|
|
for (i = 0; i < fwActivHis.numValidFwActHisEnt; i++) {
|
|
|
|
|
|
|
|
printf(" %-4d ", fwActivHis.fwActHisEnt[i].fwActivCnt);
|
|
|
|
|
|
|
|
time_t t = fwActivHis.fwActHisEnt[i].timeStamp / 1000;
|
|
|
|
struct tm ts;
|
|
|
|
ts = *localtime(&t);
|
|
|
|
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &ts);
|
|
|
|
printf(" %-20s ", buf);
|
|
|
|
printf("%-5" PRId64 " ",
|
|
|
|
(uint64_t)fwActivHis.fwActHisEnt[i].powCycleCnt);
|
|
|
|
|
|
|
|
memset(prev_fw, 0, sizeof(prev_fw));
|
|
|
|
memcpy(prev_fw, fwActivHis.fwActHisEnt[i].previousFW, sizeof(fwActivHis.fwActHisEnt[i].previousFW));
|
|
|
|
printf("%-8s ", prev_fw);
|
|
|
|
|
|
|
|
memset(new_fw, 0, sizeof(new_fw));
|
|
|
|
memcpy(new_fw, fwActivHis.fwActHisEnt[i].newFW, sizeof(fwActivHis.fwActHisEnt[i].newFW));
|
|
|
|
printf("%-8s ", new_fw);
|
|
|
|
|
|
|
|
printf(" %-2d ", fwActivHis.fwActHisEnt[i].slotNum);
|
|
|
|
printf(" 0x%02x ", fwActivHis.fwActHisEnt[i].commitActionType);
|
|
|
|
printf(" 0x%02x \n", fwActivHis.fwActHisEnt[i].result);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
printf("%s\n", "Do not have valid FW Activation History");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void json_stx_vs_fw_activate_history(stx_fw_activ_history_log_page fwActivHis)
|
|
|
|
{
|
|
|
|
struct json_object *root;
|
|
|
|
root = json_create_object();
|
|
|
|
__u32 i;
|
|
|
|
|
|
|
|
char buf[80];
|
|
|
|
|
|
|
|
struct json_object *historyLogPage;
|
|
|
|
historyLogPage = json_create_array();
|
|
|
|
json_object_add_value_array(root, "Seagate FW Activation History", historyLogPage);
|
|
|
|
|
|
|
|
if (fwActivHis.numValidFwActHisEnt > 0) {
|
|
|
|
for (i = 0; i < fwActivHis.numValidFwActHisEnt; i++) {
|
|
|
|
struct json_object *lbaf = json_create_object();
|
|
|
|
char prev_fw[8] = { 0 };
|
|
|
|
char new_fw[8] = { 0 };
|
|
|
|
|
|
|
|
json_object_add_value_int(lbaf, "Counter", fwActivHis.fwActHisEnt[i].fwActivCnt);
|
|
|
|
|
|
|
|
time_t t = fwActivHis.fwActHisEnt[i].timeStamp / 1000;
|
|
|
|
struct tm ts;
|
|
|
|
ts = *localtime(&t);
|
|
|
|
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &ts);
|
|
|
|
printf(" %-20s ", buf);
|
|
|
|
json_object_add_value_string(lbaf, "Timestamp", buf);
|
|
|
|
|
|
|
|
json_object_add_value_int(lbaf, "PCC", fwActivHis.fwActHisEnt[i].powCycleCnt);
|
|
|
|
sprintf(prev_fw, "%s", fwActivHis.fwActHisEnt[i].previousFW);
|
|
|
|
json_object_add_value_string(lbaf, "Previous_FW", prev_fw);
|
|
|
|
|
|
|
|
sprintf(new_fw, "%s", fwActivHis.fwActHisEnt[i].newFW);
|
|
|
|
json_object_add_value_string(lbaf, "New_FW", new_fw);
|
|
|
|
|
|
|
|
json_object_add_value_int(lbaf, "Slot", fwActivHis.fwActHisEnt[i].slotNum);
|
|
|
|
json_object_add_value_int(lbaf, "Commit_Action", fwActivHis.fwActHisEnt[i].commitActionType);
|
|
|
|
json_object_add_value_int(lbaf, "Result", fwActivHis.fwActHisEnt[i].result);
|
|
|
|
|
|
|
|
json_array_add_value_object(historyLogPage, lbaf);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
printf("%s\n", "Do not have valid FW Activation History");
|
|
|
|
}
|
|
|
|
|
|
|
|
json_print_object(root, NULL);
|
|
|
|
json_free_object(root);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int stx_vs_fw_activate_history(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
|
|
|
{
|
|
|
|
stx_fw_activ_history_log_page fwActivHis;
|
|
|
|
struct nvme_dev *dev;
|
|
|
|
|
|
|
|
const char *desc = "Retrieve FW Activate History for Seagate device ";
|
|
|
|
const char *output_format = "output in binary format";
|
|
|
|
int err;
|
|
|
|
struct config {
|
|
|
|
char *output_format;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct config cfg = {
|
|
|
|
.output_format = "normal",
|
|
|
|
};
|
|
|
|
|
|
|
|
OPT_ARGS(opts) = {
|
|
|
|
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
|
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
|
|
|
err = parse_and_open(&dev, argc, argv, desc, opts);
|
|
|
|
if (err < 0) {
|
|
|
|
printf ("\nDevice not found \n");;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strcmp(cfg.output_format, "json"))
|
|
|
|
printf("Seagate FW Activation Histry Information :\n");
|
|
|
|
|
|
|
|
err = nvme_get_log_simple(dev_fd(dev), 0xC2, sizeof(fwActivHis), &fwActivHis);
|
|
|
|
if (!err) {
|
|
|
|
if (strcmp(cfg.output_format, "json")) {
|
|
|
|
print_stx_vs_fw_activate_history(fwActivHis);
|
|
|
|
} else
|
|
|
|
json_stx_vs_fw_activate_history(fwActivHis);
|
|
|
|
|
|
|
|
} else if (err > 0)
|
|
|
|
nvme_show_status(err);
|
|
|
|
|
|
|
|
dev_close(dev);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
/* EOF FW Activation History log information */
|
|
|
|
|
|
|
|
|
|
|
|
static int clear_fw_activate_history(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
|
|
|
{
|
|
|
|
const char *desc = "Clear FW Activation History for the given Seagate device ";
|
|
|
|
const char *save = "specifies that the controller shall save the attribute";
|
|
|
|
int err;
|
|
|
|
struct nvme_dev *dev;
|
|
|
|
struct nvme_id_ctrl ctrl;
|
|
|
|
char modelNo[40];
|
|
|
|
__u32 result;
|
|
|
|
|
|
|
|
struct config {
|
|
|
|
bool save;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct config cfg = {
|
|
|
|
.save = 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
OPT_ARGS(opts) = {
|
|
|
|
OPT_FLAG("save", 's', &cfg.save, save),
|
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
|
|
|
err = parse_and_open(&dev, argc, argv, desc, opts);
|
|
|
|
if (err < 0) {
|
|
|
|
printf ("\nDevice not found \n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = nvme_identify_ctrl(dev_fd(dev), &ctrl);
|
|
|
|
if (!err) {
|
|
|
|
memcpy(modelNo, ctrl.mn, sizeof(modelNo));
|
|
|
|
} else {
|
|
|
|
nvme_show_status(err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stx_is_jag_pan(modelNo) == 0) {
|
|
|
|
printf ("\nDevice does not support Clear FW Activation History \n");
|
|
|
|
} else {
|
|
|
|
|
|
|
|
struct nvme_set_features_args args = {
|
|
|
|
.args_size = sizeof(args),
|
|
|
|
.fd = dev_fd(dev),
|
|
|
|
.fid = 0xC1,
|
|
|
|
.nsid = 0,
|
|
|
|
.cdw11 = 0x80000000,
|
|
|
|
.cdw12 = 0,
|
|
|
|
.save = 0,
|
|
|
|
.uuidx = 0,
|
|
|
|
.cdw15 = 0,
|
|
|
|
.data_len = 0,
|
|
|
|
.data = NULL,
|
|
|
|
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
|
|
|
|
.result = &result,
|
|
|
|
};
|
|
|
|
err = nvme_set_features(&args);
|
|
|
|
if (err)
|
|
|
|
fprintf(stderr, "%s: couldn't clear PCIe correctable errors \n",
|
|
|
|
__func__);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err < 0) {
|
|
|
|
perror("set-feature");
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev_close(dev);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-02-16 11:09:01 +01:00
|
|
|
static int vs_clr_pcie_correctable_errs(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
|
|
|
{
|
|
|
|
const char *desc = "Clear Seagate PCIe Correctable counters for the given device ";
|
|
|
|
const char *save = "specifies that the controller shall save the attribute";
|
2025-02-16 12:18:36 +01:00
|
|
|
|
|
|
|
struct nvme_id_ctrl ctrl;
|
|
|
|
char modelNo[40];
|
|
|
|
|
|
|
|
struct nvme_dev *dev;
|
|
|
|
|
2025-02-16 11:09:01 +01:00
|
|
|
__u32 result;
|
2025-02-16 12:18:36 +01:00
|
|
|
int err;
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
struct config {
|
2025-02-16 12:15:45 +01:00
|
|
|
bool save;
|
2025-02-16 11:09:01 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
struct config cfg = {
|
|
|
|
.save = 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
OPT_ARGS(opts) = {
|
|
|
|
OPT_FLAG("save", 's', &cfg.save, save),
|
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
err = parse_and_open(&dev, argc, argv, desc, opts);
|
|
|
|
if (err) {
|
2025-02-16 12:16:19 +01:00
|
|
|
printf ("\nDevice not found \n");;
|
|
|
|
return -1;
|
|
|
|
}
|
2025-02-16 11:09:01 +01:00
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
|
|
|
|
err = nvme_identify_ctrl(dev_fd(dev), &ctrl);
|
|
|
|
if (!err) {
|
|
|
|
memcpy(modelNo, ctrl.mn, sizeof(modelNo));
|
|
|
|
} else {
|
|
|
|
nvme_show_status(err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stx_is_jag_pan(modelNo) == 0) {
|
|
|
|
err = nvme_set_features_simple(dev_fd(dev), 0xE1, 0, 0xCB, cfg.save, &result);
|
|
|
|
} else {
|
|
|
|
struct nvme_set_features_args args = {
|
|
|
|
.args_size = sizeof(args),
|
|
|
|
.fd = dev_fd(dev),
|
|
|
|
.fid = 0xC3,
|
|
|
|
.nsid = 0,
|
|
|
|
.cdw11 = 0x80000000,
|
|
|
|
.cdw12 = 0,
|
|
|
|
.save = 0,
|
|
|
|
.uuidx = 0,
|
|
|
|
.cdw15 = 0,
|
|
|
|
.data_len = 0,
|
|
|
|
.data = NULL,
|
|
|
|
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
|
|
|
|
.result = &result,
|
|
|
|
};
|
|
|
|
err = nvme_set_features(&args);
|
|
|
|
if (err)
|
|
|
|
fprintf(stderr, "%s: couldn't clear PCIe correctable errors \n", __func__);
|
|
|
|
}
|
|
|
|
|
|
|
|
err = nvme_set_features_simple(dev_fd(dev), 0xE1, 0, 0xCB, cfg.save, &result);
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
if (err < 0) {
|
|
|
|
perror("set-feature");
|
2025-02-16 12:18:36 +01:00
|
|
|
return errno;
|
2025-02-16 11:09:01 +01:00
|
|
|
}
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
dev_close(dev);
|
2025-02-16 11:09:01 +01:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_host_tele(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
|
|
|
{
|
|
|
|
const char *desc = "Capture the Telemetry Host-Initiated Data in either " \
|
|
|
|
"hex-dump (default) or binary format";
|
|
|
|
const char *namespace_id = "desired namespace";
|
|
|
|
const char *log_specific = "1 - controller shall capture Data representing the internal " \
|
|
|
|
"state of the controller at the time the command is processed. " \
|
|
|
|
"0 - controller shall not update the Telemetry Host Initiated Data.";
|
|
|
|
const char *raw = "output in raw format";
|
|
|
|
struct nvme_temetry_log_hdr tele_log;
|
|
|
|
int blkCnt, maxBlk = 0, blksToGet;
|
2025-02-16 12:18:36 +01:00
|
|
|
struct nvme_dev *dev;
|
2025-02-16 11:09:01 +01:00
|
|
|
unsigned char *log;
|
2025-02-16 12:18:36 +01:00
|
|
|
__le64 offset = 0;
|
|
|
|
int err, dump_fd;
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
struct config {
|
|
|
|
__u32 namespace_id;
|
|
|
|
__u32 log_id;
|
2025-02-16 12:15:45 +01:00
|
|
|
bool raw_binary;
|
2025-02-16 11:09:01 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
struct config cfg = {
|
|
|
|
.namespace_id = 0xffffffff,
|
|
|
|
.log_id = 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
OPT_ARGS(opts) = {
|
|
|
|
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
|
|
|
|
OPT_UINT("log_specific", 'i', &cfg.log_id, log_specific),
|
|
|
|
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
|
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
err = parse_and_open(&dev, argc, argv, desc, opts);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
dump_fd = STDOUT_FILENO;
|
|
|
|
cfg.log_id = (cfg.log_id << 8) | 0x07;
|
2025-02-16 12:18:36 +01:00
|
|
|
err = nvme_get_nsid_log(dev_fd(dev), false, cfg.log_id,
|
|
|
|
cfg.namespace_id,
|
|
|
|
sizeof(tele_log), (void *)(&tele_log));
|
2025-02-16 11:09:01 +01:00
|
|
|
if (!err) {
|
|
|
|
maxBlk = tele_log.tele_data_area3;
|
|
|
|
offset += 512;
|
|
|
|
|
|
|
|
if (!cfg.raw_binary) {
|
|
|
|
printf("Device:%s log-id:%d namespace-id:%#x\n",
|
2025-02-16 12:18:36 +01:00
|
|
|
dev->name, cfg.log_id,
|
|
|
|
cfg.namespace_id);
|
2025-02-16 11:09:01 +01:00
|
|
|
printf("Data Block 1 Last Block:%d Data Block 2 Last Block:%d Data Block 3 Last Block:%d\n",
|
2025-02-16 12:18:36 +01:00
|
|
|
tele_log.tele_data_area1, tele_log.tele_data_area2, tele_log.tele_data_area3);
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
d((unsigned char *)(&tele_log), sizeof(tele_log), 16, 1);
|
|
|
|
} else
|
|
|
|
seaget_d_raw((unsigned char *)(&tele_log), sizeof(tele_log), dump_fd);
|
|
|
|
} else if (err > 0)
|
2025-02-16 12:15:45 +01:00
|
|
|
nvme_show_status(err);
|
2025-02-16 11:09:01 +01:00
|
|
|
else
|
|
|
|
perror("log page");
|
|
|
|
|
|
|
|
blkCnt = 0;
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
while (blkCnt < maxBlk) {
|
2025-02-16 12:16:19 +01:00
|
|
|
unsigned long long bytesToGet;
|
|
|
|
|
2025-02-16 11:09:01 +01:00
|
|
|
blksToGet = ((maxBlk - blkCnt) >= TELEMETRY_BLOCKS_TO_READ) ? TELEMETRY_BLOCKS_TO_READ : (maxBlk - blkCnt);
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
if (blksToGet == 0) {
|
|
|
|
dev_close(dev);
|
2025-02-16 11:09:01 +01:00
|
|
|
return err;
|
2025-02-16 12:16:19 +01:00
|
|
|
}
|
2025-02-16 11:09:01 +01:00
|
|
|
|
2025-02-16 12:16:19 +01:00
|
|
|
bytesToGet = (unsigned long long)blksToGet * 512;
|
|
|
|
log = malloc(bytesToGet);
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
if (!log) {
|
|
|
|
fprintf(stderr, "could not alloc buffer for log\n");
|
2025-02-16 12:18:36 +01:00
|
|
|
dev_close(dev);
|
2025-02-16 11:09:01 +01:00
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
|
2025-02-16 12:16:19 +01:00
|
|
|
memset(log, 0, bytesToGet);
|
2025-02-16 11:09:01 +01:00
|
|
|
|
2025-02-16 12:15:45 +01:00
|
|
|
struct nvme_get_log_args args = {
|
2025-02-16 12:18:36 +01:00
|
|
|
.args_size = sizeof(args),
|
|
|
|
.fd = dev_fd(dev),
|
|
|
|
.lid = cfg.log_id,
|
|
|
|
.nsid = cfg.namespace_id,
|
|
|
|
.lpo = offset,
|
|
|
|
.lsp = 0,
|
|
|
|
.lsi = 0,
|
|
|
|
.rae = true,
|
|
|
|
.uuidx = 0,
|
|
|
|
.csi = NVME_CSI_NVM,
|
|
|
|
.ot = false,
|
|
|
|
.len = bytesToGet,
|
|
|
|
.log = (void *)log,
|
|
|
|
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
|
|
|
|
.result = NULL,
|
2025-02-16 12:15:45 +01:00
|
|
|
};
|
|
|
|
err = nvme_get_log(&args);
|
2025-02-16 11:09:01 +01:00
|
|
|
if (!err) {
|
2025-02-16 12:16:19 +01:00
|
|
|
offset += (__le64)bytesToGet;
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
if (!cfg.raw_binary) {
|
|
|
|
printf("\nBlock # :%d to %d\n", blkCnt + 1, blkCnt + blksToGet);
|
|
|
|
|
2025-02-16 12:16:19 +01:00
|
|
|
d((unsigned char *)log, bytesToGet, 16, 1);
|
2025-02-16 11:09:01 +01:00
|
|
|
} else
|
2025-02-16 12:16:19 +01:00
|
|
|
seaget_d_raw((unsigned char *)log, bytesToGet, dump_fd);
|
2025-02-16 11:09:01 +01:00
|
|
|
} else if (err > 0)
|
2025-02-16 12:15:45 +01:00
|
|
|
nvme_show_status(err);
|
2025-02-16 11:09:01 +01:00
|
|
|
else
|
|
|
|
perror("log page");
|
|
|
|
|
|
|
|
blkCnt += blksToGet;
|
|
|
|
|
|
|
|
free(log);
|
|
|
|
}
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
dev_close(dev);
|
2025-02-16 11:09:01 +01:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_ctrl_tele(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
|
|
|
{
|
2025-02-16 12:18:36 +01:00
|
|
|
const char *desc = "Capture the Telemetry Controller-Initiated Data in either " \
|
2025-02-16 11:09:01 +01:00
|
|
|
"hex-dump (default) or binary format";
|
|
|
|
const char *namespace_id = "desired namespace";
|
|
|
|
const char *raw = "output in raw format";
|
2025-02-16 12:18:36 +01:00
|
|
|
struct nvme_dev *dev;
|
|
|
|
int err, dump_fd;
|
2025-02-16 11:09:01 +01:00
|
|
|
struct nvme_temetry_log_hdr tele_log;
|
|
|
|
__le64 offset = 0;
|
|
|
|
__u16 log_id;
|
|
|
|
int blkCnt, maxBlk = 0, blksToGet;
|
|
|
|
unsigned char *log;
|
|
|
|
|
|
|
|
struct config {
|
|
|
|
__u32 namespace_id;
|
2025-02-16 12:15:45 +01:00
|
|
|
bool raw_binary;
|
2025-02-16 11:09:01 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
struct config cfg = {
|
|
|
|
.namespace_id = 0xffffffff,
|
|
|
|
};
|
|
|
|
|
|
|
|
OPT_ARGS(opts) = {
|
|
|
|
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
|
|
|
|
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
|
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
err = parse_and_open(&dev, argc, argv, desc, opts);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
dump_fd = STDOUT_FILENO;
|
|
|
|
|
|
|
|
log_id = 0x08;
|
2025-02-16 12:18:36 +01:00
|
|
|
err = nvme_get_nsid_log(dev_fd(dev), false, log_id, cfg.namespace_id,
|
|
|
|
sizeof(tele_log), (void *)(&tele_log));
|
2025-02-16 11:09:01 +01:00
|
|
|
if (!err) {
|
|
|
|
maxBlk = tele_log.tele_data_area3;
|
|
|
|
offset += 512;
|
|
|
|
|
|
|
|
if (!cfg.raw_binary) {
|
|
|
|
printf("Device:%s namespace-id:%#x\n",
|
2025-02-16 12:18:36 +01:00
|
|
|
dev->name, cfg.namespace_id);
|
2025-02-16 11:09:01 +01:00
|
|
|
printf("Data Block 1 Last Block:%d Data Block 2 Last Block:%d Data Block 3 Last Block:%d\n",
|
2025-02-16 12:18:36 +01:00
|
|
|
tele_log.tele_data_area1, tele_log.tele_data_area2, tele_log.tele_data_area3);
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
d((unsigned char *)(&tele_log), sizeof(tele_log), 16, 1);
|
|
|
|
} else
|
|
|
|
seaget_d_raw((unsigned char *)(&tele_log), sizeof(tele_log), dump_fd);
|
|
|
|
} else if (err > 0)
|
2025-02-16 12:15:45 +01:00
|
|
|
nvme_show_status(err);
|
2025-02-16 11:09:01 +01:00
|
|
|
else
|
|
|
|
perror("log page");
|
|
|
|
|
|
|
|
blkCnt = 0;
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
while (blkCnt < maxBlk) {
|
2025-02-16 12:16:19 +01:00
|
|
|
unsigned long long bytesToGet;
|
|
|
|
|
2025-02-16 11:09:01 +01:00
|
|
|
blksToGet = ((maxBlk - blkCnt) >= TELEMETRY_BLOCKS_TO_READ) ? TELEMETRY_BLOCKS_TO_READ : (maxBlk - blkCnt);
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
if (blksToGet == 0)
|
2025-02-16 11:09:01 +01:00
|
|
|
return err;
|
|
|
|
|
2025-02-16 12:16:19 +01:00
|
|
|
bytesToGet = (unsigned long long)blksToGet * 512;
|
|
|
|
log = malloc(bytesToGet);
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
if (!log) {
|
|
|
|
fprintf(stderr, "could not alloc buffer for log\n");
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
|
2025-02-16 12:16:19 +01:00
|
|
|
memset(log, 0, bytesToGet);
|
2025-02-16 11:09:01 +01:00
|
|
|
|
2025-02-16 12:15:45 +01:00
|
|
|
struct nvme_get_log_args args = {
|
2025-02-16 12:18:36 +01:00
|
|
|
.args_size = sizeof(args),
|
|
|
|
.fd = dev_fd(dev),
|
|
|
|
.lid = log_id,
|
|
|
|
.nsid = cfg.namespace_id,
|
|
|
|
.lpo = offset,
|
|
|
|
.lsp = 0,
|
|
|
|
.lsi = 0,
|
|
|
|
.rae = true,
|
|
|
|
.uuidx = 0,
|
|
|
|
.csi = NVME_CSI_NVM,
|
|
|
|
.ot = false,
|
|
|
|
.len = bytesToGet,
|
|
|
|
.log = (void *)log,
|
|
|
|
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
|
|
|
|
.result = NULL,
|
2025-02-16 12:15:45 +01:00
|
|
|
};
|
|
|
|
err = nvme_get_log(&args);
|
2025-02-16 11:09:01 +01:00
|
|
|
if (!err) {
|
2025-02-16 12:16:19 +01:00
|
|
|
offset += (__le64)bytesToGet;
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
if (!cfg.raw_binary) {
|
|
|
|
printf("\nBlock # :%d to %d\n", blkCnt + 1, blkCnt + blksToGet);
|
|
|
|
|
2025-02-16 12:16:19 +01:00
|
|
|
d((unsigned char *)log, bytesToGet, 16, 1);
|
2025-02-16 11:09:01 +01:00
|
|
|
} else
|
2025-02-16 12:16:19 +01:00
|
|
|
seaget_d_raw((unsigned char *)log, bytesToGet, dump_fd);
|
2025-02-16 11:09:01 +01:00
|
|
|
} else if (err > 0)
|
2025-02-16 12:15:45 +01:00
|
|
|
nvme_show_status(err);
|
2025-02-16 11:09:01 +01:00
|
|
|
else
|
|
|
|
perror("log page");
|
|
|
|
|
|
|
|
blkCnt += blksToGet;
|
|
|
|
|
|
|
|
free(log);
|
|
|
|
}
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
dev_close(dev);
|
2025-02-16 12:16:19 +01:00
|
|
|
return err;
|
2025-02-16 11:09:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void seaget_d_raw(unsigned char *buf, int len, int fd)
|
|
|
|
{
|
|
|
|
if (write(fd, (void *)buf, len) <= 0)
|
2025-02-16 12:18:36 +01:00
|
|
|
printf("%s: Write Failed\n", __FUNCTION__);
|
2025-02-16 11:09:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int vs_internal_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
|
|
|
{
|
|
|
|
const char *desc = "Capture the Telemetry Controller-Initiated Data in " \
|
|
|
|
"binary format";
|
|
|
|
const char *namespace_id = "desired namespace";
|
|
|
|
|
|
|
|
const char *file = "dump file";
|
2025-02-16 12:18:36 +01:00
|
|
|
struct nvme_dev *dev;
|
|
|
|
int err, dump_fd;
|
2025-02-16 11:09:01 +01:00
|
|
|
int flags = O_WRONLY | O_CREAT;
|
2025-02-16 12:18:36 +01:00
|
|
|
int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
|
2025-02-16 11:09:01 +01:00
|
|
|
struct nvme_temetry_log_hdr tele_log;
|
|
|
|
__le64 offset = 0;
|
|
|
|
__u16 log_id;
|
|
|
|
int blkCnt, maxBlk = 0, blksToGet;
|
|
|
|
unsigned char *log;
|
|
|
|
|
|
|
|
struct config {
|
|
|
|
__u32 namespace_id;
|
|
|
|
char *file;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct config cfg = {
|
|
|
|
.namespace_id = 0xffffffff,
|
|
|
|
.file = "",
|
|
|
|
};
|
|
|
|
|
|
|
|
OPT_ARGS(opts) = {
|
|
|
|
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
|
|
|
|
OPT_FILE("dump-file", 'f', &cfg.file, file),
|
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
err = parse_and_open(&dev, argc, argv, desc, opts);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
dump_fd = STDOUT_FILENO;
|
2025-02-16 12:18:36 +01:00
|
|
|
if (strlen(cfg.file)) {
|
2025-02-16 11:09:01 +01:00
|
|
|
dump_fd = open(cfg.file, flags, mode);
|
|
|
|
if (dump_fd < 0) {
|
|
|
|
perror(cfg.file);
|
2025-02-16 12:18:36 +01:00
|
|
|
dev_close(dev);
|
2025-02-16 11:09:01 +01:00
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
log_id = 0x08;
|
2025-02-16 12:18:36 +01:00
|
|
|
err = nvme_get_nsid_log(dev_fd(dev), false, log_id, cfg.namespace_id,
|
|
|
|
sizeof(tele_log), (void *)(&tele_log));
|
2025-02-16 11:09:01 +01:00
|
|
|
if (!err) {
|
|
|
|
maxBlk = tele_log.tele_data_area3;
|
|
|
|
offset += 512;
|
|
|
|
|
|
|
|
seaget_d_raw((unsigned char *)(&tele_log), sizeof(tele_log), dump_fd);
|
|
|
|
} else if (err > 0)
|
2025-02-16 12:15:45 +01:00
|
|
|
nvme_show_status(err);
|
2025-02-16 11:09:01 +01:00
|
|
|
else
|
|
|
|
perror("log page");
|
|
|
|
|
|
|
|
blkCnt = 0;
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
while (blkCnt < maxBlk) {
|
2025-02-16 12:16:19 +01:00
|
|
|
unsigned long long bytesToGet;
|
|
|
|
|
2025-02-16 11:09:01 +01:00
|
|
|
blksToGet = ((maxBlk - blkCnt) >= TELEMETRY_BLOCKS_TO_READ) ? TELEMETRY_BLOCKS_TO_READ : (maxBlk - blkCnt);
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
if (blksToGet == 0) {
|
2025-02-16 12:16:19 +01:00
|
|
|
goto out;
|
2025-02-16 11:09:01 +01:00
|
|
|
}
|
|
|
|
|
2025-02-16 12:16:19 +01:00
|
|
|
bytesToGet = (unsigned long long)blksToGet * 512;
|
|
|
|
log = malloc(bytesToGet);
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
if (!log) {
|
|
|
|
fprintf(stderr, "could not alloc buffer for log\n");
|
2025-02-16 12:16:19 +01:00
|
|
|
err = EINVAL;
|
|
|
|
goto out;
|
2025-02-16 11:09:01 +01:00
|
|
|
}
|
|
|
|
|
2025-02-16 12:16:19 +01:00
|
|
|
memset(log, 0, bytesToGet);
|
2025-02-16 11:09:01 +01:00
|
|
|
|
2025-02-16 12:15:45 +01:00
|
|
|
struct nvme_get_log_args args = {
|
2025-02-16 12:18:36 +01:00
|
|
|
.args_size = sizeof(args),
|
|
|
|
.fd = dev_fd(dev),
|
|
|
|
.lid = log_id,
|
|
|
|
.nsid = cfg.namespace_id,
|
|
|
|
.lpo = offset,
|
|
|
|
.lsp = 0,
|
|
|
|
.lsi = 0,
|
|
|
|
.rae = true,
|
|
|
|
.uuidx = 0,
|
|
|
|
.csi = NVME_CSI_NVM,
|
|
|
|
.ot = false,
|
|
|
|
.len = bytesToGet,
|
|
|
|
.log = (void *)log,
|
|
|
|
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
|
|
|
|
.result = NULL,
|
2025-02-16 12:15:45 +01:00
|
|
|
};
|
|
|
|
err = nvme_get_log(&args);
|
2025-02-16 11:09:01 +01:00
|
|
|
if (!err) {
|
2025-02-16 12:16:19 +01:00
|
|
|
offset += (__le64)bytesToGet;
|
2025-02-16 11:09:01 +01:00
|
|
|
|
2025-02-16 12:16:19 +01:00
|
|
|
seaget_d_raw((unsigned char *)log, bytesToGet, dump_fd);
|
2025-02-16 11:09:01 +01:00
|
|
|
|
|
|
|
} else if (err > 0)
|
2025-02-16 12:15:45 +01:00
|
|
|
nvme_show_status(err);
|
2025-02-16 11:09:01 +01:00
|
|
|
else
|
|
|
|
perror("log page");
|
|
|
|
|
|
|
|
blkCnt += blksToGet;
|
|
|
|
|
|
|
|
free(log);
|
|
|
|
}
|
2025-02-16 12:16:19 +01:00
|
|
|
out:
|
2025-02-16 12:18:36 +01:00
|
|
|
if (strlen(cfg.file))
|
2025-02-16 11:09:01 +01:00
|
|
|
close(dump_fd);
|
|
|
|
|
2025-02-16 12:18:36 +01:00
|
|
|
dev_close(dev);
|
2025-02-16 11:09:01 +01:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*SEAGATE-PLUGIN Version */
|
2025-02-16 12:18:36 +01:00
|
|
|
static int seagate_plugin_version(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
2025-02-16 11:09:01 +01:00
|
|
|
{
|
|
|
|
printf("Seagate-Plugin version : %d.%d \n",
|
2025-02-16 12:18:36 +01:00
|
|
|
SEAGATE_PLUGIN_VERSION_MAJOR,
|
|
|
|
SEAGATE_PLUGIN_VERSION_MINOR);
|
2025-02-16 11:09:01 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/*EOF SEAGATE-PLUGIN Version */
|
2025-02-16 12:18:36 +01:00
|
|
|
|
|
|
|
/*OCP SEAGATE-PLUGIN Version */
|
|
|
|
static int stx_ocp_plugin_version(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
|
|
|
{
|
|
|
|
printf("Seagate-OCP-Plugin version : %d.%d \n",
|
|
|
|
SEAGATE_OCP_PLUGIN_VERSION_MAJOR,
|
|
|
|
SEAGATE_OCP_PLUGIN_VERSION_MINOR);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/*EOF OCP SEAGATE-PLUGIN Version */
|