4 * Copyright (c) Eideticom Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Eideticom Inc, nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include "spdk/stdinc.h"
37 #include "spdk/nvme.h"
38 #include "spdk/string.h"
40 #define CMB_COPY_DELIM "-"
41 #define CMB_COPY_READ 0
42 #define CMB_COPY_WRITE 1
45 struct spdk_nvme_ctrlr
*ctrlr
;
46 struct spdk_nvme_transport_id trid
;
47 struct spdk_nvme_qpair
*qpair
;
48 struct spdk_nvme_ns
*ns
;
57 struct spdk_nvme_transport_id trid
;
58 struct spdk_nvme_ctrlr
*ctrlr
;
68 static struct config g_config
;
70 /* Namespaces index from 1. Return 0 to invoke an error */
72 get_nsid(const struct spdk_nvme_transport_id
*trid
)
74 if (!strcmp(trid
->traddr
, g_config
.read
.trid
.traddr
)) {
75 return g_config
.read
.nsid
;
77 if (!strcmp(trid
->traddr
, g_config
.write
.trid
.traddr
)) {
78 return g_config
.write
.nsid
;
84 get_rw(const struct spdk_nvme_transport_id
*trid
)
86 if (!strcmp(trid
->traddr
, g_config
.read
.trid
.traddr
)) {
89 if (!strcmp(trid
->traddr
, g_config
.write
.trid
.traddr
)) {
90 return CMB_COPY_WRITE
;
96 check_io(void *arg
, const struct spdk_nvme_cpl
*completion
)
98 int *rw
= (unsigned *)arg
;
100 if (*rw
== CMB_COPY_READ
) {
101 g_config
.read
.done
= 1;
103 g_config
.write
.done
= 1;
114 /* Allocate QPs for the read and write controllers */
115 g_config
.read
.qpair
= spdk_nvme_ctrlr_alloc_io_qpair(g_config
.read
.ctrlr
, NULL
, 0);
116 g_config
.write
.qpair
= spdk_nvme_ctrlr_alloc_io_qpair(g_config
.write
.ctrlr
, NULL
, 0);
117 if (g_config
.read
.qpair
== NULL
|| g_config
.read
.qpair
== NULL
) {
118 printf("ERROR: spdk_nvme_ctrlr_alloc_io_qpair() failed\n");
122 /* Allocate a buffer from our CMB */
123 buf
= spdk_nvme_ctrlr_map_cmb(g_config
.cmb
.ctrlr
, &sz
);
124 if (buf
== NULL
|| sz
< g_config
.copy_size
) {
125 printf("ERROR: buffer allocation failed\n");
126 printf("Are you sure %s has a valid CMB?\n",
127 g_config
.cmb
.trid
.traddr
);
131 /* Clear the done flags */
132 g_config
.read
.done
= 0;
133 g_config
.write
.done
= 0;
136 /* Do the read to the CMB IO buffer */
137 rc
= spdk_nvme_ns_cmd_read(g_config
.read
.ns
, g_config
.read
.qpair
, buf
,
138 g_config
.read
.slba
, g_config
.read
.nlbas
,
141 fprintf(stderr
, "starting read I/O failed\n");
144 while (!g_config
.read
.done
) {
145 spdk_nvme_qpair_process_completions(g_config
.read
.qpair
, 0);
148 /* Do the write from the CMB IO buffer */
150 rc
= spdk_nvme_ns_cmd_write(g_config
.write
.ns
, g_config
.write
.qpair
, buf
,
151 g_config
.write
.slba
, g_config
.write
.nlbas
,
154 fprintf(stderr
, "starting write I/O failed\n");
157 while (!g_config
.write
.done
) {
158 spdk_nvme_qpair_process_completions(g_config
.write
.qpair
, 0);
161 /* Clear the done flags */
162 g_config
.read
.done
= 0;
163 g_config
.write
.done
= 0;
165 /* Free CMB buffer */
166 spdk_nvme_ctrlr_unmap_cmb(g_config
.cmb
.ctrlr
);
168 /* Free the queues */
169 spdk_nvme_ctrlr_free_io_qpair(g_config
.read
.qpair
);
170 spdk_nvme_ctrlr_free_io_qpair(g_config
.write
.qpair
);
176 probe_cb(void *cb_ctx
, const struct spdk_nvme_transport_id
*trid
,
177 struct spdk_nvme_ctrlr_opts
*opts
)
179 /* We will only attach to the read or write controller */
180 if (strcmp(trid
->traddr
, g_config
.read
.trid
.traddr
) &&
181 strcmp(trid
->traddr
, g_config
.write
.trid
.traddr
)) {
182 printf("%s - not probed %s!\n", __func__
, trid
->traddr
);
186 opts
->use_cmb_sqs
= false;
188 printf("%s - probed %s!\n", __func__
, trid
->traddr
);
193 attach_cb(void *cb_ctx
, const struct spdk_nvme_transport_id
*trid
,
194 struct spdk_nvme_ctrlr
*ctrlr
, const struct spdk_nvme_ctrlr_opts
*opts
)
196 struct spdk_nvme_ns
*ns
;
198 ns
= spdk_nvme_ctrlr_get_ns(ctrlr
, get_nsid(trid
));
200 fprintf(stderr
, "Could not locate namespace %d on controller %s.\n",
201 get_nsid(trid
), trid
->traddr
);
204 if (get_rw(trid
) == CMB_COPY_READ
) {
205 g_config
.read
.ctrlr
= ctrlr
;
206 g_config
.read
.ns
= ns
;
207 g_config
.read
.lba_size
= spdk_nvme_ns_get_sector_size(ns
);
209 g_config
.write
.ctrlr
= ctrlr
;
210 g_config
.write
.ns
= ns
;
211 g_config
.write
.lba_size
= spdk_nvme_ns_get_sector_size(ns
);
213 printf("%s - attached %s!\n", __func__
, trid
->traddr
);
219 usage(char *program_name
)
221 printf("%s options (all mandatory)", program_name
);
223 printf("\t[-r NVMe read parameters]\n");
224 printf("\t[-w NVMe write parameters]\n");
225 printf("\t[-c CMB to use for data buffers]\n");
227 printf("Read/Write params:\n");
228 printf(" <pci id>-<namespace>-<start LBA>-<number of LBAs>\n");
232 parse(char *in
, struct nvme_io
*io
)
237 tok
= strtok(in
, CMB_COPY_DELIM
);
241 snprintf(&io
->trid
.traddr
[0], SPDK_NVMF_TRADDR_MAX_LEN
+ 1,
244 tok
= strtok(NULL
, CMB_COPY_DELIM
);
248 val
= spdk_strtol(tok
, 10);
252 io
->nsid
= (unsigned)val
;
254 tok
= strtok(NULL
, CMB_COPY_DELIM
);
258 val
= spdk_strtol(tok
, 10);
262 io
->slba
= (unsigned)val
;
264 tok
= strtok(NULL
, CMB_COPY_DELIM
);
268 val
= spdk_strtol(tok
, 10);
272 io
->nlbas
= (unsigned)val
;
274 tok
= strtok(NULL
, CMB_COPY_DELIM
);
281 fprintf(stderr
, "%s: error parsing %s\n", __func__
, in
);
287 parse_args(int argc
, char **argv
)
290 unsigned read
= 0, write
= 0, cmb
= 0;
292 while ((op
= getopt(argc
, argv
, "r:w:c:")) != -1) {
295 parse(optarg
, &g_config
.read
);
299 parse(optarg
, &g_config
.write
);
303 snprintf(g_config
.cmb
.trid
.traddr
, SPDK_NVMF_TRADDR_MAX_LEN
+ 1,
313 if ((!read
|| !write
|| !cmb
)) {
321 int main(int argc
, char **argv
)
324 struct spdk_env_opts opts
;
327 * Parse the input arguments. For now we use the following
330 * <pci id>-<namespace>-<start LBA>-<number of LBAs>
333 rc
= parse_args(argc
, argv
);
335 fprintf(stderr
, "Error in parse_args(): %d\n",
341 * SPDK relies on an abstraction around the local environment
342 * named env that handles memory allocation and PCI device operations.
343 * This library must be initialized first.
346 spdk_env_opts_init(&opts
);
347 opts
.name
= "cmb_copy";
349 if (spdk_env_init(&opts
) < 0) {
350 fprintf(stderr
, "Unable to initialize SPDK env\n");
355 * CMBs only apply to PCIe attached NVMe controllers so we
356 * only probe the PCIe bus. This is the default when we pass
357 * in NULL for the first argument.
360 rc
= spdk_nvme_probe(NULL
, NULL
, probe_cb
, attach_cb
, NULL
);
362 fprintf(stderr
, "Error in spdk_nvme_probe(): %d\n",
368 * For now enforce that the read and write controller are not
369 * the same. This avoids an internal only DMA.
371 if (!strcmp(g_config
.write
.trid
.traddr
, g_config
.read
.trid
.traddr
)) {
372 fprintf(stderr
, "Read and Write controllers must differ!\n");
377 * Perform a few sanity checks and set the buffer size for the
380 if (g_config
.read
.nlbas
* g_config
.read
.lba_size
!=
381 g_config
.write
.nlbas
* g_config
.write
.lba_size
) {
382 fprintf(stderr
, "Read and write sizes do not match!\n");
385 g_config
.copy_size
= g_config
.read
.nlbas
* g_config
.read
.lba_size
;
388 * Get the ctrlr pointer for the CMB. For now we assume this
389 * is either the read or write NVMe controller though in
390 * theory that is not a necessary condition.
393 if (!strcmp(g_config
.cmb
.trid
.traddr
, g_config
.read
.trid
.traddr
)) {
394 g_config
.cmb
.ctrlr
= g_config
.read
.ctrlr
;
396 if (!strcmp(g_config
.cmb
.trid
.traddr
, g_config
.write
.trid
.traddr
)) {
397 g_config
.cmb
.ctrlr
= g_config
.write
.ctrlr
;
401 * Call the cmb_copy() function which performs the CMB
402 * based copy or returns an error code if it fails.
406 fprintf(stderr
, "Error in spdk_cmb_copy(): %d\n",