1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2022 Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "spdk/bdev.h" 7 #include "spdk/log.h" 8 #include "spdk/rpc.h" 9 #include "spdk/env.h" 10 #include "spdk/string.h" 11 #include "spdk/util.h" 12 #include "spdk/thread.h" 13 #include "spdk/config.h" 14 15 #include "vfu_virtio_internal.h" 16 17 struct rpc_delete_vfu_endpoint { 18 char *name; 19 }; 20 21 static const struct spdk_json_object_decoder rpc_delete_vfu_endpoint_decode[] = { 22 {"name", offsetof(struct rpc_delete_vfu_endpoint, name), spdk_json_decode_string } 23 }; 24 25 static void 26 free_rpc_delete_vfu_endpoint(struct rpc_delete_vfu_endpoint *req) 27 { 28 free(req->name); 29 } 30 31 static void 32 rpc_vfu_virtio_delete_endpoint(struct spdk_jsonrpc_request *request, 33 const struct spdk_json_val *params) 34 { 35 struct rpc_delete_vfu_endpoint req = {0}; 36 int rc; 37 38 if (spdk_json_decode_object(params, rpc_delete_vfu_endpoint_decode, 39 SPDK_COUNTOF(rpc_delete_vfu_endpoint_decode), 40 &req)) { 41 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 42 rc = -EINVAL; 43 goto invalid; 44 } 45 46 rc = spdk_vfu_delete_endpoint(req.name); 47 if (rc < 0) { 48 goto invalid; 49 } 50 free_rpc_delete_vfu_endpoint(&req); 51 52 spdk_jsonrpc_send_bool_response(request, true); 53 return; 54 55 invalid: 56 free_rpc_delete_vfu_endpoint(&req); 57 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 58 spdk_strerror(-rc)); 59 } 60 SPDK_RPC_REGISTER("vfu_virtio_delete_endpoint", rpc_vfu_virtio_delete_endpoint, 61 SPDK_RPC_RUNTIME) 62 63 struct rpc_vfu_virtio_create_blk { 64 char *name; 65 char *bdev_name; 66 char *cpumask; 67 uint16_t num_queues; 68 uint16_t qsize; 69 bool packed_ring; 70 }; 71 72 static const struct spdk_json_object_decoder rpc_construct_vfu_virtio_create_blk[] = { 73 {"name", offsetof(struct rpc_vfu_virtio_create_blk, name), spdk_json_decode_string }, 74 {"bdev_name", offsetof(struct rpc_vfu_virtio_create_blk, bdev_name), spdk_json_decode_string }, 75 {"cpumask", offsetof(struct rpc_vfu_virtio_create_blk, cpumask), spdk_json_decode_string, true}, 76 {"num_queues", offsetof(struct rpc_vfu_virtio_create_blk, num_queues), spdk_json_decode_uint16, true }, 77 {"qsize", offsetof(struct rpc_vfu_virtio_create_blk, qsize), spdk_json_decode_uint16, true }, 78 {"packed_ring", offsetof(struct rpc_vfu_virtio_create_blk, packed_ring), spdk_json_decode_bool, true}, 79 }; 80 81 static void 82 free_rpc_vfu_virtio_create_blk(struct rpc_vfu_virtio_create_blk *req) 83 { 84 free(req->name); 85 free(req->bdev_name); 86 free(req->cpumask); 87 } 88 89 static void 90 rpc_vfu_virtio_create_blk_endpoint(struct spdk_jsonrpc_request *request, 91 const struct spdk_json_val *params) 92 { 93 struct rpc_vfu_virtio_create_blk req = {0}; 94 int rc; 95 96 if (spdk_json_decode_object(params, rpc_construct_vfu_virtio_create_blk, 97 SPDK_COUNTOF(rpc_construct_vfu_virtio_create_blk), 98 &req)) { 99 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 100 rc = -EINVAL; 101 goto invalid; 102 } 103 104 rc = spdk_vfu_create_endpoint(req.name, req.cpumask, "virtio_blk"); 105 if (rc) { 106 SPDK_ERRLOG("Failed to create virtio_blk endpoint\n"); 107 goto invalid; 108 } 109 110 rc = vfu_virtio_blk_add_bdev(req.name, req.bdev_name, req.num_queues, req.qsize, 111 req.packed_ring); 112 if (rc < 0) { 113 spdk_vfu_delete_endpoint(req.name); 114 goto invalid; 115 } 116 free_rpc_vfu_virtio_create_blk(&req); 117 118 spdk_jsonrpc_send_bool_response(request, true); 119 return; 120 121 invalid: 122 free_rpc_vfu_virtio_create_blk(&req); 123 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 124 spdk_strerror(-rc)); 125 } 126 SPDK_RPC_REGISTER("vfu_virtio_create_blk_endpoint", rpc_vfu_virtio_create_blk_endpoint, 127 SPDK_RPC_RUNTIME) 128 129 struct rpc_vfu_virtio_scsi { 130 char *name; 131 uint8_t scsi_target_num; 132 char *bdev_name; 133 }; 134 135 static const struct spdk_json_object_decoder rpc_construct_vfu_virtio_scsi[] = { 136 {"name", offsetof(struct rpc_vfu_virtio_scsi, name), spdk_json_decode_string }, 137 {"scsi_target_num", offsetof(struct rpc_vfu_virtio_scsi, scsi_target_num), spdk_json_decode_uint8 }, 138 {"bdev_name", offsetof(struct rpc_vfu_virtio_scsi, bdev_name), spdk_json_decode_string }, 139 }; 140 141 static void 142 free_rpc_vfu_virtio_scsi(struct rpc_vfu_virtio_scsi *req) 143 { 144 free(req->name); 145 free(req->bdev_name); 146 } 147 148 static void 149 rpc_vfu_virtio_scsi_add_target(struct spdk_jsonrpc_request *request, 150 const struct spdk_json_val *params) 151 { 152 struct rpc_vfu_virtio_scsi req = {0}; 153 int rc; 154 155 if (spdk_json_decode_object(params, rpc_construct_vfu_virtio_scsi, 156 SPDK_COUNTOF(rpc_construct_vfu_virtio_scsi), 157 &req)) { 158 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 159 rc = -EINVAL; 160 goto invalid; 161 } 162 163 rc = vfu_virtio_scsi_add_target(req.name, req.scsi_target_num, req.bdev_name);; 164 if (rc < 0) { 165 goto invalid; 166 } 167 168 free_rpc_vfu_virtio_scsi(&req); 169 spdk_jsonrpc_send_bool_response(request, true); 170 return; 171 172 invalid: 173 free_rpc_vfu_virtio_scsi(&req); 174 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 175 spdk_strerror(-rc)); 176 } 177 SPDK_RPC_REGISTER("vfu_virtio_scsi_add_target", rpc_vfu_virtio_scsi_add_target, 178 SPDK_RPC_RUNTIME) 179 180 struct rpc_vfu_virtio_scsi_remove { 181 char *name; 182 uint8_t scsi_target_num; 183 }; 184 185 static const struct spdk_json_object_decoder rpc_remove_vfu_virtio_scsi_target[] = { 186 {"name", offsetof(struct rpc_vfu_virtio_scsi_remove, name), spdk_json_decode_string }, 187 {"scsi_target_num", offsetof(struct rpc_vfu_virtio_scsi_remove, scsi_target_num), spdk_json_decode_uint8 }, 188 }; 189 190 static void 191 free_rpc_vfu_virtio_scsi_remove(struct rpc_vfu_virtio_scsi_remove *req) 192 { 193 free(req->name); 194 } 195 196 static void 197 rpc_vfu_virtio_scsi_remove_target(struct spdk_jsonrpc_request *request, 198 const struct spdk_json_val *params) 199 { 200 struct rpc_vfu_virtio_scsi_remove req = {0}; 201 int rc; 202 203 if (spdk_json_decode_object(params, rpc_remove_vfu_virtio_scsi_target, 204 SPDK_COUNTOF(rpc_remove_vfu_virtio_scsi_target), 205 &req)) { 206 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 207 rc = -EINVAL; 208 goto invalid; 209 } 210 211 rc = vfu_virtio_scsi_remove_target(req.name, req.scsi_target_num); 212 if (rc < 0) { 213 goto invalid; 214 } 215 216 free_rpc_vfu_virtio_scsi_remove(&req); 217 spdk_jsonrpc_send_bool_response(request, true); 218 return; 219 220 invalid: 221 free_rpc_vfu_virtio_scsi_remove(&req); 222 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 223 spdk_strerror(-rc)); 224 } 225 SPDK_RPC_REGISTER("vfu_virtio_scsi_remove_target", rpc_vfu_virtio_scsi_remove_target, 226 SPDK_RPC_RUNTIME) 227 228 struct rpc_vfu_virtio_create_scsi { 229 char *name; 230 char *cpumask; 231 uint16_t num_io_queues; 232 uint16_t qsize; 233 bool packed_ring; 234 }; 235 236 static const struct spdk_json_object_decoder rpc_construct_vfu_virtio_create_scsi[] = { 237 {"name", offsetof(struct rpc_vfu_virtio_create_scsi, name), spdk_json_decode_string }, 238 {"cpumask", offsetof(struct rpc_vfu_virtio_create_scsi, cpumask), spdk_json_decode_string, true}, 239 {"num_io_queues", offsetof(struct rpc_vfu_virtio_create_scsi, num_io_queues), spdk_json_decode_uint16, true }, 240 {"qsize", offsetof(struct rpc_vfu_virtio_create_scsi, qsize), spdk_json_decode_uint16, true }, 241 {"packed_ring", offsetof(struct rpc_vfu_virtio_create_scsi, packed_ring), spdk_json_decode_bool, true}, 242 }; 243 244 static void 245 free_rpc_vfu_virtio_create_scsi(struct rpc_vfu_virtio_create_scsi *req) 246 { 247 free(req->name); 248 free(req->cpumask); 249 } 250 251 static void 252 rpc_vfu_virtio_create_scsi_endpoint(struct spdk_jsonrpc_request *request, 253 const struct spdk_json_val *params) 254 { 255 struct rpc_vfu_virtio_create_scsi req = {0}; 256 int rc; 257 258 if (spdk_json_decode_object(params, rpc_construct_vfu_virtio_create_scsi, 259 SPDK_COUNTOF(rpc_construct_vfu_virtio_create_scsi), 260 &req)) { 261 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 262 rc = -EINVAL; 263 goto invalid; 264 } 265 266 rc = spdk_vfu_create_endpoint(req.name, req.cpumask, "virtio_scsi"); 267 if (rc) { 268 SPDK_ERRLOG("Failed to create virtio_blk endpoint\n"); 269 goto invalid; 270 } 271 272 rc = vfu_virtio_scsi_set_options(req.name, req.num_io_queues, req.qsize, req.packed_ring); 273 if (rc < 0) { 274 spdk_vfu_delete_endpoint(req.name); 275 goto invalid; 276 } 277 free_rpc_vfu_virtio_create_scsi(&req); 278 279 spdk_jsonrpc_send_bool_response(request, true); 280 return; 281 282 invalid: 283 free_rpc_vfu_virtio_create_scsi(&req); 284 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 285 spdk_strerror(-rc)); 286 } 287 SPDK_RPC_REGISTER("vfu_virtio_create_scsi_endpoint", rpc_vfu_virtio_create_scsi_endpoint, 288 SPDK_RPC_RUNTIME) 289 290 #ifdef SPDK_CONFIG_FSDEV 291 struct rpc_vfu_virtio_create_fs { 292 char *name; 293 char *fsdev_name; 294 char *tag; 295 char *cpumask; 296 uint16_t num_queues; 297 uint16_t qsize; 298 bool packed_ring; 299 struct spdk_jsonrpc_request *request; 300 }; 301 302 static const struct spdk_json_object_decoder rpc_construct_vfu_virtio_create_fs[] = { 303 {"name", offsetof(struct rpc_vfu_virtio_create_fs, name), spdk_json_decode_string }, 304 {"fsdev_name", offsetof(struct rpc_vfu_virtio_create_fs, fsdev_name), spdk_json_decode_string }, 305 {"tag", offsetof(struct rpc_vfu_virtio_create_fs, tag), spdk_json_decode_string }, 306 {"cpumask", offsetof(struct rpc_vfu_virtio_create_fs, cpumask), spdk_json_decode_string, true}, 307 {"num_queues", offsetof(struct rpc_vfu_virtio_create_fs, num_queues), spdk_json_decode_uint16, true }, 308 {"qsize", offsetof(struct rpc_vfu_virtio_create_fs, qsize), spdk_json_decode_uint16, true }, 309 {"packed_ring", offsetof(struct rpc_vfu_virtio_create_fs, packed_ring), spdk_json_decode_bool, true}, 310 }; 311 312 static void 313 free_rpc_vfu_virtio_create_fs(struct rpc_vfu_virtio_create_fs *req) 314 { 315 if (req) { 316 free(req->name); 317 free(req->fsdev_name); 318 free(req->tag); 319 free(req->cpumask); 320 free(req); 321 } 322 } 323 324 static void 325 rpc_vfu_virtio_create_fs_endpoint_cpl(void *cb_arg, int status) 326 { 327 struct rpc_vfu_virtio_create_fs *req = cb_arg; 328 329 spdk_jsonrpc_send_bool_response(req->request, true); 330 331 free_rpc_vfu_virtio_create_fs(req); 332 } 333 334 static void 335 rpc_vfu_virtio_create_fs_endpoint(struct spdk_jsonrpc_request *request, 336 const struct spdk_json_val *params) 337 { 338 struct rpc_vfu_virtio_create_fs *req; 339 int rc; 340 341 req = calloc(1, sizeof(*req)); 342 if (!req) { 343 SPDK_ERRLOG("cannot allocate req\n"); 344 rc = -ENOMEM; 345 goto invalid; 346 } 347 348 if (spdk_json_decode_object(params, rpc_construct_vfu_virtio_create_fs, 349 SPDK_COUNTOF(rpc_construct_vfu_virtio_create_fs), 350 req)) { 351 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 352 rc = -EINVAL; 353 goto invalid; 354 } 355 356 rc = spdk_vfu_create_endpoint(req->name, req->cpumask, "virtio_fs"); 357 if (rc) { 358 SPDK_ERRLOG("Failed to create virtio_fs endpoint\n"); 359 goto invalid; 360 } 361 362 req->request = request; 363 364 rc = vfu_virtio_fs_add_fsdev(req->name, req->fsdev_name, req->tag, req->num_queues, req->qsize, 365 req->packed_ring, rpc_vfu_virtio_create_fs_endpoint_cpl, req); 366 if (rc < 0) { 367 spdk_vfu_delete_endpoint(req->name); 368 goto invalid; 369 } 370 371 return; 372 373 invalid: 374 free_rpc_vfu_virtio_create_fs(req); 375 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 376 spdk_strerror(-rc)); 377 } 378 SPDK_RPC_REGISTER("vfu_virtio_create_fs_endpoint", rpc_vfu_virtio_create_fs_endpoint, 379 SPDK_RPC_RUNTIME) 380 #endif 381