1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2020 Intel Corporation. 3 * Copyright (c) Eideticom Inc. 4 * All rights reserved. 5 */ 6 7 #include "spdk/stdinc.h" 8 9 #include "spdk/env.h" 10 #include "spdk/nvme.h" 11 #include "spdk/string.h" 12 13 #define CMB_COPY_DELIM "-" 14 #define CMB_COPY_READ 0 15 #define CMB_COPY_WRITE 1 16 17 struct nvme_io { 18 struct spdk_nvme_ctrlr *ctrlr; 19 struct spdk_nvme_transport_id trid; 20 struct spdk_nvme_qpair *qpair; 21 struct spdk_nvme_ns *ns; 22 unsigned nsid; 23 unsigned slba; 24 unsigned nlbas; 25 uint32_t lba_size; 26 unsigned done; 27 }; 28 29 struct cmb_t { 30 struct spdk_nvme_transport_id trid; 31 struct spdk_nvme_ctrlr *ctrlr; 32 }; 33 34 struct config { 35 struct nvme_io read; 36 struct nvme_io write; 37 struct cmb_t cmb; 38 size_t copy_size; 39 }; 40 41 static struct config g_config; 42 43 /* Namespaces index from 1. Return 0 to invoke an error */ 44 static unsigned 45 get_nsid(const struct spdk_nvme_transport_id *trid) 46 { 47 if (!strcmp(trid->traddr, g_config.read.trid.traddr)) { 48 return g_config.read.nsid; 49 } 50 if (!strcmp(trid->traddr, g_config.write.trid.traddr)) { 51 return g_config.write.nsid; 52 } 53 return 0; 54 } 55 56 static int 57 get_rw(const struct spdk_nvme_transport_id *trid) 58 { 59 if (!strcmp(trid->traddr, g_config.read.trid.traddr)) { 60 return CMB_COPY_READ; 61 } 62 if (!strcmp(trid->traddr, g_config.write.trid.traddr)) { 63 return CMB_COPY_WRITE; 64 } 65 return -1; 66 } 67 68 static void 69 check_io(void *arg, const struct spdk_nvme_cpl *completion) 70 { 71 int *rw = (unsigned *)arg; 72 73 if (*rw == CMB_COPY_READ) { 74 g_config.read.done = 1; 75 } else { 76 g_config.write.done = 1; 77 } 78 } 79 80 static int 81 cmb_copy(void) 82 { 83 int rc = 0, rw; 84 void *buf; 85 size_t sz; 86 87 /* Allocate QPs for the read and write controllers */ 88 g_config.read.qpair = spdk_nvme_ctrlr_alloc_io_qpair(g_config.read.ctrlr, NULL, 0); 89 g_config.write.qpair = spdk_nvme_ctrlr_alloc_io_qpair(g_config.write.ctrlr, NULL, 0); 90 if (g_config.read.qpair == NULL || g_config.read.qpair == NULL) { 91 printf("ERROR: spdk_nvme_ctrlr_alloc_io_qpair() failed\n"); 92 return -ENOMEM; 93 } 94 95 /* Allocate a buffer from our CMB */ 96 buf = spdk_nvme_ctrlr_map_cmb(g_config.cmb.ctrlr, &sz); 97 if (buf == NULL || sz < g_config.copy_size) { 98 printf("ERROR: buffer allocation failed\n"); 99 printf("Are you sure %s has a valid CMB?\n", 100 g_config.cmb.trid.traddr); 101 return -ENOMEM; 102 } 103 104 /* Clear the done flags */ 105 g_config.read.done = 0; 106 g_config.write.done = 0; 107 108 rw = CMB_COPY_READ; 109 /* Do the read to the CMB IO buffer */ 110 rc = spdk_nvme_ns_cmd_read(g_config.read.ns, g_config.read.qpair, buf, 111 g_config.read.slba, g_config.read.nlbas, 112 check_io, &rw, 0); 113 if (rc != 0) { 114 fprintf(stderr, "starting read I/O failed\n"); 115 return -EIO; 116 } 117 while (!g_config.read.done) { 118 spdk_nvme_qpair_process_completions(g_config.read.qpair, 0); 119 } 120 121 /* Do the write from the CMB IO buffer */ 122 rw = CMB_COPY_WRITE; 123 rc = spdk_nvme_ns_cmd_write(g_config.write.ns, g_config.write.qpair, buf, 124 g_config.write.slba, g_config.write.nlbas, 125 check_io, &rw, 0); 126 if (rc != 0) { 127 fprintf(stderr, "starting write I/O failed\n"); 128 return -EIO; 129 } 130 while (!g_config.write.done) { 131 spdk_nvme_qpair_process_completions(g_config.write.qpair, 0); 132 } 133 134 /* Clear the done flags */ 135 g_config.read.done = 0; 136 g_config.write.done = 0; 137 138 /* Free CMB buffer */ 139 spdk_nvme_ctrlr_unmap_cmb(g_config.cmb.ctrlr); 140 141 /* Free the queues */ 142 spdk_nvme_ctrlr_free_io_qpair(g_config.read.qpair); 143 spdk_nvme_ctrlr_free_io_qpair(g_config.write.qpair); 144 145 return rc; 146 } 147 148 static bool 149 probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid, 150 struct spdk_nvme_ctrlr_opts *opts) 151 { 152 /* We will only attach to the read or write controller */ 153 if (strcmp(trid->traddr, g_config.read.trid.traddr) && 154 strcmp(trid->traddr, g_config.write.trid.traddr)) { 155 printf("%s - not probed %s!\n", __func__, trid->traddr); 156 return 0; 157 } 158 159 opts->use_cmb_sqs = false; 160 161 printf("%s - probed %s!\n", __func__, trid->traddr); 162 return 1; 163 } 164 165 static void 166 attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid, 167 struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts) 168 { 169 struct spdk_nvme_ns *ns; 170 171 ns = spdk_nvme_ctrlr_get_ns(ctrlr, get_nsid(trid)); 172 if (ns == NULL) { 173 fprintf(stderr, "Could not locate namespace %d on controller %s.\n", 174 get_nsid(trid), trid->traddr); 175 exit(-1); 176 } 177 if (get_rw(trid) == CMB_COPY_READ) { 178 g_config.read.ctrlr = ctrlr; 179 g_config.read.ns = ns; 180 g_config.read.lba_size = spdk_nvme_ns_get_sector_size(ns); 181 } else { 182 g_config.write.ctrlr = ctrlr; 183 g_config.write.ns = ns; 184 g_config.write.lba_size = spdk_nvme_ns_get_sector_size(ns); 185 } 186 printf("%s - attached %s!\n", __func__, trid->traddr); 187 188 return; 189 } 190 191 static void 192 usage(char *program_name) 193 { 194 printf("%s options (all mandatory)", program_name); 195 printf("\n"); 196 printf("\t[-r NVMe read parameters]\n"); 197 printf("\t[-w NVMe write parameters]\n"); 198 printf("\t[-c CMB to use for data buffers]\n"); 199 printf("\n"); 200 printf("Read/Write params:\n"); 201 printf(" <pci id>-<namespace>-<start LBA>-<number of LBAs>\n"); 202 } 203 204 static void 205 parse(char *in, struct nvme_io *io) 206 { 207 char *tok = NULL; 208 char *sp = NULL; 209 long int val; 210 211 tok = strtok_r(in, CMB_COPY_DELIM, &sp); 212 if (tok == NULL) { 213 goto err; 214 } 215 snprintf(&io->trid.traddr[0], SPDK_NVMF_TRADDR_MAX_LEN + 1, 216 "%s", tok); 217 218 tok = strtok_r(NULL, CMB_COPY_DELIM, &sp); 219 if (tok == NULL) { 220 goto err; 221 } 222 val = spdk_strtol(tok, 10); 223 if (val < 0) { 224 goto err; 225 } 226 io->nsid = (unsigned)val; 227 228 tok = strtok_r(NULL, CMB_COPY_DELIM, &sp); 229 if (tok == NULL) { 230 goto err; 231 } 232 val = spdk_strtol(tok, 10); 233 if (val < 0) { 234 goto err; 235 } 236 io->slba = (unsigned)val; 237 238 tok = strtok_r(NULL, CMB_COPY_DELIM, &sp); 239 if (tok == NULL) { 240 goto err; 241 } 242 val = spdk_strtol(tok, 10); 243 if (val < 0) { 244 goto err; 245 } 246 io->nlbas = (unsigned)val; 247 248 tok = strtok_r(NULL, CMB_COPY_DELIM, &sp); 249 if (tok != NULL) { 250 goto err; 251 } 252 return; 253 254 err: 255 fprintf(stderr, "%s: error parsing %s\n", __func__, in); 256 exit(-1); 257 258 } 259 260 static int 261 parse_args(int argc, char **argv) 262 { 263 int op; 264 unsigned read = 0, write = 0, cmb = 0; 265 266 while ((op = getopt(argc, argv, "r:w:c:")) != -1) { 267 switch (op) { 268 case 'r': 269 parse(optarg, &g_config.read); 270 read = 1; 271 break; 272 case 'w': 273 parse(optarg, &g_config.write); 274 write = 1; 275 break; 276 case 'c': 277 snprintf(g_config.cmb.trid.traddr, SPDK_NVMF_TRADDR_MAX_LEN + 1, 278 "%s", optarg); 279 cmb = 1; 280 break; 281 default: 282 usage(argv[0]); 283 return 1; 284 } 285 } 286 287 if ((!read || !write || !cmb)) { 288 usage(argv[0]); 289 return 1; 290 } 291 292 return 0; 293 } 294 295 int 296 main(int argc, char **argv) 297 { 298 int rc = 0; 299 struct spdk_env_opts opts; 300 301 /* 302 * Parse the input arguments. For now we use the following 303 * format list: 304 * 305 * <pci id>-<namespace>-<start LBA>-<number of LBAs> 306 * 307 */ 308 rc = parse_args(argc, argv); 309 if (rc) { 310 fprintf(stderr, "Error in parse_args(): %d\n", 311 rc); 312 return -1; 313 } 314 315 /* 316 * SPDK relies on an abstraction around the local environment 317 * named env that handles memory allocation and PCI device operations. 318 * This library must be initialized first. 319 * 320 */ 321 opts.opts_size = sizeof(opts); 322 spdk_env_opts_init(&opts); 323 opts.name = "cmb_copy"; 324 opts.shm_id = 0; 325 if (spdk_env_init(&opts) < 0) { 326 fprintf(stderr, "Unable to initialize SPDK env\n"); 327 return 1; 328 } 329 330 /* 331 * CMBs only apply to PCIe attached NVMe controllers so we 332 * only probe the PCIe bus. This is the default when we pass 333 * in NULL for the first argument. 334 */ 335 336 rc = spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL); 337 if (rc) { 338 fprintf(stderr, "Error in spdk_nvme_probe(): %d\n", 339 rc); 340 return -1; 341 } 342 343 /* 344 * For now enforce that the read and write controller are not 345 * the same. This avoids an internal only DMA. 346 */ 347 if (!strcmp(g_config.write.trid.traddr, g_config.read.trid.traddr)) { 348 fprintf(stderr, "Read and Write controllers must differ!\n"); 349 return -1; 350 } 351 352 /* 353 * Perform a few sanity checks and set the buffer size for the 354 * CMB. 355 */ 356 if (g_config.read.nlbas * g_config.read.lba_size != 357 g_config.write.nlbas * g_config.write.lba_size) { 358 fprintf(stderr, "Read and write sizes do not match!\n"); 359 return -1; 360 } 361 g_config.copy_size = g_config.read.nlbas * g_config.read.lba_size; 362 363 /* 364 * Get the ctrlr pointer for the CMB. For now we assume this 365 * is either the read or write NVMe controller though in 366 * theory that is not a necessary condition. 367 */ 368 369 if (!strcmp(g_config.cmb.trid.traddr, g_config.read.trid.traddr)) { 370 g_config.cmb.ctrlr = g_config.read.ctrlr; 371 } 372 if (!strcmp(g_config.cmb.trid.traddr, g_config.write.trid.traddr)) { 373 g_config.cmb.ctrlr = g_config.write.ctrlr; 374 } 375 376 if (!g_config.read.ctrlr || !g_config.write.ctrlr) { 377 fprintf(stderr, "No NVMe controller that support CMB was found!\n"); 378 return -1; 379 } 380 381 /* 382 * Call the cmb_copy() function which performs the CMB 383 * based copy or returns an error code if it fails. 384 */ 385 rc = cmb_copy(); 386 if (rc) { 387 fprintf(stderr, "Error in spdk_cmb_copy(): %d\n", 388 rc); 389 return -1; 390 } 391 392 return rc; 393 } 394