1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2025 Oxide Computer Company 14 */ 15 16 /* 17 * Reset an NVMe device back to a simple state. 18 */ 19 20 #include <err.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include "libnvme_test_common.h" 24 25 typedef enum { 26 RESET_ACT_EMPTY = 0, 27 RESET_ACT_DEFAULT 28 } reset_action_t; 29 30 static bool 31 device_reset_cb(nvme_ctrl_t *ctrl, const nvme_ns_disc_t *disc, 32 void *arg) 33 { 34 const uint32_t nsid = nvme_ns_disc_nsid(disc); 35 36 if (!libnvme_test_setup_ns(ctrl, NVME_NS_DISC_F_ALL, nsid, 37 UINT32_MAX)) { 38 exit(EXIT_FAILURE); 39 } 40 41 return (true); 42 } 43 44 /* 45 * Create a single namespace with all of the device capacity. We default to the 46 * best 4 KiB namespace format we can that has no metadata. If that doesn't 47 * exist, use the remaining best that we can support. 48 */ 49 static void 50 device_reset_create(nvme_ctrl_t *ctrl) 51 { 52 nvme_ctrl_info_t *info; 53 uint32_t lba, nsid; 54 uint64_t size; 55 nvme_uint128_t cap; 56 57 if (!nvme_ctrl_info_snap(ctrl, &info)) { 58 libnvme_test_ctrl_fatal(ctrl, "failed to get info snapshot"); 59 } 60 61 if (!libnvme_test_lbaf(info, NVME_TEST_LBA_SIZE, &lba)) { 62 errx(EXIT_FAILURE, "failed to find 4K LBA format, cannot " 63 "continue"); 64 } 65 66 if (!nvme_ctrl_info_cap(info, &cap)) { 67 libnvme_test_ctrl_info_fatal(info, "failed to get device " 68 "capacity"); 69 } 70 71 /* 72 * We need to convert the capacity of the device to a number of logical 73 * blocks. The device's capacity is phrased in bytes. For now, just 74 * divide the capacity in bytes by the LBA size. If we encounter a 75 * device with more than a uint64_t worth of bytes in it, for now punt. 76 */ 77 if (cap.hi != 0) { 78 errx(EXIT_FAILURE, "encountered device with > uint64_t " 79 "capacity, this program needs to be updated to deal with " 80 "that"); 81 } 82 size = cap.lo / NVME_TEST_LBA_SIZE; 83 84 if (!libnvme_test_ns_create(ctrl, size, lba, &nsid, NULL)) { 85 exit(EXIT_FAILURE); 86 } 87 88 if (!libnvme_test_setup_ns(ctrl, NVME_NS_DISC_F_ACTIVE, nsid, 89 UINT32_MAX)) { 90 exit(EXIT_FAILURE); 91 } 92 93 nvme_ctrl_info_free(info); 94 } 95 96 int 97 main(void) 98 { 99 nvme_t *nvme; 100 nvme_ctrl_t *ctrl; 101 102 libnvme_test_init(&nvme, &ctrl); 103 if (!nvme_ctrl_lock(ctrl, NVME_LOCK_L_WRITE, NVME_LOCK_F_DONT_BLOCK)) { 104 libnvme_test_ctrl_fatal(ctrl, "failed to obtain write lock"); 105 } 106 107 if (!nvme_ns_discover(ctrl, NVME_NS_DISC_F_ALL, 108 device_reset_cb, NULL)) { 109 libnvme_test_ctrl_fatal(ctrl, "failed to iterate namespaces"); 110 } 111 112 device_reset_create(ctrl); 113 114 nvme_ctrl_unlock(ctrl); 115 nvme_ctrl_fini(ctrl); 116 nvme_fini(nvme); 117 118 return (EXIT_SUCCESS); 119 } 120