Message ID | 1349163209-19712-5-git-send-email-jfrei@linux.vnet.ibm.com |
---|---|
State | New |
Headers | show |
On 02.10.2012, at 09:33, Jens Freimann wrote: > From: Heinz Graalfs <graalfs@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 <graalfs@linux.vnet.ibm.com> > Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> > Signed-off-by: Jens Freimann <jfrei@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 <graalfs@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 >
On 12/10/12 02:36, Alexander Graf wrote: > > On 02.10.2012, at 09:33, Jens Freimann wrote: > >> From: Heinz Graalfs <graalfs@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? On my 390 systems it seems to shutdown, at least that happens on lpar and z/VM as well as under KVM.
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 <graalfs@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)