xref: /spdk/lib/vhost/vhost_scsi.c (revision 95a2dcb321bc73db4e7074c1c5ad96ce24919a68)
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 <linux/virtio_scsi.h>
37 
38 #include "spdk/env.h"
39 #include "spdk/scsi.h"
40 #include "spdk/scsi_spec.h"
41 #include "spdk/conf.h"
42 #include "spdk/event.h"
43 
44 #include "spdk/vhost.h"
45 #include "vhost_internal.h"
46 #include "task.h"
47 
48 /* Features supported by SPDK VHOST lib. */
49 #define SPDK_VHOST_SCSI_FEATURES	((1ULL << VIRTIO_F_VERSION_1) | \
50 					(1ULL << VHOST_F_LOG_ALL) | \
51 					(1ULL << VHOST_USER_F_PROTOCOL_FEATURES) | \
52 					(1ULL << VIRTIO_F_NOTIFY_ON_EMPTY) | \
53 					(1ULL << VIRTIO_SCSI_F_INOUT) | \
54 					(1ULL << VIRTIO_SCSI_F_HOTPLUG) | \
55 					(1ULL << VIRTIO_SCSI_F_CHANGE ) | \
56 					(1ULL << VIRTIO_SCSI_F_T10_PI ))
57 
58 /* Features that are specified in VIRTIO SCSI but currently not supported:
59  * - Live migration not supported yet
60  * - Hotplug/hotremove
61  * - LUN params change
62  * - T10 PI
63  */
64 #define SPDK_VHOST_SCSI_DISABLED_FEATURES	((1ULL << VHOST_F_LOG_ALL) | \
65 						(1ULL << VIRTIO_SCSI_F_HOTPLUG) | \
66 						(1ULL << VIRTIO_SCSI_F_CHANGE ) | \
67 						(1ULL << VIRTIO_SCSI_F_T10_PI ))
68 
69 #define CONTROLQ_POLL_PERIOD_US (1000 * 5)
70 
71 #define VIRTIO_SCSI_CONTROLQ   0
72 #define VIRTIO_SCSI_EVENTQ   1
73 #define VIRTIO_SCSI_REQUESTQ   2
74 
75 struct spdk_vhost_scsi_dev {
76 	struct spdk_vhost_dev vdev;
77 
78 	struct spdk_scsi_dev *scsi_dev[SPDK_VHOST_SCSI_CTRLR_MAX_DEVS];
79 	struct spdk_poller *requestq_poller;
80 	struct spdk_poller *controlq_poller;
81 } __rte_cache_aligned;
82 
83 static int new_device(int vid);
84 static void destroy_device(int vid);
85 
86 const struct spdk_vhost_dev_backend spdk_vhost_scsi_device_backend = {
87 	.virtio_features = SPDK_VHOST_SCSI_FEATURES,
88 	.disabled_features = SPDK_VHOST_SCSI_DISABLED_FEATURES,
89 	.ops = {
90 		.new_device =  new_device,
91 		.destroy_device = destroy_device,
92 	}
93 };
94 
95 static void task_submit(struct spdk_vhost_task *task);
96 static int process_request(struct spdk_vhost_task *task);
97 static void invalid_request(struct spdk_vhost_task *task);
98 
99 static void
100 submit_completion(struct spdk_vhost_task *task)
101 {
102 	spdk_vhost_vq_used_ring_enqueue(&task->svdev->vdev, task->vq, task->req_idx,
103 					task->scsi.data_transferred);
104 	SPDK_TRACELOG(SPDK_TRACE_VHOST, "Finished task (%p) req_idx=%d\n", task, task->req_idx);
105 
106 	spdk_vhost_task_put(task);
107 }
108 
109 static void
110 process_mgmt_task_completion(void *arg1, void *arg2)
111 {
112 	struct spdk_vhost_task *task = arg1;
113 
114 	submit_completion(task);
115 }
116 
117 static void
118 process_task_completion(void *arg1, void *arg2)
119 {
120 	struct spdk_vhost_task *task = arg1;
121 
122 	/* The SCSI task has completed.  Do final processing and then post
123 	   notification to the virtqueue's "used" ring.
124 	 */
125 	task->resp->status = task->scsi.status;
126 
127 	if (task->scsi.status != SPDK_SCSI_STATUS_GOOD) {
128 		memcpy(task->resp->sense, task->scsi.sense_data, task->scsi.sense_data_len);
129 		task->resp->sense_len = task->scsi.sense_data_len;
130 	}
131 	task->resp->resid = task->scsi.transfer_len - task->scsi.data_transferred;
132 
133 	submit_completion(task);
134 }
135 
136 static void
137 task_submit(struct spdk_vhost_task *task)
138 {
139 	/* The task is ready to be submitted.  First create the callback event that
140 	   will be invoked when the SCSI command is completed.  See process_task_completion()
141 	   for what SPDK vhost-scsi does when the task is completed.
142 	 */
143 
144 	task->resp->response = VIRTIO_SCSI_S_OK;
145 	task->scsi.cb_event = spdk_event_allocate(rte_lcore_id(),
146 			      process_task_completion,
147 			      task, NULL);
148 	spdk_scsi_dev_queue_task(task->scsi_dev, &task->scsi);
149 }
150 
151 static void
152 mgmt_task_submit(struct spdk_vhost_task *task, enum spdk_scsi_task_func func)
153 {
154 	task->tmf_resp->response = VIRTIO_SCSI_S_OK;
155 	task->scsi.cb_event = spdk_event_allocate(rte_lcore_id(),
156 			      process_mgmt_task_completion,
157 			      task, NULL);
158 	spdk_scsi_dev_queue_mgmt_task(task->scsi_dev, &task->scsi, func);
159 }
160 
161 static void
162 invalid_request(struct spdk_vhost_task *task)
163 {
164 	spdk_vhost_vq_used_ring_enqueue(&task->svdev->vdev, task->vq, task->req_idx, 0);
165 	spdk_vhost_task_put(task);
166 
167 	SPDK_TRACELOG(SPDK_TRACE_VHOST, "Invalid request (status=%" PRIu8")\n",
168 		      task->resp ? task->resp->response : -1);
169 }
170 
171 static struct spdk_scsi_dev *
172 get_scsi_dev(struct spdk_vhost_scsi_dev *svdev, const __u8 *lun)
173 {
174 	SPDK_TRACEDUMP(SPDK_TRACE_VHOST_QUEUE, "LUN", lun, 8);
175 	/* First byte must be 1 and second is target */
176 	if (lun[0] != 1 || lun[1] >= SPDK_VHOST_SCSI_CTRLR_MAX_DEVS)
177 		return NULL;
178 
179 	return svdev->scsi_dev[lun[1]];
180 }
181 
182 static struct spdk_scsi_lun *
183 get_scsi_lun(struct spdk_scsi_dev *scsi_dev, const __u8 *lun)
184 {
185 	uint16_t lun_id = (((uint16_t)lun[2] << 8) | lun[3]) & 0x3FFF;
186 
187 	/* For now only one LUN per controller is allowed so no need to search LUN IDs */
188 	return spdk_scsi_dev_get_lun(scsi_dev, lun_id);
189 }
190 
191 static void
192 process_ctrl_request(struct spdk_vhost_scsi_dev *svdev, struct rte_vhost_vring *controlq,
193 		     uint16_t req_idx)
194 {
195 	struct spdk_vhost_task *task;
196 
197 	struct vring_desc *desc;
198 	struct virtio_scsi_ctrl_tmf_req *ctrl_req;
199 	struct virtio_scsi_ctrl_an_resp *an_resp;
200 
201 	desc = spdk_vhost_vq_get_desc(controlq, req_idx);
202 	ctrl_req = spdk_vhost_gpa_to_vva(&svdev->vdev, desc->addr);
203 
204 	SPDK_TRACELOG(SPDK_TRACE_VHOST_QUEUE,
205 		      "Processing controlq descriptor: desc %d/%p, desc_addr %p, len %d, flags %d, last_used_idx %d; kickfd %d; size %d\n",
206 		      req_idx, desc, (void *)desc->addr, desc->len, desc->flags, controlq->last_used_idx,
207 		      controlq->kickfd, controlq->size);
208 	SPDK_TRACEDUMP(SPDK_TRACE_VHOST_QUEUE, "Request desriptor", (uint8_t *)ctrl_req,
209 		       desc->len);
210 
211 	task = spdk_vhost_task_get(svdev);
212 	task->vq = controlq;
213 	task->svdev = svdev;
214 	task->req_idx = req_idx;
215 	task->scsi_dev = get_scsi_dev(task->svdev, ctrl_req->lun);
216 
217 	/* Process the TMF request */
218 	switch (ctrl_req->type) {
219 	case VIRTIO_SCSI_T_TMF:
220 		/* Get the response buffer */
221 		assert(spdk_vhost_vring_desc_has_next(desc));
222 		desc = spdk_vhost_vring_desc_get_next(controlq->desc, desc);
223 		task->tmf_resp = spdk_vhost_gpa_to_vva(&svdev->vdev, desc->addr);
224 
225 		/* Check if we are processing a valid request */
226 		if (task->scsi_dev == NULL) {
227 			task->tmf_resp->response = VIRTIO_SCSI_S_BAD_TARGET;
228 			break;
229 		}
230 
231 		switch (ctrl_req->subtype) {
232 		case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET:
233 			/* Handle LUN reset */
234 			SPDK_TRACELOG(SPDK_TRACE_VHOST_QUEUE, "LUN reset\n");
235 			task->scsi.lun = get_scsi_lun(task->scsi_dev, ctrl_req->lun);
236 
237 			mgmt_task_submit(task, SPDK_SCSI_TASK_FUNC_LUN_RESET);
238 			return;
239 		default:
240 			task->tmf_resp->response = VIRTIO_SCSI_S_ABORTED;
241 			/* Unsupported command */
242 			SPDK_TRACELOG(SPDK_TRACE_VHOST_QUEUE, "Unsupported TMF command %x\n", ctrl_req->subtype);
243 			break;
244 		}
245 		break;
246 	case VIRTIO_SCSI_T_AN_QUERY:
247 	case VIRTIO_SCSI_T_AN_SUBSCRIBE: {
248 		desc = spdk_vhost_vring_desc_get_next(controlq->desc, desc);
249 		an_resp = spdk_vhost_gpa_to_vva(&svdev->vdev, desc->addr);
250 		an_resp->response = VIRTIO_SCSI_S_ABORTED;
251 		break;
252 	}
253 	default:
254 		SPDK_TRACELOG(SPDK_TRACE_VHOST_QUEUE, "Unsupported control command %x\n", ctrl_req->type);
255 		break;
256 	}
257 
258 	spdk_vhost_vq_used_ring_enqueue(&svdev->vdev, controlq, req_idx, 0);
259 	spdk_vhost_task_put(task);
260 }
261 
262 /*
263  * Process task's descriptor chain and setup data related fields.
264  * Return
265  *   -1 if request is invalid and must be aborted,
266  *    0 if all data are set,
267  *    1 if it was not possible to allocate IO vector for this task.
268  */
269 static int
270 task_data_setup(struct spdk_vhost_task *task,
271 		struct virtio_scsi_cmd_req **req)
272 {
273 	struct rte_vhost_vring *vq = task->vq;
274 	struct spdk_vhost_dev *vdev = &task->svdev->vdev;
275 	struct vring_desc *desc =  spdk_vhost_vq_get_desc(task->vq, task->req_idx);
276 	struct iovec *iovs = task->iovs;
277 	uint16_t iovcnt = 0, iovcnt_max = VHOST_SCSI_IOVS_LEN;
278 	uint32_t len = 0;
279 
280 	/* Sanity check. First descriptor must be readable and must have next one. */
281 	if (unlikely(spdk_vhost_vring_desc_is_wr(desc) || !spdk_vhost_vring_desc_has_next(desc))) {
282 		SPDK_WARNLOG("Invalid first (request) descriptor.\n");
283 		task->resp = NULL;
284 		goto abort_task;
285 	}
286 
287 	*req = spdk_vhost_gpa_to_vva(vdev, desc->addr);
288 
289 	desc = spdk_vhost_vring_desc_get_next(vq->desc, desc);
290 	task->scsi.dxfer_dir = spdk_vhost_vring_desc_is_wr(desc) ? SPDK_SCSI_DIR_FROM_DEV :
291 			       SPDK_SCSI_DIR_TO_DEV;
292 	task->scsi.iovs = iovs;
293 
294 	if (task->scsi.dxfer_dir == SPDK_SCSI_DIR_FROM_DEV) {
295 		/*
296 		 * FROM_DEV (READ): [RD_req][WR_resp][WR_buf0]...[WR_bufN]
297 		 */
298 		task->resp = spdk_vhost_gpa_to_vva(vdev, desc->addr);
299 		if (!spdk_vhost_vring_desc_has_next(desc)) {
300 			/*
301 			 * TEST UNIT READY command and some others might not contain any payload and this is not an error.
302 			 */
303 			SPDK_TRACELOG(SPDK_TRACE_VHOST_DATA,
304 				      "No payload descriptors for FROM DEV command req_idx=%"PRIu16".\n", task->req_idx);
305 			SPDK_TRACEDUMP(SPDK_TRACE_VHOST_DATA, "CDB=", (*req)->cdb, VIRTIO_SCSI_CDB_SIZE);
306 			task->scsi.iovcnt = 1;
307 			task->scsi.iovs[0].iov_len = 0;
308 			task->scsi.length = 0;
309 			task->scsi.transfer_len = 0;
310 			return 0;
311 		}
312 
313 		desc = spdk_vhost_vring_desc_get_next(vq->desc, desc);
314 
315 		/* All remaining descriptors are data. */
316 		while (iovcnt < iovcnt_max) {
317 			spdk_vhost_vring_desc_to_iov(vdev, &iovs[iovcnt], desc);
318 			len += desc->len;
319 			iovcnt++;
320 
321 			if (!spdk_vhost_vring_desc_has_next(desc))
322 				break;
323 
324 			desc = spdk_vhost_vring_desc_get_next(vq->desc, desc);
325 			if (unlikely(!spdk_vhost_vring_desc_is_wr(desc))) {
326 				SPDK_WARNLOG("FROM DEV cmd: descriptor nr %" PRIu16" in payload chain is read only.\n", iovcnt);
327 				task->resp = NULL;
328 				goto abort_task;
329 			}
330 		}
331 	} else {
332 		SPDK_TRACELOG(SPDK_TRACE_VHOST_DATA, "TO DEV");
333 		/*
334 		 * TO_DEV (WRITE):[RD_req][RD_buf0]...[RD_bufN][WR_resp]
335 		 * No need to check descriptor WR flag as this is done while setting scsi.dxfer_dir.
336 		 */
337 
338 		/* Process descriptors up to response. */
339 		while (!spdk_vhost_vring_desc_is_wr(desc) && iovcnt < iovcnt_max) {
340 			spdk_vhost_vring_desc_to_iov(vdev, &iovs[iovcnt], desc);
341 			len += desc->len;
342 			iovcnt++;
343 
344 			if (!spdk_vhost_vring_desc_has_next(desc)) {
345 				SPDK_WARNLOG("TO_DEV cmd: no response descriptor.\n");
346 				task->resp = NULL;
347 				goto abort_task;
348 			}
349 
350 			desc = spdk_vhost_vring_desc_get_next(vq->desc, desc);
351 		}
352 
353 		task->resp = spdk_vhost_gpa_to_vva(vdev, desc->addr);
354 		if (spdk_vhost_vring_desc_has_next(desc)) {
355 			SPDK_WARNLOG("TO_DEV cmd: ignoring unexpected descriptors after response descriptor.\n");
356 		}
357 	}
358 
359 	if (iovcnt == iovcnt_max) {
360 		SPDK_WARNLOG("Too many IO vectors in chain!\n");
361 		goto abort_task;
362 	}
363 
364 	task->scsi.iovcnt = iovcnt;
365 	task->scsi.length = len;
366 	task->scsi.transfer_len = len;
367 	return 0;
368 
369 abort_task:
370 	if (task->resp) {
371 		task->resp->response = VIRTIO_SCSI_S_ABORTED;
372 	}
373 
374 	return -1;
375 }
376 
377 static int
378 process_request(struct spdk_vhost_task *task)
379 {
380 	struct virtio_scsi_cmd_req *req;
381 	int result;
382 
383 	result = task_data_setup(task, &req);
384 	if (result) {
385 		return result;
386 	}
387 
388 	task->scsi_dev = get_scsi_dev(task->svdev, req->lun);
389 	if (unlikely(task->scsi_dev == NULL)) {
390 		task->resp->response = VIRTIO_SCSI_S_BAD_TARGET;
391 		return -1;
392 	}
393 
394 	task->scsi.lun = get_scsi_lun(task->scsi_dev, req->lun);
395 	task->scsi.cdb = req->cdb;
396 	task->scsi.target_port = spdk_scsi_dev_find_port_by_id(task->scsi_dev, 0);
397 	SPDK_TRACEDUMP(SPDK_TRACE_VHOST_DATA, "request CDB", req->cdb, VIRTIO_SCSI_CDB_SIZE);
398 	return 0;
399 }
400 
401 static void
402 process_controlq(struct spdk_vhost_scsi_dev *vdev, struct rte_vhost_vring *vq)
403 {
404 	uint16_t reqs[32];
405 	uint16_t reqs_cnt, i;
406 
407 	reqs_cnt = spdk_vhost_vq_avail_ring_get(vq, reqs, RTE_DIM(reqs));
408 	for (i = 0; i < reqs_cnt; i++) {
409 		process_ctrl_request(vdev, vq, reqs[i]);
410 	}
411 }
412 
413 static void
414 process_requestq(struct spdk_vhost_scsi_dev *svdev, struct rte_vhost_vring *vq)
415 {
416 	uint16_t reqs[32];
417 	uint16_t reqs_cnt, i;
418 	struct spdk_vhost_task *task;
419 	int result;
420 
421 	reqs_cnt = spdk_vhost_vq_avail_ring_get(vq, reqs, RTE_DIM(reqs));
422 	assert(reqs_cnt <= 32);
423 
424 	for (i = 0; i < reqs_cnt; i++) {
425 		task = spdk_vhost_task_get(svdev);
426 
427 		SPDK_TRACELOG(SPDK_TRACE_VHOST, "====== Starting processing request idx %"PRIu16"======\n",
428 			      reqs[i]);
429 		task->vq = vq;
430 		task->svdev = svdev;
431 		task->req_idx = reqs[i];
432 		result = process_request(task);
433 		if (likely(result == 0)) {
434 			task_submit(task);
435 			SPDK_TRACELOG(SPDK_TRACE_VHOST, "====== Task %p req_idx %d submitted ======\n", task,
436 				      task->req_idx);
437 		} else {
438 			invalid_request(task);
439 			SPDK_TRACELOG(SPDK_TRACE_VHOST, "====== Task %p req_idx %d failed ======\n", task, task->req_idx);
440 		}
441 	}
442 }
443 
444 static void
445 vdev_controlq_worker(void *arg)
446 {
447 	struct spdk_vhost_scsi_dev *svdev = arg;
448 
449 	process_controlq(svdev, &svdev->vdev.virtqueue[VIRTIO_SCSI_CONTROLQ]);
450 }
451 
452 static void
453 vdev_worker(void *arg)
454 {
455 	struct spdk_vhost_scsi_dev *svdev = arg;
456 	uint32_t q_idx;
457 
458 	for (q_idx = VIRTIO_SCSI_REQUESTQ; q_idx < svdev->vdev.num_queues; q_idx++) {
459 		process_requestq(svdev, &svdev->vdev.virtqueue[q_idx]);
460 	}
461 }
462 
463 static void
464 add_vdev_cb(void *arg)
465 {
466 	struct spdk_vhost_scsi_dev *svdev = arg;
467 	struct spdk_vhost_dev *vdev = &svdev->vdev;
468 	uint32_t i;
469 
470 	for (i = 0; i < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS; i++) {
471 		if (svdev->scsi_dev[i] == NULL) {
472 			continue;
473 		}
474 		spdk_scsi_dev_allocate_io_channels(svdev->scsi_dev[i]);
475 	}
476 	SPDK_NOTICELOG("Started poller for vhost controller %s on lcore %d\n", vdev->name, vdev->lcore);
477 
478 	spdk_vhost_dev_mem_register(vdev);
479 
480 	spdk_poller_register(&svdev->requestq_poller, vdev_worker, svdev, vdev->lcore, 0);
481 	spdk_poller_register(&svdev->controlq_poller, vdev_controlq_worker, svdev, vdev->lcore,
482 			     CONTROLQ_POLL_PERIOD_US);
483 }
484 
485 static void
486 remove_vdev_cb(void *arg)
487 {
488 	struct spdk_vhost_scsi_dev *svdev = arg;
489 	uint32_t i;
490 
491 	for (i = 0; i < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS; i++) {
492 		if (svdev->scsi_dev[i] == NULL) {
493 			continue;
494 		}
495 		spdk_scsi_dev_free_io_channels(svdev->scsi_dev[i]);
496 	}
497 
498 	SPDK_NOTICELOG("Stopping poller for vhost controller %s\n", svdev->vdev.name);
499 	spdk_vhost_dev_mem_unregister(&svdev->vdev);
500 }
501 
502 static struct spdk_vhost_scsi_dev *
503 to_scsi_dev(struct spdk_vhost_dev *ctrlr)
504 {
505 	if (ctrlr == NULL) {
506 		return NULL;
507 	}
508 
509 	if (ctrlr->type != SPDK_VHOST_DEV_T_SCSI) {
510 		SPDK_ERRLOG("Controller %s: expected SCSI controller (%d) but got %d\n",
511 			    ctrlr->name, SPDK_VHOST_DEV_T_SCSI, ctrlr->type);
512 		return NULL;
513 	}
514 
515 	return (struct spdk_vhost_scsi_dev *)ctrlr;
516 }
517 
518 int
519 spdk_vhost_scsi_dev_construct(const char *name, uint64_t cpumask)
520 {
521 	struct spdk_vhost_scsi_dev *svdev = spdk_dma_zmalloc(sizeof(struct spdk_vhost_scsi_dev),
522 					    SPDK_CACHE_LINE_SIZE, NULL);
523 	int ret;
524 
525 	if (svdev == NULL) {
526 		return -ENOMEM;
527 	}
528 
529 	ret = spdk_vhost_dev_construct(&svdev->vdev, name, cpumask, SPDK_VHOST_DEV_T_SCSI,
530 				       &spdk_vhost_scsi_device_backend);
531 
532 	if (ret) {
533 		spdk_dma_free(svdev);
534 	}
535 
536 	return ret;
537 }
538 
539 int
540 spdk_vhost_scsi_dev_remove(struct spdk_vhost_dev *vdev)
541 {
542 	struct spdk_vhost_scsi_dev *svdev = to_scsi_dev(vdev);
543 	int i;
544 
545 	if (svdev == NULL) {
546 		return -EINVAL;
547 	}
548 
549 	for (i = 0; i < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS; ++i) {
550 		if (svdev->scsi_dev[i]) {
551 			SPDK_ERRLOG("Trying to remove non-empty controller: %s.\n", vdev->name);
552 			return -EBUSY;
553 		}
554 	}
555 
556 	if (spdk_vhost_dev_remove(vdev) != 0) {
557 		return -EIO;
558 	}
559 
560 	spdk_dma_free(svdev);
561 	return 0;
562 }
563 
564 struct spdk_scsi_dev *
565 spdk_vhost_scsi_dev_get_dev(struct spdk_vhost_dev *vdev, uint8_t num)
566 {
567 	struct spdk_vhost_scsi_dev *svdev;
568 
569 	assert(num < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS);
570 	svdev = to_scsi_dev(vdev);
571 
572 	return svdev ? svdev->scsi_dev[num] : NULL;
573 }
574 
575 int
576 spdk_vhost_scsi_dev_add_dev(const char *ctrlr_name, unsigned scsi_dev_num, const char *lun_name)
577 {
578 	struct spdk_vhost_scsi_dev *svdev;
579 	struct spdk_vhost_dev *vdev;
580 	char dev_name[SPDK_SCSI_DEV_MAX_NAME];
581 	int lun_id_list[1];
582 	char *lun_names_list[1];
583 
584 	if (ctrlr_name == NULL) {
585 		SPDK_ERRLOG("No controller name\n");
586 		return -EINVAL;
587 	}
588 
589 	if (scsi_dev_num >= SPDK_VHOST_SCSI_CTRLR_MAX_DEVS) {
590 		SPDK_ERRLOG("Controller %d device number too big (max %d)\n", scsi_dev_num,
591 			    SPDK_VHOST_SCSI_CTRLR_MAX_DEVS);
592 		return -EINVAL;
593 	}
594 
595 	if (lun_name == NULL) {
596 		SPDK_ERRLOG("No lun name specified \n");
597 		return -EINVAL;
598 	} else if (strlen(lun_name) >= SPDK_SCSI_DEV_MAX_NAME) {
599 		SPDK_ERRLOG("LUN name '%s' too long (max %d).\n", lun_name, SPDK_SCSI_DEV_MAX_NAME - 1);
600 		return -1;
601 	}
602 
603 	vdev = spdk_vhost_dev_find(ctrlr_name);
604 	if (vdev == NULL) {
605 		SPDK_ERRLOG("Controller %s is not defined.\n", ctrlr_name);
606 		return -ENODEV;
607 	}
608 
609 	svdev = to_scsi_dev(vdev);
610 	if (svdev == NULL) {
611 		return -EINVAL;
612 	}
613 
614 	if (vdev->lcore != -1) {
615 		SPDK_ERRLOG("Controller %s is in use and hotplug is not supported\n", ctrlr_name);
616 		return -ENODEV;
617 	}
618 
619 	if (svdev->scsi_dev[scsi_dev_num] != NULL) {
620 		SPDK_ERRLOG("Controller %s dev %u already occupied\n", ctrlr_name, scsi_dev_num);
621 		return -EEXIST;
622 	}
623 
624 	/*
625 	 * At this stage only one LUN per device
626 	 */
627 	snprintf(dev_name, sizeof(dev_name), "Dev %u", scsi_dev_num);
628 	lun_id_list[0] = 0;
629 	lun_names_list[0] = (char *)lun_name;
630 
631 	svdev->scsi_dev[scsi_dev_num] = spdk_scsi_dev_construct(dev_name, lun_names_list, lun_id_list, 1,
632 					SPDK_SPC_PROTOCOL_IDENTIFIER_SAS);
633 
634 	if (svdev->scsi_dev[scsi_dev_num] == NULL) {
635 		SPDK_ERRLOG("Couldn't create spdk SCSI device '%s' using lun device '%s' in controller: %s\n",
636 			    dev_name, lun_name, vdev->name);
637 		return -EINVAL;
638 	}
639 
640 	spdk_scsi_dev_add_port(svdev->scsi_dev[scsi_dev_num], 0, "vhost");
641 	SPDK_NOTICELOG("Controller %s: defined device '%s' using lun '%s'\n",
642 		       vdev->name, dev_name, lun_name);
643 	return 0;
644 }
645 
646 int
647 spdk_vhost_scsi_dev_remove_dev(struct spdk_vhost_dev *vdev, unsigned scsi_dev_num)
648 {
649 	struct spdk_vhost_scsi_dev *svdev;
650 
651 	assert(vdev != NULL);
652 	if (vdev->lcore != -1) {
653 		SPDK_ERRLOG("Controller %s is in use and hotremove is not supported\n", vdev->name);
654 		return -EBUSY;
655 	}
656 
657 	svdev = to_scsi_dev(vdev);
658 	if (svdev == NULL) {
659 		return -ENODEV;
660 	}
661 
662 	if (svdev->scsi_dev[scsi_dev_num] == NULL) {
663 		SPDK_ERRLOG("Controller %s dev %u is not occupied\n", vdev->name, scsi_dev_num);
664 		return -ENODEV;
665 	}
666 
667 	spdk_scsi_dev_destruct(svdev->scsi_dev[scsi_dev_num]);
668 	svdev->scsi_dev[scsi_dev_num] = NULL;
669 
670 	SPDK_NOTICELOG("Controller %s: removed device 'Dev %u'\n",
671 		       vdev->name, scsi_dev_num);
672 	return 0;
673 }
674 
675 int
676 spdk_vhost_scsi_controller_construct(void)
677 {
678 	struct spdk_conf_section *sp = spdk_conf_first_section(NULL);
679 	int i, dev_num;
680 	unsigned ctrlr_num = 0;
681 	char *lun_name, *dev_num_str;
682 	char *cpumask_str;
683 	char *name;
684 	uint64_t cpumask;
685 
686 	while (sp != NULL) {
687 		if (!spdk_conf_section_match_prefix(sp, "VhostScsi")) {
688 			sp = spdk_conf_next_section(sp);
689 			continue;
690 		}
691 
692 		if (sscanf(spdk_conf_section_get_name(sp), "VhostScsi%u", &ctrlr_num) != 1) {
693 			SPDK_ERRLOG("Section '%s' has non-numeric suffix.\n",
694 				    spdk_conf_section_get_name(sp));
695 			return -1;
696 		}
697 
698 		name =  spdk_conf_section_get_val(sp, "Name");
699 		cpumask_str = spdk_conf_section_get_val(sp, "Cpumask");
700 		if (cpumask_str == NULL) {
701 			cpumask = spdk_app_get_core_mask();
702 		} else if (spdk_vhost_parse_core_mask(cpumask_str, &cpumask)) {
703 			SPDK_ERRLOG("%s: Error parsing cpumask '%s' while creating controller\n", name, cpumask_str);
704 			return -1;
705 		}
706 
707 		if (spdk_vhost_scsi_dev_construct(name, cpumask) < 0) {
708 			return -1;
709 		}
710 
711 		for (i = 0; spdk_conf_section_get_nval(sp, "Dev", i) != NULL; i++) {
712 			dev_num_str = spdk_conf_section_get_nmval(sp, "Dev", i, 0);
713 			if (dev_num_str == NULL) {
714 				SPDK_ERRLOG("%s: Invalid or missing Dev number\n", name);
715 				return -1;
716 			}
717 
718 			dev_num = (int)strtol(dev_num_str, NULL, 10);
719 			lun_name = spdk_conf_section_get_nmval(sp, "Dev", i, 1);
720 			if (lun_name == NULL) {
721 				SPDK_ERRLOG("%s: Invalid or missing LUN name for dev %d\n", name, dev_num);
722 				return -1;
723 			} else if (spdk_conf_section_get_nmval(sp, "Dev", i, 2)) {
724 				SPDK_ERRLOG("%s: Only one LUN per vhost SCSI device supported\n", name);
725 				return -1;
726 			}
727 
728 			if (spdk_vhost_scsi_dev_add_dev(name, dev_num, lun_name) < 0) {
729 				return -1;
730 			}
731 		}
732 
733 		sp = spdk_conf_next_section(sp);
734 
735 	}
736 
737 	return 0;
738 }
739 
740 /*
741  * A new device is added to a data core. First the device is added to the main linked list
742  * and then allocated to a specific data core.
743  */
744 static int
745 new_device(int vid)
746 {
747 	struct spdk_vhost_dev *vdev = NULL;
748 
749 	vdev = spdk_vhost_dev_load(vid);
750 	if (vdev == NULL) {
751 		return -1;
752 	}
753 
754 	spdk_vhost_timed_event_send(vdev->lcore, add_vdev_cb, vdev, 1, "add scsi vdev");
755 	return 0;
756 }
757 
758 static void
759 destroy_device(int vid)
760 {
761 	struct spdk_vhost_scsi_dev *svdev;
762 	struct spdk_vhost_dev *vdev;
763 	struct spdk_vhost_timed_event event = {0};
764 
765 	vdev = spdk_vhost_dev_find_by_vid(vid);
766 	if (vdev == NULL) {
767 		rte_panic("Couldn't find device with vid %d to stop.\n", vid);
768 	}
769 	svdev = to_scsi_dev(vdev);
770 	assert(svdev);
771 
772 	spdk_vhost_timed_event_init(&event, vdev->lcore, NULL, NULL, 1);
773 	spdk_poller_unregister(&svdev->requestq_poller, event.spdk_event);
774 	spdk_vhost_timed_event_wait(&event, "unregister request queue poller");
775 
776 	spdk_vhost_timed_event_init(&event, vdev->lcore, NULL, NULL, 1);
777 	spdk_poller_unregister(&svdev->controlq_poller, event.spdk_event);
778 	spdk_vhost_timed_event_wait(&event, "unregister controll queue poller");
779 
780 	spdk_vhost_timed_event_send(vdev->lcore, remove_vdev_cb, svdev, 1, "remove scsi vdev");
781 
782 	spdk_vhost_dev_unload(vdev);
783 }
784 
785 SPDK_LOG_REGISTER_TRACE_FLAG("vhost", SPDK_TRACE_VHOST)
786 SPDK_LOG_REGISTER_TRACE_FLAG("vhost_queue", SPDK_TRACE_VHOST_QUEUE)
787 SPDK_LOG_REGISTER_TRACE_FLAG("vhost_data", SPDK_TRACE_VHOST_DATA)
788