Bug Summary

File:.build-ci/../plugins/sandisk/sandisk-utils.c
Warning:line 757, column 4
Value stored to 'ret' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name sandisk-utils.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 pic -pic-level 2 -pic-is-pie -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/lib/llvm-19/lib/clang/19 -include /__w/nvme-cli/nvme-cli/.build-ci/nvme-config.h -I nvme.p -I . -I .. -I ccan -I ../ccan -I libnvme/src -I ../libnvme/src -I /usr/include/json-c -D _FILE_OFFSET_BITS=64 -D _GNU_SOURCE -U NDEBUG -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -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 -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /__w/nvme-cli/nvme-cli/.build-ci/scan-results/2026-06-24-175442-590-1 -x c ../plugins/sandisk/sandisk-utils.c
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2025 Sandisk Corporation or its affiliates.
4 *
5 * Author: Jeff Lien <jeff.lien@sandisk.com>
6 * Brandon Paupore <brandon.paupore@sandisk.com>
7 */
8
9#include <errno(*__errno_location ()).h>
10#include <fcntl.h>
11#include <string.h>
12#include <unistd.h>
13#include <time.h>
14
15#include <libnvme.h>
16
17#include "common.h"
18#include "nvme-cmds.h"
19#include "nvme-print.h"
20#include "nvme.h"
21
22#include "sandisk-utils.h"
23#include "plugins/wdc/wdc-nvme-cmds.h"
24
25/* WDC UUID value */
26static const __u8 WDC_UUID[NVME_UUID_LEN16] = {
27 0x2d, 0xb9, 0x8c, 0x52, 0x0c, 0x4c, 0x5a, 0x15,
28 0xab, 0xe6, 0x33, 0x29, 0x9a, 0x70, 0xdf, 0xd0
29};
30
31/* WDC_UUID value for SN640_3 devices and SN655 devices */
32static const __u8 WDC_UUID_SN640_3[NVME_UUID_LEN16] = {
33 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
34 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22
35};
36
37/* Sandisk UUID value */
38static const __u8 SNDK_UUID[NVME_UUID_LEN16] = {
39 0xde, 0x87, 0xd1, 0xeb, 0x72, 0xc5, 0x58, 0x0b,
40 0xad, 0xd8, 0x3c, 0x29, 0xd1, 0x23, 0x7c, 0x70
41};
42
43int sndk_get_pci_ids(struct libnvme_global_ctx *ctx, struct libnvme_transport_handle *hdl,
44 uint32_t *device_id, uint32_t *vendor_id)
45{
46 char vid[256], did[256], id[32];
47 libnvme_ctrl_t c = NULL((void*)0);
48 libnvme_ns_t n = NULL((void*)0);
49 const char *name;
50 int fd, ret;
51
52 name = libnvme_transport_handle_get_name(hdl);
53 ret = libnvme_scan_ctrl(ctx, name, &c);
54 if (!ret) {
55 snprintf(vid, sizeof(vid), "%s/device/vendor",
56 libnvme_ctrl_get_sysfs_dir(c));
57 snprintf(did, sizeof(did), "%s/device/device",
58 libnvme_ctrl_get_sysfs_dir(c));
59 libnvme_free_ctrl(c);
60 } else {
61 ret = libnvme_scan_namespace(ctx, name, &n);
62 if (!ret) {
63 fprintf(stderrstderr, "Unable to find %s\n", name);
64 return ret;
65 }
66
67 snprintf(vid, sizeof(vid), "%s/device/device/vendor",
68 libnvme_ns_get_sysfs_dir(n));
69 snprintf(did, sizeof(did), "%s/device/device/device",
70 libnvme_ns_get_sysfs_dir(n));
71 libnvme_free_ns(n);
72 }
73
74 fd = open(vid, O_RDONLY00);
75 if (fd < 0) {
76 fprintf(stderrstderr, "ERROR: SNDK: %s : Open vendor file failed\n", __func__);
77 return -1;
78 }
79
80 ret = read(fd, id, 32);
81 close(fd);
82
83 if (ret < 0) {
84 fprintf(stderrstderr, "%s: Read of pci vendor id failed\n", __func__);
85 return -1;
86 }
87 id[ret < 32 ? ret : 31] = '\0';
88 if (id[strlen(id) - 1] == '\n')
89 id[strlen(id) - 1] = '\0';
90
91 *vendor_id = strtol(id, NULL((void*)0), 0);
92 ret = 0;
93
94 fd = open(did, O_RDONLY00);
95 if (fd < 0) {
96 fprintf(stderrstderr, "ERROR: SNDK: %s : Open device file failed\n", __func__);
97 return -1;
98 }
99
100 ret = read(fd, id, 32);
101 close(fd);
102
103 if (ret < 0) {
104 fprintf(stderrstderr, "ERROR: SNDK: %s: Read of pci device id failed\n", __func__);
105 return -1;
106 }
107 id[ret < 32 ? ret : 31] = '\0';
108 if (id[strlen(id) - 1] == '\n')
109 id[strlen(id) - 1] = '\0';
110
111 *device_id = strtol(id, NULL((void*)0), 0);
112 return 0;
113}
114
115int sndk_get_vendor_id(struct libnvme_transport_handle *hdl, uint32_t *vendor_id)
116{
117 struct nvme_id_ctrl ctrl;
118 int ret;
119
120 memset(&ctrl, 0, sizeof(struct nvme_id_ctrl));
121 ret = nvme_identify_ctrl(hdl, &ctrl);
122 if (ret) {
123 fprintf(stderrstderr, "ERROR: SNDK: nvme_identify_ctrl() failed 0x%x\n", ret);
124 return -1;
125 }
126
127 *vendor_id = (uint32_t) ctrl.vid;
128
129 return ret;
130}
131
132bool_Bool sndk_check_device(struct libnvme_global_ctx *ctx,
133 struct libnvme_transport_handle *hdl)
134{
135 uint32_t read_device_id = -1, read_vendor_id = -1;
136 bool_Bool supported;
137 int ret;
138
139 ret = sndk_get_pci_ids(ctx, hdl, &read_device_id, &read_vendor_id);
140 if (ret < 0) {
141 /* Use the identify nvme command to get vendor id due to NVMeOF device. */
142 if (sndk_get_vendor_id(hdl, &read_vendor_id) < 0)
143 return false0;
144 }
145
146 supported = false0;
147
148 if (read_vendor_id == SNDK_NVME_SNDK_VID0x15b7 ||
149 read_vendor_id == SNDK_NVME_WDC_VID0x1b96)
150 supported = true1;
151 else
152 fprintf(stderrstderr,
153 "ERROR: SNDK: unsupported Sandisk device, Vendor ID = 0x%x, Device ID = 0x%x\n",
154 read_vendor_id, read_device_id);
155
156 return supported;
157}
158
159void sndk_get_commit_action_bin(__u8 commit_action_type, char *action_bin)
160{
161 switch (commit_action_type) {
162 case 0:
163 strcpy(action_bin, "000b");
164 break;
165 case 1:
166 strcpy(action_bin, "001b");
167 break;
168 case 2:
169 strcpy(action_bin, "010b");
170 break;
171 case 3:
172 strcpy(action_bin, "011b");
173 break;
174 case 4:
175 strcpy(action_bin, "100b");
176 break;
177 case 5:
178 strcpy(action_bin, "101b");
179 break;
180 case 6:
181 strcpy(action_bin, "110b");
182 break;
183 case 7:
184 strcpy(action_bin, "111b");
185 break;
186 default:
187 strcpy(action_bin, "INVALID");
188 }
189}
190
191bool_Bool sndk_parse_dev_mng_log_entry(void *data,
192 __u32 entry_id,
193 struct sndk_c2_log_subpage_header **log_entry)
194{
195 __u32 remaining_len = 0;
196 __u32 log_length = 0;
197 __u32 log_entry_size = 0;
198 __u32 log_entry_id = 0;
199 __u32 offset = 0;
200 bool_Bool found = false0;
201 struct sndk_c2_log_subpage_header *p_next_log_entry = NULL((void*)0);
202 struct sndk_c2_log_page_header *hdr_ptr = (struct sndk_c2_log_page_header *)data;
203
204 log_length = le32_to_cpu(hdr_ptr->length);
205 /* Ensure log data is large enough for common header */
206 if (log_length < sizeof(struct sndk_c2_log_page_header)) {
207 fprintf(stderrstderr,
208 "ERROR: %s: log smaller than header. log_len: 0x%x HdrSize: %"PRIxPTR"l" "x""\n",
209 __func__, log_length, sizeof(struct sndk_c2_log_page_header));
210 return found;
211 }
212
213 /* Get pointer to first log Entry */
214 offset = sizeof(struct sndk_c2_log_page_header);
215 p_next_log_entry = (struct sndk_c2_log_subpage_header *)(((__u8 *)data) + offset);
216 remaining_len = log_length - offset;
217
218 if (!log_entry) {
219 fprintf(stderrstderr, "ERROR: SNDK - %s: No log entry pointer.\n", __func__);
220 return found;
221 }
222 *log_entry = NULL((void*)0);
223
224 /* Proceed only if there is at least enough data to read an entry header */
225 while (remaining_len >= sizeof(struct sndk_c2_log_subpage_header)) {
226 /* Get size of the next entry */
227 log_entry_size = le32_to_cpu(p_next_log_entry->length);
228 log_entry_id = le32_to_cpu(p_next_log_entry->entry_id);
229
230 /*
231 * If log entry size is 0 or the log entry goes past the end
232 * of the data, we must be at the end of the data
233 */
234 if (!log_entry_size || log_entry_size > remaining_len) {
235 fprintf(stderrstderr, "ERROR: SNDK: %s: Detected unaligned end of the data. ",
236 __func__);
237 fprintf(stderrstderr, "Data Offset: 0x%x Entry Size: 0x%x, ",
238 offset, log_entry_size);
239 fprintf(stderrstderr, "Remaining Log Length: 0x%x Entry Id: 0x%x\n",
240 remaining_len, log_entry_id);
241
242 /* Force the loop to end */
243 remaining_len = 0;
244 } else if (!log_entry_id || log_entry_id > 200) {
245 /* Invalid entry - fail the search */
246 fprintf(stderrstderr, "ERROR: SNDK: %s: Invalid entry found at offset: 0x%x ",
247 __func__, offset);
248 fprintf(stderrstderr, "Entry Size: 0x%x, Remaining Log Length: 0x%x ",
249 log_entry_size, remaining_len);
250 fprintf(stderrstderr, "Entry Id: 0x%x\n", log_entry_id);
251
252 /* Force the loop to end */
253 remaining_len = 0;
254 } else {
255 if (log_entry_id == entry_id) {
256 found = true1;
257 *log_entry = p_next_log_entry;
258 remaining_len = 0;
259 } else {
260 remaining_len -= log_entry_size;
261 }
262
263 if (remaining_len > 0) {
264 /* Increment the offset counter */
265 offset += log_entry_size;
266
267 /* Get the next entry */
268 p_next_log_entry =
269 (struct sndk_c2_log_subpage_header *)(((__u8 *)data) + offset);
270 }
271 }
272 }
273
274 return found;
275}
276
277bool_Bool sndk_nvme_parse_dev_status_log_entry(void *log_data,
278 __u32 entry_id,
279 __u32 *ret_data)
280{
281 struct sndk_c2_log_subpage_header *entry_data = NULL((void*)0);
282
283 if (sndk_parse_dev_mng_log_entry(log_data, entry_id, &entry_data)) {
284 if (entry_data) {
285 *ret_data = le32_to_cpu(entry_data->data);
286 return true1;
287 }
288 }
289
290 *ret_data = 0;
291 return false0;
292}
293
294bool_Bool sndk_nvme_parse_dev_status_log_str(void *log_data,
295 __u32 entry_id,
296 char *ret_data,
297 __u32 *ret_data_len)
298{
299 struct sndk_c2_log_subpage_header *entry_data = NULL((void*)0);
300 struct sndk_c2_cbs_data *entry_str_data = NULL((void*)0);
301
302 if (sndk_parse_dev_mng_log_entry(log_data, entry_id, &entry_data)) {
303 if (entry_data) {
304 entry_str_data = (struct sndk_c2_cbs_data *)&entry_data->data;
305 memcpy(ret_data,
306 (void *)&entry_str_data->data,
307 le32_to_cpu(entry_str_data->length));
308 *ret_data_len = le32_to_cpu(entry_str_data->length);
309 return true1;
310 }
311 }
312
313 *ret_data = 0;
314 *ret_data_len = 0;
315 return false0;
316}
317
318
319bool_Bool sndk_get_dev_mgment_data(struct libnvme_global_ctx *ctx, struct libnvme_transport_handle *hdl,
320 void **data)
321{
322 bool_Bool found = false0;
323 __u32 device_id = 0, vendor_id = 0;
324 int uuid_index = 0;
325 struct nvme_id_uuid_list uuid_list;
326
327 *data = NULL((void*)0);
328
329 /* The sndk_get_pci_ids function could fail when drives are connected
330 * via a PCIe switch. Therefore, the return code is intentionally
331 * being ignored. The device_id and vendor_id variables have been
332 * initialized to 0 so the code can continue on without issue for
333 * both cases: sndk_get_pci_ids successful or failed.
334 */
335 sndk_get_pci_ids(ctx, hdl, &device_id, &vendor_id);
336
337 memset(&uuid_list, 0, sizeof(struct nvme_id_uuid_list));
338 if (!libnvme_get_uuid_list(hdl, &uuid_list)) {
339 /* check for the Sandisk UUID first */
340 uuid_index = libnvme_find_uuid(&uuid_list, SNDK_UUID);
341
342 if (uuid_index < 0) {
343 /* The Sandisk UUID is not found;
344 * check for the WDC UUID second.
345 */
346 uuid_index = libnvme_find_uuid(&uuid_list, WDC_UUID);
347 if (uuid_index < 0)
348 /* Check for the UUID used on SN640 and SN655 drives */
349 uuid_index = libnvme_find_uuid(&uuid_list, WDC_UUID_SN640_3);
350 }
351
352 if (uuid_index >= 0)
353 found = sndk_get_dev_mgmt_log_page_data(hdl, data, uuid_index);
354 else {
355 fprintf(stderrstderr, "%s: UUID lists are supported but a matching ",
356 __func__);
357 fprintf(stderrstderr, "uuid was not found\n");
358 }
359 } else {
360 /* UUID lists are not supported, Default to uuid-index 0 */
361 fprintf(stderrstderr, "INFO: SNDK: %s: UUID Lists not supported\n",
362 __func__);
363 uuid_index = 0;
364 found = sndk_get_dev_mgmt_log_page_data(hdl, data, uuid_index);
365 }
366
367 return found;
368}
369
370bool_Bool sndk_validate_dev_mng_log(void *data)
371{
372 __u32 remaining_len = 0;
373 __u32 log_length = 0;
374 __u32 log_entry_size = 0;
375 __u32 log_entry_id = 0;
376 __u32 offset = 0;
377 bool_Bool valid_log = false0;
378 struct sndk_c2_log_subpage_header *p_next_log_entry = NULL((void*)0);
379 struct sndk_c2_log_page_header *hdr_ptr = (struct sndk_c2_log_page_header *)data;
380
381 log_length = le32_to_cpu(hdr_ptr->length);
382 /* Ensure log data is large enough for common header */
383 if (log_length < sizeof(struct sndk_c2_log_page_header)) {
384 fprintf(stderrstderr,
385 "ERROR: %s: log smaller than header. log_len: 0x%x HdrSize: %"PRIxPTR"l" "x""\n",
386 __func__, log_length, sizeof(struct sndk_c2_log_page_header));
387 return valid_log;
388 }
389
390 /* Get pointer to first log Entry */
391 offset = sizeof(struct sndk_c2_log_page_header);
392 p_next_log_entry = (struct sndk_c2_log_subpage_header *)(((__u8 *)data) + offset);
393 remaining_len = log_length - offset;
394
395 /* Proceed only if there is at least enough data to read an entry header */
396 while (remaining_len >= sizeof(struct sndk_c2_log_subpage_header)) {
397 /* Get size of the next entry */
398 log_entry_size = le32_to_cpu(p_next_log_entry->length);
399 log_entry_id = le32_to_cpu(p_next_log_entry->entry_id);
400 /*
401 * If log entry size is 0 or the log entry goes past the end
402 * of the data, we must be at the end of the data
403 */
404 if (!log_entry_size || log_entry_size > remaining_len) {
405 fprintf(stderrstderr, "ERROR: SNDK: %s: Detected unaligned end of the data. ",
406 __func__);
407 fprintf(stderrstderr, "Data Offset: 0x%x Entry Size: 0x%x, ",
408 offset, log_entry_size);
409 fprintf(stderrstderr, "Remaining Log Length: 0x%x Entry Id: 0x%x\n",
410 remaining_len, log_entry_id);
411
412 /* Force the loop to end */
413 remaining_len = 0;
414 } else if (!log_entry_id || log_entry_id > 200) {
415 /* Invalid entry - fail the search */
416 fprintf(stderrstderr, "ERROR: SNDK: %s: Invalid entry found at offset: 0x%x ",
417 __func__, offset);
418 fprintf(stderrstderr, "Entry Size: 0x%x, Remaining Log Length: 0x%x ",
419 log_entry_size, remaining_len);
420 fprintf(stderrstderr, "Entry Id: 0x%x\n", log_entry_id);
421
422 /* Force the loop to end */
423 remaining_len = 0;
424 valid_log = false0;
425 } else {
426 /* A valid log has at least one entry and no invalid entries */
427 valid_log = true1;
428 remaining_len -= log_entry_size;
429 if (remaining_len > 0) {
430 /* Increment the offset counter */
431 offset += log_entry_size;
432 /* Get the next entry */
433 p_next_log_entry =
434 (struct sndk_c2_log_subpage_header *)(((__u8 *)data) + offset);
435 }
436 }
437 }
438
439 return valid_log;
440}
441
442bool_Bool sndk_get_dev_mgmt_log_page_data(struct libnvme_transport_handle *hdl,
443 void **log_data,
444 __u8 uuid_ix)
445{
446 struct sndk_c2_log_page_header *hdr_ptr;
447 struct libnvme_passthru_cmd cmd;
448 bool_Bool valid = false0;
449 __u32 length = 0;
450 void *data;
451 int ret = 0;
452
453 data = (__u8 *)malloc(sizeof(__u8) * SNDK_DEV_MGMNT_LOG_PAGE_LEN0x1000);
454 if (!data) {
455 fprintf(stderrstderr, "ERROR: SNDK: malloc: %s\n", libnvme_strerror(errno(*__errno_location ())));
456 return false0;
457 }
458
459 memset(data, 0, sizeof(__u8) * SNDK_DEV_MGMNT_LOG_PAGE_LEN0x1000);
460
461 /* get the log page length */
462 nvme_init_get_log(&cmd, NVME_NSID_ALL,
463 SNDK_NVME_GET_DEV_MGMNT_LOG_PAGE_ID0xC2, NVME_CSI_NVM, data,
464 SNDK_DEV_MGMNT_LOG_PAGE_LEN0x1000);
465 cmd.cdw14 |= NVME_FIELD_ENCODE(uuid_ix,(((__u32)(uuid_ix) & (NVME_LOG_CDW14_UUID_MASK)) <<
(NVME_LOG_CDW14_UUID_SHIFT))
466 NVME_LOG_CDW14_UUID_SHIFT,(((__u32)(uuid_ix) & (NVME_LOG_CDW14_UUID_MASK)) <<
(NVME_LOG_CDW14_UUID_SHIFT))
467 NVME_LOG_CDW14_UUID_MASK)(((__u32)(uuid_ix) & (NVME_LOG_CDW14_UUID_MASK)) <<
(NVME_LOG_CDW14_UUID_SHIFT))
;
468 ret = libnvme_get_log(hdl, &cmd, false0, NVME_LOG_PAGE_PDU_SIZE4096);
469 if (ret) {
470 fprintf(stderrstderr,
471 "ERROR: SNDK: Unable to get 0x%x Log Page with uuid %d, ret = 0x%x\n",
472 SNDK_NVME_GET_DEV_MGMNT_LOG_PAGE_ID0xC2, uuid_ix, ret);
473 goto end;
474 }
475
476 hdr_ptr = (struct sndk_c2_log_page_header *)data;
477 length = le32_to_cpu(hdr_ptr->length);
478
479 if (length > SNDK_DEV_MGMNT_LOG_PAGE_LEN0x1000) {
480 /* Log page buffer too small for actual data */
481 free(data);
482 data = calloc(length, sizeof(__u8));
483 if (!data) {
484 fprintf(stderrstderr, "ERROR: SNDK: malloc: %s\n", libnvme_strerror(errno(*__errno_location ())));
485 goto end;
486 }
487
488 /* get the log page data with the increased length */
489 nvme_init_get_log(&cmd, NVME_NSID_ALL,
490 SNDK_NVME_GET_DEV_MGMNT_LOG_PAGE_ID0xC2, NVME_CSI_NVM, data,
491 length);
492 cmd.cdw14 |= NVME_FIELD_ENCODE(uuid_ix,(((__u32)(uuid_ix) & (NVME_LOG_CDW14_UUID_MASK)) <<
(NVME_LOG_CDW14_UUID_SHIFT))
493 NVME_LOG_CDW14_UUID_SHIFT,(((__u32)(uuid_ix) & (NVME_LOG_CDW14_UUID_MASK)) <<
(NVME_LOG_CDW14_UUID_SHIFT))
494 NVME_LOG_CDW14_UUID_MASK)(((__u32)(uuid_ix) & (NVME_LOG_CDW14_UUID_MASK)) <<
(NVME_LOG_CDW14_UUID_SHIFT))
;
495 ret = libnvme_get_log(hdl, &cmd, false0, NVME_LOG_PAGE_PDU_SIZE4096);
496 if (ret) {
497 fprintf(stderrstderr,
498 "ERROR: SNDK: Unable to read 0x%x Log with uuid %d, ret = 0x%x\n",
499 SNDK_NVME_GET_DEV_MGMNT_LOG_PAGE_ID0xC2, uuid_ix, ret);
500 goto end;
501 }
502 }
503
504 valid = sndk_validate_dev_mng_log(data);
505 if (valid) {
506 /* Ensure size of log data matches length in log header */
507 *log_data = calloc(length, sizeof(__u8));
508 if (!*log_data) {
509 fprintf(stderrstderr, "ERROR: SNDK: calloc: %s\n", libnvme_strerror(errno(*__errno_location ())));
510 valid = false0;
511 goto end;
512 }
513 memcpy((void *)*log_data, data, length);
514 } else {
515 fprintf(stderrstderr, "ERROR: SNDK: C2 log page not found with uuid index %d\n",
516 uuid_ix);
517 }
518
519end:
520 free(data);
521 return valid;
522}
523
524__u64 sndk_get_drive_capabilities(struct libnvme_global_ctx *ctx,
525 struct libnvme_transport_handle *hdl)
526{
527 uint32_t read_device_id = -1, read_vendor_id = -1;
528 __u64 capabilities = 0;
529 int ret;
530
531 ret = sndk_get_pci_ids(ctx, hdl, &read_device_id, &read_vendor_id);
532 if (ret < 0) {
533 if (sndk_get_vendor_id(hdl, &read_vendor_id) < 0)
534 return capabilities;
535 }
536
537 /*
538 * Below check condition is added due in NVMeOF device
539 * We aren't able to read the device_id in this case
540 * so we can only use the vendor_id
541 */
542 if (read_device_id == -1 && read_vendor_id != -1) {
543 capabilities = sndk_get_enc_drive_capabilities(ctx, hdl);
544 return capabilities;
545 }
546
547 switch (read_vendor_id) {
548 case SNDK_NVME_WDC_VID0x1b96:
549 switch (read_device_id) {
550 case SNDK_NVME_SNTMP_DEV_ID0x2761:
551 case SNDK_NVME_SNTMP_DEV_ID_10x2763:
552 capabilities |= (SNDK_DRIVE_CAP_C0_LOG_PAGE0x0000000000100000 |
553 SNDK_DRIVE_CAP_C3_LOG_PAGE0x0000000020000000 |
554 SNDK_DRIVE_CAP_CA_LOG_PAGE0x0000000000000008 |
555 SNDK_DRIVE_CAP_OCP_C4_LOG_PAGE0x0000004000000000 |
556 SNDK_DRIVE_CAP_OCP_C5_LOG_PAGE0x0000008000000000 |
557 SNDK_DRIVE_CAP_UDUI0x0000040000000000 |
558 SNDK_DRIVE_CAP_VU_FID_CLEAR_PCIE0x0000000000800000 |
559 SNDK_DRIVE_CAP_CLEAR_ASSERT0x0000000000000040 |
560 SNDK_DRIVE_CAP_CLOUD_SSD_VERSION0x0000000004000000 |
561 SNDK_DRIVE_CAP_LOG_PAGE_DIR0x0000000000020000 |
562 SNDK_DRIVE_CAP_DRIVE_STATUS0x0000000000000020 |
563 SNDK_DRIVE_CAP_SET_LATENCY_MONITOR0x0000020000000000);
564 break;
565
566 case SNDK_NVME_SN861_DEV_ID_E1S0x2750:
567 capabilities |= (SNDK_DRIVE_CAP_C0_LOG_PAGE0x0000000000100000 |
568 SNDK_DRIVE_CAP_C3_LOG_PAGE0x0000000020000000 |
569 SNDK_DRIVE_CAP_CA_LOG_PAGE0x0000000000000008 |
570 SNDK_DRIVE_CAP_OCP_C4_LOG_PAGE0x0000004000000000 |
571 SNDK_DRIVE_CAP_OCP_C5_LOG_PAGE0x0000008000000000 |
572 SNDK_DRIVE_CAP_INTERNAL_LOG0x0000000000000002 |
573 SNDK_DRIVE_CAP_FW_ACTIVATE_HISTORY_C20x0000000001000000 |
574 SNDK_DRIVE_CAP_VU_FID_CLEAR_PCIE0x0000000000800000 |
575 SNDK_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY0x0000000002000000 |
576 SNDK_DRIVE_CAP_INFO0x0000000000080000 |
577 SNDK_DRIVE_CAP_CLOUD_SSD_VERSION0x0000000004000000 |
578 SNDK_DRIVE_CAP_LOG_PAGE_DIR0x0000000000020000 |
579 SNDK_DRIVE_CAP_DRIVE_STATUS0x0000000000000020 |
580 SNDK_DRIVE_CAP_SET_LATENCY_MONITOR0x0000020000000000);
581 break;
582
583 case SNDK_NVME_SN861_DEV_ID_U20x2751:
584 case SNDK_NVME_SN861_DEV_ID_E3S0x2752:
585 capabilities |= (SNDK_DRIVE_CAP_C0_LOG_PAGE0x0000000000100000 |
586 SNDK_DRIVE_CAP_C3_LOG_PAGE0x0000000020000000 |
587 SNDK_DRIVE_CAP_CA_LOG_PAGE0x0000000000000008 |
588 SNDK_DRIVE_CAP_OCP_C4_LOG_PAGE0x0000004000000000 |
589 SNDK_DRIVE_CAP_OCP_C5_LOG_PAGE0x0000008000000000 |
590 SNDK_DRIVE_CAP_INTERNAL_LOG0x0000000000000002 |
591 SNDK_DRIVE_CAP_FW_ACTIVATE_HISTORY_C20x0000000001000000 |
592 SNDK_DRIVE_CAP_VU_FID_CLEAR_PCIE0x0000000000800000 |
593 SNDK_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY0x0000000002000000 |
594 SNDK_DRIVE_CAP_INFO0x0000000000080000 |
595 SNDK_DRIVE_CAP_CLOUD_SSD_VERSION0x0000000004000000 |
596 SNDK_DRIVE_CAP_LOG_PAGE_DIR0x0000000000020000 |
597 SNDK_DRIVE_CAP_DRIVE_STATUS0x0000000000000020 |
598 SNDK_DRIVE_CAP_RESIZE_SN8610x0000080000000000 |
599 SNDK_DRIVE_CAP_SET_LATENCY_MONITOR0x0000020000000000);
600 break;
601
602 default:
603 capabilities = 0;
604 }
605 break;
606
607 case SNDK_NVME_SNDK_VID0x15b7:
608 switch (read_device_id) {
609 case SNDK_NVME_SNESSD1_DEV_ID_E1L0x2765:
610 case SNDK_NVME_SNESSD1_DEV_ID_E20x2766:
611 case SNDK_NVME_SNESSD1_DEV_ID_E3S0x2767:
612 case SNDK_NVME_SNESSD1_DEV_ID_E3L0x2768:
613 case SNDK_NVME_SNESSD1_DEV_ID_U20x2769:
614 capabilities |= (SNDK_DRIVE_CAP_C0_LOG_PAGE0x0000000000100000 |
615 SNDK_DRIVE_CAP_C3_LOG_PAGE0x0000000020000000 |
616 SNDK_DRIVE_CAP_CA_LOG_PAGE0x0000000000000008 |
617 SNDK_DRIVE_CAP_OCP_C4_LOG_PAGE0x0000004000000000 |
618 SNDK_DRIVE_CAP_OCP_C5_LOG_PAGE0x0000008000000000 |
619 SNDK_DRIVE_CAP_UDUI0x0000040000000000 |
620 SNDK_DRIVE_CAP_VU_FID_CLEAR_PCIE0x0000000000800000 |
621 SNDK_DRIVE_CAP_CLEAR_ASSERT0x0000000000000040 |
622 SNDK_DRIVE_CAP_CLOUD_SSD_VERSION0x0000000004000000 |
623 SNDK_DRIVE_CAP_LOG_PAGE_DIR0x0000000000020000 |
624 SNDK_DRIVE_CAP_DRIVE_STATUS0x0000000000000020 |
625 SNDK_DRIVE_CAP_SET_LATENCY_MONITOR0x0000020000000000);
626 break;
627
628 case SNDK_NVME_SNESSD3_DEV_ID_E20x2770:
629 case SNDK_NVME_SNESSD3_DEV_ID_U20x2771:
630 case SNDK_NVME_SNESSD3_DEV_ID_E3L0x2772:
631 case SNDK_NVME_SNESSD3_DEV_ID_E3S0x2773:
632 case SNDK_NVME_SNESSD3_DEV_ID_E1L0x2774:
633 capabilities |= (SNDK_DRIVE_CAP_C0_LOG_PAGE0x0000000000100000 |
634 SNDK_DRIVE_CAP_C3_LOG_PAGE0x0000000020000000 |
635 SNDK_DRIVE_CAP_CA_LOG_PAGE0x0000000000000008 |
636 SNDK_DRIVE_CAP_OCP_C4_LOG_PAGE0x0000004000000000 |
637 SNDK_DRIVE_CAP_OCP_C5_LOG_PAGE0x0000008000000000 |
638 SNDK_DRIVE_CAP_UDUI0x0000040000000000 |
639 SNDK_DRIVE_CAP_VU_FID_CLEAR_PCIE0x0000000000800000 |
640 SNDK_DRIVE_CAP_CLEAR_ASSERT0x0000000000000040 |
641 SNDK_DRIVE_CAP_CLOUD_SSD_VERSION0x0000000004000000 |
642 SNDK_DRIVE_CAP_LOG_PAGE_DIR0x0000000000020000 |
643 SNDK_DRIVE_CAP_DRIVE_STATUS0x0000000000000020 |
644 SNDK_DRIVE_CAP_SET_LATENCY_MONITOR0x0000020000000000);
645 break;
646
647 case SNDK_NVME_SN7150_DEV_ID_10x503b:
648 case SNDK_NVME_SN7150_DEV_ID_20x503c:
649 case SNDK_NVME_SN7150_DEV_ID_30x503d:
650 case SNDK_NVME_SN7150_DEV_ID_40x503e:
651 case SNDK_NVME_SN7150_DEV_ID_50x503f:
652 capabilities = SNDK_DRIVE_CAP_UDUI0x0000040000000000;
653 break;
654
655 case SNDK_NVME_SNCSSD1_DEV_ID_M2_22300x5081:
656 case SNDK_NVME_SNCSSD1_DEV_ID_M2_22420x5082:
657 case SNDK_NVME_SNCSSD1_DEV_ID_M2_22800x5083:
658 capabilities = SNDK_DRIVE_CAP_UDUI0x0000040000000000;
659 break;
660
661 case SNDK_NVME_SN862_DEV_ID_E1S_250x27A0:
662 case SNDK_NVME_SN862_DEV_ID_E1S_150x27A1:
663 case SNDK_NVME_SN862_DEV_ID_E1S_950x27A2:
664 case SNDK_NVME_SN862_DEV_ID_E3S0x27A3:
665 case SNDK_NVME_SN862_DEV_ID_U20x27A4:
666 case SNDK_NVME_SNESSD2_DEV_ID_E1S_950x2790:
667 case SNDK_NVME_SNESSD2_DEV_ID_E1S_150x2791:
668 case SNDK_NVME_SNESSD2_DEV_ID_E1L0x2792:
669 case SNDK_NVME_SNESSD2_DEV_ID_E3S0x2793:
670 case SNDK_NVME_SNESSD2_DEV_ID_E3L0x2794:
671 capabilities |= (SNDK_DRIVE_CAP_C0_LOG_PAGE0x0000000000100000 |
672 SNDK_DRIVE_CAP_C3_LOG_PAGE0x0000000020000000 |
673 SNDK_DRIVE_CAP_CA_LOG_PAGE0x0000000000000008 |
674 SNDK_DRIVE_CAP_OCP_C4_LOG_PAGE0x0000004000000000 |
675 SNDK_DRIVE_CAP_OCP_C5_LOG_PAGE0x0000008000000000 |
676 SNDK_DRIVE_CAP_INTERNAL_LOG0x0000000000000002 |
677 SNDK_DRIVE_CAP_FW_ACTIVATE_HISTORY_C20x0000000001000000 |
678 SNDK_DRIVE_CAP_VU_FID_CLEAR_PCIE0x0000000000800000 |
679 SNDK_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY0x0000000002000000 |
680 SNDK_DRIVE_CAP_INFO0x0000000000080000 |
681 SNDK_DRIVE_CAP_CLOUD_SSD_VERSION0x0000000004000000 |
682 SNDK_DRIVE_CAP_LOG_PAGE_DIR0x0000000000020000 |
683 SNDK_DRIVE_CAP_DRIVE_STATUS0x0000000000000020 |
684 SNDK_DRIVE_CAP_RESIZE_SN8610x0000080000000000 |
685 SNDK_DRIVE_CAP_SET_LATENCY_MONITOR0x0000020000000000);
686 break;
687
688 default:
689 capabilities = 0;
690 }
691 break;
692 default:
693 capabilities = 0;
694 }
695
696 /* Check for fallback WDC plugin support */
697 if (!capabilities)
698 capabilities = run_wdc_get_drive_capabilities(ctx, hdl);
699
700 return capabilities;
701}
702
703__u64 sndk_get_enc_drive_capabilities(struct libnvme_global_ctx *ctx,
704 struct libnvme_transport_handle *hdl)
705{
706 int ret;
707 uint32_t read_vendor_id;
708 __u64 capabilities = 0;
709 __u32 cust_id, market_name_len,
710 drive_form_factor = 0;
711 char marketing_name[64];
712 void *dev_mng_log = NULL((void*)0);
713 int uuid_index = 0;
714 struct nvme_id_uuid_list uuid_list;
715
716 memset(marketing_name, 0, 64);
717
718 ret = sndk_get_vendor_id(hdl, &read_vendor_id);
719 if (ret < 0)
720 return capabilities;
721
722 switch (read_vendor_id) {
723 case SNDK_NVME_WDC_VID0x1b96:
724 capabilities = (SNDK_DRIVE_CAP_INTERNAL_LOG0x0000000000000002 |
725 SNDK_DRIVE_CAP_DRIVE_STATUS0x0000000000000020 |
726 SNDK_DRIVE_CAP_CLEAR_ASSERT0x0000000000000040 |
727 SNDK_DRIVE_CAP_RESIZE0x0000000000000100);
728
729 /* Check for the Sandisk or WDC UUID index */
730 memset(&uuid_list, 0, sizeof(struct nvme_id_uuid_list));
731 if (!libnvme_get_uuid_list(hdl, &uuid_list)) {
732 /* check for the Sandisk UUID first */
733 uuid_index = libnvme_find_uuid(&uuid_list, SNDK_UUID);
734
735 if (uuid_index < 0) {
736 /* The Sandisk UUID is not found;
737 * check for the WDC UUID second.
738 */
739 uuid_index = libnvme_find_uuid(&uuid_list, WDC_UUID);
740 if (uuid_index < 0)
741 /* Check for the UUID used on SN640 and SN655 drives */
742 uuid_index = libnvme_find_uuid(&uuid_list, WDC_UUID_SN640_3);
743 }
744 } else {
745 /* UUID Lists not supported, Use default uuid index - 0 */
746 fprintf(stderrstderr, "INFO: SNDK: %s: UUID Lists not supported\n",
747 __func__);
748 uuid_index = 0;
749 }
750
751 /* verify the 0xC2 Device Manageability log page is supported */
752 if (run_wdc_nvme_check_supported_log_page(ctx, hdl,
753 SNDK_NVME_GET_DEV_MGMNT_LOG_PAGE_ID0xC2,
754 uuid_index) == false0) {
755 fprintf(stderrstderr, "ERROR: SNDK: 0xC2 Log Page not supported, ");
756 fprintf(stderrstderr, "uuid_index: %d\n", uuid_index);
757 ret = -1;
Value stored to 'ret' is never read
758 goto out;
759 }
760
761 if (!sndk_get_dev_mgment_data(ctx, hdl, &dev_mng_log)) {
762 fprintf(stderrstderr, "ERROR: SNDK: 0xC2 Log Page not found\n");
763 ret = -1;
764 goto out;
765 }
766
767 /* Get the customer ID */
768 if (!sndk_nvme_parse_dev_status_log_entry(dev_mng_log,
769 SNDK_C2_CUSTOMER_ID_ID0x15,
770 (void *)&cust_id))
771 fprintf(stderrstderr, "ERROR: SNDK: Get Customer FW ID Failed\n");
772
773 /* Get the marketing name */
774 if (!sndk_nvme_parse_dev_status_log_str(dev_mng_log,
775 SNDK_C2_MARKETING_NAME_ID0x07,
776 (char *)marketing_name,
777 &market_name_len))
778 fprintf(stderrstderr, "ERROR: SNDK: Get Marketing Name Failed\n");
779
780 /* Get the drive form factor */
781 if (!sndk_nvme_parse_dev_status_log_entry(dev_mng_log,
782 SNDK_C2_FORM_FACTOR0x0A,
783 (void *)&drive_form_factor))
784 fprintf(stderrstderr, "ERROR: SNDK: Getting Form Factor Failed\n");
785
786 /* verify the 0xC0 log page is supported */
787 if (run_wdc_nvme_check_supported_log_page(ctx, hdl,
788 SNDK_NVME_GET_SMART_CLOUD_ATTR_LOG_ID0xC0, 0))
789 capabilities |= SNDK_DRIVE_CAP_C0_LOG_PAGE0x0000000000100000;
790
791 /* verify the 0xC3 log page is supported */
792 if (run_wdc_nvme_check_supported_log_page(ctx, hdl,
793 SNDK_LATENCY_MON_LOG_ID0xC3, 0))
794 capabilities |= SNDK_DRIVE_CAP_C3_LOG_PAGE0x0000000020000000;
795
796 /* verify the 0xCB log page is supported */
797 if (run_wdc_nvme_check_supported_log_page(ctx, hdl,
798 SNDK_NVME_GET_FW_ACT_HISTORY_LOG_ID0xCB, 0))
799 capabilities |= SNDK_DRIVE_CAP_FW_ACTIVATE_HISTORY0x0000000000002000;
800
801 /* verify the 0xCA log page is supported */
802 if (run_wdc_nvme_check_supported_log_page(ctx, hdl,
803 SNDK_NVME_GET_DEVICE_INFO_LOG_ID0xCA, 0))
804 capabilities |= SNDK_DRIVE_CAP_CA_LOG_PAGE0x0000000000000008;
805
806 /* verify the 0xD0 log page is supported */
807 if (run_wdc_nvme_check_supported_log_page(ctx, hdl,
808 SNDK_NVME_GET_VU_SMART_LOG_ID0xD0, 0))
809 capabilities |= SNDK_DRIVE_CAP_D0_LOG_PAGE0x0000000000000010;
810
811 if ((cust_id == SNDK_CUSTOMER_ID_0x10040x1004) ||
812 (cust_id == SNDK_CUSTOMER_ID_0x10080x1008) ||
813 (cust_id == SNDK_CUSTOMER_ID_0x10050x1005) ||
814 (cust_id == SNDK_CUSTOMER_ID_0x13040x1304))
815 /* Set capabilities for OCP compliant drives */
816 capabilities |= (SNDK_DRIVE_CAP_FW_ACTIVATE_HISTORY_C20x0000000001000000 |
817 SNDK_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY0x0000000002000000 |
818 SNDK_DRIVE_CAP_VU_FID_CLEAR_PCIE0x0000000000800000);
819 else if ((!strncmp(marketing_name, SNDK_SN861_MARKETING_NAME_1"Ultrastar DC SN861", market_name_len)) ||
820 (!strncmp(marketing_name, SNDK_SN861_MARKETING_NAME_2"ULTRASTAR DC SN861", market_name_len))) {
821 /* Set capabilities for OCP compliant drives */
822 capabilities |= (SNDK_DRIVE_CAP_FW_ACTIVATE_HISTORY_C20x0000000001000000 |
823 SNDK_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY0x0000000002000000 |
824 SNDK_DRIVE_CAP_VU_FID_CLEAR_PCIE0x0000000000800000);
825
826 if ((drive_form_factor == SNDK_C2_FORM_FACTOR_SFF_U20x00000001) ||
827 (drive_form_factor == SNDK_C2_FORM_FACTOR_EDSFF_E3S0x00000009))
828 capabilities |= SNDK_DRIVE_CAP_RESIZE_SN8610x0000080000000000;
829 else
830 capabilities &= ~SNDK_DRIVE_CAP_RESIZE0x0000000000000100;
831 } else {
832 capabilities |= (SNDK_DRIVE_CAP_CLEAR_FW_ACT_HISTORY0x0000000000004000 |
833 SNDK_DRIVE_CAP_CLEAR_PCIE0x0000000000000080);
834
835 /* if the 0xCB log page is supported */
836 if (run_wdc_nvme_check_supported_log_page(ctx, hdl,
837 SNDK_NVME_GET_FW_ACT_HISTORY_LOG_ID0xCB, 0))
838 capabilities |= SNDK_DRIVE_CAP_FW_ACTIVATE_HISTORY0x0000000000002000;
839 }
840 break;
841 default:
842 capabilities = 0;
843 }
844
845out:
846 return capabilities;
847}
848
849int sndk_get_serial_name(struct libnvme_transport_handle *hdl, char *file,
850 size_t len, const char *suffix)
851{
852 int i;
853 int ret;
854 int res_len = 0;
855 char orig[PATH_MAX4096] = {0};
856 struct nvme_id_ctrl ctrl;
857 int ctrl_sn_len = sizeof(ctrl.sn);
858
859 i = sizeof(ctrl.sn) - 1;
860 strncpy(orig, file, PATH_MAX4096 - 1);
861 memset(file, 0, len);
862 memset(&ctrl, 0, sizeof(struct nvme_id_ctrl));
863 ret = nvme_identify_ctrl(hdl, &ctrl);
864 if (ret) {
865 fprintf(stderrstderr, "ERROR: SNDK: nvme_identify_ctrl() failed 0x%x\n", ret);
866 return -1;
867 }
868 /* Remove trailing spaces from the name */
869 while (i && ctrl.sn[i] == ' ') {
870 ctrl.sn[i] = '\0';
871 i--;
872 }
873 if (ctrl.sn[sizeof(ctrl.sn) - 1] == '\0')
874 ctrl_sn_len = strlen(ctrl.sn);
875
876 res_len = snprintf(file, len, "%s%.*s%s", orig, ctrl_sn_len, ctrl.sn, suffix);
877 if (len <= res_len) {
878 fprintf(stderrstderr,
879 "ERROR: SNDK: cannot format SN due to unexpected length\n");
880 return -1;
881 }
882
883 return 0;
884}
885
886void sndk_UtilsGetTime(struct SNDK_UtilsTimeInfo *timeInfo)
887{
888 time_t currTime;
889 struct tm currTimeInfo;
890
891 tzset();
892 time(&currTime);
893 localtime_r(&currTime, &currTimeInfo);
894
895 timeInfo->year = currTimeInfo.tm_year + 1900;
896 timeInfo->month = currTimeInfo.tm_mon + 1;
897 timeInfo->dayOfWeek = currTimeInfo.tm_wday;
898 timeInfo->dayOfMonth = currTimeInfo.tm_mday;
899 timeInfo->hour = currTimeInfo.tm_hour;
900 timeInfo->minute = currTimeInfo.tm_min;
901 timeInfo->second = currTimeInfo.tm_sec;
902 timeInfo->msecs = 0;
903 timeInfo->isDST = currTimeInfo.tm_isdst;
904#ifdef NVME_HAVE_TM_GMTOFF
905 timeInfo->zone = -currTimeInfo.tm_gmtoff / 60;
906#else /* NVME_HAVE_TM_GMTOFF */
907 timeInfo->zone = -1 * (timezone / 60);
908#endif /* NVME_HAVE_TM_GMTOFF */
909}
910
911int sndk_UtilsSnprintf(char *buffer, unsigned int sizeOfBuffer,
912 const char *format, ...)
913{
914 int res = 0;
915 va_list vArgs;
916
917 va_start(vArgs, format)__builtin_va_start(vArgs, format);
918 res = vsnprintf(buffer, sizeOfBuffer, format, vArgs);
919 va_end(vArgs)__builtin_va_end(vArgs);
920
921 return res;
922}
923
924/* Verify the Controller Initiated Option is enabled */
925int sndk_check_ctrl_telemetry_option_disabled(struct libnvme_transport_handle *hdl)
926{
927 int err;
928 __u64 result;
929
930 err = nvme_get_features(hdl, 0,
931 SNDK_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID0xD2,
932 NVME_GET_FEATURES_SEL_CURRENT, 0, 0,
933 NULL((void*)0), 4, &result);
934 if (!err) {
935 if (result) {
936 fprintf(stderrstderr,
937 "%s: Controller-initiated option telemetry disabled\n",
938 __func__);
939 return -EINVAL22;
940 }
941 } else {
942 fprintf(stderrstderr, "ERROR: SNDK: Get telemetry option feature failed.");
943 nvme_show_status(err);
944 return -EPERM1;
945 }
946
947 return 0;
948}