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 long int val; 209 210 tok = strtok(in, CMB_COPY_DELIM); 211 if (tok == NULL) { 212 goto err; 213 } 214 snprintf(&io->trid.traddr[0], SPDK_NVMF_TRADDR_MAX_LEN + 1, 215 "%s", tok); 216 217 tok = strtok(NULL, CMB_COPY_DELIM); 218 if (tok == NULL) { 219 goto err; 220 } 221 val = spdk_strtol(tok, 10); 222 if (val < 0) { 223 goto err; 224 } 225 io->nsid = (unsigned)val; 226 227 tok = strtok(NULL, CMB_COPY_DELIM); 228 if (tok == NULL) { 229 goto err; 230 } 231 val = spdk_strtol(tok, 10); 232 if (val < 0) { 233 goto err; 234 } 235 io->slba = (unsigned)val; 236 237 tok = strtok(NULL, CMB_COPY_DELIM); 238 if (tok == NULL) { 239 goto err; 240 } 241 val = spdk_strtol(tok, 10); 242 if (val < 0) { 243 goto err; 244 } 245 io->nlbas = (unsigned)val; 246 247 tok = strtok(NULL, CMB_COPY_DELIM); 248 if (tok != NULL) { 249 goto err; 250 } 251 return; 252 253 err: 254 fprintf(stderr, "%s: error parsing %s\n", __func__, in); 255 exit(-1); 256 257 } 258 259 static int 260 parse_args(int argc, char **argv) 261 { 262 int op; 263 unsigned read = 0, write = 0, cmb = 0; 264 265 while ((op = getopt(argc, argv, "r:w:c:")) != -1) { 266 switch (op) { 267 case 'r': 268 parse(optarg, &g_config.read); 269 read = 1; 270 break; 271 case 'w': 272 parse(optarg, &g_config.write); 273 write = 1; 274 break; 275 case 'c': 276 snprintf(g_config.cmb.trid.traddr, SPDK_NVMF_TRADDR_MAX_LEN + 1, 277 "%s", optarg); 278 cmb = 1; 279 break; 280 default: 281 usage(argv[0]); 282 return 1; 283 } 284 } 285 286 if ((!read || !write || !cmb)) { 287 usage(argv[0]); 288 return 1; 289 } 290 291 return 0; 292 } 293 294 int 295 main(int argc, char **argv) 296 { 297 int rc = 0; 298 struct spdk_env_opts opts; 299 300 /* 301 * Parse the input arguments. For now we use the following 302 * format list: 303 * 304 * <pci id>-<namespace>-<start LBA>-<number of LBAs> 305 * 306 */ 307 rc = parse_args(argc, argv); 308 if (rc) { 309 fprintf(stderr, "Error in parse_args(): %d\n", 310 rc); 311 return -1; 312 } 313 314 /* 315 * SPDK relies on an abstraction around the local environment 316 * named env that handles memory allocation and PCI device operations. 317 * This library must be initialized first. 318 * 319 */ 320 opts.opts_size = sizeof(opts); 321 spdk_env_opts_init(&opts); 322 opts.name = "cmb_copy"; 323 opts.shm_id = 0; 324 if (spdk_env_init(&opts) < 0) { 325 fprintf(stderr, "Unable to initialize SPDK env\n"); 326 return 1; 327 } 328 329 /* 330 * CMBs only apply to PCIe attached NVMe controllers so we 331 * only probe the PCIe bus. This is the default when we pass 332 * in NULL for the first argument. 333 */ 334 335 rc = spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL); 336 if (rc) { 337 fprintf(stderr, "Error in spdk_nvme_probe(): %d\n", 338 rc); 339 return -1; 340 } 341 342 /* 343 * For now enforce that the read and write controller are not 344 * the same. This avoids an internal only DMA. 345 */ 346 if (!strcmp(g_config.write.trid.traddr, g_config.read.trid.traddr)) { 347 fprintf(stderr, "Read and Write controllers must differ!\n"); 348 return -1; 349 } 350 351 /* 352 * Perform a few sanity checks and set the buffer size for the 353 * CMB. 354 */ 355 if (g_config.read.nlbas * g_config.read.lba_size != 356 g_config.write.nlbas * g_config.write.lba_size) { 357 fprintf(stderr, "Read and write sizes do not match!\n"); 358 return -1; 359 } 360 g_config.copy_size = g_config.read.nlbas * g_config.read.lba_size; 361 362 /* 363 * Get the ctrlr pointer for the CMB. For now we assume this 364 * is either the read or write NVMe controller though in 365 * theory that is not a necessary condition. 366 */ 367 368 if (!strcmp(g_config.cmb.trid.traddr, g_config.read.trid.traddr)) { 369 g_config.cmb.ctrlr = g_config.read.ctrlr; 370 } 371 if (!strcmp(g_config.cmb.trid.traddr, g_config.write.trid.traddr)) { 372 g_config.cmb.ctrlr = g_config.write.ctrlr; 373 } 374 375 if (!g_config.read.ctrlr || !g_config.write.ctrlr) { 376 fprintf(stderr, "No NVMe controller that support CMB was found!\n"); 377 return -1; 378 } 379 380 /* 381 * Call the cmb_copy() function which performs the CMB 382 * based copy or returns an error code if it fails. 383 */ 384 rc = cmb_copy(); 385 if (rc) { 386 fprintf(stderr, "Error in spdk_cmb_copy(): %d\n", 387 rc); 388 return -1; 389 } 390 391 return rc; 392 } 393