On 02.10.2012, at 09:33, Jens Freimann wrote: > From: Heinz Graalfs <graa...@linux.vnet.ibm.com> > > This implements the sclp signal quiesce event via the SCLP Event > Facility. > This allows to gracefully shutdown a guest by using system_powerdown > notifiers. It creates a service interrupt that will trigger a > Read Event Data command from the guest. This code will then add an > event that is interpreted by linux guests as ctrl-alt-del.
Doesn't ctrl-alt-del usually reboot the machine, not shut it down? Alex > > Signed-off-by: Heinz Graalfs <graa...@linux.vnet.ibm.com> > Signed-off-by: Christian Borntraeger <borntrae...@de.ibm.com> > Signed-off-by: Jens Freimann <jf...@linux.vnet.ibm.com> > --- > hw/s390x/Makefile.objs | 1 + > hw/s390x/event-facility.c | 7 +++ > hw/s390x/sclpquiesce.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 131 insertions(+) > create mode 100644 hw/s390x/sclpquiesce.c > > diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs > index b32fc52..ed4e61a 100644 > --- a/hw/s390x/Makefile.objs > +++ b/hw/s390x/Makefile.objs > @@ -3,3 +3,4 @@ obj-y = s390-virtio-bus.o s390-virtio.o > obj-y := $(addprefix ../,$(obj-y)) > obj-y += sclp.o > obj-y += event-facility.o > +obj-y += sclpquiesce.o > diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c > index 1108e2d..9367660 100644 > --- a/hw/s390x/event-facility.c > +++ b/hw/s390x/event-facility.c > @@ -315,6 +315,7 @@ static void command_handler(SCLPEventFacility *ef, SCCB > *sccb, uint64_t code) > static int init_event_facility(S390SCLPDevice *sdev) > { > SCLPEventFacility *event_facility; > + DeviceState *quiesce; > > event_facility = g_malloc0(sizeof(SCLPEventFacility)); > sdev->ef = event_facility; > @@ -327,6 +328,12 @@ static int init_event_facility(S390SCLPDevice *sdev) > event_facility->sbus.qbus.allow_hotplug = 0; > event_facility->qdev = (DeviceState *) sdev; > > + quiesce = qdev_create(&event_facility->sbus.qbus, "sclpquiesce"); > + if (!quiesce) { > + return -1; > + } > + qdev_init_nofail(quiesce); > + > return 0; > } > > diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c > new file mode 100644 > index 0000000..9a773b8 > --- /dev/null > +++ b/hw/s390x/sclpquiesce.c > @@ -0,0 +1,123 @@ > +/* > + * SCLP event type > + * Signal Quiesce - trigger system powerdown request > + * > + * Copyright IBM, Corp. 2012 > + * > + * Authors: > + * Heinz Graalfs <graa...@de.ibm.com> > + * > + * This work is licensed under the terms of the GNU GPL, version 2 or (at > your > + * option) any later version. See the COPYING file in the top-level > directory. > + * > + */ > +#include <hw/qdev.h> > +#include "sysemu.h" > +#include "sclp.h" > +#include "event-facility.h" > + > +typedef struct SignalQuiesce { > + EventBufferHeader ebh; > + uint16_t timeout; > + uint8_t unit; > +} QEMU_PACKED SignalQuiesce; > + > +static int event_type(void) > +{ > + return SCLP_EVENT_SIGNAL_QUIESCE; > +} > + > +static unsigned int send_mask(void) > +{ > + return SCLP_EVENT_MASK_SIGNAL_QUIESCE; > +} > + > +static unsigned int receive_mask(void) > +{ > + return 0; > +} > + > +static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, > + int *slen) > +{ > + SignalQuiesce *sq = (SignalQuiesce *) evt_buf_hdr; > + > + if (*slen < sizeof(SignalQuiesce)) { > + return 0; > + } > + > + if (!event->event_pending) { > + return 0; > + } > + event->event_pending = false; > + > + sq->ebh.length = cpu_to_be16(sizeof(SignalQuiesce)); > + sq->ebh.type = SCLP_EVENT_SIGNAL_QUIESCE; > + sq->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED; > + /* > + * system_powerdown does not have a timeout. Fortunately the > + * timeout value is currently ignored by Linux, anyway > + */ > + sq->timeout = cpu_to_be16(0); > + sq->unit = cpu_to_be16(0); > + *slen -= sizeof(SignalQuiesce); > + > + return 1; > +} > + > +typedef struct QuiesceNotifier QuiesceNotifier; > + > +static struct QuiesceNotifier { > + Notifier notifier; > + SCLPEvent *event; > +} qn; > + > +static void quiesce_powerdown_req(Notifier *n, void *opaque) > +{ > + QuiesceNotifier *qn = container_of(n, QuiesceNotifier, notifier); > + SCLPEvent *event = qn->event; > + > + event->event_pending = true; > + /* trigger SCLP read operation */ > + sclp_service_interrupt(0); > +} > + > +static int quiesce_init(SCLPEvent *event) > +{ > + event->event_type = SCLP_EVENT_SIGNAL_QUIESCE; > + > + qn.notifier.notify = quiesce_powerdown_req; > + qn.event = event; > + > + qemu_register_powerdown_notifier(&qn.notifier); > + > + return 0; > +} > + > +static void quiesce_class_init(ObjectClass *klass, void *data) > +{ > + SCLPEventClass *k = SCLP_EVENT_CLASS(klass); > + > + k->init = quiesce_init; > + > + k->get_send_mask = send_mask; > + k->get_receive_mask = receive_mask; > + k->event_type = event_type; > + k->read_event_data = read_event_data; > + k->write_event_data = NULL; > +} > + > +static TypeInfo sclp_quiesce_info = { > + .name = "sclpquiesce", > + .parent = TYPE_SCLP_EVENT, > + .instance_size = sizeof(SCLPEvent), > + .class_init = quiesce_class_init, > + .class_size = sizeof(SCLPEventClass), > +}; > + > +static void register_types(void) > +{ > + type_register_static(&sclp_quiesce_info); > +} > + > +type_init(register_types) > -- > 1.7.11.7 >