Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
393 changes: 393 additions & 0 deletions plugins/ibm/ibm-nvme.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,393 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "common.h"
#include "nvme-print.h"
#include "plugin.h"

#define CREATE_CMD
#include "ibm-nvme.h"

#pragma pack(push, 1)
struct nvme_ibm_log_f0_item {
__le16 attr;
union {
__le64 raw1;
struct split_raw1 {
__le32 lower;
__le32 upper;
} split_raw1;
};
union {
__le64 raw2;
struct split_raw2 {
__le32 lower;
__le32 upper;
} split_raw2;
};
};
#pragma pack(pop)

struct nvme_ibm_additional_smart_log {
__le16 logid;
__le16 len;
struct nvme_ibm_log_f0_item read_err_rate;
struct nvme_ibm_log_f0_item retired_clk_cnt;
struct nvme_ibm_log_f0_item power_on_hours;
struct nvme_ibm_log_f0_item power_cycle_cnt;
struct nvme_ibm_log_f0_item ecc_rate;
struct nvme_ibm_log_f0_item mb_erased;
struct nvme_ibm_log_f0_item unused_rsvd_blk_cnt_percent;
struct nvme_ibm_log_f0_item progrm_fail_cnt;
struct nvme_ibm_log_f0_item erase_fail_cnt;
struct nvme_ibm_log_f0_item drive_life_remain_percent;
struct nvme_ibm_log_f0_item io_err_det_code_events;
struct nvme_ibm_log_f0_item reported_uc_errs;
struct nvme_ibm_log_f0_item drive_temperature;
struct nvme_ibm_log_f0_item thermal_throt;
struct nvme_ibm_log_f0_item drive_life_temp;
struct nvme_ibm_log_f0_item int_raid_correct_err_cnt;
struct nvme_ibm_log_f0_item ssd_life_used;
struct nvme_ibm_log_f0_item ssd_life_used_accurate;
struct nvme_ibm_log_f0_item lifetime_wr_to_flash_mb;
struct nvme_ibm_log_f0_item lifetime_rd_from_flash_mb;
struct nvme_ibm_log_f0_item lifetime_wr_from_host_mb;
struct nvme_ibm_log_f0_item lifetime_rd_to_host_mb;
struct nvme_ibm_log_f0_item vol_mem_backup_fail;
struct nvme_ibm_log_f0_item security_wear_indicator;
struct nvme_ibm_log_f0_item device_pcie_received_errors;
};

