Bug Summary

File:.build-ci/../plugins/micron/micron-nvme.c
Warning:line 2429, column 11
Potential leak of memory pointed to by 'strPDir'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -O3 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name micron-nvme.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -fcoverage-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -resource-dir /usr/bin/../lib/clang/22 -include /__w/nvme-cli/nvme-cli/.build-ci/nvme-config.h -I nvme.p -I . -I .. -I src -I ../src -I ccan -I ../ccan -I libnvme/src -I ../libnvme/src -I /usr/include/json-c -D _FILE_OFFSET_BITS=64 -D _GNU_SOURCE -U NDEBUG -internal-isystem /usr/bin/../lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=gnu11 -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-opt-analyze-headers -analyzer-output=html -faddrsig -fdwarf2-cfi-asm -o /__w/nvme-cli/nvme-cli/.build-ci/scan-results/2026-09-23-073103-589-1 -x c ../plugins/micron/micron-nvme.c
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) Micron, Inc 2024.
4 *
5 * @file: micron-nvme.c
6 * @brief: This module contains all the constructs needed for micron nvme-cli plugin.
7 * @authors:Hanumanthu H <hanumanthuh@micron.com>
8 * Chaithanya Shoba <ashoba@micron.com>
9 * Sivaprasad Gutha <sivaprasadg@micron.com>
10 */
11
12#include <ctype.h>
13#include <dirent.h>
14#include <errno(*__errno_location ()).h>
15#include <fcntl.h>
16#include <inttypes.h>
17#include <libgen.h>
18#include <limits.h>
19#include <stddef.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <sys/stat.h>
24#include <sys/types.h>
25#include <time.h>
26#include <unistd.h>
27
28#include <libnvme.h>
29
30#include <ccan/array_size/array_size.h>
31#include <ccan/endian/endian.h>
32#include <ccan/minmax/minmax.h>
33#include <shared/compiler-attributes-util.h>
34#include <shared/fs-util.h>
35#include <shared/string-util.h>
36#include <shared/uint128-util.h>
37
38#include "field-parser.h"
39#include "global-ctx.h"
40#include "micron-utils.h"
41#include "nvme-cmds.h"
42#include "nvme-pci-ids.h"
43#include "nvme-print.h"
44#include "plugin.h"
45#include "src/cleanup.h"
46
47/* Supported Vendor specific feature ids */
48#define MICRON_FEATURE_CLEAR_PCI_CORRECTABLE_ERRORS0xC3 0xC3
49#define MICRON_FEATURE_CLEAR_FW_ACTIVATION_HISTORY0xC1 0xC1
50#define MICRON_FEATURE_TELEMETRY_CONTROL_OPTION0xCF 0xCF
51#define MICRON_FEATURE_SMBUS_OPTION0xD5 0xD5
52#define MICRON_FEATURE_OCP_ENHANCED_TELEMETRY0x16 0x16
53
54/* Micron Supported Customer ID*/
55#define MICRON_CUST_ID_GENERAL0x10 0x10
56#define MICRON_CUST_ID_GG0x16 0x16
57
58/* Supported Vendor specific log page sizes */
59#define C5_log_size(((452 + 16 * 1024) / 4) * 4096) (((452 + 16 * 1024) / 4) * 4096)
60#define C0_log_size512 512
61#define C2_log_size4096 4096
62#define D0_log_size512 512
63#define FB_log_size512 512
64#define E1_log_size256 256
65#define MaxLogChunk(16 * 1024) (16 * 1024)
66#define CommonChunkSize(16 * 4096) (16 * 4096)
67#define C6_log_size512 512
68#define C5_MicronWorkLoad_log_size256 256
69
70#define SensorCount8 8
71
72/* Plugin version major_number.minor_number.patch */
73static const char *__version_major = "3";
74static const char *__version_minor = "0";
75static const char *__version_patch = "0";
76
77/*
78 * supported models of micron plugin; new models should be added at the end
79 * before UNKNOWN_MODEL. Make sure M5410 is first in the list !
80 */
81enum eDriveModel {
82 M5410 = 0,
83 M51AX,
84 M51BX,
85 M51BY,
86 M51CY,
87 M51CX,
88 M5407,
89 M5411,
90 M6001,
91 M6003,
92 M6004,
93 UNKNOWN_MODEL
94};
95
96#define MICRON_VENDOR_ID0x1344 0x1344
97
98static unsigned short vendor_id;
99static unsigned short device_id;
100
101/* Additional log page IDs */
102#define NVME_LOG_PERSISTENT_EVENT0xD 0xD
103
104struct LogPageHeader_t {
105 unsigned char numDwordsInLogPageHeaderLo;
106 unsigned char logPageHeaderFormatVersion;
107 unsigned char logPageId;
108 unsigned char numDwordsInLogPageHeaderHi;
109 unsigned int numValidDwordsInPayload;
110 unsigned int numDwordsInEntireLogPage;
111};
112
113struct MICRON_WORKLOAD_LOG_HDR {
114 unsigned short usNumEntries;
115 unsigned short usVersion;
116 unsigned int uiLength;
117};
118
119static void WriteData(__u8 *data, __u32 len, const char *dir, const char *file, const char *msg)
120{
121 __cleanup_free__attribute__((cleanup(shr_freep))) char *tempFolder = NULL((void*)0);
122 FILE *fpOutFile = NULL((void*)0);
123 int ret;
124
125 if (dir)
126 ret = asprintf(&tempFolder, "%s/%s", dir, file);
127 else
128 ret = asprintf(&tempFolder, "%s", file);
129 if (ret < 0) {
130 nvme_show_error("Failed to allocate memory for temp folder path")nvme_show_message(1, "Failed to allocate memory for temp folder path"
)
;
131 return;
132 }
133 fpOutFile = fopen(tempFolder, "ab+");
134 if (fpOutFile) {
135 if (fwrite(data, 1, len, fpOutFile) != len)
136 nvme_show_error("Failed to write %s data to %s", msg, tempFolder)nvme_show_message(1, "Failed to write %s data to %s", msg, tempFolder
)
;
137 fclose(fpOutFile);
138 } else {
139 nvme_show_error("Failed to open %s file to write %s", tempFolder, msg)nvme_show_message(1, "Failed to open %s file to write %s", tempFolder
, msg)
;
140 }
141}
142
143static enum eDriveModel GetDriveModel(
144 struct libnvme_global_ctx *ctx,
145 struct libnvme_transport_handle *hdl)
146{
147 enum eDriveModel eModel = UNKNOWN_MODEL;
148 uint32_t vid = 0, did = 0;
149
150 nvme_get_pci_ids(ctx, hdl, &vid, &did, NULL((void*)0), NULL((void*)0), NULL((void*)0));
151 vendor_id = (unsigned short)vid;
152 device_id = (unsigned short)did;
153
154 if (vendor_id == MICRON_VENDOR_ID0x1344) {
155 switch (device_id) {
156 case 0x5196:
157 case 0x51A0:
158 case 0x51A1:
159 case 0x51A2:
160 eModel = M51AX;
161 break;
162 case 0x51B0:
163 case 0x51B1:
164 case 0x51B2:
165 eModel = M51BX;
166 break;
167 case 0x51B7:
168 case 0x51B8:
169 case 0x51B9:
170 eModel = M51BY;
171 break;
172 case 0x51BB:
173 case 0x51BD:
174 case 0x51BC:
175 case 0x51BE:
176 case 0x51BF:
177 case 0x51C8:
178 case 0x51C9:
179 case 0x51CA:
180 case 0x51CB:
181 case 0x51CC:
182 case 0x51CD:
183 case 0x51CE:
184 eModel = M51CY;
185 break;
186 case 0x51C0:
187 case 0x51C1:
188 case 0x51C2:
189 case 0x51C3:
190 case 0x51C4:
191 eModel = M51CX;
192 break;
193 case 0x5405:
194 case 0x5406:
195 case 0x5407:
196 eModel = M5407;
197 break;
198 case 0x5410:
199 eModel = M5410;
200 break;
201 case 0x5411:
202 eModel = M5411;
203 break;
204 case 0x6001:
205 eModel = M6001;
206 break;
207 case 0x6004:
208 eModel = M6004;
209 break;
210 case 0x6003:
211 eModel = M6003;
212 break;
213 default:
214 break;
215 }
216 }
217 return eModel;
218}
219
220/*
221 * sanitize_serial - trim trailing spaces, null-terminate, and replace any
222 * characters that are not alphanumeric, hyphen, or underscore with underscores.
223 */
224static void sanitize_serial(char *sn, size_t len)
225{
226 size_t i;
227 size_t end;
228
229 if (!sn || len == 0)
230 return;
231
232 end = len - 1;
233 while (end > 0 && isblank((unsigned char)sn[end - 1])((*__ctype_b_loc ())[(int) (((unsigned char)sn[end - 1]))] &
(unsigned short int) _ISblank)
)
234 end--;
235 sn[end] = '\0';
236
237 for (i = 0; i < end; i++) {
238 if (!((sn[i] >= 'A' && sn[i] <= 'Z') ||
239 (sn[i] >= 'a' && sn[i] <= 'z') ||
240 (sn[i] >= '0' && sn[i] <= '9') ||
241 sn[i] == '-' || sn[i] == '_'))
242 sn[i] = '_';
243 }
244}
245
246/*
247 * is_safe_path - validate that a path string is safe for use as a filename.
248 *
249 * Rejects control characters (0x00-0x1F), characters invalid on Windows
250 * filesystems (<>"|?*), paths starting with '-' which could be
251 * misinterpreted as flags by tar/zip, and trailing backslashes which
252 * would escape the closing quote in Windows command-line argument parsing.
253 */
254static bool_Bool is_safe_path(const char *path)
255{
256 /* Lookup table: 1 = rejected character */
257 static const unsigned char rejected[256] = {
258 [0x01 ... 0x1F] = 1, /* control characters */
259 ['<'] = 1,
260 ['>'] = 1,
261 ['"'] = 1,
262 ['|'] = 1,
263 ['?'] = 1,
264 ['*'] = 1,
265 };
266 const unsigned char *p = (const unsigned char *)path;
267
268 if (!path || !*path)
269 return false0;
270
271 if (path[0] == '-')
272 return false0;
273
274 for (; *p; p++) {
275 if (rejected[*p])
276 return false0;
277 }
278
279 if (p > (const unsigned char *)path && p[-1] == '\\')
280 return false0;
281
282 return true1;
283}
284
285/*
286 * Recursively remove a directory and its contents.
287 * Since this is only used for temporary directories that we create that
288 * have no symlinks, it is safe to not check for and handle symlinks here.
289 */
290static int RemoveDirRecursive(const char *path)
291{
292 DIR *dir = NULL((void*)0);
293 struct dirent *entry;
294 char child[PATH_MAX4096];
295
296 dir = opendir(path);
297 if (!dir) {
298 if (errno(*__errno_location ()) == ENOENT2)
299 return 0;
300 return -1;
301 }
302
303 while ((entry = readdir(dir))) {
304 if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
305 continue;
306
307 if (snprintf(child, sizeof(child), "%s/%s", path, entry->d_name) >=
308 (int)sizeof(child)) {
309 closedir(dir);
310 errno(*__errno_location ()) = ENAMETOOLONG36;
311 return -1;
312 }
313
314 if (unlink(child) == 0 || errno(*__errno_location ()) == ENOENT2)
315 continue;
316
317 /*
318 * On Linux, unlinking a directory fails with EISDIR or EPERM.
319 * On Windows, it fails with EACCES. In all cases, fall through
320 * to attempt recursive removal.
321 */
322 if (errno(*__errno_location ()) != EISDIR21 && errno(*__errno_location ()) != EPERM1 && errno(*__errno_location ()) != EACCES13) {
323 int saved_errno = errno(*__errno_location ());
324
325 closedir(dir);
326 errno(*__errno_location ()) = saved_errno;
327 return -1;
328 }
329
330 if (RemoveDirRecursive(child) < 0) {
331 int saved_errno = errno(*__errno_location ());
332
333 if (saved_errno == ENOENT2)
334 continue;
335 closedir(dir);
336 errno(*__errno_location ()) = saved_errno;
337 return -1;
338 }
339 }
340
341 closedir(dir);
342
343 if (rmdir(path) < 0 && errno(*__errno_location ()) != ENOENT2)
344 return -1;
345
346 return 0;
347}
348
349/*
350 * bsdtar-based versions of tar support creating zip archives when -a is used
351 * with a .zip extension. Check if bsdtar is available and use it to create the
352 * requested zip archive.
353 *
354 * Returns 0 on success, or a negative errno value if tar is not bsdtar
355 * or if the command fails.
356 */
357static int ZipWithBsdTar(char *strDirName, char *strFileName)
358{
359 FILE *fpVersion = NULL((void*)0);
360 char version_buf[256] = { 0 };
361 bool_Bool is_bsdtar = false0;
362
363 fpVersion = popen("tar --version 2>&1", "r");
364 if (!fpVersion)
365 return -EINVAL22;
366
367 while (fgets(version_buf, sizeof(version_buf), fpVersion)) {
368 if (strstr(version_buf, "bsdtar")_Generic (0 ? (version_buf) : (void *) 1, const void *: (const
char *) (strstr (version_buf, "bsdtar")), default: strstr (version_buf
, "bsdtar"))
) {
369 is_bsdtar = true1;
370 break;
371 }
372 }
373
374 if (pclose(fpVersion))
375 return -EINVAL22;
376 fpVersion = NULL((void*)0);
377
378 if (!is_bsdtar)
379 return -EINVAL22;
380
381 char *argv[] = {"tar", "-caf", strFileName, "--", strDirName, NULL((void*)0)};
382
383 return micron_run_spawn(argv, NULL((void*)0), false0);
384}
385
386static int ZipAndRemoveDir(char *strDirName, char *strFileName)
387{
388 int err = 0;
389 int nRet;
390 bool_Bool is_tgz = false0;
391 struct stat sb;
392
393 if (strstr(strFileName, ".tar.gz")_Generic (0 ? (strFileName) : (void *) 1, const void *: (const
char *) (strstr (strFileName, ".tar.gz")), default: strstr (
strFileName, ".tar.gz"))
|| strstr(strFileName, ".tgz")_Generic (0 ? (strFileName) : (void *) 1, const void *: (const
char *) (strstr (strFileName, ".tgz")), default: strstr (strFileName
, ".tgz"))
) {
394 char *argv[] = {"tar", "-zcf", strFileName, "--", strDirName, NULL((void*)0)};
395
396 is_tgz = true1;
397 nRet = micron_run_spawn(argv, NULL((void*)0), false0);
398 } else {
399 char *argv[] = {"zip", "-q", "-r", strFileName, "--", strDirName, NULL((void*)0)};
400
401 nRet = micron_run_spawn(argv, NULL((void*)0), false0);
402 }
403
404 if (nRet && !is_tgz)
405 /* if zip is not available, see if tar can be used instead */
406 nRet = ZipWithBsdTar(strDirName, strFileName);
407
408 /* check if log file is created, if not print error message */
409 if (nRet || (stat(strFileName, &sb) == -1)) {
410 err = -EINVAL22;
411 if (is_tgz)
412 nvme_show_error("Failed to create log data package, "nvme_show_message(1, "Failed to create log data package, " "check if tar and gzip commands are installed!\n"
)
413 "check if tar and gzip commands are installed!\n")nvme_show_message(1, "Failed to create log data package, " "check if tar and gzip commands are installed!\n"
)
;
414 else
415 nvme_show_error("Failed to create log data package, "nvme_show_message(1, "Failed to create log data package, " "check if zip command is installed!\n"
)
416 "check if zip command is installed!\n")nvme_show_message(1, "Failed to create log data package, " "check if zip command is installed!\n"
)
;
417 }
418
419 if (RemoveDirRecursive(strDirName) < 0)
420 nvme_show_error("Failed to remove temporary files!")nvme_show_message(1, "Failed to remove temporary files!");
421
422 return err;
423}
424
425static int SetupDebugDataDirectories(char *strSN, char *strFilePath,
426 char *strMainDirName, size_t mainDirSize,
427 char *strOSDirName, size_t osDirSize,
428 char *strCtrlDirName, size_t ctrlDirSize)
429{
430 int err = 0;
431 struct stat st;
432 char *fileLocation = NULL((void*)0);
433 char *fileName;
434 int length = 0;
435 int nIndex = 0;
436 char *strTemp = NULL((void*)0);
437 int j;
438 int k = 0;
439
440 if (strchr(strFilePath, '/')_Generic (0 ? (strFilePath) : (void *) 1, const void *: (const
char *) (strchr (strFilePath, '/')), default: strchr (strFilePath
, '/'))
) {
441 fileName = strrchr(strFilePath, '\\')_Generic (0 ? (strFilePath) : (void *) 1, const void *: (const
char *) (strrchr (strFilePath, '\\')), default: strrchr (strFilePath
, '\\'))
;
442 if (!fileName)
443 fileName = strrchr(strFilePath, '/')_Generic (0 ? (strFilePath) : (void *) 1, const void *: (const
char *) (strrchr (strFilePath, '/')), default: strrchr (strFilePath
, '/'))
;
444
445 if (fileName) {
446 if (!strcmp(fileName, "/")) {
447 err = -1;
448 goto exit_status;
449 }
450
451 while (strFilePath[nIndex] != '\0') {
452 if ('\\' == strFilePath[nIndex] && '\\' == strFilePath[nIndex + 1]) {
453 err = -1;
454 goto exit_status;
455 }
456 nIndex++;
457 }
458
459 length = (int)strlen(strFilePath) - (int)strlen(fileName);
460
461 if (fileName == strFilePath)
462 length = 1;
463
464 fileLocation = (char *)malloc(length + 1);
465 if (!fileLocation) {
466 err = -1;
467 goto exit_status;
468 }
469 strncpy(fileLocation, strFilePath, length);
470 fileLocation[length] = '\0';
471
472 while (fileLocation[k] != '\0') {
473 if (fileLocation[k] == '\\')
474 fileLocation[k] = '/';
475 k++;
476 }
477
478 length = (int)strlen(fileLocation);
479
480 if (':' == fileLocation[length - 1]) {
481 strTemp = realloc(fileLocation, length + 2);
482
483 if (!strTemp) {
484 free(fileLocation);
485 err = -1;
486 goto exit_status;
487 }
488 fileLocation = strTemp;
489 fileLocation[length] = '/';
490 fileLocation[length + 1] = '\0';
491 length++;
492 }
493
494 if (stat(fileLocation, &st)) {
495 free(fileLocation);
496 err = -1;
497 goto exit_status;
498 }
499 free(fileLocation);
500 } else {
501 err = -1;
502 goto exit_status;
503 }
504 }
505
506 snprintf(strMainDirName, mainDirSize, "%s", strSN);
507 nIndex = strlen(strMainDirName);
508
509 j = 1;
510 while (shr_mkdir(strMainDirName, 0700) < 0) {
511 if (errno(*__errno_location ()) != EEXIST17) {
512 err = -1;
513 goto exit_status;
514 }
515 strMainDirName[nIndex] = '\0';
516 snprintf(strMainDirName + nIndex, mainDirSize - nIndex, "-%d", j);
517 j++;
518 }
519
520 if (strOSDirName) {
521 snprintf(strOSDirName, osDirSize, "%s/%s", strMainDirName, "OS");
522 if (shr_mkdir(strOSDirName, 0700) < 0) {
523 rmdir(strMainDirName);
524 err = -1;
525 goto exit_status;
526 }
527 }
528 if (strCtrlDirName) {
529 snprintf(strCtrlDirName, ctrlDirSize, "%s/%s", strMainDirName, "Controller");
530 if (shr_mkdir(strCtrlDirName, 0700) < 0) {
531 if (strOSDirName)
532 rmdir(strOSDirName);
533 rmdir(strMainDirName);
534 err = -1;
535 }
536 }
537
538exit_status:
539 return err;
540}
541
542static int GetLogPageSize(struct libnvme_transport_handle *hdl, unsigned char ucLogID, int *nLogSize)
543{
544 int err = 0;
545 unsigned char pTmpBuf[CommonChunkSize(16 * 4096)] = { 0 };
546 struct LogPageHeader_t *pLogHeader = NULL((void*)0);
547
548 if (ucLogID == 0xC1 || ucLogID == 0xC2 || ucLogID == 0xC4) {
549 err = nvme_get_log_simple(hdl, ucLogID, pTmpBuf, CommonChunkSize(16 * 4096));
550 if (!err) {
551 pLogHeader = (struct LogPageHeader_t *) pTmpBuf;
552 struct LogPageHeader_t *pLogHeader1 = (struct LogPageHeader_t *) pLogHeader;
553 *nLogSize = (int)(pLogHeader1->numDwordsInEntireLogPage) * 4;
554 if (!pLogHeader1->logPageHeaderFormatVersion) {
555 nvme_show_error("Unsupported log page format version %d of log page : 0x%X",nvme_show_message(1, "Unsupported log page format version %d of log page : 0x%X"
, ucLogID, err)
556 ucLogID, err)nvme_show_message(1, "Unsupported log page format version %d of log page : 0x%X"
, ucLogID, err)
;
557 *nLogSize = 0;
558 err = -1;
559 }
560 } else {
561 nvme_show_error("Getting size of log page : 0x%X failed with %d (ignored)!",nvme_show_message(1, "Getting size of log page : 0x%X failed with %d (ignored)!"
, ucLogID, err)
562 ucLogID, err)nvme_show_message(1, "Getting size of log page : 0x%X failed with %d (ignored)!"
, ucLogID, err)
;
563 *nLogSize = 0;
564 }
565 }
566 return err;
567}
568
569static int NVMEGetLogPage(struct libnvme_transport_handle *hdl, unsigned char ucLogID, unsigned char *pBuffer, int nBuffSize,
570 int offset)
571{
572 int err = 0;
573 struct libnvme_passthru_cmd cmd = { 0 };
574 unsigned int uiNumDwords = (unsigned int)nBuffSize / sizeof(unsigned int);
575 unsigned int uiMaxChunk = uiNumDwords;
576 unsigned int uiNumChunks = 1;
577 unsigned int uiXferDwords = 0;
578 unsigned long long ullBytesRead = offset;
579 unsigned char *pTempPtr = pBuffer;
580 unsigned char ucOpCode = 0x02;
581
582 if (!ullBytesRead && (ucLogID == 0xE6 || ucLogID == 0xE7))
583 uiMaxChunk = 4096;
584 else if (uiMaxChunk > 16 * 1024)
585 uiMaxChunk = 16 * 1024;
586
587 if (ucLogID == 0xE9) {
588 uiMaxChunk = 0x1D8C;
589 ullBytesRead = offset;
590 }
591
592 uiNumChunks = uiNumDwords / uiMaxChunk;
593 if (uiNumDwords % uiMaxChunk > 0)
594 uiNumChunks += 1;
595
596 for (unsigned int i = 0; i < uiNumChunks; i++) {
597 memset(&cmd, 0, sizeof(cmd));
598 uiXferDwords = uiMaxChunk;
599 if (i == uiNumChunks - 1 && uiNumDwords % uiMaxChunk > 0)
600 uiXferDwords = uiNumDwords % uiMaxChunk;
601
602 cmd.opcode = ucOpCode;
603 cmd.cdw10 |= ucLogID;
604 cmd.cdw10 |= ((uiXferDwords - 1) & 0x0000FFFF) << 16;
605
606 if (ucLogID == 0x7 && offset == 0)
607 cmd.cdw10 |= 0x100;
608
609 if (!ullBytesRead && (ucLogID == 0xE6 || ucLogID == 0xE7))
610 cmd.cdw11 = 1;
611 if (ullBytesRead > 0 && !(ucLogID == 0xE6 || ucLogID == 0xE7)) {
612 unsigned long long ullOffset = ullBytesRead;
613
614 cmd.cdw12 = ullOffset & 0xFFFFFFFF;
615 cmd.cdw13 = (ullOffset >> 32) & 0xFFFFFFFF;
616 }
617
618 cmd.addr = (__u64) (uintptr_t) pTempPtr;
619 cmd.nsid = 0xFFFFFFFF;
620 cmd.data_len = uiXferDwords * 4;
621 err = libnvme_exec_admin_passthru(hdl, &cmd);
622 ullBytesRead += uiXferDwords * 4;
623 if (ucLogID == 0x07 || ucLogID == 0x08 || ucLogID == 0xE9)
624 pTempPtr = pBuffer + (ullBytesRead - offset);
625 else
626 pTempPtr = pBuffer + ullBytesRead;
627 }
628
629 return err;
630}
631
632static int NVMEResetLog(struct libnvme_transport_handle *hdl, unsigned char ucLogID, int nBufferSize,
633 long long llMaxSize)
634{
635 __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) unsigned int *pBuffer = NULL((void*)0);
636 int err = 0;
637
638 pBuffer = (unsigned int *)libnvme_alloc(nBufferSize);
639 if (!pBuffer)
640 return err;
641
642 while (!err && llMaxSize > 0) {
643 err = NVMEGetLogPage(hdl, ucLogID, (unsigned char *)pBuffer, nBufferSize, 0);
644 if (err)
645 return err;
646
647 if (pBuffer[0] == 0xdeadbeef)
648 break;
649
650 llMaxSize = llMaxSize - nBufferSize;
651 }
652
653 return err;
654}
655
656static int GetCommonLogPage(struct libnvme_transport_handle *hdl, unsigned char ucLogID,
657 unsigned char **pBuffer, int nBuffSize)
658{
659 unsigned char *pTempPtr = NULL((void*)0);
660 int err = 0;
661
662 pTempPtr = (unsigned char *)libnvme_alloc(nBuffSize);
663 if (!pTempPtr) {
664 err = -ENOMEM12;
665 goto exit_status;
666 }
667 err = nvme_get_log_simple(hdl, ucLogID, pTempPtr, nBuffSize);
668 *pBuffer = pTempPtr;
669
670exit_status:
671 return err;
672}
673
674/*
675 * Plugin Commands
676 */
677static int micron_parse_options(struct libnvme_global_ctx **ctx,
678 struct libnvme_transport_handle **hdl, int argc,
679 char **argv, const char *desc,
680 struct argconfig_commandline_options *opts,
681 enum eDriveModel *modelp)
682{
683 int err = parse_and_open(ctx, hdl, argc, argv, desc, opts);
684
685 if (err)
686 return err;
687
688 if (modelp)
689 *modelp = GetDriveModel(*ctx, *hdl);
690
691 return 0;
692}
693
694static int micron_fw_commit(struct libnvme_transport_handle *hdl, int select)
695{
696 struct libnvme_passthru_cmd cmd = {
697 .opcode = nvme_admin_fw_commit,
698 .cdw10 = 8,
699 .cdw12 = select,
700 };
701
702 return libnvme_exec_admin_passthru(hdl, &cmd);
703}
704
705static int micron_selective_download(int argc, char **argv,
706 struct command *command, struct plugin *plugin)
707{
708 const char *desc =
709 "This performs a selective firmware download, which allows the user to\n"
710 "select which firmware binary to update for 9200 devices. This requires\n"
711 "a power cycle once the update completes. The options available are:\n\n"
712 "OOB - This updates the OOB and main firmware\n"
713 "EEP - This updates the eeprom and main firmware\n"
714 "ALL - This updates the eeprom, OOB, and main firmware";
715 const char *fw = "firmware file (required)";
716 const char *select = "FW Select (e.g., --select=ALL)";
717
718 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
719 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
720
721 int selectNo, fw_fd, fw_size, err, offset = 0;
722 struct libnvme_passthru_cmd cmd;
723 int xfer = 4096;
724 struct stat sb;
725 __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) void *fw_buf = NULL((void*)0);
726 unsigned char *fw_ptr;
727
728 struct config {
729 char *fw;
730 char *select;
731 };
732
733 struct config cfg = {
734 .fw = "",
735 .select = "\0",
736 };
737
738 NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"fw", 'f', "FILE", CFG_STRING, &cfg.fw, 1, fw, 0,
}, {"select", 's', "flag", CFG_STRING, &cfg.select, 1, select
, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0
, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT
, &nvme_args.verbose, 0, "Increase output verbosity", 0, }
, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0,
"suppress informational output", 0, }, {"output-format", 'o'
, "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
739 OPT_STRING("fw", 'f', "FILE", &cfg.fw, fw),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"fw", 'f', "FILE", CFG_STRING, &cfg.fw, 1, fw, 0,
}, {"select", 's', "flag", CFG_STRING, &cfg.select, 1, select
, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0
, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT
, &nvme_args.verbose, 0, "Increase output verbosity", 0, }
, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0,
"suppress informational output", 0, }, {"output-format", 'o'
, "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
740 OPT_STRING("select", 's', "flag", &cfg.select, select))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"fw", 'f', "FILE", CFG_STRING, &cfg.fw, 1, fw, 0,
}, {"select", 's', "flag", CFG_STRING, &cfg.select, 1, select
, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0
, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT
, &nvme_args.verbose, 0, "Increase output verbosity", 0, }
, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0,
"suppress informational output", 0, }, {"output-format", 'o'
, "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
741
742 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
743 if (err)
744 return err;
745
746 if (strlen(cfg.select) != 3) {
747 nvme_show_error("Invalid select flag")nvme_show_message(1, "Invalid select flag");
748 return -EINVAL22;
749 }
750
751 for (int i = 0; i < 3; i++)
752 cfg.select[i] = toupper(cfg.select[i])(__extension__ ({ int __res; if (sizeof (cfg.select[i]) > 1
) { if (__builtin_constant_p (cfg.select[i])) { int __c = (cfg
.select[i]); __res = __c < -128 || __c > 255 ? __c : (*
__ctype_toupper_loc ())[__c]; } else __res = toupper (cfg.select
[i]); } else __res = (*__ctype_toupper_loc ())[(int) (cfg.select
[i])]; __res; }))
;
753
754 if (!strncmp(cfg.select, "OOB", 3)) {
755 selectNo = 18;
756 } else if (!strncmp(cfg.select, "EEP", 3)) {
757 selectNo = 10;
758 } else if (!strncmp(cfg.select, "ALL", 3)) {
759 selectNo = 26;
760 } else {
761 nvme_show_error("Invalid select flag")nvme_show_message(1, "Invalid select flag");
762 return -EINVAL22;
763 }
764
765 fw_fd = open(cfg.fw, O_RDONLY00);
766 if (fw_fd < 0) {
767 nvme_show_error("no firmware file provided")nvme_show_message(1, "no firmware file provided");
768 return -EINVAL22;
769 }
770
771 err = fstat(fw_fd, &sb);
772 if (err < 0) {
773 nvme_show_perror("fstat");
774 err = errno(*__errno_location ());
775 goto out;
776 }
777
778 fw_size = sb.st_size;
779 if (fw_size & 0x3) {
780 nvme_show_error("Invalid size:%d for f/w image", fw_size)nvme_show_message(1, "Invalid size:%d for f/w image", fw_size
)
;
781 err = EINVAL22;
782 goto out;
783 }
784
785 fw_buf = libnvme_alloc(fw_size);
786 if (!fw_buf) {
787 nvme_show_error("No memory for f/w size:%d", fw_size)nvme_show_message(1, "No memory for f/w size:%d", fw_size);
788 err = ENOMEM12;
789 goto out;
790 }
791 fw_ptr = fw_buf;
792
793 if (read(fw_fd, fw_buf, fw_size) != ((ssize_t) (fw_size))) {
794 err = errno(*__errno_location ());
795 goto out;
796 }
797
798 while (fw_size > 0) {
799 xfer = min(xfer, fw_size)({ typeof(xfer) _a = (xfer); typeof(fw_size) _b = (fw_size); do
{ } while (0); _a < _b ? _a : _b; })
;
800
801 err = nvme_init_fw_download(&cmd, fw_ptr, xfer, offset);
802 if (err) {
803 nvme_show_err(err, "fw-download");
804 goto out;
805 }
806 err = libnvme_exec_admin_passthru(hdl, &cmd);
807 if (err) {
808 nvme_show_err(err, "fw-download");
809 goto out;
810 }
811 fw_ptr += xfer;
812 fw_size -= xfer;
813 offset += xfer;
814 }
815
816 err = micron_fw_commit(hdl, selectNo);
817
818 if (err == 0x10B || err == 0x20B) {
819 err = 0;
820 nvme_show_error(nvme_show_message(1, "Update successful! Power cycle for changes to take effect\n"
)
821 "Update successful! Power cycle for changes to take effect\n")nvme_show_message(1, "Update successful! Power cycle for changes to take effect\n"
)
;
822 }
823
824out:
825 close(fw_fd);
826 return err;
827}
828
829static int micron_smbus_option(int argc, char **argv,
830 struct command *command, struct plugin *plugin)
831{
832 __u64 result = 0;
833 __u32 cdw11 = 0;
834 const char *desc = "Enable/Disable/Get status of SMBUS option on controller";
835 const char *option = "enable or disable or status";
836 const char *value =
837 "1 - hottest component temperature, 0 - composite temperature (default) for enable option, 0 (current), 1 (default), 2 (saved) for status options";
838
839 const char *save = "1 - persistent, 0 - non-persistent (default)";
840 int fid = MICRON_FEATURE_SMBUS_OPTION0xD5;
841 enum eDriveModel model = UNKNOWN_MODEL;
842 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
843 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
844 int err = 0;
845
846 struct {
847 char *option;
848 int value;
849 int save;
850 int status;
851 } opt = {
852 .option = "disable",
853 .value = 0,
854 .save = 0,
855 .status = 0,
856 };
857
858 NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"option", 'O', "option", CFG_STRING, &opt.option,
1, option, 0, }, {"value", 'V', "NUM", CFG_POSITIVE, &opt
.value, 1, value, 0, }, {"save", 's', "NUM", CFG_POSITIVE, &
opt.save, 1, save, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
859 OPT_STRING("option", 'O', "option", &opt.option, option),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"option", 'O', "option", CFG_STRING, &opt.option,
1, option, 0, }, {"value", 'V', "NUM", CFG_POSITIVE, &opt
.value, 1, value, 0, }, {"save", 's', "NUM", CFG_POSITIVE, &
opt.save, 1, save, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
860 OPT_UINT("value", 'V', &opt.value, value),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"option", 'O', "option", CFG_STRING, &opt.option,
1, option, 0, }, {"value", 'V', "NUM", CFG_POSITIVE, &opt
.value, 1, value, 0, }, {"save", 's', "NUM", CFG_POSITIVE, &
opt.save, 1, save, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
861 OPT_UINT("save", 's', &opt.save, save))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"option", 'O', "option", CFG_STRING, &opt.option,
1, option, 0, }, {"value", 'V', "NUM", CFG_POSITIVE, &opt
.value, 1, value, 0, }, {"save", 's', "NUM", CFG_POSITIVE, &
opt.save, 1, save, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
862
863 err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &model);
864 if (err)
865 return err;
866
867 if (model != M5407 && model != M5411 && model != M6003 && model != M6004) {
868 nvme_show_error("This option is not supported for specified drive")nvme_show_message(1, "This option is not supported for specified drive"
)
;
869 return err;
870 }
871
872 if (!strcmp(opt.option, "enable")) {
873 cdw11 = opt.value << 1 | 1;
874 err = nvme_set_features_simple(hdl, 1, fid, opt.save, cdw11,
875 &result);
876 if (!err)
877 nvme_show_verbose_result("successfully enabled SMBus on drive")nvme_show_verbose_message("successfully enabled SMBus on drive"
)
;
878 else
879 nvme_show_error("Failed to enabled SMBus on drive")nvme_show_message(1, "Failed to enabled SMBus on drive");
880 } else if (!strcmp(opt.option, "status")) {
881 err = nvme_get_features(hdl, 1, fid, opt.value, 0, 0, NULL((void*)0), 0, &result);
882 if (!err)
883 printf("SMBus status on the drive: %s (returns %s temperature)\n",
884 (result & 1) ? "enabled" : "disabled",
885 (result & 2) ? "hottest component" : "composite");
886 else
887 nvme_show_error("Failed to retrieve SMBus status on the drive")nvme_show_message(1, "Failed to retrieve SMBus status on the drive"
)
;
888 } else if (!strcmp(opt.option, "disable")) {
889 cdw11 = opt.value << 1 | 0;
890 err = nvme_set_features_simple(hdl, 1, fid, opt.save, cdw11,
891 &result);
892 if (!err)
893 nvme_show_verbose_result("Successfully disabled SMBus on drive")nvme_show_verbose_message("Successfully disabled SMBus on drive"
)
;
894 else
895 nvme_show_error("Failed to disable SMBus on drive")nvme_show_message(1, "Failed to disable SMBus on drive");
896 } else {
897 nvme_show_error("Invalid option %s, valid values are enable, disable or status",nvme_show_message(1, "Invalid option %s, valid values are enable, disable or status"
, opt.option)
898 opt.option)nvme_show_message(1, "Invalid option %s, valid values are enable, disable or status"
, opt.option)
;
899 return -1;
900 }
901
902 return err;
903}
904
905static int micron_temp_stats(int argc, char **argv, struct command *acmd,
906 struct plugin *plugin)
907{
908
909 struct nvme_smart_log smart_log;
910 int err = 0;
911 unsigned int temperature = 0, i = 0;
912 unsigned int tempSensors[SensorCount8] = { 0 };
913 const char *desc = "Retrieve Micron temperature info for the given device ";
914 const char *fmt = "Output format: normal|json";
915 nvme_print_flags_t format;
916 bool_Bool is_json = false0;
917 struct json_object *root;
918 struct json_object *logPages;
919 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
920 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
921
922 NVME_ARGS_OUTPUT_FORMATS(opts, (JSON | NORMAL), fmt)nvme_args.supported_output_formats = (JSON | NORMAL); struct argconfig_commandline_options
opts[] = { {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)
0), 0, "Options", 0, ((void*)0)}, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, fmt
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
923
924 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
925 if (err)
926 return err;
927
928 err = validate_output_format(nvme_args.output_format, &format);
929 if (err) {
930 nvme_show_error("Invalid output format")nvme_show_message(1, "Invalid output format");
931 return err;
932 }
933 is_json = format == JSON;
934
935 err = nvme_get_log_smart(hdl, NVME_NSID_ALL, &smart_log);
936 if (!err) {
937 temperature = ((smart_log.temperature[1] << 8) | smart_log.temperature[0]);
938 temperature = temperature ? temperature - 273 : 0;
939 for (i = 0; i < SensorCount8; i++) {
940 tempSensors[i] = le16_to_cpu(smart_log.temp_sensor[i]);
941 tempSensors[i] = tempSensors[i] ? tempSensors[i] - 273 : 0;
942 }
943 if (is_json) {
944 struct json_object *stats = json_create_object()json_object_new_object();
945 char tempstr[64] = { 0 };
946
947 root = json_create_object()json_object_new_object();
948 logPages = json_create_array()json_object_new_array();
949 json_object_add_value_array(root, "Micron temperature information", logPages)json_object_object_add(root, "Micron temperature information"
, logPages)
;
950 sprintf(tempstr, "%u C", temperature);
951 json_object_add_value_string(stats, "Current Composite Temperature", tempstr);
952 for (i = 0; i < SensorCount8; i++) {
953 char sensor_str[256] = { 0 };
954 char datastr[64] = { 0 };
955
956 if (!smart_log.temp_sensor[i])
957 continue;
958 sprintf(sensor_str, "Temperature Sensor #%d", (i + 1));
959 sprintf(datastr, "%u C", tempSensors[i]);
960 json_object_add_value_string(stats, sensor_str, datastr);
961 }
962 json_array_add_value_object(logPages, stats)json_object_array_add(logPages, stats);
963 json_print_object(root, NULL)printf("%s", json_object_to_json_string_ext(root, (1 <<
1) | (1 << 4)))
;
964 printf("\n");
965 json_free_object(root)json_object_put(root);
966 } else {
967 printf("Micron temperature information:\n");
968 printf("%-10s : %u C\n", "Current Composite Temperature", temperature);
969 for (i = 0; i < SensorCount8; i++) {
970 if (!smart_log.temp_sensor[i])
971 continue;
972 printf("%-10s%d : %u C\n", "Temperature Sensor #", i + 1, tempSensors[i]);
973 }
974 }
975 }
976 return err;
977}
978
979struct pcie_error_counters {
980 __u16 receiver_error;
981 __u16 bad_tlp;
982 __u16 bad_dllp;
983 __u16 replay_num_rollover;
984 __u16 replay_timer_timeout;
985 __u16 advisory_non_fatal_error;
986 __u16 DLPES;
987 __u16 poisoned_tlp;
988 __u16 FCPC;
989 __u16 completion_timeout;
990 __u16 completion_abort;
991 __u16 unexpected_completion;
992 __u16 receiver_overflow;
993 __u16 malformed_tlp;
994 __u16 ecrc_error;
995 __u16 unsupported_request_error;
996} pcie_error_counters = { 0 };
997
998struct {
999 const char *err;
1000 int bit;
1001 int val;
1002} pcie_correctable_errors[] = {
1003 { (char *)"Unsupported Request Error Status (URES)", 20,
1004 offsetof(struct pcie_error_counters, unsupported_request_error)__builtin_offsetof(struct pcie_error_counters, unsupported_request_error
)
},
1005 { (char *)"ECRC Error Status (ECRCES)", 19,
1006 offsetof(struct pcie_error_counters, ecrc_error)__builtin_offsetof(struct pcie_error_counters, ecrc_error)},
1007 { (char *)"Malformed TLP Status (MTS)", 18,
1008 offsetof(struct pcie_error_counters, malformed_tlp)__builtin_offsetof(struct pcie_error_counters, malformed_tlp)},
1009 { (char *)"Receiver Overflow Status (ROS)", 17,
1010 offsetof(struct pcie_error_counters, receiver_overflow)__builtin_offsetof(struct pcie_error_counters, receiver_overflow
)
},
1011 { (char *)"Unexpected Completion Status (UCS)", 16,
1012 offsetof(struct pcie_error_counters, unexpected_completion)__builtin_offsetof(struct pcie_error_counters, unexpected_completion
)
},
1013 { (char *)"Completer Abort Status (CAS)", 15,
1014 offsetof(struct pcie_error_counters, completion_abort)__builtin_offsetof(struct pcie_error_counters, completion_abort
)
},
1015 { (char *)"Completion Timeout Status (CTS)", 14,
1016 offsetof(struct pcie_error_counters, completion_timeout)__builtin_offsetof(struct pcie_error_counters, completion_timeout
)
},
1017 { (char *)"Flow Control Protocol Error Status (FCPES)", 13,
1018 offsetof(struct pcie_error_counters, FCPC)__builtin_offsetof(struct pcie_error_counters, FCPC)},
1019 { (char *)"Poisoned TLP Status (PTS)", 12,
1020 offsetof(struct pcie_error_counters, poisoned_tlp)__builtin_offsetof(struct pcie_error_counters, poisoned_tlp)},
1021 { (char *)"Data Link Protocol Error Status (DLPES)", 4,
1022 offsetof(struct pcie_error_counters, DLPES)__builtin_offsetof(struct pcie_error_counters, DLPES)},
1023 },
1024 pcie_uncorrectable_errors[] = {
1025 { (char *)"Advisory Non-Fatal Error Status (ANFES)", 13,
1026 offsetof(struct pcie_error_counters, advisory_non_fatal_error)__builtin_offsetof(struct pcie_error_counters, advisory_non_fatal_error
)
},
1027 { (char *)"Replay Timer Timeout Status (RTS)", 12,
1028 offsetof(struct pcie_error_counters, replay_timer_timeout)__builtin_offsetof(struct pcie_error_counters, replay_timer_timeout
)
},
1029 { (char *)"REPLAY_NUM Rollover Status (RRS)", 8,
1030 offsetof(struct pcie_error_counters, replay_num_rollover)__builtin_offsetof(struct pcie_error_counters, replay_num_rollover
)
},
1031 { (char *)"Bad DLLP Status (BDS)", 7,
1032 offsetof(struct pcie_error_counters, bad_dllp)__builtin_offsetof(struct pcie_error_counters, bad_dllp)},
1033 { (char *)"Bad TLP Status (BTS)", 6,
1034 offsetof(struct pcie_error_counters, bad_tlp)__builtin_offsetof(struct pcie_error_counters, bad_tlp)},
1035 { (char *)"Receiver Error Status (RES)", 0,
1036 offsetof(struct pcie_error_counters, receiver_error)__builtin_offsetof(struct pcie_error_counters, receiver_error
)
},
1037 };
1038
1039static int micron_pcie_stats(int argc, char **argv,
1040 struct command *command, struct plugin *plugin)
1041{
1042 int i, err = 0;
1043 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
1044 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
1045 nvme_print_flags_t format = NORMAL;
1046 struct libnvme_passthru_cmd admin_cmd = { 0 };
1047 enum eDriveModel eModel = UNKNOWN_MODEL;
1048 bool_Bool is_json = false0;
1049 bool_Bool counters = false0;
1050 const char *desc = "Retrieve PCIe event counters";
1051 const char *fmt = "Output format: normal|json";
1052
1053 __u32 correctable_errors = 0;
1054 __u32 uncorrectable_errors = 0;
1055
1056 NVME_ARGS_OUTPUT_FORMATS(opts, (JSON | NORMAL), fmt)nvme_args.supported_output_formats = (JSON | NORMAL); struct argconfig_commandline_options
opts[] = { {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)
0), 0, "Options", 0, ((void*)0)}, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, fmt
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
1057
1058 err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &eModel);
1059 if (err)
1060 return err;
1061
1062 err = validate_output_format(nvme_args.output_format, &format);
1063 if (err) {
1064 nvme_show_error("Invalid output format")nvme_show_message(1, "Invalid output format");
1065 return err;
1066 }
1067 is_json = format == JSON;
1068
1069 /* pull log details based on the model name */
1070 if (eModel == UNKNOWN_MODEL) {
1071 nvme_show_error("Unsupported drive model for vs-pcie-stats command")nvme_show_message(1, "Unsupported drive model for vs-pcie-stats command"
)
;
1072 err = -ENOTSUP95;
1073 goto out;
1074 }
1075
1076 if (eModel == M5407) {
1077 admin_cmd.opcode = 0xD6;
1078 admin_cmd.addr = (__u64)(uintptr_t)&pcie_error_counters;
1079 admin_cmd.data_len = sizeof(pcie_error_counters);
1080 admin_cmd.cdw10 = 1;
1081 err = libnvme_exec_admin_passthru(hdl, &admin_cmd);
1082 if (!err) {
1083 counters = true1;
1084 correctable_errors = 10;
1085 uncorrectable_errors = 6;
1086 goto print_stats;
1087 }
1088 }
1089
1090 err = micron_get_pcie_aer_errors(hdl, &correctable_errors,
1091 &uncorrectable_errors);
1092 if (err)
1093 goto out;
1094print_stats:
1095 if (is_json) {
1096 struct json_object *root = json_create_object()json_object_new_object();
1097 struct json_object *pcieErrors = json_create_array()json_object_new_array();
1098 struct json_object *stats = json_create_object()json_object_new_object();
1099 __u8 *pcounter = (__u8 *)&pcie_error_counters;
1100
1101 json_object_add_value_array(root, "PCIE Stats", pcieErrors)json_object_object_add(root, "PCIE Stats", pcieErrors);
1102 for (i = 0; i < ARRAY_SIZE(pcie_correctable_errors)(sizeof(pcie_correctable_errors) / sizeof((pcie_correctable_errors
)[0]) + 0)
; i++) {
1103 __u16 val = counters ? *(__u16 *)(pcounter + pcie_correctable_errors[i].val) :
1104 (correctable_errors >> pcie_correctable_errors[i].bit) & 1;
1105 json_object_add_value_int(stats, pcie_correctable_errors[i].err, val)json_object_object_add(stats, pcie_correctable_errors[i].err,
json_object_new_int(val))
;
1106 }
1107 for (i = 0; i < ARRAY_SIZE(pcie_uncorrectable_errors)(sizeof(pcie_uncorrectable_errors) / sizeof((pcie_uncorrectable_errors
)[0]) + 0)
; i++) {
1108 __u16 val = counters ? *(__u16 *)(pcounter + pcie_uncorrectable_errors[i].val) :
1109 (uncorrectable_errors >>
1110 pcie_uncorrectable_errors[i].bit) & 1;
1111 json_object_add_value_int(stats, pcie_uncorrectable_errors[i].err, val)json_object_object_add(stats, pcie_uncorrectable_errors[i].err
, json_object_new_int(val))
;
1112 }
1113 json_array_add_value_object(pcieErrors, stats)json_object_array_add(pcieErrors, stats);
1114 json_print_object(root, NULL)printf("%s", json_object_to_json_string_ext(root, (1 <<
1) | (1 << 4)))
;
1115 printf("\n");
1116 json_free_object(root)json_object_put(root);
1117 } else if (counters == true1) {
1118 __u8 *pcounter = (__u8 *)&pcie_error_counters;
1119
1120 for (i = 0; i < ARRAY_SIZE(pcie_correctable_errors)(sizeof(pcie_correctable_errors) / sizeof((pcie_correctable_errors
)[0]) + 0)
; i++)
1121 printf("%-42s : %-1hu\n", pcie_correctable_errors[i].err,
1122 *(__u16 *)(pcounter + pcie_correctable_errors[i].val));
1123 for (i = 0; i < ARRAY_SIZE(pcie_uncorrectable_errors)(sizeof(pcie_uncorrectable_errors) / sizeof((pcie_uncorrectable_errors
)[0]) + 0)
; i++)
1124 printf("%-42s : %-1hu\n", pcie_uncorrectable_errors[i].err,
1125 *(__u16 *)(pcounter + pcie_uncorrectable_errors[i].val));
1126 } else if (eModel == M5407 || eModel == M5410) {
1127 for (i = 0; i < ARRAY_SIZE(pcie_correctable_errors)(sizeof(pcie_correctable_errors) / sizeof((pcie_correctable_errors
)[0]) + 0)
; i++)
1128 printf("%-42s : %-1d\n", pcie_correctable_errors[i].err,
1129 ((correctable_errors >>
1130 pcie_correctable_errors[i].bit) & 1));
1131 for (i = 0; i < ARRAY_SIZE(pcie_uncorrectable_errors)(sizeof(pcie_uncorrectable_errors) / sizeof((pcie_uncorrectable_errors
)[0]) + 0)
; i++)
1132 printf("%-42s : %-1d\n", pcie_uncorrectable_errors[i].err,
1133 ((uncorrectable_errors >>
1134 pcie_uncorrectable_errors[i].bit) & 1));
1135 } else {
1136 printf("PCIE Stats:\n");
1137 printf("Device correctable errors detected: 0x%x\n",
1138 correctable_errors);
1139 printf("Device uncorrectable errors detected: 0x%x\n",
1140 uncorrectable_errors);
1141 }
1142
1143out:
1144 return err;
1145}
1146
1147static int micron_clear_pcie_correctable_errors(int argc, char **argv,
1148 struct command *command,
1149 struct plugin *plugin)
1150{
1151 int err = -EINVAL22;
1152 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
1153 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
1154 enum eDriveModel model = UNKNOWN_MODEL;
1155 struct libnvme_passthru_cmd admin_cmd = { 0 };
1156 const char *desc = "Clear PCIe Device Correctable Errors";
1157 __u64 result = 0;
1158 __u8 fid = MICRON_FEATURE_CLEAR_PCI_CORRECTABLE_ERRORS0xC3;
1159
1160 NVME_ARGS(opts)nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0
, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT
, &nvme_args.verbose, 0, "Increase output verbosity", 0, }
, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0,
"suppress informational output", 0, }, {"output-format", 'o'
, "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
1161
1162 err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &model);
1163 if (err)
1164 return err;
1165
1166 /* For M51CX models, PCIe errors are cleared using 0xC3 feature
1167 * and for M5407 models, PCIe errors are cleared using 0xD6 command
1168 * If these fail, proceed with sysfs interface to set/clear bits
1169 */
1170 if (model == M51CX || model == M51BY || model == M51CY) {
1171 err = nvme_set_features_simple(hdl, 0, fid, false0, (1 << 31),
1172 &result);
1173 if (!err)
1174 err = (int)result;
1175 if (!err) {
1176 nvme_show_verbose_result("Device correctable errors cleared!")nvme_show_verbose_message("Device correctable errors cleared!"
)
;
1177 return 0;
1178 }
1179 } else if (model == M5407) {
1180 admin_cmd.opcode = 0xD6;
1181 admin_cmd.addr = 0;
1182 admin_cmd.cdw10 = 0;
1183 err = libnvme_exec_admin_passthru(hdl, &admin_cmd);
1184 if (!err) {
1185 nvme_show_verbose_result("Device correctable errors cleared!")nvme_show_verbose_message("Device correctable errors cleared!"
)
;
1186 return 0;
1187 }
1188 }
1189
1190 /* clear status bits using system commands */
1191 err = micron_clear_pcie_aer_correctable_errors(hdl);
1192
1193 return err;
1194}
1195
1196static struct logpage {
1197 const char *field;
1198 char datastr[128];
1199} d0_log_page[] = {
1200 { "NAND Writes (Bytes Written)", { 0 }},
1201 { "Program Failure Count", { 0 }},
1202 { "Erase Failures", { 0 }},
1203 { "Bad Block Count", { 0 }},
1204 { "NAND XOR/RAID Recovery Trigger Events", { 0 }},
1205 { "NSZE Change Supported", { 0 }},
1206 { "Number of NSZE Modifications", { 0 }}
1207};
1208
1209static void init_d0_log_page(__u8 *buf, __u8 nsze)
1210{
1211 unsigned int logD0[D0_log_size512/sizeof(int)] = { 0 };
1212 __u64 count_lo, count_hi, count;
1213
1214 memcpy(logD0, buf, sizeof(logD0));
1215
1216
1217 count = ((__u64)logD0[45] << 32) | logD0[44];
1218 sprintf(d0_log_page[0].datastr, "0x%"PRIx64"l" "x", le64_to_cpu(count));
1219
1220 count_hi = ((__u64)logD0[39] << 32) | logD0[38];
1221 count_lo = ((__u64)logD0[37] << 32) | logD0[36];
1222 if (count_hi)
1223 sprintf(d0_log_page[1].datastr, "0x%"PRIx64"l" "x""%016"PRIx64"l" "x",
1224 le64_to_cpu(count_hi), le64_to_cpu(count_lo));
1225 else
1226 sprintf(d0_log_page[1].datastr, "0x%"PRIx64"l" "x", le64_to_cpu(count_lo));
1227
1228 count = ((__u64)logD0[25] << 32) | logD0[24];
1229 sprintf(d0_log_page[2].datastr, "0x%"PRIx64"l" "x", le64_to_cpu(count));
1230
1231 sprintf(d0_log_page[3].datastr, "0x%x", logD0[3]);
1232
1233 count_lo = ((__u64)logD0[37] << 32) | logD0[36];
1234 count = ((__u64)logD0[25] << 32) | logD0[24];
1235 count = (__u64)logD0[3] - (count_lo + count);
1236 sprintf(d0_log_page[4].datastr, "0x%"PRIx64"l" "x", le64_to_cpu(count));
1237
1238 sprintf(d0_log_page[5].datastr, "0x%x", nsze);
1239 sprintf(d0_log_page[6].datastr, "0x%x", logD0[1]);
1240}
1241
1242static struct nand_stats {
1243 const char *field;
1244 char datastr[128];
1245} hyperscale_BSSD_nand_stats[] = {
1246 {"Physical Media Units Written - TLC", {0}},
1247 {"Physical Media Units Written - SLC", {0}},
1248 {"Bad User NAND Block Count (Normalized)", {0}},
1249 {"Bad User NAND Block Count (Raw)", {0}},
1250 {"XOR Recovery count", {0}},
1251 {"Uncorrectable read error count", {0}},
1252 { "User Data Erase Counts (Minimum TLC)", {0}},
1253 { "User Data Erase Counts (Maximum TLC)", {0}},
1254 { "User Data Erase Counts (Average TLC)", {0}},
1255 { "User Data Erase Counts (Minimum SLC)", {0}},
1256 { "User Data Erase Counts (Maximum SLC)", {0}},
1257 { "User Data Erase Counts (Average SLC)", {0}},
1258 { "Program Fail Count (Normalized)", {0}},
1259 { "Program Fail Count (Raw)", {0}},
1260 { "Erase Fail Count (Normalized)", {0}},
1261 { "Erase Fail Count (Raw)", {0}},
1262 { "Total # of Soft ECC Error Count", {0}},
1263 { "Bad System NAND Block Count (Normalized)", {0}},
1264 { "Bad System NAND Block Count (Raw)", {0}},
1265 {"Endurance Estimate", {0}},
1266 {"Physical Media Units Read", {0}},
1267 {"Boot SSD Spec Version", {0}},
1268};
1269
1270static void micron_readFixedBytesFromBuffer(__u8 *buf, int offset, int numBytes, char *datastr)
1271{
1272 __u16 u16Val;
1273 __u32 u32Val;
1274 __u64 count_lo, count_hi, count;
1275
1276 switch (numBytes) {
1277 case 16:
1278 {
1279 count_lo = *((__u64 *)(&buf[offset]));
1280 count_hi = *((__u64 *)(&buf[offset + 8]));
1281 if (count_hi)
1282 sprintf(datastr, "0x%"PRIx64"l" "x""%016"PRIx64"l" "x""",
1283 le64_to_cpu(count_hi),
1284 le64_to_cpu(count_lo));
1285 else
1286 sprintf(datastr, "0x%"PRIx64"l" "x""", le64_to_cpu(count_lo));
1287
1288 }
1289 break;
1290 case 8:
1291 {
1292 count = *((__u64 *)(&buf[offset]));
1293 sprintf(datastr, "0x%"PRIx64"l" "x""", le64_to_cpu(count));
1294 }
1295 break;
1296 case 6:
1297 {
1298 u32Val = *((__u32 *)(&buf[offset]));
1299 u16Val = *((__u16 *)(&buf[offset + 4]));
1300 count = (((__u64)u32Val << 32) | u16Val);
1301 sprintf(datastr, "0x%"PRIx64"l" "x""", le64_to_cpu(count));
1302 }
1303 break;
1304 case 2:
1305 {
1306 u16Val = *((__u16 *)(&buf[offset]));
1307 sprintf(datastr, "0x%04x", le16_to_cpu(u16Val));
1308 }
1309 break;
1310 }
1311}
1312
1313static void init_hyperscale_BSSD_nand_stats(__u8 *buf)
1314{
1315
1316 __u16 majorVer, minorVer, pointVer, errataVer;
1317
1318 micron_readFixedBytesFromBuffer(buf, 0, 16, hyperscale_BSSD_nand_stats[0].datastr);
1319 micron_readFixedBytesFromBuffer(buf, 16, 16, hyperscale_BSSD_nand_stats[1].datastr);
1320 micron_readFixedBytesFromBuffer(buf, 32, 2, hyperscale_BSSD_nand_stats[2].datastr);
1321 micron_readFixedBytesFromBuffer(buf, 34, 6, hyperscale_BSSD_nand_stats[3].datastr);
1322 micron_readFixedBytesFromBuffer(buf, 40, 8, hyperscale_BSSD_nand_stats[4].datastr);
1323 micron_readFixedBytesFromBuffer(buf, 48, 8, hyperscale_BSSD_nand_stats[5].datastr);
1324 micron_readFixedBytesFromBuffer(buf, 84, 8, hyperscale_BSSD_nand_stats[6].datastr);
1325 micron_readFixedBytesFromBuffer(buf, 92, 8, hyperscale_BSSD_nand_stats[7].datastr);
1326 micron_readFixedBytesFromBuffer(buf, 100, 8, hyperscale_BSSD_nand_stats[8].datastr);
1327 micron_readFixedBytesFromBuffer(buf, 108, 8, hyperscale_BSSD_nand_stats[9].datastr);
1328 micron_readFixedBytesFromBuffer(buf, 116, 8, hyperscale_BSSD_nand_stats[10].datastr);
1329 micron_readFixedBytesFromBuffer(buf, 124, 8, hyperscale_BSSD_nand_stats[11].datastr);
1330 micron_readFixedBytesFromBuffer(buf, 132, 2, hyperscale_BSSD_nand_stats[12].datastr);
1331 micron_readFixedBytesFromBuffer(buf, 134, 6, hyperscale_BSSD_nand_stats[13].datastr);
1332 micron_readFixedBytesFromBuffer(buf, 140, 2, hyperscale_BSSD_nand_stats[14].datastr);
1333 micron_readFixedBytesFromBuffer(buf, 142, 6, hyperscale_BSSD_nand_stats[15].datastr);
1334 micron_readFixedBytesFromBuffer(buf, 202, 8, hyperscale_BSSD_nand_stats[16].datastr);
1335 micron_readFixedBytesFromBuffer(buf, 218, 2, hyperscale_BSSD_nand_stats[17].datastr);
1336 micron_readFixedBytesFromBuffer(buf, 220, 6, hyperscale_BSSD_nand_stats[18].datastr);
1337 micron_readFixedBytesFromBuffer(buf, 226, 16, hyperscale_BSSD_nand_stats[19].datastr);
1338 micron_readFixedBytesFromBuffer(buf, 252, 16, hyperscale_BSSD_nand_stats[20].datastr);
1339
1340 majorVer = *((__u16 *)(&buf[300]));
1341 minorVer = *((__u16 *)(&buf[302]));
1342 pointVer = *((__u16 *)(&buf[304]));
1343 errataVer = *((__u16 *)(&buf[306]));
1344 sprintf(hyperscale_BSSD_nand_stats[21].datastr,
1345 "%x.%x.%x.%x",
1346 le16_to_cpu(majorVer),
1347 le16_to_cpu(minorVer),
1348 le16_to_cpu(pointVer),
1349 le16_to_cpu(errataVer));
1350}
1351
1352
1353/* Smart Health Log information as per OCP spec M51CX models */
1354struct request_data ocp_c0_log_page[] = {
1355 { "Physical Media Units Written", 16},
1356 { "Physical Media Units Read", 16 },
1357 { "Raw Bad User NAND Block Count", 6},
1358 { "Normalized Bad User NAND Block Count", 2},
1359 { "Raw Bad System NAND Block Count", 6},
1360 { "Normalized Bad System NAND Block Count", 2},
1361 { "XOR Recovery Count", 8},
1362 { "Uncorrectable Read Error Count", 8},
1363 { "Soft ECC Error Count", 8},
1364 { "SSD End to End Detected Counts", 4},
1365 { "SSD End to End Corrected Errors", 4},
1366 { "System data % life-used", 1},
1367 { "Refresh Count", 7},
1368 { "Maximum User Data Erase Count", 4},
1369 { "Minimum User Data Erase Count", 4},
1370 { "Thermal Throttling Count", 1},
1371 { "Thermal Throttling Status", 1},
1372 { "Reserved", 6},
1373 { "PCIe Correctable Error count", 8},
1374 { "Incomplete Shutdowns", 4},
1375 { "Reserved", 4},
1376 { "% Free Blocks", 1},
1377 { "Reserved", 7},
1378 { "Capacitor Health", 2},
1379 { "Reserved", 6},
1380 { "Unaligned I/O", 8},
1381 { "Security Version Number", 8},
1382 { "NUSE", 8},
1383 { "PLP Start Count", 16},
1384 { "Endurance Estimate", 16},
1385 { "Reserved", 302},
1386 { "Log Page Version", 2},
1387 { "Log Page GUID", 16},
1388},
1389
1390/* Smart Health Log information Extended as per Hyperscale NVME Boot SSD spec M51CX models */
1391hyperscale_c0_log_page[] = {
1392 { "Physical Media Units Written - TLC", 16},
1393 { "Physical Media Units Written - SLC", 16},
1394 { "Bad User NAND Block Count (Normalized)", 2},
1395 { "Bad User NAND Block Count (Raw)", 6},
1396 { "XOR Recovery Count", 8},
1397 { "Uncorrectable Read Error Count", 8},
1398 { "SSD End to End correction counts (Corrected Errors)", 8},
1399 { "SSD End to End correction counts (Detected Counts)", 8},
1400 { "SSD End to End correction counts (Uncorrected Counts)", 8},
1401 { "System data % life-used", 1},
1402 { "Reserved", 3},
1403 { "User Data Erase Counts (Minimum TLC)", 8},
1404 { "User Data Erase Counts (Maximum TLC)", 8},
1405 { "User Data Erase Counts (Average TLC)", 8},
1406 { "User Data Erase Counts (Minimum SLC)", 8},
1407 { "User Data Erase Counts (Maximum SLC)", 8},
1408 { "User Data Erase Counts (Average SLC)", 8},
1409 { "Program Fail Count (Normalized)", 2},
1410 { "Program Fail Count (Raw)", 6},
1411 { "Erase Fail Count (Normalized)", 2},
1412 { "Erase Fail Count (Raw)", 6},
1413 { "Pcie Correctable Error Count", 8},
1414 { "% Free Blocks (User)", 1},
1415 { "Reserved", 3},
1416 { "Security Version Number", 8},
1417 { "% Free Blocks (System)", 1},
1418 { "Reserved", 3},
1419 { "NVMe Stats (# Data set Management/TRIM Commands Completed", 16},
1420 { "Total Namespace Utilization (nvme0n1 NUSE)", 8},
1421 { "NVMe Stats (#NVMe Format Commands Completed)", 2},
1422 { "Background Back-Pressure Gauge(%)", 1},
1423 { "Reserved", 3},
1424 { "Total # of Soft ECC Error Count", 8},
1425 { "Total # of Read Refresh Count", 8},
1426 { "Bad System NAND Block Count (Normalized)", 2},
1427 { "Bad System NAND Block Count (Raw)", 6},
1428 { "Endurance Estimate (Total Writable Lifetime Bytes)", 16},
1429 { "Thermal Throttling Status & Count (Number of thermal throttling events)", 2},
1430 { "Total # Unaligned I/O", 8},
1431 { "Total Physical Media Units Read (Bytes)", 16},
1432 { "Command Timeout (# of READ CMDs exceeding threshold)", 4},
1433 { "Command Timeout (# of WRITE CMDs exceeding threshold)", 4},
1434 { "Command Timeout (# of TRIMs CMDs exceeding threshold)", 4},
1435 { "Reserved", 4},
1436 { "Total PCIe Link Retraining Count", 8},
1437 { "Active Power State Change Count", 8},
1438 { "Boot SSD Spec Version", 8},
1439 { "FTL Unit Size", 4},
1440 { "TCG Ownership Status", 4},
1441 { "Reserved", 178},
1442 { "Log Page Version", 2},
1443 { "Log Page GUID", 16},
1444},
1445
1446/* Smart Health Log information as per datacenter-nvme-ssd-specification-v2 M51BY models */
1447datacenter_c0_log_page[] = {
1448 {"Physical Media Units Written", 16},
1449 {"Physical Media Units Read", 16 },
1450 {"Raw Bad User NAND Block Count", 6},
1451 {"Normalized Bad User NAND Block Count", 2},
1452 {"Raw Bad System NAND Block Count", 6},
1453 {"Normalized Bad System NAND Block Count", 2},
1454 {"XOR Recovery Count", 8},
1455 {"Uncorrectable Read Error Count", 8},
1456 {"Soft ECC Error Count", 8},
1457 {"SSD End to End Detected Counts", 4},
1458 {"SSD End to End Corrected Errors", 4},
1459 {"System data % life-used", 1},
1460 {"Refresh Count", 7},
1461 {"Maximum User Data Erase Count", 4},
1462 {"Minimum User Data Erase Count", 4},
1463 {"Thermal Throttling Count", 1},
1464 {"Thermal Throttling Status", 1},
1465 {"DSSD Spec Version", 6},
1466 {"PCIe Correctable Error count", 8},
1467 {"Incomplete Shutdowns", 4},
1468 {"Reserved", 4},
1469 {"% Free Blocks", 1},
1470 {"Reserved", 7},
1471 {"Capacitor Health", 2},
1472 {"NVMe Errata Version", 1},
1473 {"Reserved", 5},
1474 {"Unaligned I/O", 8},
1475 {"Security Version Number", 8},
1476 {"Total NUSE", 8},
1477 {"PLP Start Count", 16},
1478 {"Endurance Estimate", 16},
1479 {"PCIe Link Retraining Count", 8},
1480 {"Power State Change Count", 8},
1481 {"Reserved", 286},
1482 {"Log Page Version", 2},
1483 {"Log Page GUID", 16},
1484},
1485
1486/* Extended SMART log information */
1487e1_log_page[] = {
1488 {"Reserved", 12},
1489 {"Grown Bad Block Count", 4},
1490 {"Per Block Max Erase Count", 4},
1491 {"Power On Minutes", 4},
1492 {"Reserved", 24},
1493 {"Write Protect Reason", 4},
1494 {"Reserved", 12},
1495 {"Drive Capacity", 8},
1496 {"Reserved", 8},
1497 {"Total Erase Count", 8},
1498 {"Lifetime Use Rate", 8},
1499 {"Erase Fail Count", 8},
1500 {"Reserved", 8},
1501 {"Reported UC Errors", 8},
1502 {"Reserved", 24},
1503 {"Program Fail Count", 16},
1504 {"Total Bytes Read", 16},
1505 {"Total Bytes Written", 16},
1506 {"Reserved", 16},
1507 {"TU Size", 4},
1508 {"Total Block Stripe Count", 4},
1509 {"Free Block Stripe Count", 4},
1510 {"Block Stripe Size", 8},
1511 {"Reserved", 16},
1512 {"User Block Min Erase Count", 4},
1513 {"User Block Avg Erase Count", 4},
1514 {"User Block Max Erase Count", 4},
1515},
1516/* Vendor Specific Health Log information */
1517fb_log_page[] = {
1518 {"Physical Media Units Written - TLC", 16, 16 },
1519 {"Physical Media Units Written - SLC", 16, 16 },
1520 {"Normalized Bad User NAND Block Count", 2, 2},
1521 {"Raw Bad User NAND Block Count", 6, 6},
1522 {"XOR Recovery Count", 8, 8},
1523 {"Uncorrectable Read Error Count", 8, 8},
1524 {"SSD End to End Corrected Errors", 8, 8},
1525 {"SSD End to End Detected Counts", 4, 8},
1526 {"SSD End to End Uncorrected Counts", 4, 8},
1527 {"System data % life-used", 1, 1},
1528 {"Reserved", 0, 3},
1529 {"Minimum User Data Erase Count - TLC", 8, 8},
1530 {"Maximum User Data Erase Count - TLC", 8, 8},
1531 {"Average User Data Erase Count - TLC", 0, 8},
1532 {"Minimum User Data Erase Count - SLC", 8, 8},
1533 {"Maximum User Data Erase Count - SLC", 8, 8},
1534 {"Average User Data Erase Count - SLC", 0, 8},
1535 {"Normalized Program Fail Count", 2, 2},
1536 {"Raw Program Fail Count", 6, 6},
1537 {"Normalized Erase Fail Count", 2, 2},
1538 {"Raw Erase Fail Count", 6, 6},
1539 {"Pcie Correctable Error Count", 8, 8},
1540 {"% Free Blocks (User)", 1, 1},
1541 {"Reserved", 0, 3},
1542 {"Security Version Number", 8, 8},
1543 {"% Free Blocks (System)", 1, 1},
1544 {"Reserved", 0, 3},
1545 {"Dataset Management (Deallocate) Commands", 16, 16},
1546 {"Incomplete TRIM Data", 8, 8},
1547 {"% Age of Completed TRIM", 1, 2},
1548 {"Background Back-Pressure Gauge", 1, 1},
1549 {"Reserved", 0, 3},
1550 {"Soft ECC Error Count", 8, 8},
1551 {"Refresh Count", 8, 8},
1552 {"Normalized Bad System NAND Block Count", 2, 2},
1553 {"Raw Bad System NAND Block Count", 6, 6},
1554 {"Endurance Estimate", 16, 16},
1555 {"Thermal Throttling Status", 1, 1},
1556 {"Thermal Throttling Count", 1, 1},
1557 {"Unaligned I/O", 8, 8},
1558 {"Physical Media Units Read", 16, 16},
1559 {"Reserved", 279, 0},
1560 {"Log Page Version", 2, 0},
1561 {"READ CMDs exceeding threshold", 0, 4},
1562 {"WRITE CMDs exceeding threshold", 0, 4},
1563 {"TRIMs CMDs exceeding threshold", 0, 4},
1564 {"Reserved", 0, 4},
1565 {"Reserved", 0, 210},
1566 {"Log Page Version", 0, 2},
1567 {"Log Page GUID", 0, 16},
1568},
1569
1570/* SMARTS for 0x6001 Nitro model */
1571//Extended Health Information (Log Identifier D0h)
1572D0_log_page[] = {
1573 {"Reserved", 2},//1:0
1574 {"Version", 2},//3:2
1575 {"Grown Bad Block Count", 4},//7:4
1576 {"Total SRAM SBE Count", 4},//11:8
1577 {"Total SRAM DBE Count", 4},//15:12
1578 {"Write Protect Reason", 4},//19:16
1579 {"Total Erase Count", 4},//23:20
1580 {"Erase Fail Count", 4},//27:24
1581 {"Program Fail Counts", 4},//31:28
1582 {"Reserved", 40},//71:32
1583 {"Completed PLN PLA Cycles", 4},//75:72
1584 {"PLN Assert Count", 4},//79:76
1585 {"PLN Deassert Count", 4},//83:80
1586 {"PLA Assert Count", 4},//87:84
1587 {"PLA Deassert Count", 4},//91:88
1588 {"Correctable NAND UECCs", 4},//95:92
1589 {"Reported Uncorrectable Errors UECCCs", 4},//99:96
1590 {"TLC Super Block Min Erase Count", 4},//103:100
1591 {"TLC Super Block Avg Erase Count", 4},//107:104
1592 {"TLC Super Block Max Erase Count", 4},//111:108
1593 {"Min ASIC Temp Recorded", 2},//113:112
1594 {"Max ASIC Temp Recorded", 2},//115:114
1595 {"Min NAND Temp Recorded", 2},//171:116
1596 {"Max NAND Temp Recorded", 2},//119:118
1597 {"SLC Super Block Min Erase Count", 4},//123:120
1598 {"SLC Super Block Avg Erase Count", 4},//127:124
1599 {"SLC Super Block Max Erase Count", 4},//131:128
1600 {"SLC Lifetime Used", 2},//133:132
1601 {"TLC Lifetime Used", 2},//135:134
1602 {"Unmapped LBA Count", 8},//143:136
1603 {"PWR1 Voltage Detection Threshold #1", 4},//147:144
1604 {"PWR1 Voltage Detection Threshold #2", 4},//151:148
1605},
1606//Micron Workload Log (Log Identifier C5h)
1607C5_log_page[] = {
1608 {"Reserved", 4},//3:0
1609 {"Number of Downshifts", 1},//4
1610 {"Reserved", 71},//75:5
1611 {"Number of LBAs Deallocated Trimmed", 4},//79:76
1612 {"Reserved", 41},//120:80
1613 {"Number of Security Send Commands", 4},//124:121
1614 {"Number of Security Receive Commands", 4},//128:125
1615 {"Total Sanitize Events", 4},//132:129
1616},
1617//Vendor Telemetry Log (Log Identifier C6h))
1618C6_log_page[] = {
1619 {"Reserved", 240},//239:0
1620 {"Total TLC NAND Write Count", 8},//247:240
1621 {"Total SLC NAND Write Count", 8},//255:248
1622 {"Total SLC Host Write Count", 8},//263:256
1623 {"Total TLC Host Write Count", 8},//272:264
1624};
1625
1626static void print_smart_cloud_health_log(__u8 *buf, bool_Bool is_json, enum eDriveModel eModel)
1627{
1628 struct json_object *root = NULL((void*)0);
1629 struct json_object *logPages = NULL((void*)0);
1630 struct json_object *stats = NULL((void*)0);
1631 int field_count = 0;
1632
1633 if (eModel == M51CX)
1634 field_count = ARRAY_SIZE(ocp_c0_log_page)(sizeof(ocp_c0_log_page) / sizeof((ocp_c0_log_page)[0]) + 0);
1635 else if (eModel == M51BY || eModel == M51CY)
1636 field_count = ARRAY_SIZE(datacenter_c0_log_page)(sizeof(datacenter_c0_log_page) / sizeof((datacenter_c0_log_page
)[0]) + 0)
;
1637
1638 if (is_json) {
1639 root = json_create_object()json_object_new_object();
1640 stats = json_create_object()json_object_new_object();
1641 logPages = json_create_array()json_object_new_array();
1642 if (eModel == M51BY || eModel == M51CY)
1643 json_object_add_value_array(root, "OCP DataCenter SMART Health Log: 0xC0",json_object_object_add(root, "OCP DataCenter SMART Health Log: 0xC0"
, logPages)
1644 logPages)json_object_object_add(root, "OCP DataCenter SMART Health Log: 0xC0"
, logPages)
;
1645 else if (eModel == M51CX)
1646 json_object_add_value_array(root, "OCP SMART Cloud Health Log: 0xC0",json_object_object_add(root, "OCP SMART Cloud Health Log: 0xC0"
, logPages)
1647 logPages)json_object_object_add(root, "OCP SMART Cloud Health Log: 0xC0"
, logPages)
;
1648 }
1649
1650 if (eModel == M51BY || eModel == M51CY)
1651 generic_structure_parser(buf, datacenter_c0_log_page, field_count, stats, 0, NULL((void*)0));
1652 else if (eModel == M51CX)
1653 generic_structure_parser(buf, ocp_c0_log_page, field_count, stats, 0, NULL((void*)0));
1654
1655 if (is_json) {
1656 json_array_add_value_object(logPages, stats)json_object_array_add(logPages, stats);
1657 json_print_object(root, NULL)printf("%s", json_object_to_json_string_ext(root, (1 <<
1) | (1 << 4)))
;
1658 printf("\n");
1659 json_free_object(root)json_object_put(root);
1660 }
1661}
1662
1663static void print_hyperscale_cloud_health_log(__u8 *buf, bool_Bool is_json)
1664{
1665 struct json_object *root;
1666 struct json_object *logPages;
1667 struct json_object *stats = NULL((void*)0);
1668 int field_count = ARRAY_SIZE(hyperscale_c0_log_page)(sizeof(hyperscale_c0_log_page) / sizeof((hyperscale_c0_log_page
)[0]) + 0)
;
1669
1670 if (is_json) {
1671 root = json_create_object()json_object_new_object();
1672 stats = json_create_object()json_object_new_object();
1673 logPages = json_create_array()json_object_new_array();
1674 json_object_add_value_array(root, "OCP Hyperscale Cloud Health Log: 0xC0",json_object_object_add(root, "OCP Hyperscale Cloud Health Log: 0xC0"
, logPages)
1675 logPages)json_object_object_add(root, "OCP Hyperscale Cloud Health Log: 0xC0"
, logPages)
;
1676 }
1677
1678 generic_structure_parser(buf, hyperscale_c0_log_page, field_count, stats, 0, NULL((void*)0));
1679
1680 if (is_json) {
1681 json_array_add_value_object(logPages, stats)json_object_array_add(logPages, stats);
1682 json_print_object(root, NULL)printf("%s", json_object_to_json_string_ext(root, (1 <<
1) | (1 << 4)))
;
1683 printf("\n");
1684 json_free_object(root)json_object_put(root);
1685 }
1686}
1687
1688static void print_nand_stats_fb(__u8 *buf, __u8 *buf2, __u8 nsze, bool_Bool is_json, __u8 spec)
1689{
1690 struct json_object *root;
1691 struct json_object *logPages;
1692 struct json_object *stats = NULL((void*)0);
1693 int field_count = ARRAY_SIZE(fb_log_page)(sizeof(fb_log_page) / sizeof((fb_log_page)[0]) + 0);
1694
1695 if (is_json) {
1696 root = json_create_object()json_object_new_object();
1697 stats = json_create_object()json_object_new_object();
1698 logPages = json_create_array()json_object_new_array();
1699 json_object_add_value_array(root, "Extended Smart Log Page : 0xFB",json_object_object_add(root, "Extended Smart Log Page : 0xFB"
, logPages)
1700 logPages)json_object_object_add(root, "Extended Smart Log Page : 0xFB"
, logPages)
;
1701 }
1702
1703 generic_structure_parser(buf, fb_log_page, field_count, stats, spec, NULL((void*)0));
1704
1705 /* print last three entries from D0 log page */
1706 if (buf2) {
1707 init_d0_log_page(buf2, nsze);
1708
1709 if (is_json) {
1710 for (int i = 0; i < 7; i++)
1711 json_object_add_value_string(stats,
1712 d0_log_page[i].field,
1713 d0_log_page[i].datastr);
1714 } else {
1715 for (int i = 0; i < 7; i++)
1716 printf("%-40s : %s\n", d0_log_page[i].field, d0_log_page[i].datastr);
1717 }
1718 }
1719
1720 if (is_json) {
1721 json_array_add_value_object(logPages, stats)json_object_array_add(logPages, stats);
1722 json_print_object(root, NULL)printf("%s", json_object_to_json_string_ext(root, (1 <<
1) | (1 << 4)))
;
1723 printf("\n");
1724 json_free_object(root)json_object_put(root);
1725 }
1726}
1727
1728static void print_nand_stats_d0(__u8 *buf, __u8 oacs, bool_Bool is_json)
1729{
1730 init_d0_log_page(buf, oacs);
1731
1732 if (is_json) {
1733 struct json_object *root = json_create_object()json_object_new_object();
1734 struct json_object *stats = json_create_object()json_object_new_object();
1735 struct json_object *logPages = json_create_array()json_object_new_array();
1736
1737 json_object_add_value_array(root, "Extended Smart Log Page : 0xD0", logPages)json_object_object_add(root, "Extended Smart Log Page : 0xD0"
, logPages)
;
1738
1739 for (int i = 0; i < 7; i++)
1740 json_object_add_value_string(stats, d0_log_page[i].field,
1741 d0_log_page[i].datastr);
1742
1743 json_array_add_value_object(logPages, stats)json_object_array_add(logPages, stats);
1744 json_print_object(root, NULL)printf("%s", json_object_to_json_string_ext(root, (1 <<
1) | (1 << 4)))
;
1745 printf("\n");
1746 json_free_object(root)json_object_put(root);
1747 } else {
1748 for (int i = 0; i < 7; i++)
1749 printf("%-40s : %s\n", d0_log_page[i].field, d0_log_page[i].datastr);
1750 }
1751}
1752
1753static void print_hyperscale_nand_stats(__u8 *buf, bool_Bool is_json)
1754{
1755 init_hyperscale_BSSD_nand_stats(buf);
1756
1757 if (is_json) {
1758 struct json_object *root = json_create_object()json_object_new_object();
1759 struct json_object *stats = json_create_object()json_object_new_object();
1760 struct json_object *logPages = json_create_array()json_object_new_array();
1761
1762 json_object_add_value_array(root, "Extended Smart Log Page : 0xC0", logPages)json_object_object_add(root, "Extended Smart Log Page : 0xC0"
, logPages)
;
1763
1764 for (int i = 0; i < 22; i++)
1765 json_object_add_value_string(stats,
1766 hyperscale_BSSD_nand_stats[i].field,
1767 hyperscale_BSSD_nand_stats[i].datastr);
1768
1769 json_array_add_value_object(logPages, stats)json_object_array_add(logPages, stats);
1770 json_print_object(root, NULL)printf("%s", json_object_to_json_string_ext(root, (1 <<
1) | (1 << 4)))
;
1771 printf("\n");
1772 json_free_object(root)json_object_put(root);
1773 } else {
1774 for (int i = 0; i < 22; i++)
1775 printf("%-40s : %s\n", hyperscale_BSSD_nand_stats[i].field,
1776 hyperscale_BSSD_nand_stats[i].datastr);
1777 }
1778}
1779
1780static bool_Bool nsze_from_oacs;/* read nsze for now from idd[4059] */
1781
1782static int micron_nand_stats(int argc, char **argv,
1783 struct command *command, struct plugin *plugin)
1784{
1785 const char *desc = "Retrieve Micron NAND stats for the given device ";
1786 unsigned int extSmartLog[D0_log_size512/sizeof(int)] = { 0 };
1787 unsigned int logFB[FB_log_size512/sizeof(int)] = { 0 };
1788 unsigned char logC0[C0_log_size512] = { 0 };
1789 enum eDriveModel eModel = UNKNOWN_MODEL;
1790 struct nvme_id_ctrl ctrl;
1791 struct libnvme_passthru_cmd cmd;
1792 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
1793 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
1794 int err;
1795 __u8 nsze;
1796 bool_Bool has_d0_log = true1;
1797 bool_Bool has_fb_log = false0;
1798 bool_Bool is_json = false0;
1799 nsze_from_oacs = false0;
1800 const char *fmt = "Output format: normal|json";
1801 nvme_print_flags_t format;
1802
1803 NVME_ARGS_OUTPUT_FORMATS(opts, (JSON | NORMAL), fmt)nvme_args.supported_output_formats = (JSON | NORMAL); struct argconfig_commandline_options
opts[] = { {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)
0), 0, "Options", 0, ((void*)0)}, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, fmt
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
1804
1805 err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &eModel);
1806 if (err)
1807 return err;
1808
1809 err = validate_output_format(nvme_args.output_format, &format);
1810 if (err) {
1811 nvme_show_error("Invalid output format")nvme_show_message(1, "Invalid output format");
1812 return err;
1813 }
1814 is_json = format == JSON;
1815
1816 /* pull log details based on the model name */
1817 if (eModel == UNKNOWN_MODEL) {
1818 nvme_show_error("Unsupported drive model for vs-nand-stats command")nvme_show_message(1, "Unsupported drive model for vs-nand-stats command"
)
;
1819 return -1;
1820 }
1821
1822 nvme_init_identify_ctrl(&cmd, &ctrl);
1823 err = libnvme_exec_admin_passthru(hdl, &cmd);
1824 if (err) {
1825 nvme_show_err(err, "ERROR : identify_ctrl() failed");
1826 return -1;
1827 }
1828
1829 if ((ctrl.vs[536] == MICRON_CUST_ID_GG0x16) && (eModel == M51CX)) {
1830 err = nvme_get_log_simple(hdl, 0xC0, logC0, C0_log_size512);
1831 if (err == 0) {
1832 print_hyperscale_nand_stats((__u8 *)logC0, is_json);
1833 goto out;
1834 } else if (err < 0) {
1835 nvme_show_err(err, "Unable to retrieve extended smart log 0xC0 for the drive");
1836 return -1;
1837 }
1838 }
1839
1840 err = nvme_get_log_simple(hdl, 0xD0, extSmartLog, D0_log_size512);
1841 has_d0_log = !err;
1842
1843 /* should check for firmware version if this log is supported or not */
1844 if (eModel != M5407 && eModel != M5410) {
1845 err = nvme_get_log_simple(hdl, 0xFB, logFB, FB_log_size512);
1846 has_fb_log = !err;
1847 }
1848
1849 nsze = (ctrl.vs[987] == 0x12);
1850 if (!nsze && nsze_from_oacs)
1851 nsze = ((ctrl.oacs >> 3) & 0x1);
1852
1853 if (has_fb_log) {
1854 __u8 spec = 1; /* FB spec version */
1855
1856 print_nand_stats_fb((__u8 *)logFB, (__u8 *)extSmartLog, nsze, is_json, spec);
1857 err = 0;
1858 } else if (has_d0_log) {
1859 print_nand_stats_d0((__u8 *)extSmartLog, nsze, is_json);
1860 err = 0;
1861 }
1862out:
1863 if (err)
1864 nvme_show_err(err, "Unable to retrieve extended smart log for the drive");
1865
1866 return err;
1867}
1868
1869static void print_log(__u8 *buf, bool_Bool is_json, unsigned char ucLogID)
1870{
1871 struct json_object *root;
1872 struct json_object *logPages;
1873 struct json_object *stats = NULL((void*)0);
1874 int field_count = 0;
1875 struct request_data *log_pageID;
1876 char tempStr[256] = { 0 };
1877
1878 if (ucLogID == 0xE1) {
1879 log_pageID = e1_log_page;
1880 field_count = ARRAY_SIZE(e1_log_page)(sizeof(e1_log_page) / sizeof((e1_log_page)[0]) + 0);
1881 sprintf(tempStr, "SMART Extended Log:0x%X", ucLogID);
1882 } else if (ucLogID == 0xD0) {
1883 log_pageID = D0_log_page;
1884 field_count = ARRAY_SIZE(D0_log_page)(sizeof(D0_log_page) / sizeof((D0_log_page)[0]) + 0);
1885 sprintf(tempStr, "SMART Extended Log:0x%X", ucLogID);
1886 } else if (ucLogID == 0xC5) {
1887 log_pageID = C5_log_page;
1888 field_count = ARRAY_SIZE(C5_log_page)(sizeof(C5_log_page) / sizeof((C5_log_page)[0]) + 0);
1889 sprintf(tempStr, "Micron Workload Log:0x%X", ucLogID);
1890 } else if (ucLogID == 0xC6) {
1891 log_pageID = C6_log_page;
1892 field_count = ARRAY_SIZE(C6_log_page)(sizeof(C6_log_page) / sizeof((C6_log_page)[0]) + 0);
1893 sprintf(tempStr, "Vendor Telemetry Log:0x%X", ucLogID);
1894 } else {
1895 log_pageID = NULL((void*)0);
1896 }
1897
1898 if (is_json) {
1899 root = json_create_object()json_object_new_object();
1900 stats = json_create_object()json_object_new_object();
1901 logPages = json_create_array()json_object_new_array();
1902 json_object_add_value_array(root, tempStr, logPages)json_object_object_add(root, tempStr, logPages);
1903 } else {
1904 printf("%s\n", tempStr);
1905 }
1906
1907 if (log_pageID != NULL((void*)0))
1908 generic_structure_parser(buf, log_pageID, field_count, stats, 0, NULL((void*)0));
1909
1910 if (is_json) {
1911 json_array_add_value_object(logPages, stats)json_object_array_add(logPages, stats);
1912 json_print_object(root, NULL)printf("%s", json_object_to_json_string_ext(root, (1 <<
1) | (1 << 4)))
;
1913 printf("\n");
1914 json_free_object(root)json_object_put(root);
1915 }
1916}
1917
1918static int micron_smart_ext_log(int argc, char **argv,
1919 struct command *command, struct plugin *plugin)
1920{
1921 const char *desc = "Retrieve extended SMART logs for the given device ";
1922 unsigned int extSmartLog[E1_log_size256/sizeof(int)] = { 0 };
1923 enum eDriveModel eModel = UNKNOWN_MODEL;
1924 int err = 0;
1925 __u8 log_id;
1926 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
1927 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
1928 bool_Bool is_json = false0;
1929 const char *fmt = "Output format: normal|json";
1930 nvme_print_flags_t format;
1931
1932 NVME_ARGS_OUTPUT_FORMATS(opts, (JSON | NORMAL), fmt)nvme_args.supported_output_formats = (JSON | NORMAL); struct argconfig_commandline_options
opts[] = { {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)
0), 0, "Options", 0, ((void*)0)}, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, fmt
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
1933
1934 err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &eModel);
1935 if (err)
1936 return err;
1937
1938 err = validate_output_format(nvme_args.output_format, &format);
1939 if (err) {
1940 nvme_show_error("Invalid output format")nvme_show_message(1, "Invalid output format");
1941 return err;
1942 }
1943 is_json = format == JSON;
1944
1945 if (eModel == M51CX || eModel == M51BY || eModel == M51CY || eModel == M6003 ||
1946 eModel == M6004) {
1947 log_id = 0xE1;
1948 } else if (eModel == M6001) {
1949 log_id = 0xD0;
1950 } else {
1951 nvme_show_error("Unsupported drive model for vs-smart-ext-log command")nvme_show_message(1, "Unsupported drive model for vs-smart-ext-log command"
)
;
1952 err = -1;
1953 goto out;
1954 }
1955 err = nvme_get_log_simple(hdl, log_id, extSmartLog, E1_log_size256);
1956 if (!err)
1957 print_log((__u8 *)extSmartLog, is_json, log_id);
1958
1959out:
1960 if (err > 0)
1961 nvme_show_status(err);
1962 return err;
1963}
1964
1965static int micron_work_load_log(int argc, char **argv, struct command *acmd, struct plugin *plugin)
1966{
1967 const char *desc = "Retrieve Micron Workload logs for the given device ";
1968 unsigned int micronWorkLoadLog[C5_MicronWorkLoad_log_size256/sizeof(int)] = { 0 };
1969 enum eDriveModel eModel = UNKNOWN_MODEL;
1970 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
1971 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
1972
1973 int err = 0;
1974 bool_Bool is_json = false0;
1975 const char *fmt = "Output format: normal|json";
1976 nvme_print_flags_t format;
1977
1978 NVME_ARGS_OUTPUT_FORMATS(opts, (JSON | NORMAL), fmt)nvme_args.supported_output_formats = (JSON | NORMAL); struct argconfig_commandline_options
opts[] = { {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)
0), 0, "Options", 0, ((void*)0)}, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, fmt
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
1979
1980 err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &eModel);
1981 if (err)
1982 return err;
1983
1984 err = validate_output_format(nvme_args.output_format, &format);
1985 if (err) {
1986 nvme_show_error("Invalid output format")nvme_show_message(1, "Invalid output format");
1987 return err;
1988 }
1989 is_json = format == JSON;
1990
1991 if (eModel == M6001 || eModel == M6004 || eModel == M6003) {
1992 err = nvme_get_log_simple(hdl, 0xC5,
1993 micronWorkLoadLog, C5_MicronWorkLoad_log_size256);
1994 if (!err)
1995 print_log((__u8 *)micronWorkLoadLog, is_json, 0xC5);
1996 } else {
1997 nvme_show_error("Unsupported drive model for vs-work-load-log command")nvme_show_message(1, "Unsupported drive model for vs-work-load-log command"
)
;
1998 err = -1;
1999 goto out;
2000 }
2001
2002out:
2003 if (err > 0)
2004 nvme_show_status(err);
2005 return err;
2006}
2007
2008static int micron_vendor_telemetry_log(int argc, char **argv,
2009 struct command *command, struct plugin *plugin)
2010{
2011 const char *desc = "Retrieve Vendor Telemetry logs for the given device ";
2012 unsigned int vendorTelemetryLog[C6_log_size512/sizeof(int)] = { 0 };
2013 enum eDriveModel eModel = UNKNOWN_MODEL;
2014 int err = 0;
2015 bool_Bool is_json = false0;
2016 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
2017 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
2018
2019 const char *fmt = "Output format: normal|json";
2020 nvme_print_flags_t format;
2021
2022 NVME_ARGS_OUTPUT_FORMATS(opts, (JSON | NORMAL), fmt)nvme_args.supported_output_formats = (JSON | NORMAL); struct argconfig_commandline_options
opts[] = { {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)
0), 0, "Options", 0, ((void*)0)}, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, fmt
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
2023
2024 err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &eModel);
2025 if (err)
2026 return err;
2027
2028 err = validate_output_format(nvme_args.output_format, &format);
2029 if (err) {
2030 nvme_show_error("Invalid output format")nvme_show_message(1, "Invalid output format");
2031 return err;
2032 }
2033 is_json = format == JSON;
2034
2035 if (eModel == M6001 || eModel == M6004 || eModel == M6003) {
2036 err = nvme_get_log_simple(hdl, 0xC6, vendorTelemetryLog, C6_log_size512);
2037 if (!err)
2038 print_log((__u8 *)vendorTelemetryLog, is_json, 0xC6);
2039 } else {
2040 nvme_show_error("Unsupported drive model for vs-vendor-telemetry-log command")nvme_show_message(1, "Unsupported drive model for vs-vendor-telemetry-log command"
)
;
2041 err = -1;
2042 goto out;
2043 }
2044
2045out:
2046 if (err > 0)
2047 nvme_show_status(err);
2048 return err;
2049}
2050
2051#define LOGPULL_METADATA_FILE"logpull_metadata_info.json" "logpull_metadata_info.json"
2052#define LOGPULL_CMD_STATUS_FILE"logpull_cmd_status_info.csv" "logpull_cmd_status_info.csv"
2053
2054#define LOGPULL_PACKAGE_VERSION"1.4" "1.4"
2055
2056#define LOGPULL_STATUS_SUCCESS"Success" "Success"
2057
2058/*
2059 * Binary file names for each log, command and feature vs-internal-log collects.
2060 * These are the names expected by log decoders, so they must match exactly.
2061 */
2062#define LOG_FILE_ID_CTRL"nvme_controller_identify_data.bin" "nvme_controller_identify_data.bin"
2063#define LOG_FILE_ID_NS"identify_namespace_%d_data.bin" "identify_namespace_%d_data.bin"
2064#define LOG_FILE_SMART"smart_data.bin" "smart_data.bin"
2065#define LOG_FILE_ERROR_INFO"error_information_log.bin" "error_information_log.bin"
2066#define LOG_FILE_FW_SLOT"firmware_slot_info_log.bin" "firmware_slot_info_log.bin"
2067#define LOG_FILE_CHANGED_NS"changed_namespace_log.bin" "changed_namespace_log.bin"
2068#define LOG_FILE_CMD_EFFECTS"command_effects_log.bin" "command_effects_log.bin"
2069#define LOG_FILE_SELF_TEST"drive_self_test.bin" "drive_self_test.bin"
2070#define LOG_FILE_TELEMETRY_HOST"nvme_host_telemetry_log.bin" "nvme_host_telemetry_log.bin"
2071#define LOG_FILE_TELEMETRY_CTRL"nvme_controller_telemetry_log.bin" "nvme_controller_telemetry_log.bin"
2072#define LOG_FILE_PEVENT"persistent_event_log.bin" "persistent_event_log.bin"
2073
2074/* Vendor log files are named after their log page identifier. */
2075#define LOG_FILE_VS_LOG(id)"nvmelog_" "id" ".bin" "nvmelog_" #id ".bin"
2076
2077#define LOG_FILE_FEAT_ARBITRATION"nvme_feature_setting_arbitration.bin" "nvme_feature_setting_arbitration.bin"
2078#define LOG_FILE_FEAT_POWER_MGMT"nvme_feature_setting_pm.bin" "nvme_feature_setting_pm.bin"
2079#define LOG_FILE_FEAT_LBA_RANGE"nvme_feature_setting_lba_range_namespace_1.bin" "nvme_feature_setting_lba_range_namespace_1.bin"
2080#define LOG_FILE_FEAT_TEMP_THRESHOLD"nvme_feature_setting_temp_threshold.bin" "nvme_feature_setting_temp_threshold.bin"
2081#define LOG_FILE_FEAT_ERROR_RECOVERY"nvme_feature_setting_error_recovery.bin" "nvme_feature_setting_error_recovery.bin"
2082#define LOG_FILE_FEAT_VWC"nvme_feature_setting_volatile_write_cache.bin" "nvme_feature_setting_volatile_write_cache.bin"
2083#define LOG_FILE_FEAT_NUM_QUEUES"nvme_feature_setting_num_queues.bin" "nvme_feature_setting_num_queues.bin"
2084#define LOG_FILE_FEAT_IRQ_COAL"nvme_feature_setting_interrupt_coalescing.bin" "nvme_feature_setting_interrupt_coalescing.bin"
2085#define LOG_FILE_FEAT_IRQ_VECTOR"nvme_feature_setting_interrupt_vec_config.bin" "nvme_feature_setting_interrupt_vec_config.bin"
2086#define LOG_FILE_FEAT_WRITE_ATOMICITY"nvme_feature_setting_write_atomicity.bin" "nvme_feature_setting_write_atomicity.bin"
2087#define LOG_FILE_FEAT_ASYNC_EVENT"nvme_feature_setting_async_event_config.bin" "nvme_feature_setting_async_event_config.bin"
2088#define LOG_FILE_FEAT_SW_PROGRESS"nvme_feature_setting_sw_progress_marker.bin" "nvme_feature_setting_sw_progress_marker.bin"
2089
2090/*
2091 * Command info identifiers, keyed by the binary file each one describes. An
2092 * unrecognized name causes that log to be skipped.
2093 */
2094static const struct logpull_cmd_info {
2095 const char *cmd_info;
2096 __u8 opcode;
2097 __u8 log_id;
2098 __u16 cmd_class;
2099 __u16 cmd_code;
2100 const char *binary_file;
2101} logpull_cmd_info_table[] = {
2102 { "NVME_IDENTIFY_CONTROLLER", 0x06, 0, 0, 0, LOG_FILE_ID_CTRL"nvme_controller_identify_data.bin" },
2103 { "NVME_IDENTIFY_NAMESPACE_ALL", 0x06, 0, 0, 0, LOG_FILE_ID_NS"identify_namespace_%d_data.bin" },
2104 { "NVME_SMART_LOG", 0x02, 0x02, 0, 0, LOG_FILE_SMART"smart_data.bin" },
2105 { "NVME_ERROR_INFO_LOG", 0x02, 0x01, 0, 0, LOG_FILE_ERROR_INFO"error_information_log.bin" },
2106 { "NVME_FW_SLOT_INFO_LOG", 0x02, 0x03, 0, 0, LOG_FILE_FW_SLOT"firmware_slot_info_log.bin" },
2107 { "NVME_CHANGED_NAMESPACE_LIST_LOG", 0x02, 0x04, 0, 0, LOG_FILE_CHANGED_NS"changed_namespace_log.bin" },
2108 { "NVME_CMD_SUPPORTED_AND_EFFECTS_LOG", 0x02, 0x05, 0, 0, LOG_FILE_CMD_EFFECTS"command_effects_log.bin" },
2109 { "NVME_DEVICE_SELF_TEST_LOG", 0x02, 0x06, 0, 0, LOG_FILE_SELF_TEST"drive_self_test.bin" },
2110 { "NVME_HOST_TELEMETRY_LOG", 0x02, 0x07, 0, 0, LOG_FILE_TELEMETRY_HOST"nvme_host_telemetry_log.bin" },
2111 { "NVME_CTRL_TELEMETRY_LOG", 0x02, 0x08, 0, 0, LOG_FILE_TELEMETRY_CTRL"nvme_controller_telemetry_log.bin" },
2112 { "NVME_PERSISTENT_EVENT_LOG", 0x02, 0x0D, 0, 0, LOG_FILE_PEVENT"persistent_event_log.bin" },
2113 { "NVME_GET_FEATURE_ARBITRATION", 0, 0, 0, 0, LOG_FILE_FEAT_ARBITRATION"nvme_feature_setting_arbitration.bin" },
2114 { "NVME_GET_FEATURE_POWER_MGNT", 0, 0, 0, 0, LOG_FILE_FEAT_POWER_MGMT"nvme_feature_setting_pm.bin" },
2115 { "NVME_GET_FEATURE_LBA_RANGE_TYPE", 0, 0, 0, 0, LOG_FILE_FEAT_LBA_RANGE"nvme_feature_setting_lba_range_namespace_1.bin" },
2116 { "NVME_GET_FEATURE_TEMP_THRESHOLD", 0, 0, 0, 0, LOG_FILE_FEAT_TEMP_THRESHOLD"nvme_feature_setting_temp_threshold.bin" },
2117 { "NVME_GET_FEATURE_ERROR_RECOVERY", 0, 0, 0, 0, LOG_FILE_FEAT_ERROR_RECOVERY"nvme_feature_setting_error_recovery.bin" },
2118 { "NVME_GET_FEATURE_VOLATILE_WRITE_CACHE", 0, 0, 0, 0, LOG_FILE_FEAT_VWC"nvme_feature_setting_volatile_write_cache.bin" },
2119 { "NVME_GET_FEATURE_NUM_QUEUES", 0, 0, 0, 0, LOG_FILE_FEAT_NUM_QUEUES"nvme_feature_setting_num_queues.bin" },
2120 { "NVME_GET_FEATURE_INTERRUPT_COALESCING", 0, 0, 0, 0, LOG_FILE_FEAT_IRQ_COAL"nvme_feature_setting_interrupt_coalescing.bin" },
2121 { "NVME_GET_FEATURE_INTERRUPT_VECTOR_CONFIG", 0, 0, 0, 0, LOG_FILE_FEAT_IRQ_VECTOR"nvme_feature_setting_interrupt_vec_config.bin" },
2122 { "NVME_GET_FEATURE_WRITE_ATOMICITY", 0, 0, 0, 0, LOG_FILE_FEAT_WRITE_ATOMICITY"nvme_feature_setting_write_atomicity.bin" },
2123 { "NVME_GET_FEATURE_ASYNC_EVENT_CONFIG", 0, 0, 0, 0, LOG_FILE_FEAT_ASYNC_EVENT"nvme_feature_setting_async_event_config.bin" },
2124 { "NVME_GET_FEATURE_SW_PROGRESS_MARKER", 0, 0, 0, 0, LOG_FILE_FEAT_SW_PROGRESS"nvme_feature_setting_sw_progress_marker.bin" },
2125 { "VU_SMART_EXTENED_LOG", 0x02, 0xE1, 0, 0, LOG_FILE_VS_LOG(E1)"nvmelog_" "E1" ".bin" },
2126 { "MICRON_VS_LOG_D2", 0x02, 0xD2, 0, 0, LOG_FILE_VS_LOG(D2)"nvmelog_" "D2" ".bin" },
2127 { "MICRON_VS_LOG_E3", 0x02, 0xE3, 0, 0, LOG_FILE_VS_LOG(E3)"nvmelog_" "E3" ".bin" },
2128 { "MICRON_VS_LOG_E4", 0x02, 0xE4, 0, 0, LOG_FILE_VS_LOG(E4)"nvmelog_" "E4" ".bin" },
2129 { "MICRON_VS_LOG_E8", 0x02, 0xE8, 0, 0, LOG_FILE_VS_LOG(E8)"nvmelog_" "E8" ".bin" },
2130 { "MICRON_VS_LOG_E9", 0x02, 0xE9, 0, 0, LOG_FILE_VS_LOG(E9)"nvmelog_" "E9" ".bin" },
2131 { "MICRON_VS_LOG_EA", 0x02, 0xEA, 0, 0, LOG_FILE_VS_LOG(EA)"nvmelog_" "EA" ".bin" },
2132 { "MICRON_VS_LOG_FA", 0x02, 0xFA, 0, 0, LOG_FILE_VS_LOG(FA)"nvmelog_" "FA" ".bin" },
2133};
2134
2135/*
2136 * State for the cmd status CSV, set up once per debug-data collection.
2137 * Collection helpers are spread across several functions that don't share a
2138 * context argument, so the destination path and serial number are kept here
2139 * rather than threaded through every signature.
2140 */
2141static char logpull_csv_path[PATH_MAX4096];
2142static char logpull_csv_serial[sizeof(((struct nvme_id_ctrl *)0)->sn) + 1];
2143
2144/*
2145 * Tracks which table entries already have a Success row. Some log pages are
2146 * reachable from more than one collection table (LID 0x03, 0x05 and 0x06 are
2147 * collected generically and again as vendor log entries), and re-decoding the
2148 * same binary serves no purpose. A failed attempt is not recorded here, so a
2149 * later success on the same file still gets a row.
2150 */
2151static bool_Bool logpull_csv_logged[ARRAY_SIZE(logpull_cmd_info_table)(sizeof(logpull_cmd_info_table) / sizeof((logpull_cmd_info_table
)[0]) + 0)
];
2152
2153/*
2154 * Replace characters that would produce invalid JSON, in place. They are
2155 * substituted rather than escaped: these fields hold printable identifiers,
2156 * so anything else is already suspect, and malformed JSON would make the
2157 * whole metadata file unreadable.
2158 */
2159static char *sanitize_json_value(char *s)
2160{
2161 char *p;
2162
2163 for (p = s; *p; p++) {
2164 if (*p == '"' || *p == '\\' || !isprint((unsigned char)*p)((*__ctype_b_loc ())[(int) (((unsigned char)*p))] & (unsigned
short int) _ISprint)
)
2165 *p = '_';
2166 }
2167
2168 return s;
2169}
2170
2171/*
2172 * Create the cmd status CSV and write its header. Also records the serial
2173 * number and path used by LogCmdStatus(). Collection continues even if this
2174 * fails; the package is simply missing its log index.
2175 */
2176static void SetupCmdStatusLog(const char *ctrl_dir, const char *serial)
2177{
2178 FILE *fp = NULL((void*)0);
2179
2180 logpull_csv_path[0] = '\0';
2181 memset(logpull_csv_logged, 0, sizeof(logpull_csv_logged));
2182 snprintf(logpull_csv_serial, sizeof(logpull_csv_serial), "%s", serial);
2183
2184 if (snprintf(logpull_csv_path, sizeof(logpull_csv_path), "%s/%s",
2185 ctrl_dir, LOGPULL_CMD_STATUS_FILE"logpull_cmd_status_info.csv") >=
2186 (int)sizeof(logpull_csv_path)) {
2187 logpull_csv_path[0] = '\0';
2188 nvme_show_error("Path too long for %s", LOGPULL_CMD_STATUS_FILE)nvme_show_message(1, "Path too long for %s", "logpull_cmd_status_info.csv"
)
;
2189 return;
2190 }
2191
2192 fp = fopen(logpull_csv_path, "wb+");
2193 if (!fp) {
2194 nvme_show_error("Failed to create %s", logpull_csv_path)nvme_show_message(1, "Failed to create %s", logpull_csv_path);
2195 logpull_csv_path[0] = '\0';
2196 return;
2197 }
2198
2199 fprintf(fp,
2200 "serial_number,cmd_info,op_code,log_id,cmd_class,cmd_code,binary_file,execution_time_us,mse_status\n");
2201 fclose(fp);
2202}
2203
2204/*
2205 * Append a row to the cmd status CSV describing the collection of @file.
2206 *
2207 * @err is the result of the collection: 0 marks the log as available to
2208 * decode, any other value records the failure and excludes the log.
2209 * Files with no cmd_info identifier are skipped rather than listed under a
2210 * made-up name.
2211 *
2212 * execution_time_us is emitted as 0; the collection paths are not
2213 * instrumented for timing.
2214 */
2215static void LogCmdStatus(const char *file, int err)
2216{
2217 const struct logpull_cmd_info *info = NULL((void*)0);
2218 char status[256] = { 0 };
2219 FILE *fp = NULL((void*)0);
2220 size_t i;
2221
2222 if (!logpull_csv_path[0] || !file)
2223 return;
2224
2225 for (i = 0; i < ARRAY_SIZE(logpull_cmd_info_table)(sizeof(logpull_cmd_info_table) / sizeof((logpull_cmd_info_table
)[0]) + 0)
; i++) {
2226 if (!strcmp(file, logpull_cmd_info_table[i].binary_file)) {
2227 info = &logpull_cmd_info_table[i];
2228 break;
2229 }
2230 }
2231 if (!info || logpull_csv_logged[i])
2232 return;
2233 if (!err)
2234 logpull_csv_logged[i] = true1;
2235
2236 /*
2237 * Some status descriptions contain commas, which would split the last
2238 * cell across columns. Substitute them so the row keeps its 9 fields.
2239 */
2240 snprintf(status, sizeof(status), "%s",
2241 err ? libnvme_status_to_string(err, false0) : LOGPULL_STATUS_SUCCESS"Success");
2242 for (char *p = status; *p; p++) {
2243 if (*p == ',')
2244 *p = ';';
2245 }
2246
2247 fp = fopen(logpull_csv_path, "ab+");
2248 if (!fp)
2249 return;
2250
2251 fprintf(fp, "%s,%s,0x%.2X,0x%.2X,0x%.4X,0x%.4X,%s,%llu,%s\n",
2252 logpull_csv_serial, info->cmd_info, info->opcode, info->log_id,
2253 info->cmd_class, info->cmd_code, info->binary_file, 0ULL, status);
2254
2255 fclose(fp);
2256}
2257
2258/*
2259 * Write the log pull metadata JSON to the package root. This identifies the
2260 * drive the package was collected from.
2261 *
2262 * device_id and vendor_id must be correct for a valid decode.
2263 */
2264static void GetLogPullMetadata(const char *strOSDirName, struct nvme_id_ctrl *ctrlp,
2265 const char *tool_version)
2266{
2267 __cleanup_free__attribute__((cleanup(shr_freep))) char *tempFile = NULL((void*)0);
2268 __cleanup_free__attribute__((cleanup(shr_freep))) char *strPDir = NULL((void*)0);
2269 char model[sizeof(ctrlp->mn) + 1] = { 0 };
2270 char serial[sizeof(ctrlp->sn) + 1] = { 0 };
2271 char fwrev[sizeof(ctrlp->fr) + 1] = { 0 };
2272 char os_string[256] = { 0 };
2273 char timestamp[64] = { 0 };
2274 char utc_offset[16] = { 0 };
2275 char *mn, *sn, *fr;
2276 char *strDest = NULL((void*)0);
2277 FILE *fp = NULL((void*)0);
2278 struct tm *tmp;
2279 time_t t;
2280
2281 strPDir = strdup(strOSDirName);
2282 if (!strPDir) {
2283 nvme_show_error("Failed to allocate memory for directory name")nvme_show_message(1, "Failed to allocate memory for directory name"
)
;
2284 return;
2285 }
2286 strDest = dirname(strPDir);
2287
2288 if (asprintf(&tempFile, "%s/%s", strDest, LOGPULL_METADATA_FILE"logpull_metadata_info.json") < 0) {
2289 nvme_show_error("Failed to allocate memory for temp file name")nvme_show_message(1, "Failed to allocate memory for temp file name"
)
;
2290 return;
2291 }
2292
2293 /*
2294 * Identify strings are space-padded and not NUL-terminated; copy them
2295 * out and trim any whitespace.
2296 */
2297 snprintf(model, sizeof(model), "%-.*s", (int)sizeof(ctrlp->mn), ctrlp->mn);
2298 snprintf(serial, sizeof(serial), "%-.*s", (int)sizeof(ctrlp->sn), ctrlp->sn);
2299 snprintf(fwrev, sizeof(fwrev), "%-.*s", (int)sizeof(ctrlp->fr), ctrlp->fr);
2300
2301 mn = sanitize_json_value(shr_trim(model));
2302 sn = sanitize_json_value(shr_trim(serial));
2303 fr = sanitize_json_value(shr_trim(fwrev));
2304
2305 micron_get_os_string(os_string, sizeof(os_string));
2306 sanitize_json_value(os_string);
2307
2308 t = time(NULL((void*)0));
2309 tmp = localtime(&t);
2310 if (tmp) {
2311 char zone[8] = { 0 };
2312
2313 strftime(timestamp, sizeof(timestamp), "%a %b %d %H:%M:%S %Y", tmp);
2314 /* %z gives "+hhmm"; this field is written as "+hh:mm" */
2315 if (strftime(zone, sizeof(zone), "%z", tmp) == 5)
2316 snprintf(utc_offset, sizeof(utc_offset), "%.3s:%.2s",
2317 zone, zone + 3);
2318 else
2319 snprintf(utc_offset, sizeof(utc_offset), "%s", zone);
2320 }
2321
2322 fp = fopen(tempFile, "wb+");
2323 if (!fp) {
2324 nvme_show_error("Failed to create %s", tempFile)nvme_show_message(1, "Failed to create %s", tempFile);
2325 return;
2326 }
2327
2328 fprintf(fp, "{\n");
2329 fprintf(fp, " \"system_os\": \"%s\",\n", os_string);
2330 fprintf(fp, " \"logpull_timestamp\": \"%s\",\n", timestamp);
2331 fprintf(fp, " \"utc_offset\": \"%s\",\n", utc_offset);
2332 fprintf(fp, " \"package_version\": \"%s\",\n", LOGPULL_PACKAGE_VERSION"1.4");
2333 fprintf(fp, " \"tool_pull_name\": \"nvme-cli\",\n");
2334 fprintf(fp, " \"tool_pull_version\": \"%s\",\n", tool_version);
2335 fprintf(fp, " \"vendor_id\": \"0x%04X\",\n", vendor_id);
2336 fprintf(fp, " \"device_id\": \"0x%04X\",\n", device_id);
2337 fprintf(fp, " \"serial_number\": \"%s\",\n", sn);
2338 fprintf(fp, " \"model_number_identify\": \"%s\",\n", mn);
2339 fprintf(fp, " \"firmware_revision\": \"%s\"\n", fr);
2340 fprintf(fp, "}\n");
2341
2342 fclose(fp);
2343}
2344
2345static void GetDriveInfo(const char *strOSDirName, int nFD,
2346 struct nvme_id_ctrl *ctrlp)
2347{
2348 FILE *fpOutFile = NULL((void*)0);
2349 __cleanup_free__attribute__((cleanup(shr_freep))) char *tempFile = NULL((void*)0);
2350 char strBuffer[1024] = { 0 };
2351 char model[41] = { 0 };
2352 char serial[21] = { 0 };
2353 char fwrev[9] = { 0 };
2354 __cleanup_free__attribute__((cleanup(shr_freep))) char *strPDir = NULL((void*)0);
2355 char *strDest = NULL((void*)0);
2356
2357 strPDir = strdup(strOSDirName);
2358 if (!strPDir) {
2359 nvme_show_error("Failed to allocate memory for directory name")nvme_show_message(1, "Failed to allocate memory for directory name"
)
;
2360 return;
2361 }
2362 strDest = dirname(strPDir);
2363
2364 if (asprintf(&tempFile, "%s/%s", strDest, "drive-info.txt") < 0) {
2365 nvme_show_error("Failed to allocate memory for temp file name")nvme_show_message(1, "Failed to allocate memory for temp file name"
)
;
2366 return;
2367 }
2368
2369 fpOutFile = fopen(tempFile, "wb+");
2370 if (!fpOutFile) {
2371 nvme_show_error("Failed to create %s", tempFile)nvme_show_message(1, "Failed to create %s", tempFile);
2372 return;
2373 }
2374
2375 strncpy(model, ctrlp->mn, 40);
2376 strncpy(serial, ctrlp->sn, 20);
2377 strncpy(fwrev, ctrlp->fr, 8);
2378
2379 snprintf(strBuffer, sizeof(strBuffer),
2380 "********************\nDrive Info\n********************\n");
2381
2382 fprintf(fpOutFile, "%s", strBuffer);
2383 snprintf(strBuffer, sizeof(strBuffer),
2384 "%-20s : /dev/nvme%d\n%-20s : %s\n%-20s : %-20s\n%-20s : %-20s\n",
2385 "Device Name", nFD,
2386 "Model No", (char *)model,
2387 "Serial No", (char *)serial, "FW-Rev", (char *)fwrev);
2388
2389 fprintf(fpOutFile, "%s", strBuffer);
2390
2391 snprintf(strBuffer, sizeof(strBuffer),
2392 "\n********************\nPCI Info\n********************\n");
2393
2394 fprintf(fpOutFile, "%s", strBuffer);
2395
2396 snprintf(strBuffer, sizeof(strBuffer),
2397 "%-22s : %04X\n%-22s : %04X\n",
2398 "VendorId", vendor_id, "DeviceId", device_id);
2399 fprintf(fpOutFile, "%s", strBuffer);
2400 fclose(fpOutFile);
2401}
2402
2403static void GetTimestampInfo(const char *strOSDirName)
2404{
2405 __u8 outstr[1024];
2406 time_t t;
2407 struct tm *tmp;
2408 size_t num;
2409 size_t remaining;
2410 int n;
2411 __cleanup_free__attribute__((cleanup(shr_freep))) char *strPDir = NULL((void*)0);
2412 char *strDest = NULL((void*)0);
2413
2414 t = time(NULL((void*)0));
2415 tmp = localtime(&t);
2416 if (!tmp)
1
Assuming 'tmp' is non-null
2
Taking false branch
2417 return;
2418
2419 num = strftime((char *)outstr, sizeof(outstr),
2420 "Timestamp (UTC): %a, %d %b %Y %H:%M:%S %z", tmp);
2421 remaining = sizeof(outstr) - num;
2422 n = snprintf((char *)(outstr + num), remaining, "\nPackage Version: 1.4");
2423 if (n > 0)
3
Assuming 'n' is <= 0
4
Taking false branch
2424 num += (size_t)n < remaining ? (size_t)n : remaining - 1;
2425 if (num) {
5
Assuming 'num' is not equal to 0
6
Taking true branch
2426 strPDir = strdup(strOSDirName);
7
Memory is allocated
2427 if (!strPDir)
8
Assuming 'strPDir' is non-null
9
Taking false branch
2428 return;
2429 strDest = dirname(strPDir);
10
Potential leak of memory pointed to by 'strPDir'
2430 WriteData(outstr, num, strDest, "timestamp_info.txt", "timestamp");
2431 }
2432}
2433
2434static void GetCtrlIDDInfo(const char *dir, struct nvme_id_ctrl *ctrlp)
2435{
2436 WriteData((__u8 *)ctrlp, sizeof(*ctrlp), dir,
2437 LOG_FILE_ID_CTRL"nvme_controller_identify_data.bin", "id-ctrl");
2438 LogCmdStatus(LOG_FILE_ID_CTRL"nvme_controller_identify_data.bin", 0);
2439}
2440
2441static void GetSmartlogData(struct libnvme_transport_handle *hdl, const char *dir)
2442{
2443 struct nvme_smart_log smart_log;
2444 int err;
2445
2446 err = nvme_get_log_smart(hdl, NVME_NSID_ALL, &smart_log);
2447 if (!err)
2448 WriteData((__u8 *)&smart_log, sizeof(smart_log), dir,
2449 LOG_FILE_SMART"smart_data.bin", "smart log");
2450 LogCmdStatus(LOG_FILE_SMART"smart_data.bin", err);
2451}
2452
2453static void GetErrorlogData(struct libnvme_transport_handle *hdl, int entries, const char *dir)
2454{
2455 int logSize = entries * sizeof(struct nvme_error_log_page);
2456 __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) struct nvme_error_log_page *error_log =
2457 (struct nvme_error_log_page *)libnvme_alloc(logSize);
2458 struct libnvme_passthru_cmd cmd;
2459 size_t len;
2460 int err;
2461
2462 if (!error_log)
2463 return;
2464
2465 len = sizeof(*error_log) * entries;
2466
2467 nvme_init_get_log(&cmd, NVME_NSID_ALL, NVME_LOG_LID_ERROR,
2468 NVME_CSI_NVM, error_log, len);
2469
2470 err = libnvme_get_log(hdl, &cmd, false0, len);
2471 if (!err)
2472 WriteData((__u8 *)error_log, logSize, dir,
2473 LOG_FILE_ERROR_INFO"error_information_log.bin", "error log");
2474 LogCmdStatus(LOG_FILE_ERROR_INFO"error_information_log.bin", err);
2475}
2476
2477static void GetGenericLogs(struct libnvme_transport_handle *hdl, const char *dir)
2478{
2479 struct nvme_self_test_log self_test_log;
2480 struct nvme_firmware_slot fw_log;
2481 struct nvme_cmd_effects_log effects;
2482 struct nvme_persistent_event_log pevent_log;
2483 __cleanup_huge__attribute__((cleanup(libnvme_free_huge))) struct libnvme_mem_huge mh = { 0, };
2484 void *pevent_log_info = NULL((void*)0);
2485 __u32 log_len = 0;
2486 int err = 0;
2487 struct libnvme_passthru_cmd cmd;
2488 size_t len;
2489
2490 /* get self test log */
2491 len = sizeof(self_test_log);
2492 nvme_init_get_log(&cmd, NVME_NSID_ALL, NVME_LOG_LID_DEVICE_SELF_TEST,
2493 NVME_CSI_NVM, &self_test_log, len);
2494 err = libnvme_get_log(hdl, &cmd, false0, len);
2495 if (!err)
2496 WriteData((__u8 *)&self_test_log, len, dir,
2497 LOG_FILE_SELF_TEST"drive_self_test.bin", "self test log");
2498 LogCmdStatus(LOG_FILE_SELF_TEST"drive_self_test.bin", err);
2499
2500 /* get fw slot info log */
2501 len = sizeof(fw_log);
2502 nvme_init_get_log(&cmd, NVME_NSID_ALL, NVME_LOG_LID_FW_SLOT,
2503 NVME_CSI_NVM, &fw_log, len);
2504 err = libnvme_get_log(hdl, &cmd, false0, len);
2505 if (!err)
2506 WriteData((__u8 *)&fw_log, len, dir,
2507 LOG_FILE_FW_SLOT"firmware_slot_info_log.bin", "firmware log");
2508 LogCmdStatus(LOG_FILE_FW_SLOT"firmware_slot_info_log.bin", err);
2509
2510 /* get effects log */
2511 len = sizeof(effects);
2512 nvme_init_get_log_cmd_effects(&cmd, NVME_CSI_NVM, &effects);
2513 err = libnvme_get_log(hdl, &cmd, false0, len);
2514 if (!err)
2515 WriteData((__u8 *)&effects, len, dir,
2516 LOG_FILE_CMD_EFFECTS"command_effects_log.bin", "effects log");
2517 LogCmdStatus(LOG_FILE_CMD_EFFECTS"command_effects_log.bin", err);
2518
2519 /* get persistent event log */
2520 (void)nvme_get_log_persistent_event(hdl, NVME_PEVENT_LOG_RELEASE_CTX,
2521 &pevent_log, sizeof(pevent_log));
2522 memset(&pevent_log, 0, sizeof(pevent_log));
2523 err = nvme_get_log_persistent_event(hdl, NVME_PEVENT_LOG_EST_CTX_AND_READ,
2524 &pevent_log, sizeof(pevent_log));
2525 if (err) {
2526 nvme_show_error("Setting persistent event log read ctx failed (ignored)!")nvme_show_message(1, "Setting persistent event log read ctx failed (ignored)!"
)
;
2527 return;
2528 }
2529
2530 log_len = le64_to_cpu(pevent_log.tll);
2531 pevent_log_info = libnvme_alloc_huge(log_len, &mh);
2532 if (!pevent_log_info) {
2533 nvme_show_perror("could not alloc buffer for persistent event log page (ignored)!\n");
2534 return;
2535 }
2536
2537 err = nvme_get_log_persistent_event(hdl, NVME_PEVENT_LOG_READ,
2538 pevent_log_info, log_len);
2539 if (!err)
2540 WriteData((__u8 *)pevent_log_info, log_len, dir,
2541 LOG_FILE_PEVENT"persistent_event_log.bin", "persistent event log");
2542 LogCmdStatus(LOG_FILE_PEVENT"persistent_event_log.bin", err);
2543}
2544
2545static int GetNSIDDInfo(struct libnvme_transport_handle *hdl, const char *dir, int nsid)
2546{
2547 char file[PATH_MAX4096] = { 0 };
2548 struct nvme_id_ns ns;
2549 struct libnvme_passthru_cmd cmd;
2550 int err;
2551
2552 nvme_init_identify_ns(&cmd, nsid, &ns);
2553 err = libnvme_exec_admin_passthru(hdl, &cmd);
2554 if (!err) {
2555 snprintf(file, sizeof(file), LOG_FILE_ID_NS"identify_namespace_%d_data.bin", nsid);
2556 WriteData((__u8 *)&ns, sizeof(ns), dir, file, "id-ns");
2557 }
2558
2559 return err;
2560}
2561
2562static void GetOSConfig(const char *strOSDirName)
2563{
2564 __cleanup_free__attribute__((cleanup(shr_freep))) char *strFileName = NULL((void*)0);
2565
2566 if (asprintf(&strFileName, "%s/%s", strOSDirName, "os_config.txt") < 0)
2567 return;
2568 micron_write_os_config_to_file(strFileName);
2569}
2570
2571static int micron_telemetry_log(struct libnvme_transport_handle *hdl, __u8 type, __u8 **data,
2572 uint32_t *logSize, int da)
2573{
2574 struct libnvme_passthru_cmd cmd;
2575 int err;
2576 int bs = NVME_LOG_TELEM_BLOCK_SIZE;
2577 uint32_t dalb = 0;
2578 bool_Bool ctrl_init = (type == NVME_LOG_LID_TELEMETRY_CTRL);
2579 struct nvme_telemetry_log *log = libnvme_alloc(bs);
2580
2581 if (!log) {
2582 nvme_show_error("Failed to allocate memory for %s telemetry log header",nvme_show_message(1, "Failed to allocate memory for %s telemetry log header"
, ctrl_init ? "controller" : "host")
2583 ctrl_init ? "controller" : "host")nvme_show_message(1, "Failed to allocate memory for %s telemetry log header"
, ctrl_init ? "controller" : "host")
;
2584 return -ENOMEM12;
2585 }
2586
2587 if (ctrl_init) {
2588 nvme_init_get_log_telemetry_ctrl(&cmd, 0, log, bs);
2589 err = libnvme_get_log_dynamic_chunk(hdl, &cmd, true1, bs);
2590 } else {
2591 nvme_init_get_log_create_telemetry_host(&cmd, log);
2592 err = libnvme_get_log_dynamic_chunk(hdl, &cmd, false0, bs);
2593 }
2594
2595 if (err) {
2596 nvme_show_error("Failed to get telemetry log header for %s",nvme_show_message(1, "Failed to get telemetry log header for %s"
, ctrl_init ? "controller" : "host")
2597 ctrl_init ? "controller" : "host")nvme_show_message(1, "Failed to get telemetry log header for %s"
, ctrl_init ? "controller" : "host")
;
2598 libnvme_free(log);
2599 return err;
2600 }
2601
2602 switch (da) {
2603 case 1:
2604 dalb = le16_to_cpu(log->dalb1);
2605 break;
2606 case 2:
2607 dalb = le16_to_cpu(log->dalb2);
2608 break;
2609 case 3:
2610 dalb = le16_to_cpu(log->dalb3);
2611 break;
2612 case 4:
2613 dalb = le32_to_cpu(log->dalb4);
2614 break;
2615 default:
2616 nvme_show_error("Invalid data area: %d", da)nvme_show_message(1, "Invalid data area: %d", da);
2617 libnvme_free(log);
2618 return -EINVAL22;
2619 }
2620
2621 if (!dalb) {
2622 nvme_show_error("Requested telemetry data for %s data area %d is empty",nvme_show_message(1, "Requested telemetry data for %s data area %d is empty"
, ctrl_init ? "controller" : "host", da)
2623 ctrl_init ? "controller" : "host", da)nvme_show_message(1, "Requested telemetry data for %s data area %d is empty"
, ctrl_init ? "controller" : "host", da)
;
2624 libnvme_free(log);
2625 return -1;
2626 }
2627
2628 *logSize = (dalb + 1) * bs;
2629 log = libnvme_realloc(log, (size_t)(*logSize));
2630 if (!log) {
2631 nvme_show_error("Failed to allocate memory for %s telemetry data (%u bytes)",nvme_show_message(1, "Failed to allocate memory for %s telemetry data (%u bytes)"
, ctrl_init ? "controller" : "host", *logSize)
2632 ctrl_init ? "controller" : "host", *logSize)nvme_show_message(1, "Failed to allocate memory for %s telemetry data (%u bytes)"
, ctrl_init ? "controller" : "host", *logSize)
;
2633 return -ENOMEM12;
2634 }
2635
2636 if (ctrl_init) {
2637 nvme_init_get_log_telemetry_ctrl(&cmd, bs, (__u8 *)log + bs, *logSize - bs);
2638 err = libnvme_get_log_dynamic_chunk(hdl, &cmd, true1, *logSize - bs);
2639 } else {
2640 nvme_init_get_log_telemetry_host(&cmd, bs, (__u8 *)log + bs, *logSize - bs);
2641 err = libnvme_get_log_dynamic_chunk(hdl, &cmd, false0, *logSize - bs);
2642 }
2643
2644 if (!err) {
2645 *data = (__u8 *)log;
2646 } else {
2647 nvme_show_err(err, "Failed to get telemetry data for %s\n",
2648 ctrl_init ? "controller" : "host");
2649 libnvme_free(log);
2650 }
2651
2652 return err;
2653}
2654
2655static int GetTelemetryData(struct libnvme_transport_handle *hdl,
2656 const char *dir, bool_Bool da4_support)
2657{
2658 unsigned char *buffer = NULL((void*)0);
2659 int i, err;
2660 uint32_t logSize = 0;
2661 char msg[256] = { 0 };
2662 struct {
2663 __u8 log;
2664 char *file;
2665 } tmap[] = {
2666 {NVME_LOG_LID_TELEMETRY_HOST, LOG_FILE_TELEMETRY_HOST"nvme_host_telemetry_log.bin"},
2667 {NVME_LOG_LID_TELEMETRY_CTRL, LOG_FILE_TELEMETRY_CTRL"nvme_controller_telemetry_log.bin"},
2668 };
2669
2670 for (i = 0; i < (int)(ARRAY_SIZE(tmap)(sizeof(tmap) / sizeof((tmap)[0]) + 0)); i++) {
2671 err = micron_telemetry_log(hdl, tmap[i].log, &buffer, &logSize,
2672 da4_support ? 4 : 3);
2673 if (!err && logSize > 0 && buffer) {
2674 snprintf(msg, sizeof(msg), "telemetry log: 0x%X", tmap[i].log);
2675 WriteData(buffer, logSize, dir, tmap[i].file, msg);
2676 }
2677 LogCmdStatus(tmap[i].file, err);
2678 libnvme_free(buffer);
2679 buffer = NULL((void*)0);
2680 logSize = 0;
2681 }
2682 return err;
2683}
2684
2685static int GetFeatureSettings(struct libnvme_transport_handle *hdl, const char *dir)
2686{
2687 unsigned char *bufp, buf[4096] = { 0 };
2688 int i, err, len, errcnt = 0;
2689 __u64 attrVal = 0;
2690 char msg[256] = { 0 };
2691
2692 struct features {
2693 int id;
2694 char *file;
2695 } fmap[] = {
2696 {0x01, LOG_FILE_FEAT_ARBITRATION"nvme_feature_setting_arbitration.bin"},
2697 {0x02, LOG_FILE_FEAT_POWER_MGMT"nvme_feature_setting_pm.bin"},
2698 {0x03, LOG_FILE_FEAT_LBA_RANGE"nvme_feature_setting_lba_range_namespace_1.bin"},
2699 {0x04, LOG_FILE_FEAT_TEMP_THRESHOLD"nvme_feature_setting_temp_threshold.bin"},
2700 {0x05, LOG_FILE_FEAT_ERROR_RECOVERY"nvme_feature_setting_error_recovery.bin"},
2701 {0x06, LOG_FILE_FEAT_VWC"nvme_feature_setting_volatile_write_cache.bin"},
2702 {0x07, LOG_FILE_FEAT_NUM_QUEUES"nvme_feature_setting_num_queues.bin"},
2703 {0x08, LOG_FILE_FEAT_IRQ_COAL"nvme_feature_setting_interrupt_coalescing.bin"},
2704 {0x09, LOG_FILE_FEAT_IRQ_VECTOR"nvme_feature_setting_interrupt_vec_config.bin"},
2705 {0x0A, LOG_FILE_FEAT_WRITE_ATOMICITY"nvme_feature_setting_write_atomicity.bin"},
2706 {0x0B, LOG_FILE_FEAT_ASYNC_EVENT"nvme_feature_setting_async_event_config.bin"},
2707 {0x80, LOG_FILE_FEAT_SW_PROGRESS"nvme_feature_setting_sw_progress_marker.bin"},
2708 };
2709
2710 for (i = 0; i < (int)(ARRAY_SIZE(fmap)(sizeof(fmap) / sizeof((fmap)[0]) + 0)); i++) {
2711 if (fmap[i].id == 0x03) {
2712 len = 4096;
2713 bufp = (unsigned char *)(&buf[0]);
2714 } else {
2715 len = 0;
2716 bufp = NULL((void*)0);
2717 }
2718 err = nvme_get_features(hdl, 1, fmap[i].id, 0, 0x0, 0, bufp, len,
2719 &attrVal);
2720 if (!err) {
2721 snprintf(msg, sizeof(msg), "feature: 0x%X", fmap[i].id);
2722 WriteData((__u8 *)&attrVal, sizeof(attrVal), dir, fmap[i].file, msg);
2723 if (bufp)
2724 WriteData(bufp, len, dir, fmap[i].file, msg);
2725 } else {
2726 nvme_show_error("Feature 0x%x data not retrieved, error %d (ignored)!",nvme_show_message(1, "Feature 0x%x data not retrieved, error %d (ignored)!"
, fmap[i].id, err)
2727 fmap[i].id, err)nvme_show_message(1, "Feature 0x%x data not retrieved, error %d (ignored)!"
, fmap[i].id, err)
;
2728 errcnt++;
2729 }
2730 LogCmdStatus(fmap[i].file, err);
2731 }
2732 return (int)(errcnt == ARRAY_SIZE(fmap)(sizeof(fmap) / sizeof((fmap)[0]) + 0));
2733}
2734
2735static int micron_drive_info(int argc, char **argv, struct command *acmd,
2736 struct plugin *plugin)
2737{
2738 const char *desc = "Get drive HW information";
2739 struct nvme_id_ctrl ctrl = { 0 };
2740 struct libnvme_passthru_cmd admin_cmd = { 0 };
2741 struct libnvme_passthru_cmd cmd;
2742 unsigned char logC0[C0_log_size512] = { 0 };
2743 struct fb_drive_info {
2744 unsigned char hw_ver_major;
2745 unsigned char hw_ver_minor;
2746 unsigned char ftl_unit_size;
2747 unsigned short bs_ver_major;
2748 unsigned short bs_ver_minor;
2749 unsigned int ownership_status;
2750 } dinfo = { 0 };
2751 enum eDriveModel model = UNKNOWN_MODEL;
2752 __u8 custId = 0x10; /* default Micron generic */
2753 bool_Bool is_json = false0;
2754 struct json_object *root;
2755 struct json_object *driveInfo;
2756 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
2757 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
2758 int err = 0;
2759
2760 const char *fmt = "Output format: normal|json";
2761 nvme_print_flags_t format;
2762
2763 NVME_ARGS_OUTPUT_FORMATS(opts, (JSON | NORMAL), fmt)nvme_args.supported_output_formats = (JSON | NORMAL); struct argconfig_commandline_options
opts[] = { {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)
0), 0, "Options", 0, ((void*)0)}, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, fmt
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
2764
2765 err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &model);
2766 if (err)
2767 return err;
2768
2769 if (model == UNKNOWN_MODEL) {
2770 nvme_show_error("ERROR : Unsupported drive for vs-drive-info cmd")nvme_show_message(1, "ERROR : Unsupported drive for vs-drive-info cmd"
)
;
2771 return -1;
2772 }
2773
2774 err = validate_output_format(nvme_args.output_format, &format);
2775 if (err) {
2776 nvme_show_error("Invalid output format")nvme_show_message(1, "Invalid output format");
2777 return err;
2778 }
2779 is_json = format == JSON;
2780
2781 if (model == M5407) {
2782 admin_cmd.opcode = 0xDA;
2783 admin_cmd.addr = (__u64) (uintptr_t) &dinfo;
2784 admin_cmd.data_len = (__u32)sizeof(dinfo);
2785 admin_cmd.cdw12 = 3;
2786 err = libnvme_exec_admin_passthru(hdl, &admin_cmd);
2787 if (err) {
2788 nvme_show_error("ERROR : drive-info opcode failed with 0x%x", err)nvme_show_message(1, "ERROR : drive-info opcode failed with 0x%x"
, err)
;
2789 return -1;
2790 }
2791 } else {
2792 nvme_init_identify_ctrl(&cmd, &ctrl);
2793 err = libnvme_exec_admin_passthru(hdl, &cmd);
2794 if (err) {
2795 nvme_show_error("ERROR : identify_ctrl() failed with 0x%x", err)nvme_show_message(1, "ERROR : identify_ctrl() failed with 0x%x"
, err)
;
2796 return -1;
2797 }
2798 dinfo.hw_ver_major = ctrl.vs[820];
2799 dinfo.hw_ver_minor = ctrl.vs[821];
2800 dinfo.ftl_unit_size = ctrl.vs[822];
2801 custId = ctrl.vs[536];
2802 }
2803
2804 if ((custId == MICRON_CUST_ID_GG0x16) && (model == M51CX)) {
2805 err = nvme_get_log_simple(hdl, 0xC0, logC0, C0_log_size512);
2806 if (err == 0) {
2807 dinfo.bs_ver_major = *((__u16 *)(logC0+300));
2808 dinfo.bs_ver_minor = *((__u16 *)(logC0+302));
2809 dinfo.ownership_status = *((__u32 *)(logC0+312));
2810 } else {
2811 nvme_show_err(err, "Unable to retrieve extended smart log 0xC0 for the drive");
2812 return -1;
2813 }
2814 }
2815
2816 if (is_json) {
2817 struct json_object *pinfo = json_create_object()json_object_new_object();
2818 char tempstr[64] = { 0 };
2819 root = json_create_object()json_object_new_object();
2820 driveInfo = json_create_array()json_object_new_array();
2821 json_object_add_value_array(root, "Micron Drive HW Information", driveInfo)json_object_object_add(root, "Micron Drive HW Information", driveInfo
)
;
2822
2823 sprintf(tempstr, "%hhu.%hhu", dinfo.hw_ver_major, dinfo.hw_ver_minor);
2824 json_object_add_value_string(pinfo, "Drive Hardware Version", tempstr);
2825
2826 if (custId == MICRON_CUST_ID_GG0x16) {
2827 if (dinfo.ftl_unit_size) {
2828 sprintf(tempstr, "%u B",
2829 (unsigned int)(dinfo.ftl_unit_size * 1024));
2830 json_object_add_value_string(pinfo, "FTL_unit_size", tempstr);
2831 }
2832
2833 if (dinfo.bs_ver_major != 0 || dinfo.bs_ver_minor != 0) {
2834 sprintf(tempstr,
2835 "HyperScale Boot Version Spec.%hhu.%hhu"
2836 , (unsigned char)dinfo.bs_ver_major,
2837 (unsigned char)dinfo.bs_ver_minor);
2838 json_object_add_value_string(pinfo, "Boot Spec.Version", tempstr);
2839 }
2840
2841 if (dinfo.ownership_status == 0)
2842 sprintf(tempstr, "N/A");
2843 else if (dinfo.ownership_status == 1)
2844 sprintf(tempstr, "UNSET");
2845 else if (dinfo.ownership_status == 2)
2846 sprintf(tempstr, "SET");
2847 else if (dinfo.ownership_status == 3)
2848 sprintf(tempstr, "BLOCKED");
2849 json_object_add_value_string(pinfo, "Drive Ownership Status", tempstr);
2850
2851 } else {
2852 if (dinfo.ftl_unit_size) {
2853 sprintf(tempstr, "%hhu KB", dinfo.ftl_unit_size);
2854 json_object_add_value_string(pinfo, "FTL_unit_size", tempstr);
2855 }
2856 if (dinfo.bs_ver_major != 0 || dinfo.bs_ver_minor != 0) {
2857 sprintf(tempstr, "%hhu.%hhu", (unsigned char)dinfo.bs_ver_major,
2858 (unsigned char)dinfo.bs_ver_minor);
2859 json_object_add_value_string(pinfo, "Boot Spec.Version", tempstr);
2860 }
2861 }
2862 json_array_add_value_object(driveInfo, pinfo)json_object_array_add(driveInfo, pinfo);
2863 json_print_object(root, NULL)printf("%s", json_object_to_json_string_ext(root, (1 <<
1) | (1 << 4)))
;
2864 printf("\n");
2865 json_free_object(root)json_object_put(root);
2866 } else {
2867 printf("Drive Hardware Version: %hhu.%hhu\n",
2868 dinfo.hw_ver_major, dinfo.hw_ver_minor);
2869
2870 if (custId == MICRON_CUST_ID_GG0x16) {
2871 if (dinfo.ftl_unit_size)
2872 printf("FTL_unit_size: %u B\n",
2873 (unsigned int)(dinfo.ftl_unit_size * 1024));
2874
2875 if (dinfo.bs_ver_major != 0 || dinfo.bs_ver_minor != 0) {
2876 printf(
2877 "Boot Spec.Version: HyperScale Boot Version Spec.%hhu.%hhu\n"
2878 , (unsigned char)dinfo.bs_ver_major,
2879 (unsigned char)dinfo.bs_ver_minor);
2880 }
2881
2882 if (dinfo.ownership_status == 0)
2883 printf("Drive Ownership Status: N/A\n");
2884 else if (dinfo.ownership_status == 1)
2885 printf("Drive Ownership Status: UNSET\n");
2886 else if (dinfo.ownership_status == 2)
2887 printf("Drive Ownership Status: SET\n");
2888 else if (dinfo.ownership_status == 3)
2889 printf("Drive Ownership Status: BLOCKED\n");
2890
2891 } else {
2892 if (dinfo.ftl_unit_size)
2893 printf("FTL_unit_size: %hhu KB\n", dinfo.ftl_unit_size);
2894 if (dinfo.bs_ver_major != 0 || dinfo.bs_ver_minor != 0)
2895 printf(
2896 "Boot Spec.Version: %hhu.%hhu\n"
2897 , (unsigned char)dinfo.bs_ver_major,
2898 (unsigned char)dinfo.bs_ver_minor);
2899 }
2900
2901 }
2902
2903 return 0;
2904}
2905
2906static int micron_cloud_ssd_plugin_version(int argc, char **argv,
2907 struct command *command, struct plugin *plugin)
2908{
2909 const char *desc = "Prints the Micron cloud SSD plugin version.";
2910 int err;
2911
2912 NVME_ARGS(opts)nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0
, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT
, &nvme_args.verbose, 0, "Increase output verbosity", 0, }
, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0,
"suppress informational output", 0, }, {"output-format", 'o'
, "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
2913
2914 err = parse_args(argc, argv, desc, opts);
2915 if (err)
2916 return err;
2917
2918 nvme_show_result("nvme-cli Micron cloud SSD plugin version: %s.%s",nvme_show_message(0, "nvme-cli Micron cloud SSD plugin version: %s.%s"
, __version_major, __version_minor)
2919 __version_major, __version_minor)nvme_show_message(0, "nvme-cli Micron cloud SSD plugin version: %s.%s"
, __version_major, __version_minor)
;
2920 return 0;
2921}
2922
2923static int micron_plugin_version(int argc, char **argv, struct command *acmd,
2924 struct plugin *plugin)
2925{
2926 const char *desc = "Prints the Micron plugin version.";
2927 int err;
2928
2929 NVME_ARGS(opts)nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0
, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT
, &nvme_args.verbose, 0, "Increase output verbosity", 0, }
, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0,
"suppress informational output", 0, }, {"output-format", 'o'
, "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
2930
2931 err = parse_args(argc, argv, desc, opts);
2932 if (err)
2933 return err;
2934
2935 nvme_show_result("nvme-cli Micron plugin version: %s.%s.%s",nvme_show_message(0, "nvme-cli Micron plugin version: %s.%s.%s"
, __version_major, __version_minor, __version_patch)
2936 __version_major, __version_minor, __version_patch)nvme_show_message(0, "nvme-cli Micron plugin version: %s.%s.%s"
, __version_major, __version_minor, __version_patch)
;
2937 return 0;
2938}
2939
2940/* Binary format of firmware activation history entry */
2941struct __packed__attribute__((__packed__)) fw_activation_history_entry {
2942 __u8 version;
2943 __u8 length;
2944 __u16 rsvd1;
2945 __le16 valid;
2946 __le64 power_on_hour;
2947 __le64 rsvd2;
2948 __le64 power_cycle_count;
2949 __u8 previous_fw[8];
2950 __u8 activated_fw[8];
2951 __u8 slot;
2952 __u8 commit_action_type;
2953 __le16 result;
2954 __u8 rsvd3[14];
2955};
2956
2957/* Binary format for firmware activation history table */
2958struct __packed__attribute__((__packed__)) micron_fw_activation_history_table {
2959 __u8 log_page;
2960 __u8 rsvd1[3];
2961 __le32 num_entries;
2962 struct fw_activation_history_entry entries[20];
2963 __u8 rsvd2[2790];
2964 __u16 version;
2965 __u8 GUID[16];
2966};
2967
2968static int display_fw_activate_entry(int entry_count, struct fw_activation_history_entry *entry,
2969 char *formatted_entry, size_t buf_size,
2970 struct json_object *stats)
2971{
2972 time_t timestamp, hours;
2973 char buffer[32];
2974 __u8 minutes, seconds;
2975 static const char * const ca[] = {"000b", "001b", "010b", "011b"};
2976 char *ptr = formatted_entry;
2977 int index = 0, entry_size = 82;
2978 int remaining;
2979 bool_Bool is_json = false0;
2980
2981 if ((entry->version != 1 && entry->version != 2) || entry->length != 64)
2982 return -EINVAL22;
2983
2984 if (stats)
2985 is_json = true1;
2986
2987 remaining = buf_size - (ptr - formatted_entry);
2988 snprintf(ptr, remaining, "%d", entry_count);
2989 if (is_json)
2990 json_object_add_value_int(stats, "Entry Number", le32_to_cpu(entry_count))json_object_object_add(stats, "Entry Number", json_object_new_int
(le32_to_cpu(entry_count)))
;
2991
2992 ptr += 10;
2993
2994 timestamp = (le64_to_cpu(entry->power_on_hour) & 0x0000FFFFFFFFFFFFUL) / 1000;
2995 hours = timestamp / 3600;
2996 minutes = (timestamp % 3600) / 60;
2997 seconds = (timestamp % 3600) % 60;
2998 remaining = buf_size - (ptr - formatted_entry);
2999 snprintf(ptr, remaining, "|%"PRIu64"l" "u"":%hhu:%hhu", (uint64_t)hours, minutes, seconds);
3000 if (is_json)
3001 json_object_add_value_string(stats, "Power On Hour", ptr+1);
3002
3003 ptr += 16;
3004
3005 remaining = buf_size - (ptr - formatted_entry);
3006 snprintf(ptr, remaining, "| %"PRIu64"l" "u", le64_to_cpu(entry->power_cycle_count));
3007 if (is_json)
3008 json_object_add_value_int(stats, "Power cycle count",json_object_object_add(stats, "Power cycle count", json_object_new_int
(le32_to_cpu(entry->power_cycle_count)))
3009 le32_to_cpu(entry->power_cycle_count))json_object_object_add(stats, "Power cycle count", json_object_new_int
(le32_to_cpu(entry->power_cycle_count)))
;
3010
3011 ptr += 10;
3012
3013 /* firmware details */
3014 memset(buffer, 0, sizeof(buffer));
3015 memcpy(buffer, entry->previous_fw, sizeof(entry->previous_fw));
3016 remaining = buf_size - (ptr - formatted_entry);
3017 snprintf(ptr, remaining, "| %s", buffer);
3018 if (is_json)
3019 json_object_add_value_string(stats, "Previous firmware", buffer);
3020
3021 ptr += 11;
3022
3023 memset(buffer, 0, sizeof(buffer));
3024 memcpy(buffer, entry->activated_fw, sizeof(entry->activated_fw));
3025 remaining = buf_size - (ptr - formatted_entry);
3026 snprintf(ptr, remaining, "| %s", buffer);
3027 if (is_json)
3028 json_object_add_value_string(stats, "New FW activated", buffer);
3029
3030 ptr += 12;
3031
3032 /* firmware slot and commit action*/
3033 remaining = buf_size - (ptr - formatted_entry);
3034 snprintf(ptr, remaining, "| %d", entry->slot);
3035 if (is_json)
3036 json_object_add_value_int(stats, "Slot number", entry->slot)json_object_object_add(stats, "Slot number", json_object_new_int
(entry->slot))
;
3037
3038 ptr += 9;
3039
3040 remaining = buf_size - (ptr - formatted_entry);
3041 if (entry->commit_action_type <= 3)
3042 snprintf(ptr, remaining, "| %s", ca[entry->commit_action_type]);
3043 else
3044 snprintf(ptr, remaining, "| xxxb");
3045
3046 if (is_json)
3047 json_object_add_value_string(stats, "Commit Action Type", ptr+2);
3048
3049 ptr += 9;
3050
3051 /* result */
3052 remaining = buf_size - (ptr - formatted_entry);
3053 if (entry->result)
3054 snprintf(ptr, remaining, "| Fail #%d", entry->result);
3055 else
3056 snprintf(ptr, remaining, "| pass");
3057
3058 if (is_json) {
3059 json_object_add_value_string(stats, "Result", ptr+2);
3060 return 0;
3061 }
3062
3063 /* replace all null characters with spaces */
3064 ptr = formatted_entry;
3065 while (index < entry_size) {
3066 if (ptr[index] == '\0')
3067 ptr[index] = ' ';
3068 index++;
3069 }
3070 return 0;
3071}
3072
3073static void micron_fw_activation_history_header_print(void)
3074{
3075 /* header to be printed field widths = 10 | 12 | 10 | 11 | 12 | 9 | 9 | 9 */
3076 printf("__________________________________________________________________________________\n");
3077 printf(" | | | | | | |\n");
3078 printf("Firmware | Power On | Power | Previous | New FW | Slot | Commit | Result\n");
3079 printf("Activation| Hour | cycle | firmware | activated | number | Action |\n");
3080 printf("Counter | | count | | | | Type |\n");
3081 printf("__________|___________|_________|__________|___________|________|________|________\n");
3082}
3083
3084static int micron_fw_activation_history(int argc, char **argv, struct command *acmd,
3085 struct plugin *plugin)
3086{
3087 const char *desc = "Retrieve Firmware Activation history of the given drive";
3088 char formatted_output[100];
3089 int count = 0;
3090 unsigned int logC2[C2_log_size4096/sizeof(int)] = { 0 };
3091 enum eDriveModel eModel = UNKNOWN_MODEL;
3092 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
3093 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
3094 int err;
3095 bool_Bool is_json = false0;
3096 struct json_object *root, *fw_act, *element;
3097 struct json_object *entry;
3098
3099 const char *fmt = "Output format: normal|json";
3100 nvme_print_flags_t format;
3101
3102 NVME_ARGS_OUTPUT_FORMATS(opts, (JSON | NORMAL), fmt)nvme_args.supported_output_formats = (JSON | NORMAL); struct argconfig_commandline_options
opts[] = { {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)
0), 0, "Options", 0, ((void*)0)}, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, fmt
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
3103
3104 err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &eModel);
3105 if (err)
3106 return err;
3107
3108 err = validate_output_format(nvme_args.output_format, &format);
3109 if (err) {
3110 nvme_show_error("Invalid output format")nvme_show_message(1, "Invalid output format");
3111 return err;
3112 }
3113 is_json = format == JSON;
3114
3115 /* check if product supports fw_history log */
3116 err = -EINVAL22;
3117 if ((eModel != M51CX) && (eModel != M51BY) && (eModel != M51CY)
3118 && (eModel != M6003) && (eModel != M6004)) {
3119 nvme_show_error("Unsupported drive model for vs-fw-activate-history command")nvme_show_message(1, "Unsupported drive model for vs-fw-activate-history command"
)
;
3120 goto out;
3121 }
3122
3123 err = nvme_get_log_simple(hdl, 0xC2, logC2, C2_log_size4096);
3124 if (err) {
3125 nvme_show_err(err, "Failed to retrieve fw activation history log");
3126 goto out;
3127 }
3128
3129 /* check if we have at least one entry to print */
3130 struct micron_fw_activation_history_table *table =
3131 (struct micron_fw_activation_history_table *)logC2;
3132
3133 /* check version and log page */
3134 if (table->log_page != 0xC2 || (table->version != 2 && table->version != 1)) {
3135 nvme_show_error("Unsupported fw activation history page: %x, version: %x",nvme_show_message(1, "Unsupported fw activation history page: %x, version: %x"
, table->log_page, table->version)
3136 table->log_page, table->version)nvme_show_message(1, "Unsupported fw activation history page: %x, version: %x"
, table->log_page, table->version)
;
3137 goto out;
3138 }
3139
3140 if (!table->num_entries) {
3141 nvme_show_error("No entries were found in fw activation history log")nvme_show_message(1, "No entries were found in fw activation history log"
)
;
3142 goto out;
3143 }
3144
3145 /* device-supplied entry count stays within the fixed table */
3146 if (le32_to_cpu(table->num_entries) > ARRAY_SIZE(table->entries)(sizeof(table->entries) / sizeof((table->entries)[0]) +
0)
)
3147 table->num_entries = cpu_to_le32(ARRAY_SIZE(table->entries)(sizeof(table->entries) / sizeof((table->entries)[0]) +
0)
);
3148
3149 if (is_json) {
3150 root = json_create_object()json_object_new_object();
3151 fw_act = json_create_object()json_object_new_object();
3152 json_object_add_value_object(root, "vs-fw-activation-history", fw_act)json_object_object_add(root, "vs-fw-activation-history", fw_act
)
;
3153 json_object_add_value_int(fw_act, "Total Entry Num",json_object_object_add(fw_act, "Total Entry Num", json_object_new_int
(le32_to_cpu(table->num_entries)))
3154 le32_to_cpu(table->num_entries))json_object_object_add(fw_act, "Total Entry Num", json_object_new_int
(le32_to_cpu(table->num_entries)))
;
3155 entry = json_create_array()json_object_new_array();
3156 json_object_add_value_array(fw_act, "Entry", entry)json_object_object_add(fw_act, "Entry", entry);
3157 for (count = 0; count < table->num_entries; count++) {
3158 element = json_create_object()json_object_new_object();
3159 if (!display_fw_activate_entry(count, &table->entries[count],
3160 formatted_output, sizeof(formatted_output),
3161 element))
3162 json_array_add_value_object(entry, element)json_object_array_add(entry, element);
3163 }
3164 json_print_object(root, NULL)printf("%s", json_object_to_json_string_ext(root, (1 <<
1) | (1 << 4)))
;
3165 printf("\n");
3166 json_free_object(root)json_object_put(root);
3167 } else {
3168 micron_fw_activation_history_header_print();
3169 for (count = 0; count < table->num_entries; count++) {
3170 memset(formatted_output, '\0', 100);
3171 if (!display_fw_activate_entry(count, &table->entries[count],
3172 formatted_output,
3173 sizeof(formatted_output), NULL((void*)0)))
3174 printf("%s\n", formatted_output);
3175 }
3176 }
3177out:
3178 return err;
3179}
3180
3181#define MICRON_FID_LATENCY_MONITOR0xD0 0xD0
3182#define MICRON_LOG_LATENCY_MONITOR0xD1 0xD1
3183
3184static int micron_latency_stats_track(int argc, char **argv, struct command *acmd,
3185 struct plugin *plugin)
3186{
3187 int err = 0;
3188 __u64 result = 0;
3189 const char *desc = "Enable, Disable or Get cmd latency monitoring stats";
3190 const char *option = "enable or disable or status, default is status";
3191 const char *cmdstr =
3192 "commands to monitor for - all|read|write|trim, default is all i.e, enabled for all commands"
3193 ;
3194 const char *thrtime =
3195 "The threshold value to use for latency monitoring in milliseconds, default is 800ms"
3196 ;
3197
3198 int fid = MICRON_FID_LATENCY_MONITOR0xD0;
3199 enum eDriveModel model = UNKNOWN_MODEL;
3200 uint32_t command_mask = 0x7; /* 1:read 2:write 4:trim 7:all */
3201 uint32_t timing_mask = 0x08080800; /* R[31-24]:W[23:16]:T[15:8]:0 */
3202 uint32_t enable = 2;
3203 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
3204 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
3205 struct {
3206 char *option;
3207 char *command;
3208 uint32_t threshold;
3209 } opt = {
3210 .option = "status",
3211 .command = "all",
3212 .threshold = 0
3213 };
3214
3215 NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"option", 'O', "option", CFG_STRING, &opt.option,
1, option, 0, }, {"command", 'c', "command", CFG_STRING, &
opt.command, 1, cmdstr, 0, }, {"threshold", 't', "NUM", CFG_POSITIVE
, &opt.threshold, 1, thrtime, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
3216 OPT_STRING("option", 'O', "option", &opt.option, option),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"option", 'O', "option", CFG_STRING, &opt.option,
1, option, 0, }, {"command", 'c', "command", CFG_STRING, &
opt.command, 1, cmdstr, 0, }, {"threshold", 't', "NUM", CFG_POSITIVE
, &opt.threshold, 1, thrtime, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
3217 OPT_STRING("command", 'c', "command", &opt.command, cmdstr),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"option", 'O', "option", CFG_STRING, &opt.option,
1, option, 0, }, {"command", 'c', "command", CFG_STRING, &
opt.command, 1, cmdstr, 0, }, {"threshold", 't', "NUM", CFG_POSITIVE
, &opt.threshold, 1, thrtime, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
3218 OPT_UINT("threshold", 't', &opt.threshold, thrtime))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"option", 'O', "option", CFG_STRING, &opt.option,
1, option, 0, }, {"command", 'c', "command", CFG_STRING, &
opt.command, 1, cmdstr, 0, }, {"threshold", 't', "NUM", CFG_POSITIVE
, &opt.threshold, 1, thrtime, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
3219
3220
3221 err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &model);
3222 if (err)
3223 return err;
3224
3225 if (!strcmp(opt.option, "enable")) {
3226 enable = 1;
3227 } else if (!strcmp(opt.option, "disable")) {
3228 enable = 0;
3229 } else if (strcmp(opt.option, "status")) {
3230 nvme_show_error("Invalid control option %s specified", opt.option)nvme_show_message(1, "Invalid control option %s specified", opt
.option)
;
3231 return -1;
3232 }
3233
3234 err = nvme_get_features(hdl, 0, fid, 0, 0, 0, NULL((void*)0), 0, &result);
3235 if (err) {
3236 nvme_show_error("Failed to retrieve latency monitoring feature status")nvme_show_message(1, "Failed to retrieve latency monitoring feature status"
)
;
3237 return err;
3238 }
3239
3240 /* If it is to retrieve the status only */
3241 if (enable == 2) {
3242 printf("Latency Tracking Statistics is currently %s",
3243 (result & 0xFFFF0000) ? "enabled" : "disabled");
3244 if ((result & 7) == 7) {
3245 printf(" for All commands\n");
3246 } else if ((result & 7) > 0) {
3247 printf(" for");
3248 if (result & 1)
3249 printf(" Read");
3250 if (result & 2)
3251 printf(" Write");
3252 if (result & 4)
3253 printf(" Trim");
3254 printf(" commands\n");
3255 } else if (!result) {
3256 printf("\n");
3257 }
3258 return err;
3259 }
3260
3261 /* read and validate threshold values if enable option is specified */
3262 if (enable == 1) {
3263 if (opt.threshold > 2550) {
3264 nvme_show_error("The maximum threshold value cannot be more than 2550 ms")nvme_show_message(1, "The maximum threshold value cannot be more than 2550 ms"
)
;
3265 return -1;
3266 } else if (opt.threshold % 10) {
3267 /* timing mask is in terms of 10ms units, so min allowed is 10ms */
3268 nvme_show_error("The threshold value should be multiple of 10 ms")nvme_show_message(1, "The threshold value should be multiple of 10 ms"
)
;
3269 return -1;
3270 }
3271 opt.threshold /= 10;
3272 }
3273
3274 /* read-in command(s) to be monitored */
3275 if (!strcmp(opt.command, "read")) {
3276 command_mask = 0x1;
3277 timing_mask = (opt.threshold << 24);
3278 } else if (!strcmp(opt.command, "write")) {
3279 command_mask = 0x2;
3280 timing_mask = (opt.threshold << 16);
3281 } else if (!strcmp(opt.command, "trim")) {
3282 command_mask = 0x4;
3283 timing_mask = (opt.threshold << 8);
3284 } else if (strcmp(opt.command, "all")) {
3285 nvme_show_error("Invalid command %s specified for option %s",nvme_show_message(1, "Invalid command %s specified for option %s"
, opt.command, opt.option)
3286 opt.command, opt.option)nvme_show_message(1, "Invalid command %s specified for option %s"
, opt.command, opt.option)
;
3287 return -1;
3288 }
3289
3290 err = nvme_set_features(hdl, 0, MICRON_FID_LATENCY_MONITOR0xD0, 1, enable,
3291 command_mask, timing_mask, 0, 0, NULL((void*)0), 0, &result);
3292 if (!err) {
3293 nvme_show_verbose_result("Successfully %sd latency monitoring for %s commands with %dms threshold",nvme_show_verbose_message("Successfully %sd latency monitoring for %s commands with %dms threshold"
, opt.option, opt.command, !opt.threshold ? 800 : opt.threshold
* 10)
3294 opt.option, opt.command, !opt.threshold ? 800 : opt.threshold * 10)nvme_show_verbose_message("Successfully %sd latency monitoring for %s commands with %dms threshold"
, opt.option, opt.command, !opt.threshold ? 800 : opt.threshold
* 10)
;
3295 } else {
3296 nvme_show_error("Failed to %s latency monitoring for %s commands with %dms threshold",nvme_show_message(1, "Failed to %s latency monitoring for %s commands with %dms threshold"
, opt.option, opt.command, !opt.threshold ? 800 : opt.threshold
* 10)
3297 opt.option, opt.command, !opt.threshold ? 800 : opt.threshold * 10)nvme_show_message(1, "Failed to %s latency monitoring for %s commands with %dms threshold"
, opt.option, opt.command, !opt.threshold ? 800 : opt.threshold
* 10)
;
3298 }
3299
3300 return err;
3301}
3302
3303
3304static int micron_latency_stats_logs(int argc, char **argv, struct command *acmd,
3305 struct plugin *plugin)
3306{
3307#define LATENCY_LOG_ENTRIES16 16
3308 struct latency_log_entry {
3309 uint64_t timestamp;
3310 uint32_t latency;
3311 uint32_t cmdtag;
3312 union {
3313 struct {
3314 uint32_t opcode:8;
3315 uint32_t fuse:2;
3316 uint32_t rsvd1:4;
3317 uint32_t psdt:2;
3318 uint32_t cid:16;
3319 };
3320 uint32_t dw0;
3321 };
3322 uint32_t nsid;
3323 uint32_t slba_low;
3324 uint32_t slba_high;
3325 union {
3326 struct {
3327 uint32_t nlb:16;
3328 uint32_t rsvd2:9;
3329 uint32_t deac:1;
3330 uint32_t prinfo:4;
3331 uint32_t fua:1;
3332 uint32_t lr:1;
3333 };
3334 uint32_t dw12;
3335 };
3336 uint32_t dsm;
3337 uint32_t rfu[6];
3338 } log[LATENCY_LOG_ENTRIES16];
3339 enum eDriveModel model = UNKNOWN_MODEL;
3340 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
3341 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
3342 int err = -1;
3343 const char *desc = "Display Latency tracking log information";
3344
3345 NVME_ARGS(opts)nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0
, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT
, &nvme_args.verbose, 0, "Increase output verbosity", 0, }
, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0,
"suppress informational output", 0, }, {"output-format", 'o'
, "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
3346
3347 err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &model);
3348 if (err)
3349 return err;
3350 memset(&log, 0, sizeof(log));
3351 err = nvme_get_log_simple(hdl, 0xD1, &log, sizeof(log));
3352 if (err) {
3353 nvme_show_err(err, "Unable to retrieve the latency stats log");
3354 return err;
3355 }
3356 /* print header and each log entry */
3357 printf("Timestamp, Latency, CmdTag, Opcode, Fuse, Psdt, Cid, Nsid, Slba_L, Slba_H, Nlb, ");
3358 printf("DEAC, PRINFO, FUA, LR\n");
3359 for (int i = 0; i < LATENCY_LOG_ENTRIES16; i++)
3360 printf("%"PRIu64"l" "u"",%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u\n",
3361 log[i].timestamp, log[i].latency, log[i].cmdtag, log[i].opcode,
3362 log[i].fuse, log[i].psdt, log[i].cid, log[i].nsid,
3363 log[i].slba_low, log[i].slba_high, log[i].nlb,
3364 log[i].deac, log[i].prinfo, log[i].fua, log[i].lr);
3365 printf("\n");
3366 return err;
3367}
3368
3369static int micron_latency_stats_info(int argc, char **argv, struct command *acmd,
3370 struct plugin *plugin)
3371{
3372 const char *desc = "display command latency statistics";
3373 const char *cmdstr = "command to display stats - all|read|write|trim, default is all";
3374 int err = 0;
3375 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
3376 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
3377 enum eDriveModel model = UNKNOWN_MODEL;
3378 #define LATENCY_BUCKET_COUNT32 32
3379 #define LATENCY_BUCKET_RSVD32 32
3380 struct micron_latency_stats {
3381 uint64_t version; /* major << 32 | minior */
3382 uint64_t all_cmds[LATENCY_BUCKET_COUNT32 + LATENCY_BUCKET_RSVD32];
3383 uint64_t read_cmds[LATENCY_BUCKET_COUNT32 + LATENCY_BUCKET_RSVD32];
3384 uint64_t write_cmds[LATENCY_BUCKET_COUNT32 + LATENCY_BUCKET_RSVD32];
3385 uint64_t trim_cmds[LATENCY_BUCKET_COUNT32 + LATENCY_BUCKET_RSVD32];
3386 uint32_t reserved[255]; /* round up to 4K */
3387 } log;
3388
3389 struct latency_thresholds {
3390 uint32_t start;
3391 uint32_t end;
3392 char *unit;
3393 } thresholds[LATENCY_BUCKET_COUNT32] = {
3394 {0, 50, "us"}, {50, 100, "us"}, {100, 150, "us"}, {150, 200, "us"},
3395 {200, 300, "us"}, {300, 400, "us"}, {400, 500, "us"}, {500, 600, "us"},
3396 {600, 700, "us"}, {700, 800, "us"}, {800, 900, "us"}, {900, 1000, "us"},
3397 {1, 5, "ms"}, {5, 10, "ms"}, {10, 20, "ms"}, {20, 50, "ms"}, {50, 100, "ms"},
3398 {100, 200, "ms"}, {200, 300, "ms"}, {300, 400, "ms"}, {400, 500, "ms"},
3399 {500, 600, "ms"}, {600, 700, "ms"}, {700, 800, "ms"}, {800, 900, "ms"},
3400 {900, 1000, "ms"}, {1, 2, "s"}, {2, 3, "s"}, {3, 4, "s"}, {4, 5, "s"},
3401 {5, 8, "s"},
3402 {8, INT_MAX2147483647, "s"},
3403 };
3404
3405 struct {
3406 char *command;
3407 } opt = {
3408 .command = "all"
3409 };
3410
3411 uint64_t *cmd_stats = &log.all_cmds[0];
3412 char *cmd_str = "All";
3413
3414 NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"command", 'c', "command", CFG_STRING, &opt.command
, 1, cmdstr, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, (
(void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v'
, "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
3415 OPT_STRING("command", 'c', "command", &opt.command, cmdstr))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"command", 'c', "command", CFG_STRING, &opt.command
, 1, cmdstr, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, (
(void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v'
, "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
3416
3417 err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &model);
3418 if (err)
3419 return err;
3420 if (!strcmp(opt.command, "read")) {
3421 cmd_stats = &log.read_cmds[0];
3422 cmd_str = "Read";
3423 } else if (!strcmp(opt.command, "write")) {
3424 cmd_stats = &log.write_cmds[0];
3425 cmd_str = "Write";
3426 } else if (!strcmp(opt.command, "trim")) {
3427 cmd_stats = &log.trim_cmds[0];
3428 cmd_str = "Trim";
3429 } else if (strcmp(opt.command, "all")) {
3430 nvme_show_error("Invalid command option %s to display latency stats", opt.command)nvme_show_message(1, "Invalid command option %s to display latency stats"
, opt.command)
;
3431 return -1;
3432 }
3433
3434 memset(&log, 0, sizeof(log));
3435 err = nvme_get_log_simple(hdl, 0xD0, &log, sizeof(log));
3436 if (err) {
3437 nvme_show_err(err, "Unable to retrieve latency stats log for the drive");
3438 return err;
3439 }
3440 printf("Micron IO %s Command Latency Statistics\n"
3441 "Major Revision : %d\nMinor Revision : %d\n",
3442 cmd_str, (int)(log.version >> 32), (int)(log.version & 0xFFFFFFFF));
3443 printf("=============================================\n");
3444 printf("Bucket Start End Command Count\n");
3445 printf("=============================================\n");
3446
3447 for (int b = 0; b < LATENCY_BUCKET_COUNT32; b++) {
3448 int bucket = b + 1;
3449 char start[32] = { 0 };
3450 char end[32] = { 0 };
3451
3452 sprintf(start, "%u%s", thresholds[b].start, thresholds[b].unit);
3453 if (thresholds[b].end == INT_MAX2147483647)
3454 sprintf(end, "INF");
3455 else
3456 sprintf(end, "%u%s", thresholds[b].end, thresholds[b].unit);
3457 printf("%2d %8s %8s %8"PRIu64"l" "u""\n", bucket, start, end, cmd_stats[b]);
3458 }
3459 return err;
3460}
3461
3462static int micron_ocp_smart_health_logs(int argc, char **argv, struct command *acmd,
3463 struct plugin *plugin)
3464{
3465 const char *desc = "Retrieve Smart or Extended Smart Health log for the given device ";
3466 unsigned int logC0[C0_log_size512/sizeof(int)] = { 0 };
3467 unsigned int logFB[FB_log_size512/sizeof(int)] = { 0 };
3468 struct nvme_id_ctrl ctrl;
3469 enum eDriveModel eModel = UNKNOWN_MODEL;
3470 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
3471 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
3472 bool_Bool is_json = false0;
3473 nsze_from_oacs = false0;
3474 const char *fmt = "Output format: normal|json";
3475 nvme_print_flags_t format;
3476 int err = 0;
3477
3478 NVME_ARGS_OUTPUT_FORMATS(opts, (JSON | NORMAL), fmt)nvme_args.supported_output_formats = (JSON | NORMAL); struct argconfig_commandline_options
opts[] = { {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)
0), 0, "Options", 0, ((void*)0)}, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, fmt
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
3479
3480 err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &eModel);
3481 if (err)
3482 return err;
3483
3484 err = validate_output_format(nvme_args.output_format, &format);
3485 if (err) {
3486 nvme_show_error("Invalid output format")nvme_show_message(1, "Invalid output format");
3487 return err;
3488 }
3489 is_json = format == JSON;
3490
3491 /* For M5410 and M5407, this option prints 0xFB log page */
3492 if (eModel == M5410 || eModel == M5407) {
3493 __u8 spec = (eModel == M5410) ? 0 : 1;
3494 __u8 nsze;
3495 struct libnvme_passthru_cmd cmd;
3496
3497 nvme_init_identify_ctrl(&cmd, &ctrl);
3498 err = libnvme_exec_admin_passthru(hdl, &cmd);
3499 if (!err)
3500 err = nvme_get_log_simple(hdl, 0xFB, logFB, FB_log_size512);
3501 if (err) {
3502 nvme_show_err(err, "Unable to retrieve smart log 0xFB for the drive");
3503 goto out;
3504 }
3505
3506 nsze = (ctrl.vs[987] == 0x12);
3507 if (!nsze && nsze_from_oacs)
3508 nsze = ((ctrl.oacs >> 3) & 0x1);
3509 print_nand_stats_fb((__u8 *)logFB, NULL((void*)0), nsze, is_json, spec);
3510 goto out;
3511 }
3512
3513 /* check for models that support 0xC0 log */
3514 if ((eModel != M51CX) && (eModel != M51BY) && (eModel != M51CY)
3515 && (eModel != M6003) && (eModel != M6004)) {
3516 nvme_show_error("Unsupported drive model for vs-smart-add-log command")nvme_show_message(1, "Unsupported drive model for vs-smart-add-log command"
)
;
3517 err = -1;
3518 goto out;
3519 }
3520
3521 err = nvme_get_log_simple(hdl, 0xC0, logC0, C0_log_size512);
3522 if (!err)
3523 print_smart_cloud_health_log((__u8 *)logC0, is_json, eModel);
3524 else
3525 nvme_show_err(err, "Unable to retrieve extended smart log 0xC0 for the drive");
3526out:
3527 return err;
3528}
3529
3530static int micron_clr_fw_activation_history(int argc, char **argv,
3531 struct command *command, struct plugin *plugin)
3532{
3533 const char *desc = "Clear FW activation history";
3534 __u64 result = 0;
3535 __u8 fid = MICRON_FEATURE_CLEAR_FW_ACTIVATION_HISTORY0xC1;
3536 enum eDriveModel model = UNKNOWN_MODEL;
3537 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
3538 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
3539
3540 NVME_ARGS(opts)nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0
, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT
, &nvme_args.verbose, 0, "Increase output verbosity", 0, }
, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0,
"suppress informational output", 0, }, {"output-format", 'o'
, "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
3541 int err = 0;
3542
3543 err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &model);
3544 if (err)
3545 return err;
3546
3547 if ((model != M51CX) && (model != M51BY) && (model != M51CY)
3548 && (model != M6003) && (model != M6004)) {
3549 nvme_show_error("This option is not supported for specified drive")nvme_show_message(1, "This option is not supported for specified drive"
)
;
3550 return err;
3551 }
3552
3553 err = nvme_set_features_simple(hdl, 1 << 31, fid, 0, 0, &result);
3554 if (!err)
3555 err = (int)result;
3556 else
3557 nvme_show_err(err, "Failed to clear fw activation history");
3558
3559 return err;
3560}
3561
3562static int micron_telemetry_cntrl_option(int argc, char **argv,
3563 struct command *command, struct plugin *plugin)
3564{
3565 int err = 0;
3566 __u64 result = 0;
3567 const char *desc = "Enable or Disable Controller telemetry log generation";
3568 const char *option = "enable or disable or status";
3569 const char *select =
3570 "select/save values: enable/disable options1 - save (persistent), 0 - non-persistent and for status options: 0 - current, 1 - default, 2-saved"
3571 ;
3572
3573 int fid = MICRON_FEATURE_TELEMETRY_CONTROL_OPTION0xCF;
3574 enum eDriveModel model = UNKNOWN_MODEL;
3575 struct nvme_id_ctrl ctrl = { 0 };
3576 struct libnvme_passthru_cmd cmd;
3577 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
3578 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
3579
3580 struct {
3581 char *option;
3582 int select;
3583 } opt = {
3584 .option = "disable",
3585 .select = 0,
3586 };
3587
3588 NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"option", 'O', "option", CFG_STRING, &opt.option,
1, option, 0, }, {"select", 's', "NUM", CFG_POSITIVE, &opt
.select, 1, select, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
3589 OPT_STRING("option", 'O', "option", &opt.option, option),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"option", 'O', "option", CFG_STRING, &opt.option,
1, option, 0, }, {"select", 's', "NUM", CFG_POSITIVE, &opt
.select, 1, select, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
3590 OPT_UINT("select", 's', &opt.select, select))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"option", 'O', "option", CFG_STRING, &opt.option,
1, option, 0, }, {"select", 's', "NUM", CFG_POSITIVE, &opt
.select, 1, select, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
3591
3592 err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &model);
3593 if (err)
3594 return err;
3595
3596 nvme_init_identify_ctrl(&cmd, &ctrl);
3597 err = libnvme_exec_admin_passthru(hdl, &cmd);
3598 if ((ctrl.lpa & 0x8) != 0x8) {
3599 printf("drive doesn't support host/controller generated telemetry logs\n");
3600 return err;
3601 }
3602
3603 if (!strcmp(opt.option, "enable")) {
3604 err = nvme_set_features(hdl, 1, fid, (opt.select & 0x1), 1, 0, 0, 0, 0,
3605 NULL((void*)0), 0, &result);
3606 if (!err)
3607 nvme_show_verbose_result("successfully set controller telemetry option")nvme_show_verbose_message("successfully set controller telemetry option"
)
;
3608 else
3609 nvme_show_error("Failed to set controller telemetry option")nvme_show_message(1, "Failed to set controller telemetry option"
)
;
3610 } else if (!strcmp(opt.option, "disable")) {
3611 err = nvme_set_features(hdl, 1, fid, (opt.select & 0x1), 0, 0, 0, 0, 0,
3612 NULL((void*)0), 0, &result);
3613 if (!err)
3614 nvme_show_verbose_result("successfully disabled controller telemetry option")nvme_show_verbose_message("successfully disabled controller telemetry option"
)
;
3615 else
3616 nvme_show_error("Failed to disable controller telemetry option")nvme_show_message(1, "Failed to disable controller telemetry option"
)
;
3617 } else if (!strcmp(opt.option, "status")) {
3618 err = nvme_get_features(hdl, 1, fid, opt.select & 0x3, 0, 0, NULL((void*)0), 0,
3619 &result);
3620 if (!err)
3621 printf("Controller telemetry option : %s\n",
3622 (result) ? "enabled" : "disabled");
3623 else
3624 nvme_show_error("Failed to retrieve controller telemetry option")nvme_show_message(1, "Failed to retrieve controller telemetry option"
)
;
3625 } else {
3626 nvme_show_error("invalid option %s, valid values are enable,disable or status",nvme_show_message(1, "invalid option %s, valid values are enable,disable or status"
, opt.option)
3627 opt.option)nvme_show_message(1, "invalid option %s, valid values are enable,disable or status"
, opt.option)
;
3628 return -1;
3629 }
3630
3631 return err;
3632}
3633
3634/* M51XX models log page header */
3635struct micron_common_log_header {
3636 uint8_t id;
3637 uint8_t version;
3638 uint16_t pn;
3639 uint32_t log_size;
3640 uint32_t max_size;
3641 uint32_t write_pointer;
3642 uint32_t next_pointer;
3643 uint32_t overwritten_bytes;
3644 uint8_t flags;
3645 uint8_t reserved[7];
3646};
3647
3648/* helper function to retrieve logs with specific offset and max chunk size */
3649int nvme_get_log_lpo(struct libnvme_transport_handle *hdl, __u8 log_id, __u32 lpo, __u32 chunk,
3650 __u32 data_len, void *data)
3651{
3652 __u32 offset = lpo, xfer_len = data_len;
3653 struct libnvme_passthru_cmd cmd;
3654 void *ptr = data;
3655 int ret = 0;
3656
3657 /* divide data into multiple chunks */
3658 do {
3659 xfer_len = data_len - offset;
3660 if (xfer_len > chunk)
3661 xfer_len = chunk;
3662
3663 nvme_init_get_log(&cmd, NVME_NSID_ALL, log_id, NVME_CSI_NVM,
3664 ptr, xfer_len);
3665 nvme_init_get_log_lpo(&cmd, lpo);
3666 ret = libnvme_get_log(hdl, &cmd, false0, xfer_len);
3667 if (ret)
3668 return ret;
3669 offset += xfer_len;
3670 ptr += xfer_len;
3671 } while (offset < data_len);
3672 return ret;
3673}
3674
3675/* retrieves logs with common log format */
3676static int get_common_log(struct libnvme_transport_handle *hdl, uint8_t id, uint8_t **buf, int *size)
3677{
3678 struct micron_common_log_header hdr = { 0 };
3679 int log_size = sizeof(hdr), first = 0, second = 0;
3680 uint8_t *buffer = NULL((void*)0);
3681 int ret = -1;
3682 int chunk = 0x4000; /* max chunk size to be used for these logs */
3683
3684 ret = nvme_get_log_simple(hdl, id, &hdr, sizeof(hdr));
3685 if (ret) {
3686 nvme_show_error("pull hdr failed for %u with error: 0x%x", id, ret)nvme_show_message(1, "pull hdr failed for %u with error: 0x%x"
, id, ret)
;
3687 return ret;
3688 }
3689
3690 if (hdr.id != id || !hdr.log_size || !hdr.max_size ||
3691 hdr.write_pointer < sizeof(hdr)) {
3692 nvme_show_error(nvme_show_message(1, "invalid log data for LOG: 0x%X, id: 0x%X, size: %u, max: %u, wp: %u, flags: %u, np: %u\n"
, id, hdr.id, hdr.log_size, hdr.max_size, hdr.write_pointer, hdr
.flags, hdr.next_pointer)
3693 "invalid log data for LOG: 0x%X, id: 0x%X, size: %u, max: %u, wp: %u, flags: %u, np: %u\n"nvme_show_message(1, "invalid log data for LOG: 0x%X, id: 0x%X, size: %u, max: %u, wp: %u, flags: %u, np: %u\n"
, id, hdr.id, hdr.log_size, hdr.max_size, hdr.write_pointer, hdr
.flags, hdr.next_pointer)
3694 , id, hdr.id, hdr.log_size, hdr.max_size, hdr.write_pointer, hdr.flags,nvme_show_message(1, "invalid log data for LOG: 0x%X, id: 0x%X, size: %u, max: %u, wp: %u, flags: %u, np: %u\n"
, id, hdr.id, hdr.log_size, hdr.max_size, hdr.write_pointer, hdr
.flags, hdr.next_pointer)
3695 hdr.next_pointer)nvme_show_message(1, "invalid log data for LOG: 0x%X, id: 0x%X, size: %u, max: %u, wp: %u, flags: %u, np: %u\n"
, id, hdr.id, hdr.log_size, hdr.max_size, hdr.write_pointer, hdr
.flags, hdr.next_pointer)
;
3696 return 1;
3697 }
3698
3699 /*
3700 * we may have just 32-bytes for some models; write to wfile if log hasn't
3701 * yet reached its max size
3702 */
3703 if (hdr.log_size == sizeof(hdr)) {
3704 buffer = (uint8_t *)libnvme_alloc(sizeof(hdr));
3705 if (!buffer) {
3706 nvme_show_error("malloc of %zu bytes failed for log: 0x%X",nvme_show_message(1, "malloc of %zu bytes failed for log: 0x%X"
, sizeof(hdr), id)
3707 sizeof(hdr), id)nvme_show_message(1, "malloc of %zu bytes failed for log: 0x%X"
, sizeof(hdr), id)
;
3708 return -ENOMEM12;
3709 }
3710 memcpy(buffer, (uint8_t *)&hdr, sizeof(hdr));
3711 } else if (hdr.log_size < hdr.max_size) {
3712 /* log_size includes the header, so the payload is the remainder */
3713 uint32_t payload = hdr.log_size - sizeof(hdr);
3714
3715 buffer = (uint8_t *)libnvme_alloc(hdr.log_size);
3716 if (!buffer) {
3717 nvme_show_error("malloc of %u bytes failed for log: 0x%X",nvme_show_message(1, "malloc of %u bytes failed for log: 0x%X"
, hdr.log_size, id)
3718 hdr.log_size, id)nvme_show_message(1, "malloc of %u bytes failed for log: 0x%X"
, hdr.log_size, id)
;
3719 return -ENOMEM12;
3720 }
3721 memcpy(buffer, &hdr, sizeof(hdr));
3722 ret = nvme_get_log_lpo(hdl, id, sizeof(hdr), chunk, payload,
3723 buffer + sizeof(hdr));
3724 if (!ret)
3725 log_size += payload;
3726 } else if (hdr.log_size >= hdr.max_size) {
3727 /*
3728 * reached maximum, to maintain, sequence we need to depend on write
3729 * pointer to detect wrap-overs. FW doesn't yet implement the condition
3730 * hdr.log_size > hdr.max_size; also ignore over-written log data; we
3731 * also ignore collisions for now
3732 */
3733 buffer = (uint8_t *)libnvme_alloc(hdr.max_size + sizeof(hdr));
3734 if (!buffer) {
3735 nvme_show_error("malloc of %zu bytes failed for log: 0x%X",nvme_show_message(1, "malloc of %zu bytes failed for log: 0x%X"
, hdr.max_size + sizeof(hdr), id)
3736 hdr.max_size + sizeof(hdr), id)nvme_show_message(1, "malloc of %zu bytes failed for log: 0x%X"
, hdr.max_size + sizeof(hdr), id)
;
3737 return -ENOMEM12;
3738 }
3739 memcpy(buffer, &hdr, sizeof(hdr));
3740
3741 first = hdr.max_size - hdr.write_pointer;
3742 second = hdr.write_pointer - sizeof(hdr);
3743
3744 if (first) {
3745 ret = nvme_get_log_lpo(hdl, id, hdr.write_pointer, chunk, first,
3746 buffer + sizeof(hdr));
3747 if (ret) {
3748 libnvme_free(buffer);
3749 nvme_show_error("failed to get log: 0x%X", id)nvme_show_message(1, "failed to get log: 0x%X", id);
3750 return ret;
3751 }
3752 log_size += first;
3753 }
3754 if (second) {
3755 ret = nvme_get_log_lpo(hdl, id, sizeof(hdr), chunk, second,
3756 buffer + sizeof(hdr) + first);
3757 if (ret) {
3758 nvme_show_error("failed to get log: 0x%X", id)nvme_show_message(1, "failed to get log: 0x%X", id);
3759 libnvme_free(buffer);
3760 return ret;
3761 }
3762 log_size += second;
3763 }
3764 }
3765 *buf = buffer;
3766 *size = log_size;
3767 return ret;
3768}
3769
3770static int GetOcpEnhancedTelemetryLogs(struct libnvme_transport_handle *hdl, const char *dir)
3771{
3772 int err = 0;
3773 unsigned int uiBufferSize = 512;
3774 unsigned char pBuffer[512] = { 0 };
3775 __u64 result = 0;
3776
3777 pBuffer[1] = 1;
3778
3779 /* Enable ETDAS so Data Area 4 is included in the telemetry logs */
3780 err = nvme_set_features(hdl, NVME_NSID_ALL,
3781 MICRON_FEATURE_OCP_ENHANCED_TELEMETRY0x16, 1, 0, 0, 0,
3782 0, 0, pBuffer, uiBufferSize, &result);
3783
3784 if (err)
3785 nvme_show_error("Failed to set ETDAS, Data Area 4 won't be available")nvme_show_message(1, "Failed to set ETDAS, Data Area 4 won't be available"
)
;
3786
3787 return GetTelemetryData(hdl, dir, !err);
3788}
3789
3790static int micron_internal_logs(int argc, char **argv, struct command *acmd,
3791 struct plugin *plugin)
3792{
3793 int err = -EINVAL22;
3794 int ctrlIdx, telemetry_option = 0;
3795 int ns_err;
3796 char strOSDirName[1024];
3797 char strCtrlDirName[1024];
3798 char strMainDirName[256];
3799 unsigned int *puiIDDBuf;
3800 unsigned int uiMask;
3801 struct nvme_id_ctrl ctrl;
3802 struct libnvme_passthru_cmd cmd;
3803 char safe_sn[sizeof(ctrl.sn) + 1] = { 0 };
3804 char msg[256] = { 0 };
3805 int c_logs_index = 8; /* should be current size of aVendorLogs */
3806 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
3807 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
3808 struct {
3809 unsigned char ucLogPage;
3810 const char *strFileName;
3811 int nLogSize;
3812 int nMaxSize;
3813 } aVendorLogs[32] = {
3814 { 0x03, LOG_FILE_FW_SLOT"firmware_slot_info_log.bin", 512, 0 },
3815 { 0xC1, LOG_FILE_VS_LOG(C1)"nvmelog_" "C1" ".bin", 0, 0 },
3816 { 0xC2, LOG_FILE_VS_LOG(C2)"nvmelog_" "C2" ".bin", 0, 0 },
3817 { 0xC4, LOG_FILE_VS_LOG(C4)"nvmelog_" "C4" ".bin", 0, 0 },
3818 { 0xC5, LOG_FILE_VS_LOG(C5)"nvmelog_" "C5" ".bin", C5_log_size(((452 + 16 * 1024) / 4) * 4096), 0 },
3819 { 0xD0, LOG_FILE_VS_LOG(D0)"nvmelog_" "D0" ".bin", D0_log_size512, 0 },
3820 { 0xE6, LOG_FILE_VS_LOG(E6)"nvmelog_" "E6" ".bin", 0, 0 },
3821 { 0xE7, LOG_FILE_VS_LOG(E7)"nvmelog_" "E7" ".bin", 0, 0 }
3822 },
3823 aM51XXLogs[] = {
3824 /* this should be collected first for M51AX */
3825 { 0xFB, LOG_FILE_VS_LOG(FB)"nvmelog_" "FB" ".bin", 4096, 0 },
3826 { 0xD0, LOG_FILE_VS_LOG(D0)"nvmelog_" "D0" ".bin", 512, 0 },
3827 { 0x03, LOG_FILE_FW_SLOT"firmware_slot_info_log.bin", 512, 0},
3828 { 0xF7, LOG_FILE_VS_LOG(F7)"nvmelog_" "F7" ".bin", 4096, 512 * 1024 },
3829 { 0xF8, LOG_FILE_VS_LOG(F8)"nvmelog_" "F8" ".bin", 4096, 512 * 1024 },
3830 { 0xF9, LOG_FILE_VS_LOG(F9)"nvmelog_" "F9" ".bin", 4096, 200 * 1024 * 1024 },
3831 { 0xFC, LOG_FILE_VS_LOG(FC)"nvmelog_" "FC" ".bin", 4096, 200 * 1024 * 1024 },
3832 { 0xFD, LOG_FILE_VS_LOG(FD)"nvmelog_" "FD" ".bin", 4096, 80 * 1024 * 1024 }
3833 },
3834 aM51AXLogs[] = {
3835 { 0xCA, LOG_FILE_VS_LOG(CA)"nvmelog_" "CA" ".bin", 512, 0 },
3836 { 0xFA, LOG_FILE_VS_LOG(FA)"nvmelog_" "FA" ".bin", 4096, 15232 },
3837 { 0xF6, LOG_FILE_VS_LOG(F6)"nvmelog_" "F6" ".bin", 4096, 512 * 1024 },
3838 { 0xFE, LOG_FILE_VS_LOG(FE)"nvmelog_" "FE" ".bin", 4096, 512 * 1024 },
3839 { 0xFF, LOG_FILE_VS_LOG(FF)"nvmelog_" "FF" ".bin", 4096, 162 * 1024 },
3840 { 0x04, LOG_FILE_CHANGED_NS"changed_namespace_log.bin", 4096, 0 },
3841 { 0x05, LOG_FILE_CMD_EFFECTS"command_effects_log.bin", 4096, 0 },
3842 { 0x06, LOG_FILE_SELF_TEST"drive_self_test.bin", 4096, 0 }
3843 },
3844 aM51BXLogs[] = {
3845 { 0xFA, LOG_FILE_VS_LOG(FA)"nvmelog_" "FA" ".bin", 4096, 16376 },
3846 { 0xFE, LOG_FILE_VS_LOG(FE)"nvmelog_" "FE" ".bin", 4096, 256 * 1024 },
3847 { 0xFF, LOG_FILE_VS_LOG(FF)"nvmelog_" "FF" ".bin", 4096, 64 * 1024 },
3848 { 0xCA, LOG_FILE_VS_LOG(CA)"nvmelog_" "CA" ".bin", 512, 1024 }
3849 },
3850 aM51CXLogs[] = {
3851 { 0xE1, LOG_FILE_VS_LOG(E1)"nvmelog_" "E1" ".bin", 0, 0 },
3852 { 0xE2, LOG_FILE_VS_LOG(E2)"nvmelog_" "E2" ".bin", 0, 0 },
3853 { 0xE3, LOG_FILE_VS_LOG(E3)"nvmelog_" "E3" ".bin", 0, 0 },
3854 { 0xE4, LOG_FILE_VS_LOG(E4)"nvmelog_" "E4" ".bin", 0, 0 },
3855 { 0xE5, LOG_FILE_VS_LOG(E5)"nvmelog_" "E5" ".bin", 0, 0 },
3856 { 0xE8, LOG_FILE_VS_LOG(E8)"nvmelog_" "E8" ".bin", 0, 0 },
3857 { 0xE9, LOG_FILE_VS_LOG(E9)"nvmelog_" "E9" ".bin", 0, 0 },
3858 { 0xEA, LOG_FILE_VS_LOG(EA)"nvmelog_" "EA" ".bin", 0, 0 }
3859 };
3860
3861 enum eDriveModel eModel = UNKNOWN_MODEL;
3862
3863 const char *desc = "This retrieves the micron debug log package";
3864 const char *package = "Log output data file name (required)";
3865 const char *type = "telemetry log type - host or controller";
3866 const char *data_area = "telemetry log data area 1, 2, 3 or 4";
3867 unsigned char *dataBuffer = NULL((void*)0);
3868 int bSize = 0;
3869 int maxSize = 0;
3870 struct MICRON_WORKLOAD_LOG_HDR stWllHdr = { 0 };
3871
3872 struct config {
3873 char *type;
3874 char *package;
3875 int data_area;
3876 int log;
3877 };
3878
3879 struct config cfg = {
3880 .type = "",
3881 .package = "",
3882 .data_area = -1,
3883 .log = 0x07,
3884 };
3885
3886 NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"type", 't', "log type", CFG_STRING, &cfg.type, 1
, type, 0, }, {"package", 'p', "FILE", CFG_STRING, &cfg.package
, 1, package, 0, }, {"data_area", 'd', "NUM", CFG_POSITIVE, &
cfg.data_area, 1, data_area, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
3887 OPT_STRING("type", 't', "log type", &cfg.type, type),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"type", 't', "log type", CFG_STRING, &cfg.type, 1
, type, 0, }, {"package", 'p', "FILE", CFG_STRING, &cfg.package
, 1, package, 0, }, {"data_area", 'd', "NUM", CFG_POSITIVE, &
cfg.data_area, 1, data_area, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
3888 OPT_STRING("package", 'p', "FILE", &cfg.package, package),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"type", 't', "log type", CFG_STRING, &cfg.type, 1
, type, 0, }, {"package", 'p', "FILE", CFG_STRING, &cfg.package
, 1, package, 0, }, {"data_area", 'd', "NUM", CFG_POSITIVE, &
cfg.data_area, 1, data_area, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
3889 OPT_UINT("data_area", 'd', &cfg.data_area, data_area))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"type", 't', "log type", CFG_STRING, &cfg.type, 1
, type, 0, }, {"package", 'p', "FILE", CFG_STRING, &cfg.package
, 1, package, 0, }, {"data_area", 'd', "NUM", CFG_POSITIVE, &
cfg.data_area, 1, data_area, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
3890
3891 err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &eModel);
3892 if (err)
3893 return err;
3894
3895 err = -EINVAL22;
3896 /* if telemetry type is specified, check for data area */
3897 if (strlen(cfg.type)) {
3898 if (!strcmp(cfg.type, "controller")) {
3899 cfg.log = 0x08;
3900 } else if (strcmp(cfg.type, "host")) {
3901 nvme_show_error("telemetry type (host or controller) should be specified i.e. -t=host")nvme_show_message(1, "telemetry type (host or controller) should be specified i.e. -t=host"
)
;
3902 goto out;
3903 }
3904
3905 if (cfg.data_area <= 0 || cfg.data_area > 4) {
3906 nvme_show_error("data area must be selected using -d option ie --d=1,2,3,4")nvme_show_message(1, "data area must be selected using -d option ie --d=1,2,3,4"
)
;
3907 goto out;
3908 }
3909 telemetry_option = 1;
3910 } else if (cfg.data_area >= 0) {
3911 nvme_show_error(nvme_show_message(1, "data area option is valid only for telemetry option (i.e --type=host|controller)"
)
3912 "data area option is valid only for telemetry option (i.e --type=host|controller)")nvme_show_message(1, "data area option is valid only for telemetry option (i.e --type=host|controller)"
)
;
3913 goto out;
3914 }
3915
3916 if (!strlen(cfg.package)) {
3917 if (telemetry_option)
3918 nvme_show_error("Log data file must be specified. ie -p=logfile.bin")nvme_show_message(1, "Log data file must be specified. ie -p=logfile.bin"
)
;
3919 else
3920 nvme_show_error(nvme_show_message(1, "Log data file must be specified. ie -p=logfile.zip or -p=logfile.tgz|logfile.tar.gz"
)
3921 "Log data file must be specified. ie -p=logfile.zip or -p=logfile.tgz|logfile.tar.gz")nvme_show_message(1, "Log data file must be specified. ie -p=logfile.zip or -p=logfile.tgz|logfile.tar.gz"
)
;
3922 goto out;
3923 }
3924
3925 if (!is_safe_path(cfg.package)) {
3926 nvme_show_error(nvme_show_message(1, "Invalid package path: contains unsafe characters\n"
)
3927 "Invalid package path: contains unsafe characters\n")nvme_show_message(1, "Invalid package path: contains unsafe characters\n"
)
;
3928 goto out;
3929 }
3930
3931 /* pull log details based on the model name */
3932 if (eModel == UNKNOWN_MODEL) {
3933 nvme_show_error("Unsupported drive model for vs-internal-log collection")nvme_show_message(1, "Unsupported drive model for vs-internal-log collection"
)
;
3934 err = -ENOTSUP95;
3935 goto out;
3936 }
3937
3938 if (sscanf(libnvme_transport_handle_get_name(hdl), "nvme%d", &ctrlIdx) != 1)
3939 ctrlIdx = 0;
3940
3941 nvme_init_identify_ctrl(&cmd, &ctrl);
3942 err = libnvme_exec_admin_passthru(hdl, &cmd);
3943 if (err)
3944 goto out;
3945
3946 err = -EINVAL22;
3947 if (telemetry_option) {
3948 if ((ctrl.lpa & 0x8) != 0x8) {
3949 nvme_show_error("telemetry option is not supported for specified drive")nvme_show_message(1, "telemetry option is not supported for specified drive"
)
;
3950 goto out;
3951 }
3952 uint32_t logSize = 0; __u8 *buffer = NULL((void*)0);
3953
3954 err = micron_telemetry_log(hdl, cfg.log, &buffer, &logSize,
3955 cfg.data_area);
3956 if (!err && logSize > 0 && buffer) {
3957 snprintf(msg, sizeof(msg), "telemetry log: 0x%X", cfg.log);
3958 WriteData(buffer, logSize, NULL((void*)0), cfg.package, msg);
3959 libnvme_free(buffer);
3960 }
3961 goto out;
3962 }
3963
3964 printf("Preparing log package. This will take a few seconds...\n");
3965
3966 strncpy(safe_sn, ctrl.sn, sizeof(safe_sn) - 1);
3967 sanitize_serial(safe_sn, sizeof(safe_sn));
3968 err = SetupDebugDataDirectories(safe_sn, cfg.package,
3969 strMainDirName, sizeof(strMainDirName),
3970 strOSDirName, sizeof(strOSDirName),
3971 strCtrlDirName, sizeof(strCtrlDirName));
3972 if (err) {
3973 nvme_show_error("Failed to create debug data directories")nvme_show_message(1, "Failed to create debug data directories"
)
;
3974 goto out;
3975 }
3976
3977 /*
3978 * Set up the cmd status CSV before any collection so each helper can
3979 * append its own row.
3980 */
3981 SetupCmdStatusLog(strCtrlDirName, safe_sn);
3982
3983 GetLogPullMetadata(strOSDirName, &ctrl, plugin->version);
3984 GetTimestampInfo(strOSDirName);
3985 GetCtrlIDDInfo(strCtrlDirName, &ctrl);
3986 GetOSConfig(strOSDirName);
3987 GetDriveInfo(strOSDirName, ctrlIdx, &ctrl);
3988
3989 /*
3990 * All namespaces share a single command info entry.
3991 * Report success if any namespace was collected.
3992 */
3993 ns_err = -1;
3994 for (int i = 1; i <= ctrl.nn; i++) {
3995 if (!GetNSIDDInfo(hdl, strCtrlDirName, i))
3996 ns_err = 0;
3997 }
3998 LogCmdStatus(LOG_FILE_ID_NS"identify_namespace_%d_data.bin", ns_err);
3999
4000 GetSmartlogData(hdl, strCtrlDirName);
4001 GetErrorlogData(hdl, ctrl.elpe, strCtrlDirName);
4002 GetGenericLogs(hdl, strCtrlDirName);
4003 /* pull if telemetry log data is supported */
4004 if ((ctrl.lpa & 0x8) == 0x8) {
4005 if (eModel == M51BY)
4006 GetOcpEnhancedTelemetryLogs(hdl, strCtrlDirName);
4007 else
4008 GetTelemetryData(hdl, strCtrlDirName, ctrl.lpa & 0x40);
4009 }
4010 GetFeatureSettings(hdl, strCtrlDirName);
4011
4012 if (eModel != M5410 && eModel != M5407) {
4013 memcpy(&aVendorLogs[c_logs_index], aM51XXLogs, sizeof(aM51XXLogs));
4014 c_logs_index += ARRAY_SIZE(aM51XXLogs)(sizeof(aM51XXLogs) / sizeof((aM51XXLogs)[0]) + 0);
4015 if (eModel == M51AX)
4016 memcpy((char *)&aVendorLogs[c_logs_index], aM51AXLogs, sizeof(aM51AXLogs));
4017 else if (eModel == M51BX)
4018 memcpy((char *)&aVendorLogs[c_logs_index], aM51BXLogs, sizeof(aM51BXLogs));
4019 else if (eModel == M51CX || eModel == M51BY || eModel == M51CY)
4020 memcpy((char *)&aVendorLogs[c_logs_index], aM51CXLogs, sizeof(aM51CXLogs));
4021 }
4022
4023 for (int i = 0; i < (int)(ARRAY_SIZE(aVendorLogs)(sizeof(aVendorLogs) / sizeof((aVendorLogs)[0]) + 0)) && aVendorLogs[i].ucLogPage; i++) {
4024 bool_Bool wrote = false0;
4025
4026 err = -1;
4027 switch (aVendorLogs[i].ucLogPage) {
4028 case 0xE1:
4029 case 0xE5:
4030 continue;
4031 case 0xE9:
4032 if (eModel != M51CX && eModel != M51BY)
4033 continue;
4034
4035 err = NVMEGetLogPage(hdl, aVendorLogs[i].ucLogPage,
4036 (unsigned char *)&stWllHdr,
4037 sizeof(struct MICRON_WORKLOAD_LOG_HDR), 0);
4038 if (err == 0) {
4039 bSize = stWllHdr.uiLength;
4040 if (bSize < (int)sizeof(struct MICRON_WORKLOAD_LOG_HDR)) {
4041 nvme_show_error("Invalid log size for log id : 0x%02X",nvme_show_message(1, "Invalid log size for log id : 0x%02X", aVendorLogs
[i].ucLogPage)
4042 aVendorLogs[i].ucLogPage)nvme_show_message(1, "Invalid log size for log id : 0x%02X", aVendorLogs
[i].ucLogPage)
;
4043 err = -1;
4044 break;
4045 }
4046 dataBuffer = (unsigned char *)libnvme_alloc(bSize);
4047 if (!dataBuffer) {
4048 nvme_show_error("Memory allocation failed for log id : 0x%02X",nvme_show_message(1, "Memory allocation failed for log id : 0x%02X"
, aVendorLogs[i].ucLogPage)
4049 aVendorLogs[i].ucLogPage)nvme_show_message(1, "Memory allocation failed for log id : 0x%02X"
, aVendorLogs[i].ucLogPage)
;
4050 continue;
4051 }
4052 memcpy(dataBuffer, &stWllHdr,
4053 sizeof(struct MICRON_WORKLOAD_LOG_HDR));
4054 err = NVMEGetLogPage(hdl,
4055 aVendorLogs[i].ucLogPage,
4056 (dataBuffer +
4057 sizeof(struct MICRON_WORKLOAD_LOG_HDR)),
4058 (bSize -
4059 sizeof(struct MICRON_WORKLOAD_LOG_HDR)),
4060 sizeof(struct MICRON_WORKLOAD_LOG_HDR));
4061 if (err != 0)
4062 nvme_show_error("Failed to fetch the E9 logs")nvme_show_message(1, "Failed to fetch the E9 logs");
4063
4064 }
4065 break;
4066 case 0xE2:
4067 if (eModel == M51CX || eModel == M51BY || eModel == M51CY)
4068 continue;
4069
4070 err = get_common_log(hdl, aVendorLogs[i].ucLogPage,
4071 &dataBuffer, &bSize);
4072 break;
4073 case 0xE3:
4074 case 0xE4:
4075 case 0xE8:
4076 case 0xEA:
4077 err = get_common_log(hdl, aVendorLogs[i].ucLogPage,
4078 &dataBuffer, &bSize);
4079 break;
4080 case 0xC1:
4081 case 0xC2:
4082 if (eModel == M51CX || eModel == M51BY || eModel == M51CY)
4083 continue;
4084
4085 err = GetLogPageSize(hdl, aVendorLogs[i].ucLogPage, &bSize);
4086 if (err == 0 && bSize > 0)
4087 err = GetCommonLogPage(hdl,
4088 aVendorLogs[i].ucLogPage,
4089 &dataBuffer, bSize);
4090 break;
4091 case 0xC4:
4092 if (eModel == M51BY || eModel == M51CY)
4093 continue;
4094
4095 err = GetLogPageSize(hdl, aVendorLogs[i].ucLogPage,
4096 &bSize);
4097 if (!err && bSize > 0)
4098 err = GetCommonLogPage(hdl, aVendorLogs[i].ucLogPage,
4099 &dataBuffer, bSize);
4100 break;
4101 case 0xE6:
4102 case 0xE7:
4103 puiIDDBuf = (unsigned int *)&ctrl;
4104 uiMask = puiIDDBuf[1015];
4105 if (!uiMask || (aVendorLogs[i].ucLogPage == 0xE6 && uiMask == 2) ||
4106 (aVendorLogs[i].ucLogPage == 0xE7 && uiMask == 1))
4107 continue;
4108
4109 bSize = (int)puiIDDBuf[1023];
4110 if (bSize % (16 * 1024))
4111 bSize += (16 * 1024) - (bSize % (16 * 1024));
4112 dataBuffer = (unsigned char *)libnvme_alloc(bSize);
4113 if (bSize && dataBuffer) {
4114 memset(dataBuffer, 0, bSize);
4115 if (eModel == M5410 || eModel == M5407)
4116 err = NVMEGetLogPage(hdl,
4117 aVendorLogs[i].ucLogPage,
4118 dataBuffer, bSize, 0);
4119 else
4120 err = nvme_get_log_simple(hdl,
4121 aVendorLogs[i].ucLogPage,
4122 dataBuffer, bSize);
4123 }
4124 break;
4125 case 0xF7:
4126 case 0xF9:
4127 case 0xFC:
4128 case 0xFD:
4129 if (eModel == M51BX)
4130 (void)NVMEResetLog(hdl, aVendorLogs[i].ucLogPage,
4131 aVendorLogs[i].nLogSize, aVendorLogs[i].nMaxSize);
4132
4133 continue;
4134 default:
4135 bSize = aVendorLogs[i].nLogSize;
4136 dataBuffer = (unsigned char *)libnvme_alloc(bSize);
4137 if (!dataBuffer)
4138 break;
4139 memset(dataBuffer, 0, bSize);
4140 err = nvme_get_log_simple(hdl, aVendorLogs[i].ucLogPage,
4141 dataBuffer, bSize);
4142 maxSize = aVendorLogs[i].nMaxSize - bSize;
4143 while (!err && maxSize > 0 && ((unsigned int *)dataBuffer)[0] != 0xdeadbeef) {
4144 snprintf(msg, sizeof(msg), "log 0x%x", aVendorLogs[i].ucLogPage);
4145 WriteData(dataBuffer, bSize, strCtrlDirName, aVendorLogs[i].strFileName, msg);
4146 wrote = true1;
4147 err = nvme_get_log_simple(hdl,
4148 aVendorLogs[i].ucLogPage,
4149 dataBuffer, bSize);
4150 if (err || (((unsigned int *)dataBuffer)[0] == 0xdeadbeef))
4151 break;
4152 maxSize -= bSize;
4153 }
4154 break;
4155 }
4156
4157 if (!err && dataBuffer && ((unsigned int *)dataBuffer)[0] != 0xdeadbeef) {
4158 snprintf(msg, sizeof(msg), "log 0x%x", aVendorLogs[i].ucLogPage);
4159 WriteData(dataBuffer, bSize, strCtrlDirName, aVendorLogs[i].strFileName, msg);
4160 wrote = true1;
4161 }
4162
4163 /*
4164 * Only logs with data on disk are marked available to decode.
4165 * A log that is empty or intentionally skipped gets no row.
4166 */
4167 if (wrote)
4168 LogCmdStatus(aVendorLogs[i].strFileName, 0);
4169 else if (err)
4170 LogCmdStatus(aVendorLogs[i].strFileName, err);
4171
4172 libnvme_free(dataBuffer);
4173 dataBuffer = NULL((void*)0);
4174 }
4175
4176 err = ZipAndRemoveDir(strMainDirName, cfg.package);
4177out:
4178 return err;
4179}
4180
4181#define MIN_LOG_SIZE512 512
4182static int micron_logpage_dir(int argc, char **argv, struct command *acmd,
4183 struct plugin *plugin)
4184{
4185 int err = -1;
4186 const char *desc = "List the supported log pages";
4187 enum eDriveModel model = UNKNOWN_MODEL;
4188 char logbuf[MIN_LOG_SIZE512];
4189 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
4190 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
4191 int i;
4192
4193 NVME_ARGS(opts)nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0
, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT
, &nvme_args.verbose, 0, "Increase output verbosity", 0, }
, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0,
"suppress informational output", 0, }, {"output-format", 'o'
, "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
4194
4195 err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &model);
4196 if (err)
4197 return err;
4198
4199 struct nvme_supported_logs {
4200 uint8_t log_id;
4201 uint8_t supported;
4202 char *desc;
4203 } log_list[] = {
4204 {0x00, 0, "Support Log Pages"},
4205 {0x01, 0, "Error Information"},
4206 {0x02, 0, "SMART / Health Information"},
4207 {0x03, 0, "Firmware Slot Information"},
4208 {0x04, 0, "Changed Namespace List"},
4209 {0x05, 0, "Commands Supported and Effects"},
4210 {0x06, 0, "Device Self Test"},
4211 {0x07, 0, "Telemetry Host-Initiated"},
4212 {0x08, 0, "Telemetry Controller-Initiated"},
4213 {0x09, 0, "Endurance Group Information"},
4214 {0x0A, 0, "Predictable Latency Per NVM Set"},
4215 {0x0B, 0, "Predictable Latency Event Aggregate"},
4216 {0x0C, 0, "Asymmetric Namespace Access"},
4217 {0x0D, 0, "Persistent Event Log"},
4218 {0x0E, 0, "Predictable Latency Event Aggregate"},
4219 {0x0F, 0, "Endurance Group Event Aggregate"},
4220 {0x10, 0, "Media Unit Status"},
4221 {0x11, 0, "Supported Capacity Configuration List"},
4222 {0x12, 0, "Feature Identifiers Supported and Effects"},
4223 {0x13, 0, "NVMe-MI Commands Supported and Effects"},
4224 {0x14, 0, "Command and Feature lockdown"},
4225 {0x15, 0, "Boot Partition"},
4226 {0x16, 0, "Rotational Media Information"},
4227 {0x70, 0, "Discovery"},
4228 {0x80, 0, "Reservation Notification"},
4229 {0x81, 0, "Sanitize Status"},
4230 {0xC0, 0, "SMART Cloud Health Log"},
4231 {0xC2, 0, "Firmware Activation History"},
4232 {0xC3, 0, "Latency Monitor Log"},
4233 };
4234
4235 printf("Supported log page list\nLog ID : Description\n");
4236 for (i = 0; i < ARRAY_SIZE(log_list)(sizeof(log_list) / sizeof((log_list)[0]) + 0); i++) {
4237 err = nvme_get_log_simple(hdl, log_list[i].log_id,
4238 &logbuf[0], MIN_LOG_SIZE512);
4239 if (err)
4240 continue;
4241 printf("%02Xh : %s\n", log_list[i].log_id, log_list[i].desc);
4242 }
4243
4244 return err;
4245}
4246
4247static int micron_cloud_boot_SSD_version(int argc, char **argv,
4248 struct command *command, struct plugin *plugin)
4249{
4250 const char *desc = "Prints HyperScale Boot Version";
4251 unsigned char logC0[C0_log_size512] = { 0 };
4252 struct nvme_id_ctrl ctrl;
4253 struct libnvme_passthru_cmd cmd;
4254 enum eDriveModel eModel = UNKNOWN_MODEL;
4255 int err = 0;
4256 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
4257 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
4258
4259 NVME_ARGS(opts)nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0
, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT
, &nvme_args.verbose, 0, "Increase output verbosity", 0, }
, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0,
"suppress informational output", 0, }, {"output-format", 'o'
, "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
4260
4261 err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &eModel);
4262 if (err)
4263 return err;
4264
4265 nvme_init_identify_ctrl(&cmd, &ctrl);
4266 err = libnvme_exec_admin_passthru(hdl, &cmd);
4267 if (err == 0) {
4268 if (ctrl.vs[536] != MICRON_CUST_ID_GG0x16) {
4269 nvme_show_error("cloud-boot-SSD-version option is not supported for specified drive")nvme_show_message(1, "cloud-boot-SSD-version option is not supported for specified drive"
)
;
4270 goto out;
4271 }
4272 } else {
4273 nvme_show_error("Error %d retrieving controller identification data", err)nvme_show_message(1, "Error %d retrieving controller identification data"
, err)
;
4274 goto out;
4275 }
4276
4277 err = nvme_get_log_simple(hdl, 0xC0, logC0, C0_log_size512);
4278 if (err == 0) {
4279 __u16 major, minor;
4280
4281 major = *((__u16 *)(logC0+300));
4282 minor = *((__u16 *)(logC0+302));
4283
4284 printf("HyperScale Boot Version Spec.%x.%x\n", le16_to_cpu(major)
4285 , le16_to_cpu(minor));
4286 } else {
4287 nvme_show_err(err, "Error retrieving extended smart log 0xC0 for the drive");
4288 goto out;
4289 }
4290out:
4291 return err;
4292}
4293
4294static int micron_device_waf(int argc, char **argv, struct command *acmd,
4295 struct plugin *plugin)
4296{
4297 const char *desc = "Prints device Write Amplification Factor(WAF)";
4298 unsigned char logC0[C0_log_size512] = { 0 };
4299 struct nvme_id_ctrl ctrl;
4300 struct libnvme_passthru_cmd cmd;
4301 struct nvme_smart_log smart_log;
4302 enum eDriveModel eModel = UNKNOWN_MODEL;
4303 int err = 0;
4304 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
4305 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
4306
4307 long double tlc_units_written, slc_units_written;
4308 long double data_units_written, write_amplification_factor;
4309
4310 NVME_ARGS(opts)nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0
, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT
, &nvme_args.verbose, 0, "Increase output verbosity", 0, }
, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0,
"suppress informational output", 0, }, {"output-format", 'o'
, "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
4311
4312 err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &eModel);
4313 if (err)
4314 return err;
4315
4316 nvme_init_identify_ctrl(&cmd, &ctrl);
4317 err = libnvme_exec_admin_passthru(hdl, &cmd);
4318 if (err == 0) {
4319 if (ctrl.vs[536] != MICRON_CUST_ID_GG0x16) {
4320 nvme_show_error("vs-device-waf option is not supported for specified drive")nvme_show_message(1, "vs-device-waf option is not supported for specified drive"
)
;
4321 goto out;
4322 }
4323 } else {
4324 nvme_show_error("Error %d retrieving controller identification data", err)nvme_show_message(1, "Error %d retrieving controller identification data"
, err)
;
4325 goto out;
4326 }
4327
4328 err = nvme_get_log_smart(hdl, NVME_NSID_ALL, &smart_log);
4329 if (err != 0) {
4330 nvme_show_error("nvme_smart_log() failed, err = %d", err)nvme_show_message(1, "nvme_smart_log() failed, err = %d", err
)
;
4331 goto out;
4332 }
4333
4334 err = nvme_get_log_simple(hdl, 0xC0, logC0, C0_log_size512);
4335 if (err != 0) {
4336 nvme_show_error("Failed to get extended smart log, err = %d", err)nvme_show_message(1, "Failed to get extended smart log, err = %d"
, err)
;
4337 goto out;
4338 }
4339
4340 data_units_written = int128_to_double(smart_log.data_units_written);
4341 tlc_units_written = int128_to_double((__u8 *)logC0);
4342 slc_units_written = int128_to_double((__u8 *)(logC0+16));
4343 write_amplification_factor = (data_units_written/(tlc_units_written + slc_units_written));
4344 printf("Write Amplification Factor %.0Lf\n", write_amplification_factor);
4345
4346out:
4347 return err;
4348}
4349
4350static int micron_cloud_log(int argc, char **argv, struct command *acmd,
4351 struct plugin *plugin)
4352{
4353 const char *desc = "Retrieve Smart or Extended Smart Health log for the given device ";
4354 unsigned int logC0[C0_log_size512/sizeof(int)] = { 0 };
4355 struct nvme_id_ctrl ctrl;
4356 struct libnvme_passthru_cmd cmd;
4357 enum eDriveModel eModel = UNKNOWN_MODEL;
4358 int err = 0;
4359 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
4360 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
4361 bool_Bool is_json = false0;
4362 const char *fmt = "Output format: normal|json";
4363 nvme_print_flags_t format;
4364
4365 NVME_ARGS_OUTPUT_FORMATS(opts, (JSON | NORMAL), fmt)nvme_args.supported_output_formats = (JSON | NORMAL); struct argconfig_commandline_options
opts[] = { {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)
0), 0, "Options", 0, ((void*)0)}, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, fmt
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
4366
4367 err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &eModel);
4368 if (err)
4369 return err;
4370
4371 err = validate_output_format(nvme_args.output_format, &format);
4372 if (err) {
4373 nvme_show_error("Invalid output format")nvme_show_message(1, "Invalid output format");
4374 return err;
4375 }
4376 is_json = format == JSON;
4377
4378 /* check for models that support 0xC0 log */
4379 if (eModel != M51CX) {
4380 nvme_show_error("Unsupported drive model for vs-cloud-log commmand")nvme_show_message(1, "Unsupported drive model for vs-cloud-log commmand"
)
;
4381 err = -1;
4382 goto out;
4383 }
4384
4385 nvme_init_identify_ctrl(&cmd, &ctrl);
4386 err = libnvme_exec_admin_passthru(hdl, &cmd);
4387 if (err == 0) {
4388 if (ctrl.vs[536] != MICRON_CUST_ID_GG0x16) {
4389 nvme_show_error("vs-cloud-log option is not supported for specified drive")nvme_show_message(1, "vs-cloud-log option is not supported for specified drive"
)
;
4390 goto out;
4391 }
4392 } else {
4393 nvme_show_error("Error %d retrieving controller identification data", err)nvme_show_message(1, "Error %d retrieving controller identification data"
, err)
;
4394 goto out;
4395 }
4396
4397 err = nvme_get_log_simple(hdl, 0xC0, logC0, C0_log_size512);
4398 if (err == 0)
4399 print_hyperscale_cloud_health_log((__u8 *)logC0, is_json);
4400 else
4401 nvme_show_error("Unable to retrieve extended smart log 0xC0 for the drive")nvme_show_message(1, "Unable to retrieve extended smart log 0xC0 for the drive"
)
;
4402
4403out:
4404 if (err > 0)
4405 nvme_show_status(err);
4406 return err;
4407}
4408
4409/* Extended SMART log structure with Micron-specific fields in reserved area */
4410struct micron_smart_log_ext {
4411 struct nvme_smart_log base;
4412 /* Access vendor-specific fields via rsvd232 overlay */
4413};
4414
4415static inline __u64 get_smart_olec(struct nvme_smart_log *smart)
4416{
4417 return le64_to_cpu(smart->op_lifetime_energy_consumed);
4418}
4419
4420static inline __u32 get_smart_ipm(struct nvme_smart_log *smart)
4421{
4422 return le32_to_cpu(smart->interval_power_measurement);
4423}
4424
4425static void print_micron_health_log_normal(struct nvme_smart_log *smart,
4426 const char *devname)
4427{
4428 __u16 temp = smart->temperature[1] << 8 | smart->temperature[0];
4429 __u64 olec = get_smart_olec(smart);
4430 __u32 ipm = get_smart_ipm(smart);
4431 int i;
4432
4433 printf("SMART/Health Information Log for %s\n", devname);
4434 printf("========================================\n");
4435
4436 printf("Critical Warning : 0x%02x\n",
4437 smart->critical_warning);
4438 if (smart->critical_warning) {
4439 if (smart->critical_warning & 0x01)
4440 printf(" - Available spare below threshold\n");
4441 if (smart->critical_warning & 0x02)
4442 printf(" - Temperature threshold exceeded\n");
4443 if (smart->critical_warning & 0x04)
4444 printf(" - NVM subsystem reliability degraded\n");
4445 if (smart->critical_warning & 0x08)
4446 printf(" - Media placed in read-only mode\n");
4447 if (smart->critical_warning & 0x10)
4448 printf(" - Volatile memory backup failed\n");
4449 if (smart->critical_warning & 0x20)
4450 printf(" - PMR read-only or unreliable\n");
4451 }
4452
4453 printf("Composite Temperature : %u K (%d C)\n",
4454 temp, temp ? temp - 273 : 0);
4455 printf("Available Spare : %u%%\n", smart->avail_spare);
4456 printf("Available Spare Threshold : %u%%\n", smart->spare_thresh);
4457 printf("Percentage Used : %u%%\n", smart->percent_used);
4458 printf("Endurance Grp Critical Warn : 0x%02x\n",
4459 smart->endu_grp_crit_warn_sumry);
4460
4461 printf("Data Units Read : %s\n",
4462 uint128_t_to_string(le128_to_cpu(smart->data_units_read)));
4463 printf("Data Units Written : %s\n",
4464 uint128_t_to_string(le128_to_cpu(smart->data_units_written)));
4465 printf("Host Read Commands : %s\n",
4466 uint128_t_to_string(le128_to_cpu(smart->host_reads)));
4467 printf("Host Write Commands : %s\n",
4468 uint128_t_to_string(le128_to_cpu(smart->host_writes)));
4469 printf("Controller Busy Time : %s min\n",
4470 uint128_t_to_string(le128_to_cpu(smart->ctrl_busy_time)));
4471 printf("Power Cycles : %s\n",
4472 uint128_t_to_string(le128_to_cpu(smart->power_cycles)));
4473 printf("Power On Hours : %s\n",
4474 uint128_t_to_string(le128_to_cpu(smart->power_on_hours)));
4475 printf("Unsafe Shutdowns : %s\n",
4476 uint128_t_to_string(le128_to_cpu(smart->unsafe_shutdowns)));
4477 printf("Media Errors : %s\n",
4478 uint128_t_to_string(le128_to_cpu(smart->media_errors)));
4479 printf("Num Error Log Entries : %s\n",
4480 uint128_t_to_string(le128_to_cpu(smart->num_err_log_entries)));
4481
4482 printf("Warning Comp Temp Time : %u min\n",
4483 le32_to_cpu(smart->warning_temp_time));
4484 printf("Critical Comp Temp Time : %u min\n",
4485 le32_to_cpu(smart->critical_comp_time));
4486
4487 for (i = 0; i < 8; i++) {
4488 __u16 ts = le16_to_cpu(smart->temp_sensor[i]);
4489
4490 if (ts)
4491 printf("Temperature Sensor %d : %u K (%d C)\n",
4492 i + 1, ts, ts - 273);
4493 }
4494
4495 printf("Thm Temp 1 Trans Count : %u\n",
4496 le32_to_cpu(smart->thm_temp1_trans_count));
4497 printf("Thm Temp 2 Trans Count : %u\n",
4498 le32_to_cpu(smart->thm_temp2_trans_count));
4499 printf("Thm Temp 1 Total Time : %u sec\n",
4500 le32_to_cpu(smart->thm_temp1_total_time));
4501 printf("Thm Temp 2 Total Time : %u sec\n",
4502 le32_to_cpu(smart->thm_temp2_total_time));
4503
4504 /* Micron-specific extended fields */
4505 printf("OLEC (Energy) : %llu\n",
4506 (unsigned long long)olec);
4507 printf("Interval Power Measurement : %u\n", ipm);
4508}
4509
4510static void print_micron_health_log_json(struct nvme_smart_log *smart,
4511 const char *devname)
4512{
4513 __u16 temp = smart->temperature[1] << 8 | smart->temperature[0];
4514 __u64 olec = get_smart_olec(smart);
4515 __u32 ipm = get_smart_ipm(smart);
4516 struct json_object *root;
4517 int i;
4518
4519 root = json_create_object()json_object_new_object();
4520
4521 json_object_add_value_string(root, "device", devname);
4522 json_object_add_value_int(root, "critical_warning",json_object_object_add(root, "critical_warning", json_object_new_int
(smart->critical_warning))
4523 smart->critical_warning)json_object_object_add(root, "critical_warning", json_object_new_int
(smart->critical_warning))
;
4524 json_object_add_value_int(root, "temperature_kelvin", temp)json_object_object_add(root, "temperature_kelvin", json_object_new_int
(temp))
;
4525 json_object_add_value_int(root, "temperature_celsius",json_object_object_add(root, "temperature_celsius", json_object_new_int
(temp ? temp - 273 : 0))
4526 temp ? temp - 273 : 0)json_object_object_add(root, "temperature_celsius", json_object_new_int
(temp ? temp - 273 : 0))
;
4527 json_object_add_value_int(root, "avail_spare", smart->avail_spare)json_object_object_add(root, "avail_spare", json_object_new_int
(smart->avail_spare))
;
4528 json_object_add_value_int(root, "spare_thresh", smart->spare_thresh)json_object_object_add(root, "spare_thresh", json_object_new_int
(smart->spare_thresh))
;
4529 json_object_add_value_int(root, "percent_used", smart->percent_used)json_object_object_add(root, "percent_used", json_object_new_int
(smart->percent_used))
;
4530 json_object_add_value_int(root, "endurance_grp_crit_warn",json_object_object_add(root, "endurance_grp_crit_warn", json_object_new_int
(smart->endu_grp_crit_warn_sumry))
4531 smart->endu_grp_crit_warn_sumry)json_object_object_add(root, "endurance_grp_crit_warn", json_object_new_int
(smart->endu_grp_crit_warn_sumry))
;
4532
4533 json_object_add_value_string(root, "data_units_read",
4534 uint128_t_to_string(le128_to_cpu(smart->data_units_read)));
4535 json_object_add_value_string(root, "data_units_written",
4536 uint128_t_to_string(le128_to_cpu(smart->data_units_written)));
4537 json_object_add_value_string(root, "host_reads",
4538 uint128_t_to_string(le128_to_cpu(smart->host_reads)));
4539 json_object_add_value_string(root, "host_writes",
4540 uint128_t_to_string(le128_to_cpu(smart->host_writes)));
4541 json_object_add_value_string(root, "ctrl_busy_time",
4542 uint128_t_to_string(le128_to_cpu(smart->ctrl_busy_time)));
4543 json_object_add_value_string(root, "power_cycles",
4544 uint128_t_to_string(le128_to_cpu(smart->power_cycles)));
4545 json_object_add_value_string(root, "power_on_hours",
4546 uint128_t_to_string(le128_to_cpu(smart->power_on_hours)));
4547 json_object_add_value_string(root, "unsafe_shutdowns",
4548 uint128_t_to_string(le128_to_cpu(smart->unsafe_shutdowns)));
4549 json_object_add_value_string(root, "media_errors",
4550 uint128_t_to_string(le128_to_cpu(smart->media_errors)));
4551 json_object_add_value_string(root, "num_err_log_entries",
4552 uint128_t_to_string(le128_to_cpu(smart->num_err_log_entries)));
4553
4554 json_object_add_value_uint(root, "warning_temp_time",json_object_object_add(root, "warning_temp_time", json_object_new_uint64
(le32_to_cpu(smart->warning_temp_time)))
4555 le32_to_cpu(smart->warning_temp_time))json_object_object_add(root, "warning_temp_time", json_object_new_uint64
(le32_to_cpu(smart->warning_temp_time)))
;
4556 json_object_add_value_uint(root, "critical_comp_time",json_object_object_add(root, "critical_comp_time", json_object_new_uint64
(le32_to_cpu(smart->critical_comp_time)))
4557 le32_to_cpu(smart->critical_comp_time))json_object_object_add(root, "critical_comp_time", json_object_new_uint64
(le32_to_cpu(smart->critical_comp_time)))
;
4558
4559 for (i = 0; i < 8; i++) {
4560 __u16 ts = le16_to_cpu(smart->temp_sensor[i]);
4561 char key[32];
4562
4563 if (ts) {
4564 sprintf(key, "temp_sensor_%d", i + 1);
4565 json_object_add_value_int(root, key, ts - 273)json_object_object_add(root, key, json_object_new_int(ts - 273
))
;
4566 }
4567 }
4568
4569 json_object_add_value_uint(root, "thm_temp1_trans_count",json_object_object_add(root, "thm_temp1_trans_count", json_object_new_uint64
(le32_to_cpu(smart->thm_temp1_trans_count)))
4570 le32_to_cpu(smart->thm_temp1_trans_count))json_object_object_add(root, "thm_temp1_trans_count", json_object_new_uint64
(le32_to_cpu(smart->thm_temp1_trans_count)))
;
4571 json_object_add_value_uint(root, "thm_temp2_trans_count",json_object_object_add(root, "thm_temp2_trans_count", json_object_new_uint64
(le32_to_cpu(smart->thm_temp2_trans_count)))
4572 le32_to_cpu(smart->thm_temp2_trans_count))json_object_object_add(root, "thm_temp2_trans_count", json_object_new_uint64
(le32_to_cpu(smart->thm_temp2_trans_count)))
;
4573 json_object_add_value_uint(root, "thm_temp1_total_time",json_object_object_add(root, "thm_temp1_total_time", json_object_new_uint64
(le32_to_cpu(smart->thm_temp1_total_time)))
4574 le32_to_cpu(smart->thm_temp1_total_time))json_object_object_add(root, "thm_temp1_total_time", json_object_new_uint64
(le32_to_cpu(smart->thm_temp1_total_time)))
;
4575 json_object_add_value_uint(root, "thm_temp2_total_time",json_object_object_add(root, "thm_temp2_total_time", json_object_new_uint64
(le32_to_cpu(smart->thm_temp2_total_time)))
4576 le32_to_cpu(smart->thm_temp2_total_time))json_object_object_add(root, "thm_temp2_total_time", json_object_new_uint64
(le32_to_cpu(smart->thm_temp2_total_time)))
;
4577
4578 /* Micron-specific extended fields */
4579 json_object_add_value_uint64(root, "olec", olec)json_object_object_add(root, "olec", json_object_new_uint64(olec
))
;
4580 json_object_add_value_uint(root, "ipm", ipm)json_object_object_add(root, "ipm", json_object_new_uint64(ipm
))
;
4581
4582 json_print_object(root, NULL)printf("%s", json_object_to_json_string_ext(root, (1 <<
1) | (1 << 4)))
;
4583 printf("\n");
4584 json_free_object(root)json_object_put(root);
4585}
4586
4587static int micron_health_info(int argc, char **argv, struct command *acmd,
4588 struct plugin *plugin)
4589{
4590 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
4591 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
4592 const char *desc = "Retrieve SMART/Health log for Micron drives";
4593 const char *fmt = "Output format: normal|json";
4594 enum eDriveModel eModel = UNKNOWN_MODEL;
4595 struct nvme_smart_log smart_log = { 0 };
4596 bool_Bool is_json = false0;
4597 nvme_print_flags_t format;
4598 int err = 0;
4599
4600 NVME_ARGS_OUTPUT_FORMATS(opts, (JSON | NORMAL), fmt)nvme_args.supported_output_formats = (JSON | NORMAL); struct argconfig_commandline_options
opts[] = { {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)
0), 0, "Options", 0, ((void*)0)}, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, fmt
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
4601
4602 err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &eModel);
4603 if (err)
4604 return err;
4605
4606 if (eModel == UNKNOWN_MODEL)
4607 nvme_show_error("WARNING: Unknown drive model")nvme_show_message(1, "WARNING: Unknown drive model");
4608
4609 err = validate_output_format(nvme_args.output_format, &format);
4610 if (err) {
4611 nvme_show_error("Invalid output format")nvme_show_message(1, "Invalid output format");
4612 return err;
4613 }
4614 is_json = format == JSON;
4615
4616 err = nvme_get_log_smart(hdl, NVME_NSID_ALL, &smart_log);
4617 if (err) {
4618 nvme_show_error("Failed to get SMART log: %s",nvme_show_message(1, "Failed to get SMART log: %s", libnvme_strerror
(err))
4619 libnvme_strerror(err))nvme_show_message(1, "Failed to get SMART log: %s", libnvme_strerror
(err))
;
4620 return err;
4621 }
4622
4623 if (is_json)
4624 print_micron_health_log_json(&smart_log, argv[optind]);
4625 else
4626 print_micron_health_log_normal(&smart_log, argv[optind]);
4627
4628 return 0;
4629}
4630
4631/*
4632 * Identify Controller field offsets for Micron-specific fields
4633 * PMS: Power Measurement Support - bit 21 of CTRATT
4634 */
4635#define CTRATT_PMS_BIT21 21
4636
4637static inline __u16 get_id_ctrl_ipmsr(struct nvme_id_ctrl *ctrl)
4638{
4639 __le16 *p = (__le16 *)&ctrl->ipmsr;
4640
4641 return le16_to_cpu(*p);
4642}
4643
4644static inline __u16 get_id_ctrl_msmt(struct nvme_id_ctrl *ctrl)
4645{
4646 __le16 *p = (__le16 *)&ctrl->msmt;
4647
4648 return le16_to_cpu(*p);
4649}
4650
4651static inline bool_Bool get_id_ctrl_pms(struct nvme_id_ctrl *ctrl)
4652{
4653 return (le32_to_cpu(ctrl->ctratt) >> CTRATT_PMS_BIT21) & 0x1;
4654}
4655
4656/* Micron vendor-specific id-ctrl fields display */
4657static void micron_id_ctrl_vs(__u8 *vs, struct json_object *root)
4658{
4659 /* Cast back to get full ctrl structure for our extended fields */
4660 struct nvme_id_ctrl *ctrl =
4661 (struct nvme_id_ctrl *)(vs - offsetof(struct nvme_id_ctrl, vs)__builtin_offsetof(struct nvme_id_ctrl, vs));
4662 __u16 ipmsr = get_id_ctrl_ipmsr(ctrl);
4663 __u16 msmt = get_id_ctrl_msmt(ctrl);
4664 bool_Bool pms = get_id_ctrl_pms(ctrl);
4665
4666 if (root) {
4667 /* JSON output */
4668 json_object_add_value_int(root, "pms", pms ? 1 : 0)json_object_object_add(root, "pms", json_object_new_int(pms ?
1 : 0))
;
4669 json_object_add_value_uint(root, "ipmsr", ipmsr)json_object_object_add(root, "ipmsr", json_object_new_uint64(
ipmsr))
;
4670 json_object_add_value_uint(root, "msmt", msmt)json_object_object_add(root, "msmt", json_object_new_uint64(msmt
))
;
4671 } else {
4672 /* Normal output */
4673 printf("pms : %u\n", pms ? 1 : 0);
4674 printf("ipmsr : %u\n", ipmsr);
4675 printf("msmt : %u\n", msmt);
4676 }
4677}
4678
4679static int micron_id_ctrl(int argc, char **argv, struct command *acmd,
4680 struct plugin *plugin)
4681{
4682 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
4683 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
4684 const char *desc = "Identify Controller with Micron vendor fields";
4685 enum eDriveModel eModel = UNKNOWN_MODEL;
4686 struct nvme_id_ctrl ctrl = { 0 };
4687 struct libnvme_passthru_cmd cmd;
4688 nvme_print_flags_t flags;
4689 int err = 0;
4690
4691 NVME_ARGS(opts)nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0
, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT
, &nvme_args.verbose, 0, "Increase output verbosity", 0, }
, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0,
"suppress informational output", 0, }, {"output-format", 'o'
, "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
4692
4693 err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &eModel);
4694 if (err)
4695 return err;
4696
4697 if (eModel == UNKNOWN_MODEL) {
4698 nvme_show_error(nvme_show_message(1, "WARNING: Drive not recognized as Micron, proceeding anyway\n"
)
4699 "WARNING: Drive not recognized as Micron, proceeding anyway\n")nvme_show_message(1, "WARNING: Drive not recognized as Micron, proceeding anyway\n"
)
;
4700 }
4701
4702 err = validate_output_format(nvme_args.output_format, &flags);
4703 if (err) {
4704 nvme_show_error("Invalid output format")nvme_show_message(1, "Invalid output format");
4705 return err;
4706 }
4707
4708 nvme_init_identify_ctrl(&cmd, &ctrl);
4709 err = libnvme_exec_admin_passthru(hdl, &cmd);
4710 if (err) {
4711 nvme_show_error("identify controller failed: %s",nvme_show_message(1, "identify controller failed: %s", libnvme_strerror
(err))
4712 libnvme_strerror(err))nvme_show_message(1, "identify controller failed: %s", libnvme_strerror
(err))
;
4713 return err;
4714 }
4715
4716 nvme_show_id_ctrl(ctx, hdl, &ctrl, flags, micron_id_ctrl_vs);
4717
4718 return 0;
4719}
4720
4721static struct command select_download_cmd = {
4722 .name = "select-download",
4723 .help = "Selective Firmware Download",
4724 .fn = micron_selective_download,
4725};
4726
4727static struct command vs_temperature_stats_cmd = {
4728 .name = "vs-temperature-stats",
4729 .help = "Retrieve Micron temperature statistics ",
4730 .fn = micron_temp_stats,
4731};
4732
4733static struct command vs_pcie_stats_cmd = {
4734 .name = "vs-pcie-stats",
4735 .help = "Retrieve Micron PCIe error stats",
4736 .fn = micron_pcie_stats,
4737};
4738
4739static struct command clear_pcie_correctable_errors_cmd = {
4740 .name = "clear-pcie-correctable-errors",
4741 .help = "Clear correctable PCIe errors",
4742 .fn = micron_clear_pcie_correctable_errors,
4743};
4744
4745static struct command vs_internal_log_cmd = {
4746 .name = "vs-internal-log",
4747 .help = "Retrieve Micron logs",
4748 .fn = micron_internal_logs,
4749};
4750
4751static struct command vs_telemetry_controller_option_cmd = {
4752 .name = "vs-telemetry-controller-option",
4753 .help = "Enable/Disable controller telemetry log generation",
4754 .fn = micron_telemetry_cntrl_option,
4755};
4756
4757static struct command vs_nand_stats_cmd = {
4758 .name = "vs-nand-stats",
4759 .help = "Retrieve NAND Stats",
4760 .fn = micron_nand_stats,
4761};
4762
4763static struct command vs_smart_ext_log_cmd = {
4764 .name = "vs-smart-ext-log",
4765 .help = "Retrieve extended SMART logs",
4766 .fn = micron_smart_ext_log,
4767};
4768
4769static struct command vs_drive_info_cmd = {
4770 .name = "vs-drive-info",
4771 .help = "Retrieve Drive information",
4772 .fn = micron_drive_info,
4773};
4774
4775static struct command plugin_version_cmd = {
4776 .name = "plugin-version",
4777 .help = "Display plugin version info",
4778 .fn = micron_plugin_version,
4779 .no_device = true1,
4780};
4781
4782static struct command cloud_ssd_plugin_version_cmd = {
4783 .name = "cloud-SSD-plugin-version",
4784 .help = "Display plugin version info",
4785 .fn = micron_cloud_ssd_plugin_version,
4786 .no_device = true1,
4787};
4788
4789static struct command log_page_directory_cmd = {
4790 .name = "log-page-directory",
4791 .help = "Retrieve log page directory",
4792 .fn = micron_logpage_dir,
4793};
4794
4795static struct command vs_fw_activate_history_cmd = {
4796 .name = "vs-fw-activate-history",
4797 .help = "Display FW activation history",
4798 .fn = micron_fw_activation_history,
4799};
4800
4801static struct command latency_tracking_cmd = {
4802 .name = "latency-tracking",
4803 .help = "Latency monitoring feature control",
4804 .fn = micron_latency_stats_track,
4805};
4806
4807static struct command latency_stats_cmd = {
4808 .name = "latency-stats",
4809 .help = "Latency information for tracked commands",
4810 .fn = micron_latency_stats_info,
4811};
4812
4813static struct command latency_logs_cmd = {
4814 .name = "latency-logs",
4815 .help = "Latency log details tracked by drive",
4816 .fn = micron_latency_stats_logs,
4817};
4818
4819static struct command vs_smart_add_log_cmd = {
4820 .name = "vs-smart-add-log",
4821 .help = "Retrieve extended SMART data",
4822 .fn = micron_ocp_smart_health_logs,
4823};
4824
4825static struct command clear_fw_activate_history_cmd = {
4826 .name = "clear-fw-activate-history",
4827 .help = "Clear FW activation history",
4828 .fn = micron_clr_fw_activation_history,
4829};
4830
4831static struct command vs_smbus_option_cmd = {
4832 .name = "vs-smbus-option",
4833 .help = "Enable/Disable SMBUS on the drive",
4834 .fn = micron_smbus_option,
4835};
4836
4837static struct command cloud_boot_ssd_version_cmd = {
4838 .name = "cloud-boot-SSD-version",
4839 .help = "Prints HyperScale Boot Version",
4840 .fn = micron_cloud_boot_SSD_version,
4841};
4842
4843static struct command vs_device_waf_cmd = {
4844 .name = "vs-device-waf",
4845 .help = "Reports SLC and TLC WAF ratio",
4846 .fn = micron_device_waf,
4847};
4848
4849static struct command vs_cloud_log_cmd = {
4850 .name = "vs-cloud-log",
4851 .help = "Retrieve Extended Health Information of Hyperscale NVMe Boot SSD",
4852 .fn = micron_cloud_log,
4853};
4854
4855static struct command vs_work_load_log_cmd = {
4856 .name = "vs-work-load-log",
4857 .help = "Retrieve Workload logs",
4858 .fn = micron_work_load_log,
4859};
4860
4861static struct command vs_vendor_telemetry_log_cmd = {
4862 .name = "vs-vendor-telemetry-log",
4863 .help = "Retrieve Vendor Telemetry logs",
4864 .fn = micron_vendor_telemetry_log,
4865};
4866
4867static struct command smart_log_cmd = {
4868 .name = "smart-log",
4869 .help = "Retrieve SMART/Health Log",
4870 .fn = micron_health_info,
4871};
4872
4873static struct command id_ctrl_cmd = {
4874 .name = "id-ctrl",
4875 .help = "Identify Controller",
4876 .fn = micron_id_ctrl,
4877};
4878
4879static struct command *commands[] = {
4880 &select_download_cmd,
4881 &vs_temperature_stats_cmd,
4882 &vs_pcie_stats_cmd,
4883 &clear_pcie_correctable_errors_cmd,
4884 &vs_internal_log_cmd,
4885 &vs_telemetry_controller_option_cmd,
4886 &vs_nand_stats_cmd,
4887 &vs_smart_ext_log_cmd,
4888 &vs_drive_info_cmd,
4889 &plugin_version_cmd,
4890 &cloud_ssd_plugin_version_cmd,
4891 &log_page_directory_cmd,
4892 &vs_fw_activate_history_cmd,
4893 &latency_tracking_cmd,
4894 &latency_stats_cmd,
4895 &latency_logs_cmd,
4896 &vs_smart_add_log_cmd,
4897 &clear_fw_activate_history_cmd,
4898 &vs_smbus_option_cmd,
4899 &cloud_boot_ssd_version_cmd,
4900 &vs_device_waf_cmd,
4901 &vs_cloud_log_cmd,
4902 &vs_work_load_log_cmd,
4903 &vs_vendor_telemetry_log_cmd,
4904 &smart_log_cmd,
4905 &id_ctrl_cmd,
4906 NULL((void*)0),
4907};
4908
4909static struct plugin plugin = {
4910 .name = "micron",
4911 .desc = "Micron vendor specific extensions",
4912 .version = NVME_VERSION"3.1",
4913};
4914
4915static void __shr_constructor__attribute__((constructor)) register_plugin(void)
4916{
4917 plugin_add_group(&plugin, NULL((void*)0), commands);
4918 register_extension(&plugin);
4919}