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

Generated by: LCOV version 1.15