static void show_ibm_smart_log(struct nvme_ibm_additional_smart_log *smart, const char *devname)
{
int i, entries = (sizeof(struct nvme_ibm_additional_smart_log) - 4)
/ sizeof(struct nvme_ibm_log_f0_item);
struct nvme_ibm_log_f0_item *entry;

entry = &smart->read_err_rate;

printf("Additional IBM Smart Log for NVME device:%s\n", devname);

for (i = 0; i < entries; i++, entry++) {
switch (le16_to_cpu(entry->attr)) {
case 0x0001:
printf("Total UC Read Errors : %"PRIu64"\n",
le64_to_cpu(smart->read_err_rate.raw1));
printf("Total Reads vs Read Errors : %"PRIu64"\n",
le64_to_cpu(smart->read_err_rate.raw2));
break;
case 0x0005:
printf("Total Retired Blks : %"PRIu64"\n",
le64_to_cpu(smart->retired_clk_cnt.raw1));
break;
case 0x0009:
printf("Total Power On Hours : %"PRIu64"\n",
le64_to_cpu(smart->power_on_hours.raw1));
printf("Time since Last P/C(ms) : %"PRIu64"\n",
le64_to_cpu(smart->power_on_hours.raw2));
break;
case 0x000c:
printf("Total Number of Power Cycles : %"PRIu64"\n",
le64_to_cpu(smart->power_cycle_cnt.raw1));
break;
case 0x000d:
printf("Read (ECC) Errors recov nodelay : %"PRIu64"\n",
le64_to_cpu(smart->ecc_rate.raw1));
printf("Total Reads vs Read Errs nodelay : %"PRIu64"\n",
le64_to_cpu(smart->ecc_rate.raw2));
break;
case 0x0064:
printf("Total MB Erased : %"PRIu64"\n",
le64_to_cpu(smart->mb_erased.raw1));
break;
case 0x00aa:
printf("Unused Rsv Blk 100*Cur/Mfg Spares : %"PRIu64"\n",
le64_to_cpu(smart->unused_rsvd_blk_cnt_percent.raw1));
printf("Current Spares : %"PRIu32"\n",
le32_to_cpu(smart->unused_rsvd_blk_cnt_percent.split_raw2.upper));
printf("Total Spares @ Mfg : %"PRIu32"\n",
le32_to_cpu(smart->unused_rsvd_blk_cnt_percent.split_raw2.lower));
break;
case 0x00ab:
printf("Total Number of Program Fails : %"PRIu64"\n",
le64_to_cpu(smart->progrm_fail_cnt.raw1));
printf("Program fails since Power Cycle : %"PRIu64"\n",
le64_to_cpu(smart->progrm_fail_cnt.raw2));
break;
case 0x00ac:
printf("Total Number of Erase Fails : %"PRIu64"\n",
le64_to_cpu(smart->erase_fail_cnt.raw1));
printf("Erase fails since Power Cycle : %"PRIu64"\n",
le64_to_cpu(smart->erase_fail_cnt.raw2));
break;
case 0x00b1:
printf("Life remaining percent : %"PRIu64"\n",
le64_to_cpu(smart->drive_life_remain_percent.raw1));
printf("PE Cycles most : %"PRIu32"\n",
le32_to_cpu(smart->drive_life_remain_percent.split_raw2.upper));
printf("PE Cycles least : %"PRIu32"\n",
le32_to_cpu(smart->drive_life_remain_percent.split_raw2.lower));
break;
case 0x00b8:
printf("Total number of IOEDC : %"PRIu64"\n",
le64_to_cpu(smart->io_err_det_code_events.raw1));
break;
case 0x00bb:
printf("Total number of UC Errors : %"PRIu64"\n",
le64_to_cpu(smart->reported_uc_errs.raw1));
break;
case 0x00be:
printf("Current Temperature (in C) : %"PRIu64"\n",
le64_to_cpu(smart->drive_temperature.raw1));
printf("Highest Temperature since Power ON : %"PRIu32"\n",
le32_to_cpu(smart->drive_temperature.split_raw2.upper));
printf("Lowest Temperature since Power ON : %"PRIu32"\n",
le32_to_cpu(smart->drive_temperature.split_raw2.lower));
break;
case 0x00bf:
printf("Percentage throttled : %"PRIu64"\n",
le64_to_cpu(smart->thermal_throt.raw1));
printf("Thermal throttling starts : %"PRIu32"\n",
le32_to_cpu(smart->thermal_throt.split_raw2.upper));
printf("Thermal throttling stops : %"PRIu32"\n",
le32_to_cpu(smart->thermal_throt.split_raw2.lower));
break;
case 0x00c2:
printf("PON Time in mins Highest Temperature: %"PRIu32"\n",
le32_to_cpu(smart->drive_life_temp.split_raw1.upper));
printf("PON Time in mins Lowest Temperature : %"PRIu32"\n",
le32_to_cpu(smart->drive_life_temp.split_raw1.lower));
printf("Highest Lifetime Temperature (in C) : %"PRIu32"\n",
le32_to_cpu(smart->drive_life_temp.split_raw2.upper));
printf("Lowest Lifetime Temperature (in C) : %"PRIu32"\n",
le32_to_cpu(smart->drive_life_temp.split_raw2.lower));
break;
case 0x00c3:
printf("Internal RAID Correctable Error : %"PRIu64"\n",
le64_to_cpu(smart->int_raid_correct_err_cnt.raw1));
break;
case 0x00e7:
printf("Life used in percentage : %"PRIu64"\n",
le64_to_cpu(smart->ssd_life_used.raw1));
printf("Average PE Cycles of Flash : %"PRIu64"\n",
le64_to_cpu(smart->ssd_life_used.raw2));
break;
case 0x00e8:
printf("Accurate Life used in percentage : %"PRIu64".%"PRIu64"\n",
le64_to_cpu(smart->ssd_life_used_accurate.raw1)/100,
le64_to_cpu(smart->ssd_life_used_accurate.raw1)%100);
break;
case 0x00e9:
printf("Lifetime Writes to flash in MB : %"PRIu64"\n",
le64_to_cpu(smart->lifetime_wr_to_flash_mb.raw1));
break;
case 0x00ea:
printf("Lifetime Read from flash in MB : %"PRIu64"\n",
le64_to_cpu(smart->lifetime_rd_from_flash_mb.raw1));
break;
case 0x00f1:
printf("Lifetime Writes from Host in MB : %"PRIu64"\n",
le64_to_cpu(smart->lifetime_wr_from_host_mb.raw1));
break;
case 0x00f2:
printf("Lifetime Read to Host in MB : %"PRIu64"\n",
le64_to_cpu(smart->lifetime_rd_to_host_mb.raw1));
break;
case 0x00f3:
printf("Vol. Memory Backup Failures : %"PRIu64"\n",
le64_to_cpu(smart->vol_mem_backup_fail.raw1));
break;
case 0x00f4:
printf("Security Wear Indicator : %"PRIu64"\n",
le64_to_cpu(smart->security_wear_indicator.raw1));
break;
case 0x00f5:
printf("PCIe Received Errors : %"PRIu32"\n",
le32_to_cpu(smart->device_pcie_received_errors.split_raw1.upper));
printf("PCIe Received Bad TLP : %"PRIu32"\n",
le32_to_cpu(smart->device_pcie_received_errors.split_raw1.lower));
printf("PCIe Received Bad DLLP : %"PRIu32"\n",
le32_to_cpu(smart->device_pcie_received_errors.split_raw2.upper));
printf("PCIe Recd Transitions to Recoveries : %"PRIu32"\n",
le32_to_cpu(smart->device_pcie_received_errors.split_raw2.lower));
default:
break;
}
}
}

