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