vfio_ccw_fsm.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*
  2. * Finite state machine for vfio-ccw device handling
  3. *
  4. * Copyright IBM Corp. 2017
  5. *
  6. * Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com>
  7. */
  8. #include <linux/vfio.h>
  9. #include <linux/mdev.h>
  10. #include "ioasm.h"
  11. #include "vfio_ccw_private.h"
  12. static int fsm_io_helper(struct vfio_ccw_private *private)
  13. {
  14. struct subchannel *sch;
  15. union orb *orb;
  16. int ccode;
  17. __u8 lpm;
  18. unsigned long flags;
  19. sch = private->sch;
  20. spin_lock_irqsave(sch->lock, flags);
  21. private->state = VFIO_CCW_STATE_BUSY;
  22. spin_unlock_irqrestore(sch->lock, flags);
  23. orb = cp_get_orb(&private->cp, (u32)(addr_t)sch, sch->lpm);
  24. /* Issue "Start Subchannel" */
  25. ccode = ssch(sch->schid, orb);
  26. switch (ccode) {
  27. case 0:
  28. /*
  29. * Initialize device status information
  30. */
  31. sch->schib.scsw.cmd.actl |= SCSW_ACTL_START_PEND;
  32. return 0;
  33. case 1: /* Status pending */
  34. case 2: /* Busy */
  35. return -EBUSY;
  36. case 3: /* Device/path not operational */
  37. {
  38. lpm = orb->cmd.lpm;
  39. if (lpm != 0)
  40. sch->lpm &= ~lpm;
  41. else
  42. sch->lpm = 0;
  43. if (cio_update_schib(sch))
  44. return -ENODEV;
  45. return sch->lpm ? -EACCES : -ENODEV;
  46. }
  47. default:
  48. return ccode;
  49. }
  50. }
  51. static void fsm_notoper(struct vfio_ccw_private *private,
  52. enum vfio_ccw_event event)
  53. {
  54. struct subchannel *sch = private->sch;
  55. /*
  56. * TODO:
  57. * Probably we should send the machine check to the guest.
  58. */
  59. css_sched_sch_todo(sch, SCH_TODO_UNREG);
  60. private->state = VFIO_CCW_STATE_NOT_OPER;
  61. }
  62. /*
  63. * No operation action.
  64. */
  65. static void fsm_nop(struct vfio_ccw_private *private,
  66. enum vfio_ccw_event event)
  67. {
  68. }
  69. static void fsm_io_error(struct vfio_ccw_private *private,
  70. enum vfio_ccw_event event)
  71. {
  72. pr_err("vfio-ccw: FSM: I/O request from state:%d\n", private->state);
  73. private->io_region.ret_code = -EIO;
  74. }
  75. static void fsm_io_busy(struct vfio_ccw_private *private,
  76. enum vfio_ccw_event event)
  77. {
  78. private->io_region.ret_code = -EBUSY;
  79. }
  80. static void fsm_disabled_irq(struct vfio_ccw_private *private,
  81. enum vfio_ccw_event event)
  82. {
  83. struct subchannel *sch = private->sch;
  84. /*
  85. * An interrupt in a disabled state means a previous disable was not
  86. * successful - should not happen, but we try to disable again.
  87. */
  88. cio_disable_subchannel(sch);
  89. }
  90. /*
  91. * Deal with the ccw command request from the userspace.
  92. */
  93. static void fsm_io_request(struct vfio_ccw_private *private,
  94. enum vfio_ccw_event event)
  95. {
  96. union orb *orb;
  97. union scsw *scsw = &private->scsw;
  98. struct ccw_io_region *io_region = &private->io_region;
  99. struct mdev_device *mdev = private->mdev;
  100. private->state = VFIO_CCW_STATE_BOXED;
  101. memcpy(scsw, io_region->scsw_area, sizeof(*scsw));
  102. if (scsw->cmd.fctl & SCSW_FCTL_START_FUNC) {
  103. orb = (union orb *)io_region->orb_area;
  104. io_region->ret_code = cp_init(&private->cp, mdev_dev(mdev),
  105. orb);
  106. if (io_region->ret_code)
  107. goto err_out;
  108. io_region->ret_code = cp_prefetch(&private->cp);
  109. if (io_region->ret_code) {
  110. cp_free(&private->cp);
  111. goto err_out;
  112. }
  113. /* Start channel program and wait for I/O interrupt. */
  114. io_region->ret_code = fsm_io_helper(private);
  115. if (io_region->ret_code) {
  116. cp_free(&private->cp);
  117. goto err_out;
  118. }
  119. return;
  120. } else if (scsw->cmd.fctl & SCSW_FCTL_HALT_FUNC) {
  121. /* XXX: Handle halt. */
  122. io_region->ret_code = -EOPNOTSUPP;
  123. goto err_out;
  124. } else if (scsw->cmd.fctl & SCSW_FCTL_CLEAR_FUNC) {
  125. /* XXX: Handle clear. */
  126. io_region->ret_code = -EOPNOTSUPP;
  127. goto err_out;
  128. }
  129. err_out:
  130. private->state = VFIO_CCW_STATE_IDLE;
  131. }
  132. /*
  133. * Got an interrupt for a normal io (state busy).
  134. */
  135. static void fsm_irq(struct vfio_ccw_private *private,
  136. enum vfio_ccw_event event)
  137. {
  138. struct irb *irb = this_cpu_ptr(&cio_irb);
  139. memcpy(&private->irb, irb, sizeof(*irb));
  140. queue_work(vfio_ccw_work_q, &private->io_work);
  141. if (private->completion)
  142. complete(private->completion);
  143. }
  144. /*
  145. * Device statemachine
  146. */
  147. fsm_func_t *vfio_ccw_jumptable[NR_VFIO_CCW_STATES][NR_VFIO_CCW_EVENTS] = {
  148. [VFIO_CCW_STATE_NOT_OPER] = {
  149. [VFIO_CCW_EVENT_NOT_OPER] = fsm_nop,
  150. [VFIO_CCW_EVENT_IO_REQ] = fsm_io_error,
  151. [VFIO_CCW_EVENT_INTERRUPT] = fsm_disabled_irq,
  152. },
  153. [VFIO_CCW_STATE_STANDBY] = {
  154. [VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper,
  155. [VFIO_CCW_EVENT_IO_REQ] = fsm_io_error,
  156. [VFIO_CCW_EVENT_INTERRUPT] = fsm_irq,
  157. },
  158. [VFIO_CCW_STATE_IDLE] = {
  159. [VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper,
  160. [VFIO_CCW_EVENT_IO_REQ] = fsm_io_request,
  161. [VFIO_CCW_EVENT_INTERRUPT] = fsm_irq,
  162. },
  163. [VFIO_CCW_STATE_BOXED] = {
  164. [VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper,
  165. [VFIO_CCW_EVENT_IO_REQ] = fsm_io_busy,
  166. [VFIO_CCW_EVENT_INTERRUPT] = fsm_irq,
  167. },
  168. [VFIO_CCW_STATE_BUSY] = {
  169. [VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper,
  170. [VFIO_CCW_EVENT_IO_REQ] = fsm_io_busy,
  171. [VFIO_CCW_EVENT_INTERRUPT] = fsm_irq,
  172. },
  173. };