static int get_ibm_addi_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Get IBM specific additional smart log and show it.";
const char *raw = "Dump output in binary format";

struct nvme_ibm_additional_smart_log smart_log;
struct nvme_dev *dev;
int err;

struct config {
bool raw_binary;
};

struct config cfg = {
.raw_binary = 0,
};

OPT_ARGS(opts) = {
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
OPT_END()
};

err = parse_and_open(&dev, argc, argv, desc, opts);
if (err)
return err;

err = nvme_get_log_simple(dev_fd(dev), 0xf0, sizeof(smart_log), &smart_log);

if (!err) {
if (!cfg.raw_binary)
show_ibm_smart_log(&smart_log, dev->name);
else
d_raw((unsigned char *)&smart_log, sizeof(smart_log));
} else if (err > 0)
nvme_show_status(err);
else
nvme_show_error("ibm additional smart log: %s\n", nvme_strerror(errno));

dev_close(dev);
return err;
}

#pragma pack(push, 1)
struct nvme_ibm_vpd_log {
char version[4];
char description[40];
char masterpn[12];
char ec[10];
char fru[12];
char finalasm[12];
char fc[4];
char ccin[4];
char ibm11s[8];
char ssid[8];
char endurance[4];
char capacity[10];
char warranty[12];
char encryption[1];
char rctt[2];
char loadid[8];
char mfgloc[3];
char ffc[5];
char iotimeout[2];
char formattimeout[4];
char ioqs[4];
char mediatype[2];
char mfgsn[20];
char firmware[8];
char pad[4];
};
#pragma pack(pop)

