diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2021-07-02 20:49:35 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2021-07-02 20:49:35 +0000 |
commit | f2c543b4ccad3b9f8871d952cddf66b3b438595b (patch) | |
tree | c3c363d1cc72514221685c42a79a19b320114acc /plugins/scaleflux | |
parent | Adding debian version 1.12-8. (diff) | |
download | nvme-cli-f2c543b4ccad3b9f8871d952cddf66b3b438595b.tar.xz nvme-cli-f2c543b4ccad3b9f8871d952cddf66b3b438595b.zip |
Merging upstream version 1.14.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'plugins/scaleflux')
-rw-r--r-- | plugins/scaleflux/sfx-nvme.c | 377 | ||||
-rw-r--r-- | plugins/scaleflux/sfx-nvme.h | 4 |
2 files changed, 252 insertions, 129 deletions
diff --git a/plugins/scaleflux/sfx-nvme.c b/plugins/scaleflux/sfx-nvme.c index 846ca77..df7f9a3 100644 --- a/plugins/scaleflux/sfx-nvme.c +++ b/plugins/scaleflux/sfx-nvme.c @@ -8,6 +8,8 @@ #include <asm/byteorder.h> #include <sys/ioctl.h> #include <sys/sysinfo.h> +#include <sys/stat.h> +#include <unistd.h> #include "linux/nvme_ioctl.h" @@ -15,7 +17,6 @@ #include "nvme-print.h" #include "nvme-ioctl.h" #include "nvme-status.h" -#include "json.h" #include "plugin.h" #include "argconfig.h" @@ -28,36 +29,40 @@ #define SECTOR_SHIFT 9 #define SFX_GET_FREESPACE _IOWR('N', 0x240, struct sfx_freespace_ctx) -#define IDEMA_CAP(exp_GB) (((__u64)exp_GB - 50ULL) * 1953504ULL + 97696368ULL) +#define NVME_IOCTL_CLR_CARD _IO('N', 0x47) +#define IDEMA_CAP(exp_GB) (((__u64)exp_GB - 50ULL) * 1953504ULL + 97696368ULL) +#define IDEMA_CAP2GB(exp_sector) (((__u64)exp_sector - 97696368ULL) / 1953504ULL + 50ULL) enum { SFX_LOG_LATENCY_READ_STATS = 0xc1, SFX_LOG_SMART = 0xc2, - SFX_LOG_LATENCY_WRITE_STATS = 0xc3, + SFX_LOG_LATENCY_WRITE_STATS = 0xc3, SFX_LOG_QUAL = 0xc4, SFX_LOG_MISMATCHLBA = 0xc5, SFX_LOG_MEDIA = 0xc6, SFX_LOG_BBT = 0xc7, SFX_LOG_IDENTIFY = 0xcc, SFX_FEAT_ATOMIC = 0x01, + SFX_FEAT_UP_P_CAP = 0xac, + SFX_FEAT_CLR_CARD = 0xdc, }; enum sfx_nvme_admin_opcode { nvme_admin_query_cap_info = 0xd3, nvme_admin_change_cap = 0xd4, - nvme_admin_sfx_set_features = 0xd5, - nvme_admin_sfx_get_features = 0xd6, + nvme_admin_sfx_set_features = 0xd5, + nvme_admin_sfx_get_features = 0xd6, }; struct sfx_freespace_ctx { __u64 free_space; - __u64 phy_cap; /* physical capacity, in unit of sector */ - __u64 phy_space; /* physical space considering OP, in unit of sector */ - __u64 user_space; /* user required space, in unit of sector*/ - __u64 hw_used; /* hw space used in 4K */ - __u64 app_written; /* app data written in 4K */ + __u64 phy_cap; /* physical capacity, in unit of sector */ + __u64 phy_space; /* physical space considering OP, in unit of sector */ + __u64 user_space; /* user required space, in unit of sector*/ + __u64 hw_used; /* hw space used in 4K */ + __u64 app_written; /* app data written in 4K */ }; struct nvme_capacity_info { @@ -66,7 +71,7 @@ struct nvme_capacity_info { __u64 used_space; __u64 free_space; }; -struct __attribute__((packed)) nvme_additional_smart_log_item { +struct __attribute__((packed)) nvme_additional_smart_log_item { uint8_t key; uint8_t _kp[2]; uint8_t norm; @@ -112,11 +117,10 @@ int nvme_change_cap(int fd, __u32 nsid, __u64 capacity) struct nvme_admin_cmd cmd = { .opcode = nvme_admin_change_cap, .nsid = nsid, - .cdw10 = (capacity & 0xffffffff), - .cdw11 = (capacity >> 32), + .cdw10 = (capacity & 0xffffffff), + .cdw11 = (capacity >> 32), }; - return nvme_submit_passthru(fd, NVME_IOCTL_ADMIN_CMD,&cmd); } @@ -267,65 +271,65 @@ static void show_sfx_smart_log(struct nvme_additional_smart_log *smart, unsigned int nsid, const char *devname) { printf("Additional Smart Log for ScaleFlux device:%s namespace-id:%x\n", - devname, nsid); - printf("key normalized raw\n"); - printf("program_fail_count : %3d%% %"PRIu64"\n", - smart->program_fail_cnt.norm, - int48_to_long(smart->program_fail_cnt.raw)); - printf("erase_fail_count : %3d%% %"PRIu64"\n", - smart->erase_fail_cnt.norm, - int48_to_long(smart->erase_fail_cnt.raw)); - printf("wear_leveling : %3d%% min: %u, max: %u, avg: %u\n", - smart->wear_leveling_cnt.norm, - le16_to_cpu(smart->wear_leveling_cnt.wear_level.min), - le16_to_cpu(smart->wear_leveling_cnt.wear_level.max), - le16_to_cpu(smart->wear_leveling_cnt.wear_level.avg)); - printf("end_to_end_error_detection_count: %3d%% %"PRIu64"\n", - smart->e2e_err_cnt.norm, - int48_to_long(smart->e2e_err_cnt.raw)); - printf("crc_error_count : %3d%% %"PRIu64"\n", - smart->crc_err_cnt.norm, - int48_to_long(smart->crc_err_cnt.raw)); - printf("timed_workload_media_wear : %3d%% %.3f%%\n", - smart->timed_workload_media_wear.norm, - ((float)int48_to_long(smart->timed_workload_media_wear.raw)) / 1024); - printf("timed_workload_host_reads : %3d%% %"PRIu64"%%\n", - smart->timed_workload_host_reads.norm, - int48_to_long(smart->timed_workload_host_reads.raw)); - printf("timed_workload_timer : %3d%% %"PRIu64" min\n", - smart->timed_workload_timer.norm, - int48_to_long(smart->timed_workload_timer.raw)); - printf("thermal_throttle_status : %3d%% %u%%, cnt: %u\n", - smart->thermal_throttle_status.norm, - smart->thermal_throttle_status.thermal_throttle.pct, - smart->thermal_throttle_status.thermal_throttle.count); - printf("retry_buffer_overflow_count : %3d%% %"PRIu64"\n", - smart->retry_buffer_overflow_cnt.norm, - int48_to_long(smart->retry_buffer_overflow_cnt.raw)); - printf("pll_lock_loss_count : %3d%% %"PRIu64"\n", - smart->pll_lock_loss_cnt.norm, - int48_to_long(smart->pll_lock_loss_cnt.raw)); - printf("nand_bytes_written : %3d%% sectors: %"PRIu64"\n", - smart->nand_bytes_written.norm, - int48_to_long(smart->nand_bytes_written.raw)); - printf("host_bytes_written : %3d%% sectors: %"PRIu64"\n", - smart->host_bytes_written.norm, - int48_to_long(smart->host_bytes_written.raw)); - printf("raid_recover_cnt : %3d%% %"PRIu64"\n", - smart->raid_recover_cnt.norm, - int48_to_long(smart->raid_recover_cnt.raw)); - printf("read_ecc_cnt : %3d%% %"PRIu64"\n", - smart->read_ecc_cnt.norm, - int48_to_long(smart->read_ecc_cnt.raw)); - printf("prog_timeout_cnt : %3d%% %"PRIu64"\n", - smart->prog_timeout_cnt.norm, - int48_to_long(smart->prog_timeout_cnt.raw)); - printf("erase_timeout_cnt : %3d%% %"PRIu64"\n", - smart->erase_timeout_cnt.norm, - int48_to_long(smart->erase_timeout_cnt.raw)); - printf("read_timeout_cnt : %3d%% %"PRIu64"\n", - smart->read_timeout_cnt.norm, - int48_to_long(smart->read_timeout_cnt.raw)); + devname, nsid); + printf("key normalized raw\n"); + printf("program_fail_count : %3d%% %"PRIu64"\n", + smart->program_fail_cnt.norm, + int48_to_long(smart->program_fail_cnt.raw)); + printf("erase_fail_count : %3d%% %"PRIu64"\n", + smart->erase_fail_cnt.norm, + int48_to_long(smart->erase_fail_cnt.raw)); + printf("wear_leveling : %3d%% min: %u, max: %u, avg: %u\n", + smart->wear_leveling_cnt.norm, + le16_to_cpu(smart->wear_leveling_cnt.wear_level.min), + le16_to_cpu(smart->wear_leveling_cnt.wear_level.max), + le16_to_cpu(smart->wear_leveling_cnt.wear_level.avg)); + printf("end_to_end_error_detection_count: %3d%% %"PRIu64"\n", + smart->e2e_err_cnt.norm, + int48_to_long(smart->e2e_err_cnt.raw)); + printf("crc_error_count : %3d%% %"PRIu64"\n", + smart->crc_err_cnt.norm, + int48_to_long(smart->crc_err_cnt.raw)); + printf("timed_workload_media_wear : %3d%% %.3f%%\n", + smart->timed_workload_media_wear.norm, + ((float)int48_to_long(smart->timed_workload_media_wear.raw)) / 1024); + printf("timed_workload_host_reads : %3d%% %"PRIu64"%%\n", + smart->timed_workload_host_reads.norm, + int48_to_long(smart->timed_workload_host_reads.raw)); + printf("timed_workload_timer : %3d%% %"PRIu64" min\n", + smart->timed_workload_timer.norm, + int48_to_long(smart->timed_workload_timer.raw)); + printf("thermal_throttle_status : %3d%% %u%%, cnt: %u\n", + smart->thermal_throttle_status.norm, + smart->thermal_throttle_status.thermal_throttle.pct, + smart->thermal_throttle_status.thermal_throttle.count); + printf("retry_buffer_overflow_count : %3d%% %"PRIu64"\n", + smart->retry_buffer_overflow_cnt.norm, + int48_to_long(smart->retry_buffer_overflow_cnt.raw)); + printf("pll_lock_loss_count : %3d%% %"PRIu64"\n", + smart->pll_lock_loss_cnt.norm, + int48_to_long(smart->pll_lock_loss_cnt.raw)); + printf("nand_bytes_written : %3d%% sectors: %"PRIu64"\n", + smart->nand_bytes_written.norm, + int48_to_long(smart->nand_bytes_written.raw)); + printf("host_bytes_written : %3d%% sectors: %"PRIu64"\n", + smart->host_bytes_written.norm, + int48_to_long(smart->host_bytes_written.raw)); + printf("raid_recover_cnt : %3d%% %"PRIu64"\n", + smart->raid_recover_cnt.norm, + int48_to_long(smart->raid_recover_cnt.raw)); + printf("read_ecc_cnt : %3d%% %"PRIu64"\n", + smart->read_ecc_cnt.norm, + int48_to_long(smart->read_ecc_cnt.raw)); + printf("prog_timeout_cnt : %3d%% %"PRIu64"\n", + smart->prog_timeout_cnt.norm, + int48_to_long(smart->prog_timeout_cnt.raw)); + printf("erase_timeout_cnt : %3d%% %"PRIu64"\n", + smart->erase_timeout_cnt.norm, + int48_to_long(smart->erase_timeout_cnt.raw)); + printf("read_timeout_cnt : %3d%% %"PRIu64"\n", + smart->read_timeout_cnt.norm, + int48_to_long(smart->read_timeout_cnt.raw)); } static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) @@ -357,8 +361,8 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd, fd = parse_and_open(argc, argv, desc, opts); - err = nvme_get_log(fd, cfg.namespace_id, 0xca, false, sizeof(smart_log), - (void *)&smart_log); + err = nvme_get_log(fd, cfg.namespace_id, 0xca, false, NVME_NO_LOG_LSP, + sizeof(smart_log), (void *)&smart_log); if (!err) { if (cfg.json) show_sfx_smart_log_jsn(&smart_log, cfg.namespace_id, devicename); @@ -373,7 +377,6 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd, return err; } - struct sfx_lat_stats { __u16 maj; __u16 min; @@ -440,7 +443,8 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct fd = parse_and_open(argc, argv, desc, opts); - err = nvme_get_log(fd, 0xffffffff, cfg.write ? 0xc3 : 0xc1, false, sizeof(stats), (void *)&stats); + err = nvme_get_log(fd, 0xffffffff, cfg.write ? 0xc3 : 0xc1, false, NVME_NO_LOG_LSP, + sizeof(stats), (void *)&stats); if (!err) { if (!cfg.raw_binary) show_lat_stats(&stats, cfg.write); @@ -448,7 +452,7 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct d_raw((unsigned char *)&stats, sizeof(stats)); } else if (err > 0) fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_status_to_string(err), err); return err; } @@ -517,16 +521,16 @@ static void bd_table_show(unsigned char *bd_table, __u64 table_size) bb_elem = (__u64 *)(bd_table + 5 * sizeof(__u32)); printf("Bad Block Table \n"); - printf("MF_BB_COUNT: %u\n", mf_bb_count); - printf("GROWN_BB_COUNT: %u\n", grown_bb_count); - printf("TOTAL_BB_COUNT: %u\n", total_bb_count); - printf("REMAP_MFBB_COUNT: %u\n", remap_mfbb_count); - printf("REMAP_GBB_COUNT: %u\n", remap_gbb_count); + printf("MF_BB_COUNT: %u\n", mf_bb_count); + printf("GROWN_BB_COUNT: %u\n", grown_bb_count); + printf("TOTAL_BB_COUNT: %u\n", total_bb_count); + printf("REMAP_MFBB_COUNT: %u\n", remap_mfbb_count); + printf("REMAP_GBB_COUNT: %u\n", remap_gbb_count); printf("REMAP_MFBB_TABLE ["); i = 0; while (bb_elem < elem_end && i < remap_mfbb_count) { - printf(" 0x%llx", *(bb_elem++)); + printf(" 0x%"PRIx64"", (uint64_t)*(bb_elem++)); i++; } printf(" ]\n"); @@ -534,14 +538,14 @@ static void bd_table_show(unsigned char *bd_table, __u64 table_size) printf("REMAP_GBB_TABLE ["); i = 0; while (bb_elem < elem_end && i < remap_gbb_count) { - printf(" 0x%llx",*(bb_elem++)); + printf(" 0x%"PRIx64"", (uint64_t)*(bb_elem++)); i++; } printf(" ]\n"); } /** - * @brief "hooks of sfx get-bad-block" + * @brief "hooks of sfx get-bad-block" * * @param argc * @param argv @@ -592,10 +596,16 @@ static int sfx_get_bad_block(int argc, char **argv, struct command *cmd, struct static void show_cap_info(struct sfx_freespace_ctx *ctx) { - printf("user sectors: %#llx\n", ctx->user_space); - printf("totl physical sectors: %#llx\n", ctx->phy_space); - printf("free physical sectors: %#llx\n", ctx->free_space); - printf("used physical sectors: %#llx\n", ctx->phy_space - ctx->free_space); + + printf("logic capacity:%5lluGB(0x%"PRIx64")\n", + IDEMA_CAP2GB(ctx->user_space), (uint64_t)ctx->user_space); + printf("provisioned capacity:%5lluGB(0x%"PRIx64")\n", + IDEMA_CAP2GB(ctx->phy_space), (uint64_t)ctx->phy_space); + printf("free provisioned capacity:%5lluGB(0x%"PRIx64")\n", + IDEMA_CAP2GB(ctx->free_space), (uint64_t)ctx->free_space); + printf("used provisioned capacity:%5lluGB(0x%"PRIx64")\n", + IDEMA_CAP2GB(ctx->phy_space) - IDEMA_CAP2GB(ctx->free_space), + (uint64_t)(ctx->phy_space - ctx->free_space)); } static int query_cap_info(int argc, char **argv, struct command *cmd, struct plugin *plugin) @@ -631,42 +641,94 @@ static int query_cap_info(int argc, char **argv, struct command *cmd, struct plu return err; } -static int change_cap_mem_check(int fd, __u64 trg_in_4k) +static int change_sanity_check(int fd, __u64 trg_in_4k, int *shrink) { struct sfx_freespace_ctx freespace_ctx = { 0 }; struct sysinfo s_info; __u64 mem_need = 0; __u64 cur_in_4k = 0; + __u64 provisoned_cap_4k = 0; __u32 cnt_ms = 0; + int extend = 0; while (ioctl(fd, SFX_GET_FREESPACE, &freespace_ctx)) { if (cnt_ms++ > 600) {//1min - fprintf(stderr, "vu ioctl fail, errno %d\r\n", errno); return -1; } usleep(100000); } - cur_in_4k = freespace_ctx.user_space >> (SFX_PAGE_SHIFT - SECTOR_SHIFT); - if (cur_in_4k > trg_in_4k) { - return 0; + /* + * capacity illegal check + */ + provisoned_cap_4k = freespace_ctx.phy_space >> + (SFX_PAGE_SHIFT - SECTOR_SHIFT); + if (trg_in_4k < provisoned_cap_4k || + trg_in_4k > ((__u64)provisoned_cap_4k * 4)) { + fprintf(stderr, + "WARNING: Only support 1.0~4.0 x provisoned capacity!\n"); + if (trg_in_4k < provisoned_cap_4k) { + fprintf(stderr, + "WARNING: The target capacity is less than 1.0 x provisioned capacity!\n"); + } else { + fprintf(stderr, + "WARNING: The target capacity is larger than 4.0 x provisioned capacity!\n"); + } + return -1; } - - if (sysinfo(&s_info) < 0) { - printf("change-cap query mem info fail\n"); + if (trg_in_4k > ((__u64)provisoned_cap_4k*4)) { + fprintf(stderr, "WARNING: the target capacity is too large\n"); return -1; } - mem_need = (trg_in_4k - cur_in_4k) * 8; - if (s_info.freeram <= 10 || mem_need > s_info.freeram) { - fprintf(stderr, "WARNING: mem needed is %llu, free mem is %lu\n" - "Insufficient memory, please drop cache or add free memory and retry\n", - mem_need, s_info.freeram); - return -1; + /* + * check whether mem enough if extend + * */ + cur_in_4k = freespace_ctx.user_space >> (SFX_PAGE_SHIFT - SECTOR_SHIFT); + extend = (cur_in_4k <= trg_in_4k); + if (extend) { + if (sysinfo(&s_info) < 0) { + printf("change-cap query mem info fail\n"); + return -1; + } + mem_need = (trg_in_4k - cur_in_4k) * 8; + if (s_info.freeram <= 10 || mem_need > s_info.freeram) { + fprintf(stderr, + "WARNING: Free memory is not enough! " + "Please drop cache or extend more memory and retry\n" + "WARNING: Memory needed is %"PRIu64", free memory is %"PRIu64"\n", + (uint64_t)mem_need, (uint64_t)s_info.freeram); + return -1; + } } + *shrink = !extend; + return 0; } +/** + * @brief prompt and get user confirm input + * + * @param str, prompt string + * + * @return 0, cancled; 1 confirmed + */ +static int sfx_confirm_change(const char *str) +{ + char confirm; + fprintf(stderr, "WARNING: %s.\n" + "Use the force [--force] option to suppress this warning.\n", str); + + fprintf(stderr, "Confirm Y/y, Others cancel:\n"); + confirm = fgetc(stdin); + if (confirm != 'y' && confirm != 'Y') { + fprintf(stderr, "Cancled.\n"); + return 0; + } + fprintf(stderr, "Sending operation ... \n"); + return 1; +} + static int change_cap(int argc, char **argv, struct command *cmd, struct plugin *plugin) { int err = -1, fd; @@ -678,6 +740,8 @@ static int change_cap(int argc, char **argv, struct command *cmd, struct plugin const char *force = "The \"I know what I'm doing\" flag, skip confirmation before sending command"; __u64 cap_in_4k = 0; __u64 cap_in_sec = 0; + int shrink = 0; + struct config { __u64 cap_in_byte; __u32 capacity_in_gb; @@ -694,7 +758,7 @@ static int change_cap(int argc, char **argv, struct command *cmd, struct plugin OPT_ARGS(opts) = { OPT_UINT("cap", 'c', &cfg.capacity_in_gb, cap_gb), - OPT_UINT("cap-byte", 'z', &cfg.cap_in_byte, cap_byte), + OPT_SUFFIX("cap-byte", 'z', &cfg.cap_in_byte, cap_byte), OPT_FLAG("force", 'f', &cfg.force, force), OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), OPT_FLAG("json", 'j', &cfg.json, json), @@ -706,22 +770,21 @@ static int change_cap(int argc, char **argv, struct command *cmd, struct plugin return fd; } - if (!cfg.force) { - fprintf(stderr, "WARNING: Changing capacity may irrevocably delete user data.\n" - "You have 10 seconds to press Ctrl-C to cancel this operation.\n\n" - "Use the force [--force|-f] option to suppress this warning.\n"); - sleep(10); - fprintf(stderr, "Sending operation ... \n"); - } - cap_in_sec = IDEMA_CAP(cfg.capacity_in_gb); cap_in_4k = cap_in_sec >> 3; if (cfg.cap_in_byte) cap_in_4k = cfg.cap_in_byte >> 12; - printf("%dG %lluB %llu 4K\n", - cfg.capacity_in_gb, cfg.cap_in_byte, cap_in_4k); - if (change_cap_mem_check(fd, cap_in_4k)) + printf("%dG %"PRIu64"B %"PRIu64" 4K\n", + cfg.capacity_in_gb, (uint64_t)cfg.cap_in_byte, (uint64_t)cap_in_4k); + + if (change_sanity_check(fd, cap_in_4k, &shrink)) { + printf("ScaleFlux change-capacity: fail\n"); return err; + } + + if (!cfg.force && shrink && !sfx_confirm_change("Changing Cap may irrevocably delete this device's data")) { + return 0; + } err = nvme_change_cap(fd, 0xffffffff, cap_in_4k); if (err < 0) @@ -731,20 +794,54 @@ static int change_cap(int argc, char **argv, struct command *cmd, struct plugin nvme_status_to_string(err), err); else { printf("ScaleFlux change-capacity: success\n"); - if(ioctl(fd, BLKRRPART) < 0) { - fprintf(stderr, "failed to re-read partition table\n"); - err = EFAULT; - } + ioctl(fd, BLKRRPART); } return err; } +static int sfx_verify_chr(int fd) +{ + static struct stat nvme_stat; + int err = fstat(fd, &nvme_stat); + + if (err < 0) { + perror("fstat"); + return errno; + } + if (!S_ISCHR(nvme_stat.st_mode)) { + fprintf(stderr, + "Error: requesting clean card on non-controller handle\n"); + return ENOTBLK; + } + return 0; +} + +static int sfx_clean_card(int fd) +{ + int ret; + + ret = sfx_verify_chr(fd); + if (ret) + return ret; + ret = ioctl(fd, NVME_IOCTL_CLR_CARD); + if (ret) + perror("Ioctl Fail."); + else + printf("ScaleFlux clean card success\n"); + + return ret; +} + char *sfx_feature_to_string(int feature) { switch (feature) { - case SFX_FEAT_ATOMIC: return "ATOMIC"; + case SFX_FEAT_ATOMIC: + return "ATOMIC"; + case SFX_FEAT_UP_P_CAP: + return "UPDATE_PROVISION_CAPACITY"; - default: return "Unknown"; + default: + return "Unknown"; } } @@ -752,27 +849,34 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl { int err = 0, fd; char *desc = "ScaleFlux internal set features\n" - "feature id 1: ATOMIC"; + "feature id 1: ATOMIC\n" + "value 0: Disable atomic write\n" + " 1: Enable atomic write"; const char *value = "new value of feature (required)"; const char *feature_id = "hex feature name (required)"; const char *namespace_id = "desired namespace"; + const char *force = "The \"I know what I'm doing\" flag, skip confirmation before sending command"; + struct nvme_id_ns ns; struct config { __u32 namespace_id; __u32 feature_id; __u32 value; + __u32 force; }; struct config cfg = { .namespace_id = 1, .feature_id = 0, .value = 0, + .force = 0, }; OPT_ARGS(opts) = { OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), OPT_UINT("feature-id", 'f', &cfg.feature_id, feature_id), - OPT_UINT("value", 'v', &cfg.value, value), + OPT_UINT("value", 'v', &cfg.value, value), + OPT_FLAG("force", 's', &cfg.force, force), OPT_END() }; @@ -786,7 +890,17 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl return EINVAL; } - if (cfg.feature_id == SFX_FEAT_ATOMIC) { + if (cfg.feature_id == SFX_FEAT_CLR_CARD) { + /*Warning for clean card*/ + if (!cfg.force && !sfx_confirm_change("Going to clean device's data, confirm umount fs and try again")) { + return 0; + } else { + return sfx_clean_card(fd); + } + + } + + if (cfg.feature_id == SFX_FEAT_ATOMIC && cfg.value != 0) { if (cfg.namespace_id != 0xffffffff) { err = nvme_identify_ns(fd, cfg.namespace_id, 0, &ns); if (err) { @@ -806,14 +920,25 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl return EFAULT; } } + } else if (cfg.feature_id == SFX_FEAT_UP_P_CAP) { + if (cfg.value <= 0) { + fprintf(stderr, "Invalid Param\n"); + return EINVAL; + } + + /*Warning for change pacp by GB*/ + if (!cfg.force && !sfx_confirm_change("Changing physical capacity may irrevocably delete this device's data")) { + return 0; + } } err = nvme_sfx_set_features(fd, cfg.namespace_id, cfg.feature_id, cfg.value); + if (err < 0) { perror("ScaleFlux-set-feature"); return errno; } else if (!err) { - printf("ScaleFlux set-feature:%02x (%s), value:%#08x\n", cfg.feature_id, + printf("ScaleFlux set-feature:%#02x (%s), value:%d\n", cfg.feature_id, sfx_feature_to_string(cfg.feature_id), cfg.value); } else if (err > 0) fprintf(stderr, "NVMe Status:%s(%x)\n", diff --git a/plugins/scaleflux/sfx-nvme.h b/plugins/scaleflux/sfx-nvme.h index daf9c33..8f14501 100644 --- a/plugins/scaleflux/sfx-nvme.h +++ b/plugins/scaleflux/sfx-nvme.h @@ -14,12 +14,10 @@ PLUGIN(NAME("sfx", "ScaleFlux vendor specific extensions"), ENTRY("query-cap", "Query current capacity info", query_cap_info) ENTRY("change-cap", "Dynamic change capacity", change_cap) ENTRY("set-feature", "Set a feature", sfx_set_feature) - ENTRY("get-feature", "get a feature", sfx_get_feature) + ENTRY("get-feature", "Get a feature", sfx_get_feature) ) ); #endif #include "define_cmd.h" - - |