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 14 #include "vfu_virtio_internal.h" 15 16 struct rpc_delete_vfu_endpoint { 17 char *name; 18 }; 19 20 static const struct spdk_json_object_decoder rpc_delete_vfu_endpoint_decode[] = { 21 {"name", offsetof(struct rpc_delete_vfu_endpoint, name), spdk_json_decode_string } 22 }; 23 24 static void 25 free_rpc_delete_vfu_endpoint(struct rpc_delete_vfu_endpoint *req) 26 { 27 free(req->name); 28 } 29 30 static void 31 rpc_vfu_virtio_delete_endpoint(struct spdk_jsonrpc_request *request, 32 const struct spdk_json_val *params) 33 { 34 struct rpc_delete_vfu_endpoint req = {0}; 35 int rc; 36 37 if (spdk_json_decode_object(params, rpc_delete_vfu_endpoint_decode, 38 SPDK_COUNTOF(rpc_delete_vfu_endpoint_decode), 39 &req)) { 40 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 41 rc = -EINVAL; 42 goto invalid; 43 } 44 45 rc = spdk_vfu_delete_endpoint(req.name); 46 if (rc < 0) { 47 goto invalid; 48 } 49 free_rpc_delete_vfu_endpoint(&req); 50 51 spdk_jsonrpc_send_bool_response(request, true); 52 return; 53 54 invalid: 55 free_rpc_delete_vfu_endpoint(&req); 56 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 57 spdk_strerror(-rc)); 58 } 59 SPDK_RPC_REGISTER("vfu_virtio_delete_endpoint", rpc_vfu_virtio_delete_endpoint, 60 SPDK_RPC_RUNTIME) 61 62 struct rpc_vfu_virtio_create_blk { 63 char *name; 64 char *bdev_name; 65 char *cpumask; 66 uint16_t num_queues; 67 uint16_t qsize; 68 bool packed_ring; 69 }; 70 71 static const struct spdk_json_object_decoder rpc_construct_vfu_virtio_create_blk[] = { 72 {"name", offsetof(struct rpc_vfu_virtio_create_blk, name), spdk_json_decode_string }, 73 {"bdev_name", offsetof(struct rpc_vfu_virtio_create_blk, bdev_name), spdk_json_decode_string }, 74 {"cpumask", offsetof(struct rpc_vfu_virtio_create_blk, cpumask), spdk_json_decode_string, true}, 75 {"num_queues", offsetof(struct rpc_vfu_virtio_create_blk, num_queues), spdk_json_decode_uint16, true }, 76 {"qsize", offsetof(struct rpc_vfu_virtio_create_blk, qsize), spdk_json_decode_uint16, true }, 77 {"packed_ring", offsetof(struct rpc_vfu_virtio_create_blk, packed_ring), spdk_json_decode_bool, true}, 78 }; 79 80 static void 81 free_rpc_vfu_virtio_create_blk(struct rpc_vfu_virtio_create_blk *req) 82 { 83 free(req->name); 84 free(req->bdev_name); 85 free(req->cpumask); 86 } 87 88 static void 89 rpc_vfu_virtio_create_blk_endpoint(struct spdk_jsonrpc_request *request, 90 const struct spdk_json_val *params) 91 { 92 struct rpc_vfu_virtio_create_blk req = {0}; 93 int rc; 94 95 if (spdk_json_decode_object(params, rpc_construct_vfu_virtio_create_blk, 96 SPDK_COUNTOF(rpc_construct_vfu_virtio_create_blk), 97 &req)) { 98 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 99 rc = -EINVAL; 100 goto invalid; 101 } 102 103 rc = spdk_vfu_create_endpoint(req.name, req.cpumask, "virtio_blk"); 104 if (rc) { 105 SPDK_ERRLOG("Failed to create virtio_blk endpoint\n"); 106 goto invalid; 107 } 108 109 rc = vfu_virtio_blk_add_bdev(req.name, req.bdev_name, req.num_queues, req.qsize, 110 req.packed_ring); 111 if (rc < 0) { 112 spdk_vfu_delete_endpoint(req.name); 113 goto invalid; 114 } 115 free_rpc_vfu_virtio_create_blk(&req); 116 117 spdk_jsonrpc_send_bool_response(request, true); 118 return; 119 120 invalid: 121 free_rpc_vfu_virtio_create_blk(&req); 122 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 123 spdk_strerror(-rc)); 124 } 125 SPDK_RPC_REGISTER("vfu_virtio_create_blk_endpoint", rpc_vfu_virtio_create_blk_endpoint, 126 SPDK_RPC_RUNTIME) 127 128 struct rpc_vfu_virtio_scsi { 129 char *name; 130 uint8_t scsi_target_num; 131 char *bdev_name; 132 }; 133 134 static const struct spdk_json_object_decoder rpc_construct_vfu_virtio_scsi[] = { 135 {"name", offsetof(struct rpc_vfu_virtio_scsi, name), spdk_json_decode_string }, 136 {"scsi_target_num", offsetof(struct rpc_vfu_virtio_scsi, scsi_target_num), spdk_json_decode_uint8 }, 137 {"bdev_name", offsetof(struct rpc_vfu_virtio_scsi, bdev_name), spdk_json_decode_string }, 138 }; 139 140 static void 141 free_rpc_vfu_virtio_scsi(struct rpc_vfu_virtio_scsi *req) 142 { 143 free(req->name); 144 free(req->bdev_name); 145 } 146 147 static void 148 rpc_vfu_virtio_scsi_add_target(struct spdk_jsonrpc_request *request, 149 const struct spdk_json_val *params) 150 { 151 struct rpc_vfu_virtio_scsi req = {0}; 152 int rc; 153 154 if (spdk_json_decode_object(params, rpc_construct_vfu_virtio_scsi, 155 SPDK_COUNTOF(rpc_construct_vfu_virtio_scsi), 156 &req)) { 157 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 158 rc = -EINVAL; 159 goto invalid; 160 } 161 162 rc = vfu_virtio_scsi_add_target(req.name, req.scsi_target_num, req.bdev_name);; 163 if (rc < 0) { 164 goto invalid; 165 } 166 167 free_rpc_vfu_virtio_scsi(&req); 168 spdk_jsonrpc_send_bool_response(request, true); 169 return; 170 171 invalid: 172 free_rpc_vfu_virtio_scsi(&req); 173 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 174 spdk_strerror(-rc)); 175 } 176 SPDK_RPC_REGISTER("vfu_virtio_scsi_add_target", rpc_vfu_virtio_scsi_add_target, 177 SPDK_RPC_RUNTIME) 178 179 struct rpc_vfu_virtio_scsi_remove { 180 char *name; 181 uint8_t scsi_target_num; 182 }; 183 184 static const struct spdk_json_object_decoder rpc_remove_vfu_virtio_scsi_target[] = { 185 {"name", offsetof(struct rpc_vfu_virtio_scsi_remove, name), spdk_json_decode_string }, 186 {"scsi_target_num", offsetof(struct rpc_vfu_virtio_scsi_remove, scsi_target_num), spdk_json_decode_uint8 }, 187 }; 188 189 static void 190 free_rpc_vfu_virtio_scsi_remove(struct rpc_vfu_virtio_scsi_remove *req) 191 { 192 free(req->name); 193 } 194 195 static void 196 rpc_vfu_virtio_scsi_remove_target(struct spdk_jsonrpc_request *request, 197 const struct spdk_json_val *params) 198 { 199 struct rpc_vfu_virtio_scsi_remove req = {0}; 200 int rc; 201 202 if (spdk_json_decode_object(params, rpc_remove_vfu_virtio_scsi_target, 203 SPDK_COUNTOF(rpc_remove_vfu_virtio_scsi_target), 204 &req)) { 205 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 206 rc = -EINVAL; 207 goto invalid; 208 } 209 210 rc = vfu_virtio_scsi_remove_target(req.name, req.scsi_target_num); 211 if (rc < 0) { 212 goto invalid; 213 } 214 215 free_rpc_vfu_virtio_scsi_remove(&req); 216 spdk_jsonrpc_send_bool_response(request, true); 217 return; 218 219 invalid: 220 free_rpc_vfu_virtio_scsi_remove(&req); 221 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 222 spdk_strerror(-rc)); 223 } 224 SPDK_RPC_REGISTER("vfu_virtio_scsi_remove_target", rpc_vfu_virtio_scsi_remove_target, 225 SPDK_RPC_RUNTIME) 226 227 struct rpc_vfu_virtio_create_scsi { 228 char *name; 229 char *cpumask; 230 uint16_t num_io_queues; 231 uint16_t qsize; 232 bool packed_ring; 233 }; 234 235 static const struct spdk_json_object_decoder rpc_construct_vfu_virtio_create_scsi[] = { 236 {"name", offsetof(struct rpc_vfu_virtio_create_scsi, name), spdk_json_decode_string }, 237 {"cpumask", offsetof(struct rpc_vfu_virtio_create_scsi, cpumask), spdk_json_decode_string, true}, 238 {"num_io_queues", offsetof(struct rpc_vfu_virtio_create_scsi, num_io_queues), spdk_json_decode_uint16, true }, 239 {"qsize", offsetof(struct rpc_vfu_virtio_create_scsi, qsize), spdk_json_decode_uint16, true }, 240 {"packed_ring", offsetof(struct rpc_vfu_virtio_create_scsi, packed_ring), spdk_json_decode_bool, true}, 241 }; 242 243 static void 244 free_rpc_vfu_virtio_create_scsi(struct rpc_vfu_virtio_create_scsi *req) 245 { 246 free(req->name); 247 free(req->cpumask); 248 } 249 250 static void 251 rpc_vfu_virtio_create_scsi_endpoint(struct spdk_jsonrpc_request *request, 252 const struct spdk_json_val *params) 253 { 254 struct rpc_vfu_virtio_create_scsi req = {0}; 255 int rc; 256 257 if (spdk_json_decode_object(params, rpc_construct_vfu_virtio_create_scsi, 258 SPDK_COUNTOF(rpc_construct_vfu_virtio_create_scsi), 259 &req)) { 260 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 261 rc = -EINVAL; 262 goto invalid; 263 } 264 265 rc = spdk_vfu_create_endpoint(req.name, req.cpumask, "virtio_scsi"); 266 if (rc) { 267 SPDK_ERRLOG("Failed to create virtio_blk endpoint\n"); 268 goto invalid; 269 } 270 271 rc = vfu_virtio_scsi_set_options(req.name, req.num_io_queues, req.qsize, req.packed_ring); 272 if (rc < 0) { 273 spdk_vfu_delete_endpoint(req.name); 274 goto invalid; 275 } 276 free_rpc_vfu_virtio_create_scsi(&req); 277 278 spdk_jsonrpc_send_bool_response(request, true); 279 return; 280 281 invalid: 282 free_rpc_vfu_virtio_create_scsi(&req); 283 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 284 spdk_strerror(-rc)); 285 } 286 SPDK_RPC_REGISTER("vfu_virtio_create_scsi_endpoint", rpc_vfu_virtio_create_scsi_endpoint, 287 SPDK_RPC_RUNTIME) 288