#define MEDIATYPE 3
static void show_ibm_vpd_log(struct nvme_ibm_vpd_log *vpd, const char *devname)
{
struct nvme_ibm_vpd_log vpdlog;
char *mediatype[MEDIATYPE][2] = {
{ "00", "NAND TLC" },
{ "01", "3DXP" },
{ "02", "LL NAND" }
};

printf("IBM VPD for NVME device:%s\n", devname);
printf("VPD Log Page Version : %.*s\n", (int)sizeof(vpdlog.version),
vpd->version);
printf("Description or ID : %.*s\n", (int)sizeof(vpdlog.description),
vpd->description);
printf("Master Part Number : %.*s\n", (int)sizeof(vpdlog.masterpn),
vpd->masterpn);
printf("EC Level : %.*s\n", (int)sizeof(vpdlog.ec), vpd->ec);
printf("FRU Part Number : %.*s\n", (int)sizeof(vpdlog.fru), vpd->fru);
printf("Final Assembly PN : %.*s\n", (int)sizeof(vpdlog.finalasm),
vpd->finalasm);
printf("Feature Code : %.*s\n", (int)sizeof(vpdlog.fc), vpd->fc);
printf("CCIN : %.*s\n", (int)sizeof(vpdlog.ccin), vpd->ccin);
printf("11S Serial Number : 11S%.*sY%.*s%.*s\n", 7, vpd->masterpn,
(int)sizeof(vpdlog.mfgloc), vpd->mfgloc, (int)sizeof(vpdlog.ibm11s),
vpd->ibm11s);
printf("PCI SSID : %.*s\n", (int)sizeof(vpdlog.ssid), vpd->ssid);
printf("Endurance (DWPD) : %.*s\n", (int)sizeof(vpdlog.endurance),
vpd->endurance);
printf("Capacity (GB) : %.*s\n", (int)sizeof(vpdlog.capacity),
vpd->capacity);
printf("Warranty (Peta Bytes Written) : %.*s\n", (int)sizeof(vpdlog.warranty),
vpd->warranty);
printf("Encryption (0=not supported) : %.*s\n", (int)sizeof(vpdlog.encryption),
vpd->encryption);
printf("RCTT : %.*s\n", (int)sizeof(vpdlog.rctt), vpd->rctt);
printf("Load ID : %.*s\n", (int)sizeof(vpdlog.loadid), vpd->loadid);
printf("MFG Location : %.*s\n", (int)sizeof(vpdlog.mfgloc),
vpd->mfgloc);
printf("FFC : %.*s\n", (int)sizeof(vpdlog.ffc), vpd->ffc);
printf("IO Timeout in Seconds : 0x%.*s\n", (int)sizeof(vpdlog.iotimeout),
vpd->iotimeout);
printf("Format Timeout in Seconds : 0x%.*s\n", (int)sizeof(vpdlog.formattimeout),
vpd->formattimeout);
printf("Optimal Number of IO Queues : 0x%.*s\n", (int)sizeof(vpdlog.ioqs),
vpd->ioqs);

for (int i = 0; i < MEDIATYPE; i++) {
if (!strncmp(mediatype[i][0], vpd->mediatype, (int)sizeof(vpdlog.mediatype)))
printf("Media Type : %.*s (%.*s)\n",
(int)sizeof(mediatype[i][1]), mediatype[i][1],
(int)sizeof(vpdlog.mediatype), vpd->mediatype);
}

printf("Manufacturer Serial Number : %.*s\n", (int) sizeof(vpdlog.mfgsn), vpd->mfgsn);
printf("Firmware version : %.*s\n", (int) sizeof(vpdlog.firmware),
vpd->firmware);
}

static int get_ibm_vpd_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
struct nvme_ibm_vpd_log vpd_log;
int err;
struct nvme_dev *dev;

const char *desc = "Get IBM vendor specific VPD log";
const char *raw = "dump output in binary format";

struct config {
int raw_binary;
};

struct config cfg = {
.raw_binary = 0,
};

OPT_ARGS(opts) = {
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
OPT_END()
};

err = parse_and_open(&dev, argc, argv, desc, opts);
if (err < 0)
return err;

bzero(&vpd_log, sizeof(vpd_log));
err = nvme_get_log_simple(dev_fd(dev), 0xf1, sizeof(vpd_log), &vpd_log);

if (!err) {
if (!cfg.raw_binary)
show_ibm_vpd_log(&vpd_log, dev->name);
else
d_raw((unsigned char *)&vpd_log, sizeof(vpd_log));
} else if (err > 0)
nvme_show_status(err);
else
nvme_show_error("ibm vpd log: %s\n", nvme_strerror(errno));

dev_close(dev);
return err;
}
Loading