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