| File: | .build-ci/../plugins/scaleflux/sfx-nvme.c |
| Warning: | line 1597, column 23 The left operand of '/' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | |||
| 2 | #include <fcntl.h> | |||
| 3 | #include <errno(*__errno_location ()).h> | |||
| 4 | #include <stdio.h> | |||
| 5 | #include <stdlib.h> | |||
| 6 | #include <string.h> | |||
| 7 | #include <unistd.h> | |||
| 8 | #include <linux1/fs.h> | |||
| 9 | #include <inttypes.h> | |||
| 10 | #include <asm/byteorder.h> | |||
| 11 | #include <sys/sysinfo.h> | |||
| 12 | #include <sys/stat.h> | |||
| 13 | #include <sys/types.h> | |||
| 14 | #include <sys/ioctl.h> | |||
| 15 | #include <dirent.h> | |||
| 16 | #include <time.h> | |||
| 17 | ||||
| 18 | #include <libnvme.h> | |||
| 19 | ||||
| 20 | #include "common.h" | |||
| 21 | #include "nvme-cmds.h" | |||
| 22 | #include "nvme-print.h" | |||
| 23 | #include "nvme.h" | |||
| 24 | #include "plugin.h" | |||
| 25 | #include "util/cleanup.h" | |||
| 26 | #include "util/types.h" | |||
| 27 | ||||
| 28 | #define CREATE_CMD | |||
| 29 | #include "sfx-nvme.h" | |||
| 30 | #include "sfx-types.h" | |||
| 31 | ||||
| 32 | #define SFX_PAGE_SHIFT12 12 | |||
| 33 | #define SECTOR_SHIFT9 9 | |||
| 34 | ||||
| 35 | #define SFX_GET_FREESPACE(((2U|1U) << (((0 +8)+8)+14)) | ((('N')) << (0 +8 )) | (((0x240)) << 0) | ((((sizeof(struct sfx_freespace_ctx )))) << ((0 +8)+8))) _IOWR('N', 0x240, struct sfx_freespace_ctx)(((2U|1U) << (((0 +8)+8)+14)) | ((('N')) << (0 +8 )) | (((0x240)) << 0) | ((((sizeof(struct sfx_freespace_ctx )))) << ((0 +8)+8))) | |||
| 36 | #define NVME_IOCTL_CLR_CARD(((0U) << (((0 +8)+8)+14)) | ((('N')) << (0 +8)) | (((0x47)) << 0) | ((0) << ((0 +8)+8))) _IO('N', 0x47)(((0U) << (((0 +8)+8)+14)) | ((('N')) << (0 +8)) | (((0x47)) << 0) | ((0) << ((0 +8)+8))) | |||
| 37 | ||||
| 38 | //See IDEMA LBA1-03 | |||
| 39 | #define IDEMA_CAP(exp_GB)(((__u64)exp_GB - 50ULL) * 1953504ULL + 97696368ULL) (((__u64)exp_GB - 50ULL) * 1953504ULL + 97696368ULL) | |||
| 40 | #define IDEMA_CAP2GB(exp_sector)(((__u64)exp_sector - 97696368ULL) / 1953504ULL + 50ULL) (((__u64)exp_sector - 97696368ULL) / 1953504ULL + 50ULL) | |||
| 41 | #define IDEMA_CAP2GB_LDS(exp_sector)(((__u64)exp_sector - 12212046ULL) / 244188ULL + 50ULL) (((__u64)exp_sector - 12212046ULL) / 244188ULL + 50ULL) | |||
| 42 | ||||
| 43 | #define VANDA_MAJOR_IDX0 0 | |||
| 44 | #define VANDA_MINOR_IDX0 0 | |||
| 45 | ||||
| 46 | #define MYRTLE_MAJOR_IDX4 4 | |||
| 47 | #define MYRTLE_MINOR_IDX1 1 | |||
| 48 | ||||
| 49 | ||||
| 50 | ||||
| 51 | int nvme_query_cap(struct libnvme_transport_handle *hdl, __u32 nsid, __u32 data_len, void *data) | |||
| 52 | { | |||
| 53 | int rc = 0; | |||
| 54 | struct libnvme_passthru_cmd cmd = { | |||
| 55 | .opcode = nvme_admin_query_cap_info, | |||
| 56 | .nsid = nsid, | |||
| 57 | .addr = (__u64)(uintptr_t) data, | |||
| 58 | .data_len = data_len, | |||
| 59 | }; | |||
| 60 | ||||
| 61 | rc = ioctl(libnvme_transport_handle_get_fd(hdl), SFX_GET_FREESPACE(((2U|1U) << (((0 +8)+8)+14)) | ((('N')) << (0 +8 )) | (((0x240)) << 0) | ((((sizeof(struct sfx_freespace_ctx )))) << ((0 +8)+8))), data); | |||
| 62 | return rc ? libnvme_exec_admin_passthru(hdl, &cmd) : 0; | |||
| 63 | } | |||
| 64 | ||||
| 65 | int nvme_change_cap(struct libnvme_transport_handle *hdl, __u32 nsid, __u64 capacity) | |||
| 66 | { | |||
| 67 | struct libnvme_passthru_cmd cmd = { | |||
| 68 | .opcode = nvme_admin_change_cap, | |||
| 69 | .nsid = nsid, | |||
| 70 | .cdw10 = (capacity & 0xffffffff), | |||
| 71 | .cdw11 = (capacity >> 32), | |||
| 72 | }; | |||
| 73 | ||||
| 74 | return libnvme_exec_admin_passthru(hdl, &cmd); | |||
| 75 | } | |||
| 76 | ||||
| 77 | int nvme_sfx_set_features(struct libnvme_transport_handle *hdl, __u32 nsid, __u32 fid, __u32 value) | |||
| 78 | { | |||
| 79 | struct libnvme_passthru_cmd cmd = { | |||
| 80 | .opcode = nvme_admin_sfx_set_features, | |||
| 81 | .nsid = nsid, | |||
| 82 | .cdw10 = fid, | |||
| 83 | .cdw11 = value, | |||
| 84 | }; | |||
| 85 | ||||
| 86 | return libnvme_exec_admin_passthru(hdl, &cmd); | |||
| 87 | } | |||
| 88 | ||||
| 89 | int nvme_sfx_get_features(struct libnvme_transport_handle *hdl, __u32 nsid, __u32 fid, __u32 *result) | |||
| 90 | { | |||
| 91 | int err = 0; | |||
| 92 | struct libnvme_passthru_cmd cmd = { | |||
| 93 | .opcode = nvme_admin_sfx_get_features, | |||
| 94 | .nsid = nsid, | |||
| 95 | .cdw10 = fid, | |||
| 96 | }; | |||
| 97 | ||||
| 98 | err = libnvme_exec_admin_passthru(hdl, &cmd); | |||
| 99 | if (!err && result) | |||
| 100 | *result = cmd.result; | |||
| 101 | ||||
| 102 | return err; | |||
| 103 | } | |||
| 104 | ||||
| 105 | #ifdef CONFIG_JSONC | |||
| 106 | static void show_sfx_smart_log_jsn(struct nvme_additional_smart_log *smart, | |||
| 107 | unsigned int nsid, const char *devname) | |||
| 108 | { | |||
| 109 | struct json_object *root, *entry_stats, *dev_stats, *multi; | |||
| 110 | ||||
| 111 | root = json_create_object()json_object_new_object(); | |||
| 112 | json_object_add_value_string(root, "ScaleFlux Smart log", devname); | |||
| 113 | ||||
| 114 | dev_stats = json_create_object()json_object_new_object(); | |||
| 115 | ||||
| 116 | entry_stats = json_create_object()json_object_new_object(); | |||
| 117 | json_object_add_value_int(entry_stats, "normalized", smart->program_fail_cnt.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->program_fail_cnt.norm)); | |||
| 118 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->program_fail_cnt.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->program_fail_cnt.raw))); | |||
| 119 | json_object_add_value_object(dev_stats, "program_fail_count", entry_stats)json_object_object_add(dev_stats, "program_fail_count", entry_stats ); | |||
| 120 | ||||
| 121 | entry_stats = json_create_object()json_object_new_object(); | |||
| 122 | json_object_add_value_int(entry_stats, "normalized", smart->erase_fail_cnt.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->erase_fail_cnt.norm)); | |||
| 123 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->erase_fail_cnt.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->erase_fail_cnt.raw))); | |||
| 124 | json_object_add_value_object(dev_stats, "erase_fail_count", entry_stats)json_object_object_add(dev_stats, "erase_fail_count", entry_stats ); | |||
| 125 | ||||
| 126 | entry_stats = json_create_object()json_object_new_object(); | |||
| 127 | json_object_add_value_int(entry_stats, "normalized", smart->wear_leveling_cnt.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->wear_leveling_cnt.norm)); | |||
| 128 | multi = json_create_object()json_object_new_object(); | |||
| 129 | json_object_add_value_int(multi, "min", le16_to_cpu(smart->wear_leveling_cnt.wear_level.min))json_object_object_add(multi, "min", json_object_new_int(le16_to_cpu (smart->wear_leveling_cnt.wear_level.min))); | |||
| 130 | json_object_add_value_int(multi, "max", le16_to_cpu(smart->wear_leveling_cnt.wear_level.max))json_object_object_add(multi, "max", json_object_new_int(le16_to_cpu (smart->wear_leveling_cnt.wear_level.max))); | |||
| 131 | json_object_add_value_int(multi, "avg", le16_to_cpu(smart->wear_leveling_cnt.wear_level.avg))json_object_object_add(multi, "avg", json_object_new_int(le16_to_cpu (smart->wear_leveling_cnt.wear_level.avg))); | |||
| 132 | json_object_add_value_object(entry_stats, "raw", multi)json_object_object_add(entry_stats, "raw", multi); | |||
| 133 | json_object_add_value_object(dev_stats, "wear_leveling", entry_stats)json_object_object_add(dev_stats, "wear_leveling", entry_stats ); | |||
| 134 | ||||
| 135 | entry_stats = json_create_object()json_object_new_object(); | |||
| 136 | json_object_add_value_int(entry_stats, "normalized", smart->e2e_err_cnt.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->e2e_err_cnt.norm)); | |||
| 137 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->e2e_err_cnt.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->e2e_err_cnt.raw))); | |||
| 138 | json_object_add_value_object(dev_stats, "end_to_end_error_detection_count", entry_stats)json_object_object_add(dev_stats, "end_to_end_error_detection_count" , entry_stats); | |||
| 139 | ||||
| 140 | entry_stats = json_create_object()json_object_new_object(); | |||
| 141 | json_object_add_value_int(entry_stats, "normalized", smart->crc_err_cnt.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->crc_err_cnt.norm)); | |||
| 142 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->crc_err_cnt.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->crc_err_cnt.raw))); | |||
| 143 | json_object_add_value_object(dev_stats, "crc_error_count", entry_stats)json_object_object_add(dev_stats, "crc_error_count", entry_stats ); | |||
| 144 | ||||
| 145 | entry_stats = json_create_object()json_object_new_object(); | |||
| 146 | json_object_add_value_int(entry_stats, "normalized", smart->timed_workload_media_wear.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->timed_workload_media_wear.norm)); | |||
| 147 | json_object_add_value_float(entry_stats, "raw", ((float)int48_to_long(smart->timed_workload_media_wear.raw)) / 1024)json_object_object_add(entry_stats, "raw", json_object_new_double (((float)int48_to_long(smart->timed_workload_media_wear.raw )) / 1024)); | |||
| 148 | json_object_add_value_object(dev_stats, "timed_workload_media_wear", entry_stats)json_object_object_add(dev_stats, "timed_workload_media_wear" , entry_stats); | |||
| 149 | ||||
| 150 | entry_stats = json_create_object()json_object_new_object(); | |||
| 151 | json_object_add_value_int(entry_stats, "normalized", smart->timed_workload_host_reads.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->timed_workload_host_reads.norm)); | |||
| 152 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->timed_workload_host_reads.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->timed_workload_host_reads.raw))); | |||
| 153 | json_object_add_value_object(dev_stats, "timed_workload_host_reads", entry_stats)json_object_object_add(dev_stats, "timed_workload_host_reads" , entry_stats); | |||
| 154 | ||||
| 155 | entry_stats = json_create_object()json_object_new_object(); | |||
| 156 | json_object_add_value_int(entry_stats, "normalized", smart->timed_workload_timer.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->timed_workload_timer.norm)); | |||
| 157 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->timed_workload_timer.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->timed_workload_timer.raw))); | |||
| 158 | json_object_add_value_object(dev_stats, "timed_workload_timer", entry_stats)json_object_object_add(dev_stats, "timed_workload_timer", entry_stats ); | |||
| 159 | ||||
| 160 | entry_stats = json_create_object()json_object_new_object(); | |||
| 161 | json_object_add_value_int(entry_stats, "normalized", smart->thermal_throttle_status.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->thermal_throttle_status.norm)); | |||
| 162 | multi = json_create_object()json_object_new_object(); | |||
| 163 | json_object_add_value_int(multi, "pct", smart->thermal_throttle_status.thermal_throttle.pct)json_object_object_add(multi, "pct", json_object_new_int(smart ->thermal_throttle_status.thermal_throttle.pct)); | |||
| 164 | json_object_add_value_int(multi, "cnt", smart->thermal_throttle_status.thermal_throttle.count)json_object_object_add(multi, "cnt", json_object_new_int(smart ->thermal_throttle_status.thermal_throttle.count)); | |||
| 165 | json_object_add_value_object(entry_stats, "raw", multi)json_object_object_add(entry_stats, "raw", multi); | |||
| 166 | json_object_add_value_object(dev_stats, "thermal_throttle_status", entry_stats)json_object_object_add(dev_stats, "thermal_throttle_status", entry_stats ); | |||
| 167 | ||||
| 168 | entry_stats = json_create_object()json_object_new_object(); | |||
| 169 | json_object_add_value_int(entry_stats, "normalized", smart->retry_buffer_overflow_cnt.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->retry_buffer_overflow_cnt.norm)); | |||
| 170 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->retry_buffer_overflow_cnt.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->retry_buffer_overflow_cnt.raw))); | |||
| 171 | json_object_add_value_object(dev_stats, "retry_buffer_overflow_count", entry_stats)json_object_object_add(dev_stats, "retry_buffer_overflow_count" , entry_stats); | |||
| 172 | ||||
| 173 | entry_stats = json_create_object()json_object_new_object(); | |||
| 174 | json_object_add_value_int(entry_stats, "normalized", smart->pll_lock_loss_cnt.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->pll_lock_loss_cnt.norm)); | |||
| 175 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->pll_lock_loss_cnt.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->pll_lock_loss_cnt.raw))); | |||
| 176 | json_object_add_value_object(dev_stats, "pll_lock_loss_count", entry_stats)json_object_object_add(dev_stats, "pll_lock_loss_count", entry_stats ); | |||
| 177 | ||||
| 178 | entry_stats = json_create_object()json_object_new_object(); | |||
| 179 | json_object_add_value_int(entry_stats, "normalized", smart->nand_bytes_written.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->nand_bytes_written.norm)); | |||
| 180 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->nand_bytes_written.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->nand_bytes_written.raw))); | |||
| 181 | json_object_add_value_object(dev_stats, "nand_bytes_written", entry_stats)json_object_object_add(dev_stats, "nand_bytes_written", entry_stats ); | |||
| 182 | ||||
| 183 | entry_stats = json_create_object()json_object_new_object(); | |||
| 184 | json_object_add_value_int(entry_stats, "normalized", smart->host_bytes_written.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->host_bytes_written.norm)); | |||
| 185 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->host_bytes_written.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->host_bytes_written.raw))); | |||
| 186 | json_object_add_value_object(dev_stats, "host_bytes_written", entry_stats)json_object_object_add(dev_stats, "host_bytes_written", entry_stats ); | |||
| 187 | ||||
| 188 | entry_stats = json_create_object()json_object_new_object(); | |||
| 189 | json_object_add_value_int(entry_stats, "normalized", smart->raid_recover_cnt.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->raid_recover_cnt.norm)); | |||
| 190 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->raid_recover_cnt.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->raid_recover_cnt.raw))); | |||
| 191 | json_object_add_value_object(dev_stats, "raid_recover_cnt", entry_stats)json_object_object_add(dev_stats, "raid_recover_cnt", entry_stats ); | |||
| 192 | ||||
| 193 | entry_stats = json_create_object()json_object_new_object(); | |||
| 194 | json_object_add_value_int(entry_stats, "normalized", smart->prog_timeout_cnt.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->prog_timeout_cnt.norm)); | |||
| 195 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->prog_timeout_cnt.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->prog_timeout_cnt.raw))); | |||
| 196 | json_object_add_value_object(dev_stats, "prog_timeout_cnt", entry_stats)json_object_object_add(dev_stats, "prog_timeout_cnt", entry_stats ); | |||
| 197 | ||||
| 198 | entry_stats = json_create_object()json_object_new_object(); | |||
| 199 | json_object_add_value_int(entry_stats, "normalized", smart->erase_timeout_cnt.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->erase_timeout_cnt.norm)); | |||
| 200 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->erase_timeout_cnt.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->erase_timeout_cnt.raw))); | |||
| 201 | json_object_add_value_object(dev_stats, "erase_timeout_cnt", entry_stats)json_object_object_add(dev_stats, "erase_timeout_cnt", entry_stats ); | |||
| 202 | ||||
| 203 | entry_stats = json_create_object()json_object_new_object(); | |||
| 204 | json_object_add_value_int(entry_stats, "normalized", smart->read_timeout_cnt.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->read_timeout_cnt.norm)); | |||
| 205 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->read_timeout_cnt.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->read_timeout_cnt.raw))); | |||
| 206 | json_object_add_value_object(dev_stats, "read_timeout_cnt", entry_stats)json_object_object_add(dev_stats, "read_timeout_cnt", entry_stats ); | |||
| 207 | ||||
| 208 | entry_stats = json_create_object()json_object_new_object(); | |||
| 209 | json_object_add_value_int(entry_stats, "normalized", smart->read_ecc_cnt.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->read_ecc_cnt.norm)); | |||
| 210 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->read_ecc_cnt.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->read_ecc_cnt.raw))); | |||
| 211 | json_object_add_value_object(dev_stats, "read_ecc_cnt", entry_stats)json_object_object_add(dev_stats, "read_ecc_cnt", entry_stats ); | |||
| 212 | ||||
| 213 | entry_stats = json_create_object()json_object_new_object(); | |||
| 214 | json_object_add_value_int(entry_stats, "normalized", smart->non_media_crc_err_cnt.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->non_media_crc_err_cnt.norm)); | |||
| 215 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->non_media_crc_err_cnt.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->non_media_crc_err_cnt.raw))); | |||
| 216 | json_object_add_value_object(dev_stats, "non_media_crc_err_cnt", entry_stats)json_object_object_add(dev_stats, "non_media_crc_err_cnt", entry_stats ); | |||
| 217 | ||||
| 218 | entry_stats = json_create_object()json_object_new_object(); | |||
| 219 | json_object_add_value_int(entry_stats, "normalized", smart->compression_path_err_cnt.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->compression_path_err_cnt.norm)); | |||
| 220 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->compression_path_err_cnt.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->compression_path_err_cnt.raw))); | |||
| 221 | json_object_add_value_object(dev_stats, "compression_path_err_cnt", entry_stats)json_object_object_add(dev_stats, "compression_path_err_cnt", entry_stats); | |||
| 222 | ||||
| 223 | entry_stats = json_create_object()json_object_new_object(); | |||
| 224 | json_object_add_value_int(entry_stats, "normalized", smart->out_of_space_flag.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->out_of_space_flag.norm)); | |||
| 225 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->out_of_space_flag.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->out_of_space_flag.raw))); | |||
| 226 | json_object_add_value_object(dev_stats, "out_of_space_flag", entry_stats)json_object_object_add(dev_stats, "out_of_space_flag", entry_stats ); | |||
| 227 | ||||
| 228 | entry_stats = json_create_object()json_object_new_object(); | |||
| 229 | json_object_add_value_int(entry_stats, "normalized", smart->physical_usage_ratio.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->physical_usage_ratio.norm)); | |||
| 230 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->physical_usage_ratio.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->physical_usage_ratio.raw))); | |||
| 231 | json_object_add_value_object(dev_stats, "physical_usage_ratio", entry_stats)json_object_object_add(dev_stats, "physical_usage_ratio", entry_stats ); | |||
| 232 | ||||
| 233 | entry_stats = json_create_object()json_object_new_object(); | |||
| 234 | json_object_add_value_int(entry_stats, "normalized", smart->grown_bb.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->grown_bb.norm)); | |||
| 235 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->grown_bb.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->grown_bb.raw))); | |||
| 236 | json_object_add_value_object(dev_stats, "grown_bb", entry_stats)json_object_object_add(dev_stats, "grown_bb", entry_stats); | |||
| 237 | ||||
| 238 | json_object_add_value_object(root, "Device stats", dev_stats)json_object_object_add(root, "Device stats", dev_stats); | |||
| 239 | ||||
| 240 | json_print_object(root, NULL)printf("%s", json_object_to_json_string_ext(root, (1 << 1) | (1 << 4))); | |||
| 241 | printf("\n"); | |||
| 242 | json_free_object(root)json_object_put(root); | |||
| 243 | } | |||
| 244 | #else /* CONFIG_JSONC */ | |||
| 245 | #define show_sfx_smart_log_jsn(smart, nsid, devname) | |||
| 246 | #endif /* CONFIG_JSONC */ | |||
| 247 | ||||
| 248 | static void show_sfx_smart_log(struct nvme_additional_smart_log *smart, | |||
| 249 | unsigned int nsid, const char *devname) | |||
| 250 | { | |||
| 251 | printf("Additional Smart Log for ScaleFlux device:%s namespace-id:%x\n", | |||
| 252 | devname, nsid); | |||
| 253 | printf("key normalized raw\n"); | |||
| 254 | printf("program_fail_count : %3d%% %"PRIu64"l" "u""\n", | |||
| 255 | smart->program_fail_cnt.norm, | |||
| 256 | int48_to_long(smart->program_fail_cnt.raw)); | |||
| 257 | printf("erase_fail_count : %3d%% %"PRIu64"l" "u""\n", | |||
| 258 | smart->erase_fail_cnt.norm, | |||
| 259 | int48_to_long(smart->erase_fail_cnt.raw)); | |||
| 260 | printf("wear_leveling : %3d%% min: %u, max: %u, avg: %u\n", | |||
| 261 | smart->wear_leveling_cnt.norm, | |||
| 262 | le16_to_cpu(smart->wear_leveling_cnt.wear_level.min), | |||
| 263 | le16_to_cpu(smart->wear_leveling_cnt.wear_level.max), | |||
| 264 | le16_to_cpu(smart->wear_leveling_cnt.wear_level.avg)); | |||
| 265 | printf("end_to_end_error_detection_count: %3d%% %"PRIu64"l" "u""\n", | |||
| 266 | smart->e2e_err_cnt.norm, | |||
| 267 | int48_to_long(smart->e2e_err_cnt.raw)); | |||
| 268 | printf("crc_error_count : %3d%% %"PRIu64"l" "u""\n", | |||
| 269 | smart->crc_err_cnt.norm, | |||
| 270 | int48_to_long(smart->crc_err_cnt.raw)); | |||
| 271 | printf("timed_workload_media_wear : %3d%% %.3f%%\n", | |||
| 272 | smart->timed_workload_media_wear.norm, | |||
| 273 | ((float)int48_to_long(smart->timed_workload_media_wear.raw)) / 1024); | |||
| 274 | printf("timed_workload_host_reads : %3d%% %"PRIu64"l" "u""%%\n", | |||
| 275 | smart->timed_workload_host_reads.norm, | |||
| 276 | int48_to_long(smart->timed_workload_host_reads.raw)); | |||
| 277 | printf("timed_workload_timer : %3d%% %"PRIu64"l" "u"" min\n", | |||
| 278 | smart->timed_workload_timer.norm, | |||
| 279 | int48_to_long(smart->timed_workload_timer.raw)); | |||
| 280 | printf("thermal_throttle_status : %3d%% %u%%, cnt: %u\n", | |||
| 281 | smart->thermal_throttle_status.norm, | |||
| 282 | smart->thermal_throttle_status.thermal_throttle.pct, | |||
| 283 | smart->thermal_throttle_status.thermal_throttle.count); | |||
| 284 | printf("retry_buffer_overflow_count : %3d%% %"PRIu64"l" "u""\n", | |||
| 285 | smart->retry_buffer_overflow_cnt.norm, | |||
| 286 | int48_to_long(smart->retry_buffer_overflow_cnt.raw)); | |||
| 287 | printf("pll_lock_loss_count : %3d%% %"PRIu64"l" "u""\n", | |||
| 288 | smart->pll_lock_loss_cnt.norm, | |||
| 289 | int48_to_long(smart->pll_lock_loss_cnt.raw)); | |||
| 290 | printf("nand_bytes_written : %3d%% sectors: %"PRIu64"l" "u""\n", | |||
| 291 | smart->nand_bytes_written.norm, | |||
| 292 | int48_to_long(smart->nand_bytes_written.raw)); | |||
| 293 | printf("host_bytes_written : %3d%% sectors: %"PRIu64"l" "u""\n", | |||
| 294 | smart->host_bytes_written.norm, | |||
| 295 | int48_to_long(smart->host_bytes_written.raw)); | |||
| 296 | printf("raid_recover_cnt : %3d%% %"PRIu64"l" "u""\n", | |||
| 297 | smart->raid_recover_cnt.norm, | |||
| 298 | int48_to_long(smart->raid_recover_cnt.raw)); | |||
| 299 | printf("read_ecc_cnt : %3d%% %"PRIu64"l" "u""\n", | |||
| 300 | smart->read_ecc_cnt.norm, | |||
| 301 | int48_to_long(smart->read_ecc_cnt.raw)); | |||
| 302 | printf("prog_timeout_cnt : %3d%% %"PRIu64"l" "u""\n", | |||
| 303 | smart->prog_timeout_cnt.norm, | |||
| 304 | int48_to_long(smart->prog_timeout_cnt.raw)); | |||
| 305 | printf("erase_timeout_cnt : %3d%% %"PRIu64"l" "u""\n", | |||
| 306 | smart->erase_timeout_cnt.norm, | |||
| 307 | int48_to_long(smart->erase_timeout_cnt.raw)); | |||
| 308 | printf("read_timeout_cnt : %3d%% %"PRIu64"l" "u""\n", | |||
| 309 | smart->read_timeout_cnt.norm, | |||
| 310 | int48_to_long(smart->read_timeout_cnt.raw)); | |||
| 311 | printf("non_media_crc_err_cnt : %3d%% %" PRIu64"l" "u" "\n", | |||
| 312 | smart->non_media_crc_err_cnt.norm, | |||
| 313 | int48_to_long(smart->non_media_crc_err_cnt.raw)); | |||
| 314 | printf("compression_path_err_cnt : %3d%% %" PRIu64"l" "u" "\n", | |||
| 315 | smart->compression_path_err_cnt.norm, | |||
| 316 | int48_to_long(smart->compression_path_err_cnt.raw)); | |||
| 317 | printf("out_of_space_flag : %3d%% %" PRIu64"l" "u" "\n", | |||
| 318 | smart->out_of_space_flag.norm, | |||
| 319 | int48_to_long(smart->out_of_space_flag.raw)); | |||
| 320 | printf("phy_capacity_used_ratio : %3d%% %" PRIu64"l" "u" "\n", | |||
| 321 | smart->physical_usage_ratio.norm, | |||
| 322 | int48_to_long(smart->physical_usage_ratio.raw)); | |||
| 323 | printf("grown_bb_count : %3d%% %" PRIu64"l" "u" "\n", | |||
| 324 | smart->grown_bb.norm, int48_to_long(smart->grown_bb.raw)); | |||
| 325 | ||||
| 326 | ||||
| 327 | } | |||
| 328 | ||||
| 329 | static int get_additional_smart_log(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 330 | { | |||
| 331 | struct nvme_additional_smart_log smart_log; | |||
| 332 | char *desc = | |||
| 333 | "Get ScaleFlux vendor specific additional smart log (optionally, for the specified namespace), and show it."; | |||
| 334 | const char *namespace = "(optional) desired namespace"; | |||
| 335 | const char *raw = "dump output in binary format"; | |||
| 336 | #ifdef CONFIG_JSONC | |||
| 337 | const char *json = "Dump output in json format"; | |||
| 338 | #endif /* CONFIG_JSONC */ | |||
| 339 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 340 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 341 | nvme_print_flags_t flags; | |||
| 342 | struct config { | |||
| 343 | __u32 namespace_id; | |||
| 344 | bool_Bool raw_binary; | |||
| 345 | bool_Bool json; | |||
| 346 | }; | |||
| 347 | int err; | |||
| 348 | ||||
| 349 | struct config cfg = { | |||
| 350 | .namespace_id = NVME_NSID_ALL, | |||
| 351 | }; | |||
| 352 | ||||
| 353 | NVME_ARGS(opts,struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"namespace-id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace, 0, }, {"raw-binary", 'b', ((void*)0), CFG_FLAG , &cfg.raw_binary, 0, raw, 0, }, {"json", 'j', ((void*)0) , CFG_FLAG, &cfg.json, 0, json, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options", 0, ((void *)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &nvme_args. verbose, 0, "Increase output verbosity", 0, }, {"output-format" , 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 354 | OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace),struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"namespace-id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace, 0, }, {"raw-binary", 'b', ((void*)0), CFG_FLAG , &cfg.raw_binary, 0, raw, 0, }, {"json", 'j', ((void*)0) , CFG_FLAG, &cfg.json, 0, json, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options", 0, ((void *)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &nvme_args. verbose, 0, "Increase output verbosity", 0, }, {"output-format" , 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 355 | OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"namespace-id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace, 0, }, {"raw-binary", 'b', ((void*)0), CFG_FLAG , &cfg.raw_binary, 0, raw, 0, }, {"json", 'j', ((void*)0) , CFG_FLAG, &cfg.json, 0, json, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options", 0, ((void *)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &nvme_args. verbose, 0, "Increase output verbosity", 0, }, {"output-format" , 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 356 | OPT_FLAG_JSON("json", 'j', &cfg.json, json))struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"namespace-id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace, 0, }, {"raw-binary", 'b', ((void*)0), CFG_FLAG , &cfg.raw_binary, 0, raw, 0, }, {"json", 'j', ((void*)0) , CFG_FLAG, &cfg.json, 0, json, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options", 0, ((void *)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &nvme_args. verbose, 0, "Increase output verbosity", 0, }, {"output-format" , 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } }; | |||
| 357 | ||||
| 358 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 359 | if (err) | |||
| 360 | return err; | |||
| 361 | ||||
| 362 | err = validate_output_format(nvme_args.output_format, &flags); | |||
| 363 | if (err < 0) { | |||
| 364 | nvme_show_error("Invalid output format")nvme_show_message(1, "Invalid output format"); | |||
| 365 | return err; | |||
| 366 | } | |||
| 367 | ||||
| 368 | err = nvme_get_nsid_log(hdl, cfg.namespace_id, false0, 0xca, | |||
| 369 | (void *)&smart_log, sizeof(smart_log)); | |||
| 370 | if (!err) { | |||
| 371 | if (flags & JSON || cfg.json) | |||
| 372 | show_sfx_smart_log_jsn(&smart_log, cfg.namespace_id, | |||
| 373 | libnvme_transport_handle_get_name(hdl)); | |||
| 374 | else if (!cfg.raw_binary) | |||
| 375 | show_sfx_smart_log(&smart_log, cfg.namespace_id, | |||
| 376 | libnvme_transport_handle_get_name(hdl)); | |||
| 377 | else | |||
| 378 | d_raw((unsigned char *)&smart_log, sizeof(smart_log)); | |||
| 379 | } else if (err > 0) { | |||
| 380 | nvme_show_status(err); | |||
| 381 | } | |||
| 382 | return err; | |||
| 383 | } | |||
| 384 | ||||
| 385 | static void show_lat_stats_vanda(struct sfx_lat_stats_vanda *stats, int write) | |||
| 386 | { | |||
| 387 | int i; | |||
| 388 | ||||
| 389 | printf("ScaleFlux IO %s Command Latency Statistics\n", write ? "Write" : "Read"); | |||
| 390 | printf("-------------------------------------\n"); | |||
| 391 | printf("Major Revision : %u\n", stats->maj); | |||
| 392 | printf("Minor Revision : %u\n", stats->min); | |||
| 393 | ||||
| 394 | printf("\nGroup 1: Range is 0-1ms, step is 32us\n"); | |||
| 395 | for (i = 0; i < 32; i++) | |||
| 396 | printf("Bucket %2d: %u\n", i, stats->bucket_1[i]); | |||
| 397 | ||||
| 398 | printf("\nGroup 2: Range is 1-32ms, step is 1ms\n"); | |||
| 399 | for (i = 0; i < 31; i++) | |||
| 400 | printf("Bucket %2d: %u\n", i, stats->bucket_2[i]); | |||
| 401 | ||||
| 402 | printf("\nGroup 3: Range is 32ms-1s, step is 32ms:\n"); | |||
| 403 | for (i = 0; i < 31; i++) | |||
| 404 | printf("Bucket %2d: %u\n", i, stats->bucket_3[i]); | |||
| 405 | ||||
| 406 | printf("\nGroup 4: Range is 1s-2s:\n"); | |||
| 407 | printf("Bucket %2d: %u\n", 0, stats->bucket_4[0]); | |||
| 408 | ||||
| 409 | printf("\nGroup 5: Range is 2s-4s:\n"); | |||
| 410 | printf("Bucket %2d: %u\n", 0, stats->bucket_5[0]); | |||
| 411 | ||||
| 412 | printf("\nGroup 6: Range is 4s+:\n"); | |||
| 413 | printf("Bucket %2d: %u\n", 0, stats->bucket_6[0]); | |||
| 414 | } | |||
| 415 | ||||
| 416 | static void show_lat_stats_myrtle(struct sfx_lat_stats_myrtle *stats, int write) | |||
| 417 | { | |||
| 418 | int i; | |||
| 419 | ||||
| 420 | printf("ScaleFlux IO %s Command Latency Statistics\n", write ? "Write" : "Read"); | |||
| 421 | printf("-------------------------------------\n"); | |||
| 422 | printf("Major Revision : %u\n", stats->maj); | |||
| 423 | printf("Minor Revision : %u\n", stats->min); | |||
| 424 | ||||
| 425 | printf("\nGroup 1: Range is 0us~63us, step 1us\n"); | |||
| 426 | for (i = 0; i < 64; i++) | |||
| 427 | printf("Bucket %2d: %u\n", i, stats->bucket_1[i]); | |||
| 428 | ||||
| 429 | printf("\nGroup 2: Range is 63us~127us, step 1us\n"); | |||
| 430 | for (i = 0; i < 64; i++) | |||
| 431 | printf("Bucket %2d: %u\n", i, stats->bucket_2[i]); | |||
| 432 | ||||
| 433 | printf("\nGroup 3: Range is 127us~255us, step 2us\n"); | |||
| 434 | for (i = 0; i < 64; i++) | |||
| 435 | printf("Bucket %2d: %u\n", i, stats->bucket_3[i]); | |||
| 436 | ||||
| 437 | printf("\nGroup 4: Range is 255us~510us, step 4us\n"); | |||
| 438 | for (i = 0; i < 64; i++) | |||
| 439 | printf("Bucket %2d: %u\n", i, stats->bucket_4[i]); | |||
| 440 | ||||
| 441 | printf("\nGroup 5: Range is 510us~1.02ms step\n"); | |||
| 442 | for (i = 0; i < 64; i++) | |||
| 443 | printf("Bucket %2d: %u\n", i, stats->bucket_5[i]); | |||
| 444 | ||||
| 445 | printf("\nGroup 6: Range is 1.02ms~2.04ms step 16us\n"); | |||
| 446 | for (i = 0; i < 64; i++) | |||
| 447 | printf("Bucket %2d: %u\n", i, stats->bucket_6[i]); | |||
| 448 | ||||
| 449 | printf("\nGroup 7: Range is 2.04ms~4.08ms step 32us\n"); | |||
| 450 | for (i = 0; i < 64; i++) | |||
| 451 | printf("Bucket %2d: %u\n", i, stats->bucket_7[i]); | |||
| 452 | ||||
| 453 | printf("\nGroup 8: Range is 4.08ms~8.16ms step 64us\n"); | |||
| 454 | for (i = 0; i < 64; i++) | |||
| 455 | printf("Bucket %2d: %u\n", i, stats->bucket_8[i]); | |||
| 456 | ||||
| 457 | printf("\nGroup 9: Range is 8.16ms~16.32ms step 128us\n"); | |||
| 458 | for (i = 0; i < 64; i++) | |||
| 459 | printf("Bucket %2d: %u\n", i, stats->bucket_9[i]); | |||
| 460 | ||||
| 461 | printf("\nGroup 10: Range is 16.32ms~32.64ms step 256us\n"); | |||
| 462 | for (i = 0; i < 64; i++) | |||
| 463 | printf("Bucket %2d: %u\n", i, stats->bucket_10[i]); | |||
| 464 | ||||
| 465 | printf("\nGroup 11: Range is 32.64ms~65.28ms step 512us\n"); | |||
| 466 | for (i = 0; i < 64; i++) | |||
| 467 | printf("Bucket %2d: %u\n", i, stats->bucket_11[i]); | |||
| 468 | ||||
| 469 | printf("\nGroup 12: Range is 65.28ms~130.56ms step 1.024ms\n"); | |||
| 470 | for (i = 0; i < 64; i++) | |||
| 471 | printf("Bucket %2d: %u\n", i, stats->bucket_12[i]); | |||
| 472 | ||||
| 473 | printf("\nGroup 13: Range is 130.56ms~261.12ms step 2.048ms\n"); | |||
| 474 | for (i = 0; i < 64; i++) | |||
| 475 | printf("Bucket %2d: %u\n", i, stats->bucket_13[i]); | |||
| 476 | ||||
| 477 | printf("\nGroup 14: Range is 261.12ms~522.24ms step 4.096ms\n"); | |||
| 478 | for (i = 0; i < 64; i++) | |||
| 479 | printf("Bucket %2d: %u\n", i, stats->bucket_14[i]); | |||
| 480 | ||||
| 481 | printf("\nGroup 15: Range is 522.24ms~1.04s step 8.192ms\n"); | |||
| 482 | for (i = 0; i < 64; i++) | |||
| 483 | printf("Bucket %2d: %u\n", i, stats->bucket_15[i]); | |||
| 484 | ||||
| 485 | printf("\nGroup 16: Range is 1.04s~2.09s step 16.384ms\n"); | |||
| 486 | for (i = 0; i < 64; i++) | |||
| 487 | printf("Bucket %2d: %u\n", i, stats->bucket_16[i]); | |||
| 488 | ||||
| 489 | printf("\nGroup 17: Range is 2.09s~4.18s step 32.768ms\n"); | |||
| 490 | for (i = 0; i < 64; i++) | |||
| 491 | printf("Bucket %2d: %u\n", i, stats->bucket_17[i]); | |||
| 492 | ||||
| 493 | printf("\nGroup 18: Range is 4.18s~8.36s step 65.536ms\n"); | |||
| 494 | for (i = 0; i < 64; i++) | |||
| 495 | printf("Bucket %2d: %u\n", i, stats->bucket_18[i]); | |||
| 496 | ||||
| 497 | printf("\nGroup 19: Range is 8.36s~ step 131.072ms\n"); | |||
| 498 | for (i = 0; i < 64; i++) | |||
| 499 | printf("Bucket %2d: %u\n", i, stats->bucket_19[i]); | |||
| 500 | ||||
| 501 | printf("\nAverage latency statistics %" PRIu64"l" "u" "\n", | |||
| 502 | (uint64_t)stats->average); | |||
| 503 | } | |||
| 504 | ||||
| 505 | ||||
| 506 | static int get_lat_stats_log(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 507 | { | |||
| 508 | struct sfx_lat_stats stats; | |||
| 509 | char *desc = "Get ScaleFlux Latency Statistics log and show it."; | |||
| 510 | const char *raw = "dump output in binary format"; | |||
| 511 | const char *write = "Get write statistics (read default)"; | |||
| 512 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 513 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 514 | struct config { | |||
| 515 | bool_Bool raw_binary; | |||
| 516 | bool_Bool write; | |||
| 517 | }; | |||
| 518 | int err; | |||
| 519 | ||||
| 520 | struct config cfg = { | |||
| 521 | }; | |||
| 522 | ||||
| 523 | NVME_ARGS(opts,struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"write", 'w', ((void*)0), CFG_FLAG, &cfg.write, 0 , write, 0, }, {"raw-binary", 'b', ((void*)0), CFG_FLAG, & cfg.raw_binary, 0, raw, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR , ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose" , 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 524 | OPT_FLAG("write", 'w', &cfg.write, write),struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"write", 'w', ((void*)0), CFG_FLAG, &cfg.write, 0 , write, 0, }, {"raw-binary", 'b', ((void*)0), CFG_FLAG, & cfg.raw_binary, 0, raw, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR , ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose" , 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 525 | OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw))struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"write", 'w', ((void*)0), CFG_FLAG, &cfg.write, 0 , write, 0, }, {"raw-binary", 'b', ((void*)0), CFG_FLAG, & cfg.raw_binary, 0, raw, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR , ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose" , 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } }; | |||
| 526 | ||||
| 527 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 528 | if (err) | |||
| 529 | return err; | |||
| 530 | ||||
| 531 | err = nvme_get_log_simple(hdl, cfg.write ? 0xc3 : 0xc1, | |||
| 532 | (void *)&stats, sizeof(stats)); | |||
| 533 | if (!err) { | |||
| 534 | if ((stats.ver.maj == VANDA_MAJOR_IDX0) && (stats.ver.min == VANDA_MINOR_IDX0)) { | |||
| 535 | if (!cfg.raw_binary) | |||
| 536 | show_lat_stats_vanda(&stats.vanda, cfg.write); | |||
| 537 | else | |||
| 538 | d_raw((unsigned char *)&stats.vanda, sizeof(struct sfx_lat_stats_vanda)); | |||
| 539 | } else if ((stats.ver.maj == MYRTLE_MAJOR_IDX4) && (stats.ver.min == MYRTLE_MINOR_IDX1)) { | |||
| 540 | if (!cfg.raw_binary) | |||
| 541 | show_lat_stats_myrtle(&stats.myrtle, cfg.write); | |||
| 542 | else | |||
| 543 | d_raw((unsigned char *)&stats.myrtle, sizeof(struct sfx_lat_stats_myrtle)); | |||
| 544 | } else { | |||
| 545 | printf("ScaleFlux IO %s Command Latency Statistics Invalid Version Maj %d Min %d\n", | |||
| 546 | cfg.write ? "Write" : "Read", stats.ver.maj, stats.ver.min); | |||
| 547 | } | |||
| 548 | } else if (err > 0) { | |||
| 549 | nvme_show_status(err); | |||
| 550 | } | |||
| 551 | return err; | |||
| 552 | } | |||
| 553 | ||||
| 554 | int sfx_nvme_get_log(struct libnvme_transport_handle *hdl, __u32 nsid, __u8 log_id, __u32 data_len, void *data) | |||
| 555 | { | |||
| 556 | struct libnvme_passthru_cmd cmd = { | |||
| 557 | .opcode = nvme_admin_get_log_page, | |||
| 558 | .nsid = nsid, | |||
| 559 | .addr = (__u64)(uintptr_t) data, | |||
| 560 | .data_len = data_len, | |||
| 561 | }; | |||
| 562 | __u32 numd = (data_len >> 2) - 1; | |||
| 563 | __u16 numdu = numd >> 16, numdl = numd & 0xffff; | |||
| 564 | ||||
| 565 | cmd.cdw10 = log_id | (numdl << 16); | |||
| 566 | cmd.cdw11 = numdu; | |||
| 567 | ||||
| 568 | return libnvme_exec_admin_passthru(hdl, &cmd); | |||
| 569 | } | |||
| 570 | ||||
| 571 | /** | |||
| 572 | * @brief get bb table through admin_passthru | |||
| 573 | * | |||
| 574 | * @param fd | |||
| 575 | * @param buf | |||
| 576 | * @param size | |||
| 577 | * | |||
| 578 | * @return -1 fail ; 0 success | |||
| 579 | */ | |||
| 580 | static int get_bb_table(struct libnvme_transport_handle *hdl, __u32 nsid, unsigned char *buf, __u64 size) | |||
| 581 | { | |||
| 582 | if (libnvme_transport_handle_get_fd(hdl) < 0 || !buf || size != 256*4096*sizeof(unsigned char)) { | |||
| 583 | fprintf(stderrstderr, "Invalid Param \r\n"); | |||
| 584 | return -EINVAL22; | |||
| 585 | } | |||
| 586 | ||||
| 587 | return sfx_nvme_get_log(hdl, nsid, SFX_LOG_BBT, size, (void *)buf); | |||
| 588 | } | |||
| 589 | ||||
| 590 | /** | |||
| 591 | * @brief display bb table | |||
| 592 | * | |||
| 593 | * @param bd_table buffer that contain bb table dumped from driver | |||
| 594 | * @param table_size buffer size (BYTES), should at least has 8 bytes for mf_bb_count and grown_bb_count | |||
| 595 | */ | |||
| 596 | static void bd_table_show(unsigned char *bd_table, __u64 table_size) | |||
| 597 | { | |||
| 598 | __u32 mf_bb_count = 0; | |||
| 599 | __u32 grown_bb_count = 0; | |||
| 600 | __u32 total_bb_count = 0; | |||
| 601 | __u32 remap_mfbb_count = 0; | |||
| 602 | __u32 remap_gbb_count = 0; | |||
| 603 | __u64 *bb_elem; | |||
| 604 | __u64 *elem_end = (__u64 *)(bd_table + table_size); | |||
| 605 | __u64 i; | |||
| 606 | ||||
| 607 | /*buf should at least have 8bytes for mf_bb_count & total_bb_count*/ | |||
| 608 | if (!bd_table || table_size < sizeof(__u64)) | |||
| 609 | return; | |||
| 610 | ||||
| 611 | mf_bb_count = *((__u32 *)bd_table); | |||
| 612 | grown_bb_count = *((__u32 *)(bd_table + sizeof(__u32))); | |||
| 613 | total_bb_count = *((__u32 *)(bd_table + 2 * sizeof(__u32))); | |||
| 614 | remap_mfbb_count = *((__u32 *)(bd_table + 3 * sizeof(__u32))); | |||
| 615 | remap_gbb_count = *((__u32 *)(bd_table + 4 * sizeof(__u32))); | |||
| 616 | bb_elem = (__u64 *)(bd_table + 5 * sizeof(__u32)); | |||
| 617 | ||||
| 618 | printf("Bad Block Table\n"); | |||
| 619 | printf("MF_BB_COUNT: %u\n", mf_bb_count); | |||
| 620 | printf("GROWN_BB_COUNT: %u\n", grown_bb_count); | |||
| 621 | printf("TOTAL_BB_COUNT: %u\n", total_bb_count); | |||
| 622 | printf("REMAP_MFBB_COUNT: %u\n", remap_mfbb_count); | |||
| 623 | printf("REMAP_GBB_COUNT: %u\n", remap_gbb_count); | |||
| 624 | ||||
| 625 | printf("REMAP_MFBB_TABLE ["); | |||
| 626 | i = 0; | |||
| 627 | while (bb_elem < elem_end && i < remap_mfbb_count) { | |||
| 628 | printf(" 0x%"PRIx64"l" "x""", (uint64_t)*(bb_elem++)); | |||
| 629 | i++; | |||
| 630 | } | |||
| 631 | printf(" ]\n"); | |||
| 632 | ||||
| 633 | printf("REMAP_GBB_TABLE ["); | |||
| 634 | i = 0; | |||
| 635 | while (bb_elem < elem_end && i < remap_gbb_count) { | |||
| 636 | printf(" 0x%"PRIx64"l" "x""", (uint64_t)*(bb_elem++)); | |||
| 637 | i++; | |||
| 638 | } | |||
| 639 | printf(" ]\n"); | |||
| 640 | } | |||
| 641 | ||||
| 642 | /** | |||
| 643 | * @brief "hooks of sfx get-bad-block" | |||
| 644 | * | |||
| 645 | * @param argc | |||
| 646 | * @param argv | |||
| 647 | * @param cmd | |||
| 648 | * @param plugin | |||
| 649 | * | |||
| 650 | * @return | |||
| 651 | */ | |||
| 652 | static int sfx_get_bad_block(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 653 | { | |||
| 654 | const __u64 buf_size = 256*4096*sizeof(unsigned char); | |||
| 655 | unsigned char *data_buf; | |||
| 656 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 657 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 658 | int err = 0; | |||
| 659 | ||||
| 660 | char *desc = "Get bad block table of sfx block device."; | |||
| 661 | ||||
| 662 | NVME_ARGS(opts)struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0 , "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT , &nvme_args.verbose, 0, "Increase output verbosity", 0, } , {"output-format", 'o', "FMT", CFG_STRING, &nvme_args.output_format , 1, "Output format: normal|json|binary|tabular", 0, }, {"timeout" , 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1, "timeout value, in milliseconds" , 0, }, {"dry-run", 0, ((void*)0), CFG_FLAG, &nvme_args.dry_run , 0, "show command instead of executing", 0, }, {"no-retries" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_retries, 0, "disable retry logic on errors" , 0, }, {"no-ioctl-probing", 0, ((void*)0), CFG_FLAG, &nvme_args .no_ioctl_probing, 0, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version", 0, "NUM", CFG_POSITIVE, & nvme_args.output_format_ver, 1, "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args .verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } }; | |||
| 663 | ||||
| 664 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 665 | if (err) | |||
| 666 | return err; | |||
| 667 | ||||
| 668 | data_buf = malloc(buf_size); | |||
| 669 | if (!data_buf) { | |||
| 670 | fprintf(stderrstderr, "malloc fail, errno %d\r\n", errno(*__errno_location ())); | |||
| 671 | return -1; | |||
| 672 | } | |||
| 673 | ||||
| 674 | err = get_bb_table(hdl, NVME_NSID_ALL, data_buf, buf_size); | |||
| 675 | if (err < 0) { | |||
| 676 | perror("get-bad-block"); | |||
| 677 | } else if (err) { | |||
| 678 | nvme_show_status(err); | |||
| 679 | } else { | |||
| 680 | bd_table_show(data_buf, buf_size); | |||
| 681 | printf("ScaleFlux get bad block table: success\n"); | |||
| 682 | } | |||
| 683 | ||||
| 684 | free(data_buf); | |||
| 685 | return 0; | |||
| 686 | } | |||
| 687 | ||||
| 688 | static void show_cap_info(struct sfx_freespace_ctx *ctx) | |||
| 689 | { | |||
| 690 | ||||
| 691 | printf("logic capacity:%5lluGB(0x%"PRIx64"l" "x"")\n", | |||
| 692 | IDEMA_CAP2GB(ctx->user_space)(((__u64)ctx->user_space - 97696368ULL) / 1953504ULL + 50ULL ), (uint64_t)ctx->user_space); | |||
| 693 | printf("provisioned capacity:%5lluGB(0x%"PRIx64"l" "x"")\n", | |||
| 694 | IDEMA_CAP2GB(ctx->phy_space)(((__u64)ctx->phy_space - 97696368ULL) / 1953504ULL + 50ULL ), (uint64_t)ctx->phy_space); | |||
| 695 | printf("free provisioned capacity:%5lluGB(0x%"PRIx64"l" "x"")\n", | |||
| 696 | IDEMA_CAP2GB(ctx->free_space)(((__u64)ctx->free_space - 97696368ULL) / 1953504ULL + 50ULL ), (uint64_t)ctx->free_space); | |||
| 697 | printf("used provisioned capacity:%5lluGB(0x%"PRIx64"l" "x"")\n", | |||
| 698 | IDEMA_CAP2GB(ctx->phy_space)(((__u64)ctx->phy_space - 97696368ULL) / 1953504ULL + 50ULL ) - IDEMA_CAP2GB(ctx->free_space)(((__u64)ctx->free_space - 97696368ULL) / 1953504ULL + 50ULL ), | |||
| 699 | (uint64_t)(ctx->phy_space - ctx->free_space)); | |||
| 700 | printf("map_unit :0x%"PRIx64"l" "x""K\n", (uint64_t)(ctx->map_unit * 4)); | |||
| 701 | } | |||
| 702 | ||||
| 703 | static int query_cap_info(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 704 | { | |||
| 705 | struct sfx_freespace_ctx sfctx = { 0 }; | |||
| 706 | char *desc = "query current capacity info"; | |||
| 707 | const char *raw = "dump output in binary format"; | |||
| 708 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 709 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 710 | struct config { | |||
| 711 | bool_Bool raw_binary; | |||
| 712 | }; | |||
| 713 | struct config cfg; | |||
| 714 | int err = 0; | |||
| 715 | ||||
| 716 | NVME_ARGS(opts,struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"raw-binary", 'b', ((void*)0), CFG_FLAG, &cfg.raw_binary , 0, raw, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void *)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM" , CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 717 | OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw))struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"raw-binary", 'b', ((void*)0), CFG_FLAG, &cfg.raw_binary , 0, raw, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void *)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM" , CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } }; | |||
| 718 | ||||
| 719 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 720 | if (err) | |||
| 721 | return err; | |||
| 722 | ||||
| 723 | if (nvme_query_cap(hdl, NVME_NSID_ALL, sizeof(sfctx), &sfctx)) { | |||
| 724 | perror("sfx-query-cap"); | |||
| 725 | err = -1; | |||
| 726 | } | |||
| 727 | ||||
| 728 | if (!err) { | |||
| 729 | if (!cfg.raw_binary) | |||
| 730 | show_cap_info(&sfctx); | |||
| 731 | else | |||
| 732 | d_raw((unsigned char *)&sfctx, sizeof(sfctx)); | |||
| 733 | } | |||
| 734 | return err; | |||
| 735 | } | |||
| 736 | ||||
| 737 | static int change_sanity_check(struct libnvme_transport_handle *hdl, __u64 trg_in_4k, int *shrink) | |||
| 738 | { | |||
| 739 | struct sfx_freespace_ctx freespace_ctx = { 0 }; | |||
| 740 | struct sysinfo s_info; | |||
| 741 | __u64 mem_need = 0; | |||
| 742 | __u64 cur_in_4k = 0; | |||
| 743 | __u64 provisioned_cap_4k = 0; | |||
| 744 | int extend = 0; | |||
| 745 | ||||
| 746 | if (nvme_query_cap(hdl, NVME_NSID_ALL, sizeof(freespace_ctx), &freespace_ctx)) | |||
| 747 | return -1; | |||
| 748 | ||||
| 749 | /* | |||
| 750 | * capacity illegal check | |||
| 751 | */ | |||
| 752 | provisioned_cap_4k = freespace_ctx.phy_space >> | |||
| 753 | (SFX_PAGE_SHIFT12 - SECTOR_SHIFT9); | |||
| 754 | if (trg_in_4k < provisioned_cap_4k || | |||
| 755 | trg_in_4k > ((__u64)provisioned_cap_4k * 4)) { | |||
| 756 | fprintf(stderrstderr, | |||
| 757 | "WARNING: Only support 1.0~4.0 x provisioned capacity!\n"); | |||
| 758 | if (trg_in_4k < provisioned_cap_4k) | |||
| 759 | fprintf(stderrstderr, | |||
| 760 | "WARNING: The target capacity is less than 1.0 x provisioned capacity!\n"); | |||
| 761 | else | |||
| 762 | fprintf(stderrstderr, | |||
| 763 | "WARNING: The target capacity is larger than 4.0 x provisioned capacity!\n"); | |||
| 764 | return -1; | |||
| 765 | } | |||
| 766 | if (trg_in_4k > ((__u64)provisioned_cap_4k*4)) { | |||
| 767 | fprintf(stderrstderr, "WARNING: the target capacity is too large\n"); | |||
| 768 | return -1; | |||
| 769 | } | |||
| 770 | ||||
| 771 | /* | |||
| 772 | * check whether mem enough if extend | |||
| 773 | */ | |||
| 774 | cur_in_4k = freespace_ctx.user_space >> (SFX_PAGE_SHIFT12 - SECTOR_SHIFT9); | |||
| 775 | extend = (cur_in_4k <= trg_in_4k); | |||
| 776 | if (extend) { | |||
| 777 | if (sysinfo(&s_info) < 0) { | |||
| 778 | printf("change-cap query mem info fail\n"); | |||
| 779 | return -1; | |||
| 780 | } | |||
| 781 | mem_need = (trg_in_4k - cur_in_4k) * 8; | |||
| 782 | if (s_info.freeram <= 10 || mem_need > s_info.freeram) { | |||
| 783 | fprintf(stderrstderr, | |||
| 784 | "WARNING: Free memory is not enough! Please drop cache or extend more memory and retry\n" | |||
| 785 | "WARNING: Memory needed is %"PRIu64"l" "u"", free memory is %"PRIu64"l" "u""\n", | |||
| 786 | (uint64_t)mem_need, (uint64_t)s_info.freeram); | |||
| 787 | return -1; | |||
| 788 | } | |||
| 789 | } | |||
| 790 | *shrink = !extend; | |||
| 791 | ||||
| 792 | return 0; | |||
| 793 | } | |||
| 794 | ||||
| 795 | /** | |||
| 796 | * @brief prompt and get user confirm input | |||
| 797 | * | |||
| 798 | * @param str, prompt string | |||
| 799 | * | |||
| 800 | * @return 0, canceled; 1 confirmed | |||
| 801 | */ | |||
| 802 | static int sfx_confirm_change(const char *str) | |||
| 803 | { | |||
| 804 | unsigned char confirm; | |||
| 805 | ||||
| 806 | fprintf(stderrstderr, "WARNING: %s.\n" | |||
| 807 | "Use the force [--force] option to suppress this warning.\n", str); | |||
| 808 | ||||
| 809 | fprintf(stderrstderr, "Confirm Y/y, Others cancel:\n"); | |||
| 810 | confirm = (unsigned char)fgetc(stdinstdin); | |||
| 811 | if (confirm != 'y' && confirm != 'Y') { | |||
| 812 | fprintf(stderrstderr, "Canceled.\n"); | |||
| 813 | return 0; | |||
| 814 | } | |||
| 815 | fprintf(stderrstderr, "Sending operation ...\n"); | |||
| 816 | return 1; | |||
| 817 | } | |||
| 818 | ||||
| 819 | static int change_cap(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 820 | { | |||
| 821 | char *desc = "dynamic change capacity"; | |||
| 822 | const char *cap_gb = "cap size in GB"; | |||
| 823 | const char *cap_byte = "cap size in byte"; | |||
| 824 | const char *force = "The \"I know what I'm doing\" flag, skip confirmation before sending command"; | |||
| 825 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 826 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 827 | __u64 cap_in_4k = 0; | |||
| 828 | __u64 cap_in_sec = 0; | |||
| 829 | int shrink = 0; | |||
| 830 | int err = -1; | |||
| 831 | ||||
| 832 | struct config { | |||
| 833 | __u64 cap_in_byte; | |||
| 834 | __u32 capacity_in_gb; | |||
| 835 | bool_Bool force; | |||
| 836 | }; | |||
| 837 | ||||
| 838 | struct config cfg = { | |||
| 839 | .cap_in_byte = 0, | |||
| 840 | .capacity_in_gb = 0, | |||
| 841 | .force = 0, | |||
| 842 | }; | |||
| 843 | ||||
| 844 | NVME_ARGS(opts,struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"cap", 'c', "NUM", CFG_POSITIVE, &cfg.capacity_in_gb , 1, cap_gb, 0, }, {"cap-byte", 'z', "IONUM", CFG_LONG_SUFFIX , &cfg.cap_in_byte, 1, cap_byte, 0, }, {"force", 'f', ((void *)0), CFG_FLAG, &cfg.force, 0, force, 0, }, {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options", 0 , ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &nvme_args .verbose, 0, "Increase output verbosity", 0, }, {"output-format" , 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 845 | OPT_UINT("cap", 'c', &cfg.capacity_in_gb, cap_gb),struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"cap", 'c', "NUM", CFG_POSITIVE, &cfg.capacity_in_gb , 1, cap_gb, 0, }, {"cap-byte", 'z', "IONUM", CFG_LONG_SUFFIX , &cfg.cap_in_byte, 1, cap_byte, 0, }, {"force", 'f', ((void *)0), CFG_FLAG, &cfg.force, 0, force, 0, }, {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options", 0 , ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &nvme_args .verbose, 0, "Increase output verbosity", 0, }, {"output-format" , 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 846 | OPT_SUFFIX("cap-byte", 'z', &cfg.cap_in_byte, cap_byte),struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"cap", 'c', "NUM", CFG_POSITIVE, &cfg.capacity_in_gb , 1, cap_gb, 0, }, {"cap-byte", 'z', "IONUM", CFG_LONG_SUFFIX , &cfg.cap_in_byte, 1, cap_byte, 0, }, {"force", 'f', ((void *)0), CFG_FLAG, &cfg.force, 0, force, 0, }, {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options", 0 , ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &nvme_args .verbose, 0, "Increase output verbosity", 0, }, {"output-format" , 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 847 | OPT_FLAG("force", 'f', &cfg.force, force))struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"cap", 'c', "NUM", CFG_POSITIVE, &cfg.capacity_in_gb , 1, cap_gb, 0, }, {"cap-byte", 'z', "IONUM", CFG_LONG_SUFFIX , &cfg.cap_in_byte, 1, cap_byte, 0, }, {"force", 'f', ((void *)0), CFG_FLAG, &cfg.force, 0, force, 0, }, {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options", 0 , ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &nvme_args .verbose, 0, "Increase output verbosity", 0, }, {"output-format" , 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } }; | |||
| 848 | ||||
| 849 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 850 | if (err) | |||
| 851 | return err; | |||
| 852 | ||||
| 853 | cap_in_sec = IDEMA_CAP(cfg.capacity_in_gb)(((__u64)cfg.capacity_in_gb - 50ULL) * 1953504ULL + 97696368ULL ); | |||
| 854 | cap_in_4k = cap_in_sec >> 3; | |||
| 855 | if (cfg.cap_in_byte) | |||
| 856 | cap_in_4k = cfg.cap_in_byte >> 12; | |||
| 857 | printf("%dG %"PRIu64"l" "u""B %"PRIu64"l" "u"" 4K\n", | |||
| 858 | cfg.capacity_in_gb, (uint64_t)cfg.cap_in_byte, (uint64_t)cap_in_4k); | |||
| 859 | ||||
| 860 | if (change_sanity_check(hdl, cap_in_4k, &shrink)) { | |||
| 861 | printf("ScaleFlux change-capacity: fail\n"); | |||
| 862 | return err; | |||
| 863 | } | |||
| 864 | ||||
| 865 | if (!cfg.force && shrink && !sfx_confirm_change("Changing Cap may irrevocably delete this device's data")) { | |||
| 866 | return 0; | |||
| 867 | } | |||
| 868 | ||||
| 869 | err = nvme_change_cap(hdl, NVME_NSID_ALL, cap_in_4k); | |||
| 870 | if (err < 0) { | |||
| 871 | perror("sfx-change-cap"); | |||
| 872 | } else if (err) { | |||
| 873 | nvme_show_status(err); | |||
| 874 | } else { | |||
| 875 | printf("ScaleFlux change-capacity: success\n"); | |||
| 876 | ioctl(libnvme_transport_handle_get_fd(hdl), BLKRRPART(((0U) << (((0 +8)+8)+14)) | (((0x12)) << (0 +8)) | (((95)) << 0) | ((0) << ((0 +8)+8)))); | |||
| 877 | } | |||
| 878 | return err; | |||
| 879 | } | |||
| 880 | ||||
| 881 | static int sfx_verify_chr(struct libnvme_transport_handle *hdl) | |||
| 882 | { | |||
| 883 | static struct stat nvme_stat; | |||
| 884 | int err = fstat(libnvme_transport_handle_get_fd(hdl), &nvme_stat); | |||
| 885 | ||||
| 886 | if (err < 0) { | |||
| 887 | perror("fstat"); | |||
| 888 | return errno(*__errno_location ()); | |||
| 889 | } | |||
| 890 | if (!S_ISCHR(nvme_stat.st_mode)((((nvme_stat.st_mode)) & 0170000) == (0020000))) { | |||
| 891 | fprintf(stderrstderr, | |||
| 892 | "Error: requesting clean card on non-controller handle\n"); | |||
| 893 | return -ENOTBLK15; | |||
| 894 | } | |||
| 895 | return 0; | |||
| 896 | } | |||
| 897 | ||||
| 898 | static int sfx_clean_card(struct libnvme_transport_handle *hdl) | |||
| 899 | { | |||
| 900 | int ret; | |||
| 901 | ||||
| 902 | ret = sfx_verify_chr(hdl); | |||
| 903 | if (ret) | |||
| 904 | return ret; | |||
| 905 | ret = ioctl(libnvme_transport_handle_get_fd(hdl), NVME_IOCTL_CLR_CARD(((0U) << (((0 +8)+8)+14)) | ((('N')) << (0 +8)) | (((0x47)) << 0) | ((0) << ((0 +8)+8)))); | |||
| 906 | if (ret) | |||
| 907 | perror("Ioctl Fail."); | |||
| 908 | else | |||
| 909 | printf("ScaleFlux clean card success\n"); | |||
| 910 | ||||
| 911 | return ret; | |||
| 912 | } | |||
| 913 | ||||
| 914 | char *sfx_feature_to_string(int feature) | |||
| 915 | { | |||
| 916 | switch (feature) { | |||
| 917 | case SFX_FEAT_ATOMIC: | |||
| 918 | return "ATOMIC"; | |||
| 919 | case SFX_FEAT_UP_P_CAP: | |||
| 920 | return "UPDATE_PROVISION_CAPACITY"; | |||
| 921 | default: | |||
| 922 | return "Unknown"; | |||
| 923 | } | |||
| 924 | } | |||
| 925 | ||||
| 926 | static int sfx_set_feature(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 927 | { | |||
| 928 | char *desc = "ScaleFlux internal set features\n" | |||
| 929 | "feature id 1: ATOMIC\n" | |||
| 930 | "value 0: Disable atomic write\n" | |||
| 931 | " 1: Enable atomic write"; | |||
| 932 | const char *value = "new value of feature (required)"; | |||
| 933 | const char *feature_id = "hex feature name (required)"; | |||
| 934 | const char *namespace_id = "desired namespace"; | |||
| 935 | const char *force = "The \"I know what I'm doing\" flag, skip confirmation before sending command"; | |||
| 936 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 937 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 938 | struct nvme_id_ns ns; | |||
| 939 | int err = 0; | |||
| 940 | ||||
| 941 | struct config { | |||
| 942 | __u32 namespace_id; | |||
| 943 | __u32 feature_id; | |||
| 944 | __u32 value; | |||
| 945 | bool_Bool force; | |||
| 946 | }; | |||
| 947 | struct config cfg = { | |||
| 948 | .namespace_id = 1, | |||
| 949 | .feature_id = 0, | |||
| 950 | .value = 0, | |||
| 951 | .force = 0, | |||
| 952 | }; | |||
| 953 | ||||
| 954 | NVME_ARGS(opts,struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"namespace-id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"feature-id", 'f', "NUM", CFG_POSITIVE , &cfg.feature_id, 1, feature_id, 0, }, {"value", 'V', "NUM" , CFG_POSITIVE, &cfg.value, 1, value, 0, }, {"force", 's' , ((void*)0), CFG_FLAG, &cfg.force, 0, force, 0, }, {"", 0 , ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options" , 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, & nvme_args.verbose, 0, "Increase output verbosity", 0, }, {"output-format" , 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 955 | OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"namespace-id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"feature-id", 'f', "NUM", CFG_POSITIVE , &cfg.feature_id, 1, feature_id, 0, }, {"value", 'V', "NUM" , CFG_POSITIVE, &cfg.value, 1, value, 0, }, {"force", 's' , ((void*)0), CFG_FLAG, &cfg.force, 0, force, 0, }, {"", 0 , ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options" , 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, & nvme_args.verbose, 0, "Increase output verbosity", 0, }, {"output-format" , 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 956 | OPT_UINT("feature-id", 'f', &cfg.feature_id, feature_id),struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"namespace-id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"feature-id", 'f', "NUM", CFG_POSITIVE , &cfg.feature_id, 1, feature_id, 0, }, {"value", 'V', "NUM" , CFG_POSITIVE, &cfg.value, 1, value, 0, }, {"force", 's' , ((void*)0), CFG_FLAG, &cfg.force, 0, force, 0, }, {"", 0 , ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options" , 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, & nvme_args.verbose, 0, "Increase output verbosity", 0, }, {"output-format" , 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 957 | OPT_UINT("value", 'V', &cfg.value, value),struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"namespace-id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"feature-id", 'f', "NUM", CFG_POSITIVE , &cfg.feature_id, 1, feature_id, 0, }, {"value", 'V', "NUM" , CFG_POSITIVE, &cfg.value, 1, value, 0, }, {"force", 's' , ((void*)0), CFG_FLAG, &cfg.force, 0, force, 0, }, {"", 0 , ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options" , 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, & nvme_args.verbose, 0, "Increase output verbosity", 0, }, {"output-format" , 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 958 | OPT_FLAG("force", 's', &cfg.force, force))struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"namespace-id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"feature-id", 'f', "NUM", CFG_POSITIVE , &cfg.feature_id, 1, feature_id, 0, }, {"value", 'V', "NUM" , CFG_POSITIVE, &cfg.value, 1, value, 0, }, {"force", 's' , ((void*)0), CFG_FLAG, &cfg.force, 0, force, 0, }, {"", 0 , ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options" , 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, & nvme_args.verbose, 0, "Increase output verbosity", 0, }, {"output-format" , 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } }; | |||
| 959 | ||||
| 960 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 961 | if (err) | |||
| 962 | return err; | |||
| 963 | ||||
| 964 | if (!cfg.feature_id) { | |||
| 965 | fprintf(stderrstderr, "feature-id required param\n"); | |||
| 966 | return -EINVAL22; | |||
| 967 | } | |||
| 968 | ||||
| 969 | if (cfg.feature_id == SFX_FEAT_CLR_CARD) { | |||
| 970 | /*Warning for clean card*/ | |||
| 971 | if (!cfg.force && !sfx_confirm_change("Going to clean device's data, confirm umount fs and try again")) { | |||
| 972 | return 0; | |||
| 973 | } else { | |||
| 974 | return sfx_clean_card(hdl); | |||
| 975 | } | |||
| 976 | ||||
| 977 | } | |||
| 978 | ||||
| 979 | if (cfg.feature_id == SFX_FEAT_ATOMIC && cfg.value) { | |||
| 980 | if (cfg.namespace_id != NVME_NSID_ALL) { | |||
| 981 | err = nvme_identify_ns(hdl, cfg.namespace_id, &ns); | |||
| 982 | if (err) { | |||
| 983 | if (err < 0) | |||
| 984 | perror("identify-namespace"); | |||
| 985 | else | |||
| 986 | nvme_show_status(err); | |||
| 987 | return err; | |||
| 988 | } | |||
| 989 | /* | |||
| 990 | * atomic only support with sector-size = 4k now | |||
| 991 | */ | |||
| 992 | if ((ns.flbas & 0xf) != 1) { | |||
| 993 | printf("Please change-sector size to 4K, then retry\n"); | |||
| 994 | return -EFAULT14; | |||
| 995 | } | |||
| 996 | } | |||
| 997 | } else if (cfg.feature_id == SFX_FEAT_UP_P_CAP) { | |||
| 998 | if (cfg.value <= 0) { | |||
| 999 | fprintf(stderrstderr, "Invalid Param\n"); | |||
| 1000 | return -EINVAL22; | |||
| 1001 | } | |||
| 1002 | ||||
| 1003 | /*Warning for change pacp by GB*/ | |||
| 1004 | if (!cfg.force && !sfx_confirm_change("Changing physical capacity may irrevocably delete this device's data")) { | |||
| 1005 | return 0; | |||
| 1006 | } | |||
| 1007 | } | |||
| 1008 | ||||
| 1009 | err = nvme_sfx_set_features(hdl, cfg.namespace_id, | |||
| 1010 | cfg.feature_id, | |||
| 1011 | cfg.value); | |||
| 1012 | ||||
| 1013 | if (err < 0) { | |||
| 1014 | perror("ScaleFlux-set-feature"); | |||
| 1015 | return errno(*__errno_location ()); | |||
| 1016 | } else if (!err) { | |||
| 1017 | printf("ScaleFlux set-feature:%#02x (%s), value:%d\n", cfg.feature_id, | |||
| 1018 | sfx_feature_to_string(cfg.feature_id), cfg.value); | |||
| 1019 | } else if (err > 0) { | |||
| 1020 | nvme_show_status(err); | |||
| 1021 | } | |||
| 1022 | ||||
| 1023 | return err; | |||
| 1024 | } | |||
| 1025 | ||||
| 1026 | static int sfx_get_feature(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 1027 | { | |||
| 1028 | char *desc = "ScaleFlux internal set features\n" | |||
| 1029 | "feature id 1: ATOMIC"; | |||
| 1030 | const char *feature_id = "hex feature name (required)"; | |||
| 1031 | const char *namespace_id = "desired namespace"; | |||
| 1032 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 1033 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 1034 | __u32 result = 0; | |||
| 1035 | int err = 0; | |||
| 1036 | ||||
| 1037 | struct config { | |||
| 1038 | __u32 namespace_id; | |||
| 1039 | __u32 feature_id; | |||
| 1040 | }; | |||
| 1041 | struct config cfg = { | |||
| 1042 | .namespace_id = 0, | |||
| 1043 | .feature_id = 0, | |||
| 1044 | }; | |||
| 1045 | ||||
| 1046 | NVME_ARGS(opts,struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"namespace-id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"feature-id", 'f', "NUM", CFG_POSITIVE , &cfg.feature_id, 1, feature_id, 0, }, {"", 0, ((void*)0 ), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options", 0, ( (void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &nvme_args .verbose, 0, "Increase output verbosity", 0, }, {"output-format" , 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 1047 | OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"namespace-id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"feature-id", 'f', "NUM", CFG_POSITIVE , &cfg.feature_id, 1, feature_id, 0, }, {"", 0, ((void*)0 ), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options", 0, ( (void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &nvme_args .verbose, 0, "Increase output verbosity", 0, }, {"output-format" , 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 1048 | OPT_UINT("feature-id", 'f', &cfg.feature_id, feature_id))struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"namespace-id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"feature-id", 'f', "NUM", CFG_POSITIVE , &cfg.feature_id, 1, feature_id, 0, }, {"", 0, ((void*)0 ), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options", 0, ( (void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &nvme_args .verbose, 0, "Increase output verbosity", 0, }, {"output-format" , 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } }; | |||
| 1049 | ||||
| 1050 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 1051 | if (err) | |||
| 1052 | return err; | |||
| 1053 | ||||
| 1054 | if (!cfg.feature_id) { | |||
| 1055 | fprintf(stderrstderr, "feature-id required param\n"); | |||
| 1056 | return -EINVAL22; | |||
| 1057 | } | |||
| 1058 | ||||
| 1059 | err = nvme_sfx_get_features(hdl, cfg.namespace_id, | |||
| 1060 | cfg.feature_id, &result); | |||
| 1061 | if (err < 0) { | |||
| 1062 | perror("ScaleFlux-get-feature"); | |||
| 1063 | return errno(*__errno_location ()); | |||
| 1064 | } else if (!err) { | |||
| 1065 | printf("ScaleFlux get-feature:%02x (%s), value:%d\n", cfg.feature_id, | |||
| 1066 | sfx_feature_to_string(cfg.feature_id), result); | |||
| 1067 | } else if (err > 0) { | |||
| 1068 | nvme_show_status(err); | |||
| 1069 | } | |||
| 1070 | ||||
| 1071 | return err; | |||
| 1072 | ||||
| 1073 | } | |||
| 1074 | ||||
| 1075 | static int nvme_parse_evtlog(void *pevent_log_info, __u32 log_len, char *output) | |||
| 1076 | { | |||
| 1077 | __u32 offset = 0; | |||
| 1078 | __u32 length = log_len; | |||
| 1079 | __u16 fw_core; | |||
| 1080 | __u64 fw_time; | |||
| 1081 | __u8 code_level; | |||
| 1082 | __u8 code_type; | |||
| 1083 | char str_buffer[512]; | |||
| 1084 | __u32 str_pos; | |||
| 1085 | FILE *fd; | |||
| 1086 | int err = 0; | |||
| 1087 | ||||
| 1088 | enum sfx_evtlog_level { | |||
| 1089 | sfx_evtlog_level_warning, | |||
| 1090 | sfx_evtlog_level_error, | |||
| 1091 | }; | |||
| 1092 | ||||
| 1093 | const char *sfx_evtlog_warning[4] = { | |||
| 1094 | "RESERVED", | |||
| 1095 | "TOO_MANY_BB", | |||
| 1096 | "LOW_SPACE", | |||
| 1097 | "HIGH_TEMPERATURE" | |||
| 1098 | }; | |||
| 1099 | ||||
| 1100 | const char *sfx_evtlog_error[14] = { | |||
| 1101 | "RESERVED", | |||
| 1102 | "HAS_ASSERT", | |||
| 1103 | "HAS_PANIC_DUMP", | |||
| 1104 | "INVALID_FORMAT_CAPACITY", | |||
| 1105 | "MAT_FAILED", | |||
| 1106 | "FREEZE_DUE_TO_RECOVERY_FAILED", | |||
| 1107 | "RFS_BROKEN", | |||
| 1108 | "MEDIA_ERR_ON_PAGE_IN", | |||
| 1109 | "MEDIA_ERR_ON_MPAGE_HEADER", | |||
| 1110 | "CAPACITOR_BROKEN", | |||
| 1111 | "READONLY_DUE_TO_RECOVERY_FAILED", | |||
| 1112 | "RD_ERR_IN_GSD_RECOVERY", | |||
| 1113 | "RD_ERR_ON_PF_RECOVERY", | |||
| 1114 | "MEDIA_ERR_ON_FULL_RECOVERY" | |||
| 1115 | }; | |||
| 1116 | ||||
| 1117 | struct sfx_nvme_evtlog_info { | |||
| 1118 | __u16 time_stamp[4]; | |||
| 1119 | __u64 magic1; | |||
| 1120 | __u8 reverse[10]; | |||
| 1121 | char evt_name[32]; | |||
| 1122 | __u64 magic2; | |||
| 1123 | char fw_ver[24]; | |||
| 1124 | char bl2_ver[32]; | |||
| 1125 | __u16 code; | |||
| 1126 | __u16 assert_id; | |||
| 1127 | } __packed__attribute__((__packed__)); | |||
| 1128 | ||||
| 1129 | struct sfx_nvme_evtlog_info *info = NULL((void*)0); | |||
| 1130 | ||||
| 1131 | fd = fopen(output, "w+"); | |||
| 1132 | if (!fd) { | |||
| 1133 | fprintf(stderrstderr, "Failed to open %s file to write\n", output); | |||
| 1134 | err = ENOENT2; | |||
| 1135 | goto ret; | |||
| 1136 | } | |||
| 1137 | ||||
| 1138 | while (length > 0) { | |||
| 1139 | info = (struct sfx_nvme_evtlog_info *)(pevent_log_info + offset); | |||
| 1140 | ||||
| 1141 | if ((info->magic1 == 0x474F4C545645) && | |||
| 1142 | (info->magic2 == 0x38B0B3ABA9BA)) { | |||
| 1143 | ||||
| 1144 | memset(str_buffer, 0, 512); | |||
| 1145 | str_pos = 0; | |||
| 1146 | ||||
| 1147 | fw_core = info->time_stamp[3]; | |||
| 1148 | snprintf(str_buffer + str_pos, 16, "[%d-", fw_core); | |||
| 1149 | str_pos = strlen(str_buffer); | |||
| 1150 | ||||
| 1151 | fw_time = ((__u64)info->time_stamp[2] << 32) + ((__u64)info->time_stamp[1] << 16) + (__u64)info->time_stamp[0]; | |||
| 1152 | convert_ts(fw_time, str_buffer + str_pos); | |||
| 1153 | str_pos = strlen(str_buffer); | |||
| 1154 | ||||
| 1155 | strcpy(str_buffer + str_pos, "] event-log:\n"); | |||
| 1156 | str_pos = strlen(str_buffer); | |||
| 1157 | ||||
| 1158 | snprintf(str_buffer + str_pos, 128, | |||
| 1159 | " > fw_version: %s\n > bl2_version: %s\n", | |||
| 1160 | info->fw_ver, info->bl2_ver); | |||
| 1161 | str_pos = strlen(str_buffer); | |||
| 1162 | ||||
| 1163 | code_level = (info->code & 0x100) >> 8; | |||
| 1164 | code_type = (info->code % 0x100); | |||
| 1165 | if (code_level == sfx_evtlog_level_warning) { | |||
| 1166 | snprintf(str_buffer + str_pos, 128, | |||
| 1167 | " > error_str: [WARNING][%s]\n\n", | |||
| 1168 | sfx_evtlog_warning[code_type]); | |||
| 1169 | } else { | |||
| 1170 | if (info->assert_id) | |||
| 1171 | snprintf(str_buffer + str_pos, 128, | |||
| 1172 | " > error_str: [ERROR][%s]\n > assert_id: %d\n\n", | |||
| 1173 | sfx_evtlog_error[code_type], info->assert_id); | |||
| 1174 | else | |||
| 1175 | snprintf(str_buffer + str_pos, 128, | |||
| 1176 | " > error_str: [ERROR][%s]\n\n", | |||
| 1177 | sfx_evtlog_error[code_type]); | |||
| 1178 | } | |||
| 1179 | str_pos = strlen(str_buffer); | |||
| 1180 | ||||
| 1181 | if (fwrite(str_buffer, 1, str_pos, fd) != str_pos) { | |||
| 1182 | fprintf(stderrstderr, "Failed to write parse result to output file\n"); | |||
| 1183 | goto close_fd; | |||
| 1184 | } | |||
| 1185 | } | |||
| 1186 | ||||
| 1187 | offset++; | |||
| 1188 | length--; | |||
| 1189 | ||||
| 1190 | if (!(offset % (log_len / 100)) || (offset == log_len)) | |||
| 1191 | util_spinner("Parse", (float) (offset) / (float) (log_len)); | |||
| 1192 | } | |||
| 1193 | ||||
| 1194 | printf("\nParse-evtlog: Success\n"); | |||
| 1195 | ||||
| 1196 | close_fd: | |||
| 1197 | fclose(fd); | |||
| 1198 | ret: | |||
| 1199 | return err; | |||
| 1200 | } | |||
| 1201 | ||||
| 1202 | static int nvme_dump_evtlog(struct libnvme_transport_handle *hdl, __u32 namespace_id, __u32 storage_medium, | |||
| 1203 | char *file, bool_Bool parse, char *output) | |||
| 1204 | { | |||
| 1205 | __cleanup_huge__attribute__((cleanup(libnvme_free_huge))) struct libnvme_mem_huge mh = { 0, }; | |||
| 1206 | struct nvme_persistent_event_log *pevent; | |||
| 1207 | void *pevent_log_info; | |||
| 1208 | __u8 lsp_base, lsp; | |||
| 1209 | __u32 offset = 0; | |||
| 1210 | __u32 length = 0; | |||
| 1211 | __u32 single_len; | |||
| 1212 | __u32 log_len; | |||
| 1213 | __u32 len; | |||
| 1214 | __u64 lpo; | |||
| 1215 | void *log; | |||
| 1216 | int err = 0; | |||
| 1217 | FILE *fd = NULL((void*)0); | |||
| 1218 | struct libnvme_passthru_cmd cmd; | |||
| 1219 | ||||
| 1220 | if (!storage_medium) { | |||
| 1221 | lsp_base = 0; | |||
| 1222 | single_len = 64 * 1024 - 4; | |||
| 1223 | } else { | |||
| 1224 | lsp_base = 4; | |||
| 1225 | single_len = 32 * 1024; | |||
| 1226 | } | |||
| 1227 | ||||
| 1228 | pevent = calloc(sizeof(*pevent), sizeof(__u8)); | |||
| 1229 | if (!pevent) { | |||
| 1230 | err = -ENOMEM12; | |||
| 1231 | goto ret; | |||
| 1232 | } | |||
| 1233 | ||||
| 1234 | lsp = lsp_base + NVME_PEVENT_LOG_RELEASE_CTX; | |||
| 1235 | log = pevent; | |||
| 1236 | len = sizeof(*pevent); | |||
| 1237 | nvme_init_get_log(&cmd, NVME_NSID_NONE, NVME_LOG_LID_PERSISTENT_EVENT, | |||
| 1238 | NVME_CSI_NVM, log, len); | |||
| 1239 | cmd.cdw10 |= NVME_FIELD_ENCODE(lsp,(((__u32)(lsp) & (NVME_LOG_CDW10_LSP_MASK)) << (NVME_LOG_CDW10_LSP_SHIFT )) | |||
| 1240 | NVME_LOG_CDW10_LSP_SHIFT,(((__u32)(lsp) & (NVME_LOG_CDW10_LSP_MASK)) << (NVME_LOG_CDW10_LSP_SHIFT )) | |||
| 1241 | NVME_LOG_CDW10_LSP_MASK)(((__u32)(lsp) & (NVME_LOG_CDW10_LSP_MASK)) << (NVME_LOG_CDW10_LSP_SHIFT )); | |||
| 1242 | err = libnvme_get_log(hdl, &cmd, false0, NVME_LOG_PAGE_PDU_SIZE4096); | |||
| 1243 | if (err) { | |||
| 1244 | fprintf(stderrstderr, "Unable to get evtlog lsp=0x%x, ret = 0x%x\n", | |||
| 1245 | lsp, err); | |||
| 1246 | goto free_pevent; | |||
| 1247 | } | |||
| 1248 | ||||
| 1249 | lsp = lsp_base + NVME_PEVENT_LOG_EST_CTX_AND_READ; | |||
| 1250 | nvme_init_get_log(&cmd, NVME_NSID_NONE, NVME_LOG_LID_PERSISTENT_EVENT, | |||
| 1251 | NVME_CSI_NVM, log, len); | |||
| 1252 | cmd.cdw10 |= NVME_FIELD_ENCODE(lsp,(((__u32)(lsp) & (NVME_LOG_CDW10_LSP_MASK)) << (NVME_LOG_CDW10_LSP_SHIFT )) | |||
| 1253 | NVME_LOG_CDW10_LSP_SHIFT,(((__u32)(lsp) & (NVME_LOG_CDW10_LSP_MASK)) << (NVME_LOG_CDW10_LSP_SHIFT )) | |||
| 1254 | NVME_LOG_CDW10_LSP_MASK)(((__u32)(lsp) & (NVME_LOG_CDW10_LSP_MASK)) << (NVME_LOG_CDW10_LSP_SHIFT )); | |||
| 1255 | err = libnvme_get_log(hdl, &cmd, false0, NVME_LOG_PAGE_PDU_SIZE4096); | |||
| 1256 | if (err) { | |||
| 1257 | fprintf(stderrstderr, "Unable to get evtlog lsp=0x%x, ret = 0x%x\n", | |||
| 1258 | lsp, err); | |||
| 1259 | goto free_pevent; | |||
| 1260 | } | |||
| 1261 | ||||
| 1262 | log_len = le64_to_cpu(pevent->tll); | |||
| 1263 | if (log_len % 4) | |||
| 1264 | log_len = (log_len / 4 + 1) * 4; | |||
| 1265 | ||||
| 1266 | pevent_log_info = libnvme_alloc_huge(single_len, &mh); | |||
| 1267 | if (!pevent_log_info) { | |||
| 1268 | err = -ENOMEM12; | |||
| 1269 | goto free_pevent; | |||
| 1270 | } | |||
| 1271 | ||||
| 1272 | fd = fopen(file, "wb+"); | |||
| 1273 | if (!fd) { | |||
| 1274 | fprintf(stderrstderr, "Failed to open %s file to write\n", file); | |||
| 1275 | err = ENOENT2; | |||
| 1276 | goto free_pevent; | |||
| 1277 | } | |||
| 1278 | ||||
| 1279 | lsp = lsp_base + NVME_PEVENT_LOG_READ; | |||
| 1280 | log = pevent_log_info; | |||
| 1281 | length = log_len; | |||
| 1282 | while (length > 0) { | |||
| 1283 | lpo = offset; | |||
| 1284 | if (length > single_len) { | |||
| 1285 | len = single_len; | |||
| 1286 | } else { | |||
| 1287 | memset(log, 0, len); | |||
| 1288 | len = length; | |||
| 1289 | } | |||
| 1290 | nvme_init_get_log(&cmd, NVME_NSID_NONE, | |||
| 1291 | NVME_LOG_LID_PERSISTENT_EVENT, | |||
| 1292 | NVME_CSI_NVM, log, len); | |||
| 1293 | cmd.cdw10 |= NVME_FIELD_ENCODE(lsp,(((__u32)(lsp) & (NVME_LOG_CDW10_LSP_MASK)) << (NVME_LOG_CDW10_LSP_SHIFT )) | |||
| 1294 | NVME_LOG_CDW10_LSP_SHIFT,(((__u32)(lsp) & (NVME_LOG_CDW10_LSP_MASK)) << (NVME_LOG_CDW10_LSP_SHIFT )) | |||
| 1295 | NVME_LOG_CDW10_LSP_MASK)(((__u32)(lsp) & (NVME_LOG_CDW10_LSP_MASK)) << (NVME_LOG_CDW10_LSP_SHIFT )); | |||
| 1296 | nvme_init_get_log_lpo(&cmd, lpo); | |||
| 1297 | err = libnvme_get_log(hdl, &cmd, false0, NVME_LOG_PAGE_PDU_SIZE4096); | |||
| 1298 | if (err) { | |||
| 1299 | fprintf(stderrstderr, | |||
| 1300 | "Unable to get evtlog offset=0x%x len 0x%x ret = 0x%x\n", | |||
| 1301 | offset, len, err); | |||
| 1302 | goto close_fd; | |||
| 1303 | } | |||
| 1304 | ||||
| 1305 | if (fwrite(log, 1, len, fd) != len) { | |||
| 1306 | fprintf(stderrstderr, "Failed to write evtlog to file\n"); | |||
| 1307 | goto close_fd; | |||
| 1308 | } | |||
| 1309 | ||||
| 1310 | offset += len; | |||
| 1311 | length -= len; | |||
| 1312 | util_spinner("Parse", (float) (offset) / (float) (log_len)); | |||
| 1313 | } | |||
| 1314 | ||||
| 1315 | printf("\nDump-evtlog: Success\n"); | |||
| 1316 | ||||
| 1317 | if (parse) { | |||
| 1318 | libnvme_free_huge(&mh); | |||
| 1319 | pevent_log_info = libnvme_alloc_huge(log_len, &mh); | |||
| 1320 | if (!pevent_log_info) { | |||
| 1321 | fprintf(stderrstderr, "Failed to alloc enough memory 0x%x to parse evtlog\n", log_len); | |||
| 1322 | err = -ENOMEM12; | |||
| 1323 | goto close_fd; | |||
| 1324 | } | |||
| 1325 | ||||
| 1326 | fclose(fd); | |||
| 1327 | fd = fopen(file, "rb"); | |||
| 1328 | if (!fd) { | |||
| 1329 | fprintf(stderrstderr, "Failed to open %s file to read\n", file); | |||
| 1330 | err = ENOENT2; | |||
| 1331 | goto free_pevent; | |||
| 1332 | } | |||
| 1333 | if (fread(pevent_log_info, 1, log_len, fd) != log_len) { | |||
| 1334 | fprintf(stderrstderr, "Failed to read evtlog to buffer\n"); | |||
| 1335 | goto close_fd; | |||
| 1336 | } | |||
| 1337 | ||||
| 1338 | err = nvme_parse_evtlog(pevent_log_info, log_len, output); | |||
| 1339 | } | |||
| 1340 | ||||
| 1341 | close_fd: | |||
| 1342 | fclose(fd); | |||
| 1343 | free_pevent: | |||
| 1344 | free(pevent); | |||
| 1345 | ret: | |||
| 1346 | return err; | |||
| 1347 | } | |||
| 1348 | ||||
| 1349 | static int sfx_dump_evtlog(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 1350 | { | |||
| 1351 | char *desc = "dump evtlog into file and parse"; | |||
| 1352 | const char *file = "evtlog file(required)"; | |||
| 1353 | const char *namespace_id = "desired namespace"; | |||
| 1354 | const char *storage_medium = "evtlog storage medium\n" | |||
| 1355 | "0: nand(default) 1: nor"; | |||
| 1356 | const char *parse = "parse error & warning evtlog from evtlog file"; | |||
| 1357 | const char *output = "parse result output file"; | |||
| 1358 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 1359 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 1360 | int err = 0; | |||
| 1361 | ||||
| 1362 | struct config { | |||
| 1363 | char *file; | |||
| 1364 | __u32 namespace_id; | |||
| 1365 | __u32 storage_medium; | |||
| 1366 | bool_Bool parse; | |||
| 1367 | char *output; | |||
| 1368 | }; | |||
| 1369 | struct config cfg = { | |||
| 1370 | .file = NULL((void*)0), | |||
| 1371 | .namespace_id = NVME_NSID_ALL, | |||
| 1372 | .storage_medium = 0, | |||
| 1373 | .parse = false0, | |||
| 1374 | .output = NULL((void*)0), | |||
| 1375 | }; | |||
| 1376 | ||||
| 1377 | NVME_ARGS(opts,struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"file", 'f', "FILE", CFG_STRING, &cfg.file, 1, file , 0, }, {"namespace_id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"storage_medium", 's', "NUM", CFG_POSITIVE , &cfg.storage_medium, 1, storage_medium, 0, }, {"parse", 'p', ((void*)0), CFG_FLAG, &cfg.parse, 0, parse, 0, }, { "output", 'O', "FILE", CFG_STRING, &cfg.output, 1, output , 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0 , "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT , &nvme_args.verbose, 0, "Increase output verbosity", 0, } , {"output-format", 'o', "FMT", CFG_STRING, &nvme_args.output_format , 1, "Output format: normal|json|binary|tabular", 0, }, {"timeout" , 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1, "timeout value, in milliseconds" , 0, }, {"dry-run", 0, ((void*)0), CFG_FLAG, &nvme_args.dry_run , 0, "show command instead of executing", 0, }, {"no-retries" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_retries, 0, "disable retry logic on errors" , 0, }, {"no-ioctl-probing", 0, ((void*)0), CFG_FLAG, &nvme_args .no_ioctl_probing, 0, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version", 0, "NUM", CFG_POSITIVE, & nvme_args.output_format_ver, 1, "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args .verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 1378 | OPT_FILE("file", 'f', &cfg.file, file),struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"file", 'f', "FILE", CFG_STRING, &cfg.file, 1, file , 0, }, {"namespace_id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"storage_medium", 's', "NUM", CFG_POSITIVE , &cfg.storage_medium, 1, storage_medium, 0, }, {"parse", 'p', ((void*)0), CFG_FLAG, &cfg.parse, 0, parse, 0, }, { "output", 'O', "FILE", CFG_STRING, &cfg.output, 1, output , 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0 , "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT , &nvme_args.verbose, 0, "Increase output verbosity", 0, } , {"output-format", 'o', "FMT", CFG_STRING, &nvme_args.output_format , 1, "Output format: normal|json|binary|tabular", 0, }, {"timeout" , 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1, "timeout value, in milliseconds" , 0, }, {"dry-run", 0, ((void*)0), CFG_FLAG, &nvme_args.dry_run , 0, "show command instead of executing", 0, }, {"no-retries" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_retries, 0, "disable retry logic on errors" , 0, }, {"no-ioctl-probing", 0, ((void*)0), CFG_FLAG, &nvme_args .no_ioctl_probing, 0, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version", 0, "NUM", CFG_POSITIVE, & nvme_args.output_format_ver, 1, "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args .verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 1379 | OPT_UINT("namespace_id", 'n', &cfg.namespace_id, namespace_id),struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"file", 'f', "FILE", CFG_STRING, &cfg.file, 1, file , 0, }, {"namespace_id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"storage_medium", 's', "NUM", CFG_POSITIVE , &cfg.storage_medium, 1, storage_medium, 0, }, {"parse", 'p', ((void*)0), CFG_FLAG, &cfg.parse, 0, parse, 0, }, { "output", 'O', "FILE", CFG_STRING, &cfg.output, 1, output , 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0 , "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT , &nvme_args.verbose, 0, "Increase output verbosity", 0, } , {"output-format", 'o', "FMT", CFG_STRING, &nvme_args.output_format , 1, "Output format: normal|json|binary|tabular", 0, }, {"timeout" , 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1, "timeout value, in milliseconds" , 0, }, {"dry-run", 0, ((void*)0), CFG_FLAG, &nvme_args.dry_run , 0, "show command instead of executing", 0, }, {"no-retries" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_retries, 0, "disable retry logic on errors" , 0, }, {"no-ioctl-probing", 0, ((void*)0), CFG_FLAG, &nvme_args .no_ioctl_probing, 0, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version", 0, "NUM", CFG_POSITIVE, & nvme_args.output_format_ver, 1, "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args .verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 1380 | OPT_UINT("storage_medium", 's', &cfg.storage_medium, storage_medium),struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"file", 'f', "FILE", CFG_STRING, &cfg.file, 1, file , 0, }, {"namespace_id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"storage_medium", 's', "NUM", CFG_POSITIVE , &cfg.storage_medium, 1, storage_medium, 0, }, {"parse", 'p', ((void*)0), CFG_FLAG, &cfg.parse, 0, parse, 0, }, { "output", 'O', "FILE", CFG_STRING, &cfg.output, 1, output , 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0 , "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT , &nvme_args.verbose, 0, "Increase output verbosity", 0, } , {"output-format", 'o', "FMT", CFG_STRING, &nvme_args.output_format , 1, "Output format: normal|json|binary|tabular", 0, }, {"timeout" , 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1, "timeout value, in milliseconds" , 0, }, {"dry-run", 0, ((void*)0), CFG_FLAG, &nvme_args.dry_run , 0, "show command instead of executing", 0, }, {"no-retries" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_retries, 0, "disable retry logic on errors" , 0, }, {"no-ioctl-probing", 0, ((void*)0), CFG_FLAG, &nvme_args .no_ioctl_probing, 0, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version", 0, "NUM", CFG_POSITIVE, & nvme_args.output_format_ver, 1, "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args .verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 1381 | OPT_FLAG("parse", 'p', &cfg.parse, parse),struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"file", 'f', "FILE", CFG_STRING, &cfg.file, 1, file , 0, }, {"namespace_id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"storage_medium", 's', "NUM", CFG_POSITIVE , &cfg.storage_medium, 1, storage_medium, 0, }, {"parse", 'p', ((void*)0), CFG_FLAG, &cfg.parse, 0, parse, 0, }, { "output", 'O', "FILE", CFG_STRING, &cfg.output, 1, output , 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0 , "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT , &nvme_args.verbose, 0, "Increase output verbosity", 0, } , {"output-format", 'o', "FMT", CFG_STRING, &nvme_args.output_format , 1, "Output format: normal|json|binary|tabular", 0, }, {"timeout" , 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1, "timeout value, in milliseconds" , 0, }, {"dry-run", 0, ((void*)0), CFG_FLAG, &nvme_args.dry_run , 0, "show command instead of executing", 0, }, {"no-retries" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_retries, 0, "disable retry logic on errors" , 0, }, {"no-ioctl-probing", 0, ((void*)0), CFG_FLAG, &nvme_args .no_ioctl_probing, 0, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version", 0, "NUM", CFG_POSITIVE, & nvme_args.output_format_ver, 1, "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args .verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 1382 | OPT_FILE("output", 'O', &cfg.output, output))struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"file", 'f', "FILE", CFG_STRING, &cfg.file, 1, file , 0, }, {"namespace_id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"storage_medium", 's', "NUM", CFG_POSITIVE , &cfg.storage_medium, 1, storage_medium, 0, }, {"parse", 'p', ((void*)0), CFG_FLAG, &cfg.parse, 0, parse, 0, }, { "output", 'O', "FILE", CFG_STRING, &cfg.output, 1, output , 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0 , "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT , &nvme_args.verbose, 0, "Increase output verbosity", 0, } , {"output-format", 'o', "FMT", CFG_STRING, &nvme_args.output_format , 1, "Output format: normal|json|binary|tabular", 0, }, {"timeout" , 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1, "timeout value, in milliseconds" , 0, }, {"dry-run", 0, ((void*)0), CFG_FLAG, &nvme_args.dry_run , 0, "show command instead of executing", 0, }, {"no-retries" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_retries, 0, "disable retry logic on errors" , 0, }, {"no-ioctl-probing", 0, ((void*)0), CFG_FLAG, &nvme_args .no_ioctl_probing, 0, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version", 0, "NUM", CFG_POSITIVE, & nvme_args.output_format_ver, 1, "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args .verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } }; | |||
| 1383 | ||||
| 1384 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 1385 | if (err) | |||
| 1386 | return err; | |||
| 1387 | ||||
| 1388 | if (!cfg.file) { | |||
| 1389 | fprintf(stderrstderr, "file required param\n"); | |||
| 1390 | return -EINVAL22; | |||
| 1391 | } | |||
| 1392 | ||||
| 1393 | if (cfg.parse && !cfg.output) { | |||
| 1394 | fprintf(stderrstderr, "output file required if evtlog need be parsed\n"); | |||
| 1395 | return -EINVAL22; | |||
| 1396 | } | |||
| 1397 | ||||
| 1398 | err = nvme_dump_evtlog(hdl, cfg.namespace_id, cfg.storage_medium, cfg.file, cfg.parse, cfg.output); | |||
| 1399 | ||||
| 1400 | return 0; | |||
| 1401 | } | |||
| 1402 | ||||
| 1403 | static int nvme_expand_cap(struct libnvme_transport_handle *hdl, __u32 namespace_id, __u64 namespace_size, | |||
| 1404 | __u64 namespace_cap, __u32 lbaf, __u32 units) | |||
| 1405 | { | |||
| 1406 | struct dirent **devices; | |||
| 1407 | char dev_name[32] = ""; | |||
| 1408 | int i = 0; | |||
| 1409 | int num = 0; | |||
| 1410 | int err = 0; | |||
| 1411 | ||||
| 1412 | struct sfx_expand_cap_info { | |||
| 1413 | __u64 namespace_size; | |||
| 1414 | __u64 namespace_cap; | |||
| 1415 | __u8 reserve[10]; | |||
| 1416 | __u8 lbaf; | |||
| 1417 | __u8 reserve1[5]; | |||
| 1418 | } __packed__attribute__((__packed__)); | |||
| 1419 | ||||
| 1420 | if (libnvme_transport_handle_is_ctrl(hdl)) | |||
| 1421 | snprintf(dev_name, 32, "%sn%u", libnvme_transport_handle_get_name(hdl), namespace_id); | |||
| 1422 | else | |||
| 1423 | strcpy(dev_name, libnvme_transport_handle_get_name(hdl)); | |||
| 1424 | ||||
| 1425 | num = scandir("/dev", &devices, libnvme_filter_namespace, alphasort); | |||
| 1426 | if (num <= 0) { | |||
| 1427 | err = num; | |||
| 1428 | goto ret; | |||
| 1429 | } | |||
| 1430 | ||||
| 1431 | if (strcmp(dev_name, devices[num-1]->d_name)) { | |||
| 1432 | fprintf(stderrstderr, "Expand namespace not the last one\n"); | |||
| 1433 | err = EINVAL22; | |||
| 1434 | goto free_devices; | |||
| 1435 | } | |||
| 1436 | ||||
| 1437 | if (!units) { | |||
| 1438 | namespace_size = IDEMA_CAP(namespace_size)(((__u64)namespace_size - 50ULL) * 1953504ULL + 97696368ULL) / (1 << (lbaf * 3)); | |||
| 1439 | namespace_cap = IDEMA_CAP(namespace_cap)(((__u64)namespace_cap - 50ULL) * 1953504ULL + 97696368ULL) / (1 << (lbaf * 3)); | |||
| 1440 | } | |||
| 1441 | ||||
| 1442 | struct sfx_expand_cap_info info = { | |||
| 1443 | .namespace_size = namespace_size, | |||
| 1444 | .namespace_cap = namespace_cap, | |||
| 1445 | .lbaf = lbaf, | |||
| 1446 | }; | |||
| 1447 | ||||
| 1448 | struct libnvme_passthru_cmd cmd = { | |||
| 1449 | .opcode = nvme_admin_ns_mgmt, | |||
| 1450 | .nsid = namespace_id, | |||
| 1451 | .addr = (__u64)(uintptr_t)&info, | |||
| 1452 | .data_len = sizeof(info), | |||
| 1453 | .cdw10 = 0x0e, | |||
| 1454 | }; | |||
| 1455 | ||||
| 1456 | err = libnvme_exec_admin_passthru(hdl, &cmd); | |||
| 1457 | if (err) { | |||
| 1458 | fprintf(stderrstderr, "Create ns failed\n"); | |||
| 1459 | nvme_show_status(err); | |||
| 1460 | goto free_devices; | |||
| 1461 | } | |||
| 1462 | ||||
| 1463 | free_devices: | |||
| 1464 | for (i = 0; i < num; i++) | |||
| 1465 | free(devices[i]); | |||
| 1466 | free(devices); | |||
| 1467 | ret: | |||
| 1468 | return err; | |||
| 1469 | } | |||
| 1470 | ||||
| 1471 | static int sfx_expand_cap(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 1472 | { | |||
| 1473 | char *desc = "expand capacity"; | |||
| 1474 | const char *namespace_id = "desired namespace"; | |||
| 1475 | const char *namespace_size = "namespace size(required)"; | |||
| 1476 | const char *namespace_cap = "namespace capacity(required)"; | |||
| 1477 | const char *lbaf = "LBA format to apply\n" | |||
| 1478 | "0: 512(default) 1: 4096"; | |||
| 1479 | const char *units = "namespace size/capacity units\n" | |||
| 1480 | "0: GB(default) 1: LBA"; | |||
| 1481 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 1482 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 1483 | int err = 0; | |||
| 1484 | ||||
| 1485 | struct config { | |||
| 1486 | __u32 namespace_id; | |||
| 1487 | __u64 namespace_size; | |||
| 1488 | __u64 namespace_cap; | |||
| 1489 | __u32 lbaf; | |||
| 1490 | __u32 units; | |||
| 1491 | }; | |||
| 1492 | struct config cfg = { | |||
| 1493 | .namespace_id = NVME_NSID_ALL, | |||
| 1494 | .lbaf = 0, | |||
| 1495 | .units = 0, | |||
| 1496 | }; | |||
| 1497 | ||||
| 1498 | NVME_ARGS(opts,struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"namespace_id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"namespace_size", 's', "NUM", CFG_LONG , &cfg.namespace_size, 1, namespace_size, 0, }, {"namespace_cap" , 'c', "NUM", CFG_LONG, &cfg.namespace_cap, 1, namespace_cap , 0, }, {"lbaf", 'l', "NUM", CFG_POSITIVE, &cfg.lbaf, 1, lbaf , 0, }, {"units", 'u', "NUM", CFG_POSITIVE, &cfg.units, 1 , units, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void *)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM" , CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 1499 | OPT_UINT("namespace_id", 'n', &cfg.namespace_id, namespace_id),struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"namespace_id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"namespace_size", 's', "NUM", CFG_LONG , &cfg.namespace_size, 1, namespace_size, 0, }, {"namespace_cap" , 'c', "NUM", CFG_LONG, &cfg.namespace_cap, 1, namespace_cap , 0, }, {"lbaf", 'l', "NUM", CFG_POSITIVE, &cfg.lbaf, 1, lbaf , 0, }, {"units", 'u', "NUM", CFG_POSITIVE, &cfg.units, 1 , units, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void *)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM" , CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 1500 | OPT_LONG("namespace_size", 's', &cfg.namespace_size, namespace_size),struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"namespace_id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"namespace_size", 's', "NUM", CFG_LONG , &cfg.namespace_size, 1, namespace_size, 0, }, {"namespace_cap" , 'c', "NUM", CFG_LONG, &cfg.namespace_cap, 1, namespace_cap , 0, }, {"lbaf", 'l', "NUM", CFG_POSITIVE, &cfg.lbaf, 1, lbaf , 0, }, {"units", 'u', "NUM", CFG_POSITIVE, &cfg.units, 1 , units, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void *)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM" , CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 1501 | OPT_LONG("namespace_cap", 'c', &cfg.namespace_cap, namespace_cap),struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"namespace_id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"namespace_size", 's', "NUM", CFG_LONG , &cfg.namespace_size, 1, namespace_size, 0, }, {"namespace_cap" , 'c', "NUM", CFG_LONG, &cfg.namespace_cap, 1, namespace_cap , 0, }, {"lbaf", 'l', "NUM", CFG_POSITIVE, &cfg.lbaf, 1, lbaf , 0, }, {"units", 'u', "NUM", CFG_POSITIVE, &cfg.units, 1 , units, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void *)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM" , CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 1502 | OPT_UINT("lbaf", 'l', &cfg.lbaf, lbaf),struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"namespace_id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"namespace_size", 's', "NUM", CFG_LONG , &cfg.namespace_size, 1, namespace_size, 0, }, {"namespace_cap" , 'c', "NUM", CFG_LONG, &cfg.namespace_cap, 1, namespace_cap , 0, }, {"lbaf", 'l', "NUM", CFG_POSITIVE, &cfg.lbaf, 1, lbaf , 0, }, {"units", 'u', "NUM", CFG_POSITIVE, &cfg.units, 1 , units, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void *)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM" , CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 1503 | OPT_UINT("units", 'u', &cfg.units, units))struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"namespace_id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"namespace_size", 's', "NUM", CFG_LONG , &cfg.namespace_size, 1, namespace_size, 0, }, {"namespace_cap" , 'c', "NUM", CFG_LONG, &cfg.namespace_cap, 1, namespace_cap , 0, }, {"lbaf", 'l', "NUM", CFG_POSITIVE, &cfg.lbaf, 1, lbaf , 0, }, {"units", 'u', "NUM", CFG_POSITIVE, &cfg.units, 1 , units, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void *)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM" , CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } }; | |||
| 1504 | ||||
| 1505 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 1506 | if (err) | |||
| 1507 | return err; | |||
| 1508 | ||||
| 1509 | if (cfg.namespace_id == NVME_NSID_ALL) { | |||
| 1510 | if (libnvme_transport_handle_is_ctrl(hdl)) { | |||
| 1511 | fprintf(stderrstderr, "namespace_id or namespace device required\n"); | |||
| 1512 | return -EINVAL22; | |||
| 1513 | } else { | |||
| 1514 | cfg.namespace_id = atoi(&libnvme_transport_handle_get_name(hdl)[strlen(libnvme_transport_handle_get_name(hdl)) - 1]); | |||
| 1515 | } | |||
| 1516 | } | |||
| 1517 | ||||
| 1518 | if (!cfg.namespace_size) { | |||
| 1519 | fprintf(stderrstderr, "namespace_size required param\n"); | |||
| 1520 | return -EINVAL22; | |||
| 1521 | } | |||
| 1522 | ||||
| 1523 | if (!cfg.namespace_cap) { | |||
| 1524 | fprintf(stderrstderr, "namespace_cap required param\n"); | |||
| 1525 | return -EINVAL22; | |||
| 1526 | } | |||
| 1527 | ||||
| 1528 | err = nvme_expand_cap(hdl, cfg.namespace_id, cfg.namespace_size, cfg.namespace_cap, cfg.lbaf, cfg.units); | |||
| 1529 | if (err) | |||
| 1530 | return err; | |||
| 1531 | ||||
| 1532 | printf("%s: Success, create nsid:%d\n", acmd->name, cfg.namespace_id); | |||
| 1533 | ||||
| 1534 | return 0; | |||
| 1535 | } | |||
| 1536 | ||||
| 1537 | static int sfx_status(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 1538 | { | |||
| 1539 | const char *desc = "Get ScaleFlux specific status information and print it"; | |||
| 1540 | const char *json_desc = "Print output in JSON format, otherwise human readable"; | |||
| 1541 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 1542 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 1543 | struct nvme_id_ctrl id_ctrl = { 0 }; | |||
| 1544 | struct extended_health_info_myrtle sfx_smart = { 0 }; | |||
| 1545 | struct nvme_smart_log smart_log = { 0 }; | |||
| 1546 | struct nvme_additional_smart_log additional_smart_log = { 0 }; | |||
| 1547 | struct sfx_freespace_ctx sfx_freespace = { 0 }; | |||
| 1548 | unsigned int pcie_correctable, pcie_fatal, pcie_nonfatal; | |||
| 1549 | unsigned long long capacity; | |||
| ||||
| 1550 | bool_Bool capacity_valid = false0; | |||
| 1551 | bool_Bool pcie_cor_valid, pcie_fatal_valid, pcie_nonfatal_valid; | |||
| 1552 | int err, fd, len, sector_size; | |||
| 1553 | char pci_vid[7], pci_did[7], pci_ssvid[7], link_speed[20], link_width[5], link_string[40]; | |||
| 1554 | char path[512], numa_node[5], vendor[10], form_factor[15], temperature[10], io_speed[15]; | |||
| 1555 | char chr_dev[8], serial_number[21], model_number[41], firmware_revision[9], pcie_status[9]; | |||
| 1556 | struct json_object *root, *dev_stats, *link_stats, *crit_stats; | |||
| 1557 | nvme_print_flags_t flags; | |||
| 1558 | __u64 get_feat_result; | |||
| 1559 | double write_amp; | |||
| 1560 | ||||
| 1561 | struct config { | |||
| 1562 | bool_Bool json; | |||
| 1563 | }; | |||
| 1564 | struct config cfg = { | |||
| 1565 | .json = false0 | |||
| 1566 | }; | |||
| 1567 | ||||
| 1568 | NVME_ARGS(opts,struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"json-print", 'j', ((void*)0), CFG_FLAG, &cfg.json , 0, json_desc, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR , ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose" , 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } } | |||
| 1569 | OPT_FLAG("json-print", 'j', &cfg.json, json_desc))struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"json-print", 'j', ((void*)0), CFG_FLAG, &cfg.json , 0, json_desc, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR , ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose" , 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary|tabular" , 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout , 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, ( (void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, { ((void*)0) } }; | |||
| 1570 | ||||
| 1571 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 1572 | if (err) | |||
| 1573 | return err; | |||
| 1574 | ||||
| 1575 | err = validate_output_format(nvme_args.output_format, &flags); | |||
| 1576 | if (err < 0) { | |||
| 1577 | nvme_show_error("Invalid output format")nvme_show_message(1, "Invalid output format"); | |||
| 1578 | return err; | |||
| 1579 | } | |||
| 1580 | ||||
| 1581 | //Calculate formatted capacity, not concerned with errors, we may have a char device | |||
| 1582 | memset(&path, 0, 512); | |||
| 1583 | snprintf(path, 512, "/dev/%s", libnvme_transport_handle_get_name(hdl)); | |||
| 1584 | fd = open(path, O_RDONLY00 | O_NONBLOCK04000); | |||
| 1585 | if (fd
| |||
| 1586 | err = ioctl(fd, BLKSSZGET(((0U) << (((0 +8)+8)+14)) | (((0x12)) << (0 +8)) | (((104)) << 0) | ((0) << ((0 +8)+8))), §or_size); | |||
| 1587 | if (!err) | |||
| 1588 | err = ioctl(fd, BLKGETSIZE64(((2U) << (((0 +8)+8)+14)) | (((0x12)) << (0 +8)) | (((114)) << 0) | ((((sizeof(size_t)))) << ((0 + 8)+8))), &capacity); | |||
| 1589 | capacity_valid = (!err); | |||
| 1590 | } | |||
| 1591 | ||||
| 1592 | if (capacity_valid
| |||
| 1593 | capacity = IDEMA_CAP2GB(capacity/sector_size)(((__u64)capacity/sector_size - 97696368ULL) / 1953504ULL + 50ULL ); | |||
| 1594 | else if (capacity_valid
| |||
| 1595 | capacity = IDEMA_CAP2GB_LDS(capacity/sector_size)(((__u64)capacity/sector_size - 12212046ULL) / 244188ULL + 50ULL ); | |||
| 1596 | else | |||
| 1597 | capacity = capacity / (1000 * 1000 * 1000); //B --> GB | |||
| ||||
| 1598 | ||||
| 1599 | memset(&chr_dev, 0, 8); | |||
| 1600 | strcpy(chr_dev, libnvme_transport_handle_get_name(hdl)); | |||
| 1601 | for (len = 2; len < 8; len++) { | |||
| 1602 | if (chr_dev[len] == 'n') | |||
| 1603 | chr_dev[len] = '\0'; | |||
| 1604 | } | |||
| 1605 | ||||
| 1606 | // Populate PCIe VID/DID/SS_VID, link speed/width, and NUMA node from /sys/ | |||
| 1607 | snprintf(path, 512, "/sys/class/nvme/%s/device/vendor", chr_dev); | |||
| 1608 | fd = open(path, O_RDONLY00); | |||
| 1609 | if (fd < 0) { | |||
| 1610 | perror("Could not open PCIe VID in /sys/"); | |||
| 1611 | return -errno(*__errno_location ()); | |||
| 1612 | } | |||
| 1613 | memset(&pci_vid, 0, 7); | |||
| 1614 | len = read(fd, pci_vid, 6); | |||
| 1615 | if (len < 1) { | |||
| 1616 | perror("Could not read PCIe VID in /sys/"); | |||
| 1617 | close(fd); | |||
| 1618 | return -errno(*__errno_location ()); | |||
| 1619 | } | |||
| 1620 | close(fd); | |||
| 1621 | ||||
| 1622 | snprintf(path, 512, "/sys/class/nvme/%s/device/device", chr_dev); | |||
| 1623 | fd = open(path, O_RDONLY00); | |||
| 1624 | if (fd < 0) { | |||
| 1625 | perror("Could not open PCIe DID in /sys/"); | |||
| 1626 | return -errno(*__errno_location ()); | |||
| 1627 | } | |||
| 1628 | memset(&pci_did, 0, 7); | |||
| 1629 | len = read(fd, pci_did, 6); | |||
| 1630 | if (len < 1) { | |||
| 1631 | perror("Could not read PCIe DID in /sys/"); | |||
| 1632 | close(fd); | |||
| 1633 | return -errno(*__errno_location ()); | |||
| 1634 | } | |||
| 1635 | close(fd); | |||
| 1636 | ||||
| 1637 | if (strncmp("0xcc53", pci_vid, 6) == 0) | |||
| 1638 | strncpy(vendor, "ScaleFlux", 10); | |||
| 1639 | else if (strncmp("0x1dfd", pci_vid, 6) == 0) | |||
| 1640 | strncpy(vendor, "DIGISTOR", 10); | |||
| 1641 | else { | |||
| 1642 | fprintf(stderrstderr, "Please use on a ScaleFlux device\n"); | |||
| 1643 | return -1; | |||
| 1644 | } | |||
| 1645 | ||||
| 1646 | snprintf(path, 512, "/sys/class/nvme/%s/device/subsystem_vendor", chr_dev); | |||
| 1647 | fd = open(path, O_RDONLY00); | |||
| 1648 | if (fd < 0) { | |||
| 1649 | perror("Could not open PCIe Subsystem Vendor ID in /sys/"); | |||
| 1650 | return -errno(*__errno_location ()); | |||
| 1651 | } | |||
| 1652 | memset(&pci_ssvid, 0, 7); | |||
| 1653 | len = read(fd, pci_ssvid, 6); | |||
| 1654 | if (len < 1) { | |||
| 1655 | perror("could not read PCIe Subsystem Vendor ID in /sys/"); | |||
| 1656 | close(fd); | |||
| 1657 | return -errno(*__errno_location ()); | |||
| 1658 | } | |||
| 1659 | close(fd); | |||
| 1660 | ||||
| 1661 | snprintf(path, 512, "/sys/class/nvme/%s/device/current_link_speed", chr_dev); | |||
| 1662 | fd = open(path, O_RDONLY00); | |||
| 1663 | if (fd < 0) { | |||
| 1664 | perror("Could not open link speed in /sys/"); | |||
| 1665 | return -errno(*__errno_location ()); | |||
| 1666 | } | |||
| 1667 | memset(&link_speed, 0, 20); | |||
| 1668 | len = read(fd, link_speed, 20); | |||
| 1669 | if (len < 1) { | |||
| 1670 | perror("Could not read link speed in /sys/"); | |||
| 1671 | close(fd); | |||
| 1672 | return -errno(*__errno_location ()); | |||
| 1673 | } | |||
| 1674 | close(fd); | |||
| 1675 | // Ending string before "PCIe" and newline | |||
| 1676 | for (len = 0; (len+2) < 20 && link_speed[len+2] != '\0'; ++len) { | |||
| 1677 | if (link_speed[len] == '/' && link_speed[len+1] == 's') | |||
| 1678 | link_speed[len+2] = '\0'; | |||
| 1679 | } | |||
| 1680 | ||||
| 1681 | snprintf(path, 512, "/sys/class/nvme/%s/device/current_link_width", chr_dev); | |||
| 1682 | fd = open(path, O_RDONLY00); | |||
| 1683 | if (fd < 0) { | |||
| 1684 | perror("Could not open link width in /sys/"); | |||
| 1685 | return -errno(*__errno_location ()); | |||
| 1686 | } | |||
| 1687 | memset(&link_width, 0, 5); | |||
| 1688 | len = read(fd, link_width, 5); | |||
| 1689 | if (len < 1) { | |||
| 1690 | perror("Could not read link width in /sys/"); | |||
| 1691 | close(fd); | |||
| 1692 | return -errno(*__errno_location ()); | |||
| 1693 | } | |||
| 1694 | close(fd); | |||
| 1695 | // Ending string before newline | |||
| 1696 | for (len = 0; (len) < 5 ; ++len) { | |||
| 1697 | if (link_width[len] == '\n') | |||
| 1698 | link_width[len] = '\0'; | |||
| 1699 | } | |||
| 1700 | ||||
| 1701 | snprintf(link_string, 40, "Speed %s, Width x%s", link_speed, link_width); | |||
| 1702 | ||||
| 1703 | snprintf(path, 512, "/sys/class/nvme/%s/device/numa_node", chr_dev); | |||
| 1704 | fd = open(path, O_RDONLY00); | |||
| 1705 | if (fd < 0) { | |||
| 1706 | perror("Could not open NUMA node in /sys/"); | |||
| 1707 | return -errno(*__errno_location ()); | |||
| 1708 | } | |||
| 1709 | memset(&numa_node, 0, 5); | |||
| 1710 | len = read(fd, numa_node, 5); | |||
| 1711 | if (len < 1) { | |||
| 1712 | perror("Could not read NUMA node in /sys/"); | |||
| 1713 | close(fd); | |||
| 1714 | return -errno(*__errno_location ()); | |||
| 1715 | } | |||
| 1716 | close(fd); | |||
| 1717 | ||||
| 1718 | for (len = 0; len < 5; ++len) { | |||
| 1719 | if (numa_node[len] == '\n') | |||
| 1720 | numa_node[len] = '\0'; | |||
| 1721 | } | |||
| 1722 | ||||
| 1723 | //Populate PCIe AER errors from /sys/ | |||
| 1724 | snprintf(path, 512, "/sys/class/nvme/%s/device/aer_dev_correctable", chr_dev); | |||
| 1725 | pcie_cor_valid = true1; | |||
| 1726 | fd = open(path, O_RDONLY00); | |||
| 1727 | if (fd < 0) { | |||
| 1728 | perror("Could not open PCIe AER Correctable errors in /sys/"); | |||
| 1729 | pcie_cor_valid = false0; | |||
| 1730 | } | |||
| 1731 | ||||
| 1732 | if (pcie_cor_valid) { | |||
| 1733 | len = read(fd, path, 512); | |||
| 1734 | if (len < 1) { | |||
| 1735 | perror("Could not read PCIe AER Correctable errors in /sys/"); | |||
| 1736 | pcie_cor_valid = false0; | |||
| 1737 | } | |||
| 1738 | close(fd); | |||
| 1739 | } | |||
| 1740 | if (pcie_cor_valid) { | |||
| 1741 | len = sscanf(path, "%*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d TOTAL_ERR_COR %d", &pcie_correctable); | |||
| 1742 | if (len < 1 || len == EOF(-1)) { | |||
| 1743 | perror("Could not parse PCIe AER Correctable errors in /sys/"); | |||
| 1744 | pcie_cor_valid = false0; | |||
| 1745 | } | |||
| 1746 | } | |||
| 1747 | ||||
| 1748 | snprintf(path, 512, "/sys/class/nvme/%s/device/aer_dev_nonfatal", chr_dev); | |||
| 1749 | pcie_nonfatal_valid = true1; | |||
| 1750 | fd = open(path, O_RDONLY00); | |||
| 1751 | if (fd < 0) { | |||
| 1752 | perror("Could not open PCIe AER Non-Fatal errors in /sys/"); | |||
| 1753 | pcie_nonfatal_valid = false0; | |||
| 1754 | } | |||
| 1755 | ||||
| 1756 | if (pcie_nonfatal_valid) { | |||
| 1757 | len = read(fd, path, 512); | |||
| 1758 | if (len < 1) { | |||
| 1759 | perror("Could not read PCIe AER Non-Fatal errors in /sys/"); | |||
| 1760 | pcie_nonfatal_valid = false0; | |||
| 1761 | } | |||
| 1762 | close(fd); | |||
| 1763 | } | |||
| 1764 | if (pcie_nonfatal_valid) { | |||
| 1765 | len = sscanf(path, "%*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d TOTAL_ERR_NONFATAL %d", &pcie_nonfatal); | |||
| 1766 | if (len < 1) { | |||
| 1767 | perror("Could not parse PCIe AER Non-Fatal errors in /sys/"); | |||
| 1768 | pcie_nonfatal_valid = false0; | |||
| 1769 | } | |||
| 1770 | } | |||
| 1771 | snprintf(path, 512, "/sys/class/nvme/%s/device/aer_dev_fatal", chr_dev); | |||
| 1772 | pcie_fatal_valid = true1; | |||
| 1773 | fd = open(path, O_RDONLY00); | |||
| 1774 | if (fd < 0) { | |||
| 1775 | perror("Could not open PCIe AER Fatal errors in /sys/"); | |||
| 1776 | pcie_fatal_valid = false0; | |||
| 1777 | } | |||
| 1778 | ||||
| 1779 | if (pcie_fatal_valid) { | |||
| 1780 | len = read(fd, path, 512); | |||
| 1781 | if (len < 1) { | |||
| 1782 | perror("Could not read PCIe AER Fatal errors in /sys/"); | |||
| 1783 | pcie_fatal_valid = false0; | |||
| 1784 | } | |||
| 1785 | close(fd); | |||
| 1786 | } | |||
| 1787 | if (pcie_fatal_valid) { | |||
| 1788 | len = sscanf(path, "%*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d %*s %*d TOTAL_ERR_FATAL %d", &pcie_fatal); | |||
| 1789 | if (len < 1) { | |||
| 1790 | perror("Could not parse PCIe AER Fatal errors in /sys/"); | |||
| 1791 | close(fd); | |||
| 1792 | pcie_fatal_valid = false0; | |||
| 1793 | } | |||
| 1794 | } | |||
| 1795 | ||||
| 1796 | if (pcie_cor_valid && pcie_nonfatal_valid && pcie_fatal_valid) | |||
| 1797 | snprintf(pcie_status, 9, "%s", (pcie_fatal != 0 || pcie_nonfatal != 0 || pcie_correctable != 0) ? "Warning":"Good"); | |||
| 1798 | else | |||
| 1799 | snprintf(pcie_status, 9, "%s", "Unknown"); | |||
| 1800 | ||||
| 1801 | //Populate id-ctrl | |||
| 1802 | err = nvme_identify_ctrl(hdl, &id_ctrl); | |||
| 1803 | if (err) { | |||
| 1804 | fprintf(stderrstderr, "Unable to read nvme_identify_ctrl() error code:%x\n", err); | |||
| 1805 | return err; | |||
| 1806 | } | |||
| 1807 | //Re-format specific fields so they can be safely treated as strings later | |||
| 1808 | serial_number[20] = '\0'; | |||
| 1809 | memcpy(serial_number, id_ctrl.sn, 20); | |||
| 1810 | model_number[40] = '\0'; | |||
| 1811 | memcpy(model_number, id_ctrl.mn, 40); | |||
| 1812 | firmware_revision[8] = '\0'; | |||
| 1813 | memcpy(firmware_revision, id_ctrl.fr, 8); | |||
| 1814 | ||||
| 1815 | //Populate SMART log (0x02) | |||
| 1816 | err = nvme_get_log_smart(hdl, NVME_NSID_ALL, &smart_log); | |||
| 1817 | if (err < 0) { | |||
| 1818 | perror("Could not read SMART log (0x02)"); | |||
| 1819 | return -errno(*__errno_location ()); | |||
| 1820 | } else if (err > 0) { | |||
| 1821 | nvme_show_status(err); | |||
| 1822 | return err; | |||
| 1823 | } | |||
| 1824 | ||||
| 1825 | snprintf(temperature, 10, "%li", kelvin_to_celsius(smart_log.temperature[1]<<8 | smart_log.temperature[0])); | |||
| 1826 | ||||
| 1827 | //Populate SFX Extended Health log (0xC2) or if PCIe DID ==0x20 (Quince) use 0xD2 | |||
| 1828 | if (strncmp("0x0020", pci_did, 6) == 0) | |||
| 1829 | err = nvme_get_log_simple(hdl, SFX_LOG_EXTENDED_HEALTH_ALT, (void *)&sfx_smart, | |||
| 1830 | sizeof(sfx_smart)); | |||
| 1831 | else | |||
| 1832 | err = nvme_get_log_simple(hdl, SFX_LOG_EXTENDED_HEALTH, (void *)&sfx_smart, | |||
| 1833 | sizeof(sfx_smart)); | |||
| 1834 | if (err < 0) { | |||
| 1835 | perror("Could not read ScaleFlux SMART log"); | |||
| 1836 | return -errno(*__errno_location ()); | |||
| 1837 | } else if (err > 0) { | |||
| 1838 | nvme_show_status(err); | |||
| 1839 | return err; | |||
| 1840 | } | |||
| 1841 | ||||
| 1842 | //Make sure the OPN can be printed safely | |||
| 1843 | sfx_smart.opn[10] = '\0'; | |||
| 1844 | ||||
| 1845 | switch (sfx_smart.opn[3]) { | |||
| 1846 | case 'P': | |||
| 1847 | snprintf(form_factor, 15, "%s", "AIC"); | |||
| 1848 | break; | |||
| 1849 | case 'U': | |||
| 1850 | snprintf(form_factor, 15, "%s", (sfx_smart.opn[4] == '8')?"U.3":"U.2"); | |||
| 1851 | break; | |||
| 1852 | case 'E': | |||
| 1853 | snprintf(form_factor, 15, "%s", "E1.S"); | |||
| 1854 | break; | |||
| 1855 | default: | |||
| 1856 | snprintf(form_factor, 15, "%s", "Incorrect OPN"); | |||
| 1857 | } | |||
| 1858 | ||||
| 1859 | //Populate Additional SMART log (0xCA) | |||
| 1860 | err = nvme_get_nsid_log(hdl, NVME_NSID_ALL, false0, 0xca, (void *)&additional_smart_log, | |||
| 1861 | sizeof(struct nvme_additional_smart_log)); | |||
| 1862 | if (err < 0) { | |||
| 1863 | perror("Could not read ScaleFlux SMART log"); | |||
| 1864 | return -errno(*__errno_location ()); | |||
| 1865 | } else if (err > 0) { | |||
| 1866 | nvme_show_status(err); | |||
| 1867 | return err; | |||
| 1868 | } | |||
| 1869 | ||||
| 1870 | //OK with the '-nan' if host_bytes_written is zero | |||
| 1871 | write_amp = int48_to_long(additional_smart_log.nand_bytes_written.raw)/(1.0 * int48_to_long(additional_smart_log.host_bytes_written.raw)); | |||
| 1872 | ||||
| 1873 | //Get SFX freespace information | |||
| 1874 | err = nvme_query_cap(hdl, NVME_NSID_ALL, sizeof(sfx_freespace), &sfx_freespace); | |||
| 1875 | if (err < 0) { | |||
| 1876 | perror("Could not query freespace information (0xD6)"); | |||
| 1877 | return -errno(*__errno_location ()); | |||
| 1878 | } else if (err > 0) { | |||
| 1879 | nvme_show_status(err); | |||
| 1880 | return err; | |||
| 1881 | } | |||
| 1882 | ||||
| 1883 | //Parse IO Speed information | |||
| 1884 | memset(&io_speed, 0, 15); | |||
| 1885 | switch (sfx_smart.io_speed) { | |||
| 1886 | case '1': | |||
| 1887 | if (strncmp("0x0020", pci_did, 6)) | |||
| 1888 | strncpy(io_speed, "2.5MB/s", 15); | |||
| 1889 | else | |||
| 1890 | strncpy(io_speed, "10MB/s", 15); | |||
| 1891 | break; | |||
| 1892 | case '2': | |||
| 1893 | if (strncmp("0x0020", pci_did, 6)) | |||
| 1894 | strncpy(io_speed, "128KB/s", 15); | |||
| 1895 | else | |||
| 1896 | strncpy(io_speed, "512KB/s", 15); | |||
| 1897 | break; | |||
| 1898 | case '3': | |||
| 1899 | strncpy(io_speed, "Write Reject", 15); | |||
| 1900 | break; | |||
| 1901 | default: | |||
| 1902 | strncpy(io_speed, "Normal", 15); | |||
| 1903 | } | |||
| 1904 | ||||
| 1905 | if (sfx_smart.comp_ratio < 100) | |||
| 1906 | sfx_smart.comp_ratio = 100; | |||
| 1907 | else if (sfx_smart.comp_ratio > 800) | |||
| 1908 | sfx_smart.comp_ratio = 800; | |||
| 1909 | ||||
| 1910 | //Get status of atomic write feature | |||
| 1911 | err = nvme_get_features(hdl, 0, 0x0A, 0, 0, 0, NULL((void*)0), 0, &get_feat_result); | |||
| 1912 | if (err < 0) { | |||
| 1913 | perror("Could not get feature (0x0A)"); | |||
| 1914 | return -errno(*__errno_location ()); | |||
| 1915 | } else if (err > 0) { | |||
| 1916 | nvme_show_status(err); | |||
| 1917 | return err; | |||
| 1918 | } | |||
| 1919 | ||||
| 1920 | if (flags & JSON || cfg.json) { | |||
| 1921 | root = json_create_object()json_object_new_object(); | |||
| 1922 | json_object_add_value_string(root, "ScaleFlux Status", libnvme_transport_handle_get_name(hdl)); | |||
| 1923 | ||||
| 1924 | dev_stats = json_create_object()json_object_new_object(); | |||
| 1925 | link_stats = json_create_object()json_object_new_object(); | |||
| 1926 | crit_stats = json_create_object()json_object_new_object(); | |||
| 1927 | ||||
| 1928 | json_object_add_value_string(dev_stats, "PCIe Vendor ID", pci_vid); | |||
| 1929 | json_object_add_value_string(dev_stats, "PCIe Subsystem Vendor ID", pci_ssvid); | |||
| 1930 | json_object_add_value_string(dev_stats, "Manufacturer", vendor); | |||
| 1931 | json_object_add_value_string(dev_stats, "Model", model_number); | |||
| 1932 | json_object_add_value_string(dev_stats, "Serial Number", serial_number); | |||
| 1933 | json_object_add_value_string(dev_stats, "OPN", (char *)sfx_smart.opn); | |||
| 1934 | json_object_add_value_string(dev_stats, "Drive Type", form_factor); | |||
| 1935 | json_object_add_value_string(dev_stats, "Firmware Revision", firmware_revision); | |||
| 1936 | json_object_add_value_string(dev_stats, "Temperature [C]", temperature); | |||
| 1937 | json_object_add_value_uint(dev_stats, "Power Consumption [mW]", sfx_smart.power_mw_consumption)json_object_object_add(dev_stats, "Power Consumption [mW]", json_object_new_uint64 (sfx_smart.power_mw_consumption)); | |||
| 1938 | json_object_add_value_uint(dev_stats, "Atomic Write Mode", (get_feat_result))json_object_object_add(dev_stats, "Atomic Write Mode", json_object_new_uint64 ((get_feat_result))); | |||
| 1939 | json_object_add_value_int(dev_stats, "Percentage Used", smart_log.percent_used)json_object_object_add(dev_stats, "Percentage Used", json_object_new_int (smart_log.percent_used)); | |||
| 1940 | json_object_add_value_string(dev_stats, "Data Read", uint128_t_to_si_string(le128_to_cpu(smart_log.data_units_read), 1000 * 512)); | |||
| 1941 | json_object_add_value_string(dev_stats, "Data Written", uint128_t_to_si_string(le128_to_cpu(smart_log.data_units_written), 1000 * 512)); | |||
| 1942 | json_object_add_value_int(dev_stats, "Correctable Error Count", sfx_smart.pcie_rx_correct_errs)json_object_object_add(dev_stats, "Correctable Error Count", json_object_new_int (sfx_smart.pcie_rx_correct_errs)); | |||
| 1943 | json_object_add_value_int(dev_stats, "Uncorrectable Error Count", sfx_smart.pcie_rx_uncorrect_errs)json_object_object_add(dev_stats, "Uncorrectable Error Count" , json_object_new_int(sfx_smart.pcie_rx_uncorrect_errs)); | |||
| 1944 | json_object_add_value_string(link_stats, "PCIe Link Width", link_width); | |||
| 1945 | json_object_add_value_string(link_stats, "PCIe Link Speed", link_speed); | |||
| 1946 | if (pcie_fatal_valid) | |||
| 1947 | json_object_add_value_int(link_stats, "PCIe Link Fatal Errors", pcie_fatal)json_object_object_add(link_stats, "PCIe Link Fatal Errors", json_object_new_int (pcie_fatal)); | |||
| 1948 | if (pcie_nonfatal_valid) | |||
| 1949 | json_object_add_value_int(link_stats, "PCIe Link Non-Fatal Errors", pcie_nonfatal)json_object_object_add(link_stats, "PCIe Link Non-Fatal Errors" , json_object_new_int(pcie_nonfatal)); | |||
| 1950 | if (pcie_cor_valid) | |||
| 1951 | json_object_add_value_int(link_stats, "PCIe Link Correctable Errors", pcie_correctable)json_object_object_add(link_stats, "PCIe Link Correctable Errors" , json_object_new_int(pcie_correctable)); | |||
| 1952 | json_object_add_value_string(link_stats, "PCIe Device Status", pcie_status); | |||
| 1953 | json_object_add_value_object(dev_stats, "PCIe Link Status", link_stats)json_object_object_add(dev_stats, "PCIe Link Status", link_stats ); | |||
| 1954 | if (sfx_smart.friendly_changecap_support) { | |||
| 1955 | json_object_add_value_int(dev_stats, "Current Formatted Capacity [GB]", sfx_smart.cur_formatted_capability)json_object_object_add(dev_stats, "Current Formatted Capacity [GB]" , json_object_new_int(sfx_smart.cur_formatted_capability)); | |||
| 1956 | json_object_add_value_int(dev_stats, "Max Formatted Capacity [GB]", sfx_smart.max_formatted_capability)json_object_object_add(dev_stats, "Max Formatted Capacity [GB]" , json_object_new_int(sfx_smart.max_formatted_capability)); | |||
| 1957 | json_object_add_value_int(dev_stats, "Extendible Capacity LBA count", sfx_smart.extendible_cap_lbacount)json_object_object_add(dev_stats, "Extendible Capacity LBA count" , json_object_new_int(sfx_smart.extendible_cap_lbacount)); | |||
| 1958 | } else if (capacity_valid) | |||
| 1959 | json_object_add_value_int(dev_stats, "Formatted Capacity [GB]", capacity)json_object_object_add(dev_stats, "Formatted Capacity [GB]", json_object_new_int(capacity)); | |||
| 1960 | ||||
| 1961 | json_object_add_value_int(dev_stats, "Provisioned Capacity [GB]", IDEMA_CAP2GB(sfx_smart.total_physical_capability))json_object_object_add(dev_stats, "Provisioned Capacity [GB]" , json_object_new_int((((__u64)sfx_smart.total_physical_capability - 97696368ULL) / 1953504ULL + 50ULL))); | |||
| 1962 | json_object_add_value_int(dev_stats, "Compression Ratio", sfx_smart.comp_ratio)json_object_object_add(dev_stats, "Compression Ratio", json_object_new_int (sfx_smart.comp_ratio)); | |||
| 1963 | json_object_add_value_int(dev_stats, "Physical Used Ratio", sfx_smart.physical_usage_ratio)json_object_object_add(dev_stats, "Physical Used Ratio", json_object_new_int (sfx_smart.physical_usage_ratio)); | |||
| 1964 | json_object_add_value_int(dev_stats, "Free Physical Space [GB]", IDEMA_CAP2GB(sfx_smart.free_physical_capability))json_object_object_add(dev_stats, "Free Physical Space [GB]", json_object_new_int((((__u64)sfx_smart.free_physical_capability - 97696368ULL) / 1953504ULL + 50ULL))); | |||
| 1965 | json_object_add_value_int(dev_stats, "Firmware RSA Verification", (sfx_smart.otp_rsa_en))json_object_object_add(dev_stats, "Firmware RSA Verification" , json_object_new_int((sfx_smart.otp_rsa_en))); | |||
| 1966 | json_object_add_value_string(dev_stats, "IO Speed", io_speed); | |||
| 1967 | json_object_add_value_string(dev_stats, "NUMA Node", numa_node); | |||
| 1968 | json_object_add_value_int(dev_stats, "Indirection Unit [kiB]", (4*sfx_freespace.map_unit))json_object_object_add(dev_stats, "Indirection Unit [kiB]", json_object_new_int ((4*sfx_freespace.map_unit))); | |||
| 1969 | json_object_add_value_double(dev_stats, "Lifetime WAF", write_amp)json_object_object_add(dev_stats, "Lifetime WAF", util_json_object_new_double (write_amp)); | |||
| 1970 | ||||
| 1971 | json_object_add_value_int(crit_stats, "Thermal Throttling On", (sfx_smart.temp_throttle_info))json_object_object_add(crit_stats, "Thermal Throttling On", json_object_new_int ((sfx_smart.temp_throttle_info))); | |||
| 1972 | json_object_add_value_int(crit_stats, "Backup Capacitor Status Bad", (smart_log.critical_warning & 0x10))json_object_object_add(crit_stats, "Backup Capacitor Status Bad" , json_object_new_int((smart_log.critical_warning & 0x10) )); | |||
| 1973 | json_object_add_value_int(crit_stats, "Bad block exceeds threshold", (smart_log.critical_warning & 0x01))json_object_object_add(crit_stats, "Bad block exceeds threshold" , json_object_new_int((smart_log.critical_warning & 0x01) )); | |||
| 1974 | json_object_add_value_int(crit_stats, "Media Error", (smart_log.critical_warning & 0x04))json_object_object_add(crit_stats, "Media Error", json_object_new_int ((smart_log.critical_warning & 0x04))); | |||
| 1975 | json_object_add_value_int(crit_stats, "Read only mode", (smart_log.critical_warning & 0x08))json_object_object_add(crit_stats, "Read only mode", json_object_new_int ((smart_log.critical_warning & 0x08))); | |||
| 1976 | json_object_add_value_int(crit_stats, "Power Failure Data Loss", (sfx_smart.sfx_critical_warning & SFX_CRIT_PWR_FAIL_DATA_LOSS))json_object_object_add(crit_stats, "Power Failure Data Loss", json_object_new_int((sfx_smart.sfx_critical_warning & SFX_CRIT_PWR_FAIL_DATA_LOSS ))); | |||
| 1977 | json_object_add_value_int(crit_stats, "Exceed physical capacity limitation", (sfx_smart.sfx_critical_warning & SFX_CRIT_OVER_CAP))json_object_object_add(crit_stats, "Exceed physical capacity limitation" , json_object_new_int((sfx_smart.sfx_critical_warning & SFX_CRIT_OVER_CAP ))); | |||
| 1978 | json_object_add_value_int(crit_stats, "Read/Write lock mode", (sfx_smart.sfx_critical_warning & SFX_CRIT_RW_LOCK))json_object_object_add(crit_stats, "Read/Write lock mode", json_object_new_int ((sfx_smart.sfx_critical_warning & SFX_CRIT_RW_LOCK))); | |||
| 1979 | ||||
| 1980 | json_object_add_value_object(dev_stats, "Critical Warning(s)", crit_stats)json_object_object_add(dev_stats, "Critical Warning(s)", crit_stats ); | |||
| 1981 | ||||
| 1982 | json_object_add_value_object(root, "Device stats", dev_stats)json_object_object_add(root, "Device stats", dev_stats); | |||
| 1983 | ||||
| 1984 | json_print_object(root, NULL)printf("%s", json_object_to_json_string_ext(root, (1 << 1) | (1 << 4))); | |||
| 1985 | printf("\n"); | |||
| 1986 | json_free_object(root)json_object_put(root); | |||
| 1987 | ||||
| 1988 | } else { | |||
| 1989 | // Re-using path variable to hold critical warning text | |||
| 1990 | // order is to match sfx-status, done here to include color | |||
| 1991 | memset(path, 0, 512); | |||
| 1992 | len = snprintf(path, 512, FMT_RED"\x1b[31m" "\n%s%s%s%s%s%s%s%s" FMT_RESET"\x1b[0m", \ | |||
| 1993 | (sfx_smart.temp_throttle_info) ? "\tThermal Throttling On\n" : "", \ | |||
| 1994 | (smart_log.critical_warning & 0x10) ? "\tBackup Capacitor Status Bad\n" : "", \ | |||
| 1995 | (smart_log.critical_warning & 0x01) ? "\tBad block exceeds threshold\n" : "", \ | |||
| 1996 | (smart_log.critical_warning & 0x04) ? "\tMedia Error\n" : "", \ | |||
| 1997 | (smart_log.critical_warning & 0x08) ? "\tRead only mode\n" : "", \ | |||
| 1998 | (sfx_smart.sfx_critical_warning & SFX_CRIT_PWR_FAIL_DATA_LOSS) ? "\tPower Failure Data Loss\n" : "", \ | |||
| 1999 | (sfx_smart.sfx_critical_warning & SFX_CRIT_OVER_CAP) ? "\tExceed physical capacity limitation\n" : "", \ | |||
| 2000 | (sfx_smart.sfx_critical_warning & SFX_CRIT_RW_LOCK) ? "\tRead/Write lock mode\n" : "" \ | |||
| 2001 | ); | |||
| 2002 | if (len < 11) | |||
| 2003 | strcpy(path, "None"); | |||
| 2004 | ||||
| 2005 | printf("%-35s%s%s\n", "ScaleFlux Drive:", "/dev/", libnvme_transport_handle_get_name(hdl)); | |||
| 2006 | printf("%-35s%s\n", "PCIe Vendor ID:", pci_vid); | |||
| 2007 | printf("%-35s%s\n", "PCIe Subsystem Vendor ID:", pci_ssvid); | |||
| 2008 | printf("%-35s%s\n", "Manufacturer:", vendor); | |||
| 2009 | printf("%-35s%.*s\n", "Model:", 40, model_number); | |||
| 2010 | printf("%-35s%.*s\n", "Serial Number:", 20, serial_number); | |||
| 2011 | printf("%-35s%.*s\n", "OPN:", 32, sfx_smart.opn); | |||
| 2012 | printf("%-35s%s\n", "Drive Type:", form_factor); | |||
| 2013 | printf("%-35s%.*s\n", "Firmware Revision:", 8, firmware_revision); | |||
| 2014 | printf("%-35s%s C\n", "Temperature:", temperature); | |||
| 2015 | printf("%-35s%i mW\n", "Power Consumption:", sfx_smart.power_mw_consumption); | |||
| 2016 | printf("%-35s%s\n", "Atomic Write mode:", (get_feat_result)?"Off":"On"); | |||
| 2017 | printf("%-35s%u%%\n", "Percentage Used:", smart_log.percent_used); | |||
| 2018 | printf("%-35s%s\n", "Host Data Read:", uint128_t_to_si_string( le128_to_cpu( \ | |||
| 2019 | smart_log.data_units_read), 1000 * 512)); | |||
| 2020 | printf("%-35s%s\n", "Host Data Written:", uint128_t_to_si_string(le128_to_cpu( \ | |||
| 2021 | smart_log.data_units_written), 1000 * 512)); | |||
| 2022 | write_amp = int48_to_long(additional_smart_log.nand_bytes_written.raw)/(1.0 * int48_to_long(additional_smart_log.host_bytes_written.raw)); | |||
| 2023 | printf("%-35s%i\n", "Correctable Error Cnt:", sfx_smart.pcie_rx_correct_errs); | |||
| 2024 | printf("%-35s%i\n", "Uncorrectable Error Cnt:", sfx_smart.pcie_rx_uncorrect_errs); | |||
| 2025 | printf("%-35s%s\n", "PCIe Link Status:", link_string); | |||
| 2026 | printf("%-35s%s\n", "PCIe Device Status:", pcie_status); | |||
| 2027 | if (sfx_smart.friendly_changecap_support) { | |||
| 2028 | printf("%-35s%"PRIu64"l" "u"" GB\n", "Current Formatted Capacity:", | |||
| 2029 | (uint64_t)sfx_smart.cur_formatted_capability); | |||
| 2030 | printf("%-35s%"PRIu64"l" "u"" GB\n", "Max Formatted Capacity:", | |||
| 2031 | (uint64_t)sfx_smart.max_formatted_capability); | |||
| 2032 | printf("%-35s%"PRIu64"l" "u""\n", "Extendible Capacity LBA count:", | |||
| 2033 | (uint64_t)sfx_smart.extendible_cap_lbacount); | |||
| 2034 | } else if (capacity_valid) { | |||
| 2035 | printf("%-35s%"PRIu64"l" "u"" GB\n", "Formatted Capacity:", (uint64_t)capacity); | |||
| 2036 | } | |||
| 2037 | printf("%-35s%"PRIu64"l" "u"" GB\n", "Provisioned Capacity:", | |||
| 2038 | (uint64_t)IDEMA_CAP2GB(sfx_smart.total_physical_capability)(((__u64)sfx_smart.total_physical_capability - 97696368ULL) / 1953504ULL + 50ULL)); | |||
| 2039 | printf("%-35s%u%%\n", "Compression Ratio:", sfx_smart.comp_ratio); | |||
| 2040 | printf("%-35s%u%%\n", "Physical Used Ratio:", sfx_smart.physical_usage_ratio); | |||
| 2041 | printf("%-35s%"PRIu64"l" "u"" GB\n", "Free Physical Space:", | |||
| 2042 | (uint64_t)IDEMA_CAP2GB(sfx_smart.free_physical_capability)(((__u64)sfx_smart.free_physical_capability - 97696368ULL) / 1953504ULL + 50ULL)); | |||
| 2043 | printf("%-35s%s\n", "Firmware Verification:", (sfx_smart.otp_rsa_en) ? "On":"Off"); | |||
| 2044 | printf("%-35s%s\n", "IO Speed:", io_speed); | |||
| 2045 | printf("%-35s%s\n", "NUMA Node:", numa_node); | |||
| 2046 | printf("%-35s%"PRIu64"l" "u""K\n", "Indirection Unit:", | |||
| 2047 | (uint64_t)(4*sfx_freespace.map_unit)); | |||
| 2048 | printf("%-35s%.2f\n", "Lifetime WAF:", write_amp); | |||
| 2049 | printf("%-35s%s\n", "Critical Warning(s):", path); | |||
| 2050 | } | |||
| 2051 | ||||
| 2052 | return 0; | |||
| 2053 | } |