|
1 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 2 | +#include <errno.h> |
| 3 | +#include <fcntl.h> |
2 | 4 | #include "nvme.h" |
3 | 5 | #include "plugin.h" |
4 | 6 | #include "nvme-print.h" |
5 | 7 |
|
6 | 8 | #define CREATE_CMD |
7 | 9 | #include "feat-nvme.h" |
8 | 10 |
|
| 11 | +struct perfc_config { |
| 12 | + __u32 namespace_id; |
| 13 | + __u8 attri; |
| 14 | + bool rvspa; |
| 15 | + __u8 r4karl; |
| 16 | + char *paid; |
| 17 | + __u16 attrl; |
| 18 | + char *vs_data; |
| 19 | + bool save; |
| 20 | + __u8 sel; |
| 21 | +}; |
| 22 | + |
9 | 23 | static const char *power_mgmt_feat = "power management feature"; |
10 | 24 | static const char *sel = "[0-3]: current/default/saved/supported"; |
11 | 25 | static const char *save = "Specifies that the controller shall save the attribute"; |
| 26 | +static const char *perfc_feat = "performance characteristics feature"; |
12 | 27 |
|
13 | 28 | static int power_mgmt_get(struct nvme_dev *dev, const __u8 fid, __u8 sel) |
14 | 29 | { |
@@ -106,3 +121,140 @@ static int feat_power_mgmt(int argc, char **argv, struct command *cmd, struct pl |
106 | 121 |
|
107 | 122 | return err; |
108 | 123 | } |
| 124 | + |
| 125 | +static int perfc_get(struct nvme_dev *dev, struct perfc_config *cfg) |
| 126 | +{ |
| 127 | + __u32 result; |
| 128 | + int err; |
| 129 | + |
| 130 | + struct nvme_get_features_args args = { |
| 131 | + .args_size = sizeof(args), |
| 132 | + .fd = dev_fd(dev), |
| 133 | + .fid = NVME_FEAT_FID_PERF_CHARACTERISTICS, |
| 134 | + .cdw11 = NVME_SET(cfg->attri, FEAT_PERFC_ATTRI) | |
| 135 | + NVME_SET(cfg->rvspa, FEAT_PERFC_RVSPA), |
| 136 | + .sel = cfg->sel, |
| 137 | + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, |
| 138 | + .result = &result, |
| 139 | + }; |
| 140 | + |
| 141 | + err = nvme_get_features(&args); |
| 142 | + if (!err) { |
| 143 | + if (NVME_CHECK(args.sel, GET_FEATURES_SEL, SUPPORTED)) |
| 144 | + nvme_show_select_result(args.fid, result); |
| 145 | + else |
| 146 | + nvme_feature_show_fields(args.fid, result, NULL); |
| 147 | + } else { |
| 148 | + nvme_show_error("Get %s", perfc_feat); |
| 149 | + } |
| 150 | + |
| 151 | + return err; |
| 152 | +} |
| 153 | + |
| 154 | +static int perfc_set(struct nvme_dev *dev, struct perfc_config *cfg) |
| 155 | +{ |
| 156 | + __u32 result; |
| 157 | + int err; |
| 158 | + |
| 159 | + _cleanup_fd_ int ffd = STDIN_FILENO; |
| 160 | + |
| 161 | + struct nvme_perf_characteristics data = { |
| 162 | + .attr_buf = { 0 }, |
| 163 | + }; |
| 164 | + |
| 165 | + struct nvme_set_features_args args = { |
| 166 | + .args_size = sizeof(args), |
| 167 | + .fd = dev_fd(dev), |
| 168 | + .fid = NVME_FEAT_FID_PERF_CHARACTERISTICS, |
| 169 | + .cdw11 = NVME_SET(cfg->attri, FEAT_PERFC_ATTRI) | |
| 170 | + NVME_SET(cfg->rvspa, FEAT_PERFC_RVSPA), |
| 171 | + .save = save, |
| 172 | + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, |
| 173 | + .result = &result, |
| 174 | + .data = &data, |
| 175 | + .data_len = sizeof(data), |
| 176 | + }; |
| 177 | + |
| 178 | + switch (cfg->attri) { |
| 179 | + case NVME_FEAT_PERFC_ATTRI_STD: |
| 180 | + data.std_perf->r4karl = cfg->r4karl; |
| 181 | + break; |
| 182 | + case NVME_FEAT_PERFC_ATTRI_VS_MIN ... NVME_FEAT_PERFC_ATTRI_VS_MAX: |
| 183 | + nvme_uuid_from_string(cfg->paid, data.vs_perf->paid); |
| 184 | + data.vs_perf->attrl = cfg->attrl; |
| 185 | + if (data.vs_perf->attrl && strlen(cfg->vs_data)) { |
| 186 | + ffd = open(cfg->vs_data, O_RDONLY); |
| 187 | + if (ffd < 0) { |
| 188 | + nvme_show_error("Failed to open file %s: %s", cfg->vs_data, |
| 189 | + strerror(errno)); |
| 190 | + return -EINVAL; |
| 191 | + } |
| 192 | + err = read(ffd, data.vs_perf->vs, data.vs_perf->attrl); |
| 193 | + if (err < 0) { |
| 194 | + nvme_show_error("failed to read data buffer from input file: %s", |
| 195 | + strerror(errno)); |
| 196 | + return -errno; |
| 197 | + } |
| 198 | + } |
| 199 | + break; |
| 200 | + default: |
| 201 | + break; |
| 202 | + } |
| 203 | + |
| 204 | + err = nvme_set_features(&args); |
| 205 | + |
| 206 | + nvme_show_init(); |
| 207 | + |
| 208 | + if (err > 0) { |
| 209 | + nvme_show_status(err); |
| 210 | + } else if (err < 0) { |
| 211 | + nvme_show_perror("Set %s", perfc_feat); |
| 212 | + } else { |
| 213 | + nvme_show_result("Set %s: 0x%04x (%s)", perfc_feat, args.cdw11, |
| 214 | + save ? "Save" : "Not save"); |
| 215 | + nvme_feature_show_fields(args.fid, args.cdw11, NULL); |
| 216 | + } |
| 217 | + |
| 218 | + nvme_show_finish(); |
| 219 | + |
| 220 | + return err; |
| 221 | +} |
| 222 | + |
| 223 | +static int feat_perfc(int argc, char **argv, struct command *cmd, struct plugin *plugin) |
| 224 | +{ |
| 225 | + const char *namespace_id_optional = "optional namespace attached to controller"; |
| 226 | + const char *attri = "attribute index"; |
| 227 | + const char *rvspa = "revert vendor specific performance attribute"; |
| 228 | + const char *r4karl = "random 4 kib average read latency"; |
| 229 | + const char *paid = "performance attribute identifier"; |
| 230 | + const char *attrl = "attribute length"; |
| 231 | + const char *vs_data = "vendor specific data"; |
| 232 | + |
| 233 | + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; |
| 234 | + int err; |
| 235 | + |
| 236 | + struct perfc_config cfg = { 0 }; |
| 237 | + |
| 238 | + NVME_ARGS(opts, |
| 239 | + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_optional), |
| 240 | + OPT_BYTE("attri", 'a', &cfg.attri, attri), |
| 241 | + OPT_FLAG("rvspa", 'r', &cfg.rvspa, rvspa), |
| 242 | + OPT_BYTE("r4karl", 'R', &cfg.r4karl, r4karl), |
| 243 | + OPT_STR("paid", 'p', &cfg.paid, paid), |
| 244 | + OPT_SHRT("attrl", 'A', &cfg.attrl, attrl), |
| 245 | + OPT_FILE("vs-data", 'V', &cfg.vs_data, vs_data), |
| 246 | + OPT_FLAG("save", 's', &cfg.save, save), |
| 247 | + OPT_BYTE("sel", 'S', &cfg.sel, sel)); |
| 248 | + |
| 249 | + err = parse_and_open(&dev, argc, argv, PERFC_DESC, opts); |
| 250 | + if (err) |
| 251 | + return err; |
| 252 | + |
| 253 | + if (argconfig_parse_seen(opts, "rvspa") || argconfig_parse_seen(opts, "r4karl") || |
| 254 | + argconfig_parse_seen(opts, "paid")) |
| 255 | + err = perfc_set(dev, &cfg); |
| 256 | + else |
| 257 | + err = perfc_get(dev, &cfg); |
| 258 | + |
| 259 | + return err; |
| 260 | +} |
0 commit comments