| File: | .build-ci/../src/nvme-cmds-io.c |
| Warning: | line 1224, column 11 Potential leak of memory pointed to by 'mbuffer' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | |||
| 2 | /* | |||
| 3 | * NVM-Express command line utility. | |||
| 4 | * | |||
| 5 | * Copyright (c) 2014-2015, Intel Corporation. | |||
| 6 | * | |||
| 7 | * Written by Keith Busch <kbusch@kernel.org> | |||
| 8 | */ | |||
| 9 | ||||
| 10 | /** | |||
| 11 | * This program uses NVMe IOCTLs to run native nvme commands to a device. | |||
| 12 | */ | |||
| 13 | #include <dirent.h> | |||
| 14 | #include <errno(*__errno_location ()).h> | |||
| 15 | #include <fcntl.h> | |||
| 16 | #include <inttypes.h> | |||
| 17 | #include <libgen.h> | |||
| 18 | #include <locale.h> | |||
| 19 | #include <math.h> | |||
| 20 | #include <signal.h> | |||
| 21 | #include <stdint.h> | |||
| 22 | #include <stdio.h> | |||
| 23 | #include <stdlib.h> | |||
| 24 | #include <string.h> | |||
| 25 | #include <unistd.h> | |||
| 26 | ||||
| 27 | #include <sys/stat.h> | |||
| 28 | #include <sys/types.h> | |||
| 29 | ||||
| 30 | #include <libnvme-mi.h> | |||
| 31 | #include <libnvme.h> | |||
| 32 | ||||
| 33 | #include <ccan/array_size/array_size.h> | |||
| 34 | #include <ccan/endian/endian.h> | |||
| 35 | #include <ccan/minmax/minmax.h> | |||
| 36 | #include <shared/compiler-attributes-util.h> | |||
| 37 | #include <shared/fs-util.h> | |||
| 38 | #include <shared/mmio-util.h> | |||
| 39 | #include <shared/parse-util.h> | |||
| 40 | #include <shared/sig-util.h> | |||
| 41 | #include <shared/suffix-util.h> | |||
| 42 | #include <shared/time-util.h> | |||
| 43 | ||||
| 44 | #include "argconfig.h" | |||
| 45 | #include "cleanup.h" | |||
| 46 | #include "global-ctx.h" | |||
| 47 | #include "nvme-errno.h" | |||
| 48 | #include "nvme-print.h" | |||
| 49 | #include "plugin.h" | |||
| 50 | ||||
| 51 | static const char *app_tag = "app tag for end-to-end PI"; | |||
| 52 | static const char *app_tag_mask = "app tag mask for end-to-end PI"; | |||
| 53 | static const char *block_count = "number of blocks (zeroes based) on device to access"; | |||
| 54 | static const char *dspec_w_dtype = "directive specification associated with directive type"; | |||
| 55 | static const char *dtype = "directive type"; | |||
| 56 | static const char *force_unit_access = "force device to commit data before command completes"; | |||
| 57 | static const char *latency = "output latency statistics"; | |||
| 58 | static const char *limited_retry = "limit media access attempts"; | |||
| 59 | static const char *namespace_desired = "desired namespace"; | |||
| 60 | static const char *prinfo = "PI and check field"; | |||
| 61 | static const char *ref_tag = "reference tag for end-to-end PI"; | |||
| 62 | static const char *start_block = "64-bit LBA of first block to access"; | |||
| 63 | static const char *storage_tag = "storage tag for end-to-end PI"; | |||
| 64 | static const char *storage_tag_check = "This bit specifies if the Storage Tag field shall be checked as\n" | |||
| 65 | "part of end-to-end data protection processing"; | |||
| 66 | static const char *ish = "Ignore Shutdown (for NVMe-MI command)"; | |||
| 67 | ||||
| 68 | static int open_fallback_chardev(struct libnvme_global_ctx *ctx, | |||
| 69 | __u32 nsid, | |||
| 70 | struct libnvme_transport_handle **phdl) | |||
| 71 | { | |||
| 72 | struct libnvme_transport_handle *hdl = *phdl; | |||
| 73 | int err; | |||
| 74 | ||||
| 75 | if (libnvme_transport_handle_is_ctrl(hdl)) { | |||
| 76 | __cleanup_free__attribute__((cleanup(shr_freep))) char *cdev = NULL((void*)0); | |||
| 77 | ||||
| 78 | if (!nsid) { | |||
| 79 | nvme_show_error("controller device not supported without --namespace-id")nvme_show_message(1, "controller device not supported without --namespace-id" ); | |||
| 80 | return -EINVAL22; | |||
| 81 | } | |||
| 82 | ||||
| 83 | if (asprintf(&cdev, "/dev/%sn%d", | |||
| 84 | libnvme_transport_handle_get_name(hdl), nsid) < 0) | |||
| 85 | return -ENOMEM12; | |||
| 86 | ||||
| 87 | libnvme_close(hdl); | |||
| 88 | ||||
| 89 | err = libnvme_open(ctx, cdev, O_RDONLY00, &hdl); | |||
| 90 | if (err) { | |||
| 91 | *phdl = NULL((void*)0); | |||
| 92 | ||||
| 93 | nvme_show_error("could not open %s", cdev)nvme_show_message(1, "could not open %s", cdev); | |||
| 94 | return err; | |||
| 95 | } | |||
| 96 | ||||
| 97 | *phdl = hdl; | |||
| 98 | } | |||
| 99 | ||||
| 100 | return 0; | |||
| 101 | } | |||
| 102 | ||||
| 103 | static int write_uncor(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 104 | { | |||
| 105 | const char *desc = | |||
| 106 | "The Write Uncorrectable command is used to set a range of logical blocks to invalid."; | |||
| 107 | ||||
| 108 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 109 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 110 | struct libnvme_passthru_cmd cmd; | |||
| 111 | int err; | |||
| 112 | ||||
| 113 | struct config { | |||
| 114 | __u32 namespace_id; | |||
| 115 | __u64 start_block; | |||
| 116 | __u16 block_count; | |||
| 117 | __u8 dtype; | |||
| 118 | __u16 dspec; | |||
| 119 | }; | |||
| 120 | ||||
| 121 | struct config cfg = { | |||
| 122 | .namespace_id = 0, | |||
| 123 | .start_block = 0, | |||
| 124 | .block_count = 0, | |||
| 125 | .dtype = 0, | |||
| 126 | .dspec = 0, | |||
| 127 | }; | |||
| 128 | ||||
| 129 | OPT_ARGS(opts)struct argconfig_commandline_options opts[] = { | |||
| 130 | OPT_UINT("namespace-id", 'n', &cfg.namespace_id,{"namespace-id", 'n', "NUM", CFG_POSITIVE, _Generic(&cfg. namespace_id, uint32_t * : (&cfg.namespace_id)), ARGCONFIG_ARG_REQUIRED , namespace_desired, 0, nvme_nsid_values} | |||
| 131 | namespace_desired, nvme_nsid_values){"namespace-id", 'n', "NUM", CFG_POSITIVE, _Generic(&cfg. namespace_id, uint32_t * : (&cfg.namespace_id)), ARGCONFIG_ARG_REQUIRED , namespace_desired, 0, nvme_nsid_values}, | |||
| 132 | OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block){"start-block", 's', "IONUM", CFG_LONG_SUFFIX, _Generic(& cfg.start_block, uint64_t * : (&cfg.start_block), default : _Generic(&cfg.start_block, unsigned long long * : (& cfg.start_block), default : (void)0)), ARGCONFIG_ARG_REQUIRED , start_block, 0, }, | |||
| 133 | OPT_SHRT("block-count", 'c', &cfg.block_count, block_count){"block-count", 'c', "NUM", CFG_SHORT, _Generic(&cfg.block_count , uint16_t * : (&cfg.block_count)), ARGCONFIG_ARG_REQUIRED , block_count, 0, }, | |||
| 134 | OPT_BYTE("dir-type", 'T', &cfg.dtype, dtype){"dir-type", 'T', "NUM", CFG_BYTE, _Generic(&cfg.dtype, uint8_t * : (&cfg.dtype)), ARGCONFIG_ARG_REQUIRED, dtype, 0, }, | |||
| 135 | OPT_SHRT("dir-spec", 'S', &cfg.dspec, dspec_w_dtype){"dir-spec", 'S', "NUM", CFG_SHORT, _Generic(&cfg.dspec, uint16_t * : (&cfg.dspec)), ARGCONFIG_ARG_REQUIRED, dspec_w_dtype , 0, }, | |||
| 136 | OPT_END(){ ((void*)0) } | |||
| 137 | }; | |||
| 138 | ||||
| 139 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 140 | if (err) | |||
| 141 | return err; | |||
| 142 | ||||
| 143 | if (!cfg.namespace_id) { | |||
| 144 | err = libnvme_get_nsid(hdl, &cfg.namespace_id); | |||
| 145 | if (err < 0) { | |||
| 146 | nvme_show_error("get-namespace-id: %s", libnvme_strerror(-err))nvme_show_message(1, "get-namespace-id: %s", libnvme_strerror (-err)); | |||
| 147 | return err; | |||
| 148 | } | |||
| 149 | } | |||
| 150 | ||||
| 151 | if (cfg.dtype > 0xf) { | |||
| 152 | nvme_show_error("Invalid directive type, %x", cfg.dtype)nvme_show_message(1, "Invalid directive type, %x", cfg.dtype); | |||
| 153 | return -EINVAL22; | |||
| 154 | } | |||
| 155 | ||||
| 156 | nvme_init_write_uncorrectable(&cmd, cfg.namespace_id, cfg.start_block, | |||
| 157 | cfg.block_count, cfg.dtype << 4, cfg.dspec); | |||
| 158 | err = libnvme_exec_io_passthru(hdl, &cmd); | |||
| 159 | if (err) { | |||
| 160 | nvme_show_err(err, "write uncorrectable"); | |||
| 161 | return err; | |||
| 162 | } | |||
| 163 | ||||
| 164 | nvme_show_verbose_result("NVME Write Uncorrectable Success")nvme_show_verbose_message("NVME Write Uncorrectable Success"); | |||
| 165 | ||||
| 166 | return err; | |||
| 167 | } | |||
| 168 | ||||
| 169 | static int invalid_tags(__u64 storage_tag, __u64 ref_tag, __u8 sts, __u8 pif) | |||
| 170 | { | |||
| 171 | if (sts < 64 && storage_tag >= (1ULL << sts)) { | |||
| 172 | nvme_show_error("Storage tag larger than the STS-defined %u-bit width", sts)nvme_show_message(1, "Storage tag larger than the STS-defined %u-bit width" , sts); | |||
| 173 | return -ECLI_INVALID_TAGS; | |||
| 174 | } | |||
| 175 | ||||
| 176 | switch (pif) { | |||
| 177 | case NVME_NVM_PIF_16B_GUARD: | |||
| 178 | if (sts > 32) { | |||
| 179 | nvme_show_error("Storage tag size (STS=%u) larger than the 32-bit maximum allowed by 16b Guard PIF",nvme_show_message(1, "Storage tag size (STS=%u) larger than the 32-bit maximum allowed by 16b Guard PIF" , sts) | |||
| 180 | sts)nvme_show_message(1, "Storage tag size (STS=%u) larger than the 32-bit maximum allowed by 16b Guard PIF" , sts); | |||
| 181 | return -ECLI_INVALID_TAGS; | |||
| 182 | } | |||
| 183 | if (ref_tag >= (1ULL << (32 - sts))) { | |||
| 184 | nvme_show_error("Reference tag larger than the %u-bit width allowed by 16b Guard PIF (STS=%u)",nvme_show_message(1, "Reference tag larger than the %u-bit width allowed by 16b Guard PIF (STS=%u)" , 32 - sts, sts) | |||
| 185 | 32 - sts, sts)nvme_show_message(1, "Reference tag larger than the %u-bit width allowed by 16b Guard PIF (STS=%u)" , 32 - sts, sts); | |||
| 186 | return -ECLI_INVALID_TAGS; | |||
| 187 | } | |||
| 188 | break; | |||
| 189 | case NVME_NVM_PIF_32B_GUARD: | |||
| 190 | if (sts < 16 || sts > 64) { | |||
| 191 | nvme_show_error("Storage tag size (STS=%u) outside the 16-64 range allowed by 32b Guard PIF",nvme_show_message(1, "Storage tag size (STS=%u) outside the 16-64 range allowed by 32b Guard PIF" , sts) | |||
| 192 | sts)nvme_show_message(1, "Storage tag size (STS=%u) outside the 16-64 range allowed by 32b Guard PIF" , sts); | |||
| 193 | return -ECLI_INVALID_TAGS; | |||
| 194 | } | |||
| 195 | if (sts > 16 && ref_tag >= (1ULL << (80 - sts))) { | |||
| 196 | nvme_show_error("Reference tag larger than the %u-bit width allowed by 32b Guard PIF (STS=%u)",nvme_show_message(1, "Reference tag larger than the %u-bit width allowed by 32b Guard PIF (STS=%u)" , 80 - sts, sts) | |||
| 197 | 80 - sts, sts)nvme_show_message(1, "Reference tag larger than the %u-bit width allowed by 32b Guard PIF (STS=%u)" , 80 - sts, sts); | |||
| 198 | return -ECLI_INVALID_TAGS; | |||
| 199 | } | |||
| 200 | break; | |||
| 201 | case NVME_NVM_PIF_64B_GUARD: | |||
| 202 | if (sts > 48) { | |||
| 203 | nvme_show_error("Storage tag size (STS=%u) larger than the 48-bit maximum allowed by 64b Guard PIF",nvme_show_message(1, "Storage tag size (STS=%u) larger than the 48-bit maximum allowed by 64b Guard PIF" , sts) | |||
| 204 | sts)nvme_show_message(1, "Storage tag size (STS=%u) larger than the 48-bit maximum allowed by 64b Guard PIF" , sts); | |||
| 205 | return -ECLI_INVALID_TAGS; | |||
| 206 | } | |||
| 207 | if (sts > 0 && ref_tag >= (1ULL << (48 - sts))) { | |||
| 208 | nvme_show_error("Reference tag larger than the %u-bit width allowed by 64b Guard PIF (STS=%u)",nvme_show_message(1, "Reference tag larger than the %u-bit width allowed by 64b Guard PIF (STS=%u)" , 48 - sts, sts) | |||
| 209 | 48 - sts, sts)nvme_show_message(1, "Reference tag larger than the %u-bit width allowed by 64b Guard PIF (STS=%u)" , 48 - sts, sts); | |||
| 210 | return -ECLI_INVALID_TAGS; | |||
| 211 | } | |||
| 212 | break; | |||
| 213 | default: | |||
| 214 | nvme_show_error("Invalid PIF value: %u", pif)nvme_show_message(1, "Invalid PIF value: %u", pif); | |||
| 215 | return -ECLI_INVALID_TAGS; | |||
| 216 | } | |||
| 217 | ||||
| 218 | return 0; | |||
| 219 | } | |||
| 220 | ||||
| 221 | static int check_lbstm_byte_granularity(__u64 lbstm, __u8 sts) | |||
| 222 | { | |||
| 223 | __u8 nr_full_bytes = sts / 8; | |||
| 224 | __u8 nr_rem_bits = sts % 8; | |||
| 225 | __u8 rem_mask, byte; | |||
| 226 | __u8 i; | |||
| 227 | ||||
| 228 | if (sts > 64) | |||
| 229 | return -EINVAL22; | |||
| 230 | ||||
| 231 | if (sts < 64) | |||
| 232 | lbstm &= (1ULL << sts) - 1; | |||
| 233 | ||||
| 234 | for (i = 0; i < nr_full_bytes; i++) { | |||
| 235 | byte = (lbstm >> (i * 8)) & 0xff; | |||
| 236 | if (byte != 0x00 && byte != 0xff) | |||
| 237 | return -EINVAL22; | |||
| 238 | } | |||
| 239 | ||||
| 240 | if (nr_rem_bits) { | |||
| 241 | rem_mask = (1u << nr_rem_bits) - 1; | |||
| 242 | byte = (lbstm >> (nr_full_bytes * 8)) & rem_mask; | |||
| 243 | if (byte != 0x00 && byte != rem_mask) | |||
| 244 | return -EINVAL22; | |||
| 245 | } | |||
| 246 | ||||
| 247 | return 0; | |||
| 248 | } | |||
| 249 | ||||
| 250 | static int check_lbstm_masking_not_supported(__u64 lbstm, __u8 sts) | |||
| 251 | { | |||
| 252 | __u64 stm_mask; | |||
| 253 | ||||
| 254 | if (sts > 64) | |||
| 255 | return -EINVAL22; | |||
| 256 | ||||
| 257 | stm_mask = (sts < 64) ? ((1ULL << sts) - 1) : ~0ULL; | |||
| 258 | if ((lbstm & stm_mask) != stm_mask) | |||
| 259 | return -EINVAL22; | |||
| 260 | ||||
| 261 | return 0; | |||
| 262 | } | |||
| 263 | ||||
| 264 | static int get_pif_sts_via_qpif(struct nvme_nvm_id_ns *nvm_ns, __u32 elbaf, | |||
| 265 | __u8 sts, __u8 *pif) | |||
| 266 | { | |||
| 267 | __u64 lbstm; | |||
| 268 | int err = 0; | |||
| 269 | ||||
| 270 | *pif = NVME_NVM_ELBAF_QPIF(elbaf)(((elbaf) >> NVME_NVM_ELBAF_QPIF_SHIFT) & NVME_NVM_ELBAF_QPIF_MASK ); | |||
| 271 | ||||
| 272 | lbstm = le64_to_cpu(nvm_ns->lbstm); | |||
| 273 | switch (NVME_NVM_PIFA_STMLA(nvm_ns->pifa)(((nvm_ns->pifa) >> NVME_NVM_PIFA_STMLA_SHIFT) & NVME_NVM_PIFA_STMLA_MASK)) { | |||
| 274 | case NVME_NVM_PIFA_BIT_GRANULARITY_MASKING: | |||
| 275 | break; | |||
| 276 | case NVME_NVM_PIFA_BYTE_GRANULARITY_MASKING: | |||
| 277 | err = check_lbstm_byte_granularity(lbstm, sts); | |||
| 278 | break; | |||
| 279 | case NVME_NVM_PIFA_MASKING_NOT_SUPPORTED: | |||
| 280 | err = check_lbstm_masking_not_supported(lbstm, sts); | |||
| 281 | break; | |||
| 282 | default: | |||
| 283 | err = -EINVAL22; | |||
| 284 | break; | |||
| 285 | } | |||
| 286 | ||||
| 287 | if (!err) | |||
| 288 | return 0; | |||
| 289 | ||||
| 290 | nvme_show_error("Logical Block Storage Tag Mask is inconsistent with the Storage Tag Masking Level Attribute")nvme_show_message(1, "Logical Block Storage Tag Mask is inconsistent with the Storage Tag Masking Level Attribute" ); | |||
| 291 | ||||
| 292 | return -ECLI_INVALID_PI_FORMAT; | |||
| 293 | } | |||
| 294 | ||||
| 295 | static int get_pif_sts(struct nvme_id_ns *ns, struct nvme_nvm_id_ns *nvm_ns, | |||
| 296 | __u8 *pif, __u8 *sts) | |||
| 297 | { | |||
| 298 | __u8 lba_index; | |||
| 299 | __u32 elbaf; | |||
| 300 | ||||
| 301 | nvme_id_ns_flbas_to_lbaf_inuse(ns->flbas, &lba_index); | |||
| 302 | elbaf = le32_to_cpu(nvm_ns->elbaf[lba_index]); | |||
| 303 | *sts = NVME_NVM_ELBAF_STS(elbaf)(((elbaf) >> NVME_NVM_ELBAF_STS_SHIFT) & NVME_NVM_ELBAF_STS_MASK ); | |||
| 304 | *pif = NVME_NVM_ELBAF_PIF(elbaf)(((elbaf) >> NVME_NVM_ELBAF_PIF_SHIFT) & NVME_NVM_ELBAF_PIF_MASK ); | |||
| 305 | ||||
| 306 | if (*pif == NVME_NVM_PIF_QTYPE && NVME_NVM_PIC_QPIFS(nvm_ns->pic)(((nvm_ns->pic) >> NVME_NVM_PIC_QPIFS_SHIFT) & NVME_NVM_PIC_QPIFS_MASK )) | |||
| 307 | return get_pif_sts_via_qpif(nvm_ns, elbaf, *sts, pif); | |||
| 308 | ||||
| 309 | return 0; | |||
| 310 | } | |||
| 311 | ||||
| 312 | static int get_pi_info(struct libnvme_transport_handle *hdl, | |||
| 313 | __u32 nsid, __u8 prinfo, __u64 ilbrt, __u64 lbst, | |||
| 314 | unsigned int *logical_block_size, __u16 *metadata_size) | |||
| 315 | { | |||
| 316 | __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) struct nvme_nvm_id_ns *nvm_ns = NULL((void*)0); | |||
| 317 | __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) struct nvme_id_ns *ns = NULL((void*)0); | |||
| 318 | struct libnvme_passthru_cmd cmd; | |||
| 319 | __u8 sts = 0, pif = 0; | |||
| 320 | unsigned int lbs = 0; | |||
| 321 | __u8 lba_index; | |||
| 322 | int pi_size; | |||
| 323 | __u16 ms; | |||
| 324 | int err; | |||
| 325 | ||||
| 326 | ns = libnvme_alloc(sizeof(*ns)); | |||
| 327 | if (!ns) | |||
| 328 | return -ENOMEM12; | |||
| 329 | ||||
| 330 | nvme_init_identify_ns(&cmd, nsid, ns); | |||
| 331 | err = libnvme_exec_admin_passthru(hdl, &cmd); | |||
| 332 | if (err) { | |||
| 333 | nvme_show_err(err, "identify namespace"); | |||
| 334 | return -ECLI_IDENTIFY_NS_FAILED; | |||
| 335 | } | |||
| 336 | ||||
| 337 | nvme_id_ns_flbas_to_lbaf_inuse(ns->flbas, &lba_index); | |||
| 338 | if (ns->lbaf[lba_index].ds >= 32) { | |||
| 339 | nvme_show_error("invalid LBA data size %u",nvme_show_message(1, "invalid LBA data size %u", ns->lbaf[ lba_index].ds) | |||
| 340 | ns->lbaf[lba_index].ds)nvme_show_message(1, "invalid LBA data size %u", ns->lbaf[ lba_index].ds); | |||
| 341 | return -ECLI_INVALID_LBA_FORMAT; | |||
| 342 | } | |||
| 343 | lbs = 1U << ns->lbaf[lba_index].ds; | |||
| 344 | ms = le16_to_cpu(ns->lbaf[lba_index].ms); | |||
| 345 | /* | |||
| 346 | * Conservative fallback: if Identify NVM CS NS below fails for any | |||
| 347 | * reason other than Invalid Field, we return early with PI simply | |||
| 348 | * unavailable, and this is the size submit_io() will use. For an | |||
| 349 | * extended-LBA namespace the metadata is always part of the | |||
| 350 | * transfer, so publish the full size now; the PRACT exception below | |||
| 351 | * can only shrink it once PI info actually comes back. | |||
| 352 | */ | |||
| 353 | *logical_block_size = lbs + (NVME_FLBAS_META_EXT(ns->flbas)(((ns->flbas) >> NVME_FLBAS_META_EXT_SHIFT) & NVME_FLBAS_META_EXT_MASK ) ? ms : 0); | |||
| 354 | *metadata_size = ms; | |||
| 355 | ||||
| 356 | nvm_ns = libnvme_alloc(sizeof(*nvm_ns)); | |||
| 357 | if (!nvm_ns) | |||
| 358 | return -ENOMEM12; | |||
| 359 | ||||
| 360 | nvme_init_identify_csi_ns(&cmd, nsid, NVME_CSI_NVM, 0, nvm_ns); | |||
| 361 | err = libnvme_exec_admin_passthru(hdl, &cmd); | |||
| 362 | if (!err) { | |||
| 363 | err = get_pif_sts(ns, nvm_ns, &pif, &sts); | |||
| 364 | if (err) | |||
| 365 | return err; | |||
| 366 | } else if (!nvme_status_equals(err, NVME_STATUS_TYPE_NVME, | |||
| 367 | NVME_SC_INVALID_FIELD)) { | |||
| 368 | return err; | |||
| 369 | } | |||
| 370 | ||||
| 371 | pi_size = (pif == NVME_NVM_PIF_16B_GUARD) ? 8 : 16; | |||
| 372 | if (NVME_FLBAS_META_EXT(ns->flbas)(((ns->flbas) >> NVME_FLBAS_META_EXT_SHIFT) & NVME_FLBAS_META_EXT_MASK )) { | |||
| 373 | /* | |||
| 374 | * No meta data is transferred for PRACT=1 and MD=PI size: | |||
| 375 | * 5.2.2.1 Protection Information and Write Commands | |||
| 376 | * 5.2.2.2 Protection Information and Read Commands | |||
| 377 | */ | |||
| 378 | if (!((prinfo & 0x8) != 0 && ms == pi_size)) | |||
| 379 | lbs += ms; | |||
| 380 | } | |||
| 381 | ||||
| 382 | err = invalid_tags(lbst, ilbrt, sts, pif); | |||
| 383 | if (err) | |||
| 384 | return err; | |||
| 385 | ||||
| 386 | *logical_block_size = lbs; | |||
| 387 | *metadata_size = ms; | |||
| 388 | ||||
| 389 | return 0; | |||
| 390 | } | |||
| 391 | ||||
| 392 | static int init_pi_tags(struct libnvme_transport_handle *hdl, | |||
| 393 | struct libnvme_passthru_cmd *cmd, __u32 nsid, __u64 ilbrt, __u64 lbst, | |||
| 394 | __u16 lbat, __u16 lbatm) | |||
| 395 | { | |||
| 396 | __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) struct nvme_nvm_id_ns *nvm_ns = NULL((void*)0); | |||
| 397 | __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) struct nvme_id_ns *ns = NULL((void*)0); | |||
| 398 | struct libnvme_passthru_cmd id_cmd; | |||
| 399 | __u8 sts = 0, pif = 0; | |||
| 400 | int err = 0; | |||
| 401 | ||||
| 402 | ns = libnvme_alloc(sizeof(*ns)); | |||
| 403 | if (!ns) | |||
| 404 | return -ENOMEM12; | |||
| 405 | ||||
| 406 | nvme_init_identify_ns(&id_cmd, nsid, ns); | |||
| 407 | err = libnvme_exec_admin_passthru(hdl, &id_cmd); | |||
| 408 | if (err) { | |||
| 409 | nvme_show_err(err, "identify namespace"); | |||
| 410 | return err; | |||
| 411 | } | |||
| 412 | ||||
| 413 | nvm_ns = libnvme_alloc(sizeof(*nvm_ns)); | |||
| 414 | if (!nvm_ns) | |||
| 415 | return -ENOMEM12; | |||
| 416 | ||||
| 417 | nvme_init_identify_csi_ns(&id_cmd, nsid, NVME_CSI_NVM, 0, nvm_ns); | |||
| 418 | err = libnvme_exec_admin_passthru(hdl, &id_cmd); | |||
| 419 | if (!err) { | |||
| 420 | err = get_pif_sts(ns, nvm_ns, &pif, &sts); | |||
| 421 | if (err) | |||
| 422 | return err; | |||
| 423 | } else if (nvme_status_get_type(err) != NVME_STATUS_TYPE_NVME || | |||
| 424 | nvme_status_code(nvme_status_get_value(err)) != NVME_SC_INVALID_FIELD) { | |||
| 425 | return err; | |||
| 426 | } | |||
| 427 | ||||
| 428 | err = invalid_tags(lbst, ilbrt, sts, pif); | |||
| 429 | if (err) | |||
| 430 | return err; | |||
| 431 | ||||
| 432 | nvme_init_var_size_tags(cmd, pif, sts, ilbrt, lbst); | |||
| 433 | nvme_init_app_tag(cmd, lbat, lbatm); | |||
| 434 | ||||
| 435 | return 0; | |||
| 436 | } | |||
| 437 | ||||
| 438 | static int write_zeroes(int argc, char **argv, | |||
| 439 | struct command *acmd, struct plugin *plugin) | |||
| 440 | { | |||
| 441 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 442 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 443 | struct libnvme_passthru_cmd cmd; | |||
| 444 | __u16 control = 0; | |||
| 445 | int err; | |||
| 446 | ||||
| 447 | const char *desc = | |||
| 448 | "The Write Zeroes command is used to set a range of logical blocks to zero."; | |||
| 449 | const char *deac = | |||
| 450 | "Set DEAC bit, requesting controller to deallocate specified logical blocks"; | |||
| 451 | const char *nsz = "Clear all logical blocks to zero in the entire namespace"; | |||
| 452 | ||||
| 453 | struct config { | |||
| 454 | __u32 nsid; | |||
| 455 | __u64 start_block; | |||
| 456 | __u16 block_count; | |||
| 457 | __u8 dtype; | |||
| 458 | bool_Bool deac; | |||
| 459 | bool_Bool limited_retry; | |||
| 460 | bool_Bool force_unit_access; | |||
| 461 | __u8 prinfo; | |||
| 462 | __u64 ilbrt; | |||
| 463 | __u16 lbatm; | |||
| 464 | __u16 lbat; | |||
| 465 | __u64 lbst; | |||
| 466 | bool_Bool stc; | |||
| 467 | __u16 dspec; | |||
| 468 | bool_Bool nsz; | |||
| 469 | }; | |||
| 470 | ||||
| 471 | struct config cfg = { | |||
| 472 | .nsid = 0, | |||
| 473 | .start_block = 0, | |||
| 474 | .block_count = 0, | |||
| 475 | .dtype = 0, | |||
| 476 | .deac = false0, | |||
| 477 | .limited_retry = false0, | |||
| 478 | .force_unit_access = false0, | |||
| 479 | .prinfo = 0, | |||
| 480 | .ilbrt = 0, | |||
| 481 | .lbatm = 0, | |||
| 482 | .lbat = 0, | |||
| 483 | .lbst = 0, | |||
| 484 | .stc = false0, | |||
| 485 | .dspec = 0, | |||
| 486 | .nsz = false0, | |||
| 487 | }; | |||
| 488 | ||||
| 489 | OPT_ARGS(opts)struct argconfig_commandline_options opts[] = { | |||
| 490 | OPT_UINT("namespace-id", 'n', &cfg.nsid, namespace_desired,{"namespace-id", 'n', "NUM", CFG_POSITIVE, _Generic(&cfg. nsid, uint32_t * : (&cfg.nsid)), ARGCONFIG_ARG_REQUIRED, namespace_desired , 0, nvme_nsid_values} | |||
| 491 | nvme_nsid_values){"namespace-id", 'n', "NUM", CFG_POSITIVE, _Generic(&cfg. nsid, uint32_t * : (&cfg.nsid)), ARGCONFIG_ARG_REQUIRED, namespace_desired , 0, nvme_nsid_values}, | |||
| 492 | OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block){"start-block", 's', "IONUM", CFG_LONG_SUFFIX, _Generic(& cfg.start_block, uint64_t * : (&cfg.start_block), default : _Generic(&cfg.start_block, unsigned long long * : (& cfg.start_block), default : (void)0)), ARGCONFIG_ARG_REQUIRED , start_block, 0, }, | |||
| 493 | OPT_SHRT("block-count", 'c', &cfg.block_count, block_count){"block-count", 'c', "NUM", CFG_SHORT, _Generic(&cfg.block_count , uint16_t * : (&cfg.block_count)), ARGCONFIG_ARG_REQUIRED , block_count, 0, }, | |||
| 494 | OPT_BYTE("dir-type", 'T', &cfg.dtype, dtype){"dir-type", 'T', "NUM", CFG_BYTE, _Generic(&cfg.dtype, uint8_t * : (&cfg.dtype)), ARGCONFIG_ARG_REQUIRED, dtype, 0, }, | |||
| 495 | OPT_FLAG("deac", 'd', &cfg.deac, deac){"deac", 'd', ((void*)0), CFG_FLAG, _Generic(&cfg.deac, _Bool * : (&cfg.deac)), ARGCONFIG_ARG_NONE, deac, 0, }, | |||
| 496 | OPT_FLAG("limited-retry", 'l', &cfg.limited_retry,{"limited-retry", 'l', ((void*)0), CFG_FLAG, _Generic(&cfg .limited_retry, _Bool * : (&cfg.limited_retry)), ARGCONFIG_ARG_NONE , limited_retry, 0, } | |||
| 497 | limited_retry){"limited-retry", 'l', ((void*)0), CFG_FLAG, _Generic(&cfg .limited_retry, _Bool * : (&cfg.limited_retry)), ARGCONFIG_ARG_NONE , limited_retry, 0, }, | |||
| 498 | OPT_FLAG("force-unit-access", 'f', &cfg.force_unit_access,{"force-unit-access", 'f', ((void*)0), CFG_FLAG, _Generic(& cfg.force_unit_access, _Bool * : (&cfg.force_unit_access) ), ARGCONFIG_ARG_NONE, force_unit_access, 0, } | |||
| 499 | force_unit_access){"force-unit-access", 'f', ((void*)0), CFG_FLAG, _Generic(& cfg.force_unit_access, _Bool * : (&cfg.force_unit_access) ), ARGCONFIG_ARG_NONE, force_unit_access, 0, }, | |||
| 500 | OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo){"prinfo", 'p', "NUM", CFG_BYTE, _Generic(&cfg.prinfo, uint8_t * : (&cfg.prinfo)), ARGCONFIG_ARG_REQUIRED, prinfo, 0, }, | |||
| 501 | OPT_SUFFIX("ref-tag", 'r', &cfg.ilbrt, ref_tag){"ref-tag", 'r', "IONUM", CFG_LONG_SUFFIX, _Generic(&cfg. ilbrt, uint64_t * : (&cfg.ilbrt), default : _Generic(& cfg.ilbrt, unsigned long long * : (&cfg.ilbrt), default : (void)0)), ARGCONFIG_ARG_REQUIRED, ref_tag, 0, }, | |||
| 502 | OPT_SHRT("app-tag-mask", 'm', &cfg.lbatm, app_tag_mask){"app-tag-mask", 'm', "NUM", CFG_SHORT, _Generic(&cfg.lbatm , uint16_t * : (&cfg.lbatm)), ARGCONFIG_ARG_REQUIRED, app_tag_mask , 0, }, | |||
| 503 | OPT_SHRT("app-tag", 'a', &cfg.lbat, app_tag){"app-tag", 'a', "NUM", CFG_SHORT, _Generic(&cfg.lbat, uint16_t * : (&cfg.lbat)), ARGCONFIG_ARG_REQUIRED, app_tag, 0, }, | |||
| 504 | OPT_SUFFIX("storage-tag", 'S', &cfg.lbst, storage_tag){"storage-tag", 'S', "IONUM", CFG_LONG_SUFFIX, _Generic(& cfg.lbst, uint64_t * : (&cfg.lbst), default : _Generic(& cfg.lbst, unsigned long long * : (&cfg.lbst), default : ( void)0)), ARGCONFIG_ARG_REQUIRED, storage_tag, 0, }, | |||
| 505 | OPT_FLAG("storage-tag-check", 'C', &cfg.stc, storage_tag_check){"storage-tag-check", 'C', ((void*)0), CFG_FLAG, _Generic(& cfg.stc, _Bool * : (&cfg.stc)), ARGCONFIG_ARG_NONE, storage_tag_check , 0, }, | |||
| 506 | OPT_SHRT("dir-spec", 'D', &cfg.dspec, dspec_w_dtype){"dir-spec", 'D', "NUM", CFG_SHORT, _Generic(&cfg.dspec, uint16_t * : (&cfg.dspec)), ARGCONFIG_ARG_REQUIRED, dspec_w_dtype , 0, }, | |||
| 507 | OPT_FLAG("namespace-zeroes", 'Z', &cfg.nsz, nsz){"namespace-zeroes", 'Z', ((void*)0), CFG_FLAG, _Generic(& cfg.nsz, _Bool * : (&cfg.nsz)), ARGCONFIG_ARG_NONE, nsz, 0 , }, | |||
| 508 | OPT_END(){ ((void*)0) } | |||
| 509 | }; | |||
| 510 | ||||
| 511 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 512 | if (err) | |||
| 513 | return err; | |||
| 514 | ||||
| 515 | if (cfg.prinfo > 0xf) | |||
| 516 | return -EINVAL22; | |||
| 517 | ||||
| 518 | if (cfg.dtype > 0x7) { | |||
| 519 | nvme_show_error("Invalid directive type, %x", cfg.dtype)nvme_show_message(1, "Invalid directive type, %x", cfg.dtype); | |||
| 520 | return -EINVAL22; | |||
| 521 | } | |||
| 522 | ||||
| 523 | control |= (cfg.prinfo << 10); | |||
| 524 | if (cfg.limited_retry) | |||
| 525 | control |= NVME_IO_LR; | |||
| 526 | if (cfg.force_unit_access) | |||
| 527 | control |= NVME_IO_FUA; | |||
| 528 | if (cfg.deac) | |||
| 529 | control |= NVME_IO_DEAC; | |||
| 530 | if (cfg.stc) | |||
| 531 | control |= NVME_IO_STC; | |||
| 532 | if (cfg.nsz) | |||
| 533 | control |= NVME_IO_NSZ; | |||
| 534 | control |= (cfg.dtype << 4); | |||
| 535 | if (!cfg.nsid) { | |||
| 536 | err = libnvme_get_nsid(hdl, &cfg.nsid); | |||
| 537 | if (err < 0) { | |||
| 538 | nvme_show_error("get-namespace-id: %s", libnvme_strerror(-err))nvme_show_message(1, "get-namespace-id: %s", libnvme_strerror (-err)); | |||
| 539 | return err; | |||
| 540 | } | |||
| 541 | } | |||
| 542 | ||||
| 543 | nvme_init_write_zeros(&cmd, cfg.nsid, cfg.start_block, cfg.block_count, | |||
| 544 | control, cfg.dspec, 0, 0); | |||
| 545 | ||||
| 546 | err = init_pi_tags(hdl, &cmd, cfg.nsid, cfg.ilbrt, cfg.lbst, cfg.lbat, | |||
| 547 | cfg.lbatm); | |||
| 548 | if (err) | |||
| 549 | return err; | |||
| 550 | ||||
| 551 | err = libnvme_exec_io_passthru(hdl, &cmd); | |||
| 552 | if (err) { | |||
| 553 | nvme_show_err(err, "write-zeroes"); | |||
| 554 | return err; | |||
| 555 | } | |||
| 556 | ||||
| 557 | nvme_show_verbose_result("NVME Write Zeroes Success")nvme_show_verbose_message("NVME Write Zeroes Success"); | |||
| 558 | ||||
| 559 | if (!cfg.nsz || !nvme_args.verbose) | |||
| 560 | return err; | |||
| 561 | ||||
| 562 | if (cmd.result & 0x1) | |||
| 563 | nvme_show_result(nvme_show_message(0, "All logical blocks in the entire namespace cleared to zero" ) | |||
| 564 | "All logical blocks in the entire namespace cleared to zero")nvme_show_message(0, "All logical blocks in the entire namespace cleared to zero" ); | |||
| 565 | else | |||
| 566 | nvme_show_result("%d logical blocks cleared to zero", cfg.block_count)nvme_show_message(0, "%d logical blocks cleared to zero", cfg .block_count); | |||
| 567 | ||||
| 568 | return err; | |||
| 569 | } | |||
| 570 | ||||
| 571 | static int dsm(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 572 | { | |||
| 573 | const char *desc = "The Dataset Management command is used by the host to\n" | |||
| 574 | "indicate attributes for ranges of logical blocks. This includes attributes\n" | |||
| 575 | "for discarding unused blocks, data read and write frequency, access size, and other\n" | |||
| 576 | "information that may be used to optimize performance and reliability."; | |||
| 577 | const char *blocks = "Comma separated list of the number of blocks in each range"; | |||
| 578 | const char *starting_blocks = "Comma separated list of the starting block in each range"; | |||
| 579 | const char *context_attrs = "Comma separated list of the context attributes in each range"; | |||
| 580 | const char *ad = "Attribute Deallocate"; | |||
| 581 | const char *idw = "Attribute Integral Dataset for Write"; | |||
| 582 | const char *idr = "Attribute Integral Dataset for Read"; | |||
| 583 | const char *cdw11 = "All the command DWORD 11 attributes. Use instead of specifying individual attributes"; | |||
| 584 | ||||
| 585 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 586 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 587 | __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) struct nvme_dsm_range *dsm = NULL((void*)0); | |||
| 588 | struct libnvme_passthru_cmd cmd; | |||
| 589 | __u32 ctx_attrs[NVME_DSM_MAX_RANGES] = {0,}; | |||
| 590 | __u32 nlbs[NVME_DSM_MAX_RANGES] = {0,}; | |||
| 591 | __u64 slbas[NVME_DSM_MAX_RANGES] = {0,}; | |||
| 592 | uint16_t nc, nb, ns; | |||
| 593 | int err; | |||
| 594 | ||||
| 595 | struct config { | |||
| 596 | __u32 namespace_id; | |||
| 597 | char *ctx_attrs; | |||
| 598 | char *blocks; | |||
| 599 | char *slbas; | |||
| 600 | bool_Bool ad; | |||
| 601 | bool_Bool idw; | |||
| 602 | bool_Bool idr; | |||
| 603 | __u32 cdw11; | |||
| 604 | }; | |||
| 605 | ||||
| 606 | struct config cfg = { | |||
| 607 | .namespace_id = 0, | |||
| 608 | .ctx_attrs = "", | |||
| 609 | .blocks = "", | |||
| 610 | .slbas = "", | |||
| 611 | .ad = false0, | |||
| 612 | .idw = false0, | |||
| 613 | .idr = false0, | |||
| 614 | .cdw11 = 0, | |||
| 615 | }; | |||
| 616 | ||||
| 617 | OPT_ARGS(opts)struct argconfig_commandline_options opts[] = { | |||
| 618 | OPT_UINT("namespace-id", 'n', &cfg.namespace_id,{"namespace-id", 'n', "NUM", CFG_POSITIVE, _Generic(&cfg. namespace_id, uint32_t * : (&cfg.namespace_id)), ARGCONFIG_ARG_REQUIRED , namespace_id_desired, 0, nvme_nsid_values} | |||
| 619 | namespace_id_desired, nvme_nsid_values){"namespace-id", 'n', "NUM", CFG_POSITIVE, _Generic(&cfg. namespace_id, uint32_t * : (&cfg.namespace_id)), ARGCONFIG_ARG_REQUIRED , namespace_id_desired, 0, nvme_nsid_values}, | |||
| 620 | OPT_LIST("ctx-attrs", 'a', &cfg.ctx_attrs, context_attrs){"ctx-attrs", 'a', "LIST", CFG_STRING, _Generic(&cfg.ctx_attrs , char ** : (&cfg.ctx_attrs), const char ** : (&cfg.ctx_attrs )), ARGCONFIG_ARG_REQUIRED, context_attrs, 0, }, | |||
| 621 | OPT_LIST("blocks", 'b', &cfg.blocks, blocks){"blocks", 'b', "LIST", CFG_STRING, _Generic(&cfg.blocks, char ** : (&cfg.blocks), const char ** : (&cfg.blocks )), ARGCONFIG_ARG_REQUIRED, blocks, 0, }, | |||
| 622 | OPT_LIST("slbs", 's', &cfg.slbas, starting_blocks){"slbs", 's', "LIST", CFG_STRING, _Generic(&cfg.slbas, char ** : (&cfg.slbas), const char ** : (&cfg.slbas)), ARGCONFIG_ARG_REQUIRED , starting_blocks, 0, }, | |||
| 623 | OPT_FLAG("ad", 'd', &cfg.ad, ad){"ad", 'd', ((void*)0), CFG_FLAG, _Generic(&cfg.ad, _Bool * : (&cfg.ad)), ARGCONFIG_ARG_NONE, ad, 0, }, | |||
| 624 | OPT_FLAG("idw", 'w', &cfg.idw, idw){"idw", 'w', ((void*)0), CFG_FLAG, _Generic(&cfg.idw, _Bool * : (&cfg.idw)), ARGCONFIG_ARG_NONE, idw, 0, }, | |||
| 625 | OPT_FLAG("idr", 'r', &cfg.idr, idr){"idr", 'r', ((void*)0), CFG_FLAG, _Generic(&cfg.idr, _Bool * : (&cfg.idr)), ARGCONFIG_ARG_NONE, idr, 0, }, | |||
| 626 | OPT_UINT("cdw11", 'c', &cfg.cdw11, cdw11){"cdw11", 'c', "NUM", CFG_POSITIVE, _Generic(&cfg.cdw11, uint32_t * : (&cfg.cdw11)), ARGCONFIG_ARG_REQUIRED, cdw11, 0, }, | |||
| 627 | OPT_END(){ ((void*)0) } | |||
| 628 | }; | |||
| 629 | ||||
| 630 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 631 | if (err) | |||
| 632 | return err; | |||
| 633 | ||||
| 634 | err = open_fallback_chardev(ctx, cfg.namespace_id, &hdl); | |||
| 635 | if (err) | |||
| 636 | return err; | |||
| 637 | ||||
| 638 | nc = shr_parse_csv_u32(cfg.ctx_attrs, ctx_attrs, ARRAY_SIZE(ctx_attrs))shr_parse_csv_uint(cfg.ctx_attrs, (unsigned int *)(ctx_attrs) + (sizeof(char [1 - 2*!(sizeof(*(ctx_attrs)) == sizeof(unsigned int))]) - 1), (sizeof(ctx_attrs) / sizeof((ctx_attrs)[0]) + 0 )); | |||
| 639 | nb = shr_parse_csv_u32(cfg.blocks, nlbs, ARRAY_SIZE(nlbs))shr_parse_csv_uint(cfg.blocks, (unsigned int *)(nlbs) + (sizeof (char [1 - 2*!(sizeof(*(nlbs)) == sizeof(unsigned int))]) - 1 ), (sizeof(nlbs) / sizeof((nlbs)[0]) + 0)); | |||
| 640 | ns = shr_parse_csv_u64(cfg.slbas, slbas, ARRAY_SIZE(slbas))shr_parse_csv_ulonglong(cfg.slbas, (unsigned long long *)(slbas ) + (sizeof(char [1 - 2*!(sizeof(*(slbas)) == sizeof(unsigned long long))]) - 1), (sizeof(slbas) / sizeof((slbas)[0]) + 0) ); | |||
| 641 | if ((nb != ns) || | |||
| 642 | (argconfig_given(opts, &cfg.ctx_attrs) && nb != nc)) { | |||
| 643 | nvme_show_error("No valid range definition provided")nvme_show_message(1, "No valid range definition provided"); | |||
| 644 | return -EINVAL22; | |||
| 645 | } | |||
| 646 | if (!nb || nb > NVME_DSM_MAX_RANGES) { | |||
| 647 | nvme_show_error("No range definition provided")nvme_show_message(1, "No range definition provided"); | |||
| 648 | return -EINVAL22; | |||
| 649 | } | |||
| 650 | ||||
| 651 | if (!cfg.namespace_id) { | |||
| 652 | err = libnvme_get_nsid(hdl, &cfg.namespace_id); | |||
| 653 | if (err < 0) { | |||
| 654 | nvme_show_error("get-namespace-id: %s", libnvme_strerror(-err))nvme_show_message(1, "get-namespace-id: %s", libnvme_strerror (-err)); | |||
| 655 | return err; | |||
| 656 | } | |||
| 657 | } | |||
| 658 | if (cfg.cdw11) { | |||
| 659 | cfg.ad = NVME_GET(cfg.cdw11, DSM_CDW11_AD)(((cfg.cdw11) >> NVME_DSM_CDW11_AD_SHIFT) & NVME_DSM_CDW11_AD_MASK ); | |||
| 660 | cfg.idw = NVME_GET(cfg.cdw11, DSM_CDW11_IDW)(((cfg.cdw11) >> NVME_DSM_CDW11_IDW_SHIFT) & NVME_DSM_CDW11_IDW_MASK ); | |||
| 661 | cfg.idr = NVME_GET(cfg.cdw11, DSM_CDW11_IDR)(((cfg.cdw11) >> NVME_DSM_CDW11_IDR_SHIFT) & NVME_DSM_CDW11_IDR_MASK ); | |||
| 662 | } | |||
| 663 | ||||
| 664 | dsm = libnvme_alloc(sizeof(*dsm) * nb); | |||
| 665 | if (!dsm) | |||
| 666 | return -ENOMEM12; | |||
| 667 | ||||
| 668 | nvme_init_dsm_range(dsm, ctx_attrs, nlbs, slbas, nb); | |||
| 669 | nvme_init_dsm(&cmd, cfg.namespace_id, nb, cfg.idr, cfg.idw, cfg.ad, dsm, | |||
| 670 | sizeof(*dsm) * nb); | |||
| 671 | err = libnvme_exec_io_passthru(hdl, &cmd); | |||
| 672 | if (err) { | |||
| 673 | nvme_show_err(err, "data-set management"); | |||
| 674 | return err; | |||
| 675 | } | |||
| 676 | ||||
| 677 | nvme_show_verbose_result("NVMe DSM: success")nvme_show_verbose_message("NVMe DSM: success"); | |||
| 678 | ||||
| 679 | return err; | |||
| 680 | } | |||
| 681 | ||||
| 682 | static int copy_cmd(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 683 | { | |||
| 684 | const char *desc = "The Copy command is used by the host to copy data\n" | |||
| 685 | "from one or more source logical block ranges to a\n" | |||
| 686 | "single consecutive destination logical block range."; | |||
| 687 | const char *d_sdlba = "64-bit addr of first destination logical block"; | |||
| 688 | const char *d_slbas = "64-bit addr of first block per range (comma-separated list)"; | |||
| 689 | const char *d_nlbs = "number of blocks per range (comma-separated list, zeroes-based values)"; | |||
| 690 | const char *d_snsids = "source namespace identifier per range (comma-separated list)"; | |||
| 691 | const char *d_sopts = "source options per range (comma-separated list)"; | |||
| 692 | const char *d_lr = "limited retry"; | |||
| 693 | const char *d_fua = "force unit access"; | |||
| 694 | const char *d_prinfor = "protection information and check field (read part)"; | |||
| 695 | const char *d_prinfow = "protection information and check field (write part)"; | |||
| 696 | const char *d_ilbrt = "initial lba reference tag (write part)"; | |||
| 697 | const char *d_eilbrts = "expected lba reference tags (read part, comma-separated list)"; | |||
| 698 | const char *d_lbat = "lba application tag (write part)"; | |||
| 699 | const char *d_elbats = "expected lba application tags (read part, comma-separated list)"; | |||
| 700 | const char *d_lbatm = "lba application tag mask (write part)"; | |||
| 701 | const char *d_elbatms = "expected lba application tag masks (read part, comma-separated list)"; | |||
| 702 | const char *d_dtype = "directive type (write part)"; | |||
| 703 | const char *d_dspec = "directive specific (write part)"; | |||
| 704 | const char *d_format = "source range entry format"; | |||
| 705 | ||||
| 706 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 707 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 708 | __u16 nr, nb, ns, nrts, natms, nats, nids; | |||
| 709 | struct libnvme_passthru_cmd cmd; | |||
| 710 | __u16 nlbs[256] = { 0 }; | |||
| 711 | __u64 slbas[256] = { 0 }; | |||
| 712 | __u32 snsids[256] = { 0 }; | |||
| 713 | __u16 sopts[256] = { 0 }; | |||
| 714 | int err; | |||
| 715 | ||||
| 716 | union { | |||
| 717 | __u32 short_pi[256]; | |||
| 718 | __u64 long_pi[256]; | |||
| 719 | } eilbrts; | |||
| 720 | ||||
| 721 | __u16 elbatms[256] = { 0 }; | |||
| 722 | __u16 elbats[256] = { 0 }; | |||
| 723 | ||||
| 724 | __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) union { | |||
| 725 | struct nvme_copy_range_f0 f0[256]; | |||
| 726 | struct nvme_copy_range_f1 f1[256]; | |||
| 727 | struct nvme_copy_range_f2 f2[256]; | |||
| 728 | struct nvme_copy_range_f3 f3[256]; | |||
| 729 | } *copy = NULL((void*)0); | |||
| 730 | ||||
| 731 | struct config { | |||
| 732 | __u32 nsid; | |||
| 733 | __u64 sdlba; | |||
| 734 | char *slbas; | |||
| 735 | char *nlbs; | |||
| 736 | char *snsids; | |||
| 737 | char *sopts; | |||
| 738 | bool_Bool lr; | |||
| 739 | bool_Bool fua; | |||
| 740 | __u8 prinfow; | |||
| 741 | __u8 prinfor; | |||
| 742 | __u64 ilbrt; | |||
| 743 | char *eilbrts; | |||
| 744 | __u16 lbat; | |||
| 745 | char *elbats; | |||
| 746 | __u16 lbatm; | |||
| 747 | char *elbatms; | |||
| 748 | __u8 dtype; | |||
| 749 | __u16 dspec; | |||
| 750 | __u8 format; | |||
| 751 | __u64 lbst; | |||
| 752 | bool_Bool stc; | |||
| 753 | }; | |||
| 754 | ||||
| 755 | struct config cfg = { | |||
| 756 | .nsid = 0, | |||
| 757 | .sdlba = 0, | |||
| 758 | .slbas = "", | |||
| 759 | .nlbs = "", | |||
| 760 | .snsids = "", | |||
| 761 | .sopts = "", | |||
| 762 | .lr = false0, | |||
| 763 | .fua = false0, | |||
| 764 | .prinfow = 0, | |||
| 765 | .prinfor = 0, | |||
| 766 | .ilbrt = 0, | |||
| 767 | .eilbrts = "", | |||
| 768 | .lbat = 0, | |||
| 769 | .elbats = "", | |||
| 770 | .lbatm = 0, | |||
| 771 | .elbatms = "", | |||
| 772 | .dtype = 0, | |||
| 773 | .dspec = 0, | |||
| 774 | .format = 0, | |||
| 775 | .lbst = 0, | |||
| 776 | .stc = false0, | |||
| 777 | }; | |||
| 778 | ||||
| 779 | OPT_ARGS(opts)struct argconfig_commandline_options opts[] = { | |||
| 780 | OPT_UINT("namespace-id", 'n', &cfg.nsid, namespace_id_desired,{"namespace-id", 'n', "NUM", CFG_POSITIVE, _Generic(&cfg. nsid, uint32_t * : (&cfg.nsid)), ARGCONFIG_ARG_REQUIRED, namespace_id_desired , 0, nvme_nsid_values} | |||
| 781 | nvme_nsid_values){"namespace-id", 'n', "NUM", CFG_POSITIVE, _Generic(&cfg. nsid, uint32_t * : (&cfg.nsid)), ARGCONFIG_ARG_REQUIRED, namespace_id_desired , 0, nvme_nsid_values}, | |||
| 782 | OPT_SUFFIX("sdlba", 'd', &cfg.sdlba, d_sdlba){"sdlba", 'd', "IONUM", CFG_LONG_SUFFIX, _Generic(&cfg.sdlba , uint64_t * : (&cfg.sdlba), default : _Generic(&cfg. sdlba, unsigned long long * : (&cfg.sdlba), default : (void )0)), ARGCONFIG_ARG_REQUIRED, d_sdlba, 0, }, | |||
| 783 | OPT_LIST("slbs", 's', &cfg.slbas, d_slbas){"slbs", 's', "LIST", CFG_STRING, _Generic(&cfg.slbas, char ** : (&cfg.slbas), const char ** : (&cfg.slbas)), ARGCONFIG_ARG_REQUIRED , d_slbas, 0, }, | |||
| 784 | OPT_LIST("blocks", 'b', &cfg.nlbs, d_nlbs){"blocks", 'b', "LIST", CFG_STRING, _Generic(&cfg.nlbs, char ** : (&cfg.nlbs), const char ** : (&cfg.nlbs)), ARGCONFIG_ARG_REQUIRED , d_nlbs, 0, }, | |||
| 785 | OPT_LIST("snsids", 'N', &cfg.snsids, d_snsids){"snsids", 'N', "LIST", CFG_STRING, _Generic(&cfg.snsids, char ** : (&cfg.snsids), const char ** : (&cfg.snsids )), ARGCONFIG_ARG_REQUIRED, d_snsids, 0, }, | |||
| 786 | OPT_LIST("sopts", 'O', &cfg.sopts, d_sopts){"sopts", 'O', "LIST", CFG_STRING, _Generic(&cfg.sopts, char ** : (&cfg.sopts), const char ** : (&cfg.sopts)), ARGCONFIG_ARG_REQUIRED , d_sopts, 0, }, | |||
| 787 | OPT_FLAG("limited-retry", 'l', &cfg.lr, d_lr){"limited-retry", 'l', ((void*)0), CFG_FLAG, _Generic(&cfg .lr, _Bool * : (&cfg.lr)), ARGCONFIG_ARG_NONE, d_lr, 0, }, | |||
| 788 | OPT_FLAG("force-unit-access", 'f', &cfg.fua, d_fua){"force-unit-access", 'f', ((void*)0), CFG_FLAG, _Generic(& cfg.fua, _Bool * : (&cfg.fua)), ARGCONFIG_ARG_NONE, d_fua , 0, }, | |||
| 789 | OPT_BYTE("prinfow", 'p', &cfg.prinfow, d_prinfow){"prinfow", 'p', "NUM", CFG_BYTE, _Generic(&cfg.prinfow, uint8_t * : (&cfg.prinfow)), ARGCONFIG_ARG_REQUIRED, d_prinfow, 0 , }, | |||
| 790 | OPT_BYTE("prinfor", 'P', &cfg.prinfor, d_prinfor){"prinfor", 'P', "NUM", CFG_BYTE, _Generic(&cfg.prinfor, uint8_t * : (&cfg.prinfor)), ARGCONFIG_ARG_REQUIRED, d_prinfor, 0 , }, | |||
| 791 | OPT_SUFFIX("ref-tag", 'r', &cfg.ilbrt, d_ilbrt){"ref-tag", 'r', "IONUM", CFG_LONG_SUFFIX, _Generic(&cfg. ilbrt, uint64_t * : (&cfg.ilbrt), default : _Generic(& cfg.ilbrt, unsigned long long * : (&cfg.ilbrt), default : (void)0)), ARGCONFIG_ARG_REQUIRED, d_ilbrt, 0, }, | |||
| 792 | OPT_LIST("expected-ref-tags", 'R', &cfg.eilbrts, d_eilbrts){"expected-ref-tags", 'R', "LIST", CFG_STRING, _Generic(& cfg.eilbrts, char ** : (&cfg.eilbrts), const char ** : (& cfg.eilbrts)), ARGCONFIG_ARG_REQUIRED, d_eilbrts, 0, }, | |||
| 793 | OPT_SHRT("app-tag", 'a', &cfg.lbat, d_lbat){"app-tag", 'a', "NUM", CFG_SHORT, _Generic(&cfg.lbat, uint16_t * : (&cfg.lbat)), ARGCONFIG_ARG_REQUIRED, d_lbat, 0, }, | |||
| 794 | OPT_LIST("expected-app-tags", 'A', &cfg.elbats, d_elbats){"expected-app-tags", 'A', "LIST", CFG_STRING, _Generic(& cfg.elbats, char ** : (&cfg.elbats), const char ** : (& cfg.elbats)), ARGCONFIG_ARG_REQUIRED, d_elbats, 0, }, | |||
| 795 | OPT_SHRT("app-tag-mask", 'm', &cfg.lbatm, d_lbatm){"app-tag-mask", 'm', "NUM", CFG_SHORT, _Generic(&cfg.lbatm , uint16_t * : (&cfg.lbatm)), ARGCONFIG_ARG_REQUIRED, d_lbatm , 0, }, | |||
| 796 | OPT_LIST("expected-app-tag-masks", 'M', &cfg.elbatms,{"expected-app-tag-masks", 'M', "LIST", CFG_STRING, _Generic( &cfg.elbatms, char ** : (&cfg.elbatms), const char ** : (&cfg.elbatms)), ARGCONFIG_ARG_REQUIRED, d_elbatms, 0, } | |||
| 797 | d_elbatms){"expected-app-tag-masks", 'M', "LIST", CFG_STRING, _Generic( &cfg.elbatms, char ** : (&cfg.elbatms), const char ** : (&cfg.elbatms)), ARGCONFIG_ARG_REQUIRED, d_elbatms, 0, }, | |||
| 798 | OPT_BYTE("dir-type", 'T', &cfg.dtype, d_dtype){"dir-type", 'T', "NUM", CFG_BYTE, _Generic(&cfg.dtype, uint8_t * : (&cfg.dtype)), ARGCONFIG_ARG_REQUIRED, d_dtype, 0, }, | |||
| 799 | OPT_SHRT("dir-spec", 'S', &cfg.dspec, d_dspec){"dir-spec", 'S', "NUM", CFG_SHORT, _Generic(&cfg.dspec, uint16_t * : (&cfg.dspec)), ARGCONFIG_ARG_REQUIRED, d_dspec, 0, }, | |||
| 800 | OPT_BYTE("format", 'F', &cfg.format, d_format){"format", 'F', "NUM", CFG_BYTE, _Generic(&cfg.format, uint8_t * : (&cfg.format)), ARGCONFIG_ARG_REQUIRED, d_format, 0, }, | |||
| 801 | OPT_SUFFIX("storage-tag", 't', &cfg.lbst, storage_tag){"storage-tag", 't', "IONUM", CFG_LONG_SUFFIX, _Generic(& cfg.lbst, uint64_t * : (&cfg.lbst), default : _Generic(& cfg.lbst, unsigned long long * : (&cfg.lbst), default : ( void)0)), ARGCONFIG_ARG_REQUIRED, storage_tag, 0, }, | |||
| 802 | OPT_FLAG("storage-tag-check", 'c', &cfg.stc, storage_tag_check){"storage-tag-check", 'c', ((void*)0), CFG_FLAG, _Generic(& cfg.stc, _Bool * : (&cfg.stc)), ARGCONFIG_ARG_NONE, storage_tag_check , 0, }, | |||
| 803 | OPT_END(){ ((void*)0) } | |||
| 804 | }; | |||
| 805 | ||||
| 806 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 807 | if (err) | |||
| 808 | return err; | |||
| 809 | ||||
| 810 | nb = shr_parse_csv_u16(cfg.nlbs, nlbs, ARRAY_SIZE(nlbs))shr_parse_csv_ushort(cfg.nlbs, (unsigned short *)(nlbs) + (sizeof (char [1 - 2*!(sizeof(*(nlbs)) == sizeof(unsigned short))]) - 1), (sizeof(nlbs) / sizeof((nlbs)[0]) + 0)); | |||
| 811 | ns = shr_parse_csv_u64(cfg.slbas, slbas, ARRAY_SIZE(slbas))shr_parse_csv_ulonglong(cfg.slbas, (unsigned long long *)(slbas ) + (sizeof(char [1 - 2*!(sizeof(*(slbas)) == sizeof(unsigned long long))]) - 1), (sizeof(slbas) / sizeof((slbas)[0]) + 0) ); | |||
| 812 | nids = shr_parse_csv_u32(cfg.snsids, snsids, ARRAY_SIZE(snsids))shr_parse_csv_uint(cfg.snsids, (unsigned int *)(snsids) + (sizeof (char [1 - 2*!(sizeof(*(snsids)) == sizeof(unsigned int))]) - 1), (sizeof(snsids) / sizeof((snsids)[0]) + 0)); | |||
| 813 | shr_parse_csv_u16(cfg.sopts, sopts, ARRAY_SIZE(sopts))shr_parse_csv_ushort(cfg.sopts, (unsigned short *)(sopts) + ( sizeof(char [1 - 2*!(sizeof(*(sopts)) == sizeof(unsigned short ))]) - 1), (sizeof(sopts) / sizeof((sopts)[0]) + 0)); | |||
| 814 | ||||
| 815 | switch (cfg.format) { | |||
| 816 | case 0: | |||
| 817 | case 2: | |||
| 818 | nrts = shr_parse_csv_u32(cfg.eilbrts,shr_parse_csv_uint(cfg.eilbrts, (unsigned int *)(eilbrts.short_pi ) + (sizeof(char [1 - 2*!(sizeof(*(eilbrts.short_pi)) == sizeof (unsigned int))]) - 1), (sizeof(eilbrts.short_pi) / sizeof((eilbrts .short_pi)[0]) + 0)) | |||
| 819 | eilbrts.short_pi, ARRAY_SIZE(eilbrts.short_pi))shr_parse_csv_uint(cfg.eilbrts, (unsigned int *)(eilbrts.short_pi ) + (sizeof(char [1 - 2*!(sizeof(*(eilbrts.short_pi)) == sizeof (unsigned int))]) - 1), (sizeof(eilbrts.short_pi) / sizeof((eilbrts .short_pi)[0]) + 0)); | |||
| 820 | break; | |||
| 821 | case 1: | |||
| 822 | case 3: | |||
| 823 | nrts = shr_parse_csv_u64(cfg.eilbrts,shr_parse_csv_ulonglong(cfg.eilbrts, (unsigned long long *)(eilbrts .long_pi) + (sizeof(char [1 - 2*!(sizeof(*(eilbrts.long_pi)) == sizeof(unsigned long long))]) - 1), (sizeof(eilbrts.long_pi) / sizeof((eilbrts.long_pi)[0]) + 0)) | |||
| 824 | eilbrts.long_pi, ARRAY_SIZE(eilbrts.long_pi))shr_parse_csv_ulonglong(cfg.eilbrts, (unsigned long long *)(eilbrts .long_pi) + (sizeof(char [1 - 2*!(sizeof(*(eilbrts.long_pi)) == sizeof(unsigned long long))]) - 1), (sizeof(eilbrts.long_pi) / sizeof((eilbrts.long_pi)[0]) + 0)); | |||
| 825 | break; | |||
| 826 | default: | |||
| 827 | nvme_show_error("invalid format")nvme_show_message(1, "invalid format"); | |||
| 828 | return -EINVAL22; | |||
| 829 | } | |||
| 830 | ||||
| 831 | natms = shr_parse_csv_u16(cfg.elbatms, elbatms,shr_parse_csv_ushort(cfg.elbatms, (unsigned short *)(elbatms) + (sizeof(char [1 - 2*!(sizeof(*(elbatms)) == sizeof(unsigned short))]) - 1), (sizeof(elbatms) / sizeof((elbatms)[0]) + 0) ) | |||
| 832 | ARRAY_SIZE(elbatms))shr_parse_csv_ushort(cfg.elbatms, (unsigned short *)(elbatms) + (sizeof(char [1 - 2*!(sizeof(*(elbatms)) == sizeof(unsigned short))]) - 1), (sizeof(elbatms) / sizeof((elbatms)[0]) + 0) ); | |||
| 833 | nats = shr_parse_csv_u16(cfg.elbats, elbats,shr_parse_csv_ushort(cfg.elbats, (unsigned short *)(elbats) + (sizeof(char [1 - 2*!(sizeof(*(elbats)) == sizeof(unsigned short ))]) - 1), (sizeof(elbats) / sizeof((elbats)[0]) + 0)) | |||
| 834 | ARRAY_SIZE(elbats))shr_parse_csv_ushort(cfg.elbats, (unsigned short *)(elbats) + (sizeof(char [1 - 2*!(sizeof(*(elbats)) == sizeof(unsigned short ))]) - 1), (sizeof(elbats) / sizeof((elbats)[0]) + 0)); | |||
| 835 | ||||
| 836 | nr = max(nb, max(ns, max(nrts, max(natms, nats))))({ typeof(nb) _a = (nb); typeof(({ typeof(ns) _a = (ns); typeof (({ typeof(nrts) _a = (nrts); typeof(({ typeof(natms) _a = (natms ); typeof(nats) _b = (nats); do { } while (0); _a > _b ? _a : _b; })) _b = (({ typeof(natms) _a = (natms); typeof(nats) _b = (nats); do { } while (0); _a > _b ? _a : _b; })); do { } while (0); _a > _b ? _a : _b; })) _b = (({ typeof(nrts) _a = (nrts); typeof(({ typeof(natms) _a = (natms); typeof(nats) _b = (nats); do { } while (0); _a > _b ? _a : _b; })) _b = (({ typeof(natms) _a = (natms); typeof(nats) _b = (nats); do { } while (0); _a > _b ? _a : _b; })); do { } while (0); _a > _b ? _a : _b; })); do { } while (0); _a > _b ? _a : _b ; })) _b = (({ typeof(ns) _a = (ns); typeof(({ typeof(nrts) _a = (nrts); typeof(({ typeof(natms) _a = (natms); typeof(nats) _b = (nats); do { } while (0); _a > _b ? _a : _b; })) _b = (({ typeof(natms) _a = (natms); typeof(nats) _b = (nats); do { } while (0); _a > _b ? _a : _b; })); do { } while (0); _a > _b ? _a : _b; })) _b = (({ typeof(nrts) _a = (nrts); typeof (({ typeof(natms) _a = (natms); typeof(nats) _b = (nats); do { } while (0); _a > _b ? _a : _b; })) _b = (({ typeof(natms ) _a = (natms); typeof(nats) _b = (nats); do { } while (0); _a > _b ? _a : _b; })); do { } while (0); _a > _b ? _a : _b ; })); do { } while (0); _a > _b ? _a : _b; })); do { } while (0); _a > _b ? _a : _b; }); | |||
| 837 | if (cfg.format == 2 || cfg.format == 3) { | |||
| 838 | if (nr != nids) { | |||
| 839 | nvme_show_error("formats 2 and 3 require source namespace ids for each source range")nvme_show_message(1, "formats 2 and 3 require source namespace ids for each source range" ); | |||
| 840 | return -EINVAL22; | |||
| 841 | } | |||
| 842 | } else if (nids) { | |||
| 843 | nvme_show_error("formats 0 and 1 do not support cross-namespace copy")nvme_show_message(1, "formats 0 and 1 do not support cross-namespace copy" ); | |||
| 844 | return -EINVAL22; | |||
| 845 | } | |||
| 846 | if (!nr || nr > 256) { | |||
| 847 | nvme_show_error("invalid range")nvme_show_message(1, "invalid range"); | |||
| 848 | return -EINVAL22; | |||
| 849 | } | |||
| 850 | ||||
| 851 | if (!cfg.nsid) { | |||
| 852 | err = libnvme_get_nsid(hdl, &cfg.nsid); | |||
| 853 | if (err < 0) { | |||
| 854 | nvme_show_error("get-namespace-id: %s", libnvme_strerror(-err))nvme_show_message(1, "get-namespace-id: %s", libnvme_strerror (-err)); | |||
| 855 | return err; | |||
| 856 | } | |||
| 857 | } | |||
| 858 | ||||
| 859 | copy = libnvme_alloc(sizeof(*copy)); | |||
| 860 | if (!copy) | |||
| 861 | return -ENOMEM12; | |||
| 862 | ||||
| 863 | switch (cfg.format) { | |||
| 864 | case 1: | |||
| 865 | nvme_init_copy_range_f1(copy->f1, nlbs, slbas, eilbrts.long_pi, | |||
| 866 | elbatms, elbats, nr); | |||
| 867 | break; | |||
| 868 | case 2: | |||
| 869 | nvme_init_copy_range_f2(copy->f2, snsids, nlbs, slbas, sopts, | |||
| 870 | eilbrts.short_pi, elbatms, elbats, nr); | |||
| 871 | break; | |||
| 872 | case 3: | |||
| 873 | nvme_init_copy_range_f3(copy->f3, snsids, nlbs, slbas, sopts, | |||
| 874 | eilbrts.long_pi, elbatms, elbats, nr); | |||
| 875 | break; | |||
| 876 | default: | |||
| 877 | nvme_init_copy_range_f0(copy->f0, nlbs, slbas, eilbrts.short_pi, | |||
| 878 | elbatms, elbats, nr); | |||
| 879 | break; | |||
| 880 | } | |||
| 881 | ||||
| 882 | nvme_init_copy(&cmd, cfg.nsid, cfg.sdlba, nr, cfg.format, | |||
| 883 | cfg.prinfor, cfg.prinfow, 0, cfg.dtype, cfg.stc, cfg.stc, | |||
| 884 | cfg.fua, cfg.lr, 0, cfg.dspec, copy->f0); | |||
| 885 | err = init_pi_tags(hdl, &cmd, cfg.nsid, cfg.ilbrt, cfg.lbst, cfg.lbat, | |||
| 886 | cfg.lbatm); | |||
| 887 | if (err) | |||
| 888 | return err; | |||
| 889 | err = libnvme_exec_io_passthru(hdl, &cmd); | |||
| 890 | if (err) { | |||
| 891 | nvme_show_err(err, "NVMe Copy"); | |||
| 892 | return err; | |||
| 893 | } | |||
| 894 | ||||
| 895 | nvme_show_verbose_result("NVMe Copy: success")nvme_show_verbose_message("NVMe Copy: success"); | |||
| 896 | ||||
| 897 | return err; | |||
| 898 | } | |||
| 899 | ||||
| 900 | static int flush_cmd(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 901 | { | |||
| 902 | const char *desc = "Commit data and metadata associated with\n" | |||
| 903 | "given namespaces to nonvolatile media. Applies to all commands\n" | |||
| 904 | "finished before the flush was submitted. Additional data may also be\n" | |||
| 905 | "flushed by the controller, from any namespace, depending on controller and\n" | |||
| 906 | "associated namespace status."; | |||
| 907 | ||||
| 908 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 909 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 910 | struct libnvme_passthru_cmd cmd = {}; | |||
| 911 | int err; | |||
| 912 | ||||
| 913 | struct config { | |||
| 914 | __u32 namespace_id; | |||
| 915 | }; | |||
| 916 | ||||
| 917 | struct config cfg = { | |||
| 918 | .namespace_id = 0, | |||
| 919 | }; | |||
| 920 | ||||
| 921 | OPT_ARGS(opts)struct argconfig_commandline_options opts[] = { | |||
| 922 | OPT_UINT("namespace-id", 'n', &cfg.namespace_id,{"namespace-id", 'n', "NUM", CFG_POSITIVE, _Generic(&cfg. namespace_id, uint32_t * : (&cfg.namespace_id)), ARGCONFIG_ARG_REQUIRED , namespace_id_desired, 0, nvme_nsid_values} | |||
| 923 | namespace_id_desired, nvme_nsid_values){"namespace-id", 'n', "NUM", CFG_POSITIVE, _Generic(&cfg. namespace_id, uint32_t * : (&cfg.namespace_id)), ARGCONFIG_ARG_REQUIRED , namespace_id_desired, 0, nvme_nsid_values}, | |||
| 924 | OPT_END(){ ((void*)0) } | |||
| 925 | }; | |||
| 926 | ||||
| 927 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 928 | if (err) | |||
| 929 | return err; | |||
| 930 | ||||
| 931 | err = open_fallback_chardev(ctx, cfg.namespace_id, &hdl); | |||
| 932 | if (err) | |||
| 933 | return err; | |||
| 934 | ||||
| 935 | if (!cfg.namespace_id) { | |||
| 936 | err = libnvme_get_nsid(hdl, &cfg.namespace_id); | |||
| 937 | if (err < 0) { | |||
| 938 | nvme_show_error("get-namespace-id: %s", libnvme_strerror(-err))nvme_show_message(1, "get-namespace-id: %s", libnvme_strerror (-err)); | |||
| 939 | return err; | |||
| 940 | } | |||
| 941 | } | |||
| 942 | ||||
| 943 | cmd.opcode = nvme_cmd_flush; | |||
| 944 | cmd.nsid = cfg.namespace_id; | |||
| 945 | ||||
| 946 | err = libnvme_exec_io_passthru(hdl, &cmd); | |||
| 947 | if (err) { | |||
| 948 | nvme_show_err(err, "flush"); | |||
| 949 | return err; | |||
| 950 | } | |||
| 951 | ||||
| 952 | nvme_show_verbose_result("NVMe Flush: success")nvme_show_verbose_message("NVMe Flush: success"); | |||
| 953 | ||||
| 954 | return err; | |||
| 955 | } | |||
| 956 | ||||
| 957 | static int submit_io(int opcode, char *command, const char *desc, int argc, char **argv) | |||
| 958 | { | |||
| 959 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 960 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 961 | unsigned long long buffer_size = 0, mbuffer_size = 0; | |||
| 962 | __cleanup_free__attribute__((cleanup(shr_freep))) struct nvme_nvm_id_ns *nvm_ns = NULL((void*)0); | |||
| 963 | __cleanup_huge__attribute__((cleanup(libnvme_free_huge))) struct libnvme_mem_huge mh = { 0, }; | |||
| 964 | __cleanup_free__attribute__((cleanup(shr_freep))) struct nvme_id_ns *ns = NULL((void*)0); | |||
| 965 | unsigned int logical_block_size = 0; | |||
| 966 | struct timeval start_time, end_time; | |||
| 967 | __cleanup_free__attribute__((cleanup(shr_freep))) void *mbuffer = NULL((void*)0); | |||
| 968 | __cleanup_fd__attribute__((cleanup(shr_cleanup_fd))) int dfd = -1, mfd = -1; | |||
| 969 | __u16 control = 0, nblocks = 0; | |||
| 970 | struct libnvme_passthru_cmd cmd; | |||
| 971 | __u8 sts = 0, pif = 0; | |||
| 972 | bool_Bool pi_available; | |||
| 973 | __u32 dsmgmt = 0; | |||
| 974 | int mode = 0644; | |||
| 975 | void *buffer; | |||
| 976 | __u16 ms = 0; | |||
| 977 | int err = 0; | |||
| 978 | int flags; | |||
| 979 | ||||
| 980 | const char *start_block_addr = "64-bit addr of first block to access"; | |||
| 981 | const char *block_size = "if specified, logical block size in bytes;\n" | |||
| 982 | "discovered by identify namespace otherwise"; | |||
| 983 | const char *data_size = "size of data in bytes"; | |||
| 984 | const char *metadata_size = "size of metadata in bytes"; | |||
| 985 | const char *data = "data file"; | |||
| 986 | const char *metadata = "metadata file"; | |||
| 987 | const char *limited_retry_num = "limit num. media access attempts"; | |||
| 988 | const char *show = "show command before sending"; | |||
| 989 | const char *dtype_for_write = "directive type (for write-only)"; | |||
| 990 | const char *dspec = "directive specific (for write-only)"; | |||
| 991 | const char *dsm = "dataset management attributes (lower 8 bits)"; | |||
| 992 | const char *force = "The \"I know what I'm doing\" flag, do not enforce exclusive access for write"; | |||
| 993 | ||||
| 994 | struct config { | |||
| 995 | __u32 nsid; | |||
| 996 | __u64 start_block; | |||
| 997 | __u16 block_count; | |||
| 998 | __u16 block_size; | |||
| 999 | __u64 data_size; | |||
| 1000 | __u64 metadata_size; | |||
| 1001 | __u64 ilbrt; | |||
| 1002 | char *data; | |||
| 1003 | char *metadata; | |||
| 1004 | __u8 prinfo; | |||
| 1005 | __u16 lbatm; | |||
| 1006 | __u16 lbat; | |||
| 1007 | __u64 lbst; | |||
| 1008 | bool_Bool limited_retry; | |||
| 1009 | bool_Bool force_unit_access; | |||
| 1010 | bool_Bool stc; | |||
| 1011 | __u8 dtype; | |||
| 1012 | __u16 dspec; | |||
| 1013 | __u8 dsmgmt; | |||
| 1014 | bool_Bool show; | |||
| 1015 | bool_Bool latency; | |||
| 1016 | bool_Bool force; | |||
| 1017 | }; | |||
| 1018 | ||||
| 1019 | struct config cfg = { | |||
| 1020 | .nsid = 0, | |||
| 1021 | .start_block = 0, | |||
| 1022 | .block_count = 0, | |||
| 1023 | .block_size = 0, | |||
| 1024 | .data_size = 0, | |||
| 1025 | .metadata_size = 0, | |||
| 1026 | .ilbrt = 0, | |||
| 1027 | .data = "", | |||
| 1028 | .metadata = "", | |||
| 1029 | .prinfo = 0, | |||
| 1030 | .lbatm = 0, | |||
| 1031 | .lbat = 0, | |||
| 1032 | .lbst = 0, | |||
| 1033 | .limited_retry = false0, | |||
| 1034 | .force_unit_access = false0, | |||
| 1035 | .stc = false0, | |||
| 1036 | .dtype = 0, | |||
| 1037 | .dspec = 0, | |||
| 1038 | .dsmgmt = 0, | |||
| 1039 | .show = false0, | |||
| 1040 | .latency = false0, | |||
| 1041 | .force = false0, | |||
| 1042 | }; | |||
| 1043 | ||||
| 1044 | OPT_ARGS(opts)struct argconfig_commandline_options opts[] = { | |||
| 1045 | OPT_UINT("namespace-id", 'n', &cfg.nsid, namespace_id_desired,{"namespace-id", 'n', "NUM", CFG_POSITIVE, _Generic(&cfg. nsid, uint32_t * : (&cfg.nsid)), ARGCONFIG_ARG_REQUIRED, namespace_id_desired , 0, nvme_nsid_values} | |||
| 1046 | nvme_nsid_values){"namespace-id", 'n', "NUM", CFG_POSITIVE, _Generic(&cfg. nsid, uint32_t * : (&cfg.nsid)), ARGCONFIG_ARG_REQUIRED, namespace_id_desired , 0, nvme_nsid_values}, | |||
| 1047 | OPT_SUFFIX("start-block", 's', &cfg.start_block,{"start-block", 's', "IONUM", CFG_LONG_SUFFIX, _Generic(& cfg.start_block, uint64_t * : (&cfg.start_block), default : _Generic(&cfg.start_block, unsigned long long * : (& cfg.start_block), default : (void)0)), ARGCONFIG_ARG_REQUIRED , start_block_addr, 0, } | |||
| 1048 | start_block_addr){"start-block", 's', "IONUM", CFG_LONG_SUFFIX, _Generic(& cfg.start_block, uint64_t * : (&cfg.start_block), default : _Generic(&cfg.start_block, unsigned long long * : (& cfg.start_block), default : (void)0)), ARGCONFIG_ARG_REQUIRED , start_block_addr, 0, }, | |||
| 1049 | OPT_SHRT("block-count", 'c', &cfg.block_count, block_count){"block-count", 'c', "NUM", CFG_SHORT, _Generic(&cfg.block_count , uint16_t * : (&cfg.block_count)), ARGCONFIG_ARG_REQUIRED , block_count, 0, }, | |||
| 1050 | OPT_SHRT("block-size", 'b', &cfg.block_size, block_size){"block-size", 'b', "NUM", CFG_SHORT, _Generic(&cfg.block_size , uint16_t * : (&cfg.block_size)), ARGCONFIG_ARG_REQUIRED , block_size, 0, }, | |||
| 1051 | OPT_SUFFIX("data-size", 'z', &cfg.data_size, data_size){"data-size", 'z', "IONUM", CFG_LONG_SUFFIX, _Generic(&cfg .data_size, uint64_t * : (&cfg.data_size), default : _Generic (&cfg.data_size, unsigned long long * : (&cfg.data_size ), default : (void)0)), ARGCONFIG_ARG_REQUIRED, data_size, 0, }, | |||
| 1052 | OPT_SUFFIX("metadata-size", 'y', &cfg.metadata_size,{"metadata-size", 'y', "IONUM", CFG_LONG_SUFFIX, _Generic(& cfg.metadata_size, uint64_t * : (&cfg.metadata_size), default : _Generic(&cfg.metadata_size, unsigned long long * : (& cfg.metadata_size), default : (void)0)), ARGCONFIG_ARG_REQUIRED , metadata_size, 0, } | |||
| 1053 | metadata_size){"metadata-size", 'y', "IONUM", CFG_LONG_SUFFIX, _Generic(& cfg.metadata_size, uint64_t * : (&cfg.metadata_size), default : _Generic(&cfg.metadata_size, unsigned long long * : (& cfg.metadata_size), default : (void)0)), ARGCONFIG_ARG_REQUIRED , metadata_size, 0, }, | |||
| 1054 | OPT_SUFFIX("ref-tag", 'r', &cfg.ilbrt, ref_tag){"ref-tag", 'r', "IONUM", CFG_LONG_SUFFIX, _Generic(&cfg. ilbrt, uint64_t * : (&cfg.ilbrt), default : _Generic(& cfg.ilbrt, unsigned long long * : (&cfg.ilbrt), default : (void)0)), ARGCONFIG_ARG_REQUIRED, ref_tag, 0, }, | |||
| 1055 | OPT_FILE("data", 'd', &cfg.data, data){"data", 'd', "FILE", CFG_FILE, _Generic(&cfg.data, char * * : (&cfg.data), const char ** : (&cfg.data)), ARGCONFIG_ARG_REQUIRED , data, 0, }, | |||
| 1056 | OPT_FILE("metadata", 'M', &cfg.metadata, metadata){"metadata", 'M', "FILE", CFG_FILE, _Generic(&cfg.metadata , char ** : (&cfg.metadata), const char ** : (&cfg.metadata )), ARGCONFIG_ARG_REQUIRED, metadata, 0, }, | |||
| 1057 | OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo){"prinfo", 'p', "NUM", CFG_BYTE, _Generic(&cfg.prinfo, uint8_t * : (&cfg.prinfo)), ARGCONFIG_ARG_REQUIRED, prinfo, 0, }, | |||
| 1058 | OPT_SHRT("app-tag-mask", 'm', &cfg.lbatm, app_tag_mask){"app-tag-mask", 'm', "NUM", CFG_SHORT, _Generic(&cfg.lbatm , uint16_t * : (&cfg.lbatm)), ARGCONFIG_ARG_REQUIRED, app_tag_mask , 0, }, | |||
| 1059 | OPT_SHRT("app-tag", 'a', &cfg.lbat, app_tag){"app-tag", 'a', "NUM", CFG_SHORT, _Generic(&cfg.lbat, uint16_t * : (&cfg.lbat)), ARGCONFIG_ARG_REQUIRED, app_tag, 0, }, | |||
| 1060 | OPT_SUFFIX("storage-tag", 'g', &cfg.lbst, storage_tag){"storage-tag", 'g', "IONUM", CFG_LONG_SUFFIX, _Generic(& cfg.lbst, uint64_t * : (&cfg.lbst), default : _Generic(& cfg.lbst, unsigned long long * : (&cfg.lbst), default : ( void)0)), ARGCONFIG_ARG_REQUIRED, storage_tag, 0, }, | |||
| 1061 | OPT_FLAG("limited-retry", 'l', &cfg.limited_retry,{"limited-retry", 'l', ((void*)0), CFG_FLAG, _Generic(&cfg .limited_retry, _Bool * : (&cfg.limited_retry)), ARGCONFIG_ARG_NONE , limited_retry_num, 0, } | |||
| 1062 | limited_retry_num){"limited-retry", 'l', ((void*)0), CFG_FLAG, _Generic(&cfg .limited_retry, _Bool * : (&cfg.limited_retry)), ARGCONFIG_ARG_NONE , limited_retry_num, 0, }, | |||
| 1063 | OPT_FLAG("force-unit-access", 'f', &cfg.force_unit_access,{"force-unit-access", 'f', ((void*)0), CFG_FLAG, _Generic(& cfg.force_unit_access, _Bool * : (&cfg.force_unit_access) ), ARGCONFIG_ARG_NONE, force_unit_access, 0, } | |||
| 1064 | force_unit_access){"force-unit-access", 'f', ((void*)0), CFG_FLAG, _Generic(& cfg.force_unit_access, _Bool * : (&cfg.force_unit_access) ), ARGCONFIG_ARG_NONE, force_unit_access, 0, }, | |||
| 1065 | OPT_FLAG("storage-tag-check", 'C', &cfg.stc, storage_tag_check){"storage-tag-check", 'C', ((void*)0), CFG_FLAG, _Generic(& cfg.stc, _Bool * : (&cfg.stc)), ARGCONFIG_ARG_NONE, storage_tag_check , 0, }, | |||
| 1066 | OPT_BYTE("dir-type", 'T', &cfg.dtype, dtype_for_write){"dir-type", 'T', "NUM", CFG_BYTE, _Generic(&cfg.dtype, uint8_t * : (&cfg.dtype)), ARGCONFIG_ARG_REQUIRED, dtype_for_write , 0, }, | |||
| 1067 | OPT_SHRT("dir-spec", 'S', &cfg.dspec, dspec){"dir-spec", 'S', "NUM", CFG_SHORT, _Generic(&cfg.dspec, uint16_t * : (&cfg.dspec)), ARGCONFIG_ARG_REQUIRED, dspec, 0, }, | |||
| 1068 | OPT_BYTE("dsm", 'D', &cfg.dsmgmt, dsm){"dsm", 'D', "NUM", CFG_BYTE, _Generic(&cfg.dsmgmt, uint8_t * : (&cfg.dsmgmt)), ARGCONFIG_ARG_REQUIRED, dsm, 0, }, | |||
| 1069 | OPT_FLAG("show-command", 'V', &cfg.show, show){"show-command", 'V', ((void*)0), CFG_FLAG, _Generic(&cfg .show, _Bool * : (&cfg.show)), ARGCONFIG_ARG_NONE, show, 0 , }, | |||
| 1070 | OPT_FLAG("latency", 't', &cfg.latency, latency){"latency", 't', ((void*)0), CFG_FLAG, _Generic(&cfg.latency , _Bool * : (&cfg.latency)), ARGCONFIG_ARG_NONE, latency, 0, }, | |||
| 1071 | OPT_FLAG("force", 0, &cfg.force, force){"force", 0, ((void*)0), CFG_FLAG, _Generic(&cfg.force, _Bool * : (&cfg.force)), ARGCONFIG_ARG_NONE, force, 0, }, | |||
| 1072 | OPT_END(){ ((void*)0) } | |||
| 1073 | }; | |||
| 1074 | ||||
| 1075 | if (opcode
| |||
| 1076 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 1077 | if (err) | |||
| 1078 | return err; | |||
| 1079 | } else { | |||
| 1080 | err = parse_args(argc, argv, desc, opts); | |||
| 1081 | if (err) | |||
| 1082 | return err; | |||
| 1083 | err = open_exclusive(&ctx, &hdl, argc, argv, cfg.force, opts); | |||
| 1084 | if (err) { | |||
| 1085 | if (err == -EBUSY16) { | |||
| 1086 | nvme_show_error("Failed to open %s.",nvme_show_message(1, "Failed to open %s.", __xpg_basename(nvme_args .device)) | |||
| 1087 | basename(nvme_args.device))nvme_show_message(1, "Failed to open %s.", __xpg_basename(nvme_args .device)); | |||
| 1088 | nvme_show_error("Namespace is currently busy.")nvme_show_message(1, "Namespace is currently busy."); | |||
| 1089 | if (!cfg.force) | |||
| 1090 | nvme_show_error(nvme_show_message(1, "Use the force [--force] option to ignore that." ) | |||
| 1091 | "Use the force [--force] option to ignore that.")nvme_show_message(1, "Use the force [--force] option to ignore that." ); | |||
| 1092 | } | |||
| 1093 | return err; | |||
| 1094 | } | |||
| 1095 | } | |||
| 1096 | ||||
| 1097 | if (!cfg.nsid) { | |||
| 1098 | err = libnvme_get_nsid(hdl, &cfg.nsid); | |||
| 1099 | if (err < 0) { | |||
| 1100 | nvme_show_error("get-namespace-id: %s", libnvme_strerror(-err))nvme_show_message(1, "get-namespace-id: %s", libnvme_strerror (-err)); | |||
| 1101 | return err; | |||
| 1102 | } | |||
| 1103 | } | |||
| 1104 | ||||
| 1105 | if (cfg.prinfo > 0xf) | |||
| 1106 | return -EINVAL22; | |||
| 1107 | ||||
| 1108 | dsmgmt = cfg.dsmgmt; | |||
| 1109 | control |= (cfg.prinfo << 10); | |||
| 1110 | if (cfg.limited_retry) | |||
| 1111 | control |= NVME_IO_LR; | |||
| 1112 | if (cfg.force_unit_access) | |||
| 1113 | control |= NVME_IO_FUA; | |||
| 1114 | if (cfg.stc) | |||
| 1115 | control |= NVME_IO_STC; | |||
| 1116 | if (cfg.dtype) { | |||
| 1117 | if (cfg.dtype > 0xf) { | |||
| 1118 | nvme_show_error("Invalid directive type, %x", cfg.dtype)nvme_show_message(1, "Invalid directive type, %x", cfg.dtype); | |||
| 1119 | return -EINVAL22; | |||
| 1120 | } | |||
| 1121 | control |= cfg.dtype << 4; | |||
| 1122 | dsmgmt |= ((__u32)cfg.dspec) << 16; | |||
| 1123 | } | |||
| 1124 | ||||
| 1125 | if (opcode & 1) { | |||
| 1126 | dfd = mfd = STDIN_FILENO0; | |||
| 1127 | flags = O_RDONLY00; | |||
| 1128 | } else { | |||
| 1129 | dfd = mfd = STDOUT_FILENO1; | |||
| 1130 | flags = O_WRONLY01 | O_CREAT0100 | O_TRUNC01000; | |||
| 1131 | } | |||
| 1132 | ||||
| 1133 | if (strlen(cfg.data)) { | |||
| 1134 | dfd = shr_open_rawdata(cfg.data, flags, mode)open((cfg.data), (flags), mode); | |||
| 1135 | if (dfd < 0) { | |||
| 1136 | nvme_show_perror(cfg.data); | |||
| 1137 | return -EINVAL22; | |||
| 1138 | } | |||
| 1139 | } | |||
| 1140 | ||||
| 1141 | if (strlen(cfg.metadata)) { | |||
| 1142 | mfd = shr_open_rawdata(cfg.metadata, flags, mode)open((cfg.metadata), (flags), mode); | |||
| 1143 | if (mfd < 0) { | |||
| 1144 | nvme_show_perror(cfg.metadata); | |||
| 1145 | return -EINVAL22; | |||
| 1146 | } | |||
| 1147 | } | |||
| 1148 | ||||
| 1149 | if (!cfg.data_size) { | |||
| 1150 | nvme_show_error("data size not provided")nvme_show_message(1, "data size not provided"); | |||
| 1151 | return -EINVAL22; | |||
| 1152 | } | |||
| 1153 | ||||
| 1154 | if (cfg.block_size) { | |||
| 1155 | logical_block_size = cfg.block_size; | |||
| 1156 | ms = cfg.metadata_size; | |||
| 1157 | pi_available = true1; | |||
| 1158 | } else { | |||
| 1159 | err = get_pi_info(hdl, cfg.nsid, cfg.prinfo, | |||
| 1160 | cfg.ilbrt, cfg.lbst, &logical_block_size, &ms); | |||
| 1161 | switch (err) { | |||
| 1162 | case 0: | |||
| 1163 | pi_available = true1; | |||
| 1164 | break; | |||
| 1165 | case -ENOMEM12: | |||
| 1166 | /* Could not even allocate the Identify buffer. */ | |||
| 1167 | case -ECLI_IDENTIFY_NS_FAILED: | |||
| 1168 | /* Base Identify Namespace failed: no logical block size. */ | |||
| 1169 | case -ECLI_INVALID_LBA_FORMAT: | |||
| 1170 | /* LBA data size too large: no logical block size. */ | |||
| 1171 | case -ECLI_INVALID_TAGS: | |||
| 1172 | /* Reference/storage tag is invalid for this PI format. */ | |||
| 1173 | case -ECLI_INVALID_PI_FORMAT: | |||
| 1174 | /* Namespace's reported PI format is self-inconsistent. */ | |||
| 1175 | return err; | |||
| 1176 | default: | |||
| 1177 | /* Identify NVM CS NS failed/unsupported: PI unavailable. */ | |||
| 1178 | nvme_show_err(err, "identify NVM CS NS: continuing without protection information"); | |||
| 1179 | pi_available = false0; | |||
| 1180 | break; | |||
| 1181 | } | |||
| 1182 | } | |||
| 1183 | ||||
| 1184 | buffer_size = ((long long)cfg.block_count + 1) * logical_block_size; | |||
| 1185 | if (cfg.data_size < buffer_size) | |||
| 1186 | nvme_show_error("Rounding data size to fit block count (%lld bytes)", buffer_size)nvme_show_message(1, "Rounding data size to fit block count (%lld bytes)" , buffer_size); | |||
| 1187 | else | |||
| 1188 | buffer_size = cfg.data_size; | |||
| 1189 | ||||
| 1190 | if (argconfig_given(opts, &cfg.block_count)) { | |||
| 1191 | /* Use the value provided */ | |||
| 1192 | nblocks = cfg.block_count; | |||
| 1193 | } else { | |||
| 1194 | /* Get the required block count. Note this is a zeroes based value. */ | |||
| 1195 | nblocks = ((buffer_size + (logical_block_size - 1)) / logical_block_size) - 1; | |||
| 1196 | ||||
| 1197 | /* Update the data size based on the required block count */ | |||
| 1198 | buffer_size = ((unsigned long long)nblocks + 1) * logical_block_size; | |||
| 1199 | } | |||
| 1200 | ||||
| 1201 | buffer = libnvme_alloc_huge(buffer_size, &mh); | |||
| 1202 | if (!buffer) { | |||
| 1203 | nvme_show_error("failed to allocate huge memory")nvme_show_message(1, "failed to allocate huge memory"); | |||
| 1204 | return -ENOMEM12; | |||
| 1205 | } | |||
| 1206 | ||||
| 1207 | if (cfg.metadata_size) { | |||
| 1208 | mbuffer_size = ((unsigned long long)cfg.block_count + 1) * ms; | |||
| 1209 | if (ms
| |||
| 1210 | nvme_show_error("Rounding metadata size to fit block count (%lld bytes)",nvme_show_message(1, "Rounding metadata size to fit block count (%lld bytes)" , mbuffer_size) | |||
| 1211 | mbuffer_size)nvme_show_message(1, "Rounding metadata size to fit block count (%lld bytes)" , mbuffer_size); | |||
| 1212 | else | |||
| 1213 | mbuffer_size = cfg.metadata_size; | |||
| 1214 | ||||
| 1215 | mbuffer = malloc(mbuffer_size); | |||
| 1216 | if (!mbuffer) | |||
| 1217 | return -ENOMEM12; | |||
| 1218 | memset(mbuffer, 0, mbuffer_size); | |||
| 1219 | } | |||
| 1220 | ||||
| 1221 | if (opcode & 1) { | |||
| 1222 | err = read(dfd, (void *)buffer, cfg.data_size); | |||
| 1223 | if (err < 0) { | |||
| 1224 | err = -errno(*__errno_location ()); | |||
| ||||
| 1225 | nvme_show_error("failed to read data buffer from input file %s", libnvme_strerror(errno))nvme_show_message(1, "failed to read data buffer from input file %s" , libnvme_strerror((*__errno_location ()))); | |||
| 1226 | return err; | |||
| 1227 | } | |||
| 1228 | } | |||
| 1229 | ||||
| 1230 | if ((opcode & 1) && cfg.metadata_size) { | |||
| 1231 | err = read(mfd, (void *)mbuffer, mbuffer_size); | |||
| 1232 | if (err < 0) { | |||
| 1233 | err = -errno(*__errno_location ()); | |||
| 1234 | nvme_show_error("failed to read meta-data buffer from input file %s", libnvme_strerror(errno))nvme_show_message(1, "failed to read meta-data buffer from input file %s" , libnvme_strerror((*__errno_location ()))); | |||
| 1235 | return err; | |||
| 1236 | } | |||
| 1237 | } | |||
| 1238 | ||||
| 1239 | if (cfg.show || nvme_args.dry_run) { | |||
| 1240 | nvme_show_result("opcode : %02x", opcode)nvme_show_message(0, "opcode : %02x", opcode); | |||
| 1241 | nvme_show_result("nsid : %02x", cfg.nsid)nvme_show_message(0, "nsid : %02x", cfg.nsid); | |||
| 1242 | nvme_show_result("flags : %02x", 0)nvme_show_message(0, "flags : %02x", 0); | |||
| 1243 | nvme_show_result("control : %04x", control)nvme_show_message(0, "control : %04x", control); | |||
| 1244 | nvme_show_result("nblocks : %04x", nblocks)nvme_show_message(0, "nblocks : %04x", nblocks); | |||
| 1245 | nvme_show_result("metadata : %"PRIx64, (uint64_t)(uintptr_t)mbuffer)nvme_show_message(0, "metadata : %""l" "x", (uint64_t)(uintptr_t )mbuffer); | |||
| 1246 | nvme_show_result("addr : %"PRIx64, (uint64_t)(uintptr_t)buffer)nvme_show_message(0, "addr : %""l" "x", (uint64_t)(uintptr_t )buffer); | |||
| 1247 | nvme_show_result("slba : %"PRIx64, (uint64_t)cfg.start_block)nvme_show_message(0, "slba : %""l" "x", (uint64_t)cfg .start_block); | |||
| 1248 | nvme_show_result("dsmgmt : %08x", dsmgmt)nvme_show_message(0, "dsmgmt : %08x", dsmgmt); | |||
| 1249 | nvme_show_result("reftag : %"PRIx64, (uint64_t)cfg.ilbrt)nvme_show_message(0, "reftag : %""l" "x", (uint64_t)cfg .ilbrt); | |||
| 1250 | nvme_show_result("apptag : %04x", cfg.lbat)nvme_show_message(0, "apptag : %04x", cfg.lbat); | |||
| 1251 | nvme_show_result("appmask : %04x", cfg.lbatm)nvme_show_message(0, "appmask : %04x", cfg.lbatm); | |||
| 1252 | nvme_show_result("storagetagcheck : %04x", cfg.stc)nvme_show_message(0, "storagetagcheck : %04x", cfg.stc); | |||
| 1253 | nvme_show_result("storagetag : %"PRIx64, (uint64_t)cfg.lbst)nvme_show_message(0, "storagetag : %""l" "x", (uint64_t) cfg.lbst); | |||
| 1254 | nvme_show_result("pif : %02x", pif)nvme_show_message(0, "pif : %02x", pif); | |||
| 1255 | nvme_show_result("sts : %02x", sts)nvme_show_message(0, "sts : %02x", sts); | |||
| 1256 | } | |||
| 1257 | if (nvme_args.dry_run) | |||
| 1258 | return 0; | |||
| 1259 | ||||
| 1260 | nvme_init_io(&cmd, opcode, cfg.nsid, cfg.start_block, buffer, | |||
| 1261 | buffer_size, mbuffer, mbuffer_size); | |||
| 1262 | cmd.cdw12 = NVME_FIELD_ENCODE(nblocks,(((__u32)(nblocks) & (NVME_IOCS_COMMON_CDW12_NLB_MASK)) << (NVME_IOCS_COMMON_CDW12_NLB_SHIFT)) | |||
| 1263 | NVME_IOCS_COMMON_CDW12_NLB_SHIFT,(((__u32)(nblocks) & (NVME_IOCS_COMMON_CDW12_NLB_MASK)) << (NVME_IOCS_COMMON_CDW12_NLB_SHIFT)) | |||
| 1264 | NVME_IOCS_COMMON_CDW12_NLB_MASK)(((__u32)(nblocks) & (NVME_IOCS_COMMON_CDW12_NLB_MASK)) << (NVME_IOCS_COMMON_CDW12_NLB_SHIFT)) | | |||
| 1265 | NVME_FIELD_ENCODE(control,(((__u32)(control) & (NVME_IOCS_COMMON_CDW12_CONTROL_MASK )) << (NVME_IOCS_COMMON_CDW12_CONTROL_SHIFT)) | |||
| 1266 | NVME_IOCS_COMMON_CDW12_CONTROL_SHIFT,(((__u32)(control) & (NVME_IOCS_COMMON_CDW12_CONTROL_MASK )) << (NVME_IOCS_COMMON_CDW12_CONTROL_SHIFT)) | |||
| 1267 | NVME_IOCS_COMMON_CDW12_CONTROL_MASK)(((__u32)(control) & (NVME_IOCS_COMMON_CDW12_CONTROL_MASK )) << (NVME_IOCS_COMMON_CDW12_CONTROL_SHIFT)); | |||
| 1268 | cmd.cdw13 = NVME_FIELD_ENCODE(cfg.dspec,(((__u32)(cfg.dspec) & (NVME_IOCS_COMMON_CDW13_DSPEC_MASK )) << (NVME_IOCS_COMMON_CDW13_DSPEC_SHIFT)) | |||
| 1269 | NVME_IOCS_COMMON_CDW13_DSPEC_SHIFT,(((__u32)(cfg.dspec) & (NVME_IOCS_COMMON_CDW13_DSPEC_MASK )) << (NVME_IOCS_COMMON_CDW13_DSPEC_SHIFT)) | |||
| 1270 | NVME_IOCS_COMMON_CDW13_DSPEC_MASK)(((__u32)(cfg.dspec) & (NVME_IOCS_COMMON_CDW13_DSPEC_MASK )) << (NVME_IOCS_COMMON_CDW13_DSPEC_SHIFT)) | | |||
| 1271 | NVME_FIELD_ENCODE(cfg.dsmgmt,(((__u32)(cfg.dsmgmt) & (NVME_IOCS_COMMON_CDW13_DSM_MASK) ) << (NVME_IOCS_COMMON_CDW13_DSM_SHIFT)) | |||
| 1272 | NVME_IOCS_COMMON_CDW13_DSM_SHIFT,(((__u32)(cfg.dsmgmt) & (NVME_IOCS_COMMON_CDW13_DSM_MASK) ) << (NVME_IOCS_COMMON_CDW13_DSM_SHIFT)) | |||
| 1273 | NVME_IOCS_COMMON_CDW13_DSM_MASK)(((__u32)(cfg.dsmgmt) & (NVME_IOCS_COMMON_CDW13_DSM_MASK) ) << (NVME_IOCS_COMMON_CDW13_DSM_SHIFT)); | |||
| 1274 | if (pi_available) { | |||
| 1275 | err = init_pi_tags(hdl, &cmd, cfg.nsid, cfg.ilbrt, cfg.lbst, | |||
| 1276 | cfg.lbat, cfg.lbatm); | |||
| 1277 | if (err) | |||
| 1278 | return err; | |||
| 1279 | } | |||
| 1280 | gettimeofday(&start_time, NULL((void*)0)); | |||
| 1281 | err = libnvme_exec_io_passthru(hdl, &cmd); | |||
| 1282 | gettimeofday(&end_time, NULL((void*)0)); | |||
| 1283 | if (cfg.latency) | |||
| 1284 | nvme_show_result(" latency: %s: %llu us", command, shr_elapsed_utime(start_time, end_time))nvme_show_message(0, " latency: %s: %llu us", command, shr_elapsed_utime (start_time, end_time)); | |||
| 1285 | if (err) { | |||
| 1286 | nvme_show_err(err, "submit-io"); | |||
| 1287 | return err; | |||
| 1288 | } | |||
| 1289 | ||||
| 1290 | if (!(opcode & 1) && write(dfd, (void *)buffer, buffer_size) < 0) { | |||
| 1291 | nvme_show_error(nvme_show_message(1, "write: %s: failed to write buffer to output file" , libnvme_strerror((*__errno_location ()))) | |||
| 1292 | "write: %s: failed to write buffer to output file",nvme_show_message(1, "write: %s: failed to write buffer to output file" , libnvme_strerror((*__errno_location ()))) | |||
| 1293 | libnvme_strerror(errno))nvme_show_message(1, "write: %s: failed to write buffer to output file" , libnvme_strerror((*__errno_location ()))); | |||
| 1294 | err = -EINVAL22; | |||
| 1295 | } else if (!(opcode & 1) && cfg.metadata_size && | |||
| 1296 | write(mfd, (void *)mbuffer, mbuffer_size) < 0) { | |||
| 1297 | nvme_show_error(nvme_show_message(1, "write: %s: failed to write meta-data buffer to output file" , libnvme_strerror((*__errno_location ()))) | |||
| 1298 | "write: %s: failed to write meta-data buffer to output file",nvme_show_message(1, "write: %s: failed to write meta-data buffer to output file" , libnvme_strerror((*__errno_location ()))) | |||
| 1299 | libnvme_strerror(errno))nvme_show_message(1, "write: %s: failed to write meta-data buffer to output file" , libnvme_strerror((*__errno_location ()))); | |||
| 1300 | err = -EINVAL22; | |||
| 1301 | } else { | |||
| 1302 | nvme_show_verbose_result("%s: Success", command)nvme_show_verbose_message("%s: Success", command); | |||
| 1303 | } | |||
| 1304 | ||||
| 1305 | return err; | |||
| 1306 | } | |||
| 1307 | ||||
| 1308 | static int compare(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 1309 | { | |||
| 1310 | const char *desc = "Compare specified logical blocks on\n" | |||
| 1311 | "device with specified data buffer; return failure if buffer\n" | |||
| 1312 | "and block(s) are dissimilar"; | |||
| 1313 | ||||
| 1314 | return submit_io(nvme_cmd_compare, "compare", desc, argc, argv); | |||
| ||||
| 1315 | } | |||
| 1316 | ||||
| 1317 | static int read_cmd(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 1318 | { | |||
| 1319 | const char *desc = "Copy specified logical blocks on the given\n" | |||
| 1320 | "device to specified data buffer (default buffer is stdout)."; | |||
| 1321 | ||||
| 1322 | return submit_io(nvme_cmd_read, "read", desc, argc, argv); | |||
| 1323 | } | |||
| 1324 | ||||
| 1325 | static int write_cmd(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 1326 | { | |||
| 1327 | const char *desc = "Copy from provided data buffer (default\n" | |||
| 1328 | "buffer is stdin) to specified logical blocks on the given device."; | |||
| 1329 | ||||
| 1330 | return submit_io(nvme_cmd_write, "write", desc, argc, argv); | |||
| 1331 | } | |||
| 1332 | ||||
| 1333 | static int verify_cmd(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 1334 | { | |||
| 1335 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 1336 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 1337 | struct libnvme_passthru_cmd cmd; | |||
| 1338 | __u16 control = 0; | |||
| 1339 | int err; | |||
| 1340 | ||||
| 1341 | const char *desc = "Verify specified logical blocks on the given device."; | |||
| 1342 | const char *force_unit_access_verify = | |||
| 1343 | "force device to commit cached data before performing the verify operation"; | |||
| 1344 | const char *storage_tag_check = | |||
| 1345 | "This bit specifies the Storage Tag field shall be checked as part of Verify operation"; | |||
| 1346 | ||||
| 1347 | struct config { | |||
| 1348 | __u32 nsid; | |||
| 1349 | __u64 start_block; | |||
| 1350 | __u16 block_count; | |||
| 1351 | bool_Bool limited_retry; | |||
| 1352 | bool_Bool force_unit_access; | |||
| 1353 | __u8 prinfo; | |||
| 1354 | __u64 ilbrt; | |||
| 1355 | __u16 lbat; | |||
| 1356 | __u16 lbatm; | |||
| 1357 | __u64 lbst; | |||
| 1358 | bool_Bool stc; | |||
| 1359 | }; | |||
| 1360 | ||||
| 1361 | struct config cfg = { | |||
| 1362 | .nsid = 0, | |||
| 1363 | .start_block = 0, | |||
| 1364 | .block_count = 0, | |||
| 1365 | .limited_retry = false0, | |||
| 1366 | .force_unit_access = false0, | |||
| 1367 | .prinfo = 0, | |||
| 1368 | .ilbrt = 0, | |||
| 1369 | .lbat = 0, | |||
| 1370 | .lbatm = 0, | |||
| 1371 | .lbst = 0, | |||
| 1372 | .stc = false0, | |||
| 1373 | }; | |||
| 1374 | ||||
| 1375 | OPT_ARGS(opts)struct argconfig_commandline_options opts[] = { | |||
| 1376 | OPT_UINT("namespace-id", 'n', &cfg.nsid, namespace_desired,{"namespace-id", 'n', "NUM", CFG_POSITIVE, _Generic(&cfg. nsid, uint32_t * : (&cfg.nsid)), ARGCONFIG_ARG_REQUIRED, namespace_desired , 0, nvme_nsid_values} | |||
| 1377 | nvme_nsid_values){"namespace-id", 'n', "NUM", CFG_POSITIVE, _Generic(&cfg. nsid, uint32_t * : (&cfg.nsid)), ARGCONFIG_ARG_REQUIRED, namespace_desired , 0, nvme_nsid_values}, | |||
| 1378 | OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block){"start-block", 's', "IONUM", CFG_LONG_SUFFIX, _Generic(& cfg.start_block, uint64_t * : (&cfg.start_block), default : _Generic(&cfg.start_block, unsigned long long * : (& cfg.start_block), default : (void)0)), ARGCONFIG_ARG_REQUIRED , start_block, 0, }, | |||
| 1379 | OPT_SHRT("block-count", 'c', &cfg.block_count, block_count){"block-count", 'c', "NUM", CFG_SHORT, _Generic(&cfg.block_count , uint16_t * : (&cfg.block_count)), ARGCONFIG_ARG_REQUIRED , block_count, 0, }, | |||
| 1380 | OPT_FLAG("limited-retry", 'l', &cfg.limited_retry,{"limited-retry", 'l', ((void*)0), CFG_FLAG, _Generic(&cfg .limited_retry, _Bool * : (&cfg.limited_retry)), ARGCONFIG_ARG_NONE , limited_retry, 0, } | |||
| 1381 | limited_retry){"limited-retry", 'l', ((void*)0), CFG_FLAG, _Generic(&cfg .limited_retry, _Bool * : (&cfg.limited_retry)), ARGCONFIG_ARG_NONE , limited_retry, 0, }, | |||
| 1382 | OPT_FLAG("force-unit-access", 'f', &cfg.force_unit_access,{"force-unit-access", 'f', ((void*)0), CFG_FLAG, _Generic(& cfg.force_unit_access, _Bool * : (&cfg.force_unit_access) ), ARGCONFIG_ARG_NONE, force_unit_access_verify, 0, } | |||
| 1383 | force_unit_access_verify){"force-unit-access", 'f', ((void*)0), CFG_FLAG, _Generic(& cfg.force_unit_access, _Bool * : (&cfg.force_unit_access) ), ARGCONFIG_ARG_NONE, force_unit_access_verify, 0, }, | |||
| 1384 | OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo){"prinfo", 'p', "NUM", CFG_BYTE, _Generic(&cfg.prinfo, uint8_t * : (&cfg.prinfo)), ARGCONFIG_ARG_REQUIRED, prinfo, 0, }, | |||
| 1385 | OPT_SUFFIX("ref-tag", 'r', &cfg.ilbrt, ref_tag){"ref-tag", 'r', "IONUM", CFG_LONG_SUFFIX, _Generic(&cfg. ilbrt, uint64_t * : (&cfg.ilbrt), default : _Generic(& cfg.ilbrt, unsigned long long * : (&cfg.ilbrt), default : (void)0)), ARGCONFIG_ARG_REQUIRED, ref_tag, 0, }, | |||
| 1386 | OPT_SHRT("app-tag", 'a', &cfg.lbat, app_tag){"app-tag", 'a', "NUM", CFG_SHORT, _Generic(&cfg.lbat, uint16_t * : (&cfg.lbat)), ARGCONFIG_ARG_REQUIRED, app_tag, 0, }, | |||
| 1387 | OPT_SHRT("app-tag-mask", 'm', &cfg.lbatm, app_tag_mask){"app-tag-mask", 'm', "NUM", CFG_SHORT, _Generic(&cfg.lbatm , uint16_t * : (&cfg.lbatm)), ARGCONFIG_ARG_REQUIRED, app_tag_mask , 0, }, | |||
| 1388 | OPT_SUFFIX("storage-tag", 'S', &cfg.lbst, storage_tag){"storage-tag", 'S', "IONUM", CFG_LONG_SUFFIX, _Generic(& cfg.lbst, uint64_t * : (&cfg.lbst), default : _Generic(& cfg.lbst, unsigned long long * : (&cfg.lbst), default : ( void)0)), ARGCONFIG_ARG_REQUIRED, storage_tag, 0, }, | |||
| 1389 | OPT_FLAG("storage-tag-check", 'C', &cfg.stc, storage_tag_check){"storage-tag-check", 'C', ((void*)0), CFG_FLAG, _Generic(& cfg.stc, _Bool * : (&cfg.stc)), ARGCONFIG_ARG_NONE, storage_tag_check , 0, }, | |||
| 1390 | OPT_END(){ ((void*)0) } | |||
| 1391 | }; | |||
| 1392 | ||||
| 1393 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 1394 | if (err) | |||
| 1395 | return err; | |||
| 1396 | ||||
| 1397 | err = open_fallback_chardev(ctx, cfg.nsid, &hdl); | |||
| 1398 | if (err) | |||
| 1399 | return err; | |||
| 1400 | ||||
| 1401 | if (cfg.prinfo > 0xf) | |||
| 1402 | return -EINVAL22; | |||
| 1403 | ||||
| 1404 | control |= (cfg.prinfo << 10); | |||
| 1405 | if (cfg.limited_retry) | |||
| 1406 | control |= NVME_IO_LR; | |||
| 1407 | if (cfg.force_unit_access) | |||
| 1408 | control |= NVME_IO_FUA; | |||
| 1409 | if (cfg.stc) | |||
| 1410 | control |= NVME_IO_STC; | |||
| 1411 | ||||
| 1412 | if (!cfg.nsid) { | |||
| 1413 | err = libnvme_get_nsid(hdl, &cfg.nsid); | |||
| 1414 | if (err < 0) { | |||
| 1415 | nvme_show_error("get-namespace-id: %s", libnvme_strerror(-err))nvme_show_message(1, "get-namespace-id: %s", libnvme_strerror (-err)); | |||
| 1416 | return err; | |||
| 1417 | } | |||
| 1418 | } | |||
| 1419 | ||||
| 1420 | nvme_init_verify(&cmd, cfg.nsid, cfg.start_block, | |||
| 1421 | cfg.block_count, control, 0, NULL((void*)0), 0, NULL((void*)0), 0); | |||
| 1422 | err = init_pi_tags(hdl, &cmd, cfg.nsid, cfg.ilbrt, cfg.lbst, | |||
| 1423 | cfg.lbat, cfg.lbatm); | |||
| 1424 | if (err) | |||
| 1425 | return err; | |||
| 1426 | err = libnvme_exec_io_passthru(hdl, &cmd); | |||
| 1427 | if (err) { | |||
| 1428 | nvme_show_err(err, "verify"); | |||
| 1429 | return err; | |||
| 1430 | } | |||
| 1431 | ||||
| 1432 | nvme_show_verbose_result("NVME Verify Success")nvme_show_verbose_message("NVME Verify Success"); | |||
| 1433 | ||||
| 1434 | return err; | |||
| 1435 | } | |||
| 1436 | ||||
| 1437 | static int get_lba_status(int argc, char **argv, struct command *acmd, | |||
| 1438 | struct plugin *plugin) | |||
| 1439 | { | |||
| 1440 | const char *desc = "Information about potentially unrecoverable LBAs."; | |||
| 1441 | const char *slba = | |||
| 1442 | "Starting LBA(SLBA) in 64-bit address of the first logical block addressed by this command"; | |||
| 1443 | const char *mndw = | |||
| 1444 | "Maximum Number of Dwords(MNDW) specifies maximum number of dwords to return"; | |||
| 1445 | const char *atype = "Action Type(ATYPE) specifies the mechanism\n" | |||
| 1446 | "the controller uses in determining the LBA Status Descriptors to return."; | |||
| 1447 | const char *rl = | |||
| 1448 | "Range Length(RL) specifies the length of the range of contiguous LBAs beginning at SLBA"; | |||
| 1449 | ||||
| 1450 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 1451 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 1452 | struct libnvme_passthru_cmd cmd; | |||
| 1453 | __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) void *buf = NULL((void*)0); | |||
| 1454 | nvme_print_flags_t flags; | |||
| 1455 | unsigned long buf_len; | |||
| 1456 | int err; | |||
| 1457 | ||||
| 1458 | struct config { | |||
| 1459 | bool_Bool ish; | |||
| 1460 | __u32 namespace_id; | |||
| 1461 | __u64 slba; | |||
| 1462 | __u32 mndw; | |||
| 1463 | __u8 atype; | |||
| 1464 | __u16 rl; | |||
| 1465 | }; | |||
| 1466 | ||||
| 1467 | struct config cfg = { | |||
| 1468 | .ish = false0, | |||
| 1469 | .namespace_id = 0, | |||
| 1470 | .slba = 0, | |||
| 1471 | .mndw = 0, | |||
| 1472 | .atype = 0, | |||
| 1473 | .rl = 0, | |||
| 1474 | }; | |||
| 1475 | ||||
| 1476 | OPT_ARGS(opts)struct argconfig_commandline_options opts[] = { | |||
| 1477 | OPT_FLAG("ish", 'I', &cfg.ish, ish){"ish", 'I', ((void*)0), CFG_FLAG, _Generic(&cfg.ish, _Bool * : (&cfg.ish)), ARGCONFIG_ARG_NONE, ish, 0, }, | |||
| 1478 | OPT_UINT("namespace-id", 'n', &cfg.namespace_id,{"namespace-id", 'n', "NUM", CFG_POSITIVE, _Generic(&cfg. namespace_id, uint32_t * : (&cfg.namespace_id)), ARGCONFIG_ARG_REQUIRED , namespace_desired, 0, nvme_nsid_values} | |||
| 1479 | namespace_desired, nvme_nsid_values){"namespace-id", 'n', "NUM", CFG_POSITIVE, _Generic(&cfg. namespace_id, uint32_t * : (&cfg.namespace_id)), ARGCONFIG_ARG_REQUIRED , namespace_desired, 0, nvme_nsid_values}, | |||
| 1480 | OPT_SUFFIX("start-lba", 's', &cfg.slba, slba){"start-lba", 's', "IONUM", CFG_LONG_SUFFIX, _Generic(&cfg .slba, uint64_t * : (&cfg.slba), default : _Generic(& cfg.slba, unsigned long long * : (&cfg.slba), default : ( void)0)), ARGCONFIG_ARG_REQUIRED, slba, 0, }, | |||
| 1481 | OPT_UINT("max-dw", 'm', &cfg.mndw, mndw){"max-dw", 'm', "NUM", CFG_POSITIVE, _Generic(&cfg.mndw, uint32_t * : (&cfg.mndw)), ARGCONFIG_ARG_REQUIRED, mndw, 0, }, | |||
| 1482 | OPT_BYTE("action", 'a', &cfg.atype, atype){"action", 'a', "NUM", CFG_BYTE, _Generic(&cfg.atype, uint8_t * : (&cfg.atype)), ARGCONFIG_ARG_REQUIRED, atype, 0, }, | |||
| 1483 | OPT_SHRT("range-len", 'l', &cfg.rl, rl){"range-len", 'l', "NUM", CFG_SHORT, _Generic(&cfg.rl, uint16_t * : (&cfg.rl)), ARGCONFIG_ARG_REQUIRED, rl, 0, }, | |||
| 1484 | OPT_END(){ ((void*)0) } | |||
| 1485 | }; | |||
| 1486 | ||||
| 1487 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 1488 | if (err) | |||
| 1489 | return err; | |||
| 1490 | ||||
| 1491 | flags = nvme_args.output_flags; | |||
| 1492 | ||||
| 1493 | if (!cfg.atype) { | |||
| 1494 | nvme_show_error("action type (--action) has to be given")nvme_show_message(1, "action type (--action) has to be given" ); | |||
| 1495 | return -EINVAL22; | |||
| 1496 | } | |||
| 1497 | ||||
| 1498 | buf_len = (cfg.mndw + 1) * 4; | |||
| 1499 | buf = libnvme_alloc(buf_len); | |||
| 1500 | if (!buf) | |||
| 1501 | return -ENOMEM12; | |||
| 1502 | ||||
| 1503 | nvme_init_get_lba_status(&cmd, cfg.namespace_id, cfg.slba, cfg.mndw, | |||
| 1504 | cfg.atype, cfg.rl, buf); | |||
| 1505 | if (cfg.ish) { | |||
| 1506 | if (libnvme_transport_handle_is_mi(hdl)) | |||
| 1507 | nvme_init_mi_cmd_flags(&cmd, ish); | |||
| 1508 | else | |||
| 1509 | nvme_show_error("ISH is supported only for NVMe-MI")nvme_show_message(1, "ISH is supported only for NVMe-MI"); | |||
| 1510 | } | |||
| 1511 | err = libnvme_exec_admin_passthru(hdl, &cmd); | |||
| 1512 | if (err) { | |||
| 1513 | nvme_show_err(err, "get lba status"); | |||
| 1514 | return err; | |||
| 1515 | } | |||
| 1516 | ||||
| 1517 | nvme_show_lba_status(buf, buf_len, flags); | |||
| 1518 | ||||
| 1519 | return err; | |||
| 1520 | } | |||
| 1521 | ||||
| 1522 | static int capacity_mgmt(int argc, char **argv, struct command *acmd, struct plugin *plugin) | |||
| 1523 | { | |||
| 1524 | const char *desc = "Host software uses the Capacity Management command to\n" | |||
| 1525 | "configure Endurance Groups and NVM Sets in an NVM subsystem by either\n" | |||
| 1526 | "selecting one of a set of supported configurations or by specifying the\n" | |||
| 1527 | "capacity of the Endurance Group or NVM Set to be created"; | |||
| 1528 | const char *operation = "Operation to be performed by the controller"; | |||
| 1529 | const char *element_id = "Value specific to the value of the Operation field."; | |||
| 1530 | const char *cap_lower = | |||
| 1531 | "Least significant 32 bits of the capacity in bytes of the Endurance Group or NVM Set to be created"; | |||
| 1532 | const char *cap_upper = | |||
| 1533 | "Most significant 32 bits of the capacity in bytes of the Endurance Group or NVM Set to be created"; | |||
| 1534 | ||||
| 1535 | __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0); | |||
| 1536 | __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0); | |||
| 1537 | struct libnvme_passthru_cmd cmd; | |||
| 1538 | int err = -1; | |||
| 1539 | ||||
| 1540 | struct config { | |||
| 1541 | bool_Bool ish; | |||
| 1542 | __u8 operation; | |||
| 1543 | __u16 element_id; | |||
| 1544 | __u32 dw11; | |||
| 1545 | __u32 dw12; | |||
| 1546 | }; | |||
| 1547 | ||||
| 1548 | struct config cfg = { | |||
| 1549 | .ish = false0, | |||
| 1550 | .operation = 0xff, | |||
| 1551 | .element_id = 0xffff, | |||
| 1552 | .dw11 = 0, | |||
| 1553 | .dw12 = 0, | |||
| 1554 | }; | |||
| 1555 | ||||
| 1556 | OPT_ARGS(opts)struct argconfig_commandline_options opts[] = { | |||
| 1557 | OPT_FLAG("ish", 'I', &cfg.ish, ish){"ish", 'I', ((void*)0), CFG_FLAG, _Generic(&cfg.ish, _Bool * : (&cfg.ish)), ARGCONFIG_ARG_NONE, ish, 0, }, | |||
| 1558 | OPT_BYTE("operation", 'O', &cfg.operation, operation){"operation", 'O', "NUM", CFG_BYTE, _Generic(&cfg.operation , uint8_t * : (&cfg.operation)), ARGCONFIG_ARG_REQUIRED, operation , 0, }, | |||
| 1559 | OPT_SHRT("element-id", 'i', &cfg.element_id, element_id){"element-id", 'i', "NUM", CFG_SHORT, _Generic(&cfg.element_id , uint16_t * : (&cfg.element_id)), ARGCONFIG_ARG_REQUIRED , element_id, 0, }, | |||
| 1560 | OPT_UINT("cap-lower", 'l', &cfg.dw11, cap_lower){"cap-lower", 'l', "NUM", CFG_POSITIVE, _Generic(&cfg.dw11 , uint32_t * : (&cfg.dw11)), ARGCONFIG_ARG_REQUIRED, cap_lower , 0, }, | |||
| 1561 | OPT_UINT("cap-upper", 'u', &cfg.dw12, cap_upper){"cap-upper", 'u', "NUM", CFG_POSITIVE, _Generic(&cfg.dw12 , uint32_t * : (&cfg.dw12)), ARGCONFIG_ARG_REQUIRED, cap_upper , 0, }, | |||
| 1562 | OPT_END(){ ((void*)0) } | |||
| 1563 | }; | |||
| 1564 | ||||
| 1565 | err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); | |||
| 1566 | if (err) | |||
| 1567 | return err; | |||
| 1568 | ||||
| 1569 | if (cfg.operation > 0xf) { | |||
| 1570 | nvme_show_error("invalid operation field: %u", cfg.operation)nvme_show_message(1, "invalid operation field: %u", cfg.operation ); | |||
| 1571 | return -1; | |||
| 1572 | } | |||
| 1573 | ||||
| 1574 | nvme_init_capacity_mgmt(&cmd, cfg.operation, cfg.element_id, | |||
| 1575 | (__u64)cfg.dw12 << 32 | cfg.dw11); | |||
| 1576 | if (cfg.ish) { | |||
| 1577 | if (libnvme_transport_handle_is_mi(hdl)) | |||
| 1578 | nvme_init_mi_cmd_flags(&cmd, ish); | |||
| 1579 | else | |||
| 1580 | nvme_show_error("ISH is supported only for NVMe-MI")nvme_show_message(1, "ISH is supported only for NVMe-MI"); | |||
| 1581 | } | |||
| 1582 | err = libnvme_exec_admin_passthru(hdl, &cmd); | |||
| 1583 | if (err) { | |||
| 1584 | nvme_show_err(err, "capacity management"); | |||
| 1585 | return err; | |||
| 1586 | } | |||
| 1587 | ||||
| 1588 | nvme_show_verbose_result("Capacity Management Command is Success")nvme_show_verbose_message("Capacity Management Command is Success" ); | |||
| 1589 | ||||
| 1590 | if (cfg.operation == 1) | |||
| 1591 | nvme_show_result("Created Element Identifier for Endurance Group is: %"nvme_show_message(0, "Created Element Identifier for Endurance Group is: %" "l" "u", (uint64_t)cmd.result) | |||
| 1592 | PRIu64, (uint64_t)cmd.result)nvme_show_message(0, "Created Element Identifier for Endurance Group is: %" "l" "u", (uint64_t)cmd.result); | |||
| 1593 | else if (cfg.operation == 3) | |||
| 1594 | nvme_show_result("Created Element Identifier for NVM Set is: %"nvme_show_message(0, "Created Element Identifier for NVM Set is: %" "l" "u", (uint64_t)cmd.result) | |||
| 1595 | PRIu64, (uint64_t)cmd.result)nvme_show_message(0, "Created Element Identifier for NVM Set is: %" "l" "u", (uint64_t)cmd.result); | |||
| 1596 | ||||
| 1597 | return err; | |||
| 1598 | } | |||
| 1599 | ||||
| 1600 | static struct command dsm_cmd = { | |||
| 1601 | .name = "dsm", | |||
| 1602 | .help = "Submit a Data Set Management command, return results", | |||
| 1603 | .fn = dsm, | |||
| 1604 | }; | |||
| 1605 | ||||
| 1606 | static struct command copy_cmd_cmd = { | |||
| 1607 | .name = "copy", | |||
| 1608 | .help = "Submit a Simple Copy command, return results", | |||
| 1609 | .fn = copy_cmd, | |||
| 1610 | }; | |||
| 1611 | ||||
| 1612 | static struct command flush_cmd_cmd = { | |||
| 1613 | .name = "flush", | |||
| 1614 | .help = "Submit a Flush command, return results", | |||
| 1615 | .fn = flush_cmd, | |||
| 1616 | }; | |||
| 1617 | ||||
| 1618 | static struct command compare_cmd = { | |||
| 1619 | .name = "compare", | |||
| 1620 | .help = "Submit a Compare command, return results", | |||
| 1621 | .fn = compare, | |||
| 1622 | }; | |||
| 1623 | ||||
| 1624 | static struct command read_cmd_cmd = { | |||
| 1625 | .name = "read", | |||
| 1626 | .help = "Submit a read command, return results", | |||
| 1627 | .fn = read_cmd, | |||
| 1628 | }; | |||
| 1629 | ||||
| 1630 | static struct command write_cmd_cmd = { | |||
| 1631 | .name = "write", | |||
| 1632 | .help = "Submit a write command, return results", | |||
| 1633 | .fn = write_cmd, | |||
| 1634 | }; | |||
| 1635 | ||||
| 1636 | static struct command write_zeroes_cmd = { | |||
| 1637 | .name = "write-zeroes", | |||
| 1638 | .help = "Submit a write zeroes command, return results", | |||
| 1639 | .fn = write_zeroes, | |||
| 1640 | }; | |||
| 1641 | ||||
| 1642 | static struct command write_uncor_cmd = { | |||
| 1643 | .name = "write-uncor", | |||
| 1644 | .help = "Submit a write uncorrectable command, return results", | |||
| 1645 | .fn = write_uncor, | |||
| 1646 | }; | |||
| 1647 | ||||
| 1648 | static struct command verify_cmd_cmd = { | |||
| 1649 | .name = "verify", | |||
| 1650 | .help = "Submit a verify command, return results", | |||
| 1651 | .fn = verify_cmd, | |||
| 1652 | }; | |||
| 1653 | ||||
| 1654 | static struct command get_lba_status_cmd = { | |||
| 1655 | .name = "get-lba-status", | |||
| 1656 | .help = "Submit a Get LBA Status command, return results", | |||
| 1657 | .fn = get_lba_status, | |||
| 1658 | }; | |||
| 1659 | ||||
| 1660 | static struct command capacity_mgmt_cmd = { | |||
| 1661 | .name = "capacity-mgmt", | |||
| 1662 | .help = "Submit Capacity Management Command, return results", | |||
| 1663 | .fn = capacity_mgmt, | |||
| 1664 | }; | |||
| 1665 | ||||
| 1666 | static struct command *commands[] = { | |||
| 1667 | &dsm_cmd, | |||
| 1668 | ©_cmd_cmd, | |||
| 1669 | &flush_cmd_cmd, | |||
| 1670 | &compare_cmd, | |||
| 1671 | &read_cmd_cmd, | |||
| 1672 | &write_cmd_cmd, | |||
| 1673 | &write_zeroes_cmd, | |||
| 1674 | &write_uncor_cmd, | |||
| 1675 | &verify_cmd_cmd, | |||
| 1676 | &get_lba_status_cmd, | |||
| 1677 | &capacity_mgmt_cmd, | |||
| 1678 | NULL((void*)0), | |||
| 1679 | }; | |||
| 1680 | ||||
| 1681 | static void __shr_constructor__attribute__((constructor)) register_group(void) | |||
| 1682 | { | |||
| 1683 | plugin_add_group(&builtin, "I/O Commands", commands); | |||
| 1684 | } |