LCOV - code coverage report
Current view: top level - lib/vhost - vhost_scsi.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 0 733 0.0 %
Date: 2024-12-16 00:23:21 Functions: 0 53 0.0 %

          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             :         }
     181           0 : }
     182             : 
     183             : static void
     184           0 : remove_scsi_tgt(struct spdk_vhost_scsi_dev *svdev,
     185             :                 unsigned scsi_tgt_num)
     186             : {
     187             :         struct spdk_scsi_dev_vhost_state *state;
     188             :         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             :         }
     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             :         }
     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             : }
     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             : }
     245             : 
     246             : static void
     247           0 : process_removed_devs(struct spdk_vhost_scsi_session *svsession)
     248             : {
     249             :         struct spdk_scsi_dev *dev;
     250             :         struct spdk_scsi_dev_session_state *state;
     251             :         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             :                 }
     269             :         }
     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             :         struct spdk_vhost_virtqueue *vq;
     278             :         struct vring_desc *desc, *desc_table;
     279             :         struct virtio_scsi_event *desc_ev;
     280           0 :         uint32_t desc_table_size, req_size = 0;
     281             :         uint16_t req;
     282             :         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           0 : out:
     324           0 :         vhost_vq_used_ring_enqueue(vsession, vq, req, req_size);
     325             : }
     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             :                                    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             :         }
     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             :                                    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             :         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             : }
     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             :         struct vring_desc *desc, *desc_table;
     430             :         struct virtio_scsi_ctrl_tmf_req *ctrl_req;
     431             :         struct virtio_scsi_ctrl_an_resp *an_resp;
     432           0 :         uint32_t desc_table_size, used_len = 0;
     433             :         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           0 :         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           0 :                 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           0 :                 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           0 :         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           0 :         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           0 : out:
     517           0 :         vhost_vq_used_ring_enqueue(vsession, task->vq, task->req_idx, used_len);
     518           0 :         vhost_scsi_task_put(task);
     519             : }
     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             :         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             :         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             :         } 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           0 : 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             : }
     662             : 
     663             : static int
     664           0 : process_request(struct spdk_vhost_scsi_task *task)
     665             : {
     666             :         struct virtio_scsi_cmd_req *req;
     667             :         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             : }
     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             :         struct spdk_vhost_scsi_task *task;
     698             :         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             :         } 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             :                 } 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             : }
     730             : 
     731             : static int
     732           0 : submit_inflight_desc(struct spdk_vhost_scsi_session *svsession,
     733             :                      struct spdk_vhost_virtqueue *vq)
     734             : {
     735             :         struct spdk_vhost_session *vsession;
     736             :         spdk_vhost_resubmit_info *resubmit;
     737             :         spdk_vhost_resubmit_desc *resubmit_list;
     738             :         uint16_t req_idx;
     739             :         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             :         }
     764           0 :         resubmit_cnt = resubmit->resubmit_num;
     765           0 :         resubmit->resubmit_num = 0;
     766           0 :         return resubmit_cnt;
     767             : }
     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             :         uint16_t reqs[32];
     774             :         uint16_t reqs_cnt, i;
     775             :         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             :         }
     797             : 
     798           0 :         return reqs_cnt > 0 ? reqs_cnt : resubmit_cnt;
     799             : }
     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             :         }
     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             :         }
     818             : 
     819           0 :         return rc > 0 ? SPDK_POLLER_BUSY : SPDK_POLLER_IDLE;
     820             : }
     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             :         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             :         }
     834             : 
     835           0 :         return rc > 0 ? SPDK_POLLER_BUSY : SPDK_POLLER_IDLE;
     836             : }
     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             : }
     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             :         struct spdk_vhost_dev *vdev;
     864             :         struct spdk_vhost_scsi_dev *svdev;
     865             :         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             : }
     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             :         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             :                                 &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             :         }
     919             : 
     920           0 :         return rc;
     921             : }
     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             : 
     943           0 :         if (vhost_user_dev_busy(vdev)) {
     944           0 :                 return -EBUSY;
     945             :         }
     946             : 
     947           0 :         for (i = 0; i < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS; ++i) {
     948           0 :                 if (svdev->scsi_dev_state[i].dev) {
     949           0 :                         rc = spdk_vhost_scsi_dev_remove_tgt(vdev, i, NULL, NULL);
     950           0 :                         if (rc != 0) {
     951           0 :                                 SPDK_ERRLOG("%s: failed to force-remove target %d\n", vdev->name, i);
     952           0 :                                 return rc;
     953             :                         }
     954             :                 }
     955             :         }
     956             : 
     957           0 :         svdev->registered = false;
     958             : 
     959           0 :         if (svdev->ref == 0) {
     960           0 :                 rc = vhost_dev_unregister(vdev);
     961           0 :                 if (rc != 0) {
     962           0 :                         return rc;
     963             :                 }
     964           0 :                 free(svdev);
     965             :         }
     966             : 
     967           0 :         return rc;
     968             : }
     969             : 
     970             : struct spdk_scsi_dev *
     971           0 : spdk_vhost_scsi_dev_get_tgt(struct spdk_vhost_dev *vdev, uint8_t num)
     972             : {
     973             :         struct spdk_vhost_scsi_dev *svdev;
     974             : 
     975           0 :         assert(num < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS);
     976           0 :         svdev = to_scsi_dev(vdev);
     977           0 :         assert(svdev != NULL);
     978           0 :         if (svdev->scsi_dev_state[num].status != VHOST_SCSI_DEV_PRESENT) {
     979           0 :                 return NULL;
     980             :         }
     981             : 
     982           0 :         assert(svdev->scsi_dev_state[num].dev != NULL);
     983           0 :         return svdev->scsi_dev_state[num].dev;
     984             : }
     985             : 
     986             : static unsigned
     987           0 : get_scsi_dev_num(const struct spdk_vhost_scsi_dev *svdev,
     988             :                  const struct spdk_scsi_lun *lun)
     989             : {
     990             :         const struct spdk_scsi_dev *scsi_dev;
     991             :         unsigned scsi_dev_num;
     992             : 
     993           0 :         assert(lun != NULL);
     994           0 :         assert(svdev != NULL);
     995           0 :         scsi_dev = spdk_scsi_lun_get_dev(lun);
     996           0 :         for (scsi_dev_num = 0; scsi_dev_num < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS; scsi_dev_num++) {
     997           0 :                 if (svdev->scsi_dev_state[scsi_dev_num].dev == scsi_dev) {
     998           0 :                         break;
     999             :                 }
    1000             :         }
    1001             : 
    1002           0 :         return scsi_dev_num;
    1003             : }
    1004             : 
    1005             : static void
    1006           0 : vhost_scsi_lun_resize(const struct spdk_scsi_lun *lun, void *arg)
    1007             : {
    1008           0 :         struct spdk_vhost_scsi_dev *svdev = arg;
    1009             :         unsigned scsi_dev_num;
    1010             : 
    1011           0 :         scsi_dev_num = get_scsi_dev_num(svdev, lun);
    1012           0 :         if (scsi_dev_num == SPDK_VHOST_SCSI_CTRLR_MAX_DEVS) {
    1013             :                 /* The entire device has been already removed. */
    1014           0 :                 return;
    1015             :         }
    1016             : 
    1017           0 :         vhost_scsi_dev_param_changed(&svdev->vdev, scsi_dev_num);
    1018             : }
    1019             : 
    1020             : static void
    1021           0 : vhost_scsi_lun_hotremove(const struct spdk_scsi_lun *lun, void *arg)
    1022             : {
    1023           0 :         struct spdk_vhost_scsi_dev *svdev = arg;
    1024             :         unsigned scsi_dev_num;
    1025             : 
    1026           0 :         scsi_dev_num = get_scsi_dev_num(svdev, lun);
    1027           0 :         if (scsi_dev_num == SPDK_VHOST_SCSI_CTRLR_MAX_DEVS) {
    1028             :                 /* The entire device has been already removed. */
    1029           0 :                 return;
    1030             :         }
    1031             : 
    1032             :         /* remove entire device */
    1033           0 :         spdk_vhost_scsi_dev_remove_tgt(&svdev->vdev, scsi_dev_num, NULL, NULL);
    1034             : }
    1035             : 
    1036             : static void
    1037           0 : vhost_scsi_dev_add_tgt_cpl_cb(struct spdk_vhost_dev *vdev, void *ctx)
    1038             : {
    1039           0 :         unsigned scsi_tgt_num = (unsigned)(uintptr_t)ctx;
    1040           0 :         struct spdk_vhost_scsi_dev *svdev = SPDK_CONTAINEROF(vdev,
    1041             :                                             struct spdk_vhost_scsi_dev, vdev);
    1042             :         struct spdk_scsi_dev_vhost_state *vhost_sdev;
    1043             : 
    1044           0 :         vhost_sdev = &svdev->scsi_dev_state[scsi_tgt_num];
    1045             : 
    1046             :         /* All sessions have added the target */
    1047           0 :         assert(vhost_sdev->status == VHOST_SCSI_DEV_ADDING);
    1048           0 :         vhost_sdev->status = VHOST_SCSI_DEV_PRESENT;
    1049           0 :         svdev->ref++;
    1050           0 : }
    1051             : 
    1052             : static int
    1053           0 : vhost_scsi_session_add_tgt(struct spdk_vhost_dev *vdev,
    1054             :                            struct spdk_vhost_session *vsession, void *ctx)
    1055             : {
    1056           0 :         unsigned scsi_tgt_num = (unsigned)(uintptr_t)ctx;
    1057           0 :         struct spdk_vhost_scsi_session *svsession = (struct spdk_vhost_scsi_session *)vsession;
    1058           0 :         struct spdk_scsi_dev_session_state *session_sdev = &svsession->scsi_dev_state[scsi_tgt_num];
    1059             :         struct spdk_scsi_dev_vhost_state *vhost_sdev;
    1060             :         int rc;
    1061             : 
    1062           0 :         if (!vsession->started || session_sdev->dev != NULL) {
    1063             :                 /* Nothing to do. */
    1064           0 :                 return 0;
    1065             :         }
    1066             : 
    1067           0 :         vhost_sdev = &svsession->svdev->scsi_dev_state[scsi_tgt_num];
    1068           0 :         session_sdev->dev = vhost_sdev->dev;
    1069           0 :         session_sdev->status = VHOST_SCSI_DEV_PRESENT;
    1070             : 
    1071           0 :         rc = spdk_scsi_dev_allocate_io_channels(svsession->scsi_dev_state[scsi_tgt_num].dev);
    1072           0 :         if (rc != 0) {
    1073           0 :                 SPDK_ERRLOG("%s: Couldn't allocate io channel for SCSI target %u.\n",
    1074             :                             vsession->name, scsi_tgt_num);
    1075             : 
    1076             :                 /* unset the SCSI target so that all I/O to it will be rejected */
    1077           0 :                 session_sdev->dev = NULL;
    1078             :                 /* Set status to EMPTY so that we won't reply with SCSI hotremove
    1079             :                  * sense codes - the device hasn't ever been added.
    1080             :                  */
    1081           0 :                 session_sdev->status = VHOST_SCSI_DEV_EMPTY;
    1082             : 
    1083             :                 /* Return with no error. We'll continue allocating io_channels for
    1084             :                  * other sessions on this device in hopes they succeed. The sessions
    1085             :                  * that failed to allocate io_channels simply won't be able to
    1086             :                  * detect the SCSI target, nor do any I/O to it.
    1087             :                  */
    1088           0 :                 return 0;
    1089             :         }
    1090             : 
    1091           0 :         if (vhost_dev_has_feature(vsession, VIRTIO_SCSI_F_HOTPLUG)) {
    1092           0 :                 eventq_enqueue(svsession, scsi_tgt_num,
    1093             :                                VIRTIO_SCSI_T_TRANSPORT_RESET, VIRTIO_SCSI_EVT_RESET_RESCAN);
    1094             :         } else {
    1095           0 :                 SPDK_NOTICELOG("%s: driver does not support hotplug. "
    1096             :                                "Please restart it or perform a rescan.\n",
    1097             :                                vsession->name);
    1098             :         }
    1099             : 
    1100           0 :         return 0;
    1101             : }
    1102             : 
    1103             : int
    1104           0 : spdk_vhost_scsi_dev_add_tgt(struct spdk_vhost_dev *vdev, int scsi_tgt_num,
    1105             :                             const char *bdev_name)
    1106             : {
    1107             :         struct spdk_vhost_scsi_dev *svdev;
    1108             :         struct spdk_scsi_dev_vhost_state *state;
    1109             :         char target_name[SPDK_SCSI_DEV_MAX_NAME];
    1110             :         int lun_id_list[1];
    1111             :         const char *bdev_names_list[1];
    1112             : 
    1113           0 :         svdev = to_scsi_dev(vdev);
    1114           0 :         if (!svdev) {
    1115           0 :                 SPDK_ERRLOG("Before adding a SCSI target, there should be a SCSI device.");
    1116           0 :                 return -EINVAL;
    1117             :         }
    1118             : 
    1119           0 :         if (scsi_tgt_num < 0) {
    1120           0 :                 for (scsi_tgt_num = 0; scsi_tgt_num < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS; scsi_tgt_num++) {
    1121           0 :                         if (svdev->scsi_dev_state[scsi_tgt_num].dev == NULL) {
    1122           0 :                                 break;
    1123             :                         }
    1124             :                 }
    1125             : 
    1126           0 :                 if (scsi_tgt_num == SPDK_VHOST_SCSI_CTRLR_MAX_DEVS) {
    1127           0 :                         SPDK_ERRLOG("%s: all SCSI target slots are already in use.\n", vdev->name);
    1128           0 :                         return -ENOSPC;
    1129             :                 }
    1130             :         } else {
    1131           0 :                 if (scsi_tgt_num >= SPDK_VHOST_SCSI_CTRLR_MAX_DEVS) {
    1132           0 :                         SPDK_ERRLOG("%s: SCSI target number is too big (got %d, max %d), started from 0.\n",
    1133             :                                     vdev->name, scsi_tgt_num, SPDK_VHOST_SCSI_CTRLR_MAX_DEVS - 1);
    1134           0 :                         return -EINVAL;
    1135             :                 }
    1136             :         }
    1137             : 
    1138           0 :         if (bdev_name == NULL) {
    1139           0 :                 SPDK_ERRLOG("No lun name specified\n");
    1140           0 :                 return -EINVAL;
    1141             :         }
    1142             : 
    1143           0 :         state = &svdev->scsi_dev_state[scsi_tgt_num];
    1144           0 :         if (state->dev != NULL) {
    1145           0 :                 SPDK_ERRLOG("%s: SCSI target %u already occupied\n", vdev->name, scsi_tgt_num);
    1146           0 :                 return -EEXIST;
    1147             :         }
    1148             : 
    1149             :         /*
    1150             :          * At this stage only one LUN per target
    1151             :          */
    1152           0 :         snprintf(target_name, sizeof(target_name), "Target %u", scsi_tgt_num);
    1153           0 :         lun_id_list[0] = 0;
    1154           0 :         bdev_names_list[0] = (char *)bdev_name;
    1155             : 
    1156           0 :         state->status = VHOST_SCSI_DEV_ADDING;
    1157           0 :         state->dev = spdk_scsi_dev_construct_ext(target_name, bdev_names_list, lun_id_list, 1,
    1158             :                         SPDK_SPC_PROTOCOL_IDENTIFIER_SAS,
    1159             :                         vhost_scsi_lun_resize, svdev,
    1160             :                         vhost_scsi_lun_hotremove, svdev);
    1161             : 
    1162           0 :         if (state->dev == NULL) {
    1163           0 :                 state->status = VHOST_SCSI_DEV_EMPTY;
    1164           0 :                 SPDK_ERRLOG("%s: couldn't create SCSI target %u using bdev '%s'\n",
    1165             :                             vdev->name, scsi_tgt_num, bdev_name);
    1166           0 :                 return -EINVAL;
    1167             :         }
    1168           0 :         spdk_scsi_dev_add_port(state->dev, 0, "vhost");
    1169             : 
    1170           0 :         SPDK_INFOLOG(vhost, "%s: added SCSI target %u using bdev '%s'\n",
    1171             :                      vdev->name, scsi_tgt_num, bdev_name);
    1172             : 
    1173           0 :         if (svdev->registered) {
    1174           0 :                 vhost_user_dev_foreach_session(vdev, vhost_scsi_session_add_tgt,
    1175             :                                                vhost_scsi_dev_add_tgt_cpl_cb,
    1176           0 :                                                (void *)(uintptr_t)scsi_tgt_num);
    1177             :         } else {
    1178           0 :                 state->status = VHOST_SCSI_DEV_PRESENT;
    1179           0 :                 svdev->ref++;
    1180             :         }
    1181             : 
    1182           0 :         return scsi_tgt_num;
    1183             : }
    1184             : 
    1185             : struct scsi_tgt_hotplug_ctx {
    1186             :         unsigned scsi_tgt_num;
    1187             :         bool async_fini;
    1188             : };
    1189             : 
    1190             : static void
    1191           0 : vhost_scsi_dev_remove_tgt_cpl_cb(struct spdk_vhost_dev *vdev, void *_ctx)
    1192             : {
    1193           0 :         struct scsi_tgt_hotplug_ctx *ctx = _ctx;
    1194           0 :         struct spdk_vhost_scsi_dev *svdev = SPDK_CONTAINEROF(vdev,
    1195             :                                             struct spdk_vhost_scsi_dev, vdev);
    1196             : 
    1197           0 :         if (!ctx->async_fini) {
    1198             :                 /* there aren't any active sessions, so remove the dev and exit */
    1199           0 :                 remove_scsi_tgt(svdev, ctx->scsi_tgt_num);
    1200             :         }
    1201             : 
    1202           0 :         free(ctx);
    1203           0 : }
    1204             : 
    1205             : static int
    1206           0 : vhost_scsi_session_remove_tgt(struct spdk_vhost_dev *vdev,
    1207             :                               struct spdk_vhost_session *vsession, void *_ctx)
    1208             : {
    1209           0 :         struct scsi_tgt_hotplug_ctx *ctx = _ctx;
    1210           0 :         unsigned scsi_tgt_num = ctx->scsi_tgt_num;
    1211           0 :         struct spdk_vhost_scsi_session *svsession = (struct spdk_vhost_scsi_session *)vsession;
    1212           0 :         struct spdk_scsi_dev_session_state *state = &svsession->scsi_dev_state[scsi_tgt_num];
    1213             : 
    1214           0 :         if (!vsession->started || state->dev == NULL) {
    1215             :                 /* Nothing to do */
    1216           0 :                 return 0;
    1217             :         }
    1218             : 
    1219             :         /* Mark the target for removal */
    1220           0 :         assert(state->status == VHOST_SCSI_DEV_PRESENT);
    1221           0 :         state->status = VHOST_SCSI_DEV_REMOVING;
    1222             : 
    1223             :         /* Send a hotremove virtio event */
    1224           0 :         if (vhost_dev_has_feature(vsession, VIRTIO_SCSI_F_HOTPLUG)) {
    1225           0 :                 eventq_enqueue(svsession, scsi_tgt_num,
    1226             :                                VIRTIO_SCSI_T_TRANSPORT_RESET, VIRTIO_SCSI_EVT_RESET_REMOVED);
    1227             :         }
    1228             : 
    1229             :         /* Wait for the session's management poller to remove the target after
    1230             :          * all its pending I/O has finished.
    1231             :          */
    1232           0 :         ctx->async_fini = true;
    1233           0 :         return 0;
    1234             : }
    1235             : 
    1236             : int
    1237           0 : spdk_vhost_scsi_dev_remove_tgt(struct spdk_vhost_dev *vdev, unsigned scsi_tgt_num,
    1238             :                                spdk_vhost_event_fn cb_fn, void *cb_arg)
    1239             : {
    1240             :         struct spdk_vhost_scsi_dev *svdev;
    1241             :         struct spdk_scsi_dev_vhost_state *scsi_dev_state;
    1242             :         struct scsi_tgt_hotplug_ctx *ctx;
    1243             : 
    1244           0 :         if (scsi_tgt_num >= SPDK_VHOST_SCSI_CTRLR_MAX_DEVS) {
    1245           0 :                 SPDK_ERRLOG("%s: invalid SCSI target number %d\n", vdev->name, scsi_tgt_num);
    1246           0 :                 return -EINVAL;
    1247             :         }
    1248             : 
    1249           0 :         svdev = to_scsi_dev(vdev);
    1250           0 :         if (!svdev) {
    1251           0 :                 SPDK_ERRLOG("An invalid SCSI device that removing from a SCSI target.");
    1252           0 :                 return -EINVAL;
    1253             :         }
    1254             : 
    1255           0 :         scsi_dev_state = &svdev->scsi_dev_state[scsi_tgt_num];
    1256             : 
    1257           0 :         if (scsi_dev_state->status != VHOST_SCSI_DEV_PRESENT) {
    1258           0 :                 return -EBUSY;
    1259             :         }
    1260             : 
    1261           0 :         if (scsi_dev_state->dev == NULL || scsi_dev_state->status == VHOST_SCSI_DEV_ADDING) {
    1262           0 :                 SPDK_ERRLOG("%s: SCSI target %u is not occupied\n", vdev->name, scsi_tgt_num);
    1263           0 :                 return -ENODEV;
    1264             :         }
    1265             : 
    1266           0 :         assert(scsi_dev_state->status != VHOST_SCSI_DEV_EMPTY);
    1267           0 :         ctx = calloc(1, sizeof(*ctx));
    1268           0 :         if (ctx == NULL) {
    1269           0 :                 SPDK_ERRLOG("calloc failed\n");
    1270           0 :                 return -ENOMEM;
    1271             :         }
    1272             : 
    1273           0 :         ctx->scsi_tgt_num = scsi_tgt_num;
    1274           0 :         ctx->async_fini = false;
    1275             : 
    1276           0 :         scsi_dev_state->remove_cb = cb_fn;
    1277           0 :         scsi_dev_state->remove_ctx = cb_arg;
    1278           0 :         scsi_dev_state->status = VHOST_SCSI_DEV_REMOVING;
    1279             : 
    1280           0 :         vhost_user_dev_foreach_session(vdev, vhost_scsi_session_remove_tgt,
    1281             :                                        vhost_scsi_dev_remove_tgt_cpl_cb, ctx);
    1282           0 :         return 0;
    1283             : }
    1284             : 
    1285             : static int
    1286           0 : vhost_scsi_session_param_changed(struct spdk_vhost_dev *vdev,
    1287             :                                  struct spdk_vhost_session *vsession, void *ctx)
    1288             : {
    1289           0 :         unsigned scsi_tgt_num = (unsigned)(uintptr_t)ctx;
    1290           0 :         struct spdk_vhost_scsi_session *svsession = (struct spdk_vhost_scsi_session *)vsession;
    1291           0 :         struct spdk_scsi_dev_session_state *state = &svsession->scsi_dev_state[scsi_tgt_num];
    1292             : 
    1293           0 :         if (!vsession->started || state->dev == NULL) {
    1294             :                 /* Nothing to do */
    1295           0 :                 return 0;
    1296             :         }
    1297             : 
    1298             :         /* Send a parameter change virtio event */
    1299           0 :         if (vhost_dev_has_feature(vsession, VIRTIO_SCSI_F_CHANGE)) {
    1300             :                 /*
    1301             :                  * virtio 1.0 spec says:
    1302             :                  * By sending this event, the device signals a change in the configuration
    1303             :                  * parameters of a logical unit, for example the capacity or cache mode.
    1304             :                  * event is set to VIRTIO_SCSI_T_PARAM_CHANGE. lun addresses a logical unit
    1305             :                  * in the SCSI host. The same event SHOULD also be reported as a unit
    1306             :                  * attention condition. reason contains the additional sense code and
    1307             :                  * additional sense code qualifier, respectively in bits 0…7 and 8…15.
    1308             :                  * Note: For example, a change in * capacity will be reported as asc
    1309             :                  * 0x2a, ascq 0x09 (CAPACITY DATA HAS CHANGED).
    1310             :                  */
    1311           0 :                 eventq_enqueue(svsession, scsi_tgt_num, VIRTIO_SCSI_T_PARAM_CHANGE, 0x2a | (0x09 << 8));
    1312             :         }
    1313             : 
    1314           0 :         return 0;
    1315             : }
    1316             : 
    1317             : static int
    1318           0 : vhost_scsi_dev_param_changed(struct spdk_vhost_dev *vdev, unsigned scsi_tgt_num)
    1319             : {
    1320             :         struct spdk_vhost_scsi_dev *svdev;
    1321             :         struct spdk_scsi_dev_vhost_state *scsi_dev_state;
    1322             : 
    1323           0 :         if (scsi_tgt_num >= SPDK_VHOST_SCSI_CTRLR_MAX_DEVS) {
    1324           0 :                 SPDK_ERRLOG("%s: invalid SCSI target number %d\n", vdev->name, scsi_tgt_num);
    1325           0 :                 return -EINVAL;
    1326             :         }
    1327             : 
    1328           0 :         svdev = to_scsi_dev(vdev);
    1329           0 :         if (!svdev) {
    1330           0 :                 SPDK_ERRLOG("An invalid SCSI device that removing from a SCSI target.");
    1331           0 :                 return -EINVAL;
    1332             :         }
    1333             : 
    1334           0 :         scsi_dev_state = &svdev->scsi_dev_state[scsi_tgt_num];
    1335             : 
    1336           0 :         if (scsi_dev_state->status != VHOST_SCSI_DEV_PRESENT) {
    1337           0 :                 return -EBUSY;
    1338             :         }
    1339             : 
    1340           0 :         if (scsi_dev_state->dev == NULL || scsi_dev_state->status == VHOST_SCSI_DEV_ADDING) {
    1341           0 :                 SPDK_ERRLOG("%s: SCSI target %u is not occupied\n", vdev->name, scsi_tgt_num);
    1342           0 :                 return -ENODEV;
    1343             :         }
    1344             : 
    1345           0 :         assert(scsi_dev_state->status != VHOST_SCSI_DEV_EMPTY);
    1346             : 
    1347           0 :         vhost_user_dev_foreach_session(vdev, vhost_scsi_session_param_changed,
    1348           0 :                                        NULL, (void *)(uintptr_t)scsi_tgt_num);
    1349           0 :         return 0;
    1350             : }
    1351             : 
    1352             : static void
    1353           0 : free_task_pool(struct spdk_vhost_scsi_session *svsession)
    1354             : {
    1355           0 :         struct spdk_vhost_session *vsession = &svsession->vsession;
    1356             :         struct spdk_vhost_virtqueue *vq;
    1357             :         uint16_t i;
    1358             : 
    1359           0 :         for (i = 0; i < vsession->max_queues; i++) {
    1360           0 :                 vq = &vsession->virtqueue[i];
    1361           0 :                 if (vq->tasks == NULL) {
    1362           0 :                         continue;
    1363             :                 }
    1364             : 
    1365           0 :                 spdk_free(vq->tasks);
    1366           0 :                 vq->tasks = NULL;
    1367             :         }
    1368           0 : }
    1369             : 
    1370             : static int
    1371           0 : alloc_vq_task_pool(struct spdk_vhost_session *vsession, uint16_t qid)
    1372             : {
    1373           0 :         struct spdk_vhost_scsi_session *svsession = to_scsi_session(vsession);
    1374             :         struct spdk_vhost_virtqueue *vq;
    1375             :         struct spdk_vhost_scsi_task *task;
    1376             :         uint32_t task_cnt;
    1377             :         uint32_t j;
    1378             : 
    1379           0 :         if (qid >= SPDK_VHOST_MAX_VQUEUES) {
    1380           0 :                 return -EINVAL;
    1381             :         }
    1382             : 
    1383           0 :         vq = &vsession->virtqueue[qid];
    1384           0 :         if (vq->vring.desc == NULL) {
    1385           0 :                 return 0;
    1386             :         }
    1387             : 
    1388           0 :         task_cnt = vq->vring.size;
    1389           0 :         if (task_cnt > SPDK_VHOST_MAX_VQ_SIZE) {
    1390             :                 /* sanity check */
    1391           0 :                 SPDK_ERRLOG("%s: virtqueue %"PRIu16" is too big. (size = %"PRIu32", max = %"PRIu32")\n",
    1392             :                             vsession->name, qid, task_cnt, SPDK_VHOST_MAX_VQ_SIZE);
    1393           0 :                 return -1;
    1394             :         }
    1395           0 :         vq->tasks = spdk_zmalloc(sizeof(struct spdk_vhost_scsi_task) * task_cnt,
    1396             :                                  SPDK_CACHE_LINE_SIZE, NULL,
    1397             :                                  SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
    1398           0 :         if (vq->tasks == NULL) {
    1399           0 :                 SPDK_ERRLOG("%s: failed to allocate %"PRIu32" tasks for virtqueue %"PRIu16"\n",
    1400             :                             vsession->name, task_cnt, qid);
    1401           0 :                 return -1;
    1402             :         }
    1403             : 
    1404           0 :         for (j = 0; j < task_cnt; j++) {
    1405           0 :                 task = &((struct spdk_vhost_scsi_task *)vq->tasks)[j];
    1406           0 :                 task->svsession = svsession;
    1407           0 :                 task->vq = vq;
    1408           0 :                 task->req_idx = j;
    1409             :         }
    1410             : 
    1411           0 :         return 0;
    1412             : }
    1413             : 
    1414             : static int
    1415           0 : vhost_scsi_start(struct spdk_vhost_dev *vdev,
    1416             :                  struct spdk_vhost_session *vsession, void *unused)
    1417             : {
    1418           0 :         struct spdk_vhost_scsi_session *svsession = to_scsi_session(vsession);
    1419             :         struct spdk_vhost_scsi_dev *svdev;
    1420             :         struct spdk_scsi_dev_vhost_state *state;
    1421             :         uint32_t i;
    1422             :         int rc;
    1423             : 
    1424             :         /* return if start is already in progress */
    1425           0 :         if (svsession->requestq_poller) {
    1426           0 :                 SPDK_INFOLOG(vhost, "%s: start in progress\n", vsession->name);
    1427           0 :                 return -EINPROGRESS;
    1428             :         }
    1429             : 
    1430             :         /* validate all I/O queues are in a contiguous index range */
    1431           0 :         if (vsession->max_queues < VIRTIO_SCSI_REQUESTQ + 1) {
    1432           0 :                 SPDK_INFOLOG(vhost, "%s: max_queues %u, no I/O queues\n", vsession->name, vsession->max_queues);
    1433           0 :                 return -1;
    1434             :         }
    1435           0 :         for (i = VIRTIO_SCSI_REQUESTQ; i < vsession->max_queues; i++) {
    1436           0 :                 if (vsession->virtqueue[i].vring.desc == NULL) {
    1437           0 :                         SPDK_ERRLOG("%s: queue %"PRIu32" is empty\n", vsession->name, i);
    1438           0 :                         return -1;
    1439             :                 }
    1440             :         }
    1441             : 
    1442           0 :         svdev = to_scsi_dev(vsession->vdev);
    1443           0 :         assert(svdev != NULL);
    1444           0 :         svsession->svdev = svdev;
    1445             : 
    1446           0 :         for (i = 0; i < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS; i++) {
    1447           0 :                 state = &svdev->scsi_dev_state[i];
    1448           0 :                 if (state->dev == NULL || state->status == VHOST_SCSI_DEV_REMOVING) {
    1449           0 :                         continue;
    1450             :                 }
    1451             : 
    1452           0 :                 assert(svsession->scsi_dev_state[i].status == VHOST_SCSI_DEV_EMPTY);
    1453           0 :                 svsession->scsi_dev_state[i].dev = state->dev;
    1454           0 :                 svsession->scsi_dev_state[i].status = VHOST_SCSI_DEV_PRESENT;
    1455           0 :                 rc = spdk_scsi_dev_allocate_io_channels(state->dev);
    1456           0 :                 if (rc != 0) {
    1457           0 :                         SPDK_ERRLOG("%s: failed to alloc io_channel for SCSI target %"PRIu32"\n",
    1458             :                                     vsession->name, i);
    1459             :                         /* unset the SCSI target so that all I/O to it will be rejected */
    1460           0 :                         svsession->scsi_dev_state[i].dev = NULL;
    1461             :                         /* set EMPTY state so that we won't reply with SCSI hotremove
    1462             :                          * sense codes - the device hasn't ever been added.
    1463             :                          */
    1464           0 :                         svsession->scsi_dev_state[i].status = VHOST_SCSI_DEV_EMPTY;
    1465           0 :                         continue;
    1466             :                 }
    1467             :         }
    1468           0 :         SPDK_INFOLOG(vhost, "%s: started poller on lcore %d\n",
    1469             :                      vsession->name, spdk_env_get_current_core());
    1470             : 
    1471           0 :         svsession->requestq_poller = SPDK_POLLER_REGISTER(vdev_worker, svsession, 0);
    1472           0 :         svsession->mgmt_poller = SPDK_POLLER_REGISTER(vdev_mgmt_worker, svsession,
    1473             :                                  MGMT_POLL_PERIOD_US);
    1474           0 :         return 0;
    1475             : }
    1476             : 
    1477             : static int
    1478           0 : destroy_session_poller_cb(void *arg)
    1479             : {
    1480           0 :         struct spdk_vhost_scsi_session *svsession = arg;
    1481           0 :         struct spdk_vhost_session *vsession = &svsession->vsession;
    1482           0 :         struct spdk_vhost_user_dev *user_dev = to_user_dev(vsession->vdev);
    1483             :         struct spdk_scsi_dev_session_state *state;
    1484             :         uint32_t i;
    1485             : 
    1486           0 :         if (vsession->task_cnt > 0 || (pthread_mutex_trylock(&user_dev->lock) != 0)) {
    1487           0 :                 assert(vsession->stop_retry_count > 0);
    1488           0 :                 vsession->stop_retry_count--;
    1489           0 :                 if (vsession->stop_retry_count == 0) {
    1490           0 :                         SPDK_ERRLOG("%s: Timedout when destroy session (task_cnt %d)\n", vsession->name,
    1491             :                                     vsession->task_cnt);
    1492           0 :                         spdk_poller_unregister(&svsession->stop_poller);
    1493           0 :                         vhost_user_session_stop_done(vsession, -ETIMEDOUT);
    1494             :                 }
    1495             : 
    1496           0 :                 return SPDK_POLLER_BUSY;
    1497             :         }
    1498             : 
    1499           0 :         for (i = 0; i < vsession->max_queues; i++) {
    1500           0 :                 vhost_vq_used_signal(vsession, &vsession->virtqueue[i]);
    1501             :         }
    1502             : 
    1503           0 :         for (i = 0; i < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS; i++) {
    1504             :                 enum spdk_scsi_dev_vhost_status prev_status;
    1505             : 
    1506           0 :                 state = &svsession->scsi_dev_state[i];
    1507             :                 /* clear the REMOVED status so that we won't send hotremove events anymore */
    1508           0 :                 prev_status = state->status;
    1509           0 :                 state->status = VHOST_SCSI_DEV_EMPTY;
    1510           0 :                 if (state->dev == NULL) {
    1511           0 :                         continue;
    1512             :                 }
    1513             : 
    1514           0 :                 spdk_scsi_dev_free_io_channels(state->dev);
    1515             : 
    1516           0 :                 state->dev = NULL;
    1517             : 
    1518           0 :                 if (prev_status == VHOST_SCSI_DEV_REMOVING) {
    1519             :                         /* try to detach it globally */
    1520           0 :                         pthread_mutex_unlock(&user_dev->lock);
    1521           0 :                         vhost_user_dev_foreach_session(vsession->vdev,
    1522             :                                                        vhost_scsi_session_process_removed,
    1523             :                                                        vhost_scsi_dev_process_removed_cpl_cb,
    1524           0 :                                                        (void *)(uintptr_t)i);
    1525           0 :                         pthread_mutex_lock(&user_dev->lock);
    1526             :                 }
    1527             :         }
    1528             : 
    1529           0 :         SPDK_INFOLOG(vhost, "%s: stopping poller on lcore %d\n",
    1530             :                      vsession->name, spdk_env_get_current_core());
    1531             : 
    1532           0 :         free_task_pool(svsession);
    1533             : 
    1534           0 :         spdk_poller_unregister(&svsession->stop_poller);
    1535           0 :         vhost_user_session_stop_done(vsession, 0);
    1536             : 
    1537           0 :         pthread_mutex_unlock(&user_dev->lock);
    1538           0 :         return SPDK_POLLER_BUSY;
    1539             : }
    1540             : 
    1541             : static int
    1542           0 : vhost_scsi_stop(struct spdk_vhost_dev *vdev,
    1543             :                 struct spdk_vhost_session *vsession, void *unused)
    1544             : {
    1545           0 :         struct spdk_vhost_scsi_session *svsession = to_scsi_session(vsession);
    1546             : 
    1547             :         /* return if stop is already in progress */
    1548           0 :         if (svsession->stop_poller) {
    1549           0 :                 return -EINPROGRESS;
    1550             :         }
    1551             : 
    1552             :         /* Stop receiving new I/O requests */
    1553           0 :         spdk_poller_unregister(&svsession->requestq_poller);
    1554             : 
    1555             :         /* Stop receiving controlq requests, also stop processing the
    1556             :          * asynchronous hotremove events. All the remaining events
    1557             :          * will be finalized by the stop_poller below.
    1558             :          */
    1559           0 :         spdk_poller_unregister(&svsession->mgmt_poller);
    1560             : 
    1561           0 :         svsession->vsession.stop_retry_count = (SPDK_VHOST_SESSION_STOP_RETRY_TIMEOUT_IN_SEC * 1000 *
    1562             :                                                 1000) / SPDK_VHOST_SESSION_STOP_RETRY_PERIOD_IN_US;
    1563             : 
    1564             :         /* Wait for all pending I/Os to complete, then process all the
    1565             :          * remaining hotremove events one last time.
    1566             :          */
    1567           0 :         svsession->stop_poller = SPDK_POLLER_REGISTER(destroy_session_poller_cb,
    1568             :                                  svsession, SPDK_VHOST_SESSION_STOP_RETRY_PERIOD_IN_US);
    1569             : 
    1570           0 :         return 0;
    1571             : }
    1572             : 
    1573             : static void
    1574           0 : vhost_scsi_dump_info_json(struct spdk_vhost_dev *vdev, struct spdk_json_write_ctx *w)
    1575             : {
    1576             :         struct spdk_scsi_dev *sdev;
    1577             :         struct spdk_scsi_lun *lun;
    1578             :         uint32_t dev_idx;
    1579             : 
    1580           0 :         assert(vdev != NULL);
    1581           0 :         spdk_json_write_named_array_begin(w, "scsi");
    1582           0 :         for (dev_idx = 0; dev_idx < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS; dev_idx++) {
    1583           0 :                 sdev = spdk_vhost_scsi_dev_get_tgt(vdev, dev_idx);
    1584           0 :                 if (!sdev) {
    1585           0 :                         continue;
    1586             :                 }
    1587             : 
    1588           0 :                 spdk_json_write_object_begin(w);
    1589             : 
    1590           0 :                 spdk_json_write_named_uint32(w, "scsi_dev_num", dev_idx);
    1591             : 
    1592           0 :                 spdk_json_write_named_uint32(w, "id", spdk_scsi_dev_get_id(sdev));
    1593             : 
    1594           0 :                 spdk_json_write_named_string(w, "target_name", spdk_scsi_dev_get_name(sdev));
    1595             : 
    1596           0 :                 spdk_json_write_named_array_begin(w, "luns");
    1597             : 
    1598           0 :                 for (lun = spdk_scsi_dev_get_first_lun(sdev); lun != NULL;
    1599           0 :                      lun = spdk_scsi_dev_get_next_lun(lun)) {
    1600           0 :                         spdk_json_write_object_begin(w);
    1601             : 
    1602           0 :                         spdk_json_write_named_int32(w, "id", spdk_scsi_lun_get_id(lun));
    1603             : 
    1604           0 :                         spdk_json_write_named_string(w, "bdev_name", spdk_scsi_lun_get_bdev_name(lun));
    1605             : 
    1606           0 :                         spdk_json_write_object_end(w);
    1607             :                 }
    1608             : 
    1609           0 :                 spdk_json_write_array_end(w);
    1610           0 :                 spdk_json_write_object_end(w);
    1611             :         }
    1612             : 
    1613           0 :         spdk_json_write_array_end(w);
    1614           0 : }
    1615             : 
    1616             : static void
    1617           0 : vhost_scsi_write_config_json(struct spdk_vhost_dev *vdev, struct spdk_json_write_ctx *w)
    1618             : {
    1619             :         struct spdk_scsi_dev *scsi_dev;
    1620             :         struct spdk_scsi_lun *lun;
    1621             :         uint32_t i;
    1622             : 
    1623           0 :         spdk_json_write_object_begin(w);
    1624           0 :         spdk_json_write_named_string(w, "method", "vhost_create_scsi_controller");
    1625             : 
    1626           0 :         spdk_json_write_named_object_begin(w, "params");
    1627           0 :         spdk_json_write_named_string(w, "ctrlr", vdev->name);
    1628           0 :         spdk_json_write_named_string(w, "cpumask",
    1629             :                                      spdk_cpuset_fmt(spdk_thread_get_cpumask(vdev->thread)));
    1630           0 :         spdk_json_write_named_bool(w, "delay", true);
    1631           0 :         spdk_json_write_object_end(w);
    1632             : 
    1633           0 :         spdk_json_write_object_end(w);
    1634             : 
    1635           0 :         for (i = 0; i < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS; i++) {
    1636           0 :                 scsi_dev = spdk_vhost_scsi_dev_get_tgt(vdev, i);
    1637           0 :                 if (scsi_dev == NULL) {
    1638           0 :                         continue;
    1639             :                 }
    1640             : 
    1641           0 :                 lun = spdk_scsi_dev_get_lun(scsi_dev, 0);
    1642           0 :                 assert(lun != NULL);
    1643             : 
    1644           0 :                 spdk_json_write_object_begin(w);
    1645           0 :                 spdk_json_write_named_string(w, "method", "vhost_scsi_controller_add_target");
    1646             : 
    1647           0 :                 spdk_json_write_named_object_begin(w, "params");
    1648           0 :                 spdk_json_write_named_string(w, "ctrlr", vdev->name);
    1649           0 :                 spdk_json_write_named_uint32(w, "scsi_target_num", i);
    1650             : 
    1651           0 :                 spdk_json_write_named_string(w, "bdev_name", spdk_scsi_lun_get_bdev_name(lun));
    1652           0 :                 spdk_json_write_object_end(w);
    1653             : 
    1654           0 :                 spdk_json_write_object_end(w);
    1655             :         }
    1656             : 
    1657           0 :         spdk_json_write_object_begin(w);
    1658           0 :         spdk_json_write_named_string(w, "method", "vhost_start_scsi_controller");
    1659             : 
    1660           0 :         spdk_json_write_named_object_begin(w, "params");
    1661           0 :         spdk_json_write_named_string(w, "ctrlr", vdev->name);
    1662           0 :         spdk_json_write_object_end(w);
    1663             : 
    1664           0 :         spdk_json_write_object_end(w);
    1665           0 : }
    1666             : 
    1667           0 : SPDK_LOG_REGISTER_COMPONENT(vhost_scsi)
    1668           0 : SPDK_LOG_REGISTER_COMPONENT(vhost_scsi_queue)
    1669           0 : SPDK_LOG_REGISTER_COMPONENT(vhost_scsi_data)

Generated by: LCOV version 1.15