| File: | .build-ci/../plugins/intel/intel-nvme.c |
| Warning: | line 1406, column 10 Potential leak of memory pointed to by 'intel' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | |||
| 2 | #include <errno(*__errno_location ()).h> | |||
| 3 | #include <fcntl.h> | |||
| 4 | #include <inttypes.h> | |||
| 5 | #include <stdio.h> | |||
| 6 | #include <stdlib.h> | |||
| 7 | #include <unistd.h> | |||
| 8 | ||||
| 9 | #include <libnvme.h> | |||
| 10 | ||||
| 11 | #include <ccan/endian/endian.h> | |||
| 12 | #include <ccan/minmax/minmax.h> | |||
| 13 | #include <shared/compiler-attributes-util.h> | |||
| 14 | #include <shared/fs-util.h> | |||
| 15 | #include <shared/parse-util.h> | |||
| 16 | ||||
| 17 | #include "cleanup.h" | |||
| 18 | #include "global-ctx.h" | |||
| 19 | #include "nvme-cmds.h" | |||
| 20 | #include "nvme-print.h" | |||
| 21 | #include "plugin.h" | |||
| 22 | ||||
| 23 | struct __packed__attribute__((__packed__)) nvme_additional_smart_log_item { | |||
| 24 | __u8 key; | |||
| 25 | __u8 _kp[2]; | |||
| 26 | __u8 norm; | |||
| 27 | __u8 _np; | |||
| 28 | union __packed__attribute__((__packed__)) { | |||
| 29 | __u8 raw[6]; | |||
| 30 | struct __packed__attribute__((__packed__)) wear_level { | |||
| 31 | __le16 min; | |||
| 32 | __le16 max; | |||
| 33 | __le16 avg; | |||
| 34 | } wear_level; | |||
| 35 | struct __packed__attribute__((__packed__)) thermal_throttle { | |||
| 36 | __u8 pct; | |||
| 37 | __u32 count; | |||
| 38 | } thermal_throttle; | |||
| 39 | }; | |||
| 40 | __u8 _rp; | |||
| 41 | }; | |||
| 42 | ||||
| 43 | struct nvme_additional_smart_log { | |||
| 44 | struct nvme_additional_smart_log_item program_fail_cnt; | |||
| 45 | struct nvme_additional_smart_log_item erase_fail_cnt; | |||
| 46 | struct nvme_additional_smart_log_item wear_leveling_cnt; | |||
| 47 | struct nvme_additional_smart_log_item e2e_err_cnt; | |||
| 48 | struct nvme_additional_smart_log_item crc_err_cnt; | |||
| 49 | struct nvme_additional_smart_log_item timed_workload_media_wear; | |||
| 50 | struct nvme_additional_smart_log_item timed_workload_host_reads; | |||
| 51 | struct nvme_additional_smart_log_item timed_workload_timer; | |||
| 52 | struct nvme_additional_smart_log_item thermal_throttle_status; | |||
| 53 | struct nvme_additional_smart_log_item retry_buffer_overflow_cnt; | |||
| 54 | struct nvme_additional_smart_log_item pll_lock_loss_cnt; | |||
| 55 | struct nvme_additional_smart_log_item nand_bytes_written; | |||
| 56 | struct nvme_additional_smart_log_item host_bytes_written; | |||
| 57 | struct nvme_additional_smart_log_item host_ctx_wear_used; | |||
| 58 | struct nvme_additional_smart_log_item perf_stat_indicator; | |||
| 59 | struct nvme_additional_smart_log_item re_alloc_sectr_cnt; | |||
| 60 | struct nvme_additional_smart_log_item soft_ecc_err_rate; | |||
| 61 | struct nvme_additional_smart_log_item unexp_power_loss; | |||
| 62 | struct nvme_additional_smart_log_item media_bytes_read; | |||
| 63 | struct nvme_additional_smart_log_item avail_fw_downgrades; | |||
| 64 | }; | |||
| 65 | ||||
| 66 | struct nvme_vu_id_ctrl_field { /* CDR MR5 */ | |||
| 67 | __u8 rsvd1[3]; | |||
| 68 | __u8 ss; | |||
| 69 | __u8 health[20]; | |||
| 70 | __u8 cls; | |||
| 71 | __u8 nlw; | |||
| 72 | __u8 scap; | |||
| 73 | __u8 sstat; | |||
| 74 | __u8 bl[8]; | |||
| 75 | __u8 rsvd2[38]; | |||
| 76 | __u8 ww[8]; /* little endian */ | |||
| 77 | __u8 mic_bl[4]; | |||
| 78 | __u8 mic_fw[4]; | |||
| 79 | }; | |||
| 80 | ||||
| 81 | static void json_intel_id_ctrl(struct nvme_vu_id_ctrl_field *id, | |||
| 82 | char *health, char *bl, char *ww, char *mic_bl, char *mic_fw, | |||
| 83 | struct json_object *root) | |||
| 84 | { | |||
| 85 | json_object_add_value_int(root, "ss", id->ss)json_object_object_add(root, "ss", json_object_new_int(id-> ss)); | |||
| 86 | json_object_add_value_string(root, "health", health); | |||
| 87 | json_object_add_value_int(root, "cls", id->cls)json_object_object_add(root, "cls", json_object_new_int(id-> cls)); | |||
| 88 | json_object_add_value_int(root, "nlw", id->nlw)json_object_object_add(root, "nlw", json_object_new_int(id-> nlw)); | |||
| 89 | json_object_add_value_int(root, "scap", id->scap)json_object_object_add(root, "scap", json_object_new_int(id-> scap)); | |||
| 90 | json_object_add_value_int(root, "sstat", id->sstat)json_object_object_add(root, "sstat", json_object_new_int(id-> sstat)); | |||
| 91 | json_object_add_value_string(root, "bl", bl); | |||
| 92 | json_object_add_value_string(root, "ww", ww); | |||
| 93 | json_object_add_value_string(root, "mic_bl", mic_bl); | |||
| 94 | json_object_add_value_string(root, "mic_fw", mic_fw); | |||
| 95 | } | |||
| 96 | ||||
| 97 | static void intel_id_ctrl(__u8 *vs, struct json_object *root) | |||
| 98 | { | |||
| 99 | struct nvme_vu_id_ctrl_field *id = (struct nvme_vu_id_ctrl_field *)vs; | |||
| 100 | ||||
| 101 | char health[21] = { 0 }; | |||
| 102 | char bl[9] = { 0 }; | |||
| 103 | char ww[19] = { 0 }; | |||
| 104 | char mic_bl[5] = { 0 }; | |||
| 105 | char mic_fw[5] = { 0 }; | |||
| 106 | ||||
| 107 | if (id->health[0] == 0) | |||
| 108 | snprintf(health, 21, "%s", "healthy"); | |||
| 109 | else | |||
| 110 | snprintf(health, 21, "%s", id->health); | |||
| 111 | ||||
| 112 | snprintf(bl, 9, "%s", id->bl); | |||
| 113 | snprintf(ww, 19, "%02X%02X%02X%02X%02X%02X%02X%02X", id->ww[7], | |||
| 114 | id->ww[6], id->ww[5], id->ww[4], id->ww[3], id->ww[2], | |||
| 115 | id->ww[1], id->ww[0]); | |||
| 116 | snprintf(mic_bl, 5, "%s", id->mic_bl); | |||
| 117 | snprintf(mic_fw, 5, "%s", id->mic_fw); | |||
| 118 | ||||
| 119 | if (root) { | |||
| 120 | json_intel_id_ctrl(id, health, bl, ww, mic_bl, mic_fw, root); | |||
| 121 | return; | |||
| 122 | } | |||
| 123 | ||||
| 124 | printf("ss : %d\n", id->ss); | |||
| 125 | printf("health : %s\n", health); | |||
| 126 | printf("cls : %d\n", id->cls); | |||
| 127 | printf("nlw : %d\n", id->nlw); | |||
| 128 | printf("scap : %d\n", id->scap); | |||
| 129 | printf("sstat : %d\n", id->sstat); | |||
| 130 | printf("bl : %s\n", bl); | |||
| 131 | printf("ww : %s\n", ww); | |||
| 132 | printf("mic_bl : %s\n", mic_bl); | |||
| 133 | printf("mic_fw : %s\n", mic_fw); | |||
| 134 | } | |||
| 135 | ||||
| 136 | static int id_ctrl(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 137 | { | |||
| 138 | return __id_ctrl(argc, argv, acmd, plugin, intel_id_ctrl); | |||
| 139 | } | |||
| 140 | ||||
| 141 | static void | |||
| 142 | show_intel_smart_log_jsn(struct nvme_additional_smart_log *smart, | |||
| 143 | unsigned int nsid, const char *devname) | |||
| 144 | { | |||
| 145 | struct json_object *root, *entry_stats, *dev_stats, *multi; | |||
| 146 | ||||
| 147 | root = json_create_object()json_object_new_object(); | |||
| 148 | json_object_add_value_string(root, "Intel Smart log", devname); | |||
| 149 | ||||
| 150 | dev_stats = json_create_object()json_object_new_object(); | |||
| 151 | ||||
| 152 | entry_stats = json_create_object()json_object_new_object(); | |||
| 153 | 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)); | |||
| 154 | 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))); | |||
| 155 | json_object_add_value_object(dev_stats, "program_fail_count", entry_stats)json_object_object_add(dev_stats, "program_fail_count", entry_stats ); | |||
| 156 | ||||
| 157 | entry_stats = json_create_object()json_object_new_object(); | |||
| 158 | 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)); | |||
| 159 | 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))); | |||
| 160 | json_object_add_value_object(dev_stats, "erase_fail_count", entry_stats)json_object_object_add(dev_stats, "erase_fail_count", entry_stats ); | |||
| 161 | ||||
| 162 | entry_stats = json_create_object()json_object_new_object(); | |||
| 163 | 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)); | |||
| 164 | multi = json_create_object()json_object_new_object(); | |||
| 165 | 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))); | |||
| 166 | 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))); | |||
| 167 | 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))); | |||
| 168 | json_object_add_value_object(entry_stats, "raw", multi)json_object_object_add(entry_stats, "raw", multi); | |||
| 169 | json_object_add_value_object(dev_stats, "wear_leveling", entry_stats)json_object_object_add(dev_stats, "wear_leveling", entry_stats ); | |||
| 170 | ||||
| 171 | entry_stats = json_create_object()json_object_new_object(); | |||
| 172 | 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)); | |||
| 173 | 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))); | |||
| 174 | 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); | |||
| 175 | ||||
| 176 | entry_stats = json_create_object()json_object_new_object(); | |||
| 177 | 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)); | |||
| 178 | 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))); | |||
| 179 | json_object_add_value_object(dev_stats, "crc_error_count", entry_stats)json_object_object_add(dev_stats, "crc_error_count", entry_stats ); | |||
| 180 | ||||
| 181 | entry_stats = json_create_object()json_object_new_object(); | |||
| 182 | 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)); | |||
| 183 | json_object_add_value_double(entry_stats, "raw", ((long double)int48_to_long(smart->timed_workload_media_wear.raw)) / 1024)json_object_object_add(entry_stats, "raw", util_json_object_new_double (((long double)int48_to_long(smart->timed_workload_media_wear .raw)) / 1024)); | |||
| 184 | 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); | |||
| 185 | ||||
| 186 | entry_stats = json_create_object()json_object_new_object(); | |||
| 187 | 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)); | |||
| 188 | 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))); | |||
| 189 | 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); | |||
| 190 | ||||
| 191 | entry_stats = json_create_object()json_object_new_object(); | |||
| 192 | 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)); | |||
| 193 | 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))); | |||
| 194 | json_object_add_value_object(dev_stats, "timed_workload_timer", entry_stats)json_object_object_add(dev_stats, "timed_workload_timer", entry_stats ); | |||
| 195 | ||||
| 196 | entry_stats = json_create_object()json_object_new_object(); | |||
| 197 | 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)); | |||
| 198 | multi = json_create_object()json_object_new_object(); | |||
| 199 | 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)); | |||
| 200 | 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)); | |||
| 201 | json_object_add_value_object(entry_stats, "raw", multi)json_object_object_add(entry_stats, "raw", multi); | |||
| 202 | json_object_add_value_object(dev_stats, "thermal_throttle_status", entry_stats)json_object_object_add(dev_stats, "thermal_throttle_status", entry_stats ); | |||
| 203 | ||||
| 204 | entry_stats = json_create_object()json_object_new_object(); | |||
| 205 | 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)); | |||
| 206 | 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))); | |||
| 207 | 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); | |||
| 208 | ||||
| 209 | entry_stats = json_create_object()json_object_new_object(); | |||
| 210 | 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)); | |||
| 211 | 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))); | |||
| 212 | 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 ); | |||
| 213 | ||||
| 214 | entry_stats = json_create_object()json_object_new_object(); | |||
| 215 | 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)); | |||
| 216 | 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))); | |||
| 217 | json_object_add_value_object(dev_stats, "nand_bytes_written", entry_stats)json_object_object_add(dev_stats, "nand_bytes_written", entry_stats ); | |||
| 218 | ||||
| 219 | entry_stats = json_create_object()json_object_new_object(); | |||
| 220 | 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)); | |||
| 221 | 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))); | |||
| 222 | json_object_add_value_object(dev_stats, "host_bytes_written", entry_stats)json_object_object_add(dev_stats, "host_bytes_written", entry_stats ); | |||
| 223 | ||||
| 224 | entry_stats = json_create_object()json_object_new_object(); | |||
| 225 | json_object_add_value_int(entry_stats, "normalized", smart->host_ctx_wear_used.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->host_ctx_wear_used.norm)); | |||
| 226 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->host_ctx_wear_used.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->host_ctx_wear_used.raw))); | |||
| 227 | json_object_add_value_object(dev_stats, "host_ctx_wear_used", entry_stats)json_object_object_add(dev_stats, "host_ctx_wear_used", entry_stats ); | |||
| 228 | ||||
| 229 | entry_stats = json_create_object()json_object_new_object(); | |||
| 230 | json_object_add_value_int(entry_stats, "normalized", smart->perf_stat_indicator.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->perf_stat_indicator.norm)); | |||
| 231 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->perf_stat_indicator.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->perf_stat_indicator.raw))); | |||
| 232 | json_object_add_value_object(dev_stats, "perf_stat_indicator", entry_stats)json_object_object_add(dev_stats, "perf_stat_indicator", entry_stats ); | |||
| 233 | ||||
| 234 | entry_stats = json_create_object()json_object_new_object(); | |||
| 235 | json_object_add_value_int(entry_stats, "normalized", smart->re_alloc_sectr_cnt.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->re_alloc_sectr_cnt.norm)); | |||
| 236 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->re_alloc_sectr_cnt.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->re_alloc_sectr_cnt.raw))); | |||
| 237 | json_object_add_value_object(dev_stats, "re_alloc_sectr_cnt", entry_stats)json_object_object_add(dev_stats, "re_alloc_sectr_cnt", entry_stats ); | |||
| 238 | ||||
| 239 | entry_stats = json_create_object()json_object_new_object(); | |||
| 240 | json_object_add_value_int(entry_stats, "normalized", smart->soft_ecc_err_rate.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->soft_ecc_err_rate.norm)); | |||
| 241 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->soft_ecc_err_rate.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->soft_ecc_err_rate.raw))); | |||
| 242 | json_object_add_value_object(dev_stats, "soft_ecc_err_rate", entry_stats)json_object_object_add(dev_stats, "soft_ecc_err_rate", entry_stats ); | |||
| 243 | ||||
| 244 | entry_stats = json_create_object()json_object_new_object(); | |||
| 245 | json_object_add_value_int(entry_stats, "normalized", smart->unexp_power_loss.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->unexp_power_loss.norm)); | |||
| 246 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->unexp_power_loss.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->unexp_power_loss.raw))); | |||
| 247 | json_object_add_value_object(dev_stats, "unexp_power_loss", entry_stats)json_object_object_add(dev_stats, "unexp_power_loss", entry_stats ); | |||
| 248 | ||||
| 249 | entry_stats = json_create_object()json_object_new_object(); | |||
| 250 | json_object_add_value_int(entry_stats, "normalized", smart->media_bytes_read.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->media_bytes_read.norm)); | |||
| 251 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->media_bytes_read.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->media_bytes_read.raw))); | |||
| 252 | json_object_add_value_object(dev_stats, "media_bytes_read", entry_stats)json_object_object_add(dev_stats, "media_bytes_read", entry_stats ); | |||
| 253 | ||||
| 254 | entry_stats = json_create_object()json_object_new_object(); | |||
| 255 | json_object_add_value_int(entry_stats, "normalized", smart->avail_fw_downgrades.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int (smart->avail_fw_downgrades.norm)); | |||
| 256 | json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->avail_fw_downgrades.raw))json_object_object_add(entry_stats, "raw", json_object_new_int (int48_to_long(smart->avail_fw_downgrades.raw))); | |||
| 257 | json_object_add_value_object(dev_stats, "avail_fw_downgrades", entry_stats)json_object_object_add(dev_stats, "avail_fw_downgrades", entry_stats ); | |||
| 258 | ||||
| 259 | json_object_add_value_object(root, "Device stats", dev_stats)json_object_object_add(root, "Device stats", dev_stats); | |||
| 260 | ||||
| 261 | json_print_object(root, NULL)printf("%s", json_object_to_json_string_ext(root, (1 << 1) | (1 << 4))); | |||
| 262 | printf("\n"); | |||
| 263 | json_free_object(root)json_object_put(root); | |||
| 264 | } | |||
| 265 | ||||
| 266 | static char *id_to_key(__u8 id) | |||
| 267 | { | |||
| 268 | switch (id) { | |||
| 269 | case 0xAB: | |||
| 270 | return "program_fail_count"; | |||
| 271 | case 0xAC: | |||
| 272 | return "erase_fail_count"; | |||
| 273 | case 0xAD: | |||
| 274 | return "wear_leveling_count"; | |||
| 275 | case 0xB8: | |||
| 276 | return "e2e_error_detect_count"; | |||
| 277 | case 0xC7: | |||
| 278 | return "crc_error_count"; | |||
| 279 | case 0xE2: | |||
| 280 | return "media_wear_percentage"; | |||
| 281 | case 0xE3: | |||
| 282 | return "host_reads"; | |||
| 283 | case 0xE4: | |||
| 284 | return "timed_work_load"; | |||
| 285 | case 0xEA: | |||
| 286 | return "thermal_throttle_status"; | |||
| 287 | case 0xF0: | |||
| 288 | return "retry_buff_overflow_count"; | |||
| 289 | case 0xF3: | |||
| 290 | return "pll_lock_loss_counter"; | |||
| 291 | case 0xF4: | |||
| 292 | return "nand_bytes_written"; | |||
| 293 | case 0xF5: | |||
| 294 | return "host_bytes_written"; | |||
| 295 | case 0xF6: | |||
| 296 | return "host_context_wear_used"; | |||
| 297 | case 0xF7: | |||
| 298 | return "performance_status_indicator"; | |||
| 299 | case 0xF8: | |||
| 300 | return "media_bytes_read"; | |||
| 301 | case 0xF9: | |||
| 302 | return "available_fw_downgrades"; | |||
| 303 | case 0x05: | |||
| 304 | return "re-allocated_sector_count"; | |||
| 305 | case 0x0D: | |||
| 306 | return "soft_ecc_error_rate"; | |||
| 307 | case 0xAE: | |||
| 308 | return "unexpected_power_loss"; | |||
| 309 | default: | |||
| 310 | return "Invalid ID"; | |||
| 311 | } | |||
| 312 | } | |||
| 313 | ||||
| 314 | static void print_intel_smart_log_items(struct nvme_additional_smart_log_item *item) | |||
| 315 | { | |||
| 316 | if (!item->key) | |||
| 317 | return; | |||
| 318 | ||||
| 319 | printf("%#x %-45s %3d %"PRIu64"l" "u""\n", | |||
| 320 | item->key, id_to_key(item->key), | |||
| 321 | item->norm, int48_to_long(item->raw)); | |||
| 322 | } | |||
| 323 | ||||
| 324 | static void show_intel_smart_log(struct nvme_additional_smart_log *smart, | |||
| 325 | unsigned int nsid, const char *devname) | |||
| 326 | { | |||
| 327 | struct nvme_additional_smart_log_item *iter = &smart->program_fail_cnt; | |||
| 328 | int num_items = sizeof(struct nvme_additional_smart_log) / | |||
| 329 | sizeof(struct nvme_additional_smart_log_item); | |||
| 330 | ||||
| 331 | printf("Additional Smart Log for NVME device:%s namespace-id:%x\n", | |||
| 332 | devname, nsid); | |||
| 333 | printf("ID KEY Normalized Raw\n"); | |||
| 334 | ||||
| 335 | for (int i = 0; i < num_items; i++, iter++) | |||
| 336 | print_intel_smart_log_items(iter); | |||
| 337 | } | |||
| 338 | ||||
| 339 | static int get_additional_smart_log(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 340 | { | |||
| 341 | const char *desc = | |||
| 342 | "Get Intel vendor specific additional smart log (optionally, for the specified namespace), and show it."; | |||
| 343 | const char *namespace = "(optional) desired namespace"; | |||
| 344 | const char *raw = "Dump output in binary format"; | |||
| 345 | #ifdef CONFIG_JSONC | |||
| 346 | const char *json = "Dump output in json format"; | |||
| 347 | #endif /* CONFIG_JSONC */ | |||
| 348 | ||||
| 349 | struct nvme_additional_smart_log smart_log; | |||
| 350 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 351 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 352 | nvme_print_flags_t flags; | |||
| 353 | int err; | |||
| 354 | ||||
| 355 | struct config { | |||
| 356 | __u32 namespace_id; | |||
| 357 | bool_Bool raw_binary; | |||
| 358 | bool_Bool json; | |||
| 359 | }; | |||
| 360 | ||||
| 361 | struct config cfg = { | |||
| 362 | .namespace_id = NVME_NSID_ALL, | |||
| 363 | }; | |||
| 364 | ||||
| 365 | NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; 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, }, {"quiet", 0, ( (void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary", 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}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } } | |||
| 366 | OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; 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, }, {"quiet", 0, ( (void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary", 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}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } } | |||
| 367 | OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; 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, }, {"quiet", 0, ( (void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary", 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}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } } | |||
| 368 | OPT_FLAG_JSON("json", 'j', &cfg.json, json))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; 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, }, {"quiet", 0, ( (void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary", 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}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } }; | |||
| 369 | ||||
| 370 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 371 | if (err) | |||
| 372 | return err; | |||
| 373 | ||||
| 374 | err = validate_output_format(nvme_args.output_format, &flags); | |||
| 375 | if (err < 0) { | |||
| 376 | nvme_show_error("Invalid output format")nvme_show_message(1, "Invalid output format"); | |||
| 377 | return err; | |||
| 378 | } | |||
| 379 | ||||
| 380 | err = nvme_get_log_simple(hdl, 0xca, &smart_log, sizeof(smart_log)); | |||
| 381 | if (!err) { | |||
| 382 | if (flags & JSON || cfg.json) | |||
| 383 | show_intel_smart_log_jsn(&smart_log, cfg.namespace_id, | |||
| 384 | libnvme_transport_handle_get_name(hdl)); | |||
| 385 | else if (!cfg.raw_binary) | |||
| 386 | show_intel_smart_log(&smart_log, cfg.namespace_id, | |||
| 387 | libnvme_transport_handle_get_name(hdl)); | |||
| 388 | else | |||
| 389 | d_raw((unsigned char *)&smart_log, sizeof(smart_log)); | |||
| 390 | } else if (err > 0) { | |||
| 391 | nvme_show_status(err); | |||
| 392 | } | |||
| 393 | return err; | |||
| 394 | } | |||
| 395 | ||||
| 396 | static int get_market_log(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 397 | { | |||
| 398 | const char *desc = "Get Intel Marketing Name log and show it."; | |||
| 399 | const char *raw = "dump output in binary format"; | |||
| 400 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 401 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 402 | char log[512]; | |||
| 403 | int err; | |||
| 404 | ||||
| 405 | struct config { | |||
| 406 | bool_Bool raw_binary; | |||
| 407 | }; | |||
| 408 | ||||
| 409 | struct config cfg = { | |||
| 410 | }; | |||
| 411 | ||||
| 412 | NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; 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, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet , 0, "suppress informational output", 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary" , 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}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } } | |||
| 413 | OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; 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, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet , 0, "suppress informational output", 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary" , 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}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } }; | |||
| 414 | ||||
| 415 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 416 | if (err) | |||
| 417 | return err; | |||
| 418 | ||||
| 419 | err = nvme_get_log_simple(hdl, 0xdd, log, sizeof(log)); | |||
| 420 | if (!err) { | |||
| 421 | if (!cfg.raw_binary) | |||
| 422 | printf("Intel Marketing Name Log:\n%s\n", log); | |||
| 423 | else | |||
| 424 | d_raw((unsigned char *)&log, sizeof(log)); | |||
| 425 | } else if (err > 0) | |||
| 426 | nvme_show_status(err); | |||
| 427 | return err; | |||
| 428 | } | |||
| 429 | ||||
| 430 | struct intel_temp_stats { | |||
| 431 | __le64 curr; | |||
| 432 | __le64 last_overtemp; | |||
| 433 | __le64 life_overtemp; | |||
| 434 | __le64 highest_temp; | |||
| 435 | __le64 lowest_temp; | |||
| 436 | __u8 rsvd[40]; | |||
| 437 | __le64 max_operating_temp; | |||
| 438 | __le64 min_operating_temp; | |||
| 439 | __le64 est_offset; | |||
| 440 | }; | |||
| 441 | ||||
| 442 | static void show_temp_stats(struct intel_temp_stats *stats) | |||
| 443 | { | |||
| 444 | printf(" Intel Temperature Statistics\n"); | |||
| 445 | printf("--------------------------------\n"); | |||
| 446 | printf("Current temperature : %"PRIu64"l" "u""\n", le64_to_cpu(stats->curr)); | |||
| 447 | printf("Last critical overtemp flag : %"PRIu64"l" "u""\n", le64_to_cpu(stats->last_overtemp)); | |||
| 448 | printf("Life critical overtemp flag : %"PRIu64"l" "u""\n", le64_to_cpu(stats->life_overtemp)); | |||
| 449 | printf("Highest temperature : %"PRIu64"l" "u""\n", le64_to_cpu(stats->highest_temp)); | |||
| 450 | printf("Lowest temperature : %"PRIu64"l" "u""\n", le64_to_cpu(stats->lowest_temp)); | |||
| 451 | printf("Max operating temperature : %"PRIu64"l" "u""\n", le64_to_cpu(stats->max_operating_temp)); | |||
| 452 | printf("Min operating temperature : %"PRIu64"l" "u""\n", le64_to_cpu(stats->min_operating_temp)); | |||
| 453 | printf("Estimated offset : %"PRIu64"l" "u""\n", le64_to_cpu(stats->est_offset)); | |||
| 454 | } | |||
| 455 | ||||
| 456 | static int get_temp_stats_log(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 457 | { | |||
| 458 | struct intel_temp_stats stats; | |||
| 459 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 460 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 461 | int err; | |||
| 462 | ||||
| 463 | const char *desc = "Get Temperature Statistics log and show it."; | |||
| 464 | const char *raw = "dump output in binary format"; | |||
| 465 | struct config { | |||
| 466 | bool_Bool raw_binary; | |||
| 467 | }; | |||
| 468 | ||||
| 469 | struct config cfg = { | |||
| 470 | }; | |||
| 471 | ||||
| 472 | NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; 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, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet , 0, "suppress informational output", 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary" , 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}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } } | |||
| 473 | OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; 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, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet , 0, "suppress informational output", 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary" , 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}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } }; | |||
| 474 | ||||
| 475 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 476 | if (err) | |||
| 477 | return err; | |||
| 478 | ||||
| 479 | err = nvme_get_log_simple(hdl, 0xc5, &stats, sizeof(stats)); | |||
| 480 | if (!err) { | |||
| 481 | if (!cfg.raw_binary) | |||
| 482 | show_temp_stats(&stats); | |||
| 483 | else | |||
| 484 | d_raw((unsigned char *)&stats, sizeof(stats)); | |||
| 485 | } else if (err > 0) | |||
| 486 | nvme_show_status(err); | |||
| 487 | return err; | |||
| 488 | } | |||
| 489 | ||||
| 490 | struct intel_lat_stats { | |||
| 491 | __u16 maj; | |||
| 492 | __u16 min; | |||
| 493 | __u32 data[1216]; | |||
| 494 | }; | |||
| 495 | ||||
| 496 | struct __packed__attribute__((__packed__)) optane_lat_stats { | |||
| 497 | __u16 maj; | |||
| 498 | __u16 min; | |||
| 499 | __u64 data[9]; | |||
| 500 | }; | |||
| 501 | ||||
| 502 | #define MEDIA_MAJOR_IDX0 0 | |||
| 503 | #define MEDIA_MINOR_IDX1 1 | |||
| 504 | #define MEDIA_MAX_LEN2 2 | |||
| 505 | #define OPTANE_V1000_BUCKET_LEN8 8 | |||
| 506 | #define OPTANE_V1000_BUCKET_LEN8 8 | |||
| 507 | #define NAND_LAT_STATS_LEN4868 4868 | |||
| 508 | ||||
| 509 | ||||
| 510 | static struct intel_lat_stats stats; | |||
| 511 | static struct optane_lat_stats v1000_stats; | |||
| 512 | ||||
| 513 | struct v1000_thresholds { | |||
| 514 | __u32 read[OPTANE_V1000_BUCKET_LEN8]; | |||
| 515 | __u32 write[OPTANE_V1000_BUCKET_LEN8]; | |||
| 516 | }; | |||
| 517 | ||||
| 518 | static struct v1000_thresholds v1000_bucket; | |||
| 519 | static __u16 media_version[MEDIA_MAX_LEN2] = {0}; | |||
| 520 | ||||
| 521 | enum FormatUnit { | |||
| 522 | US, | |||
| 523 | MS, | |||
| 524 | S | |||
| 525 | }; | |||
| 526 | ||||
| 527 | /* | |||
| 528 | * COL_WIDTH controls width of columns in human-readable output. | |||
| 529 | * BUFSIZE is for local temp char[] | |||
| 530 | * US_IN_S and US_IN_MS are for unit conversions when printing. | |||
| 531 | */ | |||
| 532 | #define COL_WIDTH12 12 | |||
| 533 | #define BUFSIZE10 10 | |||
| 534 | #define US_IN_S1000000 1000000 | |||
| 535 | #define US_IN_MS1000 1000 | |||
| 536 | ||||
| 537 | static enum FormatUnit get_seconds_magnitude(__u32 microseconds) | |||
| 538 | { | |||
| 539 | if (microseconds > US_IN_S1000000) | |||
| 540 | return S; | |||
| 541 | else if (microseconds > US_IN_MS1000) | |||
| 542 | return MS; | |||
| 543 | else | |||
| 544 | return US; | |||
| 545 | } | |||
| 546 | ||||
| 547 | static float convert_seconds(__u32 microseconds) | |||
| 548 | { | |||
| 549 | float divisor = 1.0; | |||
| 550 | ||||
| 551 | if (microseconds > US_IN_S1000000) | |||
| 552 | divisor = US_IN_S1000000; | |||
| 553 | else if (microseconds > US_IN_MS1000) | |||
| 554 | divisor = US_IN_MS1000; | |||
| 555 | return microseconds / divisor; | |||
| 556 | } | |||
| 557 | ||||
| 558 | /* | |||
| 559 | * For control over whether a string will format to +/-INF or | |||
| 560 | * print out ####.##US normally. | |||
| 561 | */ | |||
| 562 | enum inf_bound_type { | |||
| 563 | NEGINF, | |||
| 564 | POSINF, | |||
| 565 | NOINF | |||
| 566 | }; | |||
| 567 | ||||
| 568 | /* | |||
| 569 | * Edge buckets may have range [#s, inf) or (-inf, #US] in some | |||
| 570 | * latency statistics formats. | |||
| 571 | * Passing in NEGINF to POSINF to bound_type overrides the string to | |||
| 572 | * either of "-INF" or "+INF", respectively. | |||
| 573 | */ | |||
| 574 | static void set_unit_string(char *buffer, __u32 microseconds, | |||
| 575 | enum FormatUnit unit, | |||
| 576 | enum inf_bound_type bound_type) | |||
| 577 | { | |||
| 578 | char *string; | |||
| 579 | ||||
| 580 | if (bound_type != NOINF) { | |||
| 581 | snprintf(buffer, BUFSIZE10, "%s", bound_type ? "+INF" : "-INF"); | |||
| 582 | return; | |||
| 583 | } | |||
| 584 | ||||
| 585 | switch (unit) { | |||
| 586 | case US: | |||
| 587 | string = "us"; | |||
| 588 | break; | |||
| 589 | case MS: | |||
| 590 | string = "ms"; | |||
| 591 | break; | |||
| 592 | case S: | |||
| 593 | string = "s"; | |||
| 594 | break; | |||
| 595 | default: | |||
| 596 | string = "_s"; | |||
| 597 | break; | |||
| 598 | } | |||
| 599 | ||||
| 600 | snprintf(buffer, BUFSIZE10, "%4.2f%s", convert_seconds(microseconds), | |||
| 601 | string); | |||
| 602 | } | |||
| 603 | ||||
| 604 | static void init_buffer(char *buffer, size_t size) | |||
| 605 | { | |||
| 606 | size_t i; | |||
| 607 | ||||
| 608 | for (i = 0; i < size; i++) | |||
| 609 | buffer[i] = i + '0'; | |||
| 610 | } | |||
| 611 | ||||
| 612 | static void show_lat_stats_bucket(struct intel_lat_stats *stats, | |||
| 613 | __u32 lower_us, enum inf_bound_type start_type, | |||
| 614 | __u32 upper_us, enum inf_bound_type end_type, int i) | |||
| 615 | { | |||
| 616 | enum FormatUnit fu = S; | |||
| 617 | char buffer[BUFSIZE10]; | |||
| 618 | ||||
| 619 | init_buffer(buffer, BUFSIZE10); | |||
| 620 | printf("%-*d", COL_WIDTH12, i); | |||
| 621 | ||||
| 622 | fu = get_seconds_magnitude(lower_us); | |||
| 623 | set_unit_string(buffer, lower_us, fu, start_type); | |||
| 624 | printf("%-*s", COL_WIDTH12, buffer); | |||
| 625 | ||||
| 626 | fu = get_seconds_magnitude(upper_us); | |||
| 627 | set_unit_string(buffer, upper_us, fu, end_type); | |||
| 628 | printf("%-*s", COL_WIDTH12, buffer); | |||
| 629 | ||||
| 630 | printf("%-*d\n", COL_WIDTH12, stats->data[i]); | |||
| 631 | } | |||
| 632 | ||||
| 633 | static void show_optane_lat_stats_bucket(struct optane_lat_stats *stats, | |||
| 634 | __u32 lower_us, enum inf_bound_type start_type, | |||
| 635 | __u32 upper_us, enum inf_bound_type end_type, int i) | |||
| 636 | { | |||
| 637 | enum FormatUnit fu = S; | |||
| 638 | char buffer[BUFSIZE10]; | |||
| 639 | ||||
| 640 | init_buffer(buffer, BUFSIZE10); | |||
| 641 | printf("%-*d", COL_WIDTH12, i); | |||
| 642 | ||||
| 643 | fu = get_seconds_magnitude(lower_us); | |||
| 644 | set_unit_string(buffer, lower_us, fu, start_type); | |||
| 645 | printf("%-*s", COL_WIDTH12, buffer); | |||
| 646 | ||||
| 647 | fu = get_seconds_magnitude(upper_us); | |||
| 648 | set_unit_string(buffer, upper_us, fu, end_type); | |||
| 649 | printf("%-*s", COL_WIDTH12, buffer); | |||
| 650 | ||||
| 651 | printf("%-*lu\n", COL_WIDTH12, (unsigned long)stats->data[i]); | |||
| 652 | } | |||
| 653 | ||||
| 654 | ||||
| 655 | static void show_lat_stats_linear(struct intel_lat_stats *stats, | |||
| 656 | __u32 start_offset, __u32 end_offset, __u32 bytes_per, | |||
| 657 | __u32 us_step, bool_Bool nonzero_print) | |||
| 658 | { | |||
| 659 | for (int i = (start_offset / bytes_per) - 1; | |||
| 660 | i < end_offset / bytes_per; i++) { | |||
| 661 | if (nonzero_print && stats->data[i] == 0) | |||
| 662 | continue; | |||
| 663 | show_lat_stats_bucket(stats, us_step * i, NOINF, | |||
| 664 | us_step * (i + 1), NOINF, i); | |||
| 665 | } | |||
| 666 | } | |||
| 667 | ||||
| 668 | /* | |||
| 669 | * For 4.0-4.5 revision. | |||
| 670 | */ | |||
| 671 | #define LATENCY_STATS_V4_BASE_BITS6 6 | |||
| 672 | #define LATENCY_STATS_V4_BASE_VAL(1 << 6) (1 << LATENCY_STATS_V4_BASE_BITS6) | |||
| 673 | ||||
| 674 | static int lat_stats_log_scale(int i) | |||
| 675 | { | |||
| 676 | // if (i < 128) | |||
| 677 | if (i < (LATENCY_STATS_V4_BASE_VAL(1 << 6) << 1)) | |||
| 678 | return i; | |||
| 679 | ||||
| 680 | int error_bits = (i >> LATENCY_STATS_V4_BASE_BITS6) - 1; | |||
| 681 | int base = 1 << (error_bits + LATENCY_STATS_V4_BASE_BITS6); | |||
| 682 | int k = i % LATENCY_STATS_V4_BASE_VAL(1 << 6); | |||
| 683 | ||||
| 684 | return base + ((k + 0.5) * (1 << error_bits)); | |||
| 685 | } | |||
| 686 | ||||
| 687 | /* | |||
| 688 | * Creates a subroot in the following manner: | |||
| 689 | * { | |||
| 690 | * "latstats" : { | |||
| 691 | * "type" : "write" or "read", | |||
| 692 | * "values" : { | |||
| 693 | */ | |||
| 694 | static void lat_stats_make_json_root( | |||
| 695 | struct json_object *root, struct json_object *bucket_list, | |||
| 696 | int write) | |||
| 697 | { | |||
| 698 | struct json_object *subroot = json_create_object()json_object_new_object(); | |||
| 699 | ||||
| 700 | json_object_add_value_object(root, "latstats", subroot)json_object_object_add(root, "latstats", subroot); | |||
| 701 | json_object_add_value_string(subroot, "type", write ? "write" : "read"); | |||
| 702 | json_object_add_value_object(subroot, "values", bucket_list)json_object_object_add(subroot, "values", bucket_list); | |||
| 703 | } | |||
| 704 | ||||
| 705 | /* | |||
| 706 | * Creates a bucket under the "values" json_object. Format is: | |||
| 707 | * "values" : { | |||
| 708 | * "bucket" : { | |||
| 709 | * "id" : #, | |||
| 710 | * "start" : string, | |||
| 711 | * "end" : string, | |||
| 712 | * "value" : 0, | |||
| 713 | * }, | |||
| 714 | */ | |||
| 715 | static void json_add_bucket(struct intel_lat_stats *stats, | |||
| 716 | struct json_object *bucket_list, __u32 id, | |||
| 717 | __u32 lower_us, enum inf_bound_type start_type, | |||
| 718 | __u32 upper_us, enum inf_bound_type end_type, __u32 val) | |||
| 719 | { | |||
| 720 | char buffer[BUFSIZE10]; | |||
| 721 | struct json_object *bucket = json_create_object()json_object_new_object(); | |||
| 722 | ||||
| 723 | init_buffer(buffer, BUFSIZE10); | |||
| 724 | ||||
| 725 | json_object_array_add(bucket_list, bucket); | |||
| 726 | json_object_add_value_int(bucket, "id", id)json_object_object_add(bucket, "id", json_object_new_int(id)); | |||
| 727 | ||||
| 728 | set_unit_string(buffer, lower_us, | |||
| 729 | get_seconds_magnitude(lower_us), start_type); | |||
| 730 | json_object_add_value_string(bucket, "start", buffer); | |||
| 731 | ||||
| 732 | set_unit_string(buffer, upper_us, | |||
| 733 | get_seconds_magnitude(upper_us), end_type); | |||
| 734 | json_object_add_value_string(bucket, "end", buffer); | |||
| 735 | ||||
| 736 | json_object_add_value_int(bucket, "value", val)json_object_object_add(bucket, "value", json_object_new_int(val )); | |||
| 737 | } | |||
| 738 | ||||
| 739 | static void json_add_bucket_optane(struct json_object *bucket_list, __u32 id, | |||
| 740 | __u32 lower_us, enum inf_bound_type start_type, | |||
| 741 | __u32 upper_us, enum inf_bound_type end_type, __u32 val) | |||
| 742 | { | |||
| 743 | char buffer[BUFSIZE10]; | |||
| 744 | struct json_object *bucket = json_create_object()json_object_new_object(); | |||
| 745 | ||||
| 746 | init_buffer(buffer, BUFSIZE10); | |||
| 747 | ||||
| 748 | json_object_array_add(bucket_list, bucket); | |||
| 749 | json_object_add_value_int(bucket, "id", id)json_object_object_add(bucket, "id", json_object_new_int(id)); | |||
| 750 | ||||
| 751 | set_unit_string(buffer, lower_us, | |||
| 752 | get_seconds_magnitude(lower_us), start_type); | |||
| 753 | json_object_add_value_string(bucket, "start", buffer); | |||
| 754 | ||||
| 755 | set_unit_string(buffer, upper_us, | |||
| 756 | get_seconds_magnitude(upper_us), end_type); | |||
| 757 | json_object_add_value_string(bucket, "end", buffer); | |||
| 758 | ||||
| 759 | json_object_add_value_uint(bucket, "value", val)json_object_object_add(bucket, "value", json_object_new_uint64 (val)); | |||
| 760 | ||||
| 761 | } | |||
| 762 | ||||
| 763 | static void json_lat_stats_linear(struct intel_lat_stats *stats, | |||
| 764 | struct json_object *bucket_list, __u32 start_offset, | |||
| 765 | __u32 end_offset, __u32 bytes_per, | |||
| 766 | __u32 us_step, bool_Bool nonzero_print) | |||
| 767 | { | |||
| 768 | for (int i = (start_offset / bytes_per) - 1; | |||
| 769 | i < end_offset / bytes_per; i++) { | |||
| 770 | if (nonzero_print && stats->data[i] == 0) | |||
| 771 | continue; | |||
| 772 | ||||
| 773 | json_add_bucket(stats, bucket_list, | |||
| 774 | i, us_step * i, NOINF, us_step * (i + 1), | |||
| 775 | NOINF, stats->data[i]); | |||
| 776 | } | |||
| 777 | } | |||
| 778 | ||||
| 779 | static void json_lat_stats_3_0(struct intel_lat_stats *stats, int write) | |||
| 780 | { | |||
| 781 | struct json_object *root = json_create_object()json_object_new_object(); | |||
| 782 | struct json_object *bucket_list = json_object_new_array(); | |||
| 783 | ||||
| 784 | lat_stats_make_json_root(root, bucket_list, write); | |||
| 785 | ||||
| 786 | json_lat_stats_linear(stats, bucket_list, 4, 131, 4, 32, false0); | |||
| 787 | json_lat_stats_linear(stats, bucket_list, 132, 255, 4, 1024, false0); | |||
| 788 | json_lat_stats_linear(stats, bucket_list, 256, 379, 4, 32768, false0); | |||
| 789 | json_lat_stats_linear(stats, bucket_list, 380, 383, 4, 32, true1); | |||
| 790 | json_lat_stats_linear(stats, bucket_list, 384, 387, 4, 32, true1); | |||
| 791 | json_lat_stats_linear(stats, bucket_list, 388, 391, 4, 32, true1); | |||
| 792 | ||||
| 793 | json_print_object(root, NULL)printf("%s", json_object_to_json_string_ext(root, (1 << 1) | (1 << 4))); | |||
| 794 | printf("\n"); | |||
| 795 | json_free_object(root)json_object_put(root); | |||
| 796 | } | |||
| 797 | ||||
| 798 | static void json_lat_stats_4_0(struct intel_lat_stats *stats, int write) | |||
| 799 | { | |||
| 800 | struct json_object *root = json_create_object()json_object_new_object(); | |||
| 801 | struct json_object *bucket_list = json_object_new_array(); | |||
| 802 | ||||
| 803 | lat_stats_make_json_root(root, bucket_list, write); | |||
| 804 | ||||
| 805 | __u32 lower_us = 0; | |||
| 806 | __u32 upper_us = 1; | |||
| 807 | bool_Bool end = false0; | |||
| 808 | int max = 1216; | |||
| 809 | ||||
| 810 | for (int i = 0; i < max; i++) { | |||
| 811 | lower_us = lat_stats_log_scale(i); | |||
| 812 | if (i >= max - 1) | |||
| 813 | end = true1; | |||
| 814 | else | |||
| 815 | upper_us = lat_stats_log_scale(i + 1); | |||
| 816 | ||||
| 817 | json_add_bucket(stats, bucket_list, i, | |||
| 818 | lower_us, NOINF, upper_us, | |||
| 819 | end ? POSINF : NOINF, stats->data[i]); | |||
| 820 | } | |||
| 821 | json_print_object(root, NULL)printf("%s", json_object_to_json_string_ext(root, (1 << 1) | (1 << 4))); | |||
| 822 | printf("\n"); | |||
| 823 | json_free_object(root)json_object_put(root); | |||
| 824 | } | |||
| 825 | ||||
| 826 | static void show_lat_stats_3_0(struct intel_lat_stats *stats) | |||
| 827 | { | |||
| 828 | show_lat_stats_linear(stats, 4, 131, 4, 32, false0); | |||
| 829 | show_lat_stats_linear(stats, 132, 255, 4, 1024, false0); | |||
| 830 | show_lat_stats_linear(stats, 256, 379, 4, 32768, false0); | |||
| 831 | show_lat_stats_linear(stats, 380, 383, 4, 32, true1); | |||
| 832 | show_lat_stats_linear(stats, 384, 387, 4, 32, true1); | |||
| 833 | show_lat_stats_linear(stats, 388, 391, 4, 32, true1); | |||
| 834 | } | |||
| 835 | ||||
| 836 | static void show_lat_stats_4_0(struct intel_lat_stats *stats) | |||
| 837 | { | |||
| 838 | int lower_us = 0; | |||
| 839 | int upper_us = 1; | |||
| 840 | bool_Bool end = false0; | |||
| 841 | int max = 1216; | |||
| 842 | ||||
| 843 | for (int i = 0; i < max; i++) { | |||
| 844 | lower_us = lat_stats_log_scale(i); | |||
| 845 | if (i >= max - 1) | |||
| 846 | end = true1; | |||
| 847 | else | |||
| 848 | upper_us = lat_stats_log_scale(i + 1); | |||
| 849 | ||||
| 850 | show_lat_stats_bucket(stats, lower_us, NOINF, | |||
| 851 | upper_us, end ? POSINF : NOINF, i); | |||
| 852 | } | |||
| 853 | } | |||
| 854 | ||||
| 855 | static void json_lat_stats_v1000_0(struct optane_lat_stats *stats, int write) | |||
| 856 | { | |||
| 857 | int i; | |||
| 858 | struct json_object *root = json_create_object()json_object_new_object(); | |||
| 859 | struct json_object *bucket_list = json_object_new_array(); | |||
| 860 | ||||
| 861 | lat_stats_make_json_root(root, bucket_list, write); | |||
| 862 | ||||
| 863 | if (write) { | |||
| 864 | for (i = 0; i < OPTANE_V1000_BUCKET_LEN8 - 1; i++) | |||
| 865 | json_add_bucket_optane(bucket_list, i, | |||
| 866 | v1000_bucket.write[i], NOINF, | |||
| 867 | v1000_bucket.write[i + 1] - 1, | |||
| 868 | NOINF, | |||
| 869 | stats->data[i]); | |||
| 870 | ||||
| 871 | json_add_bucket_optane(bucket_list, | |||
| 872 | OPTANE_V1000_BUCKET_LEN8 - 1, | |||
| 873 | v1000_bucket.write[i], | |||
| 874 | NOINF, | |||
| 875 | v1000_bucket.write[i], | |||
| 876 | POSINF, stats->data[i]); | |||
| 877 | } else { | |||
| 878 | for (i = 0; i < OPTANE_V1000_BUCKET_LEN8 - 1; i++) | |||
| 879 | json_add_bucket_optane(bucket_list, i, | |||
| 880 | v1000_bucket.read[i], NOINF, | |||
| 881 | v1000_bucket.read[i + 1] - 1, | |||
| 882 | NOINF, | |||
| 883 | stats->data[i]); | |||
| 884 | ||||
| 885 | json_add_bucket_optane(bucket_list, | |||
| 886 | OPTANE_V1000_BUCKET_LEN8 - 1, | |||
| 887 | v1000_bucket.read[i], | |||
| 888 | NOINF, | |||
| 889 | v1000_bucket.read[i], | |||
| 890 | POSINF, stats->data[i]); | |||
| 891 | } | |||
| 892 | ||||
| 893 | struct json_object *subroot = json_create_object()json_object_new_object(); | |||
| 894 | ||||
| 895 | json_object_add_value_object(root, "Average latency since last reset", subroot)json_object_object_add(root, "Average latency since last reset" , subroot); | |||
| 896 | ||||
| 897 | json_object_add_value_uint(subroot, "value in us", stats->data[8])json_object_object_add(subroot, "value in us", json_object_new_uint64 (stats->data[8])); | |||
| 898 | ||||
| 899 | json_print_object(root, NULL)printf("%s", json_object_to_json_string_ext(root, (1 << 1) | (1 << 4))); | |||
| 900 | printf("\n"); | |||
| 901 | json_free_object(root)json_object_put(root); | |||
| 902 | ||||
| 903 | } | |||
| 904 | ||||
| 905 | static void show_lat_stats_v1000_0(struct optane_lat_stats *stats, int write) | |||
| 906 | { | |||
| 907 | int i; | |||
| 908 | ||||
| 909 | if (write) { | |||
| 910 | for (i = 0; i < OPTANE_V1000_BUCKET_LEN8 - 1; i++) | |||
| 911 | show_optane_lat_stats_bucket(stats, | |||
| 912 | v1000_bucket.write[i], | |||
| 913 | NOINF, | |||
| 914 | v1000_bucket.write[i + 1] - 1, | |||
| 915 | NOINF, i); | |||
| 916 | ||||
| 917 | show_optane_lat_stats_bucket(stats, v1000_bucket.write[i], | |||
| 918 | NOINF, v1000_bucket.write[i], | |||
| 919 | POSINF, i); | |||
| 920 | } else { | |||
| 921 | for (i = 0; i < OPTANE_V1000_BUCKET_LEN8 - 1; i++) | |||
| 922 | show_optane_lat_stats_bucket(stats, | |||
| 923 | v1000_bucket.read[i], | |||
| 924 | NOINF, | |||
| 925 | v1000_bucket.read[i + 1] - 1, | |||
| 926 | NOINF, i); | |||
| 927 | ||||
| 928 | show_optane_lat_stats_bucket(stats, v1000_bucket.read[i], | |||
| 929 | NOINF, v1000_bucket.read[i], | |||
| 930 | POSINF, i); | |||
| 931 | } | |||
| 932 | ||||
| 933 | printf("Average latency since last reset: %lu us\n", (unsigned long)stats->data[8]); | |||
| 934 | ||||
| 935 | } | |||
| 936 | ||||
| 937 | static void json_lat_stats(int write) | |||
| 938 | { | |||
| 939 | switch (media_version[MEDIA_MAJOR_IDX0]) { | |||
| 940 | case 3: | |||
| 941 | json_lat_stats_3_0(&stats, write); | |||
| 942 | break; | |||
| 943 | case 4: | |||
| 944 | switch (media_version[MEDIA_MINOR_IDX1]) { | |||
| 945 | case 0: | |||
| 946 | case 1: | |||
| 947 | case 2: | |||
| 948 | case 3: | |||
| 949 | case 4: | |||
| 950 | case 5: | |||
| 951 | json_lat_stats_4_0(&stats, write); | |||
| 952 | break; | |||
| 953 | default: | |||
| 954 | nvme_show_error("Unsupported minor revision (%u.%u)",nvme_show_message(1, "Unsupported minor revision (%u.%u)", stats .maj, stats.min) | |||
| 955 | stats.maj, stats.min)nvme_show_message(1, "Unsupported minor revision (%u.%u)", stats .maj, stats.min); | |||
| 956 | break; | |||
| 957 | } | |||
| 958 | break; | |||
| 959 | case 1000: | |||
| 960 | switch (media_version[MEDIA_MINOR_IDX1]) { | |||
| 961 | case 0: | |||
| 962 | json_lat_stats_v1000_0(&v1000_stats, write); | |||
| 963 | break; | |||
| 964 | default: | |||
| 965 | nvme_show_error("Unsupported minor revision (%u.%u)",nvme_show_message(1, "Unsupported minor revision (%u.%u)", stats .maj, stats.min) | |||
| 966 | stats.maj, stats.min)nvme_show_message(1, "Unsupported minor revision (%u.%u)", stats .maj, stats.min); | |||
| 967 | break; | |||
| 968 | } | |||
| 969 | break; | |||
| 970 | default: | |||
| 971 | nvme_show_error("Unsupported revision (%u.%u)",nvme_show_message(1, "Unsupported revision (%u.%u)", stats.maj , stats.min) | |||
| 972 | stats.maj, stats.min)nvme_show_message(1, "Unsupported revision (%u.%u)", stats.maj , stats.min); | |||
| 973 | break; | |||
| 974 | } | |||
| 975 | printf("\n"); | |||
| 976 | } | |||
| 977 | ||||
| 978 | static void | |||
| 979 | print_dash_separator(int count) | |||
| 980 | { | |||
| 981 | for (int i = 0; i < count; i++) | |||
| 982 | putchar('-'); | |||
| 983 | putchar('\n'); | |||
| 984 | } | |||
| 985 | ||||
| 986 | static void show_lat_stats(int write) | |||
| 987 | { | |||
| 988 | static const int separator_length = 50; | |||
| 989 | ||||
| 990 | printf("Intel IO %s Command Latency Statistics\n", | |||
| 991 | write ? "Write" : "Read"); | |||
| 992 | printf("Major Revision : %u\nMinor Revision : %u\n", | |||
| 993 | media_version[MEDIA_MAJOR_IDX0], media_version[MEDIA_MINOR_IDX1]); | |||
| 994 | print_dash_separator(separator_length); | |||
| 995 | printf("%-12s%-12s%-12s%-20s\n", "Bucket", "Start", "End", "Value"); | |||
| 996 | print_dash_separator(separator_length); | |||
| 997 | ||||
| 998 | switch (media_version[MEDIA_MAJOR_IDX0]) { | |||
| 999 | case 3: | |||
| 1000 | show_lat_stats_3_0(&stats); | |||
| 1001 | break; | |||
| 1002 | case 4: | |||
| 1003 | switch (media_version[MEDIA_MINOR_IDX1]) { | |||
| 1004 | case 0: | |||
| 1005 | case 1: | |||
| 1006 | case 2: | |||
| 1007 | case 3: | |||
| 1008 | case 4: | |||
| 1009 | case 5: | |||
| 1010 | case 6: | |||
| 1011 | show_lat_stats_4_0(&stats); | |||
| 1012 | break; | |||
| 1013 | default: | |||
| 1014 | nvme_show_error("Unsupported minor revision (%u.%u)",nvme_show_message(1, "Unsupported minor revision (%u.%u)", stats .maj, stats.min) | |||
| 1015 | stats.maj, stats.min)nvme_show_message(1, "Unsupported minor revision (%u.%u)", stats .maj, stats.min); | |||
| 1016 | break; | |||
| 1017 | } | |||
| 1018 | break; | |||
| 1019 | case 1000: | |||
| 1020 | switch (media_version[MEDIA_MINOR_IDX1]) { | |||
| 1021 | case 0: | |||
| 1022 | show_lat_stats_v1000_0(&v1000_stats, write); | |||
| 1023 | break; | |||
| 1024 | default: | |||
| 1025 | nvme_show_error("Unsupported minor revision (%u.%u)",nvme_show_message(1, "Unsupported minor revision (%u.%u)", stats .maj, stats.min) | |||
| 1026 | stats.maj, stats.min)nvme_show_message(1, "Unsupported minor revision (%u.%u)", stats .maj, stats.min); | |||
| 1027 | break; | |||
| 1028 | } | |||
| 1029 | break; | |||
| 1030 | default: | |||
| 1031 | nvme_show_error("Unsupported revision (%u.%u)",nvme_show_message(1, "Unsupported revision (%u.%u)", stats.maj , stats.min) | |||
| 1032 | stats.maj, stats.min)nvme_show_message(1, "Unsupported revision (%u.%u)", stats.maj , stats.min); | |||
| 1033 | break; | |||
| 1034 | } | |||
| 1035 | } | |||
| 1036 | ||||
| 1037 | static int get_lat_stats_log(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 1038 | { | |||
| 1039 | __u8 data[NAND_LAT_STATS_LEN4868]; | |||
| 1040 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 1041 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 1042 | nvme_print_flags_t flags; | |||
| 1043 | int err; | |||
| 1044 | ||||
| 1045 | const char *desc = "Get Intel Latency Statistics log and show it."; | |||
| 1046 | const char *raw = "Dump output in binary format"; | |||
| 1047 | #ifdef CONFIG_JSONC | |||
| 1048 | const char *json = "Dump output in json format"; | |||
| 1049 | #endif /* CONFIG_JSONC */ | |||
| 1050 | const char *write = "Get write statistics (read default)"; | |||
| 1051 | ||||
| 1052 | struct config { | |||
| 1053 | bool_Bool raw_binary; | |||
| 1054 | bool_Bool json; | |||
| 1055 | bool_Bool write; | |||
| 1056 | }; | |||
| 1057 | ||||
| 1058 | struct config cfg = { | |||
| 1059 | }; | |||
| 1060 | ||||
| 1061 | NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; 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, }, {"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, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet , 0, "suppress informational output", 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary" , 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}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } } | |||
| 1062 | OPT_FLAG("write", 'w', &cfg.write, write),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; 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, }, {"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, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet , 0, "suppress informational output", 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary" , 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}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } } | |||
| 1063 | OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; 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, }, {"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, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet , 0, "suppress informational output", 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary" , 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}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } } | |||
| 1064 | OPT_FLAG_JSON("json", 'j', &cfg.json, json))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; 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, }, {"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, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet , 0, "suppress informational output", 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary" , 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}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } }; | |||
| 1065 | ||||
| 1066 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 1067 | if (err) | |||
| 1068 | return err; | |||
| 1069 | ||||
| 1070 | err = validate_output_format(nvme_args.output_format, &flags); | |||
| 1071 | if (err < 0) { | |||
| 1072 | nvme_show_error("Invalid output format")nvme_show_message(1, "Invalid output format"); | |||
| 1073 | return err; | |||
| 1074 | } | |||
| 1075 | ||||
| 1076 | /* For optate, latency stats are deleted every time their LID is pulled. | |||
| 1077 | * Therefore, we query the longest lat_stats log page first. | |||
| 1078 | */ | |||
| 1079 | err = nvme_get_log_simple(hdl, cfg.write ? 0xc2 : 0xc1, | |||
| 1080 | &data, sizeof(data)); | |||
| 1081 | ||||
| 1082 | media_version[0] = (data[1] << 8) | data[0]; | |||
| 1083 | media_version[1] = (data[3] << 8) | data[2]; | |||
| 1084 | ||||
| 1085 | if (err) | |||
| 1086 | return err; | |||
| 1087 | ||||
| 1088 | if (media_version[0] == 1000) { | |||
| 1089 | __u32 thresholds[OPTANE_V1000_BUCKET_LEN8] = {0}; | |||
| 1090 | __u64 result; | |||
| 1091 | ||||
| 1092 | err = nvme_get_features(hdl, 0, 0xf7, | |||
| 1093 | 0, cfg.write ? 0x1 : 0x0, | |||
| 1094 | 0, thresholds, sizeof(thresholds), | |||
| 1095 | &result); | |||
| 1096 | if (err) { | |||
| 1097 | nvme_show_error("Querying thresholds failed. ")nvme_show_message(1, "Querying thresholds failed. "); | |||
| 1098 | nvme_show_status(err); | |||
| 1099 | return err; | |||
| 1100 | } | |||
| 1101 | ||||
| 1102 | /* Update bucket thresholds to be printed */ | |||
| 1103 | if (cfg.write) { | |||
| 1104 | for (int i = 0; i < OPTANE_V1000_BUCKET_LEN8; i++) | |||
| 1105 | v1000_bucket.write[i] = thresholds[i]; | |||
| 1106 | } else { | |||
| 1107 | for (int i = 0; i < OPTANE_V1000_BUCKET_LEN8; i++) | |||
| 1108 | v1000_bucket.read[i] = thresholds[i]; | |||
| 1109 | ||||
| 1110 | } | |||
| 1111 | ||||
| 1112 | /* Move counter values to optate stats struct which has a | |||
| 1113 | * smaller size | |||
| 1114 | */ | |||
| 1115 | memcpy(&v1000_stats, (struct optane_lat_stats *)data, | |||
| 1116 | sizeof(struct optane_lat_stats)); | |||
| 1117 | } else { | |||
| 1118 | memcpy(&stats, (struct intel_lat_stats *)data, | |||
| 1119 | sizeof(struct intel_lat_stats)); | |||
| 1120 | } | |||
| 1121 | ||||
| 1122 | if (flags & JSON || cfg.json) | |||
| 1123 | json_lat_stats(cfg.write); | |||
| 1124 | else if (!cfg.raw_binary) | |||
| 1125 | show_lat_stats(cfg.write); | |||
| 1126 | else { | |||
| 1127 | if (media_version[0] == 1000) | |||
| 1128 | d_raw((unsigned char *)&v1000_stats, | |||
| 1129 | sizeof(v1000_stats)); | |||
| 1130 | else | |||
| 1131 | d_raw((unsigned char *)&stats, | |||
| 1132 | sizeof(stats)); | |||
| 1133 | } | |||
| 1134 | ||||
| 1135 | return 0; | |||
| 1136 | } | |||
| 1137 | ||||
| 1138 | struct intel_assert_dump { | |||
| 1139 | __u32 coreoffset; | |||
| 1140 | __u32 assertsize; | |||
| 1141 | __u8 assertdumptype; | |||
| 1142 | __u8 assertvalid; | |||
| 1143 | __u8 reserved[2]; | |||
| 1144 | }; | |||
| 1145 | ||||
| 1146 | struct intel_event_dump { | |||
| 1147 | __u32 numeventdumps; | |||
| 1148 | __u32 coresize; | |||
| 1149 | __u32 coreoffset; | |||
| 1150 | __u32 eventidoffset[16]; | |||
| 1151 | __u8 eventIdValidity[16]; | |||
| 1152 | }; | |||
| 1153 | ||||
| 1154 | struct intel_vu_version { | |||
| 1155 | __u16 major; | |||
| 1156 | __u16 minor; | |||
| 1157 | }; | |||
| 1158 | ||||
| 1159 | struct intel_event_header { | |||
| 1160 | __u32 eventidsize; | |||
| 1161 | struct intel_event_dump edumps[0]; | |||
| 1162 | }; | |||
| 1163 | ||||
| 1164 | struct intel_vu_log { | |||
| 1165 | struct intel_vu_version ver; | |||
| 1166 | __u32 header; | |||
| 1167 | __u32 size; | |||
| 1168 | __u32 numcores; | |||
| 1169 | __u8 reserved[4080]; | |||
| 1170 | }; | |||
| 1171 | ||||
| 1172 | struct intel_vu_nlog { | |||
| 1173 | struct intel_vu_version ver; | |||
| 1174 | __u32 logselect; | |||
| 1175 | __u32 totalnlogs; | |||
| 1176 | __u32 nlognum; | |||
| 1177 | __u32 nlogname; | |||
| 1178 | __u32 nlogbytesize; | |||
| 1179 | __u32 nlogprimarybuffsize; | |||
| 1180 | __u32 tickspersecond; | |||
| 1181 | __u32 corecount; | |||
| 1182 | __u32 nlogpausestatus; | |||
| 1183 | __u32 selectoffsetref; | |||
| 1184 | __u32 selectnlogpause; | |||
| 1185 | __u32 selectaddedoffset; | |||
| 1186 | __u32 nlogbufnum; | |||
| 1187 | __u32 nlogbufnummax; | |||
| 1188 | __u32 coreselected; | |||
| 1189 | __u32 reserved[3]; | |||
| 1190 | }; | |||
| 1191 | ||||
| 1192 | struct intel_cd_log { | |||
| 1193 | union { | |||
| 1194 | struct { | |||
| 1195 | __u32 selectLog : 3; | |||
| 1196 | __u32 selectCore : 2; | |||
| 1197 | __u32 selectNlog : 8; | |||
| 1198 | __u8 selectOffsetRef : 1; | |||
| 1199 | __u32 selectNlogPause : 2; | |||
| 1200 | __u32 reserved2 : 16; | |||
| 1201 | } fields; | |||
| 1202 | __u32 entireDword; | |||
| 1203 | } u; | |||
| 1204 | }; | |||
| 1205 | ||||
| 1206 | static void print_intel_nlog(struct intel_vu_nlog *intel_nlog) | |||
| 1207 | { | |||
| 1208 | printf("Version Major %u\n" | |||
| 1209 | "Version Minor %u\n" | |||
| 1210 | "Log_select %u\n" | |||
| 1211 | "totalnlogs %u\n" | |||
| 1212 | "nlognum %u\n" | |||
| 1213 | "nlogname %u\n" | |||
| 1214 | "nlogbytesze %u\n" | |||
| 1215 | "nlogprimarybuffsize %u\n" | |||
| 1216 | "tickspersecond %u\n" | |||
| 1217 | "corecount %u\n" | |||
| 1218 | "nlogpausestatus %u\n" | |||
| 1219 | "selectoffsetref %u\n" | |||
| 1220 | "selectnlogpause %u\n" | |||
| 1221 | "selectaddedoffset %u\n" | |||
| 1222 | "nlogbufnum %u\n" | |||
| 1223 | "nlogbufnummax %u\n" | |||
| 1224 | "coreselected %u\n", | |||
| 1225 | intel_nlog->ver.major, intel_nlog->ver.minor, | |||
| 1226 | intel_nlog->logselect, intel_nlog->totalnlogs, intel_nlog->nlognum, | |||
| 1227 | intel_nlog->nlogname, intel_nlog->nlogbytesize, | |||
| 1228 | intel_nlog->nlogprimarybuffsize, intel_nlog->tickspersecond, | |||
| 1229 | intel_nlog->corecount, intel_nlog->nlogpausestatus, | |||
| 1230 | intel_nlog->selectoffsetref, intel_nlog->selectnlogpause, | |||
| 1231 | intel_nlog->selectaddedoffset, intel_nlog->nlogbufnum, | |||
| 1232 | intel_nlog->nlogbufnummax, intel_nlog->coreselected); | |||
| 1233 | } | |||
| 1234 | ||||
| 1235 | static int read_entire_cmd(struct libnvme_passthru_cmd *cmd, int total_size, | |||
| 1236 | const size_t max_tfer, int out_fd, | |||
| 1237 | struct libnvme_transport_handle *hdl, __u8 *buf) | |||
| 1238 | { | |||
| 1239 | int err = 0; | |||
| 1240 | size_t dword_tfer = 0; | |||
| 1241 | ||||
| 1242 | dword_tfer = min(max_tfer, total_size)({ typeof(max_tfer) _a = (max_tfer); typeof(total_size) _b = ( total_size); do { } while (0); _a < _b ? _a : _b; }); | |||
| 1243 | while (total_size > 0) { | |||
| 1244 | err = libnvme_exec_admin_passthru(hdl, cmd); | |||
| 1245 | if (err) { | |||
| 1246 | nvme_show_error(nvme_show_message(1, "failed on cmd.data_len %u cmd.cdw13 %u cmd.cdw12 %x cmd.cdw10 %u err %x remaining size %d\n" , cmd->data_len, cmd->cdw13, cmd->cdw12, cmd->cdw10 , err, total_size) | |||
| 1247 | "failed on cmd.data_len %u cmd.cdw13 %u cmd.cdw12 %x cmd.cdw10 %u err %x remaining size %d\n",nvme_show_message(1, "failed on cmd.data_len %u cmd.cdw13 %u cmd.cdw12 %x cmd.cdw10 %u err %x remaining size %d\n" , cmd->data_len, cmd->cdw13, cmd->cdw12, cmd->cdw10 , err, total_size) | |||
| 1248 | cmd->data_len, cmd->cdw13, cmd->cdw12,nvme_show_message(1, "failed on cmd.data_len %u cmd.cdw13 %u cmd.cdw12 %x cmd.cdw10 %u err %x remaining size %d\n" , cmd->data_len, cmd->cdw13, cmd->cdw12, cmd->cdw10 , err, total_size) | |||
| 1249 | cmd->cdw10, err, total_size)nvme_show_message(1, "failed on cmd.data_len %u cmd.cdw13 %u cmd.cdw12 %x cmd.cdw10 %u err %x remaining size %d\n" , cmd->data_len, cmd->cdw13, cmd->cdw12, cmd->cdw10 , err, total_size); | |||
| 1250 | goto out; | |||
| 1251 | } | |||
| 1252 | ||||
| 1253 | if (out_fd > 0) { | |||
| 1254 | err = write(out_fd, buf, cmd->data_len); | |||
| 1255 | if (err < 0) { | |||
| 1256 | nvme_show_perror("write failure"); | |||
| 1257 | goto out; | |||
| 1258 | } | |||
| 1259 | err = 0; | |||
| 1260 | } | |||
| 1261 | total_size -= dword_tfer; | |||
| 1262 | cmd->cdw13 += dword_tfer; | |||
| 1263 | cmd->cdw10 = dword_tfer = min(max_tfer, total_size)({ typeof(max_tfer) _a = (max_tfer); typeof(total_size) _b = ( total_size); do { } while (0); _a < _b ? _a : _b; }); | |||
| 1264 | cmd->data_len = (min(max_tfer, total_size)({ typeof(max_tfer) _a = (max_tfer); typeof(total_size) _b = ( total_size); do { } while (0); _a < _b ? _a : _b; })) * 4; | |||
| 1265 | } | |||
| 1266 | ||||
| 1267 | out: | |||
| 1268 | return err; | |||
| 1269 | } | |||
| 1270 | ||||
| 1271 | static int write_header(__u8 *buf, int fd, size_t amnt) | |||
| 1272 | { | |||
| 1273 | if (write(fd, buf, amnt) < 0) | |||
| 1274 | return 1; | |||
| 1275 | return 0; | |||
| 1276 | } | |||
| 1277 | ||||
| 1278 | static int read_header(struct libnvme_passthru_cmd *cmd, __u8 *buf, | |||
| 1279 | struct libnvme_transport_handle *hdl, __u32 dw12, int nsid) | |||
| 1280 | { | |||
| 1281 | memset(cmd, 0, sizeof(*cmd)); | |||
| 1282 | memset(buf, 0, 4096); | |||
| 1283 | cmd->opcode = 0xd2; | |||
| 1284 | cmd->nsid = nsid; | |||
| 1285 | cmd->cdw10 = 0x400; | |||
| 1286 | cmd->cdw12 = dw12; | |||
| 1287 | cmd->data_len = 0x1000; | |||
| 1288 | cmd->addr = (uintptr_t)(void *)buf; | |||
| 1289 | return read_entire_cmd(cmd, 0x400, 0x400, -1, hdl, buf); | |||
| 1290 | } | |||
| 1291 | ||||
| 1292 | static int setup_file(char *f, char *file, struct libnvme_transport_handle *hdl, int type) | |||
| 1293 | { | |||
| 1294 | struct nvme_id_ctrl ctrl; | |||
| 1295 | struct libnvme_passthru_cmd cmd; | |||
| 1296 | int err = 0, i = sizeof(ctrl.sn) - 1; | |||
| 1297 | ||||
| 1298 | nvme_init_identify_ctrl(&cmd, &ctrl); | |||
| 1299 | err = libnvme_exec_admin_passthru(hdl, &cmd); | |||
| 1300 | if (err) | |||
| 1301 | return err; | |||
| 1302 | ||||
| 1303 | /* Remove trailing spaces from the name */ | |||
| 1304 | while (i && ctrl.sn[i] == ' ') { | |||
| 1305 | ctrl.sn[i] = '\0'; | |||
| 1306 | i--; | |||
| 1307 | } | |||
| 1308 | ||||
| 1309 | sprintf(f, "%s_%-.*s.bin", type == 0 ? "Nlog" : | |||
| 1310 | type == 1 ? "EventLog" : "AssertLog", | |||
| 1311 | (int)sizeof(ctrl.sn), ctrl.sn); | |||
| 1312 | return err; | |||
| 1313 | } | |||
| 1314 | ||||
| 1315 | static int get_internal_log_old(__u8 *buf, int output, | |||
| 1316 | struct libnvme_transport_handle *hdl, | |||
| 1317 | struct libnvme_passthru_cmd *cmd) | |||
| 1318 | { | |||
| 1319 | struct intel_vu_log *intel; | |||
| 1320 | int err = 0; | |||
| 1321 | const int dwmax = 0x400; | |||
| 1322 | const int dmamax = 0x1000; | |||
| 1323 | ||||
| 1324 | intel = (struct intel_vu_log *)buf; | |||
| 1325 | ||||
| 1326 | printf("Log major:%d minor:%d header:%d size:%d\n", | |||
| 1327 | intel->ver.major, intel->ver.minor, intel->header, intel->size); | |||
| 1328 | ||||
| 1329 | err = write(output, buf, 0x1000); | |||
| 1330 | if (err < 0) { | |||
| 1331 | nvme_show_perror("write failure"); | |||
| 1332 | goto out; | |||
| 1333 | } | |||
| 1334 | intel->size -= 0x400; | |||
| 1335 | cmd->opcode = 0xd2; | |||
| 1336 | cmd->cdw10 = min(dwmax, intel->size)({ typeof(dwmax) _a = (dwmax); typeof(intel->size) _b = (intel ->size); do { } while (0); _a < _b ? _a : _b; }); | |||
| 1337 | cmd->data_len = min(dmamax, intel->size)({ typeof(dmamax) _a = (dmamax); typeof(intel->size) _b = ( intel->size); do { } while (0); _a < _b ? _a : _b; }); | |||
| 1338 | err = read_entire_cmd(cmd, intel->size, dwmax, output, hdl, buf); | |||
| 1339 | if (err) | |||
| 1340 | goto out; | |||
| 1341 | ||||
| 1342 | err = 0; | |||
| 1343 | out: | |||
| 1344 | return err; | |||
| 1345 | } | |||
| 1346 | ||||
| 1347 | static int get_internal_log(int argc, char **argv, struct command *acmd, | |||
| 1348 | struct plugin *plugin) | |||
| 1349 | { | |||
| 1350 | __u8 buf[0x2000]; | |||
| 1351 | char f[0x100]; | |||
| 1352 | int err, output, i, j, count = 0, core_num = 1; | |||
| 1353 | struct libnvme_passthru_cmd cmd; | |||
| 1354 | struct intel_cd_log cdlog; | |||
| 1355 | struct intel_vu_nlog *intel_nlog = (struct intel_vu_nlog *)buf; | |||
| 1356 | struct intel_assert_dump *ad; | |||
| 1357 | struct intel_event_header *ehdr; | |||
| 1358 | __cleanup_free__attribute__((cleanup(shr_freep))) struct intel_vu_log *intel = NULL((void*)0); | |||
| 1359 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 1360 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 1361 | ||||
| 1362 | const char *desc = "Get Intel Firmware Log and save it."; | |||
| 1363 | const char *log = "Log type: 0, 1, or 2 for nlog, event log, and assert log, respectively."; | |||
| 1364 | const char *core = "Select which region log should come from. -1 for all"; | |||
| 1365 | const char *nlognum = "Select which nlog to read. -1 for all nlogs"; | |||
| 1366 | const char *file = "Output file; defaults to device name provided"; | |||
| 1367 | const char *verbose = "To print out verbose nlog info"; | |||
| 1368 | const char *namespace_id = "Namespace to get logs from"; | |||
| 1369 | ||||
| 1370 | struct config { | |||
| 1371 | __u32 namespace_id; | |||
| 1372 | __u32 log; | |||
| 1373 | int core; | |||
| 1374 | int lnum; | |||
| 1375 | char *file; | |||
| 1376 | bool_Bool verbose; | |||
| 1377 | }; | |||
| 1378 | ||||
| 1379 | struct config cfg = { | |||
| 1380 | .namespace_id = -1, | |||
| 1381 | .file = NULL((void*)0), | |||
| 1382 | .lnum = -1, | |||
| 1383 | .core = -1 | |||
| 1384 | }; | |||
| 1385 | ||||
| 1386 | NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"log", 'l', "NUM", CFG_POSITIVE, &cfg.log, 1, log , 0, }, {"region", 'r', "NUM", CFG_INT, &cfg.core, 1, core , 0, }, {"nlognum", 'm', "NUM", CFG_INT, &cfg.lnum, 1, nlognum , 0, }, {"namespace-id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"output-file", 'O', "FILE", CFG_STRING , &cfg.file, 1, file, 0, }, {"verbose-nlog", 'V', ((void* )0), CFG_FLAG, &cfg.verbose, 0, verbose, 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, }, {"quiet" , 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary", 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}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } } | |||
| 1387 | OPT_UINT("log", 'l', &cfg.log, log),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"log", 'l', "NUM", CFG_POSITIVE, &cfg.log, 1, log , 0, }, {"region", 'r', "NUM", CFG_INT, &cfg.core, 1, core , 0, }, {"nlognum", 'm', "NUM", CFG_INT, &cfg.lnum, 1, nlognum , 0, }, {"namespace-id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"output-file", 'O', "FILE", CFG_STRING , &cfg.file, 1, file, 0, }, {"verbose-nlog", 'V', ((void* )0), CFG_FLAG, &cfg.verbose, 0, verbose, 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, }, {"quiet" , 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary", 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}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } } | |||
| 1388 | OPT_INT("region", 'r', &cfg.core, core),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"log", 'l', "NUM", CFG_POSITIVE, &cfg.log, 1, log , 0, }, {"region", 'r', "NUM", CFG_INT, &cfg.core, 1, core , 0, }, {"nlognum", 'm', "NUM", CFG_INT, &cfg.lnum, 1, nlognum , 0, }, {"namespace-id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"output-file", 'O', "FILE", CFG_STRING , &cfg.file, 1, file, 0, }, {"verbose-nlog", 'V', ((void* )0), CFG_FLAG, &cfg.verbose, 0, verbose, 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, }, {"quiet" , 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary", 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}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } } | |||
| 1389 | OPT_INT("nlognum", 'm', &cfg.lnum, nlognum),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"log", 'l', "NUM", CFG_POSITIVE, &cfg.log, 1, log , 0, }, {"region", 'r', "NUM", CFG_INT, &cfg.core, 1, core , 0, }, {"nlognum", 'm', "NUM", CFG_INT, &cfg.lnum, 1, nlognum , 0, }, {"namespace-id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"output-file", 'O', "FILE", CFG_STRING , &cfg.file, 1, file, 0, }, {"verbose-nlog", 'V', ((void* )0), CFG_FLAG, &cfg.verbose, 0, verbose, 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, }, {"quiet" , 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary", 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}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } } | |||
| 1390 | OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"log", 'l', "NUM", CFG_POSITIVE, &cfg.log, 1, log , 0, }, {"region", 'r', "NUM", CFG_INT, &cfg.core, 1, core , 0, }, {"nlognum", 'm', "NUM", CFG_INT, &cfg.lnum, 1, nlognum , 0, }, {"namespace-id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"output-file", 'O', "FILE", CFG_STRING , &cfg.file, 1, file, 0, }, {"verbose-nlog", 'V', ((void* )0), CFG_FLAG, &cfg.verbose, 0, verbose, 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, }, {"quiet" , 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary", 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}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } } | |||
| 1391 | OPT_FILE("output-file", 'O', &cfg.file, file),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"log", 'l', "NUM", CFG_POSITIVE, &cfg.log, 1, log , 0, }, {"region", 'r', "NUM", CFG_INT, &cfg.core, 1, core , 0, }, {"nlognum", 'm', "NUM", CFG_INT, &cfg.lnum, 1, nlognum , 0, }, {"namespace-id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"output-file", 'O', "FILE", CFG_STRING , &cfg.file, 1, file, 0, }, {"verbose-nlog", 'V', ((void* )0), CFG_FLAG, &cfg.verbose, 0, verbose, 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, }, {"quiet" , 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary", 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}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } } | |||
| 1392 | OPT_FLAG("verbose-nlog", 'V', &cfg.verbose, verbose))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; struct argconfig_commandline_options opts[] = { {"", 0, ((void *)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void *)0)}, {"log", 'l', "NUM", CFG_POSITIVE, &cfg.log, 1, log , 0, }, {"region", 'r', "NUM", CFG_INT, &cfg.core, 1, core , 0, }, {"nlognum", 'm', "NUM", CFG_INT, &cfg.lnum, 1, nlognum , 0, }, {"namespace-id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id , 1, namespace_id, 0, }, {"output-file", 'O', "FILE", CFG_STRING , &cfg.file, 1, file, 0, }, {"verbose-nlog", 'V', ((void* )0), CFG_FLAG, &cfg.verbose, 0, verbose, 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, }, {"quiet" , 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary", 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}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } }; | |||
| 1393 | ||||
| 1394 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 1395 | if (err) | |||
| ||||
| 1396 | return err; | |||
| 1397 | ||||
| 1398 | intel = malloc(sizeof(*intel)); | |||
| 1399 | if (!intel) | |||
| 1400 | return -ENOMEM12; | |||
| 1401 | ||||
| 1402 | ad = (struct intel_assert_dump *)intel->reserved; | |||
| 1403 | ehdr = (struct intel_event_header *)intel->reserved; | |||
| 1404 | ||||
| 1405 | if (cfg.log > 2 || cfg.core > 4 || cfg.lnum > 255) { | |||
| 1406 | err = -EINVAL22; | |||
| ||||
| 1407 | goto out_free; | |||
| 1408 | } | |||
| 1409 | ||||
| 1410 | if (!cfg.file) { | |||
| 1411 | err = setup_file(f, cfg.file, hdl, cfg.log); | |||
| 1412 | if (err) | |||
| 1413 | goto out_free; | |||
| 1414 | cfg.file = f; | |||
| 1415 | } | |||
| 1416 | ||||
| 1417 | cdlog.u.entireDword = 0; | |||
| 1418 | ||||
| 1419 | cdlog.u.fields.selectLog = cfg.log; | |||
| 1420 | cdlog.u.fields.selectCore = cfg.core < 0 ? 0 : cfg.core; | |||
| 1421 | cdlog.u.fields.selectNlog = cfg.lnum < 0 ? 0 : cfg.lnum; | |||
| 1422 | ||||
| 1423 | output = shr_open_rawdata(cfg.file, O_WRONLY | O_CREAT | O_TRUNC, 0666)open((cfg.file), (01 | 0100 | 01000), 0666); | |||
| 1424 | if (output < 0) { | |||
| 1425 | err = output; | |||
| 1426 | goto out_free; | |||
| 1427 | } | |||
| 1428 | ||||
| 1429 | err = read_header(&cmd, buf, hdl, cdlog.u.entireDword, | |||
| 1430 | cfg.namespace_id); | |||
| 1431 | if (err) | |||
| 1432 | goto out; | |||
| 1433 | memcpy(intel, buf, sizeof(*intel)); | |||
| 1434 | ||||
| 1435 | /* for 1.1 Fultondales will use old nlog, but current assert/event */ | |||
| 1436 | if ((intel->ver.major < 1 && intel->ver.minor < 1) || | |||
| 1437 | (intel->ver.major <= 1 && intel->ver.minor <= 1 && cfg.log == 0)) { | |||
| 1438 | cmd.addr = (uintptr_t)(void *)buf; | |||
| 1439 | err = get_internal_log_old(buf, output, hdl, &cmd); | |||
| 1440 | goto out; | |||
| 1441 | } | |||
| 1442 | ||||
| 1443 | if (cfg.log == 2) { | |||
| 1444 | if (cfg.verbose) | |||
| 1445 | printf("Log major:%d minor:%d header:%d size:%d numcores:%d\n", | |||
| 1446 | intel->ver.major, intel->ver.minor, | |||
| 1447 | intel->header, intel->size, intel->numcores); | |||
| 1448 | ||||
| 1449 | err = write_header(buf, output, 0x1000); | |||
| 1450 | if (err) { | |||
| 1451 | nvme_show_perror("write failure"); | |||
| 1452 | goto out; | |||
| 1453 | } | |||
| 1454 | ||||
| 1455 | count = intel->numcores; | |||
| 1456 | } else if (cfg.log == 0) { | |||
| 1457 | if (cfg.lnum < 0) | |||
| 1458 | count = intel_nlog->totalnlogs; | |||
| 1459 | else | |||
| 1460 | count = 1; | |||
| 1461 | if (cfg.core < 0) | |||
| 1462 | core_num = intel_nlog->corecount; | |||
| 1463 | } else if (cfg.log == 1) { | |||
| 1464 | core_num = intel->numcores; | |||
| 1465 | count = 1; | |||
| 1466 | err = write_header(buf, output, sizeof(*intel)); | |||
| 1467 | if (err) | |||
| 1468 | goto out; | |||
| 1469 | } | |||
| 1470 | ||||
| 1471 | for (j = (cfg.core < 0 ? 0 : cfg.core); | |||
| 1472 | j < (cfg.core < 0 ? core_num : cfg.core + 1); | |||
| 1473 | j++) { | |||
| 1474 | cdlog.u.fields.selectCore = j; | |||
| 1475 | for (i = 0; i < count; i++) { | |||
| 1476 | if (cfg.log == 2) { | |||
| 1477 | if (!ad[i].assertvalid) | |||
| 1478 | continue; | |||
| 1479 | cmd.cdw13 = ad[i].coreoffset; | |||
| 1480 | cmd.cdw10 = 0x400; | |||
| 1481 | cmd.data_len = min(0x400, ad[i].assertsize)({ typeof(0x400) _a = (0x400); typeof(ad[i].assertsize) _b = ( ad[i].assertsize); do { } while (0); _a < _b ? _a : _b; }) * 4; | |||
| 1482 | err = read_entire_cmd(&cmd, ad[i].assertsize, | |||
| 1483 | 0x400, output, | |||
| 1484 | hdl, | |||
| 1485 | buf); | |||
| 1486 | if (err) | |||
| 1487 | goto out; | |||
| 1488 | ||||
| 1489 | } else if (cfg.log == 0) { | |||
| 1490 | /* If the user selected to read the entire nlog */ | |||
| 1491 | if (count > 1) | |||
| 1492 | cdlog.u.fields.selectNlog = i; | |||
| 1493 | ||||
| 1494 | err = read_header(&cmd, buf, hdl, | |||
| 1495 | cdlog.u.entireDword, | |||
| 1496 | cfg.namespace_id); | |||
| 1497 | if (err) | |||
| 1498 | goto out; | |||
| 1499 | err = write_header(buf, output, sizeof(*intel_nlog)); | |||
| 1500 | if (err) | |||
| 1501 | goto out; | |||
| 1502 | if (cfg.verbose) | |||
| 1503 | print_intel_nlog(intel_nlog); | |||
| 1504 | cmd.cdw13 = 0x400; | |||
| 1505 | cmd.cdw10 = 0x400; | |||
| 1506 | cmd.data_len = min(0x1000, intel_nlog->nlogbytesize)({ typeof(0x1000) _a = (0x1000); typeof(intel_nlog->nlogbytesize ) _b = (intel_nlog->nlogbytesize); do { } while (0); _a < _b ? _a : _b; }); | |||
| 1507 | err = read_entire_cmd(&cmd, intel_nlog->nlogbytesize / 4, | |||
| 1508 | 0x400, output, | |||
| 1509 | hdl, | |||
| 1510 | buf); | |||
| 1511 | if (err) | |||
| 1512 | goto out; | |||
| 1513 | } else if (cfg.log == 1) { | |||
| 1514 | cmd.cdw13 = ehdr->edumps[j].coreoffset; | |||
| 1515 | cmd.cdw10 = 0x400; | |||
| 1516 | cmd.data_len = 0x400; | |||
| 1517 | err = read_entire_cmd(&cmd, ehdr->edumps[j].coresize, | |||
| 1518 | 0x400, output, | |||
| 1519 | hdl, | |||
| 1520 | buf); | |||
| 1521 | if (err) | |||
| 1522 | goto out; | |||
| 1523 | } | |||
| 1524 | } | |||
| 1525 | } | |||
| 1526 | err = 0; | |||
| 1527 | out: | |||
| 1528 | if (err) | |||
| 1529 | nvme_show_err(err, "intel log"); | |||
| 1530 | else | |||
| 1531 | nvme_show_verbose_result("Successfully wrote log to %s", cfg.file)nvme_show_verbose_message("Successfully wrote log to %s", cfg .file); | |||
| 1532 | close(output); | |||
| 1533 | out_free: | |||
| 1534 | return err; | |||
| 1535 | } | |||
| 1536 | ||||
| 1537 | static int enable_lat_stats_tracking(int argc, char **argv, | |||
| 1538 | struct command *command, struct plugin *plugin) | |||
| 1539 | { | |||
| 1540 | const char *desc = ( | |||
| 1541 | "Enable/Disable Intel Latency Statistics Tracking.\n" | |||
| 1542 | "No argument prints current status."); | |||
| 1543 | const char *enable_desc = "Enable LST"; | |||
| 1544 | const char *disable_desc = "Disable LST"; | |||
| 1545 | const __u32 nsid = 0; | |||
| 1546 | const __u8 fid = 0xe2; | |||
| 1547 | const __u8 sel = 0; | |||
| 1548 | const __u32 cdw11 = 0x0; | |||
| 1549 | const __u32 cdw12 = 0x0; | |||
| 1550 | const __u32 data_len = 32; | |||
| 1551 | const __u32 sv = 0; | |||
| 1552 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 1553 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 1554 | void *buf = NULL((void*)0); | |||
| 1555 | __u64 result; | |||
| 1556 | int err; | |||
| 1557 | ||||
| 1558 | struct config { | |||
| 1559 | bool_Bool enable, disable; | |||
| 1560 | }; | |||
| 1561 | ||||
| 1562 | struct config cfg = { | |||
| 1563 | .enable = false0, | |||
| 1564 | .disable = false0, | |||
| 1565 | }; | |||
| 1566 | ||||
| 1567 | struct argconfig_commandline_options opts[] = { | |||
| 1568 | {"enable", 'e', "", CFG_FLAG, &cfg.enable, no_argument0, enable_desc}, | |||
| 1569 | {"disable", 'd', "", CFG_FLAG, &cfg.disable, no_argument0, disable_desc}, | |||
| 1570 | {NULL((void*)0)} | |||
| 1571 | }; | |||
| 1572 | ||||
| 1573 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 1574 | ||||
| 1575 | enum Option { | |||
| 1576 | None = -1, | |||
| 1577 | True = 1, | |||
| 1578 | False = 0, | |||
| 1579 | }; | |||
| 1580 | ||||
| 1581 | enum Option option = None; | |||
| 1582 | ||||
| 1583 | if (cfg.enable && cfg.disable) | |||
| 1584 | nvme_show_error("Cannot enable and disable simultaneously.")nvme_show_message(1, "Cannot enable and disable simultaneously." ); | |||
| 1585 | else if (cfg.enable || cfg.disable) | |||
| 1586 | option = cfg.enable; | |||
| 1587 | ||||
| 1588 | if (err) | |||
| 1589 | return err; | |||
| 1590 | ||||
| 1591 | switch (option) { | |||
| 1592 | case None: | |||
| 1593 | err = nvme_get_features(hdl, nsid, fid, sel, cdw11, 0, buf, | |||
| 1594 | data_len, &result); | |||
| 1595 | if (!err) { | |||
| 1596 | printf( | |||
| 1597 | "Latency Statistics Tracking (FID 0x%X) is currently (%"PRIu64"l" "u"").\n", | |||
| 1598 | fid, (uint64_t)result); | |||
| 1599 | } else { | |||
| 1600 | nvme_show_error("Could not read feature id 0xE2.")nvme_show_message(1, "Could not read feature id 0xE2."); | |||
| 1601 | return err; | |||
| 1602 | } | |||
| 1603 | break; | |||
| 1604 | case True: | |||
| 1605 | case False: | |||
| 1606 | err = nvme_set_features(hdl, nsid, fid, sv, option, cdw12, 0, 0, 0, buf, | |||
| 1607 | data_len, &result); | |||
| 1608 | if (err) { | |||
| 1609 | nvme_show_err(err, "Enable latency tracking"); | |||
| 1610 | } else { | |||
| 1611 | nvme_show_verbose_result("Successfully set enable bit for FID (0x%X) to %i.",nvme_show_verbose_message("Successfully set enable bit for FID (0x%X) to %i." , fid, option) | |||
| 1612 | fid, option)nvme_show_verbose_message("Successfully set enable bit for FID (0x%X) to %i." , fid, option); | |||
| 1613 | } | |||
| 1614 | break; | |||
| 1615 | default: | |||
| 1616 | nvme_show_error("%d not supported.", option)nvme_show_message(1, "%d not supported.", option); | |||
| 1617 | return -EINVAL22; | |||
| 1618 | } | |||
| 1619 | return err; | |||
| 1620 | } | |||
| 1621 | ||||
| 1622 | static int set_lat_stats_thresholds(int argc, char **argv, | |||
| 1623 | struct command *command, struct plugin *plugin) | |||
| 1624 | { | |||
| 1625 | const char *desc = "Write Intel Bucket Thresholds for Latency Statistics Tracking"; | |||
| 1626 | const char *bucket_thresholds = "Bucket Threshold List, comma separated list: 0, 10, 20 ..."; | |||
| 1627 | const char *write = "Set write bucket Thresholds for latency tracking (read default)"; | |||
| 1628 | ||||
| 1629 | const __u32 nsid = 0; | |||
| 1630 | const __u8 fid = 0xf7; | |||
| 1631 | const __u32 cdw12 = 0x0; | |||
| 1632 | const __u32 sv = 0; | |||
| 1633 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 1634 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 1635 | __u64 result; | |||
| 1636 | int err, num; | |||
| 1637 | ||||
| 1638 | struct config { | |||
| 1639 | bool_Bool write; | |||
| 1640 | char *bucket_thresholds; | |||
| 1641 | }; | |||
| 1642 | ||||
| 1643 | struct config cfg = { | |||
| 1644 | .write = false0, | |||
| 1645 | .bucket_thresholds = "", | |||
| 1646 | }; | |||
| 1647 | ||||
| 1648 | NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; 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, }, {"bucket-thresholds", 't', "LIST", CFG_STRING, &cfg.bucket_thresholds, 1, bucket_thresholds, 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, }, {"quiet" , 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary", 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}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } } | |||
| 1649 | OPT_FLAG("write", 'w', &cfg.write, write),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; 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, }, {"bucket-thresholds", 't', "LIST", CFG_STRING, &cfg.bucket_thresholds, 1, bucket_thresholds, 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, }, {"quiet" , 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary", 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}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } } | |||
| 1650 | OPT_LIST("bucket-thresholds", 't', &cfg.bucket_thresholds,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; 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, }, {"bucket-thresholds", 't', "LIST", CFG_STRING, &cfg.bucket_thresholds, 1, bucket_thresholds, 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, }, {"quiet" , 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary", 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}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } } | |||
| 1651 | bucket_thresholds))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; 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, }, {"bucket-thresholds", 't', "LIST", CFG_STRING, &cfg.bucket_thresholds, 1, bucket_thresholds, 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, }, {"quiet" , 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary", 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}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } }; | |||
| 1652 | ||||
| 1653 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 1654 | ||||
| 1655 | if (err) | |||
| 1656 | return err; | |||
| 1657 | ||||
| 1658 | /* Query maj and minor version first to figure out the amount of | |||
| 1659 | * valid buckets a user is allowed to modify. Read or write doesn't | |||
| 1660 | * matter | |||
| 1661 | */ | |||
| 1662 | err = nvme_get_log_simple(hdl, 0xc2, | |||
| 1663 | media_version, sizeof(media_version)); | |||
| 1664 | if (err) { | |||
| 1665 | nvme_show_error("Querying media version failed. ")nvme_show_message(1, "Querying media version failed. "); | |||
| 1666 | nvme_show_status(err); | |||
| 1667 | goto close_dev; | |||
| 1668 | } | |||
| 1669 | ||||
| 1670 | if (media_version[0] == 1000) { | |||
| 1671 | int thresholds[OPTANE_V1000_BUCKET_LEN8] = {0}; | |||
| 1672 | ||||
| 1673 | num = shr_parse_csv_int(cfg.bucket_thresholds, | |||
| 1674 | thresholds, | |||
| 1675 | sizeof(thresholds)); | |||
| 1676 | if (num == -1) { | |||
| 1677 | nvme_show_error("ERROR: Bucket list is malformed")nvme_show_message(1, "ERROR: Bucket list is malformed"); | |||
| 1678 | goto close_dev; | |||
| 1679 | ||||
| 1680 | } | |||
| 1681 | ||||
| 1682 | err = nvme_set_features(hdl, nsid, fid, sv, cfg.write ? 0x1 : 0x0, cdw12, | |||
| 1683 | 0, 0, 0, thresholds, sizeof(thresholds), &result); | |||
| 1684 | ||||
| 1685 | if (err) | |||
| 1686 | nvme_show_err(err, "Enable latency tracking"); | |||
| 1687 | } else { | |||
| 1688 | nvme_show_error("Unsupported command")nvme_show_message(1, "Unsupported command"); | |||
| 1689 | } | |||
| 1690 | ||||
| 1691 | close_dev: | |||
| 1692 | return err; | |||
| 1693 | } | |||
| 1694 | ||||
| 1695 | static struct command id_ctrl_cmd = { | |||
| 1696 | .name = "id-ctrl", | |||
| 1697 | .help = "Send NVMe Identify Controller", | |||
| 1698 | .fn = id_ctrl, | |||
| 1699 | }; | |||
| 1700 | ||||
| 1701 | static struct command get_internal_log_cmd = { | |||
| 1702 | .name = "internal-log", | |||
| 1703 | .help = "Retrieve Intel internal firmware log, save it", | |||
| 1704 | .fn = get_internal_log, | |||
| 1705 | }; | |||
| 1706 | ||||
| 1707 | static struct command get_lat_stats_log_cmd = { | |||
| 1708 | .name = "lat-stats", | |||
| 1709 | .help = "Retrieve Intel IO Latency Statistics log, show it", | |||
| 1710 | .fn = get_lat_stats_log, | |||
| 1711 | }; | |||
| 1712 | ||||
| 1713 | static struct command set_lat_stats_thresholds_cmd = { | |||
| 1714 | .name = "set-bucket-thresholds", | |||
| 1715 | .help = "Set Latency Stats Bucket Values, save it", | |||
| 1716 | .fn = set_lat_stats_thresholds, | |||
| 1717 | }; | |||
| 1718 | ||||
| 1719 | static struct command enable_lat_stats_tracking_cmd = { | |||
| 1720 | .name = "lat-stats-tracking", | |||
| 1721 | .help = "Enable and disable Latency Statistics logging.", | |||
| 1722 | .fn = enable_lat_stats_tracking, | |||
| 1723 | }; | |||
| 1724 | ||||
| 1725 | static struct command get_market_log_cmd = { | |||
| 1726 | .name = "market-name", | |||
| 1727 | .help = "Retrieve Intel Marketing Name log, show it", | |||
| 1728 | .fn = get_market_log, | |||
| 1729 | }; | |||
| 1730 | ||||
| 1731 | static struct command get_additional_smart_log_cmd = { | |||
| 1732 | .name = "smart-log-add", | |||
| 1733 | .help = "Retrieve Intel SMART Log, show it", | |||
| 1734 | .fn = get_additional_smart_log, | |||
| 1735 | }; | |||
| 1736 | ||||
| 1737 | static struct command get_temp_stats_log_cmd = { | |||
| 1738 | .name = "temp-stats", | |||
| 1739 | .help = "Retrieve Intel Temperature Statistics log, show it", | |||
| 1740 | .fn = get_temp_stats_log, | |||
| 1741 | }; | |||
| 1742 | ||||
| 1743 | static struct command *commands[] = { | |||
| 1744 | &id_ctrl_cmd, | |||
| 1745 | &get_internal_log_cmd, | |||
| 1746 | &get_lat_stats_log_cmd, | |||
| 1747 | &set_lat_stats_thresholds_cmd, | |||
| 1748 | &enable_lat_stats_tracking_cmd, | |||
| 1749 | &get_market_log_cmd, | |||
| 1750 | &get_additional_smart_log_cmd, | |||
| 1751 | &get_temp_stats_log_cmd, | |||
| 1752 | NULL((void*)0), | |||
| 1753 | }; | |||
| 1754 | ||||
| 1755 | static struct plugin plugin = { | |||
| 1756 | .name = "intel", | |||
| 1757 | .desc = "Intel vendor specific extensions", | |||
| 1758 | .version = NVME_VERSION"3.1", | |||
| 1759 | }; | |||
| 1760 | ||||
| 1761 | static void __shr_constructor__attribute__((constructor)) register_plugin(void) | |||
| 1762 | { | |||
| 1763 | plugin_add_group(&plugin, NULL((void*)0), commands); | |||
| 1764 | register_extension(&plugin); | |||
| 1765 | } | |||
| 1766 |