Line data Source code
1 : /* SPDX-License-Identifier: BSD-3-Clause
2 : * Copyright (C) 2017 Intel Corporation. All rights reserved.
3 : * All rights reserved.
4 : */
5 :
6 : #include "spdk/stdinc.h"
7 :
8 : #include <linux/virtio_scsi.h>
9 :
10 : #include "spdk/env.h"
11 : #include "spdk/thread.h"
12 : #include "spdk/scsi.h"
13 : #include "spdk/scsi_spec.h"
14 : #include "spdk/util.h"
15 : #include "spdk/likely.h"
16 :
17 : #include "spdk/vhost.h"
18 : #include "vhost_internal.h"
19 :
20 : /* Features supported by SPDK VHOST lib. */
21 : #define SPDK_VHOST_SCSI_FEATURES (SPDK_VHOST_FEATURES | \
22 : (1ULL << VIRTIO_SCSI_F_INOUT) | \
23 : (1ULL << VIRTIO_SCSI_F_HOTPLUG) | \
24 : (1ULL << VIRTIO_SCSI_F_CHANGE ) | \
25 : (1ULL << VIRTIO_SCSI_F_T10_PI ))
26 :
27 : /* Features that are specified in VIRTIO SCSI but currently not supported:
28 : * - Live migration not supported yet
29 : * - T10 PI
30 : */
31 : #define SPDK_VHOST_SCSI_DISABLED_FEATURES (SPDK_VHOST_DISABLED_FEATURES | \
32 : (1ULL << VIRTIO_SCSI_F_T10_PI ))
33 :
34 : /* Vhost-user-scsi support protocol features */
35 : #define SPDK_VHOST_SCSI_PROTOCOL_FEATURES (1ULL << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)
36 :
37 : #define MGMT_POLL_PERIOD_US (1000 * 5)
38 :
39 : #define VIRTIO_SCSI_CONTROLQ 0
40 : #define VIRTIO_SCSI_EVENTQ 1
41 : #define VIRTIO_SCSI_REQUESTQ 2
42 :
43 : enum spdk_scsi_dev_vhost_status {
44 : /* Target ID is empty. */
45 : VHOST_SCSI_DEV_EMPTY,
46 :
47 : /* Target is still being added. */
48 : VHOST_SCSI_DEV_ADDING,
49 :
50 : /* Target ID occupied. */
51 : VHOST_SCSI_DEV_PRESENT,
52 :
53 : /* Target ID is occupied but removal is in progress. */
54 : VHOST_SCSI_DEV_REMOVING,
55 :
56 : /* In session - device (SCSI target) seen but removed. */
57 : VHOST_SCSI_DEV_REMOVED,
58 : };
59 :
60 : /** Context for a SCSI target in a vhost device */
61 : struct spdk_scsi_dev_vhost_state {
62 : struct spdk_scsi_dev *dev;
63 : enum spdk_scsi_dev_vhost_status status;
64 : spdk_vhost_event_fn remove_cb;
65 : void *remove_ctx;
66 : };
67 :
68 : struct spdk_vhost_scsi_dev {
69 : int ref;
70 : bool registered;
71 : struct spdk_vhost_dev vdev;
72 : struct spdk_scsi_dev_vhost_state scsi_dev_state[SPDK_VHOST_SCSI_CTRLR_MAX_DEVS];
73 : };
74 :
75 : /** Context for a SCSI target in a vhost session */
76 : struct spdk_scsi_dev_session_state {
77 : struct spdk_scsi_dev *dev;
78 : enum spdk_scsi_dev_vhost_status status;
79 : };
80 :
81 : struct spdk_vhost_scsi_session {
82 : struct spdk_vhost_session vsession;
83 :
84 : struct spdk_vhost_scsi_dev *svdev;
85 : /** Local copy of the device state */
86 : struct spdk_scsi_dev_session_state scsi_dev_state[SPDK_VHOST_SCSI_CTRLR_MAX_DEVS];
87 : struct spdk_poller *requestq_poller;
88 : struct spdk_poller *mgmt_poller;
89 : struct spdk_poller *stop_poller;
90 : };
91 :
92 : struct spdk_vhost_scsi_task {
93 : struct spdk_scsi_task scsi;
94 : struct iovec iovs[SPDK_VHOST_IOVS_MAX];
95 :
96 : union {
97 : struct virtio_scsi_cmd_resp *resp;
98 : struct virtio_scsi_ctrl_tmf_resp *tmf_resp;
99 : };
100 :
101 : struct spdk_vhost_scsi_session *svsession;
102 : struct spdk_scsi_dev *scsi_dev;
103 :
104 : /** Number of bytes that were written. */
105 : uint32_t used_len;
106 :
107 : int req_idx;
108 :
109 : /* If set, the task is currently used for I/O processing. */
110 : bool used;
111 :
112 : struct spdk_vhost_virtqueue *vq;
113 : };
114 :
115 : static int vhost_scsi_start(struct spdk_vhost_dev *vdev,
116 : struct spdk_vhost_session *vsession, void *unused);
117 : static int vhost_scsi_stop(struct spdk_vhost_dev *vdev,
118 : struct spdk_vhost_session *vsession, void *unused);
119 : static void vhost_scsi_dump_info_json(struct spdk_vhost_dev *vdev,
120 : struct spdk_json_write_ctx *w);
121 : static void vhost_scsi_write_config_json(struct spdk_vhost_dev *vdev,
122 : struct spdk_json_write_ctx *w);
123 : static int vhost_scsi_dev_remove(struct spdk_vhost_dev *vdev);
124 : static int vhost_scsi_dev_param_changed(struct spdk_vhost_dev *vdev,
125 : unsigned scsi_tgt_num);
126 : static int alloc_vq_task_pool(struct spdk_vhost_session *vsession, uint16_t qid);
127 :
128 : static const struct spdk_vhost_user_dev_backend spdk_vhost_scsi_user_device_backend = {
129 : .session_ctx_size = sizeof(struct spdk_vhost_scsi_session) - sizeof(struct spdk_vhost_session),
130 : .start_session = vhost_scsi_start,
131 : .stop_session = vhost_scsi_stop,
132 : .alloc_vq_tasks = alloc_vq_task_pool,
133 : };
134 :
135 : static const struct spdk_vhost_dev_backend spdk_vhost_scsi_device_backend = {
136 : .type = VHOST_BACKEND_SCSI,
137 : .dump_info_json = vhost_scsi_dump_info_json,
138 : .write_config_json = vhost_scsi_write_config_json,
139 : .remove_device = vhost_scsi_dev_remove,
140 : .set_coalescing = vhost_user_set_coalescing,
141 : .get_coalescing = vhost_user_get_coalescing,
142 : };
143 :
144 : static inline void
145 0 : scsi_task_init(struct spdk_vhost_scsi_task *task)
146 : {
147 0 : memset(&task->scsi, 0, sizeof(task->scsi));
148 : /* Tmf_resp pointer and resp pointer are in a union.
149 : * Here means task->tmf_resp = task->resp = NULL.
150 : */
151 0 : task->resp = NULL;
152 0 : task->used = true;
153 0 : task->used_len = 0;
154 0 : }
155 :
156 : static void
157 0 : vhost_scsi_task_put(struct spdk_vhost_scsi_task *task)
158 : {
159 0 : spdk_scsi_task_put(&task->scsi);
160 0 : }
161 :
162 : static void
163 0 : vhost_scsi_task_free_cb(struct spdk_scsi_task *scsi_task)
164 : {
165 0 : struct spdk_vhost_scsi_task *task = SPDK_CONTAINEROF(scsi_task, struct spdk_vhost_scsi_task, scsi);
166 0 : struct spdk_vhost_session *vsession = &task->svsession->vsession;
167 :
168 0 : assert(vsession->task_cnt > 0);
169 0 : vsession->task_cnt--;
170 0 : task->used = false;
171 0 : }
172 :
173 : static void
174 0 : vhost_scsi_dev_unregister(void *arg1)
175 : {
176 0 : struct spdk_vhost_scsi_dev *svdev = arg1;
177 :
178 0 : if (vhost_dev_unregister(&svdev->vdev) == 0) {
179 0 : free(svdev);
180 0 : }
181 0 : }
182 :
183 : static void
184 0 : remove_scsi_tgt(struct spdk_vhost_scsi_dev *svdev,
185 : unsigned scsi_tgt_num)
186 : {
187 0 : struct spdk_scsi_dev_vhost_state *state;
188 0 : struct spdk_scsi_dev *dev;
189 :
190 0 : state = &svdev->scsi_dev_state[scsi_tgt_num];
191 0 : dev = state->dev;
192 0 : state->dev = NULL;
193 0 : assert(state->status == VHOST_SCSI_DEV_REMOVING);
194 0 : state->status = VHOST_SCSI_DEV_EMPTY;
195 0 : spdk_scsi_dev_destruct(dev, NULL, NULL);
196 0 : if (state->remove_cb) {
197 0 : state->remove_cb(&svdev->vdev, state->remove_ctx);
198 0 : state->remove_cb = NULL;
199 0 : }
200 0 : SPDK_INFOLOG(vhost, "removed target 'Target %u'\n", scsi_tgt_num);
201 :
202 0 : if (--svdev->ref == 0 && svdev->registered == false) {
203 : /* `remove_scsi_tgt` is running under vhost-user lock, so we
204 : * unregister the device in next poll.
205 : */
206 0 : spdk_thread_send_msg(spdk_get_thread(), vhost_scsi_dev_unregister, svdev);
207 0 : }
208 0 : }
209 :
210 : static void
211 0 : vhost_scsi_dev_process_removed_cpl_cb(struct spdk_vhost_dev *vdev, void *ctx)
212 : {
213 0 : unsigned scsi_tgt_num = (unsigned)(uintptr_t)ctx;
214 0 : struct spdk_vhost_scsi_dev *svdev = SPDK_CONTAINEROF(vdev,
215 : struct spdk_vhost_scsi_dev, vdev);
216 :
217 : /* all sessions have already detached the device */
218 0 : if (svdev->scsi_dev_state[scsi_tgt_num].status != VHOST_SCSI_DEV_REMOVING) {
219 : /* device was already removed in the meantime */
220 0 : return;
221 : }
222 :
223 0 : remove_scsi_tgt(svdev, scsi_tgt_num);
224 0 : }
225 :
226 : static int
227 0 : vhost_scsi_session_process_removed(struct spdk_vhost_dev *vdev,
228 : struct spdk_vhost_session *vsession, void *ctx)
229 : {
230 0 : unsigned scsi_tgt_num = (unsigned)(uintptr_t)ctx;
231 0 : struct spdk_vhost_scsi_session *svsession = (struct spdk_vhost_scsi_session *)vsession;
232 0 : struct spdk_scsi_dev_session_state *state = &svsession->scsi_dev_state[scsi_tgt_num];
233 :
234 0 : if (state->dev != NULL) {
235 : /* there's still a session that references this device,
236 : * so abort our foreach chain here. We'll be called
237 : * again from this session's management poller after it
238 : * is removed in there
239 : */
240 0 : return -1;
241 : }
242 :
243 0 : return 0;
244 0 : }
245 :
246 : static void
247 0 : process_removed_devs(struct spdk_vhost_scsi_session *svsession)
248 : {
249 0 : struct spdk_scsi_dev *dev;
250 0 : struct spdk_scsi_dev_session_state *state;
251 0 : int i;
252 :
253 0 : for (i = 0; i < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS; ++i) {
254 0 : state = &svsession->scsi_dev_state[i];
255 0 : dev = state->dev;
256 :
257 0 : if (dev && state->status == VHOST_SCSI_DEV_REMOVING &&
258 0 : !spdk_scsi_dev_has_pending_tasks(dev, NULL)) {
259 : /* detach the device from this session */
260 0 : spdk_scsi_dev_free_io_channels(dev);
261 0 : state->dev = NULL;
262 0 : state->status = VHOST_SCSI_DEV_REMOVED;
263 : /* try to detach it globally */
264 0 : vhost_user_dev_foreach_session(&svsession->svdev->vdev,
265 : vhost_scsi_session_process_removed,
266 : vhost_scsi_dev_process_removed_cpl_cb,
267 0 : (void *)(uintptr_t)i);
268 0 : }
269 0 : }
270 0 : }
271 :
272 : static void
273 0 : eventq_enqueue(struct spdk_vhost_scsi_session *svsession, unsigned scsi_dev_num,
274 : uint32_t event, uint32_t reason)
275 : {
276 0 : struct spdk_vhost_session *vsession = &svsession->vsession;
277 0 : struct spdk_vhost_virtqueue *vq;
278 0 : struct vring_desc *desc, *desc_table;
279 0 : struct virtio_scsi_event *desc_ev;
280 0 : uint32_t desc_table_size, req_size = 0;
281 0 : uint16_t req;
282 0 : int rc;
283 :
284 0 : assert(scsi_dev_num < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS);
285 0 : vq = &vsession->virtqueue[VIRTIO_SCSI_EVENTQ];
286 :
287 0 : if (vq->vring.desc == NULL || vhost_vq_avail_ring_get(vq, &req, 1) != 1) {
288 0 : SPDK_ERRLOG("%s: failed to send virtio event (no avail ring entries?).\n",
289 : vsession->name);
290 0 : return;
291 : }
292 :
293 0 : rc = vhost_vq_get_desc(vsession, vq, req, &desc, &desc_table, &desc_table_size);
294 0 : if (rc != 0 || desc->len < sizeof(*desc_ev)) {
295 0 : SPDK_ERRLOG("%s: invalid eventq descriptor at index %"PRIu16".\n",
296 : vsession->name, req);
297 0 : goto out;
298 : }
299 :
300 0 : desc_ev = vhost_gpa_to_vva(vsession, desc->addr, sizeof(*desc_ev));
301 0 : if (desc_ev == NULL) {
302 0 : SPDK_ERRLOG("%s: eventq descriptor at index %"PRIu16" points "
303 : "to unmapped guest memory address %p.\n",
304 : vsession->name, req, (void *)(uintptr_t)desc->addr);
305 0 : goto out;
306 : }
307 :
308 0 : desc_ev->event = event;
309 0 : desc_ev->lun[0] = 1;
310 0 : desc_ev->lun[1] = scsi_dev_num;
311 : /* virtio LUN id 0 can refer either to the entire device
312 : * or actual LUN 0 (the only supported by vhost for now)
313 : */
314 0 : desc_ev->lun[2] = 0 >> 8;
315 0 : desc_ev->lun[3] = 0 & 0xFF;
316 : /* virtio doesn't specify any strict format for LUN id (bytes 2 and 3)
317 : * current implementation relies on linux kernel sources
318 : */
319 0 : memset(&desc_ev->lun[4], 0, 4);
320 0 : desc_ev->reason = reason;
321 0 : req_size = sizeof(*desc_ev);
322 :
323 : out:
324 0 : vhost_vq_used_ring_enqueue(vsession, vq, req, req_size);
325 0 : }
326 :
327 : static void
328 0 : submit_completion(struct spdk_vhost_scsi_task *task)
329 : {
330 0 : struct spdk_vhost_session *vsession = &task->svsession->vsession;
331 :
332 0 : vhost_vq_used_ring_enqueue(vsession, task->vq, task->req_idx,
333 0 : task->used_len);
334 0 : SPDK_DEBUGLOG(vhost_scsi, "Finished task (%p) req_idx=%d\n", task, task->req_idx);
335 :
336 0 : vhost_scsi_task_put(task);
337 0 : }
338 :
339 : static void
340 0 : vhost_scsi_task_mgmt_cpl(struct spdk_scsi_task *scsi_task)
341 : {
342 0 : struct spdk_vhost_scsi_task *task = SPDK_CONTAINEROF(scsi_task, struct spdk_vhost_scsi_task, scsi);
343 :
344 0 : submit_completion(task);
345 0 : }
346 :
347 : static void
348 0 : vhost_scsi_task_cpl(struct spdk_scsi_task *scsi_task)
349 : {
350 0 : struct spdk_vhost_scsi_task *task = SPDK_CONTAINEROF(scsi_task, struct spdk_vhost_scsi_task, scsi);
351 :
352 : /* The SCSI task has completed. Do final processing and then post
353 : notification to the virtqueue's "used" ring.
354 : */
355 0 : task->resp->status = task->scsi.status;
356 :
357 0 : if (task->scsi.status != SPDK_SCSI_STATUS_GOOD) {
358 0 : memcpy(task->resp->sense, task->scsi.sense_data, task->scsi.sense_data_len);
359 0 : task->resp->sense_len = task->scsi.sense_data_len;
360 0 : SPDK_DEBUGLOG(vhost_scsi, "Task (%p) req_idx=%d failed - status=%u\n", task, task->req_idx,
361 : task->scsi.status);
362 0 : }
363 0 : assert(task->scsi.transfer_len == task->scsi.length);
364 0 : task->resp->resid = task->scsi.length - task->scsi.data_transferred;
365 :
366 0 : submit_completion(task);
367 0 : }
368 :
369 : static void
370 0 : task_submit(struct spdk_vhost_scsi_task *task)
371 : {
372 0 : task->resp->response = VIRTIO_SCSI_S_OK;
373 0 : spdk_scsi_dev_queue_task(task->scsi_dev, &task->scsi);
374 0 : }
375 :
376 : static void
377 0 : mgmt_task_submit(struct spdk_vhost_scsi_task *task, enum spdk_scsi_task_func func)
378 : {
379 0 : task->tmf_resp->response = VIRTIO_SCSI_S_OK;
380 0 : task->scsi.function = func;
381 0 : spdk_scsi_dev_queue_mgmt_task(task->scsi_dev, &task->scsi);
382 0 : }
383 :
384 : static void
385 0 : invalid_request(struct spdk_vhost_scsi_task *task)
386 : {
387 0 : struct spdk_vhost_session *vsession = &task->svsession->vsession;
388 :
389 0 : vhost_vq_used_ring_enqueue(vsession, task->vq, task->req_idx,
390 0 : task->used_len);
391 0 : vhost_scsi_task_put(task);
392 :
393 0 : SPDK_DEBUGLOG(vhost_scsi, "Invalid request (status=%" PRIu8")\n",
394 : task->resp ? task->resp->response : -1);
395 0 : }
396 :
397 : static int
398 0 : vhost_scsi_task_init_target(struct spdk_vhost_scsi_task *task, const __u8 *lun)
399 : {
400 0 : struct spdk_vhost_scsi_session *svsession = task->svsession;
401 0 : struct spdk_scsi_dev_session_state *state;
402 0 : uint16_t lun_id = (((uint16_t)lun[2] << 8) | lun[3]) & 0x3FFF;
403 :
404 0 : SPDK_LOGDUMP(vhost_scsi_queue, "LUN", lun, 8);
405 :
406 : /* First byte must be 1 and second is target */
407 0 : if (lun[0] != 1 || lun[1] >= SPDK_VHOST_SCSI_CTRLR_MAX_DEVS) {
408 0 : return -1;
409 : }
410 :
411 0 : state = &svsession->scsi_dev_state[lun[1]];
412 0 : task->scsi_dev = state->dev;
413 0 : if (state->dev == NULL || state->status != VHOST_SCSI_DEV_PRESENT) {
414 : /* If dev has been hotdetached, return 0 to allow sending
415 : * additional hotremove event via sense codes.
416 : */
417 0 : return state->status != VHOST_SCSI_DEV_EMPTY ? 0 : -1;
418 : }
419 :
420 0 : task->scsi.target_port = spdk_scsi_dev_find_port_by_id(task->scsi_dev, 0);
421 0 : task->scsi.lun = spdk_scsi_dev_get_lun(state->dev, lun_id);
422 0 : return 0;
423 0 : }
424 :
425 : static void
426 0 : process_ctrl_request(struct spdk_vhost_scsi_task *task)
427 : {
428 0 : struct spdk_vhost_session *vsession = &task->svsession->vsession;
429 0 : struct vring_desc *desc, *desc_table;
430 0 : struct virtio_scsi_ctrl_tmf_req *ctrl_req;
431 0 : struct virtio_scsi_ctrl_an_resp *an_resp;
432 0 : uint32_t desc_table_size, used_len = 0;
433 0 : int rc;
434 :
435 0 : spdk_scsi_task_construct(&task->scsi, vhost_scsi_task_mgmt_cpl, vhost_scsi_task_free_cb);
436 0 : rc = vhost_vq_get_desc(vsession, task->vq, task->req_idx, &desc, &desc_table,
437 : &desc_table_size);
438 0 : if (spdk_unlikely(rc != 0)) {
439 0 : SPDK_ERRLOG("%s: invalid controlq descriptor at index %d.\n",
440 : vsession->name, task->req_idx);
441 0 : goto out;
442 : }
443 :
444 0 : ctrl_req = vhost_gpa_to_vva(vsession, desc->addr, sizeof(*ctrl_req));
445 0 : if (ctrl_req == NULL) {
446 0 : SPDK_ERRLOG("%s: invalid task management request at index %d.\n",
447 : vsession->name, task->req_idx);
448 0 : goto out;
449 : }
450 :
451 0 : SPDK_DEBUGLOG(vhost_scsi_queue,
452 : "Processing controlq descriptor: desc %d/%p, desc_addr %p, len %d, flags %d, last_used_idx %d; kickfd %d; size %d\n",
453 : task->req_idx, desc, (void *)desc->addr, desc->len, desc->flags, task->vq->last_used_idx,
454 : task->vq->vring.kickfd, task->vq->vring.size);
455 0 : SPDK_LOGDUMP(vhost_scsi_queue, "Request descriptor", (uint8_t *)ctrl_req, desc->len);
456 :
457 0 : vhost_scsi_task_init_target(task, ctrl_req->lun);
458 :
459 0 : vhost_vring_desc_get_next(&desc, desc_table, desc_table_size);
460 0 : if (spdk_unlikely(desc == NULL)) {
461 0 : SPDK_ERRLOG("%s: no response descriptor for controlq request %d.\n",
462 : vsession->name, task->req_idx);
463 0 : goto out;
464 : }
465 :
466 : /* Process the TMF request */
467 0 : switch (ctrl_req->type) {
468 : case VIRTIO_SCSI_T_TMF:
469 0 : task->tmf_resp = vhost_gpa_to_vva(vsession, desc->addr, sizeof(*task->tmf_resp));
470 0 : if (spdk_unlikely(desc->len < sizeof(struct virtio_scsi_ctrl_tmf_resp) || task->tmf_resp == NULL)) {
471 0 : SPDK_ERRLOG("%s: TMF response descriptor at index %d points to invalid guest memory region\n",
472 : vsession->name, task->req_idx);
473 0 : goto out;
474 : }
475 :
476 : /* Check if we are processing a valid request */
477 0 : if (task->scsi_dev == NULL) {
478 0 : task->tmf_resp->response = VIRTIO_SCSI_S_BAD_TARGET;
479 0 : break;
480 : }
481 :
482 0 : switch (ctrl_req->subtype) {
483 : case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET:
484 : /* Handle LUN reset */
485 0 : SPDK_DEBUGLOG(vhost_scsi_queue, "%s: LUN reset\n", vsession->name);
486 :
487 0 : mgmt_task_submit(task, SPDK_SCSI_TASK_FUNC_LUN_RESET);
488 0 : return;
489 : default:
490 0 : task->tmf_resp->response = VIRTIO_SCSI_S_ABORTED;
491 : /* Unsupported command */
492 0 : SPDK_DEBUGLOG(vhost_scsi_queue, "%s: unsupported TMF command %x\n",
493 : vsession->name, ctrl_req->subtype);
494 0 : break;
495 : }
496 0 : break;
497 : case VIRTIO_SCSI_T_AN_QUERY:
498 : case VIRTIO_SCSI_T_AN_SUBSCRIBE: {
499 0 : an_resp = vhost_gpa_to_vva(vsession, desc->addr, sizeof(*an_resp));
500 0 : if (spdk_unlikely(desc->len < sizeof(struct virtio_scsi_ctrl_an_resp) || an_resp == NULL)) {
501 0 : SPDK_WARNLOG("%s: asynchronous response descriptor points to invalid guest memory region\n",
502 : vsession->name);
503 0 : goto out;
504 : }
505 :
506 0 : an_resp->response = VIRTIO_SCSI_S_ABORTED;
507 0 : break;
508 : }
509 : default:
510 0 : SPDK_DEBUGLOG(vhost_scsi_queue, "%s: Unsupported control command %x\n",
511 : vsession->name, ctrl_req->type);
512 0 : break;
513 : }
514 :
515 0 : used_len = sizeof(struct virtio_scsi_ctrl_tmf_resp);
516 : out:
517 0 : vhost_vq_used_ring_enqueue(vsession, task->vq, task->req_idx, used_len);
518 0 : vhost_scsi_task_put(task);
519 0 : }
520 :
521 : /*
522 : * Process task's descriptor chain and setup data related fields.
523 : * Return
524 : * -1 if request is invalid and must be aborted,
525 : * 0 if all data are set.
526 : */
527 : static int
528 0 : task_data_setup(struct spdk_vhost_scsi_task *task,
529 : struct virtio_scsi_cmd_req **req)
530 : {
531 0 : struct spdk_vhost_session *vsession = &task->svsession->vsession;
532 0 : struct vring_desc *desc, *desc_table;
533 0 : struct iovec *iovs = task->iovs;
534 0 : uint16_t iovcnt = 0;
535 0 : uint32_t desc_table_len, len = 0;
536 0 : int rc;
537 :
538 0 : spdk_scsi_task_construct(&task->scsi, vhost_scsi_task_cpl, vhost_scsi_task_free_cb);
539 :
540 0 : rc = vhost_vq_get_desc(vsession, task->vq, task->req_idx, &desc, &desc_table, &desc_table_len);
541 : /* First descriptor must be readable */
542 0 : if (spdk_unlikely(rc != 0 || vhost_vring_desc_is_wr(desc) ||
543 : desc->len < sizeof(struct virtio_scsi_cmd_req))) {
544 0 : SPDK_WARNLOG("%s: invalid first request descriptor at index %"PRIu16".\n",
545 : vsession->name, task->req_idx);
546 0 : goto invalid_task;
547 : }
548 :
549 0 : *req = vhost_gpa_to_vva(vsession, desc->addr, sizeof(**req));
550 0 : if (spdk_unlikely(*req == NULL)) {
551 0 : SPDK_WARNLOG("%s: request descriptor at index %d points to invalid guest memory region\n",
552 : vsession->name, task->req_idx);
553 0 : goto invalid_task;
554 : }
555 :
556 : /* Each request must have at least 2 descriptors (e.g. request and response) */
557 0 : vhost_vring_desc_get_next(&desc, desc_table, desc_table_len);
558 0 : if (desc == NULL) {
559 0 : SPDK_WARNLOG("%s: descriptor chain at index %d contains neither payload nor response buffer.\n",
560 : vsession->name, task->req_idx);
561 0 : goto invalid_task;
562 : }
563 0 : task->scsi.dxfer_dir = vhost_vring_desc_is_wr(desc) ? SPDK_SCSI_DIR_FROM_DEV :
564 : SPDK_SCSI_DIR_TO_DEV;
565 0 : task->scsi.iovs = iovs;
566 :
567 0 : if (task->scsi.dxfer_dir == SPDK_SCSI_DIR_FROM_DEV) {
568 : /*
569 : * FROM_DEV (READ): [RD_req][WR_resp][WR_buf0]...[WR_bufN]
570 : */
571 0 : task->resp = vhost_gpa_to_vva(vsession, desc->addr, sizeof(*task->resp));
572 0 : if (spdk_unlikely(desc->len < sizeof(struct virtio_scsi_cmd_resp) || task->resp == NULL)) {
573 0 : SPDK_WARNLOG("%s: response descriptor at index %d points to invalid guest memory region\n",
574 : vsession->name, task->req_idx);
575 0 : goto invalid_task;
576 : }
577 0 : rc = vhost_vring_desc_get_next(&desc, desc_table, desc_table_len);
578 0 : if (spdk_unlikely(rc != 0)) {
579 0 : SPDK_WARNLOG("%s: invalid descriptor chain at request index %d (descriptor id overflow?).\n",
580 : vsession->name, task->req_idx);
581 0 : goto invalid_task;
582 : }
583 :
584 0 : if (desc == NULL) {
585 : /*
586 : * TEST UNIT READY command and some others might not contain any payload and this is not an error.
587 : */
588 0 : SPDK_DEBUGLOG(vhost_scsi_data,
589 : "No payload descriptors for FROM DEV command req_idx=%"PRIu16".\n", task->req_idx);
590 0 : SPDK_LOGDUMP(vhost_scsi_data, "CDB=", (*req)->cdb, VIRTIO_SCSI_CDB_SIZE);
591 0 : task->used_len = sizeof(struct virtio_scsi_cmd_resp);
592 0 : task->scsi.iovcnt = 1;
593 0 : task->scsi.iovs[0].iov_len = 0;
594 0 : task->scsi.length = 0;
595 0 : task->scsi.transfer_len = 0;
596 0 : return 0;
597 : }
598 :
599 : /* All remaining descriptors are data. */
600 0 : while (desc) {
601 0 : if (spdk_unlikely(!vhost_vring_desc_is_wr(desc))) {
602 0 : SPDK_WARNLOG("%s: FROM DEV cmd: descriptor nr %" PRIu16" in payload chain is read only.\n",
603 : vsession->name, iovcnt);
604 0 : goto invalid_task;
605 : }
606 :
607 0 : if (spdk_unlikely(vhost_vring_desc_to_iov(vsession, iovs, &iovcnt, desc))) {
608 0 : goto invalid_task;
609 : }
610 0 : len += desc->len;
611 :
612 0 : rc = vhost_vring_desc_get_next(&desc, desc_table, desc_table_len);
613 0 : if (spdk_unlikely(rc != 0)) {
614 0 : SPDK_WARNLOG("%s: invalid payload in descriptor chain starting at index %d.\n",
615 : vsession->name, task->req_idx);
616 0 : goto invalid_task;
617 : }
618 : }
619 :
620 0 : task->used_len = sizeof(struct virtio_scsi_cmd_resp) + len;
621 0 : } else {
622 0 : SPDK_DEBUGLOG(vhost_scsi_data, "TO DEV");
623 : /*
624 : * TO_DEV (WRITE):[RD_req][RD_buf0]...[RD_bufN][WR_resp]
625 : * No need to check descriptor WR flag as this is done while setting scsi.dxfer_dir.
626 : */
627 :
628 : /* Process descriptors up to response. */
629 0 : while (!vhost_vring_desc_is_wr(desc)) {
630 0 : if (spdk_unlikely(vhost_vring_desc_to_iov(vsession, iovs, &iovcnt, desc))) {
631 0 : goto invalid_task;
632 : }
633 0 : len += desc->len;
634 :
635 0 : vhost_vring_desc_get_next(&desc, desc_table, desc_table_len);
636 0 : if (spdk_unlikely(desc == NULL)) {
637 0 : SPDK_WARNLOG("%s: TO_DEV cmd: no response descriptor.\n", vsession->name);
638 0 : goto invalid_task;
639 : }
640 : }
641 :
642 0 : task->resp = vhost_gpa_to_vva(vsession, desc->addr, sizeof(*task->resp));
643 0 : if (spdk_unlikely(desc->len < sizeof(struct virtio_scsi_cmd_resp) || task->resp == NULL)) {
644 0 : SPDK_WARNLOG("%s: response descriptor at index %d points to invalid guest memory region\n",
645 : vsession->name, task->req_idx);
646 0 : goto invalid_task;
647 : }
648 :
649 0 : task->used_len = sizeof(struct virtio_scsi_cmd_resp);
650 : }
651 :
652 0 : task->scsi.iovcnt = iovcnt;
653 0 : task->scsi.length = len;
654 0 : task->scsi.transfer_len = len;
655 0 : return 0;
656 :
657 : invalid_task:
658 0 : SPDK_DEBUGLOG(vhost_scsi_data, "%s: Invalid task at index %"PRIu16".\n",
659 : vsession->name, task->req_idx);
660 0 : return -1;
661 0 : }
662 :
663 : static int
664 0 : process_request(struct spdk_vhost_scsi_task *task)
665 : {
666 0 : struct virtio_scsi_cmd_req *req;
667 0 : int result;
668 :
669 0 : result = task_data_setup(task, &req);
670 0 : if (result) {
671 0 : return result;
672 : }
673 :
674 0 : result = vhost_scsi_task_init_target(task, req->lun);
675 0 : if (spdk_unlikely(result != 0)) {
676 0 : task->resp->response = VIRTIO_SCSI_S_BAD_TARGET;
677 0 : return -1;
678 : }
679 :
680 0 : task->scsi.cdb = req->cdb;
681 0 : SPDK_LOGDUMP(vhost_scsi_data, "request CDB", req->cdb, VIRTIO_SCSI_CDB_SIZE);
682 :
683 0 : if (spdk_unlikely(task->scsi.lun == NULL)) {
684 0 : spdk_scsi_task_process_null_lun(&task->scsi);
685 0 : task->resp->response = VIRTIO_SCSI_S_OK;
686 0 : return 1;
687 : }
688 :
689 0 : return 0;
690 0 : }
691 :
692 : static void
693 0 : process_scsi_task(struct spdk_vhost_session *vsession,
694 : struct spdk_vhost_virtqueue *vq,
695 : uint16_t req_idx)
696 : {
697 0 : struct spdk_vhost_scsi_task *task;
698 0 : int result;
699 :
700 0 : task = &((struct spdk_vhost_scsi_task *)vq->tasks)[req_idx];
701 0 : if (spdk_unlikely(task->used)) {
702 0 : SPDK_ERRLOG("%s: request with idx '%"PRIu16"' is already pending.\n",
703 : vsession->name, req_idx);
704 0 : vhost_vq_used_ring_enqueue(vsession, vq, req_idx, 0);
705 0 : return;
706 : }
707 :
708 0 : vsession->task_cnt++;
709 0 : scsi_task_init(task);
710 :
711 0 : if (spdk_unlikely(vq->vring_idx == VIRTIO_SCSI_CONTROLQ)) {
712 0 : process_ctrl_request(task);
713 0 : } else {
714 0 : result = process_request(task);
715 0 : if (likely(result == 0)) {
716 0 : task_submit(task);
717 0 : SPDK_DEBUGLOG(vhost_scsi, "====== Task %p req_idx %d submitted ======\n", task,
718 : task->req_idx);
719 0 : } else if (result > 0) {
720 0 : vhost_scsi_task_cpl(&task->scsi);
721 0 : SPDK_DEBUGLOG(vhost_scsi, "====== Task %p req_idx %d finished early ======\n", task,
722 : task->req_idx);
723 0 : } else {
724 0 : invalid_request(task);
725 0 : SPDK_DEBUGLOG(vhost_scsi, "====== Task %p req_idx %d failed ======\n", task,
726 : task->req_idx);
727 : }
728 : }
729 0 : }
730 :
731 : static int
732 0 : submit_inflight_desc(struct spdk_vhost_scsi_session *svsession,
733 : struct spdk_vhost_virtqueue *vq)
734 : {
735 0 : struct spdk_vhost_session *vsession;
736 0 : spdk_vhost_resubmit_info *resubmit;
737 0 : spdk_vhost_resubmit_desc *resubmit_list;
738 0 : uint16_t req_idx;
739 0 : int i, resubmit_cnt;
740 :
741 0 : resubmit = vq->vring_inflight.resubmit_inflight;
742 0 : if (spdk_likely(resubmit == NULL || resubmit->resubmit_list == NULL ||
743 : resubmit->resubmit_num == 0)) {
744 0 : return 0;
745 : }
746 :
747 0 : resubmit_list = resubmit->resubmit_list;
748 0 : vsession = &svsession->vsession;
749 :
750 0 : for (i = resubmit->resubmit_num - 1; i >= 0; --i) {
751 0 : req_idx = resubmit_list[i].index;
752 0 : SPDK_DEBUGLOG(vhost_scsi, "====== Start processing resubmit request idx %"PRIu16"======\n",
753 : req_idx);
754 :
755 0 : if (spdk_unlikely(req_idx >= vq->vring.size)) {
756 0 : SPDK_ERRLOG("%s: request idx '%"PRIu16"' exceeds virtqueue size (%"PRIu16").\n",
757 : vsession->name, req_idx, vq->vring.size);
758 0 : vhost_vq_used_ring_enqueue(vsession, vq, req_idx, 0);
759 0 : continue;
760 : }
761 :
762 0 : process_scsi_task(vsession, vq, req_idx);
763 0 : }
764 0 : resubmit_cnt = resubmit->resubmit_num;
765 0 : resubmit->resubmit_num = 0;
766 0 : return resubmit_cnt;
767 0 : }
768 :
769 : static int
770 0 : process_vq(struct spdk_vhost_scsi_session *svsession, struct spdk_vhost_virtqueue *vq)
771 : {
772 0 : struct spdk_vhost_session *vsession = &svsession->vsession;
773 0 : uint16_t reqs[32];
774 0 : uint16_t reqs_cnt, i;
775 0 : int resubmit_cnt;
776 :
777 0 : resubmit_cnt = submit_inflight_desc(svsession, vq);
778 :
779 0 : reqs_cnt = vhost_vq_avail_ring_get(vq, reqs, SPDK_COUNTOF(reqs));
780 0 : assert(reqs_cnt <= 32);
781 :
782 0 : for (i = 0; i < reqs_cnt; i++) {
783 0 : SPDK_DEBUGLOG(vhost_scsi, "====== Starting processing request idx %"PRIu16"======\n",
784 : reqs[i]);
785 :
786 0 : if (spdk_unlikely(reqs[i] >= vq->vring.size)) {
787 0 : SPDK_ERRLOG("%s: request idx '%"PRIu16"' exceeds virtqueue size (%"PRIu16").\n",
788 : vsession->name, reqs[i], vq->vring.size);
789 0 : vhost_vq_used_ring_enqueue(vsession, vq, reqs[i], 0);
790 0 : continue;
791 : }
792 :
793 0 : rte_vhost_set_inflight_desc_split(vsession->vid, vq->vring_idx, reqs[i]);
794 :
795 0 : process_scsi_task(vsession, vq, reqs[i]);
796 0 : }
797 :
798 0 : return reqs_cnt > 0 ? reqs_cnt : resubmit_cnt;
799 0 : }
800 :
801 : static int
802 0 : vdev_mgmt_worker(void *arg)
803 : {
804 0 : struct spdk_vhost_scsi_session *svsession = arg;
805 0 : struct spdk_vhost_session *vsession = &svsession->vsession;
806 0 : int rc = 0;
807 :
808 0 : process_removed_devs(svsession);
809 :
810 0 : if (vsession->virtqueue[VIRTIO_SCSI_EVENTQ].vring.desc) {
811 0 : vhost_vq_used_signal(vsession, &vsession->virtqueue[VIRTIO_SCSI_EVENTQ]);
812 0 : }
813 :
814 0 : if (vsession->virtqueue[VIRTIO_SCSI_CONTROLQ].vring.desc) {
815 0 : rc = process_vq(svsession, &vsession->virtqueue[VIRTIO_SCSI_CONTROLQ]);
816 0 : vhost_vq_used_signal(vsession, &vsession->virtqueue[VIRTIO_SCSI_CONTROLQ]);
817 0 : }
818 :
819 0 : return rc > 0 ? SPDK_POLLER_BUSY : SPDK_POLLER_IDLE;
820 0 : }
821 :
822 : static int
823 0 : vdev_worker(void *arg)
824 : {
825 0 : struct spdk_vhost_scsi_session *svsession = arg;
826 0 : struct spdk_vhost_session *vsession = &svsession->vsession;
827 0 : uint32_t q_idx;
828 0 : int rc = 0;
829 :
830 0 : for (q_idx = VIRTIO_SCSI_REQUESTQ; q_idx < vsession->max_queues; q_idx++) {
831 0 : rc = process_vq(svsession, &vsession->virtqueue[q_idx]);
832 0 : vhost_session_vq_used_signal(&vsession->virtqueue[q_idx]);
833 0 : }
834 :
835 0 : return rc > 0 ? SPDK_POLLER_BUSY : SPDK_POLLER_IDLE;
836 0 : }
837 :
838 : static struct spdk_vhost_scsi_dev *
839 0 : to_scsi_dev(struct spdk_vhost_dev *ctrlr)
840 : {
841 0 : if (ctrlr == NULL) {
842 0 : return NULL;
843 : }
844 :
845 0 : if (ctrlr->backend->type != VHOST_BACKEND_SCSI) {
846 0 : SPDK_ERRLOG("%s: not a vhost-scsi device.\n", ctrlr->name);
847 0 : return NULL;
848 : }
849 :
850 0 : return SPDK_CONTAINEROF(ctrlr, struct spdk_vhost_scsi_dev, vdev);
851 0 : }
852 :
853 : static struct spdk_vhost_scsi_session *
854 0 : to_scsi_session(struct spdk_vhost_session *vsession)
855 : {
856 0 : assert(vsession->vdev->backend->type == VHOST_BACKEND_SCSI);
857 0 : return (struct spdk_vhost_scsi_session *)vsession;
858 : }
859 :
860 : int
861 0 : vhost_scsi_controller_start(const char *name)
862 : {
863 0 : struct spdk_vhost_dev *vdev;
864 0 : struct spdk_vhost_scsi_dev *svdev;
865 0 : int rc;
866 :
867 0 : spdk_vhost_lock();
868 0 : vdev = spdk_vhost_dev_find(name);
869 0 : if (vdev == NULL) {
870 0 : spdk_vhost_unlock();
871 0 : return -ENODEV;
872 : }
873 :
874 0 : svdev = to_scsi_dev(vdev);
875 0 : assert(svdev != NULL);
876 :
877 0 : if (svdev->registered == true) {
878 : /* already started, nothing to do */
879 0 : spdk_vhost_unlock();
880 0 : return 0;
881 : }
882 :
883 0 : rc = vhost_user_dev_start(vdev);
884 0 : if (rc != 0) {
885 0 : spdk_vhost_unlock();
886 0 : return rc;
887 : }
888 0 : svdev->registered = true;
889 :
890 0 : spdk_vhost_unlock();
891 0 : return 0;
892 0 : }
893 :
894 : static int
895 0 : vhost_scsi_dev_construct(const char *name, const char *cpumask, bool delay)
896 : {
897 0 : struct spdk_vhost_scsi_dev *svdev = calloc(1, sizeof(*svdev));
898 0 : int rc;
899 :
900 0 : if (svdev == NULL) {
901 0 : return -ENOMEM;
902 : }
903 :
904 0 : svdev->vdev.virtio_features = SPDK_VHOST_SCSI_FEATURES;
905 0 : svdev->vdev.disabled_features = SPDK_VHOST_SCSI_DISABLED_FEATURES;
906 0 : svdev->vdev.protocol_features = SPDK_VHOST_SCSI_PROTOCOL_FEATURES;
907 :
908 0 : rc = vhost_dev_register(&svdev->vdev, name, cpumask, NULL,
909 : &spdk_vhost_scsi_device_backend,
910 0 : &spdk_vhost_scsi_user_device_backend, delay);
911 0 : if (rc) {
912 0 : free(svdev);
913 0 : return rc;
914 : }
915 :
916 0 : if (delay == false) {
917 0 : svdev->registered = true;
918 0 : }
919 :
920 0 : return rc;
921 0 : }
922 :
923 : int
924 0 : spdk_vhost_scsi_dev_construct(const char *name, const char *cpumask)
925 : {
926 0 : return vhost_scsi_dev_construct(name, cpumask, false);
927 : }
928 :
929 : int
930 0 : spdk_vhost_scsi_dev_construct_no_start(const char *name, const char *cpumask)
931 : {
932 0 : return vhost_scsi_dev_construct(name, cpumask, true);
933 : }
934 :
935 : static int
936 0 : vhost_scsi_dev_remove(struct spdk_vhost_dev *vdev)
937 : {
938 0 : struct spdk_vhost_scsi_dev *svdev = to_scsi_dev(vdev);
939 0 : int rc = 0, i;
940 :
941 0 : assert(svdev != NULL);
942 0 : for (i = 0; i < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS; ++i) {
943 0 : if (svdev->scsi_dev_state[i].dev) {
944 0 : rc = spdk_vhost_scsi_dev_remove_tgt(vdev, i, NULL, NULL);
945 0 : if (rc != 0) {
946 0 : SPDK_ERRLOG("%s: failed to force-remove target %d\n", vdev->name, i);
947 0 : return rc;
948 : }
949 0 : }
950 0 : }
951 :
952 0 : svdev->registered = false;
953 :
954 0 : if (svdev->ref == 0) {
955 0 : rc = vhost_dev_unregister(vdev);
956 0 : if (rc != 0) {
957 0 : return rc;
958 : }
959 0 : free(svdev);
960 0 : }
961 :
962 0 : return rc;
963 0 : }
964 :
965 : struct spdk_scsi_dev *
966 0 : spdk_vhost_scsi_dev_get_tgt(struct spdk_vhost_dev *vdev, uint8_t num)
967 : {
968 0 : struct spdk_vhost_scsi_dev *svdev;
969 :
970 0 : assert(num < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS);
971 0 : svdev = to_scsi_dev(vdev);
972 0 : assert(svdev != NULL);
973 0 : if (svdev->scsi_dev_state[num].status != VHOST_SCSI_DEV_PRESENT) {
974 0 : return NULL;
975 : }
976 :
977 0 : assert(svdev->scsi_dev_state[num].dev != NULL);
978 0 : return svdev->scsi_dev_state[num].dev;
979 0 : }
980 :
981 : static unsigned
982 0 : get_scsi_dev_num(const struct spdk_vhost_scsi_dev *svdev,
983 : const struct spdk_scsi_lun *lun)
984 : {
985 0 : const struct spdk_scsi_dev *scsi_dev;
986 0 : unsigned scsi_dev_num;
987 :
988 0 : assert(lun != NULL);
989 0 : assert(svdev != NULL);
990 0 : scsi_dev = spdk_scsi_lun_get_dev(lun);
991 0 : for (scsi_dev_num = 0; scsi_dev_num < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS; scsi_dev_num++) {
992 0 : if (svdev->scsi_dev_state[scsi_dev_num].dev == scsi_dev) {
993 0 : break;
994 : }
995 0 : }
996 :
997 0 : return scsi_dev_num;
998 0 : }
999 :
1000 : static void
1001 0 : vhost_scsi_lun_resize(const struct spdk_scsi_lun *lun, void *arg)
1002 : {
1003 0 : struct spdk_vhost_scsi_dev *svdev = arg;
1004 0 : unsigned scsi_dev_num;
1005 :
1006 0 : scsi_dev_num = get_scsi_dev_num(svdev, lun);
1007 0 : if (scsi_dev_num == SPDK_VHOST_SCSI_CTRLR_MAX_DEVS) {
1008 : /* The entire device has been already removed. */
1009 0 : return;
1010 : }
1011 :
1012 0 : vhost_scsi_dev_param_changed(&svdev->vdev, scsi_dev_num);
1013 0 : }
1014 :
1015 : static void
1016 0 : vhost_scsi_lun_hotremove(const struct spdk_scsi_lun *lun, void *arg)
1017 : {
1018 0 : struct spdk_vhost_scsi_dev *svdev = arg;
1019 0 : unsigned scsi_dev_num;
1020 :
1021 0 : scsi_dev_num = get_scsi_dev_num(svdev, lun);
1022 0 : if (scsi_dev_num == SPDK_VHOST_SCSI_CTRLR_MAX_DEVS) {
1023 : /* The entire device has been already removed. */
1024 0 : return;
1025 : }
1026 :
1027 : /* remove entire device */
1028 0 : spdk_vhost_scsi_dev_remove_tgt(&svdev->vdev, scsi_dev_num, NULL, NULL);
1029 0 : }
1030 :
1031 : static void
1032 0 : vhost_scsi_dev_add_tgt_cpl_cb(struct spdk_vhost_dev *vdev, void *ctx)
1033 : {
1034 0 : unsigned scsi_tgt_num = (unsigned)(uintptr_t)ctx;
1035 0 : struct spdk_vhost_scsi_dev *svdev = SPDK_CONTAINEROF(vdev,
1036 : struct spdk_vhost_scsi_dev, vdev);
1037 0 : struct spdk_scsi_dev_vhost_state *vhost_sdev;
1038 :
1039 0 : vhost_sdev = &svdev->scsi_dev_state[scsi_tgt_num];
1040 :
1041 : /* All sessions have added the target */
1042 0 : assert(vhost_sdev->status == VHOST_SCSI_DEV_ADDING);
1043 0 : vhost_sdev->status = VHOST_SCSI_DEV_PRESENT;
1044 0 : svdev->ref++;
1045 0 : }
1046 :
1047 : static int
1048 0 : vhost_scsi_session_add_tgt(struct spdk_vhost_dev *vdev,
1049 : struct spdk_vhost_session *vsession, void *ctx)
1050 : {
1051 0 : unsigned scsi_tgt_num = (unsigned)(uintptr_t)ctx;
1052 0 : struct spdk_vhost_scsi_session *svsession = (struct spdk_vhost_scsi_session *)vsession;
1053 0 : struct spdk_scsi_dev_session_state *session_sdev = &svsession->scsi_dev_state[scsi_tgt_num];
1054 0 : struct spdk_scsi_dev_vhost_state *vhost_sdev;
1055 0 : int rc;
1056 :
1057 0 : if (!vsession->started || session_sdev->dev != NULL) {
1058 : /* Nothing to do. */
1059 0 : return 0;
1060 : }
1061 :
1062 0 : vhost_sdev = &svsession->svdev->scsi_dev_state[scsi_tgt_num];
1063 0 : session_sdev->dev = vhost_sdev->dev;
1064 0 : session_sdev->status = VHOST_SCSI_DEV_PRESENT;
1065 :
1066 0 : rc = spdk_scsi_dev_allocate_io_channels(svsession->scsi_dev_state[scsi_tgt_num].dev);
1067 0 : if (rc != 0) {
1068 0 : SPDK_ERRLOG("%s: Couldn't allocate io channel for SCSI target %u.\n",
1069 : vsession->name, scsi_tgt_num);
1070 :
1071 : /* unset the SCSI target so that all I/O to it will be rejected */
1072 0 : session_sdev->dev = NULL;
1073 : /* Set status to EMPTY so that we won't reply with SCSI hotremove
1074 : * sense codes - the device hasn't ever been added.
1075 : */
1076 0 : session_sdev->status = VHOST_SCSI_DEV_EMPTY;
1077 :
1078 : /* Return with no error. We'll continue allocating io_channels for
1079 : * other sessions on this device in hopes they succeed. The sessions
1080 : * that failed to allocate io_channels simply won't be able to
1081 : * detect the SCSI target, nor do any I/O to it.
1082 : */
1083 0 : return 0;
1084 : }
1085 :
1086 0 : if (vhost_dev_has_feature(vsession, VIRTIO_SCSI_F_HOTPLUG)) {
1087 0 : eventq_enqueue(svsession, scsi_tgt_num,
1088 : VIRTIO_SCSI_T_TRANSPORT_RESET, VIRTIO_SCSI_EVT_RESET_RESCAN);
1089 0 : } else {
1090 0 : SPDK_NOTICELOG("%s: driver does not support hotplug. "
1091 : "Please restart it or perform a rescan.\n",
1092 : vsession->name);
1093 : }
1094 :
1095 0 : return 0;
1096 0 : }
1097 :
1098 : int
1099 0 : spdk_vhost_scsi_dev_add_tgt(struct spdk_vhost_dev *vdev, int scsi_tgt_num,
1100 : const char *bdev_name)
1101 : {
1102 0 : struct spdk_vhost_scsi_dev *svdev;
1103 0 : struct spdk_scsi_dev_vhost_state *state;
1104 0 : char target_name[SPDK_SCSI_DEV_MAX_NAME];
1105 0 : int lun_id_list[1];
1106 0 : const char *bdev_names_list[1];
1107 :
1108 0 : svdev = to_scsi_dev(vdev);
1109 0 : if (!svdev) {
1110 0 : SPDK_ERRLOG("Before adding a SCSI target, there should be a SCSI device.");
1111 0 : return -EINVAL;
1112 : }
1113 :
1114 0 : if (scsi_tgt_num < 0) {
1115 0 : for (scsi_tgt_num = 0; scsi_tgt_num < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS; scsi_tgt_num++) {
1116 0 : if (svdev->scsi_dev_state[scsi_tgt_num].dev == NULL) {
1117 0 : break;
1118 : }
1119 0 : }
1120 :
1121 0 : if (scsi_tgt_num == SPDK_VHOST_SCSI_CTRLR_MAX_DEVS) {
1122 0 : SPDK_ERRLOG("%s: all SCSI target slots are already in use.\n", vdev->name);
1123 0 : return -ENOSPC;
1124 : }
1125 0 : } else {
1126 0 : if (scsi_tgt_num >= SPDK_VHOST_SCSI_CTRLR_MAX_DEVS) {
1127 0 : SPDK_ERRLOG("%s: SCSI target number is too big (got %d, max %d), started from 0.\n",
1128 : vdev->name, scsi_tgt_num, SPDK_VHOST_SCSI_CTRLR_MAX_DEVS - 1);
1129 0 : return -EINVAL;
1130 : }
1131 : }
1132 :
1133 0 : if (bdev_name == NULL) {
1134 0 : SPDK_ERRLOG("No lun name specified\n");
1135 0 : return -EINVAL;
1136 : }
1137 :
1138 0 : state = &svdev->scsi_dev_state[scsi_tgt_num];
1139 0 : if (state->dev != NULL) {
1140 0 : SPDK_ERRLOG("%s: SCSI target %u already occupied\n", vdev->name, scsi_tgt_num);
1141 0 : return -EEXIST;
1142 : }
1143 :
1144 : /*
1145 : * At this stage only one LUN per target
1146 : */
1147 0 : snprintf(target_name, sizeof(target_name), "Target %u", scsi_tgt_num);
1148 0 : lun_id_list[0] = 0;
1149 0 : bdev_names_list[0] = (char *)bdev_name;
1150 :
1151 0 : state->status = VHOST_SCSI_DEV_ADDING;
1152 0 : state->dev = spdk_scsi_dev_construct_ext(target_name, bdev_names_list, lun_id_list, 1,
1153 : SPDK_SPC_PROTOCOL_IDENTIFIER_SAS,
1154 0 : vhost_scsi_lun_resize, svdev,
1155 0 : vhost_scsi_lun_hotremove, svdev);
1156 :
1157 0 : if (state->dev == NULL) {
1158 0 : state->status = VHOST_SCSI_DEV_EMPTY;
1159 0 : SPDK_ERRLOG("%s: couldn't create SCSI target %u using bdev '%s'\n",
1160 : vdev->name, scsi_tgt_num, bdev_name);
1161 0 : return -EINVAL;
1162 : }
1163 0 : spdk_scsi_dev_add_port(state->dev, 0, "vhost");
1164 :
1165 0 : SPDK_INFOLOG(vhost, "%s: added SCSI target %u using bdev '%s'\n",
1166 : vdev->name, scsi_tgt_num, bdev_name);
1167 :
1168 0 : if (svdev->registered) {
1169 0 : vhost_user_dev_foreach_session(vdev, vhost_scsi_session_add_tgt,
1170 : vhost_scsi_dev_add_tgt_cpl_cb,
1171 0 : (void *)(uintptr_t)scsi_tgt_num);
1172 0 : } else {
1173 0 : state->status = VHOST_SCSI_DEV_PRESENT;
1174 0 : svdev->ref++;
1175 : }
1176 :
1177 0 : return scsi_tgt_num;
1178 0 : }
1179 :
1180 : struct scsi_tgt_hotplug_ctx {
1181 : unsigned scsi_tgt_num;
1182 : bool async_fini;
1183 : };
1184 :
1185 : static void
1186 0 : vhost_scsi_dev_remove_tgt_cpl_cb(struct spdk_vhost_dev *vdev, void *_ctx)
1187 : {
1188 0 : struct scsi_tgt_hotplug_ctx *ctx = _ctx;
1189 0 : struct spdk_vhost_scsi_dev *svdev = SPDK_CONTAINEROF(vdev,
1190 : struct spdk_vhost_scsi_dev, vdev);
1191 :
1192 0 : if (!ctx->async_fini) {
1193 : /* there aren't any active sessions, so remove the dev and exit */
1194 0 : remove_scsi_tgt(svdev, ctx->scsi_tgt_num);
1195 0 : }
1196 :
1197 0 : free(ctx);
1198 0 : }
1199 :
1200 : static int
1201 0 : vhost_scsi_session_remove_tgt(struct spdk_vhost_dev *vdev,
1202 : struct spdk_vhost_session *vsession, void *_ctx)
1203 : {
1204 0 : struct scsi_tgt_hotplug_ctx *ctx = _ctx;
1205 0 : unsigned scsi_tgt_num = ctx->scsi_tgt_num;
1206 0 : struct spdk_vhost_scsi_session *svsession = (struct spdk_vhost_scsi_session *)vsession;
1207 0 : struct spdk_scsi_dev_session_state *state = &svsession->scsi_dev_state[scsi_tgt_num];
1208 :
1209 0 : if (!vsession->started || state->dev == NULL) {
1210 : /* Nothing to do */
1211 0 : return 0;
1212 : }
1213 :
1214 : /* Mark the target for removal */
1215 0 : assert(state->status == VHOST_SCSI_DEV_PRESENT);
1216 0 : state->status = VHOST_SCSI_DEV_REMOVING;
1217 :
1218 : /* Send a hotremove virtio event */
1219 0 : if (vhost_dev_has_feature(vsession, VIRTIO_SCSI_F_HOTPLUG)) {
1220 0 : eventq_enqueue(svsession, scsi_tgt_num,
1221 : VIRTIO_SCSI_T_TRANSPORT_RESET, VIRTIO_SCSI_EVT_RESET_REMOVED);
1222 0 : }
1223 :
1224 : /* Wait for the session's management poller to remove the target after
1225 : * all its pending I/O has finished.
1226 : */
1227 0 : ctx->async_fini = true;
1228 0 : return 0;
1229 0 : }
1230 :
1231 : int
1232 0 : spdk_vhost_scsi_dev_remove_tgt(struct spdk_vhost_dev *vdev, unsigned scsi_tgt_num,
1233 : spdk_vhost_event_fn cb_fn, void *cb_arg)
1234 : {
1235 0 : struct spdk_vhost_scsi_dev *svdev;
1236 0 : struct spdk_scsi_dev_vhost_state *scsi_dev_state;
1237 0 : struct scsi_tgt_hotplug_ctx *ctx;
1238 :
1239 0 : if (scsi_tgt_num >= SPDK_VHOST_SCSI_CTRLR_MAX_DEVS) {
1240 0 : SPDK_ERRLOG("%s: invalid SCSI target number %d\n", vdev->name, scsi_tgt_num);
1241 0 : return -EINVAL;
1242 : }
1243 :
1244 0 : svdev = to_scsi_dev(vdev);
1245 0 : if (!svdev) {
1246 0 : SPDK_ERRLOG("An invalid SCSI device that removing from a SCSI target.");
1247 0 : return -EINVAL;
1248 : }
1249 :
1250 0 : scsi_dev_state = &svdev->scsi_dev_state[scsi_tgt_num];
1251 :
1252 0 : if (scsi_dev_state->status != VHOST_SCSI_DEV_PRESENT) {
1253 0 : return -EBUSY;
1254 : }
1255 :
1256 0 : if (scsi_dev_state->dev == NULL || scsi_dev_state->status == VHOST_SCSI_DEV_ADDING) {
1257 0 : SPDK_ERRLOG("%s: SCSI target %u is not occupied\n", vdev->name, scsi_tgt_num);
1258 0 : return -ENODEV;
1259 : }
1260 :
1261 0 : assert(scsi_dev_state->status != VHOST_SCSI_DEV_EMPTY);
1262 0 : ctx = calloc(1, sizeof(*ctx));
1263 0 : if (ctx == NULL) {
1264 0 : SPDK_ERRLOG("calloc failed\n");
1265 0 : return -ENOMEM;
1266 : }
1267 :
1268 0 : ctx->scsi_tgt_num = scsi_tgt_num;
1269 0 : ctx->async_fini = false;
1270 :
1271 0 : scsi_dev_state->remove_cb = cb_fn;
1272 0 : scsi_dev_state->remove_ctx = cb_arg;
1273 0 : scsi_dev_state->status = VHOST_SCSI_DEV_REMOVING;
1274 :
1275 0 : vhost_user_dev_foreach_session(vdev, vhost_scsi_session_remove_tgt,
1276 0 : vhost_scsi_dev_remove_tgt_cpl_cb, ctx);
1277 0 : return 0;
1278 0 : }
1279 :
1280 : static int
1281 0 : vhost_scsi_session_param_changed(struct spdk_vhost_dev *vdev,
1282 : struct spdk_vhost_session *vsession, void *ctx)
1283 : {
1284 0 : unsigned scsi_tgt_num = (unsigned)(uintptr_t)ctx;
1285 0 : struct spdk_vhost_scsi_session *svsession = (struct spdk_vhost_scsi_session *)vsession;
1286 0 : struct spdk_scsi_dev_session_state *state = &svsession->scsi_dev_state[scsi_tgt_num];
1287 :
1288 0 : if (!vsession->started || state->dev == NULL) {
1289 : /* Nothing to do */
1290 0 : return 0;
1291 : }
1292 :
1293 : /* Send a parameter change virtio event */
1294 0 : if (vhost_dev_has_feature(vsession, VIRTIO_SCSI_F_CHANGE)) {
1295 : /*
1296 : * virtio 1.0 spec says:
1297 : * By sending this event, the device signals a change in the configuration
1298 : * parameters of a logical unit, for example the capacity or cache mode.
1299 : * event is set to VIRTIO_SCSI_T_PARAM_CHANGE. lun addresses a logical unit
1300 : * in the SCSI host. The same event SHOULD also be reported as a unit
1301 : * attention condition. reason contains the additional sense code and
1302 : * additional sense code qualifier, respectively in bits 0…7 and 8…15.
1303 : * Note: For example, a change in * capacity will be reported as asc
1304 : * 0x2a, ascq 0x09 (CAPACITY DATA HAS CHANGED).
1305 : */
1306 0 : eventq_enqueue(svsession, scsi_tgt_num, VIRTIO_SCSI_T_PARAM_CHANGE, 0x2a | (0x09 << 8));
1307 0 : }
1308 :
1309 0 : return 0;
1310 0 : }
1311 :
1312 : static int
1313 0 : vhost_scsi_dev_param_changed(struct spdk_vhost_dev *vdev, unsigned scsi_tgt_num)
1314 : {
1315 0 : struct spdk_vhost_scsi_dev *svdev;
1316 0 : struct spdk_scsi_dev_vhost_state *scsi_dev_state;
1317 :
1318 0 : if (scsi_tgt_num >= SPDK_VHOST_SCSI_CTRLR_MAX_DEVS) {
1319 0 : SPDK_ERRLOG("%s: invalid SCSI target number %d\n", vdev->name, scsi_tgt_num);
1320 0 : return -EINVAL;
1321 : }
1322 :
1323 0 : svdev = to_scsi_dev(vdev);
1324 0 : if (!svdev) {
1325 0 : SPDK_ERRLOG("An invalid SCSI device that removing from a SCSI target.");
1326 0 : return -EINVAL;
1327 : }
1328 :
1329 0 : scsi_dev_state = &svdev->scsi_dev_state[scsi_tgt_num];
1330 :
1331 0 : if (scsi_dev_state->status != VHOST_SCSI_DEV_PRESENT) {
1332 0 : return -EBUSY;
1333 : }
1334 :
1335 0 : if (scsi_dev_state->dev == NULL || scsi_dev_state->status == VHOST_SCSI_DEV_ADDING) {
1336 0 : SPDK_ERRLOG("%s: SCSI target %u is not occupied\n", vdev->name, scsi_tgt_num);
1337 0 : return -ENODEV;
1338 : }
1339 :
1340 0 : assert(scsi_dev_state->status != VHOST_SCSI_DEV_EMPTY);
1341 :
1342 0 : vhost_user_dev_foreach_session(vdev, vhost_scsi_session_param_changed,
1343 0 : NULL, (void *)(uintptr_t)scsi_tgt_num);
1344 0 : return 0;
1345 0 : }
1346 :
1347 : static void
1348 0 : free_task_pool(struct spdk_vhost_scsi_session *svsession)
1349 : {
1350 0 : struct spdk_vhost_session *vsession = &svsession->vsession;
1351 0 : struct spdk_vhost_virtqueue *vq;
1352 0 : uint16_t i;
1353 :
1354 0 : for (i = 0; i < vsession->max_queues; i++) {
1355 0 : vq = &vsession->virtqueue[i];
1356 0 : if (vq->tasks == NULL) {
1357 0 : continue;
1358 : }
1359 :
1360 0 : spdk_free(vq->tasks);
1361 0 : vq->tasks = NULL;
1362 0 : }
1363 0 : }
1364 :
1365 : static int
1366 0 : alloc_vq_task_pool(struct spdk_vhost_session *vsession, uint16_t qid)
1367 : {
1368 0 : struct spdk_vhost_scsi_session *svsession = to_scsi_session(vsession);
1369 0 : struct spdk_vhost_virtqueue *vq;
1370 0 : struct spdk_vhost_scsi_task *task;
1371 0 : uint32_t task_cnt;
1372 0 : uint32_t j;
1373 :
1374 0 : if (qid >= SPDK_VHOST_MAX_VQUEUES) {
1375 0 : return -EINVAL;
1376 : }
1377 :
1378 0 : vq = &vsession->virtqueue[qid];
1379 0 : if (vq->vring.desc == NULL) {
1380 0 : return 0;
1381 : }
1382 :
1383 0 : task_cnt = vq->vring.size;
1384 0 : if (task_cnt > SPDK_VHOST_MAX_VQ_SIZE) {
1385 : /* sanity check */
1386 0 : SPDK_ERRLOG("%s: virtqueue %"PRIu16" is too big. (size = %"PRIu32", max = %"PRIu32")\n",
1387 : vsession->name, qid, task_cnt, SPDK_VHOST_MAX_VQ_SIZE);
1388 0 : return -1;
1389 : }
1390 0 : vq->tasks = spdk_zmalloc(sizeof(struct spdk_vhost_scsi_task) * task_cnt,
1391 : SPDK_CACHE_LINE_SIZE, NULL,
1392 : SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
1393 0 : if (vq->tasks == NULL) {
1394 0 : SPDK_ERRLOG("%s: failed to allocate %"PRIu32" tasks for virtqueue %"PRIu16"\n",
1395 : vsession->name, task_cnt, qid);
1396 0 : return -1;
1397 : }
1398 :
1399 0 : for (j = 0; j < task_cnt; j++) {
1400 0 : task = &((struct spdk_vhost_scsi_task *)vq->tasks)[j];
1401 0 : task->svsession = svsession;
1402 0 : task->vq = vq;
1403 0 : task->req_idx = j;
1404 0 : }
1405 :
1406 0 : return 0;
1407 0 : }
1408 :
1409 : static int
1410 0 : vhost_scsi_start(struct spdk_vhost_dev *vdev,
1411 : struct spdk_vhost_session *vsession, void *unused)
1412 : {
1413 0 : struct spdk_vhost_scsi_session *svsession = to_scsi_session(vsession);
1414 0 : struct spdk_vhost_scsi_dev *svdev;
1415 0 : struct spdk_scsi_dev_vhost_state *state;
1416 0 : uint32_t i;
1417 0 : int rc;
1418 :
1419 : /* return if start is already in progress */
1420 0 : if (svsession->requestq_poller) {
1421 0 : SPDK_INFOLOG(vhost, "%s: start in progress\n", vsession->name);
1422 0 : return -EINPROGRESS;
1423 : }
1424 :
1425 : /* validate all I/O queues are in a contiguous index range */
1426 0 : if (vsession->max_queues < VIRTIO_SCSI_REQUESTQ + 1) {
1427 0 : SPDK_INFOLOG(vhost, "%s: max_queues %u, no I/O queues\n", vsession->name, vsession->max_queues);
1428 0 : return -1;
1429 : }
1430 0 : for (i = VIRTIO_SCSI_REQUESTQ; i < vsession->max_queues; i++) {
1431 0 : if (vsession->virtqueue[i].vring.desc == NULL) {
1432 0 : SPDK_ERRLOG("%s: queue %"PRIu32" is empty\n", vsession->name, i);
1433 0 : return -1;
1434 : }
1435 0 : }
1436 :
1437 0 : svdev = to_scsi_dev(vsession->vdev);
1438 0 : assert(svdev != NULL);
1439 0 : svsession->svdev = svdev;
1440 :
1441 0 : for (i = 0; i < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS; i++) {
1442 0 : state = &svdev->scsi_dev_state[i];
1443 0 : if (state->dev == NULL || state->status == VHOST_SCSI_DEV_REMOVING) {
1444 0 : continue;
1445 : }
1446 :
1447 0 : assert(svsession->scsi_dev_state[i].status == VHOST_SCSI_DEV_EMPTY);
1448 0 : svsession->scsi_dev_state[i].dev = state->dev;
1449 0 : svsession->scsi_dev_state[i].status = VHOST_SCSI_DEV_PRESENT;
1450 0 : rc = spdk_scsi_dev_allocate_io_channels(state->dev);
1451 0 : if (rc != 0) {
1452 0 : SPDK_ERRLOG("%s: failed to alloc io_channel for SCSI target %"PRIu32"\n",
1453 : vsession->name, i);
1454 : /* unset the SCSI target so that all I/O to it will be rejected */
1455 0 : svsession->scsi_dev_state[i].dev = NULL;
1456 : /* set EMPTY state so that we won't reply with SCSI hotremove
1457 : * sense codes - the device hasn't ever been added.
1458 : */
1459 0 : svsession->scsi_dev_state[i].status = VHOST_SCSI_DEV_EMPTY;
1460 0 : continue;
1461 : }
1462 0 : }
1463 0 : SPDK_INFOLOG(vhost, "%s: started poller on lcore %d\n",
1464 : vsession->name, spdk_env_get_current_core());
1465 :
1466 0 : svsession->requestq_poller = SPDK_POLLER_REGISTER(vdev_worker, svsession, 0);
1467 0 : svsession->mgmt_poller = SPDK_POLLER_REGISTER(vdev_mgmt_worker, svsession,
1468 : MGMT_POLL_PERIOD_US);
1469 0 : return 0;
1470 0 : }
1471 :
1472 : static int
1473 0 : destroy_session_poller_cb(void *arg)
1474 : {
1475 0 : struct spdk_vhost_scsi_session *svsession = arg;
1476 0 : struct spdk_vhost_session *vsession = &svsession->vsession;
1477 0 : struct spdk_vhost_user_dev *user_dev = to_user_dev(vsession->vdev);
1478 0 : struct spdk_scsi_dev_session_state *state;
1479 0 : uint32_t i;
1480 :
1481 0 : if (vsession->task_cnt > 0 || (pthread_mutex_trylock(&user_dev->lock) != 0)) {
1482 0 : assert(vsession->stop_retry_count > 0);
1483 0 : vsession->stop_retry_count--;
1484 0 : if (vsession->stop_retry_count == 0) {
1485 0 : SPDK_ERRLOG("%s: Timedout when destroy session (task_cnt %d)\n", vsession->name,
1486 : vsession->task_cnt);
1487 0 : spdk_poller_unregister(&svsession->stop_poller);
1488 0 : vhost_user_session_stop_done(vsession, -ETIMEDOUT);
1489 0 : }
1490 :
1491 0 : return SPDK_POLLER_BUSY;
1492 : }
1493 :
1494 0 : for (i = 0; i < vsession->max_queues; i++) {
1495 0 : vhost_vq_used_signal(vsession, &vsession->virtqueue[i]);
1496 0 : }
1497 :
1498 0 : for (i = 0; i < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS; i++) {
1499 0 : enum spdk_scsi_dev_vhost_status prev_status;
1500 :
1501 0 : state = &svsession->scsi_dev_state[i];
1502 : /* clear the REMOVED status so that we won't send hotremove events anymore */
1503 0 : prev_status = state->status;
1504 0 : state->status = VHOST_SCSI_DEV_EMPTY;
1505 0 : if (state->dev == NULL) {
1506 0 : continue;
1507 : }
1508 :
1509 0 : spdk_scsi_dev_free_io_channels(state->dev);
1510 :
1511 0 : state->dev = NULL;
1512 :
1513 0 : if (prev_status == VHOST_SCSI_DEV_REMOVING) {
1514 : /* try to detach it globally */
1515 0 : pthread_mutex_unlock(&user_dev->lock);
1516 0 : vhost_user_dev_foreach_session(vsession->vdev,
1517 : vhost_scsi_session_process_removed,
1518 : vhost_scsi_dev_process_removed_cpl_cb,
1519 0 : (void *)(uintptr_t)i);
1520 0 : pthread_mutex_lock(&user_dev->lock);
1521 0 : }
1522 0 : }
1523 :
1524 0 : SPDK_INFOLOG(vhost, "%s: stopping poller on lcore %d\n",
1525 : vsession->name, spdk_env_get_current_core());
1526 :
1527 0 : free_task_pool(svsession);
1528 :
1529 0 : spdk_poller_unregister(&svsession->stop_poller);
1530 0 : vhost_user_session_stop_done(vsession, 0);
1531 :
1532 0 : pthread_mutex_unlock(&user_dev->lock);
1533 0 : return SPDK_POLLER_BUSY;
1534 0 : }
1535 :
1536 : static int
1537 0 : vhost_scsi_stop(struct spdk_vhost_dev *vdev,
1538 : struct spdk_vhost_session *vsession, void *unused)
1539 : {
1540 0 : struct spdk_vhost_scsi_session *svsession = to_scsi_session(vsession);
1541 :
1542 : /* return if stop is already in progress */
1543 0 : if (svsession->stop_poller) {
1544 0 : return -EINPROGRESS;
1545 : }
1546 :
1547 : /* Stop receiving new I/O requests */
1548 0 : spdk_poller_unregister(&svsession->requestq_poller);
1549 :
1550 : /* Stop receiving controlq requests, also stop processing the
1551 : * asynchronous hotremove events. All the remaining events
1552 : * will be finalized by the stop_poller below.
1553 : */
1554 0 : spdk_poller_unregister(&svsession->mgmt_poller);
1555 :
1556 0 : svsession->vsession.stop_retry_count = (SPDK_VHOST_SESSION_STOP_RETRY_TIMEOUT_IN_SEC * 1000 *
1557 : 1000) / SPDK_VHOST_SESSION_STOP_RETRY_PERIOD_IN_US;
1558 :
1559 : /* Wait for all pending I/Os to complete, then process all the
1560 : * remaining hotremove events one last time.
1561 : */
1562 0 : svsession->stop_poller = SPDK_POLLER_REGISTER(destroy_session_poller_cb,
1563 : svsession, SPDK_VHOST_SESSION_STOP_RETRY_PERIOD_IN_US);
1564 :
1565 0 : return 0;
1566 0 : }
1567 :
1568 : static void
1569 0 : vhost_scsi_dump_info_json(struct spdk_vhost_dev *vdev, struct spdk_json_write_ctx *w)
1570 : {
1571 0 : struct spdk_scsi_dev *sdev;
1572 0 : struct spdk_scsi_lun *lun;
1573 0 : uint32_t dev_idx;
1574 :
1575 0 : assert(vdev != NULL);
1576 0 : spdk_json_write_named_array_begin(w, "scsi");
1577 0 : for (dev_idx = 0; dev_idx < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS; dev_idx++) {
1578 0 : sdev = spdk_vhost_scsi_dev_get_tgt(vdev, dev_idx);
1579 0 : if (!sdev) {
1580 0 : continue;
1581 : }
1582 :
1583 0 : spdk_json_write_object_begin(w);
1584 :
1585 0 : spdk_json_write_named_uint32(w, "scsi_dev_num", dev_idx);
1586 :
1587 0 : spdk_json_write_named_uint32(w, "id", spdk_scsi_dev_get_id(sdev));
1588 :
1589 0 : spdk_json_write_named_string(w, "target_name", spdk_scsi_dev_get_name(sdev));
1590 :
1591 0 : spdk_json_write_named_array_begin(w, "luns");
1592 :
1593 0 : for (lun = spdk_scsi_dev_get_first_lun(sdev); lun != NULL;
1594 0 : lun = spdk_scsi_dev_get_next_lun(lun)) {
1595 0 : spdk_json_write_object_begin(w);
1596 :
1597 0 : spdk_json_write_named_int32(w, "id", spdk_scsi_lun_get_id(lun));
1598 :
1599 0 : spdk_json_write_named_string(w, "bdev_name", spdk_scsi_lun_get_bdev_name(lun));
1600 :
1601 0 : spdk_json_write_object_end(w);
1602 0 : }
1603 :
1604 0 : spdk_json_write_array_end(w);
1605 0 : spdk_json_write_object_end(w);
1606 0 : }
1607 :
1608 0 : spdk_json_write_array_end(w);
1609 0 : }
1610 :
1611 : static void
1612 0 : vhost_scsi_write_config_json(struct spdk_vhost_dev *vdev, struct spdk_json_write_ctx *w)
1613 : {
1614 0 : struct spdk_scsi_dev *scsi_dev;
1615 0 : struct spdk_scsi_lun *lun;
1616 0 : uint32_t i;
1617 :
1618 0 : spdk_json_write_object_begin(w);
1619 0 : spdk_json_write_named_string(w, "method", "vhost_create_scsi_controller");
1620 :
1621 0 : spdk_json_write_named_object_begin(w, "params");
1622 0 : spdk_json_write_named_string(w, "ctrlr", vdev->name);
1623 0 : spdk_json_write_named_string(w, "cpumask",
1624 0 : spdk_cpuset_fmt(spdk_thread_get_cpumask(vdev->thread)));
1625 0 : spdk_json_write_named_bool(w, "delay", true);
1626 0 : spdk_json_write_object_end(w);
1627 :
1628 0 : spdk_json_write_object_end(w);
1629 :
1630 0 : for (i = 0; i < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS; i++) {
1631 0 : scsi_dev = spdk_vhost_scsi_dev_get_tgt(vdev, i);
1632 0 : if (scsi_dev == NULL) {
1633 0 : continue;
1634 : }
1635 :
1636 0 : lun = spdk_scsi_dev_get_lun(scsi_dev, 0);
1637 0 : assert(lun != NULL);
1638 :
1639 0 : spdk_json_write_object_begin(w);
1640 0 : spdk_json_write_named_string(w, "method", "vhost_scsi_controller_add_target");
1641 :
1642 0 : spdk_json_write_named_object_begin(w, "params");
1643 0 : spdk_json_write_named_string(w, "ctrlr", vdev->name);
1644 0 : spdk_json_write_named_uint32(w, "scsi_target_num", i);
1645 :
1646 0 : spdk_json_write_named_string(w, "bdev_name", spdk_scsi_lun_get_bdev_name(lun));
1647 0 : spdk_json_write_object_end(w);
1648 :
1649 0 : spdk_json_write_object_end(w);
1650 0 : }
1651 :
1652 0 : spdk_json_write_object_begin(w);
1653 0 : spdk_json_write_named_string(w, "method", "vhost_start_scsi_controller");
1654 :
1655 0 : spdk_json_write_named_object_begin(w, "params");
1656 0 : spdk_json_write_named_string(w, "ctrlr", vdev->name);
1657 0 : spdk_json_write_object_end(w);
1658 :
1659 0 : spdk_json_write_object_end(w);
1660 0 : }
1661 :
1662 0 : SPDK_LOG_REGISTER_COMPONENT(vhost_scsi)
1663 0 : SPDK_LOG_REGISTER_COMPONENT(vhost_scsi_queue)
1664 0 : SPDK_LOG_REGISTER_COMPONENT(vhost_scsi_data)
|