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 40 #include "spdk/scsi.h" 41 #include "spdk/vhost.h" 42 #include "vhost_internal.h" 43 #include "spdk/bdev.h" 44 45 static void 46 json_scsi_dev_write(struct spdk_json_write_ctx *ctx, struct spdk_scsi_dev *dev) 47 { 48 int l; 49 50 spdk_json_write_name(ctx, "id"); 51 spdk_json_write_int32(ctx, spdk_scsi_dev_get_id(dev)); 52 53 spdk_json_write_name(ctx, "device_name"); 54 spdk_json_write_string(ctx, spdk_scsi_dev_get_name(dev)); 55 56 spdk_json_write_name(ctx, "luns"); 57 spdk_json_write_array_begin(ctx); 58 59 for (l = 0; l < SPDK_SCSI_DEV_MAX_LUN; l++) { 60 struct spdk_scsi_lun *lun = spdk_scsi_dev_get_lun(dev, l); 61 62 if (!lun) { 63 continue; 64 } 65 66 spdk_json_write_object_begin(ctx); 67 68 spdk_json_write_name(ctx, "id"); 69 spdk_json_write_int32(ctx, spdk_scsi_lun_get_id(lun)); 70 71 spdk_json_write_name(ctx, "name"); 72 spdk_json_write_string(ctx, spdk_scsi_lun_get_name(lun)); 73 74 spdk_json_write_object_end(ctx); 75 } 76 spdk_json_write_array_end(ctx); 77 } 78 79 static void 80 spdk_rpc_get_vhost_scsi_controllers(struct spdk_jsonrpc_request *request, 81 const struct spdk_json_val *params) 82 { 83 struct spdk_json_write_ctx *w; 84 struct spdk_vhost_dev *vdev = NULL; 85 struct spdk_scsi_dev *dev; 86 uint32_t i; 87 88 if (params != NULL) { 89 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 90 "get_vhost_scsi_controllers requires no parameters"); 91 return; 92 } 93 94 w = spdk_jsonrpc_begin_result(request); 95 if (w == NULL) { 96 return; 97 } 98 99 spdk_json_write_array_begin(w); 100 while ((vdev = spdk_vhost_dev_next(vdev)) != NULL) { 101 if (vdev->type != SPDK_VHOST_DEV_T_SCSI) { 102 continue; 103 } 104 105 spdk_json_write_object_begin(w); 106 107 spdk_json_write_name(w, "ctrlr"); 108 spdk_json_write_string(w, spdk_vhost_dev_get_name(vdev)); 109 110 spdk_json_write_name(w, "cpu_mask"); 111 spdk_json_write_string_fmt(w, "%#" PRIx64, spdk_vhost_dev_get_cpumask(vdev)); 112 113 spdk_json_write_name(w, "scsi_devs"); 114 spdk_json_write_array_begin(w); 115 116 for (i = 0; i < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS; i++) { 117 dev = spdk_vhost_scsi_dev_get_dev(vdev, i); 118 if (!dev) 119 continue; 120 121 spdk_json_write_object_begin(w); 122 spdk_json_write_name(w, "scsi_dev_num"); 123 spdk_json_write_uint32(w, i); 124 json_scsi_dev_write(w, dev); 125 spdk_json_write_object_end(w); 126 } 127 128 spdk_json_write_array_end(w); // devs 129 130 spdk_json_write_object_end(w); // ctrl 131 } 132 spdk_json_write_array_end(w); 133 spdk_jsonrpc_end_result(request, w); 134 return; 135 } 136 SPDK_RPC_REGISTER("get_vhost_scsi_controllers", spdk_rpc_get_vhost_scsi_controllers) 137 138 struct rpc_vhost_scsi_ctrlr { 139 char *ctrlr; 140 char *cpumask; 141 }; 142 143 static void 144 free_rpc_vhost_scsi_ctrlr(struct rpc_vhost_scsi_ctrlr *req) 145 { 146 free(req->ctrlr); 147 free(req->cpumask); 148 } 149 150 static const struct spdk_json_object_decoder rpc_construct_vhost_ctrlr[] = { 151 {"ctrlr", offsetof(struct rpc_vhost_scsi_ctrlr, ctrlr), spdk_json_decode_string }, 152 {"cpumask", offsetof(struct rpc_vhost_scsi_ctrlr, cpumask), spdk_json_decode_string, true}, 153 }; 154 155 static void 156 spdk_rpc_construct_vhost_scsi_controller(struct spdk_jsonrpc_request *request, 157 const struct spdk_json_val *params) 158 { 159 struct rpc_vhost_scsi_ctrlr req = {0}; 160 struct spdk_json_write_ctx *w; 161 int rc; 162 uint64_t cpumask; 163 164 if (spdk_json_decode_object(params, rpc_construct_vhost_ctrlr, 165 SPDK_COUNTOF(rpc_construct_vhost_ctrlr), 166 &req)) { 167 SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n"); 168 rc = -EINVAL; 169 goto invalid; 170 } 171 172 cpumask = spdk_app_get_core_mask(); 173 if (req.cpumask != NULL && spdk_vhost_parse_core_mask(req.cpumask, &cpumask)) { 174 rc = -EINVAL; 175 goto invalid; 176 } 177 178 rc = spdk_vhost_scsi_dev_construct(req.ctrlr, cpumask); 179 if (rc < 0) { 180 goto invalid; 181 } 182 183 free_rpc_vhost_scsi_ctrlr(&req); 184 185 w = spdk_jsonrpc_begin_result(request); 186 if (w == NULL) { 187 return; 188 } 189 190 spdk_json_write_bool(w, true); 191 spdk_jsonrpc_end_result(request, w); 192 return; 193 194 invalid: 195 free_rpc_vhost_scsi_ctrlr(&req); 196 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, strerror(-rc)); 197 } 198 SPDK_RPC_REGISTER("construct_vhost_scsi_controller", spdk_rpc_construct_vhost_scsi_controller) 199 200 struct rpc_remove_vhost_scsi_ctrlr { 201 char *ctrlr; 202 }; 203 204 static void 205 free_rpc_remove_vhost_scsi_ctrlr(struct rpc_remove_vhost_scsi_ctrlr *req) 206 { 207 free(req->ctrlr); 208 } 209 210 static const struct spdk_json_object_decoder rpc_remove_vhost_ctrlr[] = { 211 {"ctrlr", offsetof(struct rpc_remove_vhost_scsi_ctrlr, ctrlr), spdk_json_decode_string }, 212 }; 213 214 static void 215 spdk_rpc_remove_vhost_scsi_controller(struct spdk_jsonrpc_request *request, 216 const struct spdk_json_val *params) 217 { 218 struct rpc_remove_vhost_scsi_ctrlr req = {NULL}; 219 struct spdk_json_write_ctx *w; 220 struct spdk_vhost_dev *vdev; 221 int rc; 222 223 if (spdk_json_decode_object(params, rpc_remove_vhost_ctrlr, 224 SPDK_COUNTOF(rpc_remove_vhost_ctrlr), 225 &req)) { 226 SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n"); 227 rc = -EINVAL; 228 goto invalid; 229 } 230 231 if (!(vdev = spdk_vhost_dev_find(req.ctrlr))) { 232 rc = -ENODEV; 233 goto invalid; 234 } 235 236 rc = spdk_vhost_scsi_dev_remove(vdev); 237 if (rc < 0) { 238 goto invalid; 239 } 240 241 free_rpc_remove_vhost_scsi_ctrlr(&req); 242 243 w = spdk_jsonrpc_begin_result(request); 244 if (w == NULL) { 245 return; 246 } 247 248 spdk_json_write_bool(w, true); 249 spdk_jsonrpc_end_result(request, w); 250 return; 251 252 invalid: 253 free_rpc_remove_vhost_scsi_ctrlr(&req); 254 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, strerror(-rc)); 255 } 256 SPDK_RPC_REGISTER("remove_vhost_scsi_controller", spdk_rpc_remove_vhost_scsi_controller) 257 258 259 struct rpc_add_vhost_scsi_ctrlr_lun { 260 char *ctrlr; 261 uint32_t scsi_dev_num; 262 char *lun_name; 263 }; 264 265 static void 266 free_rpc_add_vhost_scsi_ctrlr_lun(struct rpc_add_vhost_scsi_ctrlr_lun *req) 267 { 268 free(req->ctrlr); 269 free(req->lun_name); 270 } 271 272 static const struct spdk_json_object_decoder rpc_vhost_add_lun[] = { 273 {"ctrlr", offsetof(struct rpc_add_vhost_scsi_ctrlr_lun, ctrlr), spdk_json_decode_string }, 274 {"scsi_dev_num", offsetof(struct rpc_add_vhost_scsi_ctrlr_lun, scsi_dev_num), spdk_json_decode_uint32}, 275 {"lun_name", offsetof(struct rpc_add_vhost_scsi_ctrlr_lun, lun_name), spdk_json_decode_string }, 276 }; 277 278 static void 279 spdk_rpc_add_vhost_scsi_lun(struct spdk_jsonrpc_request *request, 280 const struct spdk_json_val *params) 281 { 282 struct rpc_add_vhost_scsi_ctrlr_lun req = {0}; 283 struct spdk_json_write_ctx *w; 284 int rc; 285 286 if (spdk_json_decode_object(params, rpc_vhost_add_lun, 287 SPDK_COUNTOF(rpc_vhost_add_lun), 288 &req)) { 289 SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n"); 290 rc = -EINVAL; 291 goto invalid; 292 } 293 294 rc = spdk_vhost_scsi_dev_add_dev(req.ctrlr, req.scsi_dev_num, req.lun_name); 295 if (rc < 0) { 296 goto invalid; 297 } 298 299 free_rpc_add_vhost_scsi_ctrlr_lun(&req); 300 301 w = spdk_jsonrpc_begin_result(request); 302 if (w == NULL) { 303 return; 304 } 305 306 spdk_json_write_bool(w, true); 307 spdk_jsonrpc_end_result(request, w); 308 return; 309 310 invalid: 311 free_rpc_add_vhost_scsi_ctrlr_lun(&req); 312 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, strerror(-rc)); 313 } 314 SPDK_RPC_REGISTER("add_vhost_scsi_lun", spdk_rpc_add_vhost_scsi_lun) 315 316 struct rpc_remove_vhost_scsi_ctrlr_dev { 317 char *ctrlr; 318 uint32_t scsi_dev_num; 319 }; 320 321 static void 322 free_rpc_remove_vhost_scsi_ctrlr_dev(struct rpc_remove_vhost_scsi_ctrlr_dev *req) 323 { 324 free(req->ctrlr); 325 } 326 327 static const struct spdk_json_object_decoder rpc_vhost_remove_dev[] = { 328 {"ctrlr", offsetof(struct rpc_remove_vhost_scsi_ctrlr_dev, ctrlr), spdk_json_decode_string }, 329 {"scsi_dev_num", offsetof(struct rpc_remove_vhost_scsi_ctrlr_dev, scsi_dev_num), spdk_json_decode_uint32}, 330 }; 331 332 static void 333 spdk_rpc_remove_vhost_scsi_dev(struct spdk_jsonrpc_request *request, 334 const struct spdk_json_val *params) 335 { 336 struct rpc_remove_vhost_scsi_ctrlr_dev req = {0}; 337 struct spdk_json_write_ctx *w; 338 struct spdk_vhost_dev *vdev; 339 int rc; 340 341 if (spdk_json_decode_object(params, rpc_vhost_remove_dev, 342 SPDK_COUNTOF(rpc_vhost_remove_dev), 343 &req)) { 344 SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n"); 345 rc = -EINVAL; 346 goto invalid; 347 } 348 349 if (!(vdev = spdk_vhost_dev_find(req.ctrlr))) { 350 rc = -ENODEV; 351 goto invalid; 352 } 353 354 rc = spdk_vhost_scsi_dev_remove_dev(vdev, req.scsi_dev_num); 355 if (rc < 0) { 356 goto invalid; 357 } 358 359 free_rpc_remove_vhost_scsi_ctrlr_dev(&req); 360 361 w = spdk_jsonrpc_begin_result(request); 362 if (w == NULL) { 363 return; 364 } 365 366 spdk_json_write_bool(w, true); 367 spdk_jsonrpc_end_result(request, w); 368 return; 369 370 invalid: 371 free_rpc_remove_vhost_scsi_ctrlr_dev(&req); 372 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, strerror(-rc)); 373 } 374 SPDK_RPC_REGISTER("remove_vhost_scsi_dev", spdk_rpc_remove_vhost_scsi_dev) 375 376 struct rpc_vhost_blk_ctrlr { 377 char *ctrlr; 378 char *dev_name; 379 char *cpumask; 380 bool readonly; 381 }; 382 383 static const struct spdk_json_object_decoder rpc_construct_vhost_blk_ctrlr[] = { 384 {"ctrlr", offsetof(struct rpc_vhost_blk_ctrlr, ctrlr), spdk_json_decode_string }, 385 {"dev_name", offsetof(struct rpc_vhost_blk_ctrlr, dev_name), spdk_json_decode_string }, 386 {"cpumask", offsetof(struct rpc_vhost_blk_ctrlr, cpumask), spdk_json_decode_string, true}, 387 {"readonly", offsetof(struct rpc_vhost_blk_ctrlr, readonly), spdk_json_decode_bool, true}, 388 }; 389 390 static void 391 free_rpc_vhost_blk_ctrlr(struct rpc_vhost_blk_ctrlr *req) 392 { 393 free(req->ctrlr); 394 free(req->dev_name); 395 free(req->cpumask); 396 } 397 398 static void 399 spdk_rpc_construct_vhost_blk_controller(struct spdk_jsonrpc_request *request, 400 const struct spdk_json_val *params) 401 { 402 struct rpc_vhost_blk_ctrlr req = {0}; 403 struct spdk_json_write_ctx *w; 404 int rc; 405 uint64_t cpumask; 406 407 if (spdk_json_decode_object(params, rpc_construct_vhost_blk_ctrlr, 408 SPDK_COUNTOF(rpc_construct_vhost_blk_ctrlr), 409 &req)) { 410 SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n"); 411 rc = -EINVAL; 412 goto invalid; 413 } 414 415 cpumask = spdk_app_get_core_mask(); 416 if (req.cpumask != NULL && spdk_vhost_parse_core_mask(req.cpumask, &cpumask)) { 417 rc = -EINVAL; 418 goto invalid; 419 } 420 421 rc = spdk_vhost_blk_construct(req.ctrlr, cpumask, req.dev_name, req.readonly); 422 if (rc < 0) { 423 goto invalid; 424 } 425 426 free_rpc_vhost_blk_ctrlr(&req); 427 428 w = spdk_jsonrpc_begin_result(request); 429 if (w == NULL) { 430 return; 431 } 432 433 spdk_json_write_bool(w, true); 434 spdk_jsonrpc_end_result(request, w); 435 return; 436 437 invalid: 438 free_rpc_vhost_blk_ctrlr(&req); 439 spdk_jsonrpc_send_error_response(request, 440 SPDK_JSONRPC_ERROR_INVALID_PARAMS, strerror(-rc)); 441 442 } 443 SPDK_RPC_REGISTER("construct_vhost_blk_controller", spdk_rpc_construct_vhost_blk_controller) 444 445 struct rpc_remove_vhost_blk_ctrlr { 446 char *ctrlr; 447 }; 448 449 static const struct spdk_json_object_decoder rpc_remove_vhost_blk_ctrlr[] = { 450 {"ctrlr", offsetof(struct rpc_remove_vhost_blk_ctrlr, ctrlr), spdk_json_decode_string }, 451 }; 452 453 static void 454 free_rpc_remove_vhost_blk_ctrlr(struct rpc_remove_vhost_blk_ctrlr *req) 455 { 456 free(req->ctrlr); 457 } 458 459 static void 460 spdk_rpc_remove_vhost_blk_controller(struct spdk_jsonrpc_request *request, 461 const struct spdk_json_val *params) 462 { 463 struct rpc_remove_vhost_blk_ctrlr req = {NULL}; 464 struct spdk_json_write_ctx *w; 465 struct spdk_vhost_dev *vdev; 466 int rc; 467 468 if (spdk_json_decode_object(params, rpc_remove_vhost_blk_ctrlr, 469 SPDK_COUNTOF(rpc_remove_vhost_blk_ctrlr), &req)) { 470 SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n"); 471 rc = -EINVAL; 472 goto invalid; 473 } 474 475 if (!(vdev = spdk_vhost_dev_find(req.ctrlr))) { 476 rc = -ENODEV; 477 goto invalid; 478 } 479 480 rc = spdk_vhost_blk_destroy(vdev); 481 if (rc < 0) { 482 goto invalid; 483 } 484 485 free_rpc_remove_vhost_blk_ctrlr(&req); 486 487 w = spdk_jsonrpc_begin_result(request); 488 if (w == NULL) { 489 return; 490 } 491 492 spdk_json_write_bool(w, true); 493 spdk_jsonrpc_end_result(request, w); 494 return; 495 496 invalid: 497 free_rpc_remove_vhost_blk_ctrlr(&req); 498 spdk_jsonrpc_send_error_response(request, 499 SPDK_JSONRPC_ERROR_INVALID_PARAMS, strerror(-rc)); 500 501 } 502 SPDK_RPC_REGISTER("remove_vhost_blk_controller", spdk_rpc_remove_vhost_blk_controller) 503 504 static void 505 spdk_rpc_get_vhost_blk_controllers(struct spdk_jsonrpc_request *request, 506 const struct spdk_json_val *params) 507 { 508 struct spdk_json_write_ctx *w; 509 struct spdk_vhost_dev *vdev = NULL; 510 struct spdk_bdev *bdev; 511 512 if (params != NULL) { 513 spdk_jsonrpc_send_error_response(request, 514 SPDK_JSONRPC_ERROR_INVALID_PARAMS, 515 "get_vhost_block_controllers requires no parameters"); 516 return; 517 } 518 519 w = spdk_jsonrpc_begin_result(request); 520 if (w == NULL) { 521 return; 522 } 523 524 spdk_json_write_array_begin(w); 525 while ((vdev = spdk_vhost_dev_next(vdev)) != NULL) { 526 if (vdev->type != SPDK_VHOST_DEV_T_BLK) 527 continue; 528 spdk_json_write_object_begin(w); 529 530 spdk_json_write_name(w, "ctrlr"); 531 spdk_json_write_string(w, spdk_vhost_dev_get_name(vdev)); 532 533 spdk_json_write_name(w, "cpu_mask"); 534 spdk_json_write_string_fmt(w, "%#" PRIx64, spdk_vhost_dev_get_cpumask(vdev)); 535 536 spdk_json_write_name(w, "readonly"); 537 spdk_json_write_bool(w, spdk_vhost_blk_get_readonly(vdev)); 538 539 bdev = spdk_vhost_blk_get_dev(vdev); 540 spdk_json_write_name(w, "bdev"); 541 if (bdev) 542 spdk_json_write_string(w, spdk_bdev_get_name(bdev)); 543 else 544 spdk_json_write_null(w); 545 546 spdk_json_write_object_end(w); 547 } 548 spdk_json_write_array_end(w); 549 spdk_jsonrpc_end_result(request, w); 550 } 551 SPDK_RPC_REGISTER("get_vhost_blk_controllers", spdk_rpc_get_vhost_blk_controllers) 552