| File: | .build-ci/../plugins/sandisk/sandisk-utils.c |
| Warning: | line 784, column 4 Potential leak of memory pointed to by 'dev_mng_log' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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 */ | |||
| 26 | static 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 */ | |||
| 32 | static 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 */ | |||
| 38 | static 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 | ||||
| 43 | int 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 | ||||
| 115 | int 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 | ||||
| 132 | bool_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 | ||||
| 159 | void 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 | ||||
| 191 | bool_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 | ||||
| 277 | bool_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 | ||||
| 294 | bool_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 | ||||
| 319 | bool_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 | ||||
| 370 | bool_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 | ||||
| 442 | bool_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 | ||||
| 519 | end: | |||
| 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
| |||
| 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
| |||
| 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; | |||
| 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 | ||||
| 845 | out: | |||
| 846 | return capabilities; | |||
| 847 | } | |||
| 848 | ||||
| 849 | int 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 | ||||
| 886 | void 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 | ||||
| 911 | int 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 */ | |||
| 925 | int 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 | } |