2 * Copyright (c) 2018 Citrix Systems Inc.
4 * This work is licensed under the terms of the GNU GPL, version 2 or later.
5 * See the COPYING file in the top-level directory.
8 #include "qemu/osdep.h"
9 #include "qemu/cutils.h"
10 #include "qapi/error.h"
11 #include "qapi/visitor.h"
13 #include "hw/xen/xen_common.h"
14 #include "hw/block/xen_blkif.h"
15 #include "hw/xen/xen-block.h"
16 #include "sysemu/blockdev.h"
17 #include "sysemu/block-backend.h"
18 #include "sysemu/iothread.h"
19 #include "dataplane/xen-block.h"
22 static char *xen_block_get_name(XenDevice
*xendev
, Error
**errp
)
24 XenBlockDevice
*blockdev
= XEN_BLOCK_DEVICE(xendev
);
25 XenBlockVdev
*vdev
= &blockdev
->props
.vdev
;
27 return g_strdup_printf("%lu", vdev
->number
);
30 static void xen_block_disconnect(XenDevice
*xendev
, Error
**errp
)
32 XenBlockDevice
*blockdev
= XEN_BLOCK_DEVICE(xendev
);
33 const char *type
= object_get_typename(OBJECT(blockdev
));
34 XenBlockVdev
*vdev
= &blockdev
->props
.vdev
;
36 trace_xen_block_disconnect(type
, vdev
->disk
, vdev
->partition
);
38 xen_block_dataplane_stop(blockdev
->dataplane
);
41 static void xen_block_connect(XenDevice
*xendev
, Error
**errp
)
43 XenBlockDevice
*blockdev
= XEN_BLOCK_DEVICE(xendev
);
44 const char *type
= object_get_typename(OBJECT(blockdev
));
45 XenBlockVdev
*vdev
= &blockdev
->props
.vdev
;
46 unsigned int order
, nr_ring_ref
, *ring_ref
, event_channel
, protocol
;
49 trace_xen_block_connect(type
, vdev
->disk
, vdev
->partition
);
51 if (xen_device_frontend_scanf(xendev
, "ring-page-order", "%u",
54 ring_ref
= g_new(unsigned int, nr_ring_ref
);
56 if (xen_device_frontend_scanf(xendev
, "ring-ref", "%u",
58 error_setg(errp
, "failed to read ring-ref");
62 } else if (order
<= blockdev
->props
.max_ring_page_order
) {
65 nr_ring_ref
= 1 << order
;
66 ring_ref
= g_new(unsigned int, nr_ring_ref
);
68 for (i
= 0; i
< nr_ring_ref
; i
++) {
69 const char *key
= g_strdup_printf("ring-ref%u", i
);
71 if (xen_device_frontend_scanf(xendev
, key
, "%u",
73 error_setg(errp
, "failed to read %s", key
);
74 g_free((gpointer
)key
);
79 g_free((gpointer
)key
);
82 error_setg(errp
, "invalid ring-page-order (%d)", order
);
86 if (xen_device_frontend_scanf(xendev
, "event-channel", "%u",
87 &event_channel
) != 1) {
88 error_setg(errp
, "failed to read event-channel");
93 if (xen_device_frontend_scanf(xendev
, "protocol", "%ms",
95 protocol
= BLKIF_PROTOCOL_NATIVE
;
97 if (strcmp(str
, XEN_IO_PROTO_ABI_X86_32
) == 0) {
98 protocol
= BLKIF_PROTOCOL_X86_32
;
99 } else if (strcmp(str
, XEN_IO_PROTO_ABI_X86_64
) == 0) {
100 protocol
= BLKIF_PROTOCOL_X86_64
;
102 protocol
= BLKIF_PROTOCOL_NATIVE
;
108 xen_block_dataplane_start(blockdev
->dataplane
, ring_ref
, nr_ring_ref
,
109 event_channel
, protocol
, errp
);
114 static void xen_block_unrealize(XenDevice
*xendev
, Error
**errp
)
116 XenBlockDevice
*blockdev
= XEN_BLOCK_DEVICE(xendev
);
117 XenBlockDeviceClass
*blockdev_class
=
118 XEN_BLOCK_DEVICE_GET_CLASS(xendev
);
119 const char *type
= object_get_typename(OBJECT(blockdev
));
120 XenBlockVdev
*vdev
= &blockdev
->props
.vdev
;
122 if (vdev
->type
== XEN_BLOCK_VDEV_TYPE_INVALID
) {
126 trace_xen_block_unrealize(type
, vdev
->disk
, vdev
->partition
);
128 /* Disconnect from the frontend in case this has not already happened */
129 xen_block_disconnect(xendev
, NULL
);
131 xen_block_dataplane_destroy(blockdev
->dataplane
);
132 blockdev
->dataplane
= NULL
;
134 if (blockdev_class
->unrealize
) {
135 blockdev_class
->unrealize(blockdev
, errp
);
139 static void xen_block_realize(XenDevice
*xendev
, Error
**errp
)
141 XenBlockDevice
*blockdev
= XEN_BLOCK_DEVICE(xendev
);
142 XenBlockDeviceClass
*blockdev_class
=
143 XEN_BLOCK_DEVICE_GET_CLASS(xendev
);
144 const char *type
= object_get_typename(OBJECT(blockdev
));
145 XenBlockVdev
*vdev
= &blockdev
->props
.vdev
;
146 BlockConf
*conf
= &blockdev
->props
.conf
;
147 Error
*local_err
= NULL
;
149 if (vdev
->type
== XEN_BLOCK_VDEV_TYPE_INVALID
) {
150 error_setg(errp
, "vdev property not set");
154 trace_xen_block_realize(type
, vdev
->disk
, vdev
->partition
);
156 if (blockdev_class
->realize
) {
157 blockdev_class
->realize(blockdev
, &local_err
);
159 error_propagate(errp
, local_err
);
165 * The blkif protocol does not deal with removable media, so it must
166 * always be present, even for CDRom devices.
169 if (!blk_is_inserted(conf
->blk
)) {
170 error_setg(errp
, "device needs media, but drive is empty");
174 if (!blkconf_apply_backend_options(conf
, blockdev
->info
& VDISK_READONLY
,
179 if (!(blockdev
->info
& VDISK_CDROM
) &&
180 !blkconf_geometry(conf
, NULL
, 65535, 255, 255, errp
)) {
184 blkconf_blocksizes(conf
);
186 if (conf
->logical_block_size
> conf
->physical_block_size
) {
188 errp
, "logical_block_size > physical_block_size not supported");
192 blk_set_guest_block_size(conf
->blk
, conf
->logical_block_size
);
194 if (conf
->discard_granularity
> 0) {
195 xen_device_backend_printf(xendev
, "feature-discard", "%u", 1);
198 xen_device_backend_printf(xendev
, "feature-flush-cache", "%u", 1);
199 xen_device_backend_printf(xendev
, "max-ring-page-order", "%u",
200 blockdev
->props
.max_ring_page_order
);
201 xen_device_backend_printf(xendev
, "info", "%u", blockdev
->info
);
203 xen_device_frontend_printf(xendev
, "virtual-device", "%lu",
205 xen_device_frontend_printf(xendev
, "device-type", "%s",
206 blockdev
->device_type
);
208 xen_device_backend_printf(xendev
, "sector-size", "%u",
209 conf
->logical_block_size
);
210 xen_device_backend_printf(xendev
, "sectors", "%lu",
211 blk_getlength(conf
->blk
) /
212 conf
->logical_block_size
);
214 blockdev
->dataplane
=
215 xen_block_dataplane_create(xendev
, conf
, blockdev
->props
.iothread
);
218 static void xen_block_frontend_changed(XenDevice
*xendev
,
219 enum xenbus_state frontend_state
,
222 enum xenbus_state backend_state
= xen_device_backend_get_state(xendev
);
223 Error
*local_err
= NULL
;
225 switch (frontend_state
) {
226 case XenbusStateInitialised
:
227 case XenbusStateConnected
:
228 if (backend_state
== XenbusStateConnected
) {
232 xen_block_disconnect(xendev
, &local_err
);
234 error_propagate(errp
, local_err
);
238 xen_block_connect(xendev
, &local_err
);
240 error_propagate(errp
, local_err
);
244 xen_device_backend_set_state(xendev
, XenbusStateConnected
);
247 case XenbusStateClosing
:
248 xen_device_backend_set_state(xendev
, XenbusStateClosing
);
251 case XenbusStateClosed
:
252 xen_block_disconnect(xendev
, &local_err
);
254 error_propagate(errp
, local_err
);
258 xen_device_backend_set_state(xendev
, XenbusStateClosed
);
266 static char *disk_to_vbd_name(unsigned int disk
)
268 char *name
, *prefix
= (disk
>= 26) ?
269 disk_to_vbd_name((disk
/ 26) - 1) : g_strdup("");
271 name
= g_strdup_printf("%s%c", prefix
, 'a' + disk
% 26);
277 static void xen_block_get_vdev(Object
*obj
, Visitor
*v
, const char *name
,
278 void *opaque
, Error
**errp
)
280 DeviceState
*dev
= DEVICE(obj
);
281 Property
*prop
= opaque
;
282 XenBlockVdev
*vdev
= qdev_get_prop_ptr(dev
, prop
);
285 switch (vdev
->type
) {
286 case XEN_BLOCK_VDEV_TYPE_DP
:
287 str
= g_strdup_printf("d%lup%lu", vdev
->disk
, vdev
->partition
);
290 case XEN_BLOCK_VDEV_TYPE_XVD
:
291 case XEN_BLOCK_VDEV_TYPE_HD
:
292 case XEN_BLOCK_VDEV_TYPE_SD
: {
293 char *name
= disk_to_vbd_name(vdev
->disk
);
295 str
= g_strdup_printf("%s%s%lu",
296 (vdev
->type
== XEN_BLOCK_VDEV_TYPE_XVD
) ?
298 (vdev
->type
== XEN_BLOCK_VDEV_TYPE_HD
) ?
301 name
, vdev
->partition
);
306 error_setg(errp
, "invalid vdev type");
310 visit_type_str(v
, name
, &str
, errp
);
314 static unsigned int vbd_name_to_disk(const char *name
, const char **endp
)
316 unsigned int disk
= 0;
318 while (*name
!= '\0') {
319 if (!g_ascii_isalpha(*name
) || !g_ascii_islower(*name
)) {
324 disk
+= *name
++ - 'a' + 1;
331 static void xen_block_set_vdev(Object
*obj
, Visitor
*v
, const char *name
,
332 void *opaque
, Error
**errp
)
334 DeviceState
*dev
= DEVICE(obj
);
335 Property
*prop
= opaque
;
336 XenBlockVdev
*vdev
= qdev_get_prop_ptr(dev
, prop
);
337 Error
*local_err
= NULL
;
342 qdev_prop_set_after_realize(dev
, name
, errp
);
346 visit_type_str(v
, name
, &str
, &local_err
);
348 error_propagate(errp
, local_err
);
352 p
= strchr(str
, 'd');
359 vdev
->type
= XEN_BLOCK_VDEV_TYPE_DP
;
360 } else if (strcmp(str
, "xv") == 0) {
361 vdev
->type
= XEN_BLOCK_VDEV_TYPE_XVD
;
362 } else if (strcmp(str
, "h") == 0) {
363 vdev
->type
= XEN_BLOCK_VDEV_TYPE_HD
;
364 } else if (strcmp(str
, "s") == 0) {
365 vdev
->type
= XEN_BLOCK_VDEV_TYPE_SD
;
370 if (vdev
->type
== XEN_BLOCK_VDEV_TYPE_DP
) {
371 if (qemu_strtoul(p
, &end
, 10, &vdev
->disk
)) {
382 vdev
->disk
= vbd_name_to_disk(p
, &end
);
388 if (qemu_strtoul(p
, &end
, 10, &vdev
->partition
)) {
399 switch (vdev
->type
) {
400 case XEN_BLOCK_VDEV_TYPE_DP
:
401 case XEN_BLOCK_VDEV_TYPE_XVD
:
402 if (vdev
->disk
< (1 << 4) && vdev
->partition
< (1 << 4)) {
403 vdev
->number
= (202 << 8) | (vdev
->disk
<< 4) |
405 } else if (vdev
->disk
< (1 << 20) && vdev
->partition
< (1 << 8)) {
406 vdev
->number
= (1 << 28) | (vdev
->disk
<< 8) |
413 case XEN_BLOCK_VDEV_TYPE_HD
:
414 if ((vdev
->disk
== 0 || vdev
->disk
== 1) &&
415 vdev
->partition
< (1 << 6)) {
416 vdev
->number
= (3 << 8) | (vdev
->disk
<< 6) | vdev
->partition
;
417 } else if ((vdev
->disk
== 2 || vdev
->disk
== 3) &&
418 vdev
->partition
< (1 << 6)) {
419 vdev
->number
= (22 << 8) | ((vdev
->disk
- 2) << 6) |
426 case XEN_BLOCK_VDEV_TYPE_SD
:
427 if (vdev
->disk
< (1 << 4) && vdev
->partition
< (1 << 4)) {
428 vdev
->number
= (8 << 8) | (vdev
->disk
<< 4) | vdev
->partition
;
442 error_setg(errp
, "invalid virtual disk specifier");
444 vdev
->type
= XEN_BLOCK_VDEV_TYPE_INVALID
;
449 * This property deals with 'vdev' names adhering to the Xen VBD naming
450 * scheme described in:
452 * https://xenbits.xen.org/docs/unstable/man/xen-vbd-interface.7.html
454 const PropertyInfo xen_block_prop_vdev
= {
456 .description
= "Virtual Disk specifier: d*p*/xvd*/hd*/sd*",
457 .get
= xen_block_get_vdev
,
458 .set
= xen_block_set_vdev
,
461 static Property xen_block_props
[] = {
462 DEFINE_PROP("vdev", XenBlockDevice
, props
.vdev
,
463 xen_block_prop_vdev
, XenBlockVdev
),
464 DEFINE_BLOCK_PROPERTIES(XenBlockDevice
, props
.conf
),
465 DEFINE_PROP_UINT32("max-ring-page-order", XenBlockDevice
,
466 props
.max_ring_page_order
, 4),
467 DEFINE_PROP_LINK("iothread", XenBlockDevice
, props
.iothread
,
468 TYPE_IOTHREAD
, IOThread
*),
469 DEFINE_PROP_END_OF_LIST()
472 static void xen_block_class_init(ObjectClass
*class, void *data
)
474 DeviceClass
*dev_class
= DEVICE_CLASS(class);
475 XenDeviceClass
*xendev_class
= XEN_DEVICE_CLASS(class);
477 xendev_class
->device
= "vbd";
478 xendev_class
->get_name
= xen_block_get_name
;
479 xendev_class
->realize
= xen_block_realize
;
480 xendev_class
->frontend_changed
= xen_block_frontend_changed
;
481 xendev_class
->unrealize
= xen_block_unrealize
;
483 dev_class
->props
= xen_block_props
;
486 static const TypeInfo xen_block_type_info
= {
487 .name
= TYPE_XEN_BLOCK_DEVICE
,
488 .parent
= TYPE_XEN_DEVICE
,
489 .instance_size
= sizeof(XenBlockDevice
),
491 .class_size
= sizeof(XenBlockDeviceClass
),
492 .class_init
= xen_block_class_init
,
495 static void xen_disk_unrealize(XenBlockDevice
*blockdev
, Error
**errp
)
497 trace_xen_disk_unrealize();
500 static void xen_disk_realize(XenBlockDevice
*blockdev
, Error
**errp
)
502 BlockConf
*conf
= &blockdev
->props
.conf
;
504 trace_xen_disk_realize();
506 blockdev
->device_type
= "disk";
509 error_setg(errp
, "drive property not set");
513 blockdev
->info
= blk_is_read_only(conf
->blk
) ? VDISK_READONLY
: 0;
516 static void xen_disk_class_init(ObjectClass
*class, void *data
)
518 DeviceClass
*dev_class
= DEVICE_CLASS(class);
519 XenBlockDeviceClass
*blockdev_class
= XEN_BLOCK_DEVICE_CLASS(class);
521 blockdev_class
->realize
= xen_disk_realize
;
522 blockdev_class
->unrealize
= xen_disk_unrealize
;
524 dev_class
->desc
= "Xen Disk Device";
527 static const TypeInfo xen_disk_type_info
= {
528 .name
= TYPE_XEN_DISK_DEVICE
,
529 .parent
= TYPE_XEN_BLOCK_DEVICE
,
530 .instance_size
= sizeof(XenDiskDevice
),
531 .class_init
= xen_disk_class_init
,
534 static void xen_cdrom_unrealize(XenBlockDevice
*blockdev
, Error
**errp
)
536 trace_xen_cdrom_unrealize();
539 static void xen_cdrom_realize(XenBlockDevice
*blockdev
, Error
**errp
)
541 BlockConf
*conf
= &blockdev
->props
.conf
;
543 trace_xen_cdrom_realize();
545 blockdev
->device_type
= "cdrom";
550 /* Set up an empty drive */
551 conf
->blk
= blk_new(0, BLK_PERM_ALL
);
553 rc
= blk_attach_dev(conf
->blk
, DEVICE(blockdev
));
555 error_setg_errno(errp
, -rc
, "failed to create drive");
560 blockdev
->info
= VDISK_READONLY
| VDISK_CDROM
;
563 static void xen_cdrom_class_init(ObjectClass
*class, void *data
)
565 DeviceClass
*dev_class
= DEVICE_CLASS(class);
566 XenBlockDeviceClass
*blockdev_class
= XEN_BLOCK_DEVICE_CLASS(class);
568 blockdev_class
->realize
= xen_cdrom_realize
;
569 blockdev_class
->unrealize
= xen_cdrom_unrealize
;
571 dev_class
->desc
= "Xen CD-ROM Device";
574 static const TypeInfo xen_cdrom_type_info
= {
575 .name
= TYPE_XEN_CDROM_DEVICE
,
576 .parent
= TYPE_XEN_BLOCK_DEVICE
,
577 .instance_size
= sizeof(XenCDRomDevice
),
578 .class_init
= xen_cdrom_class_init
,
581 static void xen_block_register_types(void)
583 type_register_static(&xen_block_type_info
);
584 type_register_static(&xen_disk_type_info
);
585 type_register_static(&xen_cdrom_type_info
);
588 type_init(xen_block_register_types
)