Bug Summary

File:.build-ci/../src/nvme-cmds-io.c
Warning:line 1224, column 11
Potential leak of memory pointed to by 'mbuffer'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -O3 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name nvme-cmds-io.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -fcoverage-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -resource-dir /usr/bin/../lib/clang/22 -include /__w/nvme-cli/nvme-cli/.build-ci/nvme-config.h -I nvme.p -I . -I .. -I src -I ../src -I ccan -I ../ccan -I libnvme/src -I ../libnvme/src -I /usr/include/json-c -D _FILE_OFFSET_BITS=64 -D _GNU_SOURCE -U NDEBUG -internal-isystem /usr/bin/../lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=gnu11 -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-opt-analyze-headers -analyzer-output=html -faddrsig -fdwarf2-cfi-asm -o /__w/nvme-cli/nvme-cli/.build-ci/scan-results/2026-10-24-125112-639-1 -x c ../src/nvme-cmds-io.c
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
51static const char *app_tag = "app tag for end-to-end PI";
52static const char *app_tag_mask = "app tag mask for end-to-end PI";
53static const char *block_count = "number of blocks (zeroes based) on device to access";
54static const char *dspec_w_dtype = "directive specification associated with directive type";
55static const char *dtype = "directive type";
56static const char *force_unit_access = "force device to commit data before command completes";
57static const char *latency = "output latency statistics";
58static const char *limited_retry = "limit media access attempts";
59static const char *namespace_desired = "desired namespace";
60static const char *prinfo = "PI and check field";
61static const char *ref_tag = "reference tag for end-to-end PI";
62static const char *start_block = "64-bit LBA of first block to access";
63static const char *storage_tag = "storage tag for end-to-end PI";
64static 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";
66static const char *ish = "Ignore Shutdown (for NVMe-MI command)";
67
68static 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
103static 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
169static 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
221static 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
250static 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
264static 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
295static 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
312static 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
392static 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
438static 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
571static 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
682static 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
900static 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
957static 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
1.1
'opcode' is not equal to nvme_cmd_write
!= nvme_cmd_write) {
2
Taking true branch
1076 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
1077 if (err)
3
Assuming 'err' is 0
4
Taking false branch
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) {
5
Assuming field 'nsid' is not equal to 0
6
Taking false branch
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)
7
Assuming field 'prinfo' is <= 15
8
Taking false branch
1106 return -EINVAL22;
1107
1108 dsmgmt = cfg.dsmgmt;
1109 control |= (cfg.prinfo << 10);
1110 if (cfg.limited_retry)
9
Assuming field 'limited_retry' is false
10
Taking false branch
1111 control |= NVME_IO_LR;
1112 if (cfg.force_unit_access)
11
Assuming field 'force_unit_access' is false
12
Taking false branch
1113 control |= NVME_IO_FUA;
1114 if (cfg.stc)
13
Assuming field 'stc' is false
14
Taking false branch
1115 control |= NVME_IO_STC;
1116 if (cfg.dtype) {
15
Assuming field 'dtype' is 0
16
Taking false branch
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) {
17
Taking true branch
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)) {
18
Assuming the condition is false
19
Taking false branch
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)) {
20
Assuming the condition is false
21
Taking false branch
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) {
22
Assuming field 'data_size' is not equal to 0
23
Taking false branch
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) {
24
Assuming field 'block_size' is not equal to 0
25
Taking true branch
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)
26
Assuming 'buffer_size' is <= field 'data_size'
27
Taking false branch
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)) {
28
Assuming the condition is true
29
Taking true branch
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) {
30
Assuming 'buffer' is non-null
31
Taking false branch
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) {
32
Assuming field 'metadata_size' is not equal to 0
33
Taking true branch
1208 mbuffer_size = ((unsigned long long)cfg.block_count + 1) * ms;
1209 if (ms
33.1
'ms' is not equal to 0
&& cfg.metadata_size < mbuffer_size)
34
Assuming 'mbuffer_size' is > field 'metadata_size'
35
Taking true branch
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);
36
Memory is allocated
1216 if (!mbuffer)
37
Assuming 'mbuffer' is non-null
38
Taking false branch
1217 return -ENOMEM12;
1218 memset(mbuffer, 0, mbuffer_size);
1219 }
1220
1221 if (opcode & 1) {
39
Taking true branch
1222 err = read(dfd, (void *)buffer, cfg.data_size);
1223 if (err < 0) {
40
Assuming 'err' is < 0
41
Taking true branch
1224 err = -errno(*__errno_location ());
42
Potential leak of memory pointed to by 'mbuffer'
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
1308static 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);
1
Calling 'submit_io'
1315}
1316
1317static 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
1325static 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
1333static 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
1437static 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
1522static 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
1600static struct command dsm_cmd = {
1601 .name = "dsm",
1602 .help = "Submit a Data Set Management command, return results",
1603 .fn = dsm,
1604};
1605
1606static struct command copy_cmd_cmd = {
1607 .name = "copy",
1608 .help = "Submit a Simple Copy command, return results",
1609 .fn = copy_cmd,
1610};
1611
1612static struct command flush_cmd_cmd = {
1613 .name = "flush",
1614 .help = "Submit a Flush command, return results",
1615 .fn = flush_cmd,
1616};
1617
1618static struct command compare_cmd = {
1619 .name = "compare",
1620 .help = "Submit a Compare command, return results",
1621 .fn = compare,
1622};
1623
1624static struct command read_cmd_cmd = {
1625 .name = "read",
1626 .help = "Submit a read command, return results",
1627 .fn = read_cmd,
1628};
1629
1630static struct command write_cmd_cmd = {
1631 .name = "write",
1632 .help = "Submit a write command, return results",
1633 .fn = write_cmd,
1634};
1635
1636static struct command write_zeroes_cmd = {
1637 .name = "write-zeroes",
1638 .help = "Submit a write zeroes command, return results",
1639 .fn = write_zeroes,
1640};
1641
1642static struct command write_uncor_cmd = {
1643 .name = "write-uncor",
1644 .help = "Submit a write uncorrectable command, return results",
1645 .fn = write_uncor,
1646};
1647
1648static struct command verify_cmd_cmd = {
1649 .name = "verify",
1650 .help = "Submit a verify command, return results",
1651 .fn = verify_cmd,
1652};
1653
1654static 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
1660static struct command capacity_mgmt_cmd = {
1661 .name = "capacity-mgmt",
1662 .help = "Submit Capacity Management Command, return results",
1663 .fn = capacity_mgmt,
1664};
1665
1666static struct command *commands[] = {
1667 &dsm_cmd,
1668 &copy_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
1681static void __shr_constructor__attribute__((constructor)) register_group(void)
1682{
1683 plugin_add_group(&builtin, "I/O Commands", commands);
1684}