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_module.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 }; 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\n"); 64 } 65 66 /* 67 * This function is called to parse the parameters that are specific to this application 68 */ 69 static void hello_bdev_parse_arg(int ch, char *arg) 70 { 71 switch (ch) { 72 case 'b': 73 g_bdev_name = arg; 74 break; 75 } 76 } 77 78 /* 79 * Callback function for read io completion. 80 */ 81 static void 82 read_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) 83 { 84 struct hello_context_t *hello_context = cb_arg; 85 86 if (success) { 87 SPDK_NOTICELOG("Read string from bdev : %s\n", hello_context->buff); 88 } else { 89 SPDK_ERRLOG("bdev io read error\n"); 90 } 91 92 /* Complete the bdev io and close the channel */ 93 spdk_bdev_free_io(bdev_io); 94 spdk_put_io_channel(hello_context->bdev_io_channel); 95 spdk_bdev_close(hello_context->bdev_desc); 96 SPDK_NOTICELOG("Stopping app\n"); 97 spdk_app_stop(success ? 0 : -1); 98 } 99 100 /* 101 * Callback function for write io completion. 102 */ 103 static void 104 write_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) 105 { 106 struct hello_context_t *hello_context = cb_arg; 107 int rc; 108 uint32_t blk_size; 109 110 /* Complete the I/O */ 111 spdk_bdev_free_io(bdev_io); 112 113 if (success) { 114 SPDK_NOTICELOG("bdev io write completed successfully\n"); 115 } else { 116 SPDK_ERRLOG("bdev io write error: %d\n", EIO); 117 spdk_put_io_channel(hello_context->bdev_io_channel); 118 spdk_bdev_close(hello_context->bdev_desc); 119 spdk_app_stop(-1); 120 return; 121 } 122 123 /* Zero the buffer so that we can use it for reading */ 124 blk_size = spdk_bdev_get_block_size(hello_context->bdev); 125 memset(hello_context->buff, 0, blk_size); 126 127 SPDK_NOTICELOG("Reading io\n"); 128 rc = spdk_bdev_read(hello_context->bdev_desc, hello_context->bdev_io_channel, 129 hello_context->buff, 0, blk_size, read_complete, hello_context); 130 131 if (rc) { 132 SPDK_ERRLOG("%s error while reading from bdev: %d\n", spdk_strerror(-rc), rc); 133 spdk_put_io_channel(hello_context->bdev_io_channel); 134 spdk_bdev_close(hello_context->bdev_desc); 135 spdk_app_stop(-1); 136 return; 137 } 138 } 139 140 /* 141 * Our initial event that kicks off everything from main(). 142 */ 143 static void 144 hello_start(void *arg1, void *arg2) 145 { 146 struct hello_context_t *hello_context = arg1; 147 uint32_t blk_size, buf_align; 148 int rc = 0; 149 hello_context->bdev = NULL; 150 hello_context->bdev_desc = NULL; 151 152 SPDK_NOTICELOG("Successfully started the application\n"); 153 154 /* 155 * Get the bdev. There can be many bdevs configured in 156 * in the configuration file but this application will only 157 * use the one input by the user at runtime so we get it via its name. 158 */ 159 hello_context->bdev = spdk_bdev_get_by_name(hello_context->bdev_name); 160 if (hello_context->bdev == NULL) { 161 SPDK_ERRLOG("Could not find the bdev: %s\n", hello_context->bdev_name); 162 spdk_app_stop(-1); 163 return; 164 } 165 166 /* 167 * Open the bdev by calling spdk_bdev_open() 168 * The function will return a descriptor 169 */ 170 SPDK_NOTICELOG("Opening the bdev %s\n", hello_context->bdev_name); 171 rc = spdk_bdev_open(hello_context->bdev, true, NULL, NULL, &hello_context->bdev_desc); 172 if (rc) { 173 SPDK_ERRLOG("Could not open bdev: %s\n", hello_context->bdev_name); 174 spdk_app_stop(-1); 175 return; 176 } 177 178 SPDK_NOTICELOG("Opening io channel\n"); 179 /* Open I/O channel */ 180 hello_context->bdev_io_channel = spdk_bdev_get_io_channel(hello_context->bdev_desc); 181 if (hello_context->bdev_io_channel == NULL) { 182 SPDK_ERRLOG("Could not create bdev I/O channel!!\n"); 183 spdk_bdev_close(hello_context->bdev_desc); 184 spdk_app_stop(-1); 185 return; 186 } 187 188 /* Allocate memory for the write buffer. 189 * Initialize the write buffer with the string "Hello World!" 190 */ 191 blk_size = spdk_bdev_get_block_size(hello_context->bdev); 192 buf_align = spdk_bdev_get_buf_align(hello_context->bdev); 193 hello_context->buff = spdk_dma_zmalloc(blk_size, buf_align, NULL); 194 if (!hello_context->buff) { 195 SPDK_ERRLOG("Failed to allocate buffer\n"); 196 spdk_put_io_channel(hello_context->bdev_io_channel); 197 spdk_bdev_close(hello_context->bdev_desc); 198 spdk_app_stop(-1); 199 return; 200 } 201 snprintf(hello_context->buff, blk_size, "%s", "Hello World!\n"); 202 203 SPDK_NOTICELOG("Writing to the bdev\n"); 204 rc = spdk_bdev_write(hello_context->bdev_desc, hello_context->bdev_io_channel, 205 hello_context->buff, 0, blk_size, write_complete, hello_context); 206 if (rc) { 207 SPDK_ERRLOG("%s error while writing to bdev: %d\n", spdk_strerror(-rc), rc); 208 spdk_bdev_close(hello_context->bdev_desc); 209 spdk_put_io_channel(hello_context->bdev_io_channel); 210 spdk_app_stop(-1); 211 return; 212 } 213 } 214 215 int 216 main(int argc, char **argv) 217 { 218 struct spdk_app_opts opts = {}; 219 int rc = 0; 220 struct hello_context_t hello_context = {}; 221 222 /* Set default values in opts structure. */ 223 spdk_app_opts_init(&opts); 224 opts.name = "hello_bdev"; 225 opts.config_file = "bdev.conf"; 226 227 /* 228 * The user can provide the config file and bdev name at run time. 229 * For example, to use Malloc0 in file bdev.conf run with params 230 * ./hello_bdev -c bdev.conf -b Malloc0 231 * To use passthru bdev PT0 run with params 232 * ./hello_bdev -c bdev.conf -b PT0 233 * If none of the parameters are provide the application will use the 234 * default parameters(-c bdev.conf -b Malloc0). 235 */ 236 if ((rc = spdk_app_parse_args(argc, argv, &opts, "b:", hello_bdev_parse_arg, 237 hello_bdev_usage)) != SPDK_APP_PARSE_ARGS_SUCCESS) { 238 exit(rc); 239 } 240 hello_context.bdev_name = g_bdev_name; 241 242 /* 243 * spdk_app_start() will block running hello_start() until 244 * spdk_app_stop() is called by someone (not simply when 245 * hello_start() returns), or if an error occurs during 246 * spdk_app_start() before hello_start() runs. 247 */ 248 rc = spdk_app_start(&opts, hello_start, &hello_context, NULL); 249 if (rc) { 250 SPDK_ERRLOG("ERROR starting application\n"); 251 } 252 253 /* When the app stops, free up memory that we allocated. */ 254 spdk_dma_free(hello_context.buff); 255 256 /* Gracefully close out all of the SPDK subsystems. */ 257 spdk_app_fini(); 258 return rc; 259 } 260