1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) Intel Corporation. All rights reserved. 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 36 #include "spdk_internal/log.h" 37 #include "spdk/rpc.h" 38 #include "spdk/util.h" 39 #include "spdk/string.h" 40 41 #include "spdk/scsi.h" 42 #include "spdk/vhost.h" 43 #include "vhost_internal.h" 44 #include "spdk/bdev.h" 45 46 struct rpc_vhost_scsi_ctrlr { 47 char *ctrlr; 48 char *cpumask; 49 }; 50 51 static void 52 free_rpc_vhost_scsi_ctrlr(struct rpc_vhost_scsi_ctrlr *req) 53 { 54 free(req->ctrlr); 55 free(req->cpumask); 56 } 57 58 static const struct spdk_json_object_decoder rpc_construct_vhost_ctrlr[] = { 59 {"ctrlr", offsetof(struct rpc_vhost_scsi_ctrlr, ctrlr), spdk_json_decode_string }, 60 {"cpumask", offsetof(struct rpc_vhost_scsi_ctrlr, cpumask), spdk_json_decode_string, true}, 61 }; 62 63 static void 64 spdk_rpc_construct_vhost_scsi_controller(struct spdk_jsonrpc_request *request, 65 const struct spdk_json_val *params) 66 { 67 struct rpc_vhost_scsi_ctrlr req = {0}; 68 struct spdk_json_write_ctx *w; 69 int rc; 70 char buf[64]; 71 uint64_t cpumask; 72 73 if (spdk_json_decode_object(params, rpc_construct_vhost_ctrlr, 74 SPDK_COUNTOF(rpc_construct_vhost_ctrlr), 75 &req)) { 76 SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n"); 77 rc = -EINVAL; 78 goto invalid; 79 } 80 81 cpumask = spdk_app_get_core_mask(); 82 if (req.cpumask != NULL && spdk_vhost_parse_core_mask(req.cpumask, &cpumask)) { 83 rc = -EINVAL; 84 goto invalid; 85 } 86 87 rc = spdk_vhost_scsi_dev_construct(req.ctrlr, cpumask); 88 if (rc < 0) { 89 goto invalid; 90 } 91 92 free_rpc_vhost_scsi_ctrlr(&req); 93 94 w = spdk_jsonrpc_begin_result(request); 95 if (w == NULL) { 96 return; 97 } 98 99 spdk_json_write_bool(w, true); 100 spdk_jsonrpc_end_result(request, w); 101 return; 102 103 invalid: 104 spdk_strerror_r(-rc, buf, sizeof(buf)); 105 free_rpc_vhost_scsi_ctrlr(&req); 106 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf); 107 } 108 SPDK_RPC_REGISTER("construct_vhost_scsi_controller", spdk_rpc_construct_vhost_scsi_controller) 109 110 struct rpc_remove_vhost_scsi_ctrlr { 111 char *ctrlr; 112 }; 113 114 static void 115 free_rpc_remove_vhost_scsi_ctrlr(struct rpc_remove_vhost_scsi_ctrlr *req) 116 { 117 free(req->ctrlr); 118 } 119 120 static const struct spdk_json_object_decoder rpc_remove_vhost_ctrlr[] = { 121 {"ctrlr", offsetof(struct rpc_remove_vhost_scsi_ctrlr, ctrlr), spdk_json_decode_string }, 122 }; 123 124 static void 125 spdk_rpc_remove_vhost_scsi_controller(struct spdk_jsonrpc_request *request, 126 const struct spdk_json_val *params) 127 { 128 struct rpc_remove_vhost_scsi_ctrlr req = {NULL}; 129 struct spdk_json_write_ctx *w; 130 struct spdk_vhost_dev *vdev; 131 int rc; 132 char buf[64]; 133 134 if (spdk_json_decode_object(params, rpc_remove_vhost_ctrlr, 135 SPDK_COUNTOF(rpc_remove_vhost_ctrlr), 136 &req)) { 137 SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n"); 138 rc = -EINVAL; 139 goto invalid; 140 } 141 142 if (!(vdev = spdk_vhost_dev_find(req.ctrlr))) { 143 rc = -ENODEV; 144 goto invalid; 145 } 146 147 rc = spdk_vhost_scsi_dev_remove(vdev); 148 if (rc < 0) { 149 goto invalid; 150 } 151 152 free_rpc_remove_vhost_scsi_ctrlr(&req); 153 154 w = spdk_jsonrpc_begin_result(request); 155 if (w == NULL) { 156 return; 157 } 158 159 spdk_json_write_bool(w, true); 160 spdk_jsonrpc_end_result(request, w); 161 return; 162 163 invalid: 164 spdk_strerror_r(-rc, buf, sizeof(buf)); 165 free_rpc_remove_vhost_scsi_ctrlr(&req); 166 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf); 167 } 168 SPDK_RPC_REGISTER("remove_vhost_scsi_controller", spdk_rpc_remove_vhost_scsi_controller) 169 170 171 struct rpc_add_vhost_scsi_ctrlr_lun { 172 char *ctrlr; 173 uint32_t scsi_dev_num; 174 char *lun_name; 175 }; 176 177 static void 178 free_rpc_add_vhost_scsi_ctrlr_lun(struct rpc_add_vhost_scsi_ctrlr_lun *req) 179 { 180 free(req->ctrlr); 181 free(req->lun_name); 182 } 183 184 static const struct spdk_json_object_decoder rpc_vhost_add_lun[] = { 185 {"ctrlr", offsetof(struct rpc_add_vhost_scsi_ctrlr_lun, ctrlr), spdk_json_decode_string }, 186 {"scsi_dev_num", offsetof(struct rpc_add_vhost_scsi_ctrlr_lun, scsi_dev_num), spdk_json_decode_uint32}, 187 {"lun_name", offsetof(struct rpc_add_vhost_scsi_ctrlr_lun, lun_name), spdk_json_decode_string }, 188 }; 189 190 static void 191 spdk_rpc_add_vhost_scsi_lun(struct spdk_jsonrpc_request *request, 192 const struct spdk_json_val *params) 193 { 194 struct rpc_add_vhost_scsi_ctrlr_lun req = {0}; 195 struct spdk_json_write_ctx *w; 196 int rc; 197 char buf[64]; 198 199 if (spdk_json_decode_object(params, rpc_vhost_add_lun, 200 SPDK_COUNTOF(rpc_vhost_add_lun), 201 &req)) { 202 SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n"); 203 rc = -EINVAL; 204 goto invalid; 205 } 206 207 rc = spdk_vhost_scsi_dev_add_dev(req.ctrlr, req.scsi_dev_num, req.lun_name); 208 if (rc < 0) { 209 goto invalid; 210 } 211 212 free_rpc_add_vhost_scsi_ctrlr_lun(&req); 213 214 w = spdk_jsonrpc_begin_result(request); 215 if (w == NULL) { 216 return; 217 } 218 219 spdk_json_write_bool(w, true); 220 spdk_jsonrpc_end_result(request, w); 221 return; 222 223 invalid: 224 spdk_strerror_r(-rc, buf, sizeof(buf)); 225 free_rpc_add_vhost_scsi_ctrlr_lun(&req); 226 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf); 227 } 228 SPDK_RPC_REGISTER("add_vhost_scsi_lun", spdk_rpc_add_vhost_scsi_lun) 229 230 struct rpc_remove_vhost_scsi_ctrlr_dev { 231 char *ctrlr; 232 uint32_t scsi_dev_num; 233 }; 234 235 static void 236 free_rpc_remove_vhost_scsi_ctrlr_dev(struct rpc_remove_vhost_scsi_ctrlr_dev *req) 237 { 238 free(req->ctrlr); 239 } 240 241 static const struct spdk_json_object_decoder rpc_vhost_remove_dev[] = { 242 {"ctrlr", offsetof(struct rpc_remove_vhost_scsi_ctrlr_dev, ctrlr), spdk_json_decode_string }, 243 {"scsi_dev_num", offsetof(struct rpc_remove_vhost_scsi_ctrlr_dev, scsi_dev_num), spdk_json_decode_uint32}, 244 }; 245 246 static void 247 spdk_rpc_remove_vhost_scsi_dev(struct spdk_jsonrpc_request *request, 248 const struct spdk_json_val *params) 249 { 250 struct rpc_remove_vhost_scsi_ctrlr_dev req = {0}; 251 struct spdk_json_write_ctx *w; 252 struct spdk_vhost_dev *vdev; 253 int rc; 254 char buf[64]; 255 256 if (spdk_json_decode_object(params, rpc_vhost_remove_dev, 257 SPDK_COUNTOF(rpc_vhost_remove_dev), 258 &req)) { 259 SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n"); 260 rc = -EINVAL; 261 goto invalid; 262 } 263 264 if (!(vdev = spdk_vhost_dev_find(req.ctrlr))) { 265 rc = -ENODEV; 266 goto invalid; 267 } 268 269 rc = spdk_vhost_scsi_dev_remove_dev(vdev, req.scsi_dev_num); 270 if (rc < 0) { 271 goto invalid; 272 } 273 274 free_rpc_remove_vhost_scsi_ctrlr_dev(&req); 275 276 w = spdk_jsonrpc_begin_result(request); 277 if (w == NULL) { 278 return; 279 } 280 281 spdk_json_write_bool(w, true); 282 spdk_jsonrpc_end_result(request, w); 283 return; 284 285 invalid: 286 spdk_strerror_r(-rc, buf, sizeof(buf)); 287 free_rpc_remove_vhost_scsi_ctrlr_dev(&req); 288 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf); 289 } 290 SPDK_RPC_REGISTER("remove_vhost_scsi_dev", spdk_rpc_remove_vhost_scsi_dev) 291 292 struct rpc_vhost_blk_ctrlr { 293 char *ctrlr; 294 char *dev_name; 295 char *cpumask; 296 bool readonly; 297 }; 298 299 static const struct spdk_json_object_decoder rpc_construct_vhost_blk_ctrlr[] = { 300 {"ctrlr", offsetof(struct rpc_vhost_blk_ctrlr, ctrlr), spdk_json_decode_string }, 301 {"dev_name", offsetof(struct rpc_vhost_blk_ctrlr, dev_name), spdk_json_decode_string }, 302 {"cpumask", offsetof(struct rpc_vhost_blk_ctrlr, cpumask), spdk_json_decode_string, true}, 303 {"readonly", offsetof(struct rpc_vhost_blk_ctrlr, readonly), spdk_json_decode_bool, true}, 304 }; 305 306 static void 307 free_rpc_vhost_blk_ctrlr(struct rpc_vhost_blk_ctrlr *req) 308 { 309 free(req->ctrlr); 310 free(req->dev_name); 311 free(req->cpumask); 312 } 313 314 static void 315 spdk_rpc_construct_vhost_blk_controller(struct spdk_jsonrpc_request *request, 316 const struct spdk_json_val *params) 317 { 318 struct rpc_vhost_blk_ctrlr req = {0}; 319 struct spdk_json_write_ctx *w; 320 int rc; 321 char buf[64]; 322 uint64_t cpumask; 323 324 if (spdk_json_decode_object(params, rpc_construct_vhost_blk_ctrlr, 325 SPDK_COUNTOF(rpc_construct_vhost_blk_ctrlr), 326 &req)) { 327 SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n"); 328 rc = -EINVAL; 329 goto invalid; 330 } 331 332 cpumask = spdk_app_get_core_mask(); 333 if (req.cpumask != NULL && spdk_vhost_parse_core_mask(req.cpumask, &cpumask)) { 334 rc = -EINVAL; 335 goto invalid; 336 } 337 338 rc = spdk_vhost_blk_construct(req.ctrlr, cpumask, req.dev_name, req.readonly); 339 if (rc < 0) { 340 goto invalid; 341 } 342 343 free_rpc_vhost_blk_ctrlr(&req); 344 345 w = spdk_jsonrpc_begin_result(request); 346 if (w == NULL) { 347 return; 348 } 349 350 spdk_json_write_bool(w, true); 351 spdk_jsonrpc_end_result(request, w); 352 return; 353 354 invalid: 355 spdk_strerror_r(-rc, buf, sizeof(buf)); 356 free_rpc_vhost_blk_ctrlr(&req); 357 spdk_jsonrpc_send_error_response(request, 358 SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf); 359 360 } 361 SPDK_RPC_REGISTER("construct_vhost_blk_controller", spdk_rpc_construct_vhost_blk_controller) 362 363 struct rpc_remove_vhost_blk_ctrlr { 364 char *ctrlr; 365 }; 366 367 static const struct spdk_json_object_decoder rpc_remove_vhost_blk_ctrlr[] = { 368 {"ctrlr", offsetof(struct rpc_remove_vhost_blk_ctrlr, ctrlr), spdk_json_decode_string }, 369 }; 370 371 static void 372 free_rpc_remove_vhost_blk_ctrlr(struct rpc_remove_vhost_blk_ctrlr *req) 373 { 374 free(req->ctrlr); 375 } 376 377 static void 378 spdk_rpc_remove_vhost_blk_controller(struct spdk_jsonrpc_request *request, 379 const struct spdk_json_val *params) 380 { 381 struct rpc_remove_vhost_blk_ctrlr req = {NULL}; 382 struct spdk_json_write_ctx *w; 383 struct spdk_vhost_dev *vdev; 384 int rc; 385 char buf[64]; 386 387 if (spdk_json_decode_object(params, rpc_remove_vhost_blk_ctrlr, 388 SPDK_COUNTOF(rpc_remove_vhost_blk_ctrlr), &req)) { 389 SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n"); 390 rc = -EINVAL; 391 goto invalid; 392 } 393 394 if (!(vdev = spdk_vhost_dev_find(req.ctrlr))) { 395 rc = -ENODEV; 396 goto invalid; 397 } 398 399 rc = spdk_vhost_blk_destroy(vdev); 400 if (rc < 0) { 401 goto invalid; 402 } 403 404 free_rpc_remove_vhost_blk_ctrlr(&req); 405 406 w = spdk_jsonrpc_begin_result(request); 407 if (w == NULL) { 408 return; 409 } 410 411 spdk_json_write_bool(w, true); 412 spdk_jsonrpc_end_result(request, w); 413 return; 414 415 invalid: 416 spdk_strerror_r(-rc, buf, sizeof(buf)); 417 free_rpc_remove_vhost_blk_ctrlr(&req); 418 spdk_jsonrpc_send_error_response(request, 419 SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf); 420 421 } 422 SPDK_RPC_REGISTER("remove_vhost_blk_controller", spdk_rpc_remove_vhost_blk_controller) 423 424 static void 425 spdk_rpc_get_vhost_controllers(struct spdk_jsonrpc_request *request, 426 const struct spdk_json_val *params) 427 { 428 struct spdk_json_write_ctx *w; 429 struct spdk_vhost_dev *vdev = NULL; 430 431 if (params != NULL) { 432 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 433 "get_vhost_controllers requires no parameters"); 434 return; 435 } 436 437 w = spdk_jsonrpc_begin_result(request); 438 if (w == NULL) { 439 return; 440 } 441 442 spdk_json_write_array_begin(w); 443 while ((vdev = spdk_vhost_dev_next(vdev)) != NULL) { 444 spdk_json_write_object_begin(w); 445 446 spdk_json_write_name(w, "ctrlr"); 447 spdk_json_write_string(w, spdk_vhost_dev_get_name(vdev)); 448 449 spdk_json_write_name(w, "cpumask"); 450 spdk_json_write_string_fmt(w, "%#" PRIx64, spdk_vhost_dev_get_cpumask(vdev)); 451 452 spdk_json_write_name(w, "backend_specific"); 453 454 spdk_json_write_object_begin(w); 455 spdk_vhost_dump_config_json(vdev, w); 456 spdk_json_write_object_end(w); 457 458 spdk_json_write_object_end(w); 459 } 460 461 spdk_json_write_array_end(w); 462 spdk_jsonrpc_end_result(request, w); 463 } 464 SPDK_RPC_REGISTER("get_vhost_controllers", spdk_rpc_get_vhost_controllers) 465