2
0

virtio-scsi-dataplane.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /*
  2. * Virtio SCSI dataplane
  3. *
  4. * Copyright Red Hat, Inc. 2014
  5. *
  6. * Authors:
  7. * Fam Zheng <famz@redhat.com>
  8. *
  9. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10. * See the COPYING file in the top-level directory.
  11. *
  12. */
  13. #include "qemu/osdep.h"
  14. #include "qapi/error.h"
  15. #include "hw/virtio/virtio-scsi.h"
  16. #include "qemu/error-report.h"
  17. #include "sysemu/block-backend.h"
  18. #include "hw/scsi/scsi.h"
  19. #include "scsi/constants.h"
  20. #include "hw/virtio/virtio-bus.h"
  21. #include "hw/virtio/virtio-access.h"
  22. /* Context: QEMU global mutex held */
  23. void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp)
  24. {
  25. VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
  26. VirtIODevice *vdev = VIRTIO_DEVICE(s);
  27. BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
  28. VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
  29. if (vs->conf.iothread) {
  30. if (!k->set_guest_notifiers || !k->ioeventfd_assign) {
  31. error_setg(errp,
  32. "device is incompatible with iothread "
  33. "(transport does not support notifiers)");
  34. return;
  35. }
  36. if (!virtio_device_ioeventfd_enabled(vdev)) {
  37. error_setg(errp, "ioeventfd is required for iothread");
  38. return;
  39. }
  40. s->ctx = iothread_get_aio_context(vs->conf.iothread);
  41. } else {
  42. if (!virtio_device_ioeventfd_enabled(vdev)) {
  43. return;
  44. }
  45. s->ctx = qemu_get_aio_context();
  46. }
  47. }
  48. static bool virtio_scsi_data_plane_handle_cmd(VirtIODevice *vdev,
  49. VirtQueue *vq)
  50. {
  51. bool progress;
  52. VirtIOSCSI *s = VIRTIO_SCSI(vdev);
  53. virtio_scsi_acquire(s);
  54. assert(s->ctx && s->dataplane_started);
  55. progress = virtio_scsi_handle_cmd_vq(s, vq);
  56. virtio_scsi_release(s);
  57. return progress;
  58. }
  59. static bool virtio_scsi_data_plane_handle_ctrl(VirtIODevice *vdev,
  60. VirtQueue *vq)
  61. {
  62. bool progress;
  63. VirtIOSCSI *s = VIRTIO_SCSI(vdev);
  64. virtio_scsi_acquire(s);
  65. assert(s->ctx && s->dataplane_started);
  66. progress = virtio_scsi_handle_ctrl_vq(s, vq);
  67. virtio_scsi_release(s);
  68. return progress;
  69. }
  70. static bool virtio_scsi_data_plane_handle_event(VirtIODevice *vdev,
  71. VirtQueue *vq)
  72. {
  73. bool progress;
  74. VirtIOSCSI *s = VIRTIO_SCSI(vdev);
  75. virtio_scsi_acquire(s);
  76. assert(s->ctx && s->dataplane_started);
  77. progress = virtio_scsi_handle_event_vq(s, vq);
  78. virtio_scsi_release(s);
  79. return progress;
  80. }
  81. static int virtio_scsi_vring_init(VirtIOSCSI *s, VirtQueue *vq, int n,
  82. VirtIOHandleAIOOutput fn)
  83. {
  84. BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s)));
  85. int rc;
  86. /* Set up virtqueue notify */
  87. rc = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), n, true);
  88. if (rc != 0) {
  89. fprintf(stderr, "virtio-scsi: Failed to set host notifier (%d)\n",
  90. rc);
  91. s->dataplane_fenced = true;
  92. return rc;
  93. }
  94. virtio_queue_aio_set_host_notifier_handler(vq, s->ctx, fn);
  95. return 0;
  96. }
  97. /* Context: BH in IOThread */
  98. static void virtio_scsi_dataplane_stop_bh(void *opaque)
  99. {
  100. VirtIOSCSI *s = opaque;
  101. VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
  102. int i;
  103. virtio_queue_aio_set_host_notifier_handler(vs->ctrl_vq, s->ctx, NULL);
  104. virtio_queue_aio_set_host_notifier_handler(vs->event_vq, s->ctx, NULL);
  105. for (i = 0; i < vs->conf.num_queues; i++) {
  106. virtio_queue_aio_set_host_notifier_handler(vs->cmd_vqs[i], s->ctx, NULL);
  107. }
  108. }
  109. /* Context: QEMU global mutex held */
  110. int virtio_scsi_dataplane_start(VirtIODevice *vdev)
  111. {
  112. int i;
  113. int rc;
  114. BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
  115. VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
  116. VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
  117. VirtIOSCSI *s = VIRTIO_SCSI(vdev);
  118. if (s->dataplane_started ||
  119. s->dataplane_starting ||
  120. s->dataplane_fenced) {
  121. return 0;
  122. }
  123. s->dataplane_starting = true;
  124. /* Set up guest notifier (irq) */
  125. rc = k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, true);
  126. if (rc != 0) {
  127. error_report("virtio-scsi: Failed to set guest notifiers (%d), "
  128. "ensure -accel kvm is set.", rc);
  129. goto fail_guest_notifiers;
  130. }
  131. aio_context_acquire(s->ctx);
  132. rc = virtio_scsi_vring_init(s, vs->ctrl_vq, 0,
  133. virtio_scsi_data_plane_handle_ctrl);
  134. if (rc) {
  135. goto fail_vrings;
  136. }
  137. rc = virtio_scsi_vring_init(s, vs->event_vq, 1,
  138. virtio_scsi_data_plane_handle_event);
  139. if (rc) {
  140. goto fail_vrings;
  141. }
  142. for (i = 0; i < vs->conf.num_queues; i++) {
  143. rc = virtio_scsi_vring_init(s, vs->cmd_vqs[i], i + 2,
  144. virtio_scsi_data_plane_handle_cmd);
  145. if (rc) {
  146. goto fail_vrings;
  147. }
  148. }
  149. s->dataplane_starting = false;
  150. s->dataplane_started = true;
  151. aio_context_release(s->ctx);
  152. return 0;
  153. fail_vrings:
  154. aio_wait_bh_oneshot(s->ctx, virtio_scsi_dataplane_stop_bh, s);
  155. aio_context_release(s->ctx);
  156. for (i = 0; i < vs->conf.num_queues + 2; i++) {
  157. virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false);
  158. virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i);
  159. }
  160. k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, false);
  161. fail_guest_notifiers:
  162. s->dataplane_fenced = true;
  163. s->dataplane_starting = false;
  164. s->dataplane_started = true;
  165. return -ENOSYS;
  166. }
  167. /* Context: QEMU global mutex held */
  168. void virtio_scsi_dataplane_stop(VirtIODevice *vdev)
  169. {
  170. BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
  171. VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
  172. VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
  173. VirtIOSCSI *s = VIRTIO_SCSI(vdev);
  174. int i;
  175. if (!s->dataplane_started || s->dataplane_stopping) {
  176. return;
  177. }
  178. /* Better luck next time. */
  179. if (s->dataplane_fenced) {
  180. s->dataplane_fenced = false;
  181. s->dataplane_started = false;
  182. return;
  183. }
  184. s->dataplane_stopping = true;
  185. aio_context_acquire(s->ctx);
  186. aio_wait_bh_oneshot(s->ctx, virtio_scsi_dataplane_stop_bh, s);
  187. aio_context_release(s->ctx);
  188. blk_drain_all(); /* ensure there are no in-flight requests */
  189. for (i = 0; i < vs->conf.num_queues + 2; i++) {
  190. virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false);
  191. virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i);
  192. }
  193. /* Clean up guest notifier (irq) */
  194. k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, false);
  195. s->dataplane_stopping = false;
  196. s->dataplane_started = false;
  197. }