Skip to content

Commit a60f699

Browse files
wxiong66igaw
authored andcommitted
plugins/ibm: Add IBM specific plugins code
The patch implements two functions in ibm vendor specific extensions: - Display IBM additional smart log information - Display IBM VPD information Signed-off-by: Wen Xiong<[email protected]>
1 parent 17cb459 commit a60f699

File tree

3 files changed

+414
-0
lines changed

3 files changed

+414
-0
lines changed

plugins/ibm/ibm-nvme.c

Lines changed: 393 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,393 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
#include <stdio.h>
3+
#include <stdlib.h>
4+
#include <unistd.h>
5+
6+
#include "common.h"
7+
#include "nvme-print.h"
8+
#include "plugin.h"
9+
10+
#define CREATE_CMD
11+
#include "ibm-nvme.h"
12+
13+
#pragma pack(push, 1)
14+
struct nvme_ibm_log_f0_item {
15+
__le16 attr;
16+
union {
17+
__le64 raw1;
18+
struct split_raw1 {
19+
__le32 lower;
20+
__le32 upper;
21+
} split_raw1;
22+
};
23+
union {
24+
__le64 raw2;
25+
struct split_raw2 {
26+
__le32 lower;
27+
__le32 upper;
28+
} split_raw2;
29+
};
30+
};
31+
#pragma pack(pop)
32+
33+
struct nvme_ibm_additional_smart_log {
34+
__le16 logid;
35+
__le16 len;
36+
struct nvme_ibm_log_f0_item read_err_rate;
37+
struct nvme_ibm_log_f0_item retired_clk_cnt;
38+
struct nvme_ibm_log_f0_item power_on_hours;
39+
struct nvme_ibm_log_f0_item power_cycle_cnt;
40+
struct nvme_ibm_log_f0_item ecc_rate;
41+
struct nvme_ibm_log_f0_item mb_erased;
42+
struct nvme_ibm_log_f0_item unused_rsvd_blk_cnt_percent;
43+
struct nvme_ibm_log_f0_item progrm_fail_cnt;
44+
struct nvme_ibm_log_f0_item erase_fail_cnt;
45+
struct nvme_ibm_log_f0_item drive_life_remain_percent;
46+
struct nvme_ibm_log_f0_item io_err_det_code_events;
47+
struct nvme_ibm_log_f0_item reported_uc_errs;
48+
struct nvme_ibm_log_f0_item drive_temperature;
49+
struct nvme_ibm_log_f0_item thermal_throt;
50+
struct nvme_ibm_log_f0_item drive_life_temp;
51+
struct nvme_ibm_log_f0_item int_raid_correct_err_cnt;
52+
struct nvme_ibm_log_f0_item ssd_life_used;
53+
struct nvme_ibm_log_f0_item ssd_life_used_accurate;
54+
struct nvme_ibm_log_f0_item lifetime_wr_to_flash_mb;
55+
struct nvme_ibm_log_f0_item lifetime_rd_from_flash_mb;
56+
struct nvme_ibm_log_f0_item lifetime_wr_from_host_mb;
57+
struct nvme_ibm_log_f0_item lifetime_rd_to_host_mb;
58+
struct nvme_ibm_log_f0_item vol_mem_backup_fail;
59+
struct nvme_ibm_log_f0_item security_wear_indicator;
60+
struct nvme_ibm_log_f0_item device_pcie_received_errors;
61+
};
62+
63+
static void show_ibm_smart_log(struct nvme_ibm_additional_smart_log *smart, const char *devname)
64+
{
65+
int i, entries = (sizeof(struct nvme_ibm_additional_smart_log) - 4)
66+
/ sizeof(struct nvme_ibm_log_f0_item);
67+
struct nvme_ibm_log_f0_item *entry;
68+
69+
entry = &smart->read_err_rate;
70+
71+
printf("Additional IBM Smart Log for NVME device:%s\n", devname);
72+
73+
for (i = 0; i < entries; i++, entry++) {
74+
switch (le16_to_cpu(entry->attr)) {
75+
case 0x0001:
76+
printf("Total UC Read Errors : %"PRIu64"\n",
77+
le64_to_cpu(smart->read_err_rate.raw1));
78+
printf("Total Reads vs Read Errors : %"PRIu64"\n",
79+
le64_to_cpu(smart->read_err_rate.raw2));
80+
break;
81+
case 0x0005:
82+
printf("Total Retired Blks : %"PRIu64"\n",
83+
le64_to_cpu(smart->retired_clk_cnt.raw1));
84+
break;
85+
case 0x0009:
86+
printf("Total Power On Hours : %"PRIu64"\n",
87+
le64_to_cpu(smart->power_on_hours.raw1));
88+
printf("Time since Last P/C(ms) : %"PRIu64"\n",
89+
le64_to_cpu(smart->power_on_hours.raw2));
90+
break;
91+
case 0x000c:
92+
printf("Total Number of Power Cycles : %"PRIu64"\n",
93+
le64_to_cpu(smart->power_cycle_cnt.raw1));
94+
break;
95+
case 0x000d:
96+
printf("Read (ECC) Errors recov nodelay : %"PRIu64"\n",
97+
le64_to_cpu(smart->ecc_rate.raw1));
98+
printf("Total Reads vs Read Errs nodelay : %"PRIu64"\n",
99+
le64_to_cpu(smart->ecc_rate.raw2));
100+
break;
101+
case 0x0064:
102+
printf("Total MB Erased : %"PRIu64"\n",
103+
le64_to_cpu(smart->mb_erased.raw1));
104+
break;
105+
case 0x00aa:
106+
printf("Unused Rsv Blk 100*Cur/Mfg Spares : %"PRIu64"\n",
107+
le64_to_cpu(smart->unused_rsvd_blk_cnt_percent.raw1));
108+
printf("Current Spares : %"PRIu32"\n",
109+
le32_to_cpu(smart->unused_rsvd_blk_cnt_percent.split_raw2.upper));
110+
printf("Total Spares @ Mfg : %"PRIu32"\n",
111+
le32_to_cpu(smart->unused_rsvd_blk_cnt_percent.split_raw2.lower));
112+
break;
113+
case 0x00ab:
114+
printf("Total Number of Program Fails : %"PRIu64"\n",
115+
le64_to_cpu(smart->progrm_fail_cnt.raw1));
116+
printf("Program fails since Power Cycle : %"PRIu64"\n",
117+
le64_to_cpu(smart->progrm_fail_cnt.raw2));
118+
break;
119+
case 0x00ac:
120+
printf("Total Number of Erase Fails : %"PRIu64"\n",
121+
le64_to_cpu(smart->erase_fail_cnt.raw1));
122+
printf("Erase fails since Power Cycle : %"PRIu64"\n",
123+
le64_to_cpu(smart->erase_fail_cnt.raw2));
124+
break;
125+
case 0x00b1:
126+
printf("Life remaining percent : %"PRIu64"\n",
127+
le64_to_cpu(smart->drive_life_remain_percent.raw1));
128+
printf("PE Cycles most : %"PRIu32"\n",
129+
le32_to_cpu(smart->drive_life_remain_percent.split_raw2.upper));
130+
printf("PE Cycles least : %"PRIu32"\n",
131+
le32_to_cpu(smart->drive_life_remain_percent.split_raw2.lower));
132+
break;
133+
case 0x00b8:
134+
printf("Total number of IOEDC : %"PRIu64"\n",
135+
le64_to_cpu(smart->io_err_det_code_events.raw1));
136+
break;
137+
case 0x00bb:
138+
printf("Total number of UC Errors : %"PRIu64"\n",
139+
le64_to_cpu(smart->reported_uc_errs.raw1));
140+
break;
141+
case 0x00be:
142+
printf("Current Temperature (in C) : %"PRIu64"\n",
143+
le64_to_cpu(smart->drive_temperature.raw1));
144+
printf("Highest Temperature since Power ON : %"PRIu32"\n",
145+
le32_to_cpu(smart->drive_temperature.split_raw2.upper));
146+
printf("Lowest Temperature since Power ON : %"PRIu32"\n",
147+
le32_to_cpu(smart->drive_temperature.split_raw2.lower));
148+
break;
149+
case 0x00bf:
150+
printf("Percentage throttled : %"PRIu64"\n",
151+
le64_to_cpu(smart->thermal_throt.raw1));
152+
printf("Thermal throttling starts : %"PRIu32"\n",
153+
le32_to_cpu(smart->thermal_throt.split_raw2.upper));
154+
printf("Thermal throttling stops : %"PRIu32"\n",
155+
le32_to_cpu(smart->thermal_throt.split_raw2.lower));
156+
break;
157+
case 0x00c2:
158+
printf("PON Time in mins Highest Temperature: %"PRIu32"\n",
159+
le32_to_cpu(smart->drive_life_temp.split_raw1.upper));
160+
printf("PON Time in mins Lowest Temperature : %"PRIu32"\n",
161+
le32_to_cpu(smart->drive_life_temp.split_raw1.lower));
162+
printf("Highest Lifetime Temperature (in C) : %"PRIu32"\n",
163+
le32_to_cpu(smart->drive_life_temp.split_raw2.upper));
164+
printf("Lowest Lifetime Temperature (in C) : %"PRIu32"\n",
165+
le32_to_cpu(smart->drive_life_temp.split_raw2.lower));
166+
break;
167+
case 0x00c3:
168+
printf("Internal RAID Correctable Error : %"PRIu64"\n",
169+
le64_to_cpu(smart->int_raid_correct_err_cnt.raw1));
170+
break;
171+
case 0x00e7:
172+
printf("Life used in percentage : %"PRIu64"\n",
173+
le64_to_cpu(smart->ssd_life_used.raw1));
174+
printf("Average PE Cycles of Flash : %"PRIu64"\n",
175+
le64_to_cpu(smart->ssd_life_used.raw2));
176+
break;
177+
case 0x00e8:
178+
printf("Accurate Life used in percentage : %"PRIu64".%"PRIu64"\n",
179+
le64_to_cpu(smart->ssd_life_used_accurate.raw1)/100,
180+
le64_to_cpu(smart->ssd_life_used_accurate.raw1)%100);
181+
break;
182+
case 0x00e9:
183+
printf("Lifetime Writes to flash in MB : %"PRIu64"\n",
184+
le64_to_cpu(smart->lifetime_wr_to_flash_mb.raw1));
185+
break;
186+
case 0x00ea:
187+
printf("Lifetime Read from flash in MB : %"PRIu64"\n",
188+
le64_to_cpu(smart->lifetime_rd_from_flash_mb.raw1));
189+
break;
190+
case 0x00f1:
191+
printf("Lifetime Writes from Host in MB : %"PRIu64"\n",
192+
le64_to_cpu(smart->lifetime_wr_from_host_mb.raw1));
193+
break;
194+
case 0x00f2:
195+
printf("Lifetime Read to Host in MB : %"PRIu64"\n",
196+
le64_to_cpu(smart->lifetime_rd_to_host_mb.raw1));
197+
break;
198+
case 0x00f3:
199+
printf("Vol. Memory Backup Failures : %"PRIu64"\n",
200+
le64_to_cpu(smart->vol_mem_backup_fail.raw1));
201+
break;
202+
case 0x00f4:
203+
printf("Security Wear Indicator : %"PRIu64"\n",
204+
le64_to_cpu(smart->security_wear_indicator.raw1));
205+
break;
206+
case 0x00f5:
207+
printf("PCIe Received Errors : %"PRIu32"\n",
208+
le32_to_cpu(smart->device_pcie_received_errors.split_raw1.upper));
209+
printf("PCIe Received Bad TLP : %"PRIu32"\n",
210+
le32_to_cpu(smart->device_pcie_received_errors.split_raw1.lower));
211+
printf("PCIe Received Bad DLLP : %"PRIu32"\n",
212+
le32_to_cpu(smart->device_pcie_received_errors.split_raw2.upper));
213+
printf("PCIe Recd Transitions to Recoveries : %"PRIu32"\n",
214+
le32_to_cpu(smart->device_pcie_received_errors.split_raw2.lower));
215+
default:
216+
break;
217+
}
218+
}
219+
}
220+
221+
static int get_ibm_addi_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
222+
{
223+
const char *desc = "Get IBM specific additional smart log and show it.";
224+
const char *raw = "Dump output in binary format";
225+
226+
struct nvme_ibm_additional_smart_log smart_log;
227+
struct nvme_dev *dev;
228+
int err;
229+
230+
struct config {
231+
bool raw_binary;
232+
};
233+
234+
struct config cfg = {
235+
.raw_binary = 0,
236+
};
237+
238+
OPT_ARGS(opts) = {
239+
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
240+
OPT_END()
241+
};
242+
243+
err = parse_and_open(&dev, argc, argv, desc, opts);
244+
if (err)
245+
return err;
246+
247+
err = nvme_get_log_simple(dev_fd(dev), 0xf0, sizeof(smart_log), &smart_log);
248+
249+
if (!err) {
250+
if (!cfg.raw_binary)
251+
show_ibm_smart_log(&smart_log, dev->name);
252+
else
253+
d_raw((unsigned char *)&smart_log, sizeof(smart_log));
254+
} else if (err > 0)
255+
nvme_show_status(err);
256+
else
257+
nvme_show_error("ibm additional smart log: %s\n", nvme_strerror(errno));
258+
259+
dev_close(dev);
260+
return err;
261+
}
262+
263+
#pragma pack(push, 1)
264+
struct nvme_ibm_vpd_log {
265+
char version[4];
266+
char description[40];
267+
char masterpn[12];
268+
char ec[10];
269+
char fru[12];
270+
char finalasm[12];
271+
char fc[4];
272+
char ccin[4];
273+
char ibm11s[8];
274+
char ssid[8];
275+
char endurance[4];
276+
char capacity[10];
277+
char warranty[12];
278+
char encryption[1];
279+
char rctt[2];
280+
char loadid[8];
281+
char mfgloc[3];
282+
char ffc[5];
283+
char iotimeout[2];
284+
char formattimeout[4];
285+
char ioqs[4];
286+
char mediatype[2];
287+
char mfgsn[20];
288+
char firmware[8];
289+
char pad[4];
290+
};
291+
#pragma pack(pop)
292+
293+
#define MEDIATYPE 3
294+
static void show_ibm_vpd_log(struct nvme_ibm_vpd_log *vpd, const char *devname)
295+
{
296+
struct nvme_ibm_vpd_log vpdlog;
297+
char *mediatype[MEDIATYPE][2] = {
298+
{ "00", "NAND TLC" },
299+
{ "01", "3DXP" },
300+
{ "02", "LL NAND" }
301+
};
302+
303+
printf("IBM VPD for NVME device:%s\n", devname);
304+
printf("VPD Log Page Version : %.*s\n", (int)sizeof(vpdlog.version),
305+
vpd->version);
306+
printf("Description or ID : %.*s\n", (int)sizeof(vpdlog.description),
307+
vpd->description);
308+
printf("Master Part Number : %.*s\n", (int)sizeof(vpdlog.masterpn),
309+
vpd->masterpn);
310+
printf("EC Level : %.*s\n", (int)sizeof(vpdlog.ec), vpd->ec);
311+
printf("FRU Part Number : %.*s\n", (int)sizeof(vpdlog.fru), vpd->fru);
312+
printf("Final Assembly PN : %.*s\n", (int)sizeof(vpdlog.finalasm),
313+
vpd->finalasm);
314+
printf("Feature Code : %.*s\n", (int)sizeof(vpdlog.fc), vpd->fc);
315+
printf("CCIN : %.*s\n", (int)sizeof(vpdlog.ccin), vpd->ccin);
316+
printf("11S Serial Number : 11S%.*sY%.*s%.*s\n", 7, vpd->masterpn,
317+
(int)sizeof(vpdlog.mfgloc), vpd->mfgloc, (int)sizeof(vpdlog.ibm11s),
318+
vpd->ibm11s);
319+
printf("PCI SSID : %.*s\n", (int)sizeof(vpdlog.ssid), vpd->ssid);
320+
printf("Endurance (DWPD) : %.*s\n", (int)sizeof(vpdlog.endurance),
321+
vpd->endurance);
322+
printf("Capacity (GB) : %.*s\n", (int)sizeof(vpdlog.capacity),
323+
vpd->capacity);
324+
printf("Warranty (Peta Bytes Written) : %.*s\n", (int)sizeof(vpdlog.warranty),
325+
vpd->warranty);
326+
printf("Encryption (0=not supported) : %.*s\n", (int)sizeof(vpdlog.encryption),
327+
vpd->encryption);
328+
printf("RCTT : %.*s\n", (int)sizeof(vpdlog.rctt), vpd->rctt);
329+
printf("Load ID : %.*s\n", (int)sizeof(vpdlog.loadid), vpd->loadid);
330+
printf("MFG Location : %.*s\n", (int)sizeof(vpdlog.mfgloc),
331+
vpd->mfgloc);
332+
printf("FFC : %.*s\n", (int)sizeof(vpdlog.ffc), vpd->ffc);
333+
printf("IO Timeout in Seconds : 0x%.*s\n", (int)sizeof(vpdlog.iotimeout),
334+
vpd->iotimeout);
335+
printf("Format Timeout in Seconds : 0x%.*s\n", (int)sizeof(vpdlog.formattimeout),
336+
vpd->formattimeout);
337+
printf("Optimal Number of IO Queues : 0x%.*s\n", (int)sizeof(vpdlog.ioqs),
338+
vpd->ioqs);
339+
340+
for (int i = 0; i < MEDIATYPE; i++) {
341+
if (!strncmp(mediatype[i][0], vpd->mediatype, (int)sizeof(vpdlog.mediatype)))
342+
printf("Media Type : %.*s (%.*s)\n",
343+
(int)sizeof(mediatype[i][1]), mediatype[i][1],
344+
(int)sizeof(vpdlog.mediatype), vpd->mediatype);
345+
}
346+
347+
printf("Manufacturer Serial Number : %.*s\n", (int) sizeof(vpdlog.mfgsn), vpd->mfgsn);
348+
printf("Firmware version : %.*s\n", (int) sizeof(vpdlog.firmware),
349+
vpd->firmware);
350+
}
351+
352+
static int get_ibm_vpd_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
353+
{
354+
struct nvme_ibm_vpd_log vpd_log;
355+
int err;
356+
struct nvme_dev *dev;
357+
358+
const char *desc = "Get IBM vendor specific VPD log";
359+
const char *raw = "dump output in binary format";
360+
361+
struct config {
362+
int raw_binary;
363+
};
364+
365+
struct config cfg = {
366+
.raw_binary = 0,
367+
};
368+
369+
OPT_ARGS(opts) = {
370+
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
371+
OPT_END()
372+
};
373+
374+
err = parse_and_open(&dev, argc, argv, desc, opts);
375+
if (err < 0)
376+
return err;
377+
378+
bzero(&vpd_log, sizeof(vpd_log));
379+
err = nvme_get_log_simple(dev_fd(dev), 0xf1, sizeof(vpd_log), &vpd_log);
380+
381+
if (!err) {
382+
if (!cfg.raw_binary)
383+
show_ibm_vpd_log(&vpd_log, dev->name);
384+
else
385+
d_raw((unsigned char *)&vpd_log, sizeof(vpd_log));
386+
} else if (err > 0)
387+
nvme_show_status(err);
388+
else
389+
nvme_show_error("ibm vpd log: %s\n", nvme_strerror(errno));
390+
391+
dev_close(dev);
392+
return err;
393+
}

0 commit comments

Comments
 (0)