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