1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2018 Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "spdk/stdinc.h" 7 8 #include "spdk/log.h" 9 #include "spdk/nvme.h" 10 #include "spdk/env.h" 11 12 #define MAX_DEVS 64 13 14 struct dev { 15 bool error_expected; 16 struct spdk_nvme_ctrlr *ctrlr; 17 struct spdk_nvme_ns *ns; 18 struct spdk_nvme_qpair *qpair; 19 void *data; 20 char name[SPDK_NVMF_TRADDR_MAX_LEN + 1]; 21 }; 22 23 static struct dev devs[MAX_DEVS]; 24 static int num_devs = 0; 25 26 #define foreach_dev(iter) \ 27 for (iter = devs; iter - devs < num_devs; iter++) 28 29 static int outstanding_commands = 0; 30 static int failed = 0; 31 32 static bool 33 probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid, 34 struct spdk_nvme_ctrlr_opts *opts) 35 { 36 printf("Attaching to %s\n", trid->traddr); 37 38 return true; 39 } 40 41 static void 42 attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid, 43 struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts) 44 { 45 struct dev *dev; 46 uint32_t nsid; 47 48 /* add to dev list */ 49 dev = &devs[num_devs++]; 50 if (num_devs >= MAX_DEVS) { 51 return; 52 } 53 54 dev->ctrlr = ctrlr; 55 nsid = spdk_nvme_ctrlr_get_first_active_ns(ctrlr); 56 dev->ns = spdk_nvme_ctrlr_get_ns(ctrlr, nsid); 57 58 dev->qpair = spdk_nvme_ctrlr_alloc_io_qpair(ctrlr, NULL, 0); 59 if (dev->qpair == NULL) { 60 failed = 1; 61 return; 62 } 63 64 snprintf(dev->name, sizeof(dev->name), "%s", 65 trid->traddr); 66 67 printf("Attached to %s\n", dev->name); 68 } 69 70 static void 71 get_feature_test_cb(void *cb_arg, const struct spdk_nvme_cpl *cpl) 72 { 73 struct dev *dev = cb_arg; 74 75 outstanding_commands--; 76 77 if (spdk_nvme_cpl_is_error(cpl) && dev->error_expected) { 78 if (cpl->status.sct != SPDK_NVME_SCT_GENERIC || 79 cpl->status.sc != SPDK_NVME_SC_INVALID_FIELD) { 80 failed = 1; 81 } 82 printf("%s: get features failed as expected\n", dev->name); 83 return; 84 } 85 86 if (!spdk_nvme_cpl_is_error(cpl) && !dev->error_expected) { 87 printf("%s: get features successfully as expected\n", dev->name); 88 return; 89 } 90 91 failed = 1; 92 } 93 94 static void 95 get_feature_test(bool error_expected) 96 { 97 struct dev *dev; 98 struct spdk_nvme_cmd cmd; 99 100 memset(&cmd, 0, sizeof(cmd)); 101 cmd.opc = SPDK_NVME_OPC_GET_FEATURES; 102 cmd.cdw10_bits.get_features.fid = SPDK_NVME_FEAT_NUMBER_OF_QUEUES; 103 104 foreach_dev(dev) { 105 dev->error_expected = error_expected; 106 if (spdk_nvme_ctrlr_cmd_admin_raw(dev->ctrlr, &cmd, NULL, 0, 107 get_feature_test_cb, dev) != 0) { 108 printf("Error: failed to send Get Features command for dev=%p\n", dev); 109 failed = 1; 110 goto cleanup; 111 } 112 outstanding_commands++; 113 } 114 115 cleanup: 116 117 while (outstanding_commands) { 118 foreach_dev(dev) { 119 spdk_nvme_ctrlr_process_admin_completions(dev->ctrlr); 120 } 121 } 122 } 123 124 static void 125 read_test_cb(void *cb_arg, const struct spdk_nvme_cpl *cpl) 126 { 127 struct dev *dev = cb_arg; 128 129 outstanding_commands--; 130 spdk_free(dev->data); 131 132 if (spdk_nvme_cpl_is_error(cpl) && dev->error_expected) { 133 if (cpl->status.sct != SPDK_NVME_SCT_MEDIA_ERROR || 134 cpl->status.sc != SPDK_NVME_SC_UNRECOVERED_READ_ERROR) { 135 failed = 1; 136 } 137 printf("%s: read failed as expected\n", dev->name); 138 return; 139 } 140 141 if (!spdk_nvme_cpl_is_error(cpl) && !dev->error_expected) { 142 printf("%s: read successfully as expected\n", dev->name); 143 return; 144 } 145 146 failed = 1; 147 } 148 149 static void 150 read_test(bool error_expected) 151 { 152 struct dev *dev; 153 154 foreach_dev(dev) { 155 if (dev->ns == NULL) { 156 continue; 157 } 158 159 dev->error_expected = error_expected; 160 dev->data = spdk_zmalloc(0x1000, 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA); 161 if (!dev->data) { 162 failed = 1; 163 goto cleanup; 164 } 165 166 if (spdk_nvme_ns_cmd_read(dev->ns, dev->qpair, dev->data, 167 0, 1, read_test_cb, dev, 0) != 0) { 168 printf("Error: failed to send Read command for dev=%p\n", dev); 169 failed = 1; 170 goto cleanup; 171 } 172 173 outstanding_commands++; 174 } 175 176 cleanup: 177 178 while (outstanding_commands) { 179 foreach_dev(dev) { 180 spdk_nvme_qpair_process_completions(dev->qpair, 0); 181 } 182 } 183 } 184 185 int 186 main(int argc, char **argv) 187 { 188 struct dev *dev; 189 struct spdk_env_opts opts; 190 int rc; 191 struct spdk_nvme_detach_ctx *detach_ctx = NULL; 192 193 opts.opts_size = sizeof(opts); 194 spdk_env_opts_init(&opts); 195 opts.name = "err_injection"; 196 opts.core_mask = "0x1"; 197 opts.shm_id = 0; 198 if (spdk_env_init(&opts) < 0) { 199 fprintf(stderr, "Unable to initialize SPDK env\n"); 200 return 1; 201 } 202 203 printf("NVMe Error Injection test\n"); 204 205 if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) { 206 fprintf(stderr, "spdk_nvme_probe() failed\n"); 207 return 1; 208 } 209 210 if (failed) { 211 goto exit; 212 } 213 214 if (!num_devs) { 215 printf("No NVMe controller found, %s exiting\n", argv[0]); 216 return 1; 217 } 218 219 foreach_dev(dev) { 220 /* Admin error injection at submission path */ 221 rc = spdk_nvme_qpair_add_cmd_error_injection(dev->ctrlr, NULL, 222 SPDK_NVME_OPC_GET_FEATURES, true, 5000, 1, 223 SPDK_NVME_SCT_GENERIC, SPDK_NVME_SC_INVALID_FIELD); 224 failed += rc; 225 /* IO error injection at completion path */ 226 rc = spdk_nvme_qpair_add_cmd_error_injection(dev->ctrlr, dev->qpair, 227 SPDK_NVME_OPC_READ, false, 0, 1, 228 SPDK_NVME_SCT_MEDIA_ERROR, SPDK_NVME_SC_UNRECOVERED_READ_ERROR); 229 failed += rc; 230 } 231 232 if (failed) { 233 goto exit; 234 } 235 236 /* Admin Get Feature, expect error return */ 237 get_feature_test(true); 238 /* Admin Get Feature, expect successful return */ 239 get_feature_test(false); 240 /* Read, expect error return */ 241 read_test(true); 242 /* Read, expect successful return */ 243 read_test(false); 244 245 exit: 246 printf("Cleaning up...\n"); 247 foreach_dev(dev) { 248 spdk_nvme_detach_async(dev->ctrlr, &detach_ctx); 249 } 250 if (detach_ctx) { 251 spdk_nvme_detach_poll(detach_ctx); 252 } 253 254 return failed; 255 } 256