From 749efe961f0e1a71461a9c79e6e4584d35af6e7f Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 19 Feb 2024 11:45:34 +0100 Subject: Adding upstream version 2.8. Signed-off-by: Daniel Baumann --- plugins/meson.build | 3 + plugins/sed/meson.build | 4 + plugins/sed/sed.c | 178 +++++++++++ plugins/sed/sed.h | 19 ++ plugins/sed/sedopal_cmd.c | 512 ++++++++++++++++++++++++++++++ plugins/sed/sedopal_cmd.h | 55 ++++ plugins/sed/sedopal_spec.h | 71 +++++ plugins/solidigm/solidigm-internal-logs.c | 116 +++++-- plugins/solidigm/solidigm-nvme.h | 2 +- plugins/wdc/wdc-nvme.c | 147 +++++++-- plugins/wdc/wdc-nvme.h | 2 +- plugins/wdc/wdc-utils.c | 12 +- 12 files changed, 1048 insertions(+), 73 deletions(-) create mode 100644 plugins/sed/meson.build create mode 100644 plugins/sed/sed.c create mode 100644 plugins/sed/sed.h create mode 100644 plugins/sed/sedopal_cmd.c create mode 100644 plugins/sed/sedopal_cmd.h create mode 100644 plugins/sed/sedopal_spec.h (limited to 'plugins') diff --git a/plugins/meson.build b/plugins/meson.build index 38b7cde..bb4c9ad 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -29,4 +29,7 @@ if json_c_dep.found() ] subdir('solidigm') subdir('ocp') + if conf.has('HAVE_SED_OPAL') + subdir('sed') + endif endif diff --git a/plugins/sed/meson.build b/plugins/sed/meson.build new file mode 100644 index 0000000..4a2e544 --- /dev/null +++ b/plugins/sed/meson.build @@ -0,0 +1,4 @@ +sources += [ + 'plugins/sed/sed.c', + 'plugins/sed/sedopal_cmd.c', +] diff --git a/plugins/sed/sed.c b/plugins/sed/sed.c new file mode 100644 index 0000000..0471e54 --- /dev/null +++ b/plugins/sed/sed.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "nvme.h" +#include "libnvme.h" +#include "nvme-print.h" +#include "sedopal_cmd.h" +#include + +#define CREATE_CMD +#include "sed.h" + +OPT_ARGS(no_opts) = { + OPT_END() +}; + +OPT_ARGS(key_opts) = { + OPT_FLAG("ask-key", 'k', &sedopal_ask_key, + "prompt for SED authentication key"), + OPT_END() +}; + +OPT_ARGS(revert_opts) = { + OPT_FLAG("destructive", 'e', &sedopal_destructive_revert, + "destructive revert"), + OPT_FLAG("psid", 'p', &sedopal_psid_revert, "PSID revert"), + OPT_END() +}; + + +/* + * Open the NVMe device specified on the command line. It must be the + * NVMe block device (e.g. /dev/nvme0n1). + */ +static int sed_opal_open_device(struct nvme_dev **dev, int argc, char **argv, + const char *desc, struct argconfig_commandline_options *opts) +{ + int err; + + err = parse_and_open(dev, argc, argv, desc, opts); + if (err) + return err; + + if (!S_ISBLK((*dev)->direct.stat.st_mode)) { + fprintf(stderr, + "ERROR : The NVMe block device must be specified\n"); + err = -EINVAL; + dev_close(*dev); + } + + return err; +} + +static int sed_opal_discover(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + int err; + const char *desc = "Query SED device and display locking features"; + struct nvme_dev *dev; + + err = sed_opal_open_device(&dev, argc, argv, desc, no_opts); + if (err) + return err; + + err = sedopal_cmd_discover(dev->direct.fd); + + dev_close(dev); + return err; +} + +static int sed_opal_initialize(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + int err; + const char *desc = "Initialize a SED device for locking"; + struct nvme_dev *dev; + + err = sed_opal_open_device(&dev, argc, argv, desc, no_opts); + if (err) + return err; + + err = sedopal_cmd_initialize(dev->direct.fd); + if (err != 0) + fprintf(stderr, "initialize: SED error - %s\n", + sedopal_error_to_text(err)); + + dev_close(dev); + return err; +} + +static int sed_opal_revert(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + int err; + const char *desc = "Revert a SED device from locking state"; + struct nvme_dev *dev; + + err = sed_opal_open_device(&dev, argc, argv, desc, revert_opts); + if (err) + return err; + + err = sedopal_cmd_revert(dev->direct.fd); + if (err != 0) + fprintf(stderr, "revert: SED error - %s\n", + sedopal_error_to_text(err)); + + dev_close(dev); + return err; +} + +static int sed_opal_lock(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + int err; + const char *desc = "Lock a SED device"; + struct nvme_dev *dev; + + err = sed_opal_open_device(&dev, argc, argv, desc, key_opts); + if (err) + return err; + + err = sedopal_cmd_lock(dev->direct.fd); + if (err != 0) + fprintf(stderr, "lock: SED error - %s\n", + sedopal_error_to_text(err)); + + dev_close(dev); + return err; +} + +static int sed_opal_unlock(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + int err; + const char *desc = "Unlock a SED device"; + struct nvme_dev *dev; + + err = sed_opal_open_device(&dev, argc, argv, desc, key_opts); + if (err) + return err; + + err = sedopal_cmd_unlock(dev->direct.fd); + if (err != 0) + fprintf(stderr, "unlock: SED error - %s\n", + sedopal_error_to_text(err)); + + dev_close(dev); + return err; +} + +static int sed_opal_password(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + int err; + const char *desc = "Change the locking password of a SED device"; + struct nvme_dev *dev; + + err = sed_opal_open_device(&dev, argc, argv, desc, no_opts); + if (err) + return err; + + err = sedopal_cmd_password(dev->direct.fd); + if (err != 0) + fprintf(stderr, "password: SED error - %s\n", + sedopal_error_to_text(err)); + + dev_close(dev); + return err; +} diff --git a/plugins/sed/sed.h b/plugins/sed/sed.h new file mode 100644 index 0000000..1618272 --- /dev/null +++ b/plugins/sed/sed.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#undef CMD_INC_FILE +#define CMD_INC_FILE plugins/sed/sed + +#include "cmd.h" +#include + +PLUGIN(NAME("sed", "SED Opal Command Set", NVME_VERSION), + COMMAND_LIST( + ENTRY("discover", "Discover SED Opal Locking Features", sed_opal_discover, "1") + ENTRY("initialize", "Initialize a SED Opal Device for locking", sed_opal_initialize) + ENTRY("revert", "Revert a SED Opal Device from locking", sed_opal_revert) + ENTRY("lock", "Lock a SED Opal Device", sed_opal_lock) + ENTRY("unlock", "Unlock a SED Opal Device", sed_opal_unlock) + ENTRY("password", "Change the SED Opal Device password", sed_opal_password) + ) +); + +#include "define_cmd.h" diff --git a/plugins/sed/sedopal_cmd.c b/plugins/sed/sedopal_cmd.c new file mode 100644 index 0000000..649e0b2 --- /dev/null +++ b/plugins/sed/sedopal_cmd.c @@ -0,0 +1,512 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sedopal_spec.h" +#include "sedopal_cmd.h" + +/* + * ask user for key rather than obtaining it from kernel keyring + */ +bool sedopal_ask_key; + +/* + * initiate dialog to ask for and confirm new password + */ +bool sedopal_ask_new_key; + +/* + * perform a destructive drive revert + */ +bool sedopal_destructive_revert; + +/* + * perform a PSID drive revert + */ +bool sedopal_psid_revert; + +/* + * Map method status codes to error text + */ +static const char * const sedopal_errors[] = { + [SED_STATUS_SUCCESS] = "Success", + [SED_STATUS_NOT_AUTHORIZED] = "Host Not Authorized", + [SED_STATUS_OBSOLETE_1] = "Obsolete", + [SED_STATUS_SP_BUSY] = "SP Session Busy", + [SED_STATUS_SP_FAILED] = "SP Failed", + [SED_STATUS_SP_DISABLED] = "SP Disabled", + [SED_STATUS_SP_FROZEN] = "SP Frozen", + [SED_STATUS_NO_SESSIONS_AVAILABLE] = "No Sessions Available", + [SED_STATUS_UNIQUENESS_CONFLICT] = "Uniqueness Conflict", + [SED_STATUS_INSUFFICIENT_SPACE] = "Insufficient Space", + [SED_STATUS_INSUFFICIENT_ROWS] = "Insufficient Rows", + [SED_STATUS_OBSOLETE_2] = "Obsolete", + [SED_STATUS_INVALID_PARAMETER] = "Invalid Parameter", + [SED_STATUS_OBSOLETE_3] = "Obsolete", + [SED_STATUS_OBSOLETE_4] = "Obsolete", + [SED_STATUS_TPER_MALFUNCTION] = "TPER Malfunction", + [SED_STATUS_TRANSACTION_FAILURE] = "Transaction Failure", + [SED_STATUS_RESPONSE_OVERFLOW] = "Response Overflow", + [SED_STATUS_AUTHORITY_LOCKED_OUT] = "Authority Locked Out", +}; + +const char *sedopal_error_to_text(int code) +{ + if (code == SED_STATUS_FAIL) + return "Failed"; + + if (code == SED_STATUS_NO_METHOD_STATUS) + return "Method returned no status"; + + if (code < SED_STATUS_SUCCESS || + code > SED_STATUS_AUTHORITY_LOCKED_OUT) + return("Unknown Error"); + + return sedopal_errors[code]; +} + +/* + * Read a user entered password and do some basic validity checks. + */ +char *sedopal_get_password(char *prompt) +{ + char *pass; + int len; + + pass = getpass(prompt); + if (pass == NULL) + return NULL; + + len = strlen(pass); + if (len < SEDOPAL_MIN_PASSWORD_LEN) + return NULL; + + if (len > SEDOPAL_MAX_PASSWORD_LEN) + return NULL; + + return pass; +} + +/* + * Initialize a SED Opal key. The key can either specify that the actual + * key should be looked up in the kernel keyring, or it should be + * populated in the key by prompting the user. + */ +int sedopal_set_key(struct opal_key *key) +{ +#if !HAVE_KEY_TYPE + /* + * If key_type isn't avaialable, force key prompt + */ + sedopal_ask_key = true; +#endif + + if (sedopal_ask_key) { + char *pass; + char *prompt; + + /* + * set proper prompt + */ + if (sedopal_ask_new_key) + prompt = SEDOPAL_NEW_PW_PROMPT; + else { + if (sedopal_psid_revert) + prompt = SEDOPAL_PSID_PROMPT; + else + prompt = SEDOPAL_CURRENT_PW_PROMPT; + } + + pass = sedopal_get_password(prompt); + if (pass == NULL) + return -EINVAL; + +#if HAVE_KEY_TYPE + key->key_type = OPAL_INCLUDED; +#endif + key->key_len = strlen(pass); + memcpy(key->key, pass, key->key_len); + + /* + * If getting a new key, ask for it to be re-entered + * and verify the two entries are the same. + */ + if (sedopal_ask_new_key) { + pass = sedopal_get_password(SEDOPAL_REENTER_PW_PROMPT); + if (strncmp((char *)key->key, pass, key->key_len)) { + fprintf(stderr, + "Error: passwords don't match\n"); + return -EINVAL; + } + } + } else { +#if HAVE_KEY_TYPE + key->key_type = OPAL_KEYRING; +#endif + key->key_len = 0; + } + + key->lr = 0; + + return 0; +} + +/* + * Prepare a drive for SED Opal locking. + */ +int sedopal_cmd_initialize(int fd) +{ + int rc; + struct opal_key key; + struct opal_lr_act lr_act = {}; + struct opal_user_lr_setup lr_setup = {}; + + sedopal_ask_key = true; + rc = sedopal_set_key(&key); + if (rc != 0) + return rc; + + /* + * take ownership of the device + */ + rc = ioctl(fd, IOC_OPAL_TAKE_OWNERSHIP, &key); + if (rc != 0) { + fprintf(stderr, + "Error: failed to take device ownership - %d\n", rc); + return rc; + } + + /* + * activate lsp + */ + lr_act.num_lrs = 1; + lr_act.sum = false; + lr_act.key = key; + + rc = ioctl(fd, IOC_OPAL_ACTIVATE_LSP, &lr_act); + if (rc != 0) { + fprintf(stderr, "Error: failed to activate LSP - %d\n", rc); + return rc; + } + + /* + * setup global locking range + */ + lr_setup.range_start = 0; + lr_setup.range_length = 0; + lr_setup.RLE = true; + lr_setup.WLE = true; + + lr_setup.session.opal_key = key; + lr_setup.session.sum = 0; + lr_setup.session.who = OPAL_ADMIN1; + + rc = ioctl(fd, IOC_OPAL_LR_SETUP, &lr_setup); + if (rc != 0) { + fprintf(stderr, + "Error: failed to setup locking range - %d\n", rc); + return rc; + } + + return rc; +} + +/* + * Lock a SED Opal drive + */ +int sedopal_cmd_lock(int fd) +{ + + return sedopal_lock_unlock(fd, OPAL_LK); +} + +/* + * Unlock a SED Opal drive + */ +int sedopal_cmd_unlock(int fd) +{ + + return sedopal_lock_unlock(fd, OPAL_RW); +} + +/* + * Prepare and issue an ioctl to lock/unlock a drive + */ +int sedopal_lock_unlock(int fd, int lock_state) +{ + int rc; + struct opal_lock_unlock opal_lu = {}; + + rc = sedopal_set_key(&opal_lu.session.opal_key); + if (rc != 0) + return rc; + + opal_lu.session.sum = 0; + opal_lu.session.who = OPAL_ADMIN1; + opal_lu.l_state = lock_state; + + rc = ioctl(fd, IOC_OPAL_LOCK_UNLOCK, &opal_lu); + if (rc != 0) + fprintf(stderr, + "Error: failed locking or unlocking - %d\n", rc); + + /* + * If the unlock was successful, force a re-read of the + * partition table. + */ + if (rc == 0) { + rc = ioctl(fd, BLKRRPART, 0); + if (rc != 0) + fprintf(stderr, + "Error: failed re-reading partition\n"); + } + + return rc; +} + +/* + * Confirm a destructive drive so that data is inadvertently erased + */ +static bool sedopal_confirm_revert(void) +{ + int rc; + char ans; + bool confirmed = false; + + /* + * verify that destructive revert is really the intention + */ + fprintf(stdout, + "Destructive revert erases drive data. Continue (y/n)? "); + rc = fscanf(stdin, " %c", &ans); + if ((rc == 1) && (ans == 'y' || ans == 'Y')) { + fprintf(stdout, "Are you sure (y/n)? "); + rc = fscanf(stdin, " %c", &ans); + if ((rc == 1) && (ans == 'y' || ans == 'Y')) + confirmed = true; + } + + return confirmed; +} + +/* + * perform a destructive drive revert + */ +static int sedopal_revert_destructive(int fd) +{ + struct opal_key key; + int rc; + + if (!sedopal_confirm_revert()) { + fprintf(stderr, "Aborting destructive revert\n"); + return -1; + } + + /* + * for destructive revert, require that key is provided + */ + sedopal_ask_key = true; + + rc = sedopal_set_key(&key); + if (rc == 0) + rc = ioctl(fd, IOC_OPAL_REVERT_TPR, &key); + + return rc; +} + +/* + * perform a PSID drive revert + */ +static int sedopal_revert_psid(int fd) +{ +#ifdef IOC_OPAL_PSID_REVERT_TPR + struct opal_key key; + int rc; + + if (!sedopal_confirm_revert()) { + fprintf(stderr, "Aborting PSID revert\n"); + return -1; + } + + rc = sedopal_set_key(&key); + if (rc == 0) { + rc = ioctl(fd, IOC_OPAL_PSID_REVERT_TPR, &key); + if (rc != 0) + fprintf(stderr, "PSID_REVERT_TPR rc %d\n", rc); + } + + return rc; +#else + fprintf(stderr, "ERROR : PSID revert is not supported\n"); + return -EOPNOTSUPP; +#endif /* IOC_OPAL_PSID_REVERT_TPR */ +} + +/* + * revert a drive from the provisioned state to a state where locking + * is disabled. + */ +int sedopal_cmd_revert(int fd) +{ + int rc; + + /* + * for revert, require that key/PSID is provided + */ + sedopal_ask_key = true; + + if (sedopal_psid_revert) { + rc = sedopal_revert_psid(fd); + } else if (sedopal_destructive_revert) { + rc = sedopal_revert_destructive(fd); + } else { +#ifdef IOC_OPAL_REVERT_LSP + struct opal_revert_lsp revert_lsp; + + rc = sedopal_set_key(&revert_lsp.key); + if (rc != 0) + return rc; + + revert_lsp.options = OPAL_PRESERVE; + revert_lsp.__pad = 0; + + rc = ioctl(fd, IOC_OPAL_REVERT_LSP, &revert_lsp); +#else + rc = -EOPNOTSUPP; +#endif + } + + if (rc != 0) + fprintf(stderr, "Error: failed reverting drive - %d\n", rc); + + return rc; +} + +/* + * Change the password of a drive. The existing password must be + * provided and the new password is confirmed by re-entry. + */ +int sedopal_cmd_password(int fd) +{ + int rc; + struct opal_new_pw new_pw = {}; + + new_pw.new_user_pw.who = OPAL_ADMIN1; + new_pw.new_user_pw.opal_key.lr = 0; + new_pw.session.who = OPAL_ADMIN1; + new_pw.session.sum = 0; + new_pw.session.opal_key.lr = 0; + + /* + * get current key + */ + sedopal_ask_key = true; + if (sedopal_set_key(&new_pw.session.opal_key) != 0) + return -EINVAL; + + /* + * get new key + */ + sedopal_ask_new_key = true; + if (sedopal_set_key(&new_pw.new_user_pw.opal_key) != 0) + return -EINVAL; + + rc = ioctl(fd, IOC_OPAL_SET_PW, &new_pw); + if (rc != 0) + fprintf(stderr, "Error: failed setting password - %d\n", rc); + + return rc; +} + +/* + * Print the state of locking features. + */ +void sedopal_print_locking_features(uint8_t features) +{ + printf("Locking Features:\n"); + printf("\tLocking Supported: %s\n", + (features & OPAL_FEATURE_LOCKING_SUPPORTED) ? "Yes" : "No"); + printf("\tLocking Feature Enabled: %s\n", + (features & OPAL_FEATURE_LOCKING_ENABLED) ? "Yes" : "No"); + printf("\tLocked: %s\n", + (features & OPAL_FEATURE_LOCKED) ? "Yes" : "No"); +} + +/* + * Query a drive to determine if it's SED Opal capable and + * it's current locking status. + */ +int sedopal_cmd_discover(int fd) +{ +#ifdef IOC_OPAL_DISCOVERY + int rc; + bool sedopal_locking_supported = false; + struct opal_discovery discover; + struct level_0_discovery_header *dh; + struct level_0_discovery_features *feat; + struct level_0_discovery_features *feat_end; + uint16_t code; + uint8_t locking_flags; + char buf[4096]; + + discover.data = (__u64)buf; + discover.size = sizeof(buf); + + rc = ioctl(fd, IOC_OPAL_DISCOVERY, &discover); + if (rc < 0) { + fprintf(stderr, "Error: ioctl IOC_OPAL_DISCOVERY failed\n"); + return rc; + } + + /* + * The returned buffer contains a level 0 discovery header + * folowed by an array of level 0 feature records. + * + * TCG Opal Specification v2.0.2 section 3.1.1 + */ + dh = (struct level_0_discovery_header *)buf; + feat = (struct level_0_discovery_features *)(dh + 1); + feat_end = (struct level_0_discovery_features *) + (buf + be32toh(dh->parameter_length)); + + /* + * iterate through all the features that were returned + */ + while (feat < feat_end) { + code = be16toh(feat->code); + switch (code) { + case OPAL_FEATURE_CODE_LOCKING: + locking_flags = feat->feature; + break; + case OPAL_FEATURE_CODE_OPALV2: + sedopal_locking_supported = true; + break; + default: + break; + } + + feat++; + } + + rc = 0; + if (!sedopal_locking_supported) { + fprintf(stderr, "Error: device does not support SED Opal\n"); + rc = -1; + } else + sedopal_print_locking_features(locking_flags); + + return rc; +#else /* IOC_OPAL_DISCOVERY */ + fprintf(stderr, "ERROR : NVMe device discovery is not supported\n"); + return -EOPNOTSUPP; +#endif +} diff --git a/plugins/sed/sedopal_cmd.h b/plugins/sed/sedopal_cmd.h new file mode 100644 index 0000000..3b6eae2 --- /dev/null +++ b/plugins/sed/sedopal_cmd.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef _SED_OPAL_CMD_H +#define _SED_OPAL_CMD_H + +#define SEDOPAL_CURRENT_PW_PROMPT "Password: " +#define SEDOPAL_NEW_PW_PROMPT "New Password: " +#define SEDOPAL_REENTER_PW_PROMPT "Re-enter New Password: " +#define SEDOPAL_PSID_PROMPT "PSID: " + +#define SEDOPAL_MIN_PASSWORD_LEN 8 +#define SEDOPAL_MAX_PASSWORD_LEN 32 + +#define NVME_DEV_PATH "/dev/nvme" + +extern bool sedopal_ask_key; +extern bool sedopal_ask_new_key; +extern bool sedopal_destructive_revert; +extern bool sedopal_psid_revert; + +/* + * Sub-commands supported by the sedopal command + */ +enum sedopal_cmds { + SEDOPAL_CMD_NOT_SPECIFIED = -1, + SEDOPAL_CMD_INITIALIZE = 0, + SEDOPAL_CMD_LOCK = 1, + SEDOPAL_CMD_UNLOCK = 2, + SEDOPAL_CMD_REVERT = 3, + SEDOPAL_CMD_PASSWORD = 4, + SEDOPAL_CMD_DISCOVER = 5, +}; + +struct cmd_table { + int (*cmd_handler)(int fd); +}; + +/* + * command handlers + */ +int sedopal_cmd_initialize(int fd); +int sedopal_cmd_lock(int fd); +int sedopal_cmd_unlock(int fd); +int sedopal_cmd_revert(int fd); +int sedopal_cmd_password(int fd); +int sedopal_cmd_discover(int fd); + +/* + * utility functions + */ +int sedopal_open_nvme_device(char *device); +int sedopal_lock_unlock(int fd, int lock_state); +const char *sedopal_error_to_text(int code); + +#endif /* _SED_OPAL_CMD_H */ diff --git a/plugins/sed/sedopal_spec.h b/plugins/sed/sedopal_spec.h new file mode 100644 index 0000000..7523060 --- /dev/null +++ b/plugins/sed/sedopal_spec.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef _SED_OPAL_SPEC_H +#define _SED_OPAL_SPEC_H + +/* + * TCP Storage Architecture Core Specification Version 2.01 + * section 5.1.5 Method Status Codes + */ +enum sed_status_codes { + SED_STATUS_SUCCESS = 0x00, + SED_STATUS_NOT_AUTHORIZED = 0x01, + SED_STATUS_OBSOLETE_1 = 0x02, + SED_STATUS_SP_BUSY = 0x03, + SED_STATUS_SP_FAILED = 0x04, + SED_STATUS_SP_DISABLED = 0x05, + SED_STATUS_SP_FROZEN = 0x06, + SED_STATUS_NO_SESSIONS_AVAILABLE = 0x07, + SED_STATUS_UNIQUENESS_CONFLICT = 0x08, + SED_STATUS_INSUFFICIENT_SPACE = 0x09, + SED_STATUS_INSUFFICIENT_ROWS = 0x0A, + SED_STATUS_OBSOLETE_2 = 0x0B, + SED_STATUS_INVALID_PARAMETER = 0x0C, + SED_STATUS_OBSOLETE_3 = 0x0D, + SED_STATUS_OBSOLETE_4 = 0x0E, + SED_STATUS_TPER_MALFUNCTION = 0x0F, + SED_STATUS_TRANSACTION_FAILURE = 0x10, + SED_STATUS_RESPONSE_OVERFLOW = 0x11, + SED_STATUS_AUTHORITY_LOCKED_OUT = 0x12, + SED_STATUS_FAIL = 0x3F, + SED_STATUS_NO_METHOD_STATUS = 0x89, +}; + +/* + * Definitions from TCG Opal Specification v2.0.2 + */ + +/* + * level 0 feature codes - section 3.1.1 + */ +#define OPAL_FEATURE_CODE_LOCKING 0x0002 +#define OPAL_FEATURE_CODE_OPALV2 0x0203 + +/* locking features */ +#define OPAL_FEATURE_LOCKING_SUPPORTED 0x01 +#define OPAL_FEATURE_LOCKING_ENABLED 0x02 +#define OPAL_FEATURE_LOCKED 0x04 + + +/* + * discovery header as specified in section 3.1.1.1 + */ +struct level_0_discovery_header { + uint32_t parameter_length; + uint32_t revision; + uint64_t reserved; + uint8_t vendor_specific[32]; +}; + +/* + * level 0 features as specified in section 3.1.1.3 + */ +struct level_0_discovery_features { + uint16_t code; + uint8_t version; + uint8_t length; + uint8_t feature; + uint8_t reserved[11]; +}; + +#endif /* _SED_OPAL_SPEC_H */ diff --git a/plugins/solidigm/solidigm-internal-logs.c b/plugins/solidigm/solidigm-internal-logs.c index 236652a..c604761 100644 --- a/plugins/solidigm/solidigm-internal-logs.c +++ b/plugins/solidigm/solidigm-internal-logs.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "common.h" #include "nvme.h" @@ -122,7 +123,7 @@ struct nlog_dump_header4_1 { struct config { __u32 namespace_id; - char *file_prefix; + char *dir_prefix; char *type; bool verbose; }; @@ -222,6 +223,7 @@ static int dump_assert_logs(struct nvme_dev *dev, struct config cfg) __u8 buf[INTERNAL_LOG_MAX_BYTE_TRANSFER]; __u8 head_buf[INTERNAL_LOG_MAX_BYTE_TRANSFER]; char file_path[PATH_MAX]; + char file_name[] = "AssertLog.bin"; struct assert_dump_header *ad = (struct assert_dump_header *) head_buf; struct nvme_passthru_cmd cmd = { .opcode = 0xd2, @@ -236,7 +238,8 @@ static int dump_assert_logs(struct nvme_dev *dev, struct config cfg) if (err) return err; - sprintf(file_path, "%s_AssertLog.bin", cfg.file_prefix); + snprintf(file_path, sizeof(file_path), "%.*s/%s", + (int) (sizeof(file_path) - sizeof(file_name) - 1), cfg.dir_prefix, file_name); output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (output < 0) return -errno; @@ -291,7 +294,7 @@ static int dump_event_logs(struct nvme_dev *dev, struct config cfg) err = read_header(&cmd, dev_fd(dev)); if (err) return err; - sprintf(file_path, "%s_EventLog.bin", cfg.file_prefix); + snprintf(file_path, sizeof(file_path), "%s/EventLog.bin", cfg.dir_prefix); output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (output < 0) return -errno; @@ -387,7 +390,8 @@ static int dump_nlogs(struct nvme_dev *dev, struct config cfg, int core) count = nlog_header->totalnlogs; core_num = core < 0 ? nlog_header->corecount : 0; if (!header_size) { - sprintf(file_path, "%s_NLog.bin", cfg.file_prefix); + snprintf(file_path, sizeof(file_path), "%s/NLog.bin", + cfg.dir_prefix); output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (output < 0) return -errno; @@ -423,25 +427,32 @@ enum telemetry_type { static int dump_telemetry(struct nvme_dev *dev, struct config cfg, enum telemetry_type ttype) { - struct nvme_telemetry_log *log = NULL; + _cleanup_free_ struct nvme_telemetry_log *log = NULL; size_t log_size = 0; - int err = 0, output; + int err = 0; __u8 *buffer = NULL; size_t bytes_remaining = 0; enum nvme_telemetry_da da; size_t max_data_tx; char file_path[PATH_MAX]; - char *log_name; + char *file_name; + char *log_descr; + struct stat sb; + + _cleanup_file_ int output = -1; switch (ttype) { case HOSTGENNEW: - log_name = "TelemetryHostGenNew"; + file_name = "lid_0x07_lsp_0x01_lsi_0x0000.bin"; + log_descr = "Generated Host Initiated"; break; case HOSTGENOLD: - log_name = "TelemetryHostGenOld"; + file_name = "lid_0x07_lsp_0x00_lsi_0x0000.bin"; + log_descr = "Existing Host Initiated"; break; case CONTROLLER: - log_name = "TelemetryController"; + file_name = "lid_0x08_lsp_0x00_lsi_0x0000.bin"; + log_descr = "Controller Initiated"; break; default: return -EINVAL; @@ -453,11 +464,6 @@ static int dump_telemetry(struct nvme_dev *dev, struct config cfg, enum telemetr if (max_data_tx > DRIVER_MAX_TX_256K) max_data_tx = DRIVER_MAX_TX_256K; - sprintf(file_path, "%s_%s.bin", cfg.file_prefix, log_name); - output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (output < 0) - return -errno; - switch (ttype) { case HOSTGENNEW: err = nvme_get_telemetry_log(dev_fd(dev), true, false, false, max_data_tx, da, @@ -474,7 +480,20 @@ static int dump_telemetry(struct nvme_dev *dev, struct config cfg, enum telemetr } if (err) - goto tele_close_output; + return err; + + snprintf(file_path, sizeof(file_path), "%s/log_pages", cfg.dir_prefix); + if (!(stat(file_path, &sb) == 0 && S_ISDIR(sb.st_mode))) { + if (mkdir(file_path, 777) != 0) { + perror(file_path); + return -errno; + } + } + + snprintf(file_path, sizeof(file_path), "%s/log_pages/%s", cfg.dir_prefix, file_name); + output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (output < 0) + return -errno; bytes_remaining = log_size; buffer = (__u8 *)log; @@ -486,45 +505,49 @@ static int dump_telemetry(struct nvme_dev *dev, struct config cfg, enum telemetr err = -errno; goto tele_close_output; } + bytes_remaining -= bytes_written; buffer += bytes_written; } - printf("Successfully wrote log to %s\n", file_path); + printf("Successfully wrote %s Telemetry log to %s\n", log_descr, file_path); tele_close_output: - free(log); close(output); - return err; } int solidigm_get_internal_log(int argc, char **argv, struct command *command, struct plugin *plugin) { + char folder[PATH_MAX]; + char zip_name[PATH_MAX]; + char *output_path; char sn_prefix[sizeof(((struct nvme_id_ctrl *)0)->sn)+1]; int log_count = 0; int err; - struct nvme_dev *dev; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; bool all = false; + time_t t; + struct tm tm; const char *desc = "Get Debug Firmware Logs and save them."; const char *type = "Log type: ALL, CONTROLLERINITTELEMETRY, HOSTINITTELEMETRY, HOSTINITTELEMETRYNOGEN, NLOG, ASSERT, EVENT. Defaults to ALL."; - const char *prefix = "Output file prefix; defaults to device serial number."; + const char *prefix = "Output dir prefix; defaults to device serial number."; const char *verbose = "To print out verbose info."; const char *namespace_id = "Namespace to get logs from."; struct config cfg = { .namespace_id = NVME_NSID_ALL, - .file_prefix = NULL, + .dir_prefix = NULL, .type = NULL, }; OPT_ARGS(opts) = { OPT_STR("type", 't', &cfg.type, type), OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_FILE("file-prefix", 'p', &cfg.file_prefix, prefix), + OPT_FILE("dir-prefix", 'p', &cfg.dir_prefix, prefix), OPT_FLAG("verbose", 'v', &cfg.verbose, verbose), OPT_END() }; @@ -533,12 +556,22 @@ int solidigm_get_internal_log(int argc, char **argv, struct command *command, if (err) return err; - if (!cfg.file_prefix) { + if (!cfg.dir_prefix) { err = get_serial_number(sn_prefix, dev_fd(dev)); if (err) - goto out_dev; - cfg.file_prefix = sn_prefix; + return err; + cfg.dir_prefix = sn_prefix; + } + t = time(NULL); + tm = *localtime(&t); + snprintf(folder, sizeof(folder), "%s-%d%02d%02d%02d%02d%02d", cfg.dir_prefix, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + if (mkdir(folder, 0777) != 0) { + perror("mkdir"); + return -errno; } + cfg.dir_prefix = folder; + output_path = folder; if (!cfg.type) cfg.type = "ALL"; @@ -547,8 +580,9 @@ int solidigm_get_internal_log(int argc, char **argv, struct command *command, *p = toupper(*p); } - if (!strcmp(cfg.type, "ALL")) + if (!strcmp(cfg.type, "ALL")) { all = true; + } if (all || !strcmp(cfg.type, "ASSERT")) { err = dump_assert_logs(dev, cfg); if (err == 0) @@ -592,14 +626,32 @@ int solidigm_get_internal_log(int argc, char **argv, struct command *command, perror("Error retrieving Telemetry Host Initiated"); } + if (log_count > 0) { + int ret_cmd; + char cmd[ARG_MAX]; + char *where_err = cfg.verbose ? "" : ">/dev/null 2>&1"; + + snprintf(zip_name, sizeof(zip_name), "%s.zip", cfg.dir_prefix); + snprintf(cmd, sizeof(cmd), "cd \"%s\" && zip -r \"../%s\" ./* %s", cfg.dir_prefix, + zip_name, where_err); + printf("Compressing logs to %s\n", zip_name); + ret_cmd = system(cmd); + if (ret_cmd == -1) + perror(cmd); + else { + output_path = zip_name; + snprintf(cmd, sizeof(cmd), "rm -rf %s", cfg.dir_prefix); + printf("Removing %s\n", cfg.dir_prefix); + if (system(cmd) != 0) + perror("Failed removing logs folder"); + } + } + if (log_count == 0) { if (err > 0) nvme_show_status(err); } else if ((log_count > 1) || cfg.verbose) - printf("Total: %d log files with prefix: %s\n", log_count, cfg.file_prefix); -out_dev: - /* Redundant close() to make static code analysis happy */ - close(dev->direct.fd); - dev_close(dev); + printf("Total: %d log files in %s\n", log_count, output_path); + return err; } diff --git a/plugins/solidigm/solidigm-nvme.h b/plugins/solidigm/solidigm-nvme.h index a984a38..bee8266 100644 --- a/plugins/solidigm/solidigm-nvme.h +++ b/plugins/solidigm/solidigm-nvme.h @@ -13,7 +13,7 @@ #include "cmd.h" -#define SOLIDIGM_PLUGIN_VERSION "1.0" +#define SOLIDIGM_PLUGIN_VERSION "1.1" PLUGIN(NAME("solidigm", "Solidigm vendor specific extensions", SOLIDIGM_PLUGIN_VERSION), COMMAND_LIST( diff --git a/plugins/wdc/wdc-nvme.c b/plugins/wdc/wdc-nvme.c index d663131..8cbcf2e 100644 --- a/plugins/wdc/wdc-nvme.c +++ b/plugins/wdc/wdc-nvme.c @@ -94,10 +94,40 @@ #define WDC_NVME_SN520_DEV_ID 0x5003 #define WDC_NVME_SN520_DEV_ID_1 0x5004 #define WDC_NVME_SN520_DEV_ID_2 0x5005 -#define WDC_NVME_SN530_DEV_ID 0x5009 -#define WDC_NVME_SN530_DEV_ID_1 0x501d + +#define WDC_NVME_SN530_DEV_ID_1 0x5007 +#define WDC_NVME_SN530_DEV_ID_2 0x5008 +#define WDC_NVME_SN530_DEV_ID_3 0x5009 +#define WDC_NVME_SN530_DEV_ID_4 0x500b +#define WDC_NVME_SN530_DEV_ID_5 0x501d + +#define WDC_NVME_SN350_DEV_ID 0x5019 + +#define WDC_NVME_SN570_DEV_ID 0x501A + +#define WDC_NVME_SN850X_DEV_ID 0x5030 + +#define WDC_NVME_SN5000_DEV_ID_1 0x5034 +#define WDC_NVME_SN5000_DEV_ID_2 0x5035 +#define WDC_NVME_SN5000_DEV_ID_3 0x5036 +#define WDC_NVME_SN5000_DEV_ID_4 0x504A + +#define WDC_NVME_SN7000S_DEV_ID_1 0x5039 + +#define WDC_NVME_SN7150_DEV_ID_1 0x503b +#define WDC_NVME_SN7150_DEV_ID_2 0x503c +#define WDC_NVME_SN7150_DEV_ID_3 0x503d +#define WDC_NVME_SN7150_DEV_ID_4 0x503e +#define WDC_NVME_SN7150_DEV_ID_5 0x503f + +#define WDC_NVME_SN7100_DEV_ID_1 0x5043 +#define WDC_NVME_SN7100_DEV_ID_2 0x5044 +#define WDC_NVME_SN7100_DEV_ID_3 0x5045 + +#define WDC_NVME_SN8000S_DEV_ID 0x5049 + #define WDC_NVME_SN720_DEV_ID 0x5002 -#define WDC_NVME_SN730A_DEV_ID 0x5006 +#define WDC_NVME_SN730_DEV_ID 0x5006 #define WDC_NVME_SN740_DEV_ID 0x5015 #define WDC_NVME_SN740_DEV_ID_1 0x5016 #define WDC_NVME_SN740_DEV_ID_2 0x5017 @@ -989,7 +1019,7 @@ struct wdc_e6_log_hdr { /* DUI log header */ struct wdc_dui_log_section { __le16 section_type; - __le16 data_area_id; + __le16 reserved; __le32 section_size; }; @@ -1671,6 +1701,7 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev) WDC_DRIVE_CAP_DRIVE_LOG | WDC_DRIVE_CAP_CRASH_DUMP | WDC_DRIVE_CAP_PFAIL_DUMP | WDC_DRIVE_CAP_PURGE); break; + case WDC_NVME_SN200_DEV_ID: capabilities = (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG | WDC_DRIVE_CAP_CLEAR_PCIE | WDC_DRIVE_CAP_DRIVE_LOG | WDC_DRIVE_CAP_CRASH_DUMP | WDC_DRIVE_CAP_PFAIL_DUMP | @@ -1686,10 +1717,12 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev) WDC_NVME_ADD_LOG_OPCODE)) capabilities |= WDC_DRIVE_CAP_C1_LOG_PAGE; break; + default: capabilities = 0; } break; + case WDC_NVME_VID_2: switch (read_device_id) { case WDC_NVME_SN630_DEV_ID: @@ -1708,6 +1741,7 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev) WDC_NVME_GET_VU_SMART_LOG_OPCODE)) capabilities |= WDC_DRIVE_CAP_D0_LOG_PAGE; break; + case WDC_NVME_SN640_DEV_ID: fallthrough; case WDC_NVME_SN640_DEV_ID_1: @@ -1780,6 +1814,7 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev) capabilities |= (WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY | WDC_DRIVE_CAP_CLEAR_PCIE); break; + case WDC_NVME_SN840_DEV_ID: fallthrough; case WDC_NVME_SN840_DEV_ID_1: @@ -1810,6 +1845,7 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev) WDC_NVME_GET_VU_SMART_LOG_OPCODE)) capabilities |= WDC_DRIVE_CAP_D0_LOG_PAGE; break; + case WDC_NVME_SN650_DEV_ID: fallthrough; case WDC_NVME_SN650_DEV_ID_1: @@ -1869,6 +1905,7 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev) WDC_DRIVE_CAP_CLEAR_PCIE); break; + case WDC_NVME_SN861_DEV_ID: fallthrough; case WDC_NVME_SN861_DEV_ID_1: @@ -1886,28 +1923,28 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev) WDC_DRIVE_CAP_LOG_PAGE_DIR | WDC_DRIVE_CAP_SET_LATENCY_MONITOR); break; + default: capabilities = 0; } break; + case WDC_NVME_SNDK_VID: switch (read_device_id) { case WDC_NVME_SXSLCL_DEV_ID: capabilities = WDC_DRIVE_CAP_DRIVE_ESSENTIALS; break; + case WDC_NVME_SN520_DEV_ID: fallthrough; case WDC_NVME_SN520_DEV_ID_1: fallthrough; case WDC_NVME_SN520_DEV_ID_2: fallthrough; - case WDC_NVME_SN530_DEV_ID: - fallthrough; - case WDC_NVME_SN530_DEV_ID_1: - fallthrough; case WDC_NVME_SN810_DEV_ID: capabilities = WDC_DRIVE_CAP_DUI_DATA; break; + case WDC_NVME_SN820CL_DEV_ID: capabilities = WDC_DRIVE_CAP_DUI_DATA | WDC_DRIVE_CAP_CLOUD_BOOT_SSD_VERSION | @@ -1916,15 +1953,62 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev) WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE | WDC_DRIVE_CAP_NAND_STATS | WDC_DRIVE_CAP_DEVICE_WAF | WDC_DRIVE_CAP_TEMP_STATS; break; + case WDC_NVME_SN720_DEV_ID: capabilities = WDC_DRIVE_CAP_DUI_DATA | WDC_DRIVE_CAP_NAND_STATS | WDC_DRIVE_CAP_NS_RESIZE; break; - case WDC_NVME_SN730A_DEV_ID: + + case WDC_NVME_SN730_DEV_ID: capabilities = WDC_DRIVE_CAP_DUI | WDC_DRIVE_CAP_NAND_STATS | WDC_DRIVE_CAP_INFO | WDC_DRIVE_CAP_TEMP_STATS | WDC_DRIVE_CAP_VUC_CLEAR_PCIE | WDC_DRIVE_CAP_PCIE_STATS; break; + + case WDC_NVME_SN530_DEV_ID_1: + fallthrough; + case WDC_NVME_SN530_DEV_ID_2: + fallthrough; + case WDC_NVME_SN530_DEV_ID_3: + fallthrough; + case WDC_NVME_SN530_DEV_ID_4: + fallthrough; + case WDC_NVME_SN530_DEV_ID_5: + fallthrough; + case WDC_NVME_SN350_DEV_ID: + fallthrough; + case WDC_NVME_SN570_DEV_ID: + fallthrough; + case WDC_NVME_SN850X_DEV_ID: + fallthrough; + case WDC_NVME_SN5000_DEV_ID_1: + fallthrough; + case WDC_NVME_SN5000_DEV_ID_2: + fallthrough; + case WDC_NVME_SN5000_DEV_ID_3: + fallthrough; + case WDC_NVME_SN5000_DEV_ID_4: + fallthrough; + case WDC_NVME_SN7000S_DEV_ID_1: + fallthrough; + case WDC_NVME_SN7150_DEV_ID_1: + fallthrough; + case WDC_NVME_SN7150_DEV_ID_2: + fallthrough; + case WDC_NVME_SN7150_DEV_ID_3: + fallthrough; + case WDC_NVME_SN7150_DEV_ID_4: + fallthrough; + case WDC_NVME_SN7150_DEV_ID_5: + fallthrough; + case WDC_NVME_SN7100_DEV_ID_1: + fallthrough; + case WDC_NVME_SN7100_DEV_ID_2: + fallthrough; + case WDC_NVME_SN7100_DEV_ID_3: + fallthrough; + case WDC_NVME_SN8000S_DEV_ID: + fallthrough; case WDC_NVME_SN740_DEV_ID: fallthrough; case WDC_NVME_SN740_DEV_ID_1: @@ -1936,6 +2020,7 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev) case WDC_NVME_SN340_DEV_ID: capabilities = WDC_DRIVE_CAP_DUI; break; + case WDC_NVME_ZN350_DEV_ID: fallthrough; case WDC_NVME_ZN350_DEV_ID_1: @@ -1945,6 +2030,7 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev) WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2 | WDC_DRIVE_CAP_INFO | WDC_DRIVE_CAP_CLOUD_SSD_VERSION | WDC_DRIVE_CAP_LOG_PAGE_DIR; break; + default: capabilities = 0; } @@ -2632,6 +2718,16 @@ static int wdc_do_dump_e6(int fd, __u32 opcode, __u32 data_len, int i; struct nvme_passthru_cmd admin_cmd; + /* if data_len is not 4 byte aligned */ + if (data_len & 0x00000003) { + /* Round down to the next 4 byte aligned value */ + fprintf(stderr, "%s: INFO: data_len 0x%x not 4 byte aligned.\n", + __func__, data_len); + fprintf(stderr, "%s: INFO: Round down to 0x%x.\n", + __func__, (data_len &= 0xFFFFFFFC)); + data_len &= 0xFFFFFFFC; + } + dump_data = (__u8 *)malloc(sizeof(__u8) * data_len); if (!dump_data) { @@ -2649,7 +2745,8 @@ static int wdc_do_dump_e6(int fd, __u32 opcode, __u32 data_len, admin_cmd.opcode = opcode; admin_cmd.cdw12 = cdw12; - log_size = data_len; + /* subtract off the header size since that was already copied into the buffer */ + log_size = (data_len - curr_data_offset); while (log_size > 0) { xfer_size = min(xfer_size, log_size); @@ -2890,6 +2987,8 @@ static int wdc_do_cap_dui_v1(int fd, char *file, __u32 xfer_size, int data_area, fprintf(stderr, "INFO: WDC: Capture V1 Device Unit Info log, data area = %d\n", data_area); fprintf(stderr, "INFO: WDC: DUI Header Version = 0x%x\n", log_hdr->hdr_version); + fprintf(stderr, "INFO: WDC: DUI section count = 0x%x\n", log_hdr->section_count); + fprintf(stderr, "INFO: WDC: DUI log size = 0x%x\n", log_hdr->log_size); } if (!cap_dui_length) { @@ -2899,23 +2998,15 @@ static int wdc_do_cap_dui_v1(int fd, char *file, __u32 xfer_size, int data_area, /* parse log header for all sections up to specified data area inclusively */ if (data_area != WDC_NVME_DUI_MAX_DATA_AREA) { - for (j = 0; j < WDC_NVME_DUI_MAX_SECTION; j++) { - if (log_hdr->log_section[j].data_area_id <= data_area && - log_hdr->log_section[j].data_area_id) { - log_size += log_hdr->log_section[j].section_size; - if (verbose) - fprintf(stderr, - "%s: Data area ID %d : section size 0x%x, total size = 0x%x\n", - __func__, log_hdr->log_section[j].data_area_id, - (unsigned int)log_hdr->log_section[j].section_size, - (unsigned int)log_size); + for (j = 0; j < log_hdr->section_count; j++) { + log_size += log_hdr->log_section[j].section_size; + if (verbose) + fprintf(stderr, + "%s: section size 0x%x, total size = 0x%x\n", + __func__, + (unsigned int)log_hdr->log_section[j].section_size, + (unsigned int)log_size); - } else { - if (verbose) - fprintf(stderr, "%s: break, total size = 0x%x\n", __func__, - (unsigned int)log_size); - break; - } } } else { log_size = cap_dui_length; @@ -8112,7 +8203,7 @@ static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command, struct ocp_cloud_smart_log log; char buf[2 * sizeof(log.log_page_guid) + 3]; - ret = validate_output_format(output_format, &fmt); + ret = validate_output_format(cfg.output_format, &fmt); if (ret < 0) { fprintf(stderr, "Invalid output format: %s\n", cfg.output_format); goto out; @@ -11496,7 +11587,7 @@ static int wdc_vs_drive_info(int argc, char **argv, } } break; - case WDC_NVME_SN730A_DEV_ID: + case WDC_NVME_SN730_DEV_ID: memcpy(vsData, &ctrl.vs[0], 32); major_rev = ctrl.sn[12]; diff --git a/plugins/wdc/wdc-nvme.h b/plugins/wdc/wdc-nvme.h index f3f28a7..d3692bc 100644 --- a/plugins/wdc/wdc-nvme.h +++ b/plugins/wdc/wdc-nvme.h @@ -5,7 +5,7 @@ #if !defined(WDC_NVME) || defined(CMD_HEADER_MULTI_READ) #define WDC_NVME -#define WDC_PLUGIN_VERSION "2.3.5" +#define WDC_PLUGIN_VERSION "2.7.0" #include "cmd.h" PLUGIN(NAME("wdc", "Western Digital vendor specific extensions", WDC_PLUGIN_VERSION), diff --git a/plugins/wdc/wdc-utils.c b/plugins/wdc/wdc-utils.c index be2ef06..414a06a 100644 --- a/plugins/wdc/wdc-utils.c +++ b/plugins/wdc/wdc-utils.c @@ -192,15 +192,5 @@ bool wdc_CheckUuidListSupport(struct nvme_dev *dev, struct nvme_id_uuid_list *uu bool wdc_UuidEqual(struct nvme_id_uuid_list_entry *entry1, struct nvme_id_uuid_list_entry *entry2) { - int i; - - for (i = 0; i < 16; i++) { - if (entry1->uuid[i] != entry2->uuid[i]) - break; - } - - if (i == 16) - return true; - else - return false; + return !memcmp(entry1, entry2, NVME_UUID_LEN); } -- cgit v1.2.3