Skip to content

Commit

Permalink
s390: sclp signal quiesce support
Browse files Browse the repository at this point in the history
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.

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>
Signed-off-by: Alexander Graf <agraf@suse.de>
  • Loading branch information
Heinz Graalfs authored and agraf committed Oct 29, 2012
1 parent 559a17a commit ab9074b
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 0 deletions.
1 change: 1 addition & 0 deletions hw/s390x/Makefile.objs
Expand Up @@ -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
7 changes: 7 additions & 0 deletions hw/s390x/event-facility.c
Expand Up @@ -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;
Expand All @@ -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;
}

Expand Down
123 changes: 123 additions & 0 deletions 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)

0 comments on commit ab9074b

Please sign in to comment.