diff --git a/Documentation/nvme-sndk-vs-internal-log.txt b/Documentation/nvme-sndk-vs-internal-log.txt index 7a9e2376a6..c37f679449 100644 --- a/Documentation/nvme-sndk-vs-internal-log.txt +++ b/Documentation/nvme-sndk-vs-internal-log.txt @@ -40,12 +40,25 @@ OPTIONS -d :: --data-area=:: Data area to retrieve. For capture with a --type value that includes - telemetry (CONTROLLER or HOST), this specifies the NVMe telemetry data - area to capture, containing data from areas 1 to . For - capture without such a --type value, this specifies the amount of - vendor defined debug data to capture, and this is only supported on the - SN340, SN350, SN530, SN570, SN730, SN740, SN840, SN850X, SN5000, - SN5100S, SN7000S, SN7100, and SN7150 devices. + telemetry (CONTROLLER, HOST, or BOTH), this specifies the NVMe + telemetry data area to capture, containing data from areas 1 to + . For capture without such a --type value, this specifies + the amount of vendor defined debug data to capture, and this is only + supported on the SN340, SN350, SN530, SN570, SN730, SN740, SN840, + SN850X, SN5000, SN5100S, SN7000S, SN7100, and SN7150 devices. + +-t :: +--type=:: + Specifies the telemetry type - NONE, HOST, CONTROLLER, or BOTH. This + parameter is used to get either the host-initiated or controller- + initiated telemetry log page. If BOTH is specified, both host and + controller telemetry are captured and packaged into a tar archive. + If not specified or if is NONE, the command will return vendor + defined debug data. + +-v :: +--verbose=:: + Provides additional debug messages for certain drives. -f :: --file-size=:: @@ -64,17 +77,6 @@ OPTIONS --data-area parameter, and only for capture with --type=NONE or --type not specified. --t :: ---type=:: - Specifies the telemetry type - NONE, HOST, or CONTROLLER. This parameter - is used to get either the host-initiated or controller-initiated - telemetry log page. If not specified or if is NONE, the command - will return vendor defined debug data. - --v :: ---verbose=:: - Provides additional debug messages for certain drives. - EXAMPLES -------- * Gets the internal firmware log from the device and saves to default file in current directory (e.g. STM00019F3F9_internal_fw_log_20171127_095704.bin): @@ -119,6 +121,11 @@ EXAMPLES ------------ # nvme sndk vs-internal-log /dev/nvme1 -t controller -o ctlr-telem-log-da3.bin -d 3 ------------ +* Gets both host and controller telemetry log pages to data area 3 from the device and packages them in a tar file: ++ +------------ +# nvme sndk vs-internal-log /dev/nvme1 -t both -o both-telem-log-da3.tar -d 3 +------------ NVME ---- diff --git a/Documentation/nvme-wdc-vs-internal-log.txt b/Documentation/nvme-wdc-vs-internal-log.txt index c8a1723a31..414a482aa7 100644 --- a/Documentation/nvme-wdc-vs-internal-log.txt +++ b/Documentation/nvme-wdc-vs-internal-log.txt @@ -47,23 +47,6 @@ OPTIONS SN340, SN350, SN530, SN570, SN730, SN740, SN840, SN850X, SN5000, SN5100S, SN7000S, SN7100, and SN7150 devices. --f :: ---file-size=:: - Specifies the desired size of the data file starting at the passed in - offset. This allows the user to retrieve the data in several smaller - files of the passed in size. This parameter is only supported on the - devices mentioned in the documentation of the --data-area parameter, - and only for capture with --type=NONE or --type not specified. - --e :: ---offset=:: - Specifies the data offset at which to start retrieving the data. This - parameter is used in combination with the file size parameter to - retrieve the data in several smaller files. This parameter is only - supported on the devices mentioned in the documentation of the - --data-area parameter, and only for capture with --type=NONE or --type - not specified. - -t :: --type=:: Specifies the telemetry type - NONE, HOST, or CONTROLLER. This parameter @@ -75,6 +58,23 @@ OPTIONS --verbose=:: Provides additional debug messages for certain drives. +-f :: +--file-size=:: + Deprecated. Specifies the desired size of the data file starting at the + passed in offset. This allows the user to retrieve the data in several + smaller files of the passed in size. This parameter is only supported on + the devices mentioned in the documentation of the --data-area parameter, + and only for capture with --type=NONE or --type not specified. + +-e :: +--offset=:: + Deprecated. Specifies the data offset at which to start retrieving the + data. This parameter is used in combination with the file size parameter + to retrieve the data in several smaller files. This parameter is only + supported on the devices mentioned in the documentation of the + --data-area parameter, and only for capture with --type=NONE or --type + not specified. + EXAMPLES -------- * Gets the internal firmware log from the device and saves to default file in current directory (e.g. STM00019F3F9_internal_fw_log_20171127_095704.bin): diff --git a/plugins/sandisk/sandisk-nvme.c b/plugins/sandisk/sandisk-nvme.c index 76dd84d901..ff9b1d2691 100644 --- a/plugins/sandisk/sandisk-nvme.c +++ b/plugins/sandisk/sandisk-nvme.c @@ -91,6 +91,11 @@ static int sndk_do_cap_telemetry_log(struct nvme_global_ctx *ctx, } host_gen = 0; ctrl_init = 1; + } else if (type == SNDK_TELEMETRY_TYPE_BOTH) { + fprintf(stderr, + "%s: BOTH type should be handled by sndk_do_cap_both_telemetry_log\n", + __func__); + return -EINVAL; } else { fprintf(stderr, "%s: Invalid type parameter; type = %d\n", __func__, type); return -EINVAL; @@ -173,6 +178,81 @@ static int sndk_do_cap_telemetry_log(struct nvme_global_ctx *ctx, return err; } +static int sndk_do_cap_both_telemetry_log(struct nvme_global_ctx *ctx, + struct nvme_transport_handle *hdl, + const char *tar_file, __u32 bs, + int data_area) +{ + char host_file[PATH_MAX] = {0}; + char controller_file[PATH_MAX] = {0}; + char tar_cmd[PATH_MAX * 3] = {0}; + char *base_name; + int ret = 0; + + base_name = strdup(tar_file); + if (!base_name) { + fprintf(stderr, "%s: Memory allocation failed\n", __func__); + return -ENOMEM; + } + + /* Remove .tar extension if present */ + char *tar_ext = strstr(base_name, ".tar"); + + if (tar_ext) + *tar_ext = '\0'; + + /* Create temporary files for host and controller telemetry */ + snprintf(host_file, PATH_MAX, "%s_host_telemetry.bin", base_name); + snprintf(controller_file, PATH_MAX, "%s_controller_telemetry.bin", + base_name); + + fprintf(stderr, "%s: Capturing HOST telemetry to %s\n", __func__, + host_file); + ret = sndk_do_cap_telemetry_log(ctx, hdl, host_file, bs, + SNDK_TELEMETRY_TYPE_HOST, data_area); + if (ret) { + fprintf(stderr, "%s: Failed to capture HOST telemetry: %d\n", + __func__, ret); + goto cleanup; + } + + fprintf(stderr, "%s: Capturing CONTROLLER telemetry to %s\n", __func__, + controller_file); + ret = sndk_do_cap_telemetry_log(ctx, hdl, controller_file, bs, + SNDK_TELEMETRY_TYPE_CONTROLLER, + data_area); + if (ret) { + fprintf(stderr, + "%s: Failed to capture CONTROLLER telemetry: %d\n", + __func__, ret); + goto cleanup_host; + } + + /* Create tar file containing both telemetry files */ + fprintf(stderr, "%s: Creating tar file %s\n", __func__, tar_file); + snprintf(tar_cmd, sizeof(tar_cmd), "tar -cf \"%s\" \"%s\" \"%s\"", + tar_file, host_file, controller_file); + + ret = system(tar_cmd); + if (ret) { + fprintf(stderr, "%s: Failed to create tar file: %s\n", + __func__, tar_file); + ret = -1; + } else { + fprintf(stderr, "%s: Successfully created tar file: %s\n", + __func__, tar_file); + ret = 0; + } + + /* Clean up temporary files */ + unlink(controller_file); +cleanup_host: + unlink(host_file); +cleanup: + free(base_name); + return ret; +} + static __u32 sndk_dump_udui_data(struct nvme_transport_handle *hdl, __u32 dataLen, __u32 offset, __u8 *dump_data) { @@ -196,8 +276,7 @@ static __u32 sndk_dump_udui_data(struct nvme_transport_handle *hdl, } static int sndk_do_cap_udui(struct nvme_transport_handle *hdl, char *file, - __u32 xfer_size, int verbose, __u64 file_size, - __u64 offset) + __u32 xfer_size, int verbose) { int ret = 0; int output; @@ -206,6 +285,7 @@ static int sndk_do_cap_udui(struct nvme_transport_handle *hdl, char *file, __u32 udui_log_hdr_size = sizeof(struct nvme_telemetry_log); __u32 chunk_size = xfer_size; __u64 total_size; + __u64 offset = 0; log = (struct nvme_telemetry_log *)malloc(udui_log_hdr_size); if (!log) { @@ -225,14 +305,6 @@ static int sndk_do_cap_udui(struct nvme_transport_handle *hdl, char *file, } total_size = (le32_to_cpu(log->dalb4) + 1) * 512; - if (offset > total_size) { - fprintf(stderr, "%s: ERROR: SNDK: offset larger than log length = 0x%"PRIx64"\n", - __func__, (uint64_t)total_size); - goto out; - } - - if (file_size && (total_size - offset) > file_size) - total_size = offset + file_size; log = (struct nvme_telemetry_log *)realloc(log, chunk_size); @@ -311,16 +383,18 @@ static int sndk_vs_internal_fw_log(int argc, char **argv, const char *size = "Data retrieval transfer size."; const char *data_area = "Data area to retrieve up to. Supported for telemetry, see man page for other use cases."; + const char *type = + "Telemetry type - NONE, HOST, CONTROLLER, or BOTH:\n" \ + " NONE - Default, capture without using NVMe telemetry.\n" \ + " HOST - Host-initiated telemetry.\n" \ + " CONTROLLER - Controller-initiated telemetry.\n" \ + " BOTH - Both HOST and CONTROLLER telemetry packaged in tar file."; + const char *verbose = "Display more debug messages."; const char *file_size = "Output file size. Deprecated, see man page for supported devices."; const char *offset = "Output file data offset. Deprecated, see man page for supported devices."; - const char *type = - "Telemetry type - NONE, HOST, or CONTROLLER:\n" \ - " NONE - Default, capture without using NVMe telemetry.\n" \ - " HOST - Host-initiated telemetry.\n" \ - " CONTROLLER - Controller-initiated telemetry."; - char f[PATH_MAX] = {0}; + char f[PATH_MAX-4] = {0}; char fileSuffix[PATH_MAX] = {0}; __u32 xfer_size = 0; int telemetry_type = 0, telemetry_data_area = 0; @@ -339,6 +413,7 @@ static int sndk_vs_internal_fw_log(int argc, char **argv, __u64 file_size; __u64 offset; char *type; + bool verbose; }; struct config cfg = { @@ -348,15 +423,18 @@ static int sndk_vs_internal_fw_log(int argc, char **argv, .file_size = 0, .offset = 0, .type = NULL, + .verbose = false, }; NVME_ARGS(opts, OPT_FILE("output-file", 'o', &cfg.file, file), OPT_UINT("transfer-size", 's', &cfg.xfer_size, size), OPT_UINT("data-area", 'd', &cfg.data_area, data_area), + OPT_FILE("type", 't', &cfg.type, type), + OPT_FLAG("verbose", 'v', &cfg.verbose, verbose), OPT_LONG("file-size", 'f', &cfg.file_size, file_size), OPT_LONG("offset", 'e', &cfg.offset, offset), - OPT_FILE("type", 't', &cfg.type, type)); + OPT_END()); ret = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); if (ret) @@ -385,7 +463,8 @@ static int sndk_vs_internal_fw_log(int argc, char **argv, goto out; } close(verify_file); - strncpy(f, cfg.file, PATH_MAX - 1); + remove(cfg.file); + strncpy(f, cfg.file, PATH_MAX - 5); } else { sndk_UtilsGetTime(&timeInfo); memset(timeStamp, 0, sizeof(timeStamp)); @@ -423,54 +502,69 @@ static int sndk_vs_internal_fw_log(int argc, char **argv, if (!cfg.type || !strcmp(cfg.type, "NONE") || !strcmp(cfg.type, "none")) { telemetry_type = SNDK_TELEMETRY_TYPE_NONE; - data_area = 0; + telemetry_data_area = 0; } else if (!strcmp(cfg.type, "HOST") || !strcmp(cfg.type, "host")) { telemetry_type = SNDK_TELEMETRY_TYPE_HOST; telemetry_data_area = cfg.data_area; } else if (!strcmp(cfg.type, "CONTROLLER") || !strcmp(cfg.type, "controller")) { telemetry_type = SNDK_TELEMETRY_TYPE_CONTROLLER; telemetry_data_area = cfg.data_area; + } else if (!strcmp(cfg.type, "BOTH") || !strcmp(cfg.type, "both")) { + telemetry_type = SNDK_TELEMETRY_TYPE_BOTH; + telemetry_data_area = cfg.data_area; } else { fprintf(stderr, - "ERROR: SNDK: Invalid type - Must be NONE, HOST or CONTROLLER\n"); + "ERROR: SNDK: Invalid type - Must be NONE, HOST, CONTROLLER, or BOTH\n"); ret = -1; goto out; } capabilities = sndk_get_drive_capabilities(ctx, hdl); - /* Supported through WDC plugin for non-telemetry */ - if ((capabilities & SNDK_DRIVE_CAP_INTERNAL_LOG) && + if ((capabilities & SNDK_DRIVE_CAP_INTERNAL_LOG_MASK) && (telemetry_type != SNDK_TELEMETRY_TYPE_NONE)) { - if (sndk_get_default_telemetry_da(hdl, &telemetry_data_area)) { - fprintf(stderr, "%s: Error determining default telemetry data area\n", - __func__); - return -EINVAL; - } - - ret = sndk_do_cap_telemetry_log(ctx, hdl, f, xfer_size, - telemetry_type, telemetry_data_area); - goto out; - } - - if (capabilities & SNDK_DRIVE_CAP_UDUI) { - if ((telemetry_type == SNDK_TELEMETRY_TYPE_HOST) || - (telemetry_type == SNDK_TELEMETRY_TYPE_CONTROLLER)) { + /* If no data area specified, get the default value */ + if (telemetry_data_area == 0) { if (sndk_get_default_telemetry_da(hdl, &telemetry_data_area)) { fprintf(stderr, "%s: Error determining default telemetry data area\n", - __func__); + __func__); return -EINVAL; } + } + + if (telemetry_type == SNDK_TELEMETRY_TYPE_BOTH) { + /* For BOTH type, ensure filename has .tar extension */ + char tar_file[PATH_MAX] = {0}; + + if (strstr(f, ".tar") == NULL) { + char *bin_ext = strstr(f, ".bin"); + + if (bin_ext) + *bin_ext = '\0'; + snprintf(tar_file, PATH_MAX, "%s.tar", f); + } else { + snprintf(tar_file, PATH_MAX, "%s", f); + } + ret = sndk_do_cap_both_telemetry_log(ctx, hdl, + tar_file, xfer_size, + telemetry_data_area); + } else { ret = sndk_do_cap_telemetry_log(ctx, hdl, f, xfer_size, telemetry_type, telemetry_data_area); - goto out; - } else { - ret = sndk_do_cap_udui(hdl, f, xfer_size, - nvme_args.verbose, cfg.file_size, - cfg.offset); + } + goto out; + } + + if (capabilities & SNDK_DRIVE_CAP_UDUI) { + if (cfg.data_area) { + fprintf(stderr, + "ERROR: SNDK: Data area parameter is not supported when type is NONE\n"); + ret = -1; goto out; } + ret = sndk_do_cap_udui(hdl, f, xfer_size, cfg.verbose); + goto out; } /* Fallback to WDC plugin if otherwise not supported */ diff --git a/plugins/sandisk/sandisk-nvme.h b/plugins/sandisk/sandisk-nvme.h index 0101b7e7bd..2691bc74b6 100644 --- a/plugins/sandisk/sandisk-nvme.h +++ b/plugins/sandisk/sandisk-nvme.h @@ -5,7 +5,7 @@ #if !defined(SANDISK_NVME) || defined(CMD_HEADER_MULTI_READ) #define SANDISK_NVME -#define SANDISK_PLUGIN_VERSION "3.1.0" +#define SANDISK_PLUGIN_VERSION "3.1.1" #include "cmd.h" PLUGIN(NAME("sndk", "Sandisk vendor specific extensions", SANDISK_PLUGIN_VERSION), diff --git a/plugins/sandisk/sandisk-utils.c b/plugins/sandisk/sandisk-utils.c index 4efc687080..d77615572e 100644 --- a/plugins/sandisk/sandisk-utils.c +++ b/plugins/sandisk/sandisk-utils.c @@ -24,6 +24,12 @@ static const __u8 WDC_UUID[NVME_UUID_LEN] = { 0xab, 0xe6, 0x33, 0x29, 0x9a, 0x70, 0xdf, 0xd0 }; +/* WDC_UUID value for SN640_3 devices and SN655 devices */ +static const __u8 WDC_UUID_SN640_3[NVME_UUID_LEN] = { + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 +}; + /* Sandisk UUID value */ static const __u8 SNDK_UUID[NVME_UUID_LEN] = { 0xde, 0x87, 0xd1, 0xeb, 0x72, 0xc5, 0x58, 0x0b, @@ -334,6 +340,9 @@ bool sndk_get_dev_mgment_data(struct nvme_global_ctx *ctx, struct nvme_transport * check for the WDC UUID second. */ uuid_index = nvme_uuid_find(&uuid_list, WDC_UUID); + if (uuid_index < 0) + /* Check for the UUID used on SN640 and SN655 drives */ + uuid_index = nvme_uuid_find(&uuid_list, WDC_UUID_SN640_3); } if (uuid_index >= 0) @@ -543,6 +552,7 @@ __u64 sndk_get_drive_capabilities(struct nvme_global_ctx *ctx, SNDK_DRIVE_CAP_OCP_C5_LOG_PAGE | SNDK_DRIVE_CAP_UDUI | SNDK_DRIVE_CAP_VU_FID_CLEAR_PCIE | + SNDK_DRIVE_CAP_CLEAR_ASSERT | SNDK_DRIVE_CAP_CLOUD_SSD_VERSION | SNDK_DRIVE_CAP_LOG_PAGE_DIR | SNDK_DRIVE_CAP_DRIVE_STATUS | @@ -604,6 +614,7 @@ __u64 sndk_get_drive_capabilities(struct nvme_global_ctx *ctx, SNDK_DRIVE_CAP_OCP_C5_LOG_PAGE | SNDK_DRIVE_CAP_UDUI | SNDK_DRIVE_CAP_VU_FID_CLEAR_PCIE | + SNDK_DRIVE_CAP_CLEAR_ASSERT | SNDK_DRIVE_CAP_CLOUD_SSD_VERSION | SNDK_DRIVE_CAP_LOG_PAGE_DIR | SNDK_DRIVE_CAP_DRIVE_STATUS | @@ -671,11 +682,15 @@ __u64 sndk_get_enc_drive_capabilities(struct nvme_global_ctx *ctx, /* check for the Sandisk UUID first */ uuid_index = nvme_uuid_find(&uuid_list, SNDK_UUID); - if (uuid_index < 0) + if (uuid_index < 0) { /* The Sandisk UUID is not found; * check for the WDC UUID second. */ uuid_index = nvme_uuid_find(&uuid_list, WDC_UUID); + if (uuid_index < 0) + /* Check for the UUID used on SN640 and SN655 drives */ + uuid_index = nvme_uuid_find(&uuid_list, WDC_UUID_SN640_3); + } } else { /* UUID Lists not supported, Use default uuid index - 0 */ fprintf(stderr, "INFO: SNDK: %s: UUID Lists not supported\n", @@ -718,6 +733,11 @@ __u64 sndk_get_enc_drive_capabilities(struct nvme_global_ctx *ctx, (void *)&drive_form_factor)) fprintf(stderr, "ERROR: SNDK: Getting Form Factor Failed\n"); + /* verify the 0xC0 log page is supported */ + if (run_wdc_nvme_check_supported_log_page(ctx, hdl, + SNDK_NVME_GET_SMART_CLOUD_ATTR_LOG_ID, 0)) + capabilities |= SNDK_DRIVE_CAP_C0_LOG_PAGE; + /* verify the 0xC3 log page is supported */ if (run_wdc_nvme_check_supported_log_page(ctx, hdl, SNDK_LATENCY_MON_LOG_ID, 0)) @@ -753,11 +773,6 @@ __u64 sndk_get_enc_drive_capabilities(struct nvme_global_ctx *ctx, SNDK_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY | SNDK_DRIVE_CAP_VU_FID_CLEAR_PCIE); - /* verify the 0xC0 log page is supported */ - if (run_wdc_nvme_check_supported_log_page(ctx, hdl, - SNDK_LATENCY_MON_LOG_ID, 0)) - capabilities |= SNDK_DRIVE_CAP_C0_LOG_PAGE; - if ((drive_form_factor == SNDK_C2_FORM_FACTOR_SFF_U2) || (drive_form_factor == SNDK_C2_FORM_FACTOR_EDSFF_E3S)) capabilities |= SNDK_DRIVE_CAP_RESIZE_SN861; diff --git a/plugins/sandisk/sandisk-utils.h b/plugins/sandisk/sandisk-utils.h index ca70d45955..9a23bd3408 100644 --- a/plugins/sandisk/sandisk-utils.h +++ b/plugins/sandisk/sandisk-utils.h @@ -232,7 +232,7 @@ #define SNDK_TELEMETRY_TYPE_NONE 0x0 #define SNDK_TELEMETRY_TYPE_HOST 0x1 #define SNDK_TELEMETRY_TYPE_CONTROLLER 0x2 - +#define SNDK_TELEMETRY_TYPE_BOTH 0x3 /* Misc */ #define SNDK_MAX_PATH_LEN 256 #define SNDK_GUID_LENGTH 16 diff --git a/plugins/wdc/wdc-nvme.c b/plugins/wdc/wdc-nvme.c index bbccb470f0..0c3f85784f 100644 --- a/plugins/wdc/wdc-nvme.c +++ b/plugins/wdc/wdc-nvme.c @@ -1962,6 +1962,7 @@ static __u64 wdc_get_drive_capabilities(struct nvme_global_ctx *ctx, struct nvme WDC_DRIVE_CAP_OCP_C5_LOG_PAGE | WDC_DRIVE_CAP_UDUI | WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE | + WDC_DRIVE_CAP_CLEAR_ASSERT | WDC_DRIVE_CAP_CLOUD_SSD_VERSION | WDC_DRIVE_CAP_LOG_PAGE_DIR | WDC_DRIVE_CAP_DRIVE_STATUS | @@ -3396,6 +3397,13 @@ static int wdc_do_cap_diag(struct nvme_global_ctx *ctx, struct nvme_transport_ha memset(log_hdr, 0, e6_log_hdr_size); if (type == WDC_TELEMETRY_TYPE_NONE) { + if (data_area) { + fprintf(stderr, + "%s: ERROR: Data area parameter is not supported when type is NONE\n", + __func__); + ret = -1; + goto out; + } ret = wdc_dump_length_e6(hdl, WDC_NVME_CAP_DIAG_OPCODE, WDC_NVME_CAP_DIAG_HEADER_TOC_SIZE>>2, @@ -4295,15 +4303,16 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *acmd, const char *size = "Data retrieval transfer size."; const char *data_area = "Data area to retrieve up to. Supported for telemetry, see man page for other use cases."; - const char *file_size = - "Output file size. See man page for supported devices."; - const char *offset = - "Output file data offset. See man page for supported devices."; const char *type = "Telemetry type - NONE, HOST, or CONTROLLER:\n" \ " NONE - Default, capture without using NVMe telemetry.\n" \ " HOST - Host-initiated telemetry.\n" \ " CONTROLLER - Controller-initiated telemetry."; + const char *verbose = "Display more debug messages."; + const char *file_size = + "Output file size. Deprecated, see man page for supported devices."; + const char *offset = + "Output file data offset. Deprecated, see man page for supported devices."; char f[PATH_MAX] = {0}; char fb[PATH_MAX/2] = {0}; char fileSuffix[PATH_MAX] = {0}; @@ -4326,6 +4335,7 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *acmd, __u64 file_size; __u64 offset; char *type; + bool verbose; }; struct config cfg = { @@ -4335,15 +4345,18 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *acmd, .file_size = 0, .offset = 0, .type = NULL, + .verbose = false, }; NVME_ARGS(opts, OPT_FILE("output-file", 'o', &cfg.file, file), OPT_UINT("transfer-size", 's', &cfg.xfer_size, size), OPT_UINT("data-area", 'd', &cfg.data_area, data_area), + OPT_FILE("type", 't', &cfg.type, type), + OPT_FLAG("verbose", 'v', &cfg.verbose, verbose), OPT_LONG("file-size", 'f', &cfg.file_size, file_size), OPT_LONG("offset", 'e', &cfg.offset, offset), - OPT_FILE("type", 't', &cfg.type, type)); + OPT_END()); ret = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); if (ret) @@ -4468,7 +4481,8 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *acmd, capabilities = wdc_get_drive_capabilities(ctx, hdl); if ((capabilities & WDC_DRIVE_CAP_INTERNAL_LOG) == WDC_DRIVE_CAP_INTERNAL_LOG) { if (!wdc_is_sn861(device_id)) { - if (wdc_get_default_telemetry_da(hdl, &telemetry_data_area)) { + if (telemetry_type != WDC_TELEMETRY_TYPE_NONE && + wdc_get_default_telemetry_da(hdl, &telemetry_data_area)) { fprintf(stderr, "%s: Error determining default telemetry data area\n", __func__); return -EINVAL;