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 #include "spdk/thread.h" 36 #include "spdk/bdev.h" 37 #include "spdk/env.h" 38 #include "spdk/event.h" 39 #include "spdk/log.h" 40 #include "spdk/string.h" 41 #include "spdk/bdev_zone.h" 42 43 static char *g_bdev_name = "Malloc0"; 44 45 /* 46 * We'll use this struct to gather housekeeping hello_context to pass between 47 * our events and callbacks. 48 */ 49 struct hello_context_t { 50 struct spdk_bdev *bdev; 51 struct spdk_bdev_desc *bdev_desc; 52 struct spdk_io_channel *bdev_io_channel; 53 char *buff; 54 char *bdev_name; 55 struct spdk_bdev_io_wait_entry bdev_io_wait; 56 }; 57 58 /* 59 * Usage function for printing parameters that are specific to this application 60 */ 61 static void 62 hello_bdev_usage(void) 63 { 64 printf(" -b <bdev> name of the bdev to use\n"); 65 } 66 67 /* 68 * This function is called to parse the parameters that are specific to this application 69 */ 70 static int hello_bdev_parse_arg(int ch, char *arg) 71 { 72 switch (ch) { 73 case 'b': 74 g_bdev_name = arg; 75 break; 76 default: 77 return -EINVAL; 78 } 79 return 0; 80 } 81 82 /* 83 * Callback function for read io completion. 84 */ 85 static void 86 read_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) 87 { 88 struct hello_context_t *hello_context = cb_arg; 89 90 if (success) { 91 SPDK_NOTICELOG("Read string from bdev : %s\n", hello_context->buff); 92 } else { 93 SPDK_ERRLOG("bdev io read error\n"); 94 } 95 96 /* Complete the bdev io and close the channel */ 97 spdk_bdev_free_io(bdev_io); 98 spdk_put_io_channel(hello_context->bdev_io_channel); 99 spdk_bdev_close(hello_context->bdev_desc); 100 SPDK_NOTICELOG("Stopping app\n"); 101 spdk_app_stop(success ? 0 : -1); 102 } 103 104 static void 105 hello_read(void *arg) 106 { 107 struct hello_context_t *hello_context = arg; 108 int rc = 0; 109 uint32_t length = spdk_bdev_get_block_size(hello_context->bdev); 110 111 SPDK_NOTICELOG("Reading io\n"); 112 rc = spdk_bdev_read(hello_context->bdev_desc, hello_context->bdev_io_channel, 113 hello_context->buff, 0, length, read_complete, hello_context); 114 115 if (rc == -ENOMEM) { 116 SPDK_NOTICELOG("Queueing io\n"); 117 /* In case we cannot perform I/O now, queue I/O */ 118 hello_context->bdev_io_wait.bdev = hello_context->bdev; 119 hello_context->bdev_io_wait.cb_fn = hello_read; 120 hello_context->bdev_io_wait.cb_arg = hello_context; 121 spdk_bdev_queue_io_wait(hello_context->bdev, hello_context->bdev_io_channel, 122 &hello_context->bdev_io_wait); 123 } else if (rc) { 124 SPDK_ERRLOG("%s error while reading from bdev: %d\n", spdk_strerror(-rc), rc); 125 spdk_put_io_channel(hello_context->bdev_io_channel); 126 spdk_bdev_close(hello_context->bdev_desc); 127 spdk_app_stop(-1); 128 } 129 } 130 131 /* 132 * Callback function for write io completion. 133 */ 134 static void 135 write_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) 136 { 137 struct hello_context_t *hello_context = cb_arg; 138 uint32_t length; 139 140 /* Complete the I/O */ 141 spdk_bdev_free_io(bdev_io); 142 143 if (success) { 144 SPDK_NOTICELOG("bdev io write completed successfully\n"); 145 } else { 146 SPDK_ERRLOG("bdev io write error: %d\n", EIO); 147 spdk_put_io_channel(hello_context->bdev_io_channel); 148 spdk_bdev_close(hello_context->bdev_desc); 149 spdk_app_stop(-1); 150 return; 151 } 152 153 /* Zero the buffer so that we can use it for reading */ 154 length = spdk_bdev_get_block_size(hello_context->bdev); 155 memset(hello_context->buff, 0, length); 156 157 hello_read(hello_context); 158 } 159 160 static void 161 hello_write(void *arg) 162 { 163 struct hello_context_t *hello_context = arg; 164 int rc = 0; 165 uint32_t length = spdk_bdev_get_block_size(hello_context->bdev); 166 167 SPDK_NOTICELOG("Writing to the bdev\n"); 168 rc = spdk_bdev_write(hello_context->bdev_desc, hello_context->bdev_io_channel, 169 hello_context->buff, 0, length, write_complete, hello_context); 170 171 if (rc == -ENOMEM) { 172 SPDK_NOTICELOG("Queueing io\n"); 173 /* In case we cannot perform I/O now, queue I/O */ 174 hello_context->bdev_io_wait.bdev = hello_context->bdev; 175 hello_context->bdev_io_wait.cb_fn = hello_write; 176 hello_context->bdev_io_wait.cb_arg = hello_context; 177 spdk_bdev_queue_io_wait(hello_context->bdev, hello_context->bdev_io_channel, 178 &hello_context->bdev_io_wait); 179 } else if (rc) { 180 SPDK_ERRLOG("%s error while writing to bdev: %d\n", spdk_strerror(-rc), rc); 181 spdk_put_io_channel(hello_context->bdev_io_channel); 182 spdk_bdev_close(hello_context->bdev_desc); 183 spdk_app_stop(-1); 184 } 185 } 186 187 static void 188 hello_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, 189 void *event_ctx) 190 { 191 SPDK_NOTICELOG("Unsupported bdev event: type %d\n", type); 192 } 193 194 static void 195 reset_zone_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) 196 { 197 struct hello_context_t *hello_context = cb_arg; 198 199 /* Complete the I/O */ 200 spdk_bdev_free_io(bdev_io); 201 202 if (!success) { 203 SPDK_ERRLOG("bdev io reset zone error: %d\n", EIO); 204 spdk_put_io_channel(hello_context->bdev_io_channel); 205 spdk_bdev_close(hello_context->bdev_desc); 206 spdk_app_stop(-1); 207 return; 208 } 209 210 hello_write(hello_context); 211 } 212 213 static void 214 hello_reset_zone(void *arg) 215 { 216 struct hello_context_t *hello_context = arg; 217 int rc = 0; 218 219 rc = spdk_bdev_zone_management(hello_context->bdev_desc, hello_context->bdev_io_channel, 220 0, SPDK_BDEV_ZONE_RESET, reset_zone_complete, hello_context); 221 222 if (rc == -ENOMEM) { 223 SPDK_NOTICELOG("Queueing io\n"); 224 /* In case we cannot perform I/O now, queue I/O */ 225 hello_context->bdev_io_wait.bdev = hello_context->bdev; 226 hello_context->bdev_io_wait.cb_fn = hello_reset_zone; 227 hello_context->bdev_io_wait.cb_arg = hello_context; 228 spdk_bdev_queue_io_wait(hello_context->bdev, hello_context->bdev_io_channel, 229 &hello_context->bdev_io_wait); 230 } else if (rc) { 231 SPDK_ERRLOG("%s error while resetting zone: %d\n", spdk_strerror(-rc), rc); 232 spdk_put_io_channel(hello_context->bdev_io_channel); 233 spdk_bdev_close(hello_context->bdev_desc); 234 spdk_app_stop(-1); 235 } 236 } 237 238 /* 239 * Our initial event that kicks off everything from main(). 240 */ 241 static void 242 hello_start(void *arg1) 243 { 244 struct hello_context_t *hello_context = arg1; 245 uint32_t blk_size, buf_align; 246 int rc = 0; 247 hello_context->bdev = NULL; 248 hello_context->bdev_desc = NULL; 249 250 SPDK_NOTICELOG("Successfully started the application\n"); 251 252 /* 253 * There can be many bdevs configured, but this application will only use 254 * the one input by the user at runtime. 255 * 256 * Open the bdev by calling spdk_bdev_open_ext() with its name. 257 * The function will return a descriptor 258 */ 259 SPDK_NOTICELOG("Opening the bdev %s\n", hello_context->bdev_name); 260 rc = spdk_bdev_open_ext(hello_context->bdev_name, true, hello_bdev_event_cb, NULL, 261 &hello_context->bdev_desc); 262 if (rc) { 263 SPDK_ERRLOG("Could not open bdev: %s\n", hello_context->bdev_name); 264 spdk_app_stop(-1); 265 return; 266 } 267 268 /* A bdev pointer is valid while the bdev is opened. */ 269 hello_context->bdev = spdk_bdev_desc_get_bdev(hello_context->bdev_desc); 270 271 272 SPDK_NOTICELOG("Opening io channel\n"); 273 /* Open I/O channel */ 274 hello_context->bdev_io_channel = spdk_bdev_get_io_channel(hello_context->bdev_desc); 275 if (hello_context->bdev_io_channel == NULL) { 276 SPDK_ERRLOG("Could not create bdev I/O channel!!\n"); 277 spdk_bdev_close(hello_context->bdev_desc); 278 spdk_app_stop(-1); 279 return; 280 } 281 282 /* Allocate memory for the write buffer. 283 * Initialize the write buffer with the string "Hello World!" 284 */ 285 blk_size = spdk_bdev_get_block_size(hello_context->bdev); 286 buf_align = spdk_bdev_get_buf_align(hello_context->bdev); 287 hello_context->buff = spdk_dma_zmalloc(blk_size, buf_align, NULL); 288 if (!hello_context->buff) { 289 SPDK_ERRLOG("Failed to allocate buffer\n"); 290 spdk_put_io_channel(hello_context->bdev_io_channel); 291 spdk_bdev_close(hello_context->bdev_desc); 292 spdk_app_stop(-1); 293 return; 294 } 295 snprintf(hello_context->buff, blk_size, "%s", "Hello World!\n"); 296 297 if (spdk_bdev_is_zoned(hello_context->bdev)) { 298 hello_reset_zone(hello_context); 299 /* If bdev is zoned, the callback, reset_zone_complete, will call hello_write() */ 300 return; 301 } 302 303 hello_write(hello_context); 304 } 305 306 int 307 main(int argc, char **argv) 308 { 309 struct spdk_app_opts opts = {}; 310 int rc = 0; 311 struct hello_context_t hello_context = {}; 312 313 /* Set default values in opts structure. */ 314 spdk_app_opts_init(&opts, sizeof(opts)); 315 opts.name = "hello_bdev"; 316 317 /* 318 * Parse built-in SPDK command line parameters as well 319 * as our custom one(s). 320 */ 321 if ((rc = spdk_app_parse_args(argc, argv, &opts, "b:", NULL, hello_bdev_parse_arg, 322 hello_bdev_usage)) != SPDK_APP_PARSE_ARGS_SUCCESS) { 323 exit(rc); 324 } 325 hello_context.bdev_name = g_bdev_name; 326 327 /* 328 * spdk_app_start() will initialize the SPDK framework, call hello_start(), 329 * and then block until spdk_app_stop() is called (or if an initialization 330 * error occurs, spdk_app_start() will return with rc even without calling 331 * hello_start(). 332 */ 333 rc = spdk_app_start(&opts, hello_start, &hello_context); 334 if (rc) { 335 SPDK_ERRLOG("ERROR starting application\n"); 336 } 337 338 /* At this point either spdk_app_stop() was called, or spdk_app_start() 339 * failed because of internal error. 340 */ 341 342 /* When the app stops, free up memory that we allocated. */ 343 spdk_dma_free(hello_context.buff); 344 345 /* Gracefully close out all of the SPDK subsystems. */ 346 spdk_app_fini(); 347 return rc; 348 } 349