1c19beb3fSJin Yu /* SPDX-License-Identifier: BSD-3-Clause
2c19beb3fSJin Yu * Copyright(c) 2010-2019 Intel Corporation
3c19beb3fSJin Yu */
4c19beb3fSJin Yu
5c19beb3fSJin Yu /**
6c19beb3fSJin Yu * This work is largely based on the "vhost-user-blk" implementation by
7c19beb3fSJin Yu * SPDK(https://github.com/spdk/spdk).
8c19beb3fSJin Yu */
9c19beb3fSJin Yu
10c19beb3fSJin Yu #include <stdio.h>
11c19beb3fSJin Yu #include <stdint.h>
12c19beb3fSJin Yu #include <unistd.h>
13c19beb3fSJin Yu #include <assert.h>
14c19beb3fSJin Yu #include <ctype.h>
15c19beb3fSJin Yu #include <string.h>
16c19beb3fSJin Yu #include <stddef.h>
17c19beb3fSJin Yu
18c19beb3fSJin Yu #include <rte_cycles.h>
19c19beb3fSJin Yu #include <rte_log.h>
20c19beb3fSJin Yu #include <rte_malloc.h>
21c19beb3fSJin Yu #include <rte_byteorder.h>
22c19beb3fSJin Yu #include <rte_string_fns.h>
23c19beb3fSJin Yu
24c19beb3fSJin Yu #include "vhost_blk.h"
25c19beb3fSJin Yu #include "blk_spec.h"
26c19beb3fSJin Yu
27c19beb3fSJin Yu static void
vhost_strcpy_pad(void * dst,const char * src,size_t size,int pad)28c19beb3fSJin Yu vhost_strcpy_pad(void *dst, const char *src, size_t size, int pad)
29c19beb3fSJin Yu {
30c19beb3fSJin Yu size_t len;
31c19beb3fSJin Yu
32c19beb3fSJin Yu len = strlen(src);
33c19beb3fSJin Yu if (len < size) {
34c19beb3fSJin Yu memcpy(dst, src, len);
35c19beb3fSJin Yu memset((char *)dst + len, pad, size - len);
36c19beb3fSJin Yu } else {
37c19beb3fSJin Yu memcpy(dst, src, size);
38c19beb3fSJin Yu }
39c19beb3fSJin Yu }
40c19beb3fSJin Yu
41c19beb3fSJin Yu static int
vhost_bdev_blk_readwrite(struct vhost_block_dev * bdev,struct vhost_blk_task * task,uint64_t lba_512,__rte_unused uint32_t xfer_len)42c19beb3fSJin Yu vhost_bdev_blk_readwrite(struct vhost_block_dev *bdev,
43c19beb3fSJin Yu struct vhost_blk_task *task,
44c19beb3fSJin Yu uint64_t lba_512, __rte_unused uint32_t xfer_len)
45c19beb3fSJin Yu {
46c19beb3fSJin Yu uint32_t i;
47c19beb3fSJin Yu uint64_t offset;
48c19beb3fSJin Yu uint32_t nbytes = 0;
49c19beb3fSJin Yu
50c19beb3fSJin Yu offset = lba_512 * 512;
51c19beb3fSJin Yu
52*91d3e2d4SJin Yu /* iovs[0] is the head and iovs[iovs_cnt - 1] is the tail
53*91d3e2d4SJin Yu * Middle is the data range
54*91d3e2d4SJin Yu */
55*91d3e2d4SJin Yu for (i = 1; i < task->iovs_cnt - 1; i++) {
56c19beb3fSJin Yu if (task->dxfer_dir == BLK_DIR_TO_DEV)
57c19beb3fSJin Yu memcpy(bdev->data + offset, task->iovs[i].iov_base,
58c19beb3fSJin Yu task->iovs[i].iov_len);
59c19beb3fSJin Yu else
60c19beb3fSJin Yu memcpy(task->iovs[i].iov_base, bdev->data + offset,
61c19beb3fSJin Yu task->iovs[i].iov_len);
62c19beb3fSJin Yu offset += task->iovs[i].iov_len;
63c19beb3fSJin Yu nbytes += task->iovs[i].iov_len;
64c19beb3fSJin Yu }
65c19beb3fSJin Yu
66c19beb3fSJin Yu return nbytes;
67c19beb3fSJin Yu }
68c19beb3fSJin Yu
69c19beb3fSJin Yu int
vhost_bdev_process_blk_commands(struct vhost_block_dev * bdev,struct vhost_blk_task * task)70c19beb3fSJin Yu vhost_bdev_process_blk_commands(struct vhost_block_dev *bdev,
71c19beb3fSJin Yu struct vhost_blk_task *task)
72c19beb3fSJin Yu {
7339f59f37SThomas Monjalon size_t used_len;
74c19beb3fSJin Yu
75c19beb3fSJin Yu if (unlikely(task->data_len > (bdev->blockcnt * bdev->blocklen))) {
76c19beb3fSJin Yu fprintf(stderr, "read or write beyond capacity\n");
77c19beb3fSJin Yu return VIRTIO_BLK_S_UNSUPP;
78c19beb3fSJin Yu }
79c19beb3fSJin Yu
80c19beb3fSJin Yu switch (task->req->type) {
81c19beb3fSJin Yu case VIRTIO_BLK_T_IN:
82c19beb3fSJin Yu if (unlikely(task->data_len == 0 ||
83c19beb3fSJin Yu (task->data_len & (512 - 1)) != 0)) {
84c19beb3fSJin Yu fprintf(stderr,
85c19beb3fSJin Yu "%s - passed IO buffer is not multiple of 512b"
86c19beb3fSJin Yu "(req_idx = %"PRIu16").\n",
87c19beb3fSJin Yu task->req->type ? "WRITE" : "READ",
88*91d3e2d4SJin Yu task->req_idx);
89c19beb3fSJin Yu return VIRTIO_BLK_S_UNSUPP;
90c19beb3fSJin Yu }
91c19beb3fSJin Yu
92c19beb3fSJin Yu task->dxfer_dir = BLK_DIR_FROM_DEV;
93c19beb3fSJin Yu vhost_bdev_blk_readwrite(bdev, task,
94c19beb3fSJin Yu task->req->sector, task->data_len);
95c19beb3fSJin Yu break;
96c19beb3fSJin Yu case VIRTIO_BLK_T_OUT:
97c19beb3fSJin Yu if (unlikely(task->data_len == 0 ||
98c19beb3fSJin Yu (task->data_len & (512 - 1)) != 0)) {
99c19beb3fSJin Yu fprintf(stderr,
100c19beb3fSJin Yu "%s - passed IO buffer is not multiple of 512b"
101c19beb3fSJin Yu "(req_idx = %"PRIu16").\n",
102c19beb3fSJin Yu task->req->type ? "WRITE" : "READ",
103*91d3e2d4SJin Yu task->req_idx);
104c19beb3fSJin Yu return VIRTIO_BLK_S_UNSUPP;
105c19beb3fSJin Yu }
106c19beb3fSJin Yu
107c19beb3fSJin Yu task->dxfer_dir = BLK_DIR_TO_DEV;
108c19beb3fSJin Yu vhost_bdev_blk_readwrite(bdev, task,
109c19beb3fSJin Yu task->req->sector, task->data_len);
110c19beb3fSJin Yu break;
111c19beb3fSJin Yu case VIRTIO_BLK_T_GET_ID:
112c19beb3fSJin Yu if (!task->iovs_cnt || task->data_len)
113c19beb3fSJin Yu return VIRTIO_BLK_S_UNSUPP;
11439f59f37SThomas Monjalon used_len = RTE_MIN((size_t)VIRTIO_BLK_ID_BYTES, task->data_len);
115c19beb3fSJin Yu vhost_strcpy_pad(task->iovs[0].iov_base,
116c19beb3fSJin Yu bdev->product_name, used_len, ' ');
117c19beb3fSJin Yu break;
118c19beb3fSJin Yu default:
119c19beb3fSJin Yu fprintf(stderr, "unsupported cmd\n");
120c19beb3fSJin Yu return VIRTIO_BLK_S_UNSUPP;
121c19beb3fSJin Yu }
122c19beb3fSJin Yu
123c19beb3fSJin Yu return VIRTIO_BLK_S_OK;
124c19beb3fSJin Yu }
125