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 36 #include "spdk/string.h" 37 #include "spdk/rpc.h" 38 #include "spdk/util.h" 39 #include "spdk/log.h" 40 41 #include "bdev_virtio.h" 42 43 #define SPDK_VIRTIO_USER_DEFAULT_VQ_COUNT 1 44 #define SPDK_VIRTIO_USER_DEFAULT_QUEUE_SIZE 512 45 46 struct rpc_remove_virtio_dev { 47 char *name; 48 }; 49 50 static const struct spdk_json_object_decoder rpc_remove_virtio_dev[] = { 51 {"name", offsetof(struct rpc_remove_virtio_dev, name), spdk_json_decode_string }, 52 }; 53 54 static void 55 rpc_bdev_virtio_detach_controller_cb(void *ctx, int errnum) 56 { 57 struct spdk_jsonrpc_request *request = ctx; 58 59 if (errnum != 0) { 60 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 61 spdk_strerror(-errnum)); 62 return; 63 } 64 65 spdk_jsonrpc_send_bool_response(request, true); 66 } 67 68 static void 69 rpc_bdev_virtio_detach_controller(struct spdk_jsonrpc_request *request, 70 const struct spdk_json_val *params) 71 { 72 struct rpc_remove_virtio_dev req = {NULL}; 73 int rc = 0; 74 75 if (spdk_json_decode_object(params, rpc_remove_virtio_dev, 76 SPDK_COUNTOF(rpc_remove_virtio_dev), 77 &req)) { 78 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 79 "spdk_json_decode_object failed"); 80 goto cleanup; 81 } 82 83 rc = bdev_virtio_blk_dev_remove(req.name, rpc_bdev_virtio_detach_controller_cb, request); 84 if (rc == -ENODEV) { 85 rc = bdev_virtio_scsi_dev_remove(req.name, rpc_bdev_virtio_detach_controller_cb, request); 86 } 87 88 if (rc != 0) { 89 spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc)); 90 } 91 92 cleanup: 93 free(req.name); 94 } 95 SPDK_RPC_REGISTER("bdev_virtio_detach_controller", 96 rpc_bdev_virtio_detach_controller, SPDK_RPC_RUNTIME) 97 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_virtio_detach_controller, remove_virtio_bdev) 98 99 static void 100 rpc_bdev_virtio_scsi_get_devices(struct spdk_jsonrpc_request *request, 101 const struct spdk_json_val *params) 102 { 103 struct spdk_json_write_ctx *w; 104 105 if (params != NULL) { 106 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 107 "bdev_virtio_scsi_get_devices requires no parameters"); 108 return; 109 } 110 111 w = spdk_jsonrpc_begin_result(request); 112 bdev_virtio_scsi_dev_list(w); 113 spdk_jsonrpc_end_result(request, w); 114 } 115 SPDK_RPC_REGISTER("bdev_virtio_scsi_get_devices", 116 rpc_bdev_virtio_scsi_get_devices, SPDK_RPC_RUNTIME) 117 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_virtio_scsi_get_devices, get_virtio_scsi_devs) 118 119 struct rpc_bdev_virtio_attach_controller_ctx { 120 char *name; 121 char *trtype; 122 char *traddr; 123 char *dev_type; 124 uint32_t vq_count; 125 uint32_t vq_size; 126 struct spdk_jsonrpc_request *request; 127 }; 128 129 static const struct spdk_json_object_decoder rpc_bdev_virtio_attach_controller_ctx[] = { 130 {"name", offsetof(struct rpc_bdev_virtio_attach_controller_ctx, name), spdk_json_decode_string }, 131 {"trtype", offsetof(struct rpc_bdev_virtio_attach_controller_ctx, trtype), spdk_json_decode_string }, 132 {"traddr", offsetof(struct rpc_bdev_virtio_attach_controller_ctx, traddr), spdk_json_decode_string }, 133 {"dev_type", offsetof(struct rpc_bdev_virtio_attach_controller_ctx, dev_type), spdk_json_decode_string }, 134 {"vq_count", offsetof(struct rpc_bdev_virtio_attach_controller_ctx, vq_count), spdk_json_decode_uint32, true }, 135 {"vq_size", offsetof(struct rpc_bdev_virtio_attach_controller_ctx, vq_size), spdk_json_decode_uint32, true }, 136 }; 137 138 static void 139 free_rpc_bdev_virtio_attach_controller_ctx(struct rpc_bdev_virtio_attach_controller_ctx *req) 140 { 141 free(req->name); 142 free(req->trtype); 143 free(req->traddr); 144 free(req->dev_type); 145 free(req); 146 } 147 148 static void 149 rpc_create_virtio_dev_cb(void *ctx, int result, struct spdk_bdev **bdevs, size_t cnt) 150 { 151 struct rpc_bdev_virtio_attach_controller_ctx *req = ctx; 152 struct spdk_json_write_ctx *w; 153 size_t i; 154 155 if (result) { 156 spdk_jsonrpc_send_error_response(req->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 157 spdk_strerror(-result)); 158 free_rpc_bdev_virtio_attach_controller_ctx(req); 159 return; 160 } 161 162 w = spdk_jsonrpc_begin_result(req->request); 163 spdk_json_write_array_begin(w); 164 165 for (i = 0; i < cnt; i++) { 166 spdk_json_write_string(w, spdk_bdev_get_name(bdevs[i])); 167 } 168 169 spdk_json_write_array_end(w); 170 spdk_jsonrpc_end_result(req->request, w); 171 172 free_rpc_bdev_virtio_attach_controller_ctx(ctx); 173 } 174 175 static void 176 rpc_bdev_virtio_attach_controller(struct spdk_jsonrpc_request *request, 177 const struct spdk_json_val *params) 178 { 179 struct rpc_bdev_virtio_attach_controller_ctx *req; 180 struct spdk_bdev *bdev; 181 struct spdk_pci_addr pci_addr; 182 bool pci; 183 int rc; 184 185 req = calloc(1, sizeof(*req)); 186 if (!req) { 187 SPDK_ERRLOG("calloc() failed\n"); 188 spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM)); 189 return; 190 } 191 192 if (spdk_json_decode_object(params, rpc_bdev_virtio_attach_controller_ctx, 193 SPDK_COUNTOF(rpc_bdev_virtio_attach_controller_ctx), 194 req)) { 195 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 196 "spdk_json_decode_object failed"); 197 goto cleanup; 198 } 199 200 if (strcmp(req->trtype, "pci") == 0) { 201 if (req->vq_count != 0 || req->vq_size != 0) { 202 SPDK_ERRLOG("VQ count or size is not allowed for PCI transport type\n"); 203 spdk_jsonrpc_send_error_response(request, EINVAL, 204 "vq_count or vq_size is not allowed for PCI transport type."); 205 goto cleanup; 206 } 207 208 if (spdk_pci_addr_parse(&pci_addr, req->traddr) != 0) { 209 SPDK_ERRLOG("Invalid PCI address '%s'\n", req->traddr); 210 spdk_jsonrpc_send_error_response_fmt(request, EINVAL, "Invalid PCI address '%s'", req->traddr); 211 goto cleanup; 212 } 213 214 pci = true; 215 } else if (strcmp(req->trtype, "user") == 0) { 216 req->vq_count = req->vq_count == 0 ? SPDK_VIRTIO_USER_DEFAULT_VQ_COUNT : req->vq_count; 217 req->vq_size = req->vq_size == 0 ? SPDK_VIRTIO_USER_DEFAULT_QUEUE_SIZE : req->vq_size; 218 pci = false; 219 } else { 220 SPDK_ERRLOG("Invalid trtype '%s'\n", req->trtype); 221 spdk_jsonrpc_send_error_response_fmt(request, EINVAL, "Invalid trtype '%s'", req->trtype); 222 goto cleanup; 223 } 224 225 req->request = request; 226 if (strcmp(req->dev_type, "blk") == 0) { 227 if (pci) { 228 bdev = bdev_virtio_pci_blk_dev_create(req->name, &pci_addr); 229 } else { 230 bdev = bdev_virtio_user_blk_dev_create(req->name, req->traddr, req->vq_count, req->vq_size); 231 } 232 233 /* Virtio blk doesn't use callback so call it manually to send result. */ 234 rc = bdev ? 0 : -EINVAL; 235 rpc_create_virtio_dev_cb(req, rc, &bdev, bdev ? 1 : 0); 236 } else if (strcmp(req->dev_type, "scsi") == 0) { 237 if (pci) { 238 rc = bdev_virtio_pci_scsi_dev_create(req->name, &pci_addr, rpc_create_virtio_dev_cb, req); 239 } else { 240 rc = bdev_virtio_user_scsi_dev_create(req->name, req->traddr, req->vq_count, req->vq_size, 241 rpc_create_virtio_dev_cb, req); 242 } 243 244 if (rc < 0) { 245 /* In case of error callback is not called so do it manually to send result. */ 246 rpc_create_virtio_dev_cb(req, rc, NULL, 0); 247 } 248 } else { 249 SPDK_ERRLOG("Invalid dev_type '%s'\n", req->dev_type); 250 spdk_jsonrpc_send_error_response_fmt(request, EINVAL, "Invalid dev_type '%s'", req->dev_type); 251 goto cleanup; 252 } 253 254 return; 255 256 cleanup: 257 free_rpc_bdev_virtio_attach_controller_ctx(req); 258 } 259 SPDK_RPC_REGISTER("bdev_virtio_attach_controller", 260 rpc_bdev_virtio_attach_controller, SPDK_RPC_RUNTIME); 261 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_virtio_attach_controller, construct_virtio_dev) 262