module/vfu_device: add virtio-scsi emulation
Here we use vfu_tgt library and emulate a virtio-scsi device as the next use case. Compared with vhost-user-scsi, the packed ring is supported with this patch. Example usage method: 1. scripts/rpc.py bdev_malloc_create -b malloc0 $((512)) 512 2. scripts/rpc.py vfu_virtio_create_scsi_endpoint vfu.0 --cpumask 0x1 --num-io-queues=4 \ --qsize=128 --packed-ring 3. scripts/rpc.py vfu_virtio_scsi_add_target vfu.0 --scsi-target-num=0 --bdev-name malloc0 4. Start QEMU with '-device vfio-user-pci,socket=/spdk/vfu.0' Change-Id: I8f35d1d21aaec34844d6ddb59dc997a64f141179 Signed-off-by: Changpeng Liu <changpeng.liu@intel.com> Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/12673 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Community-CI: Mellanox Build Bot Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
parent
23ef63882c
commit
5004d7b8e8
118
doc/jsonrpc.md
118
doc/jsonrpc.md
@ -8089,6 +8089,124 @@ Example response:
|
||||
}
|
||||
~~~
|
||||
|
||||
### vfu_virtio_scsi_add_target {#rpc_vfu_virtio_scsi_add_target}
|
||||
|
||||
Add block device to specified SCSI target of vfio-user virtio-scsi PCI endpoint.
|
||||
|
||||
#### Parameters
|
||||
|
||||
Name | Optional | Type | Description
|
||||
----------------------- | -------- | ----------- | -----------
|
||||
name | Required | string | Endpoint name
|
||||
scsi_target_num | Required | number | SCSI target number
|
||||
bdev_name | Required | string | Block device name
|
||||
|
||||
#### Example
|
||||
|
||||
Example request:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"params": {
|
||||
"name": "vfu.0",
|
||||
"scsi_target_num": 0,
|
||||
"bdev_name": "Malloc0"
|
||||
},
|
||||
"jsonrpc": "2.0",
|
||||
"method": "vfu_virtio_scsi_add_target",
|
||||
"id": 1
|
||||
}
|
||||
~~~
|
||||
|
||||
Example response:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": true
|
||||
}
|
||||
~~~
|
||||
|
||||
### vfu_virtio_scsi_remove_target {#rpc_vfu_virtio_scsi_remove_target}
|
||||
|
||||
Remove a SCSI target of vfio-user virtio-scsi PCI endpoint.
|
||||
|
||||
#### Parameters
|
||||
|
||||
Name | Optional | Type | Description
|
||||
----------------------- | -------- | ----------- | -----------
|
||||
name | Required | string | Endpoint name
|
||||
scsi_target_num | Required | number | SCSI target number
|
||||
|
||||
#### Example
|
||||
|
||||
Example request:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"params": {
|
||||
"name": "vfu.0",
|
||||
"scsi_target_num": 0
|
||||
},
|
||||
"jsonrpc": "2.0",
|
||||
"method": "vfu_virtio_scsi_remove_target",
|
||||
"id": 1
|
||||
}
|
||||
~~~
|
||||
|
||||
Example response:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": true
|
||||
}
|
||||
~~~
|
||||
|
||||
### vfu_virtio_create_scsi_endpoint {#rpc_vfu_virtio_create_scsi_endpoint}
|
||||
|
||||
Create vfio-user virtio-scsi PCI endpoint.
|
||||
|
||||
#### Parameters
|
||||
|
||||
Name | Optional | Type | Description
|
||||
----------------------- | -------- | ----------- | -----------
|
||||
name | Required | string | Endpoint name
|
||||
cpumask | Optional | string | CPU masks
|
||||
num_io_queues | Optional | number | Number of IO queues
|
||||
qsize | Optional | number | Queue size
|
||||
packed_ring | Optional | boolean | Enable packed ring
|
||||
|
||||
#### Example
|
||||
|
||||
Example request:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"params": {
|
||||
"name": "vfu.0",
|
||||
"cpumask": "0x2",
|
||||
"num_io_queues": 4,
|
||||
"qsize": 256
|
||||
},
|
||||
"jsonrpc": "2.0",
|
||||
"method": "vfu_virtio_create_scsi_endpoint",
|
||||
"id": 1
|
||||
}
|
||||
~~~
|
||||
|
||||
Example response:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": true
|
||||
}
|
||||
~~~
|
||||
|
||||
## Vhost Target {#jsonrpc_components_vhost_tgt}
|
||||
|
||||
The following common preconditions need to be met in all target types.
|
||||
|
@ -164,5 +164,5 @@ DEPDIRS-event_vfu_tgt := init vfu_tgt
|
||||
# module/vfu_device
|
||||
|
||||
ifeq ($(CONFIG_VFIO_USER),y)
|
||||
DEPDIRS-vfu_device := $(BDEV_DEPS_THREAD) vfu_tgt
|
||||
DEPDIRS-vfu_device := $(BDEV_DEPS_THREAD) scsi vfu_tgt
|
||||
endif
|
||||
|
@ -9,7 +9,7 @@ include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
|
||||
SO_VER := 1
|
||||
SO_MINOR := 0
|
||||
|
||||
C_SRCS = vfu_virtio.c vfu_virtio_blk.c vfu_virtio_rpc.c
|
||||
C_SRCS = vfu_virtio.c vfu_virtio_blk.c vfu_virtio_scsi.c vfu_virtio_rpc.c
|
||||
LIBNAME = vfu_device
|
||||
|
||||
SPDK_MAP_FILE = $(SPDK_ROOT_DIR)/mk/spdk_blank.map
|
||||
|
@ -399,5 +399,10 @@ int vfu_virtio_pre_memory_remove(struct spdk_vfu_endpoint *endpoint, void *map_s
|
||||
int vfu_virtio_pci_reset_cb(struct spdk_vfu_endpoint *endpoint);
|
||||
int vfu_virtio_blk_add_bdev(const char *name, const char *bdev_name,
|
||||
uint16_t num_queues, uint16_t qsize, bool packed_ring);
|
||||
|
||||
/* virtio_scsi */
|
||||
int vfu_virtio_scsi_add_target(const char *name, uint8_t scsi_target_num,
|
||||
const char *bdev_name);
|
||||
int vfu_virtio_scsi_remove_target(const char *name, uint8_t scsi_target_num);
|
||||
int vfu_virtio_scsi_set_options(const char *name, uint16_t num_io_queues, uint16_t qsize,
|
||||
bool packed_ring);
|
||||
#endif
|
||||
|
@ -124,3 +124,164 @@ invalid:
|
||||
}
|
||||
SPDK_RPC_REGISTER("vfu_virtio_create_blk_endpoint", rpc_vfu_virtio_create_blk_endpoint,
|
||||
SPDK_RPC_RUNTIME)
|
||||
|
||||
struct rpc_vfu_virtio_scsi {
|
||||
char *name;
|
||||
uint8_t scsi_target_num;
|
||||
char *bdev_name;
|
||||
};
|
||||
|
||||
static const struct spdk_json_object_decoder rpc_construct_vfu_virtio_scsi[] = {
|
||||
{"name", offsetof(struct rpc_vfu_virtio_scsi, name), spdk_json_decode_string },
|
||||
{"scsi_target_num", offsetof(struct rpc_vfu_virtio_scsi, scsi_target_num), spdk_json_decode_uint8 },
|
||||
{"bdev_name", offsetof(struct rpc_vfu_virtio_scsi, bdev_name), spdk_json_decode_string },
|
||||
};
|
||||
|
||||
static void
|
||||
free_rpc_vfu_virtio_scsi(struct rpc_vfu_virtio_scsi *req)
|
||||
{
|
||||
free(req->name);
|
||||
free(req->bdev_name);
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_vfu_virtio_scsi_add_target(struct spdk_jsonrpc_request *request,
|
||||
const struct spdk_json_val *params)
|
||||
{
|
||||
struct rpc_vfu_virtio_scsi req = {0};
|
||||
int rc;
|
||||
|
||||
if (spdk_json_decode_object(params, rpc_construct_vfu_virtio_scsi,
|
||||
SPDK_COUNTOF(rpc_construct_vfu_virtio_scsi),
|
||||
&req)) {
|
||||
SPDK_ERRLOG("spdk_json_decode_object failed\n");
|
||||
rc = -EINVAL;
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
rc = vfu_virtio_scsi_add_target(req.name, req.scsi_target_num, req.bdev_name);;
|
||||
if (rc < 0) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
free_rpc_vfu_virtio_scsi(&req);
|
||||
spdk_jsonrpc_send_bool_response(request, true);
|
||||
return;
|
||||
|
||||
invalid:
|
||||
free_rpc_vfu_virtio_scsi(&req);
|
||||
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
||||
spdk_strerror(-rc));
|
||||
}
|
||||
SPDK_RPC_REGISTER("vfu_virtio_scsi_add_target", rpc_vfu_virtio_scsi_add_target,
|
||||
SPDK_RPC_RUNTIME)
|
||||
|
||||
struct rpc_vfu_virtio_scsi_remove {
|
||||
char *name;
|
||||
uint8_t scsi_target_num;
|
||||
};
|
||||
|
||||
static const struct spdk_json_object_decoder rpc_remove_vfu_virtio_scsi_target[] = {
|
||||
{"name", offsetof(struct rpc_vfu_virtio_scsi_remove, name), spdk_json_decode_string },
|
||||
{"scsi_target_num", offsetof(struct rpc_vfu_virtio_scsi_remove, scsi_target_num), spdk_json_decode_uint8 },
|
||||
};
|
||||
|
||||
static void
|
||||
free_rpc_vfu_virtio_scsi_remove(struct rpc_vfu_virtio_scsi_remove *req)
|
||||
{
|
||||
free(req->name);
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_vfu_virtio_scsi_remove_target(struct spdk_jsonrpc_request *request,
|
||||
const struct spdk_json_val *params)
|
||||
{
|
||||
struct rpc_vfu_virtio_scsi_remove req = {0};
|
||||
int rc;
|
||||
|
||||
if (spdk_json_decode_object(params, rpc_remove_vfu_virtio_scsi_target,
|
||||
SPDK_COUNTOF(rpc_remove_vfu_virtio_scsi_target),
|
||||
&req)) {
|
||||
SPDK_ERRLOG("spdk_json_decode_object failed\n");
|
||||
rc = -EINVAL;
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
rc = vfu_virtio_scsi_remove_target(req.name, req.scsi_target_num);
|
||||
if (rc < 0) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
free_rpc_vfu_virtio_scsi_remove(&req);
|
||||
spdk_jsonrpc_send_bool_response(request, true);
|
||||
return;
|
||||
|
||||
invalid:
|
||||
free_rpc_vfu_virtio_scsi_remove(&req);
|
||||
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
||||
spdk_strerror(-rc));
|
||||
}
|
||||
SPDK_RPC_REGISTER("vfu_virtio_scsi_remove_target", rpc_vfu_virtio_scsi_remove_target,
|
||||
SPDK_RPC_RUNTIME)
|
||||
|
||||
struct rpc_vfu_virtio_create_scsi {
|
||||
char *name;
|
||||
char *cpumask;
|
||||
uint16_t num_io_queues;
|
||||
uint16_t qsize;
|
||||
bool packed_ring;
|
||||
};
|
||||
|
||||
static const struct spdk_json_object_decoder rpc_construct_vfu_virtio_create_scsi[] = {
|
||||
{"name", offsetof(struct rpc_vfu_virtio_create_scsi, name), spdk_json_decode_string },
|
||||
{"cpumask", offsetof(struct rpc_vfu_virtio_create_scsi, cpumask), spdk_json_decode_string, true},
|
||||
{"num_io_queues", offsetof(struct rpc_vfu_virtio_create_scsi, num_io_queues), spdk_json_decode_uint16, true },
|
||||
{"qsize", offsetof(struct rpc_vfu_virtio_create_scsi, qsize), spdk_json_decode_uint16, true },
|
||||
{"packed_ring", offsetof(struct rpc_vfu_virtio_create_scsi, packed_ring), spdk_json_decode_bool, true},
|
||||
};
|
||||
|
||||
static void
|
||||
free_rpc_vfu_virtio_create_scsi(struct rpc_vfu_virtio_create_scsi *req)
|
||||
{
|
||||
free(req->name);
|
||||
free(req->cpumask);
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_vfu_virtio_create_scsi_endpoint(struct spdk_jsonrpc_request *request,
|
||||
const struct spdk_json_val *params)
|
||||
{
|
||||
struct rpc_vfu_virtio_create_scsi req = {0};
|
||||
int rc;
|
||||
|
||||
if (spdk_json_decode_object(params, rpc_construct_vfu_virtio_create_scsi,
|
||||
SPDK_COUNTOF(rpc_construct_vfu_virtio_create_scsi),
|
||||
&req)) {
|
||||
SPDK_ERRLOG("spdk_json_decode_object failed\n");
|
||||
rc = -EINVAL;
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
rc = spdk_vfu_create_endpoint(req.name, req.cpumask, "virtio_scsi");
|
||||
if (rc) {
|
||||
SPDK_ERRLOG("Failed to create virtio_blk endpoint\n");
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
rc = vfu_virtio_scsi_set_options(req.name, req.num_io_queues, req.qsize, req.packed_ring);
|
||||
if (rc < 0) {
|
||||
spdk_vfu_delete_endpoint(req.name);
|
||||
goto invalid;
|
||||
}
|
||||
free_rpc_vfu_virtio_create_scsi(&req);
|
||||
|
||||
spdk_jsonrpc_send_bool_response(request, true);
|
||||
return;
|
||||
|
||||
invalid:
|
||||
free_rpc_vfu_virtio_create_scsi(&req);
|
||||
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
||||
spdk_strerror(-rc));
|
||||
}
|
||||
SPDK_RPC_REGISTER("vfu_virtio_create_scsi_endpoint", rpc_vfu_virtio_create_scsi_endpoint,
|
||||
SPDK_RPC_RUNTIME)
|
||||
|
1037
module/vfu_device/vfu_virtio_scsi.c
Normal file
1037
module/vfu_device/vfu_virtio_scsi.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -49,3 +49,60 @@ def vfu_virtio_create_blk_endpoint(client, name, bdev_name, cpumask, num_queues,
|
||||
params['packed_ring'] = packed_ring
|
||||
|
||||
return client.call('vfu_virtio_create_blk_endpoint', params)
|
||||
|
||||
|
||||
def vfu_virtio_scsi_add_target(client, name, scsi_target_num, bdev_name):
|
||||
"""Attach a block device to the specified SCSI target.
|
||||
|
||||
Args:
|
||||
name: endpoint name
|
||||
scsi_target_num: SCSI target number
|
||||
bdev_name: name of block device
|
||||
"""
|
||||
params = {
|
||||
'name': name,
|
||||
'scsi_target_num': scsi_target_num,
|
||||
'bdev_name': bdev_name
|
||||
}
|
||||
|
||||
return client.call('vfu_virtio_scsi_add_target', params)
|
||||
|
||||
|
||||
def vfu_virtio_scsi_remove_target(client, name, scsi_target_num):
|
||||
"""Remove specified SCSI target of socket endpoint.
|
||||
|
||||
Args:
|
||||
name: endpoint name
|
||||
scsi_target_num: SCSI target number
|
||||
"""
|
||||
params = {
|
||||
'name': name,
|
||||
'scsi_target_num': scsi_target_num
|
||||
}
|
||||
|
||||
return client.call('vfu_virtio_scsi_remove_target', params)
|
||||
|
||||
|
||||
def vfu_virtio_create_scsi_endpoint(client, name, cpumask, num_io_queues, qsize, packed_ring):
|
||||
"""Create virtio-scsi endpoint.
|
||||
|
||||
Args:
|
||||
name: endpoint name
|
||||
cpumask: CPU core mask
|
||||
num_io_queues: number of IO vrings
|
||||
qsize: number of element of each vring
|
||||
packed_ring: enable packed ring
|
||||
"""
|
||||
params = {
|
||||
'name': name,
|
||||
}
|
||||
if cpumask:
|
||||
params['cpumask'] = cpumask
|
||||
if num_io_queues:
|
||||
params['num_io_queues'] = num_io_queues
|
||||
if qsize:
|
||||
params['qsize'] = qsize
|
||||
if packed_ring:
|
||||
params['packed_ring'] = packed_ring
|
||||
|
||||
return client.call('vfu_virtio_create_scsi_endpoint', params)
|
||||
|
@ -2649,6 +2649,44 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse
|
||||
p.add_argument("--packed-ring", action='store_true', help='Enable packed ring')
|
||||
p.set_defaults(func=vfu_virtio_create_blk_endpoint)
|
||||
|
||||
def vfu_virtio_scsi_add_target(args):
|
||||
rpc.vfio_user.vfu_virtio_scsi_add_target(args.client,
|
||||
name=args.name,
|
||||
scsi_target_num=args.scsi_target_num,
|
||||
bdev_name=args.bdev_name)
|
||||
|
||||
p = subparsers.add_parser('vfu_virtio_scsi_add_target', help='Attach a block device to SCSI target of PCI endpoint.')
|
||||
p.add_argument('name', help='Name of the endpoint')
|
||||
p.add_argument('--scsi-target-num', help='number of SCSI Target', type=int, required=True)
|
||||
p.add_argument('--bdev-name', help='block device name', type=str, required=True)
|
||||
p.set_defaults(func=vfu_virtio_scsi_add_target)
|
||||
|
||||
def vfu_virtio_scsi_remove_target(args):
|
||||
rpc.vfio_user.vfu_virtio_scsi_remove_target(args.client,
|
||||
name=args.name,
|
||||
scsi_target_num=args.scsi_target_num)
|
||||
|
||||
p = subparsers.add_parser('vfu_virtio_scsi_remove_target', help='Remove the specified SCSI target of PCI endpoint.')
|
||||
p.add_argument('name', help='Name of the endpoint')
|
||||
p.add_argument('--scsi-target-num', help='number of SCSI Target', type=int, required=True)
|
||||
p.set_defaults(func=vfu_virtio_scsi_remove_target)
|
||||
|
||||
def vfu_virtio_create_scsi_endpoint(args):
|
||||
rpc.vfio_user.vfu_virtio_create_scsi_endpoint(args.client,
|
||||
name=args.name,
|
||||
cpumask=args.cpumask,
|
||||
num_io_queues=args.num_io_queues,
|
||||
qsize=args.qsize,
|
||||
packed_ring=args.packed_ring)
|
||||
|
||||
p = subparsers.add_parser('vfu_virtio_create_scsi_endpoint', help='Create virtio-scsi endpoint.')
|
||||
p.add_argument('name', help='Name of the endpoint')
|
||||
p.add_argument('--cpumask', help='CPU masks')
|
||||
p.add_argument('--num-io-queues', help='number of IO vrings', type=int, default=0)
|
||||
p.add_argument('--qsize', help='number of element for each vring', type=int, default=0)
|
||||
p.add_argument("--packed-ring", action='store_true', help='Enable packed ring')
|
||||
p.set_defaults(func=vfu_virtio_create_scsi_endpoint)
|
||||
|
||||
# accel_fw
|
||||
def accel_get_opc_assignments(args):
|
||||
print_dict(rpc.accel.accel_get_opc_assignments(args.client))
|
||||
|
Loading…
Reference in New Issue
Block a user