1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2018 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 uint32_t buff_size; 27 char *bdev_name; 28 struct spdk_bdev_io_wait_entry bdev_io_wait; 29 }; 30 31 /* 32 * Usage function for printing parameters that are specific to this application 33 */ 34 static void 35 hello_bdev_usage(void) 36 { 37 printf(" -b <bdev> name of the bdev to use\n"); 38 } 39 40 /* 41 * This function is called to parse the parameters that are specific to this application 42 */ 43 static int 44 hello_bdev_parse_arg(int ch, char *arg) 45 { 46 switch (ch) { 47 case 'b': 48 g_bdev_name = arg; 49 break; 50 default: 51 return -EINVAL; 52 } 53 return 0; 54 } 55 56 /* 57 * Callback function for read io completion. 58 */ 59 static void 60 read_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) 61 { 62 struct hello_context_t *hello_context = cb_arg; 63 64 if (success) { 65 SPDK_NOTICELOG("Read string from bdev : %s\n", hello_context->buff); 66 } else { 67 SPDK_ERRLOG("bdev io read error\n"); 68 } 69 70 /* Complete the bdev io and close the channel */ 71 spdk_bdev_free_io(bdev_io); 72 spdk_put_io_channel(hello_context->bdev_io_channel); 73 spdk_bdev_close(hello_context->bdev_desc); 74 SPDK_NOTICELOG("Stopping app\n"); 75 spdk_app_stop(success ? 0 : -1); 76 } 77 78 static void 79 hello_read(void *arg) 80 { 81 struct hello_context_t *hello_context = arg; 82 int rc = 0; 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, hello_context->buff_size, read_complete, 87 hello_context); 88 89 if (rc == -ENOMEM) { 90 SPDK_NOTICELOG("Queueing io\n"); 91 /* In case we cannot perform I/O now, queue I/O */ 92 hello_context->bdev_io_wait.bdev = hello_context->bdev; 93 hello_context->bdev_io_wait.cb_fn = hello_read; 94 hello_context->bdev_io_wait.cb_arg = hello_context; 95 spdk_bdev_queue_io_wait(hello_context->bdev, hello_context->bdev_io_channel, 96 &hello_context->bdev_io_wait); 97 } else if (rc) { 98 SPDK_ERRLOG("%s error while reading from bdev: %d\n", spdk_strerror(-rc), rc); 99 spdk_put_io_channel(hello_context->bdev_io_channel); 100 spdk_bdev_close(hello_context->bdev_desc); 101 spdk_app_stop(-1); 102 } 103 } 104 105 /* 106 * Callback function for write io completion. 107 */ 108 static void 109 write_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) 110 { 111 struct hello_context_t *hello_context = cb_arg; 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 memset(hello_context->buff, 0, hello_context->buff_size); 128 129 hello_read(hello_context); 130 } 131 132 static void 133 hello_write(void *arg) 134 { 135 struct hello_context_t *hello_context = arg; 136 int rc = 0; 137 138 SPDK_NOTICELOG("Writing to the bdev\n"); 139 rc = spdk_bdev_write(hello_context->bdev_desc, hello_context->bdev_io_channel, 140 hello_context->buff, 0, hello_context->buff_size, write_complete, 141 hello_context); 142 143 if (rc == -ENOMEM) { 144 SPDK_NOTICELOG("Queueing io\n"); 145 /* In case we cannot perform I/O now, queue I/O */ 146 hello_context->bdev_io_wait.bdev = hello_context->bdev; 147 hello_context->bdev_io_wait.cb_fn = hello_write; 148 hello_context->bdev_io_wait.cb_arg = hello_context; 149 spdk_bdev_queue_io_wait(hello_context->bdev, hello_context->bdev_io_channel, 150 &hello_context->bdev_io_wait); 151 } else if (rc) { 152 SPDK_ERRLOG("%s error while writing to bdev: %d\n", spdk_strerror(-rc), rc); 153 spdk_put_io_channel(hello_context->bdev_io_channel); 154 spdk_bdev_close(hello_context->bdev_desc); 155 spdk_app_stop(-1); 156 } 157 } 158 159 static void 160 hello_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, 161 void *event_ctx) 162 { 163 SPDK_NOTICELOG("Unsupported bdev event: type %d\n", type); 164 } 165 166 static void 167 reset_zone_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) 168 { 169 struct hello_context_t *hello_context = cb_arg; 170 171 /* Complete the I/O */ 172 spdk_bdev_free_io(bdev_io); 173 174 if (!success) { 175 SPDK_ERRLOG("bdev io reset zone error: %d\n", EIO); 176 spdk_put_io_channel(hello_context->bdev_io_channel); 177 spdk_bdev_close(hello_context->bdev_desc); 178 spdk_app_stop(-1); 179 return; 180 } 181 182 hello_write(hello_context); 183 } 184 185 static void 186 hello_reset_zone(void *arg) 187 { 188 struct hello_context_t *hello_context = arg; 189 int rc = 0; 190 191 rc = spdk_bdev_zone_management(hello_context->bdev_desc, hello_context->bdev_io_channel, 192 0, SPDK_BDEV_ZONE_RESET, reset_zone_complete, hello_context); 193 194 if (rc == -ENOMEM) { 195 SPDK_NOTICELOG("Queueing io\n"); 196 /* In case we cannot perform I/O now, queue I/O */ 197 hello_context->bdev_io_wait.bdev = hello_context->bdev; 198 hello_context->bdev_io_wait.cb_fn = hello_reset_zone; 199 hello_context->bdev_io_wait.cb_arg = hello_context; 200 spdk_bdev_queue_io_wait(hello_context->bdev, hello_context->bdev_io_channel, 201 &hello_context->bdev_io_wait); 202 } else if (rc) { 203 SPDK_ERRLOG("%s error while resetting zone: %d\n", spdk_strerror(-rc), rc); 204 spdk_put_io_channel(hello_context->bdev_io_channel); 205 spdk_bdev_close(hello_context->bdev_desc); 206 spdk_app_stop(-1); 207 } 208 } 209 210 /* 211 * Our initial event that kicks off everything from main(). 212 */ 213 static void 214 hello_start(void *arg1) 215 { 216 struct hello_context_t *hello_context = arg1; 217 uint32_t buf_align; 218 int rc = 0; 219 hello_context->bdev = NULL; 220 hello_context->bdev_desc = NULL; 221 222 SPDK_NOTICELOG("Successfully started the application\n"); 223 224 /* 225 * There can be many bdevs configured, but this application will only use 226 * the one input by the user at runtime. 227 * 228 * Open the bdev by calling spdk_bdev_open_ext() with its name. 229 * The function will return a descriptor 230 */ 231 SPDK_NOTICELOG("Opening the bdev %s\n", hello_context->bdev_name); 232 rc = spdk_bdev_open_ext(hello_context->bdev_name, true, hello_bdev_event_cb, NULL, 233 &hello_context->bdev_desc); 234 if (rc) { 235 SPDK_ERRLOG("Could not open bdev: %s\n", hello_context->bdev_name); 236 spdk_app_stop(-1); 237 return; 238 } 239 240 /* A bdev pointer is valid while the bdev is opened. */ 241 hello_context->bdev = spdk_bdev_desc_get_bdev(hello_context->bdev_desc); 242 243 244 SPDK_NOTICELOG("Opening io channel\n"); 245 /* Open I/O channel */ 246 hello_context->bdev_io_channel = spdk_bdev_get_io_channel(hello_context->bdev_desc); 247 if (hello_context->bdev_io_channel == NULL) { 248 SPDK_ERRLOG("Could not create bdev I/O channel!!\n"); 249 spdk_bdev_close(hello_context->bdev_desc); 250 spdk_app_stop(-1); 251 return; 252 } 253 254 /* Allocate memory for the write buffer. 255 * Initialize the write buffer with the string "Hello World!" 256 */ 257 hello_context->buff_size = spdk_bdev_get_block_size(hello_context->bdev) * 258 spdk_bdev_get_write_unit_size(hello_context->bdev); 259 buf_align = spdk_bdev_get_buf_align(hello_context->bdev); 260 hello_context->buff = spdk_dma_zmalloc(hello_context->buff_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, hello_context->buff_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