1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) Samsung Electronics Co., Ltd. 3 * All rights reserved. 4 */ 5 6 #include "spdk/stdinc.h" 7 #include "spdk/nvme.h" 8 #include "spdk/util.h" 9 #include "spdk/env.h" 10 11 struct ctrlr { 12 struct spdk_nvme_transport_id trid; 13 struct spdk_nvme_ctrlr *ctrlr; 14 char *write_buf; 15 char *read_buf; 16 int write_completed; 17 }; 18 19 static struct ctrlr g_ctrlr; 20 21 static void cleanup(void); 22 23 static void 24 fill_pattern(char *buf, size_t num_bytes, char pattern) 25 { 26 size_t i; 27 28 for (i = 0; i < num_bytes; i++) { 29 buf[i] = pattern; 30 } 31 } 32 33 static void 34 write_complete(void *arg, const struct spdk_nvme_cpl *completion) 35 { 36 printf("Boot Partition Write - SCT : %d, SC : %d\n", 37 completion->status.sct, completion->status.sc); 38 g_ctrlr.write_completed = 1; 39 } 40 41 static int 42 boot_partition_test(void) 43 { 44 struct spdk_nvme_ctrlr *ctrlr; 45 union spdk_nvme_cap_register cap; 46 int rc; 47 union spdk_nvme_bpinfo_register bpinfo; 48 unsigned int bpsize; 49 unsigned int bpsize_in_4k; 50 51 ctrlr = g_ctrlr.ctrlr; 52 53 cap = spdk_nvme_ctrlr_get_regs_cap(ctrlr); 54 55 if (cap.bits.bps) { 56 printf("Boot Partitions are Supported by the Controller\n"); 57 } else { 58 printf("Boot Partitions are Not Supported by the Controller\n"); 59 return -ENOTSUP; 60 } 61 62 bpinfo = spdk_nvme_ctrlr_get_regs_bpinfo(ctrlr); 63 bpsize = bpinfo.bits.bpsz * 131072; 64 bpsize_in_4k = bpsize / 4096; 65 66 printf("Boot Partition Info\n"); 67 printf("Active Boot Partition ID : %d\n", bpinfo.bits.abpid); 68 printf("Boot Read Status : %d\n", bpinfo.bits.brs); 69 printf("Boot Partition Size : %d bytes\n", bpsize); 70 71 g_ctrlr.write_buf = spdk_zmalloc(bpsize, 0x1000, NULL, 72 SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA); 73 74 if (g_ctrlr.write_buf == NULL) { 75 printf("Error - could not allocate write buffer for test\n"); 76 cleanup(); 77 return -ENOMEM; 78 } 79 80 g_ctrlr.read_buf = spdk_memzone_reserve("boot_partition", bpsize, 81 SPDK_ENV_SOCKET_ID_ANY, 0); 82 83 if (g_ctrlr.read_buf == NULL) { 84 printf("Error - could not allocate read buffer for test\n"); 85 cleanup(); 86 return -ENOMEM; 87 } 88 89 fill_pattern(g_ctrlr.write_buf, bpsize, 0xDE); 90 91 g_ctrlr.write_completed = 0; 92 rc = spdk_nvme_ctrlr_write_boot_partition(ctrlr, g_ctrlr.write_buf, 93 bpsize, 0, write_complete, NULL); 94 if (rc) { 95 printf("Error - Boot Partition write failure. rc: %d", rc); 96 cleanup(); 97 return rc; 98 } 99 100 while (!g_ctrlr.write_completed) { 101 spdk_nvme_ctrlr_process_admin_completions(ctrlr); 102 } 103 104 rc = spdk_nvme_ctrlr_read_boot_partition_start(ctrlr, g_ctrlr.read_buf, 105 bpsize_in_4k, 0, 0); 106 107 if (rc) { 108 printf("Error - Boot Partition read start failure. rc: %d", rc); 109 cleanup(); 110 return rc; 111 } 112 113 do { 114 rc = spdk_nvme_ctrlr_read_boot_partition_poll(ctrlr); 115 } while (rc == -EAGAIN); 116 117 if (rc != 0) { 118 printf("Error - Boot Partition read poll failure. rc: %d", rc); 119 cleanup(); 120 return rc; 121 } 122 123 rc = memcmp(g_ctrlr.write_buf, g_ctrlr.read_buf, bpsize); 124 if (rc) { 125 printf("Error - Boot Partition written data does not match Boot Partition read data, rc: %d\n", rc); 126 cleanup(); 127 return rc; 128 } 129 130 printf("Boot Partition 0 written data matches Boot Partition 0 read data\n"); 131 132 fill_pattern(g_ctrlr.write_buf, bpsize, 0xAD); 133 134 g_ctrlr.write_completed = 0; 135 rc = spdk_nvme_ctrlr_write_boot_partition(ctrlr, g_ctrlr.write_buf, 136 bpsize, 1, write_complete, NULL); 137 if (rc) { 138 printf("Error - Boot Partition write failure. rc: %d", rc); 139 cleanup(); 140 return rc; 141 } 142 143 while (!g_ctrlr.write_completed) { 144 spdk_nvme_ctrlr_process_admin_completions(ctrlr); 145 } 146 147 rc = spdk_nvme_ctrlr_read_boot_partition_start(ctrlr, g_ctrlr.read_buf, 148 bpsize_in_4k, 0, 1); 149 150 if (rc) { 151 printf("Error - Boot Partition read start failure. rc: %d", rc); 152 cleanup(); 153 return rc; 154 } 155 156 do { 157 rc = spdk_nvme_ctrlr_read_boot_partition_poll(ctrlr); 158 } while (rc == -EAGAIN); 159 160 if (rc != 0) { 161 printf("Error - Boot Partition read poll failure. rc: %d", rc); 162 cleanup(); 163 return rc; 164 } 165 166 rc = memcmp(g_ctrlr.write_buf, g_ctrlr.read_buf, bpsize); 167 if (rc) { 168 printf("Error - Boot Partition written data does not match Boot Partition read data, rc: %d\n", rc); 169 cleanup(); 170 return rc; 171 } 172 173 printf("Boot Partition 1 written data matches Boot Partition 1 read data\n"); 174 175 cleanup(); 176 177 return 0; 178 } 179 180 static void 181 cleanup(void) 182 { 183 spdk_memzone_free("boot_partition"); 184 spdk_free(g_ctrlr.write_buf); 185 spdk_nvme_detach(g_ctrlr.ctrlr); 186 } 187 188 static void 189 usage(char *program_name) 190 { 191 printf("%s Option (Mandatory)", program_name); 192 printf("\n"); 193 printf("\t[-p PCIe address of the NVMe Device with Boot Partition support]\n"); 194 printf("\n"); 195 } 196 197 static int 198 parse_args(int argc, char **argv) 199 { 200 int op; 201 unsigned num_args = 0; 202 203 while ((op = getopt(argc, argv, "p:")) != -1) { 204 switch (op) { 205 case 'p': 206 snprintf(&g_ctrlr.trid.traddr[0], SPDK_NVMF_TRADDR_MAX_LEN + 1, 207 "%s", optarg); 208 209 g_ctrlr.trid.trtype = SPDK_NVME_TRANSPORT_PCIE; 210 211 spdk_nvme_transport_id_populate_trstring(&g_ctrlr.trid, 212 spdk_nvme_transport_id_trtype_str(g_ctrlr.trid.trtype)); 213 214 num_args++; 215 break; 216 default: 217 usage(argv[0]); 218 return 1; 219 } 220 } 221 222 if (num_args != 1) { 223 usage(argv[0]); 224 return 1; 225 } 226 227 return 0; 228 } 229 230 int 231 main(int argc, char **argv) 232 { 233 int rc; 234 struct spdk_env_opts opts; 235 236 /* 237 * Parse the input arguments. For now we use the following 238 * format list: 239 * 240 * -p <pci id> 241 * 242 */ 243 rc = parse_args(argc, argv); 244 if (rc) { 245 fprintf(stderr, "Error in parse_args(): %d\n", rc); 246 return rc; 247 } 248 249 spdk_env_opts_init(&opts); 250 opts.name = "boot_partition"; 251 opts.shm_id = 0; 252 if (spdk_env_init(&opts) < 0) { 253 fprintf(stderr, "Unable to initialize SPDK env\n"); 254 return 1; 255 } 256 257 printf("Initializing NVMe Controller\n"); 258 259 g_ctrlr.ctrlr = spdk_nvme_connect(&g_ctrlr.trid, NULL, 0); 260 if (!g_ctrlr.ctrlr) { 261 fprintf(stderr, "spdk_nvme_connect() failed\n"); 262 return 1; 263 } 264 265 printf("Initialization complete.\n"); 266 rc = boot_partition_test(); 267 return rc; 268 } 269