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