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