Bug Summary

File:.build-ci/../plugins/micron/micron-nvme.c
Warning:line 2273, column 2
Value stored to 'err' is never read

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