Subject: [PATCH/RFC 4/5] s390 zlive service processor calls

From: Carsten Otte <[EMAIL PROTECTED]>
From: Martin Peschke <[EMAIL PROTECTED]>

This patch adds support for calls to our service processor
o infrastructure that handles sclp calls
o infrastructure for sclp events
o sclp handlers

This is not a complete set of service calls, it implements only the minimal
set needed to run a Linux kernel in the virtual machine.

Signed-off-by: Carsten Otte <[EMAIL PROTECTED]>
---
 include/zlsclp.h      |  157 ++++++++++++++++++++++++++++++++
 sclp/Makefile         |   25 +++++
 sclp/event_facility.c |  239 ++++++++++++++++++++++++++++++++++++++++++++++++++
 sclp/sclp.c           |   92 +++++++++++++++++++
 sclp/scp_read_info.c  |   46 +++++++++
 sclp/signal_quiesce.c |   45 +++++++++
 6 files changed, 604 insertions(+)

Index: zlive/include/zlsclp.h
===================================================================
--- /dev/null
+++ zlive/include/zlsclp.h
@@ -0,0 +1,157 @@
+/*
+ * z/Live service call header file
+ * Copyright IBM Corp. 2007
+ * Author: Carsten Otte <[EMAIL PROTECTED]>
+ *
+ * This file is licensed under the terms of the GNU General Public License(GPL)
+ */
+
+#ifndef __ZLSCLP_H
+#define __ZLSCLP_H
+#include <zllist.h>
+#include <zlcpu.h>
+#include <stdint.h>
+
+#define SCLP_SCCB_ADDRESS_BITS                 0x7ffffff8
+
+typedef int (*sclp_handler_t)(struct zlcpu *cpu, uint32_t _sccb);
+
+// SCLP command codes
+#define SCLP_CMD_SCP_READ_INFO                 0x00020001
+#define SCLP_CMD_SCP_READ_INFO_FORCE           0x00120001
+#define SCLP_CMD_WRITE_EVENT_DATA              0x00760005
+#define SCLP_CMD_READ_EVENT_DATA               0x00770005
+#define SCLP_CMD_WRITE_EVENT_MASK              0x00780005
+
+// SCLP response codes
+// FIXME: xxx means: do we ever need/want to check for this condition?
+#define SCLP_RC_NORMAL_COMPLETION              0x0020
+#define SCLP_RC_SCLP_EQUIPMENT_CHECK           0x0040
+#define SCLP_RC_SCCB_BOUNDARY_VIOLATION                0x0100  // xxx
+#define SCLP_RC_INVALID_COMMAND                        0x01f0
+#define SCLP_RC_SOME_EVENTS_SUPPRESSED         0x0220  // naming?
+#define SCLP_RC_INSUFFICIENT_SCCB_LENGTH       0x0300
+#define SCLP_RC_CONTAINED_SCLP_EQUIPMENT_CHECK 0X0340
+#define SCLP_RC_TARGET_IN_IMPROPER_STATE       0x05f0
+#define SCLP_RC_INVALID_FUNCTION               0x40f0
+#define SCLP_RC_NO_EVENT_BUFFERS_STORED                0x60f0  // naming?
+#define SCLP_RC_EVENT_BUFFERS_SUPPRESSED       0x62f0  // naming?
+#define SCLP_RC_INVALID_SELECTION_MASK         0x70f0
+#define SCLP_RC_OUT_OF_MEMORY                  0X71f0  // xxx
+#define SCLP_RC_INCONSISTENT_LENGTHS           0x72f0
+#define SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR      0x73f0
+#define SCLP_RC_INVALID_MASK_LENGTH            0x74f0
+#define SCLP_RC_INVALID_EVENT_BUFFER_NUMBER    0x76f0  // xxx
+
+// SCLP event types (event facilities)
+#define SCLP_EVENT_STATE_CHANGE                        0x08
+#define SCLP_EVENT_ASCII_CONSOLE               0x1a
+#define SCLP_EVENT_SIGNAL_QUIESCE              0x1d
+
+// SCLP event masks (event facilities)
+#define SCLP_EVENT_MASK_STATE_CHANGE           0x01000000
+#define SCLP_EVENT_MASK_ASCII_CONSOLE          0x00000040
+#define SCLP_EVENT_MASK_SIGNAL_QUIESCE         0x00000008
+
+#define SCLP_UNCONDITIONAL_READ                        0x00
+#define SCLP_SELECTIVE_READ                    0x01
+
+#define SCLP_VARIABLE_LENGTH_RESPONSE          0x80
+
+#define SCCB_SIZE 4096
+
+#define SCLP_EVENT_DATA_PENDING_INDICATOR      0x00000001
+
+// Service Call Control Block (SCCB) and its elements
+struct sccb_header {
+       uint16_t        length;
+       uint8_t         function_code;
+       uint8_t         control_mask[3];
+       uint16_t        response_code;
+} __attribute__((packed));
+
+struct sccb_scp_read_info {
+       struct sccb_header      header;
+       uint16_t                mem_code;
+       uint8_t                 increment;
+} __attribute__((packed));
+
+typedef uint32_t sccb_control_mask_t;
+
+struct sccb_write_event_mask {
+       struct sccb_header      header;
+       uint16_t                _reserved;
+       uint16_t                mask_length;
+       sccb_control_mask_t     cp_receive_mask;
+       sccb_control_mask_t     cp_send_mask;
+       sccb_control_mask_t     sclp_send_mask;
+       sccb_control_mask_t     sclp_receive_mask;
+} __attribute__((packed));
+
+#define SCCB_UNCONDITIONAL_READ_BUFSIZE \
+       (SCCB_SIZE - sizeof(struct sccb_header))
+#define SCCB_SELECTIVE_READ_BUFSIZE \
+       (SCCB_SIZE - (sizeof(struct sccb_header) + sizeof(sccb_control_mask_t)))
+
+struct sccb_read_event_data{
+       struct sccb_header      header;
+       union {
+               struct {
+                       char buf[SCCB_UNCONDITIONAL_READ_BUFSIZE];
+               } unconditional;
+               struct {
+                       sccb_control_mask_t mask;
+                       char buf[SCCB_SELECTIVE_READ_BUFSIZE];
+               } selective;
+       } function;
+} __attribute__((packed));
+
+struct sclp_call_register {
+       struct zllist head;
+       uint64_t sclp_code;
+       sclp_handler_t handler;
+};
+
+void sclp_register (struct sclp_call_register *scr);
+void sclp_interrupt (uint32_t extint_param);
+
+// starting at byte 8 of SCCB
+struct event_buffer_header {
+       uint16_t        length;
+       uint8_t         type;
+#define SCLP_EVENT_BUFFER_ACCEPTED     0x80
+       uint8_t         flags;
+       uint16_t        _reserved;
+} __attribute__((packed));
+
+struct sclp_event_types {
+       struct zllist head;
+       sccb_control_mask_t send_mask;
+       sccb_control_mask_t receive_mask;
+       uint16_t (*send) (void *__event, uint16_t length);
+       uint16_t (*receive) (struct event_buffer_header *event);
+};
+
+void sclp_register_event(struct sclp_event_types *types);
+int sclp_send_event(struct zlcpu *cpu, struct event_buffer_header *event);
+
+struct event_buffer_ascii_console_read {
+       struct event_buffer_header      header;
+#define SCLP_ASCII_CONSOLE_DATA                0x00
+#define SCLP_ASCII_CONSOLE_END         0x01
+#define SCLP_ASCII_CONSOLE_START       0x80
+       uint8_t                         type;
+       char                            data[0];
+} __attribute__((packed));
+
+struct event_buffer_signal_quiesce {
+       struct event_buffer_header      header;
+       uint16_t                        timeout;
+#define SCLP_SIGNAL_QUIESCE_SECONDS    0
+#define SCLP_SIGNAL_QUIESCE_MINUTES    1
+#define SCLP_SIGNAL_QUIESCE_HOURS      2
+       uint8_t                         unit;
+} __attribute__((packed));
+
+void init_sclp(void);
+#endif
Index: zlive/sclp/Makefile
===================================================================
--- /dev/null
+++ zlive/sclp/Makefile
@@ -0,0 +1,25 @@
+# z/Live sclp calls makefile
+# Copyright IBM Corp. 2007
+# Author: Carsten Otte <[EMAIL PROTECTED]>
+# This file is licensed under the terms of the GNU General Public License(GPL)
+
+%.o : %.c ; echo "     Compiling       " $<; $(CC) $(CFLAGS) -c $<
+
+OBJS := sclp.o sclp_autoinit.o scp_read_info.o event_facility.o 
signal_quiesce.o
+
+all: $(OBJS)
+clean:
+       rm -f $(OBJS) sclp_autoinit.c
+
+sclp_autoinit.c: scp_read_info.c event_facility.c signal_quiesce.c
+       echo "  Creating        " $@
+       echo "//Makefile generated" >$@
+       echo "#define __ZLAUTOINIT(f) void f(void);" >>$@
+       cat $^ |grep __ZLAUTOINIT >>$@
+       echo "#undef __ZLAUTOINIT" >>$@
+       echo "#define __ZLAUTOINIT(f) { f(); };" >>$@
+       echo "void autoinit_sclp(void) {" >>$@
+       cat $^ |grep __ZLAUTOINIT >>$@
+       echo "}" >>$@
+
+.PHONY: clean all
Index: zlive/sclp/event_facility.c
===================================================================
--- /dev/null
+++ zlive/sclp/event_facility.c
@@ -0,0 +1,239 @@
+/*
+ * z/Live sclp event facility
+ * Copyright IBM Corp. 2007
+ * Author: Martin Peschke <[EMAIL PROTECTED]>
+ *
+ * This file is licensed under the terms of the GNU General Public License(GPL)
+ */
+
+#include <string.h>
+
+#include <zlintercept.h>
+#include <zlglobals.h>
+#include <zlautoinit.h>
+#include <zlsclp.h>
+#include <zlcpu.h>
+#include <zlcpu_lib.h>
+
+// SCLP is capable of providing event buffers of these types to program
+sccb_control_mask_t    sclp_send_mask;
+// SCLP accepts event buffers of these types from program
+sccb_control_mask_t    sclp_receive_mask;
+// program is capable of providing event buffers of these types to SCLP
+sccb_control_mask_t    sclp_cp_send_mask;
+// program accepts event buffers of these types from SCLP
+sccb_control_mask_t    sclp_cp_receive_mask;
+// active_selection_mask ??
+sccb_control_mask_t    sclp_active_selection_mask;
+
+struct zllist sclp_event_types_list;
+
+void sclp_register_event(struct sclp_event_types *types)
+{
+       zllist_add((struct zllist *)types, &sclp_event_types_list);
+       sclp_send_mask |= types->send_mask;
+       sclp_receive_mask |= types->receive_mask;
+       debug("sclp: registered event types (send 0x%x, receive 0x%x)", 
types->send_mask, types->receive_mask);
+       /* FIXME: requires state change event??? */
+       return;
+}
+
+static int sclp_write_event(struct event_buffer_header *event)
+{
+       struct zllist *entry;
+       struct sclp_event_types *types;
+       sccb_control_mask_t mask;
+
+       debug("got event, buffer 0x%p length 0x%d", event, event->length);
+       //FIXME: check event buffer
+       if (event->length < sizeof(struct event_buffer_header))
+               return SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR;
+
+       mask = 0x80000000 >> (event->type - 1);
+       if (!(sclp_receive_mask & mask)) {
+               log("sclp: skipping event disabled in sclp receive mask "
+                   "(event mask 0x%x, receive mask 0x%x)",
+                   mask, sclp_receive_mask);
+               return SCLP_RC_INVALID_FUNCTION;
+       }
+
+       for (entry = sclp_event_types_list.next;
+            entry != &sclp_event_types_list;
+            entry = entry->next) {
+               types = (struct sclp_event_types *)entry;
+               if (types->receive_mask & mask) {
+                       log("sclp: receiving event (event mask 0x%x)", mask);
+                       return types->receive(event);
+               }
+       }
+       return SCLP_RC_INVALID_FUNCTION; /* keeping compiler happy,
+                                           case covered by check above */
+}
+
+static int sclp_write_event_data(struct zlcpu *cpu, uint32_t _sccb)
+{
+       struct sccb_header *sccb = (void *)(_sccb + glo_origin);
+       struct event_buffer_header *event;
+       signed int size;
+
+       /* just checking */
+       for (size = sccb->length - sizeof(struct sccb_header),
+            event = (void *)sccb + sizeof(struct sccb_header);
+            size > 0 && size >= event->length;
+            size -= event->length, event = (void *)event + event->length);
+       if (size < 0)
+               sccb->response_code = SCLP_RC_INCONSISTENT_LENGTHS;
+
+       for (size = sccb->length - sizeof(struct sccb_header),
+            event = (void *)sccb + sizeof(struct sccb_header);
+            size > 0 && size >= event->length;
+            size -= event->length, event = (void *)event + event->length) {
+               sccb->response_code = sclp_write_event(event);
+               if (!(event->flags & SCLP_EVENT_BUFFER_ACCEPTED))
+                       break;
+       }
+       debug("response code 0x%02x", sccb->response_code);
+       setcc(cpu, 0);
+       sclp_interrupt(_sccb);
+       return may_do_cpu_work(cpu);
+}
+
+static int sclp_read_event_data(struct zlcpu *cpu, uint32_t _sccb)
+{
+       struct sccb_read_event_data *sccb = (void *)(_sccb + glo_origin);
+       struct zllist *entry;
+       struct sclp_event_types *types;
+       struct event_buffer_header *event;
+       signed int retval;
+       uint16_t space;
+
+       if (sccb->header.length != SCCB_SIZE) {
+               sccb->header.response_code = SCLP_RC_INSUFFICIENT_SCCB_LENGTH;
+               goto out;
+       }
+
+       switch (sccb->header.function_code) {
+       case SCLP_UNCONDITIONAL_READ:
+               sclp_active_selection_mask = sclp_cp_receive_mask;
+               event = (struct event_buffer_header 
*)sccb->function.unconditional.buf;
+               space = SCCB_UNCONDITIONAL_READ_BUFSIZE;
+               break;
+       case SCLP_SELECTIVE_READ:
+               if (!(sclp_cp_receive_mask & sccb->function.selective.mask)) {
+                       sccb->header.response_code = 
SCLP_RC_INVALID_SELECTION_MASK;
+                       goto out;
+               }
+               sclp_active_selection_mask = sccb->function.selective.mask;
+               event = (struct event_buffer_header 
*)sccb->function.selective.buf;
+               space = SCCB_SELECTIVE_READ_BUFSIZE;
+               break;
+       default:
+               sccb->header.response_code = SCLP_RC_INVALID_FUNCTION;
+               goto out;
+       }
+
+       sccb->header.response_code = SCLP_RC_NO_EVENT_BUFFERS_STORED;
+
+       for (entry = sclp_event_types_list.next;
+            entry != &sclp_event_types_list;
+            entry = entry->next) {
+               types = (struct sclp_event_types *)entry;
+               if (sccb->header.function_code == SCLP_SELECTIVE_READ &&
+                   // requires a single event bit set per type
+                   types->send_mask & sclp_active_selection_mask)
+                       continue;
+               retval = types->send(event, space);
+               if (retval == SCLP_RC_NORMAL_COMPLETION) {
+                       sccb->header.response_code = SCLP_RC_NORMAL_COMPLETION;
+                       // FIXME: assumption: not more than a single buffer 
stored
+                       event = (void *)event + event->length;
+                       space -= event->length;
+                       // FIXME: indicating more buffers though this is just 
an assumption
+                       if (!space) {
+                               _sccb |= SCLP_EVENT_DATA_PENDING_INDICATOR;
+                               break;
+                       }
+               } else if (retval == SCLP_RC_NO_EVENT_BUFFERS_STORED) {
+                       log("no buffers available (mask 0x%x)", 
types->send_mask);
+               } else {
+
+               }
+       }
+
+       // FIXME: suppressed buffers
+
+       if (sccb->header.control_mask[2] & SCLP_VARIABLE_LENGTH_RESPONSE) {
+               sccb->header.control_mask[2] &= ~SCLP_VARIABLE_LENGTH_RESPONSE;
+               sccb->header.length = ((char *)event + event->length) - (char 
*)sccb;
+       }
+out:
+       setcc(cpu, 0);
+       sclp_interrupt(_sccb);
+       return may_do_cpu_work(cpu);
+}
+
+static int sclp_write_event_mask(struct zlcpu *cpu, uint32_t _sccb)
+{
+       struct sccb_write_event_mask *sccb = (void *)(_sccb + glo_origin);
+
+       /* Attention: We assume that Linux uses 4-byte masks, what it actually
+          does. Architecture allows for masks of variable size, though */
+       if (sccb->mask_length != sizeof(sccb_control_mask_t)) {
+               sccb->header.response_code = SCLP_RC_INVALID_MASK_LENGTH;
+               goto out;
+       }
+
+       /* keep track of the guest's capability masks */
+       sclp_cp_send_mask = sccb->cp_send_mask;
+       sclp_cp_receive_mask = sccb->cp_receive_mask;
+       /* CP receive mask becomes active selection mask */
+       sclp_active_selection_mask = sclp_cp_receive_mask;
+       /* return the SCLP's capability masks to the guest */
+       sccb->sclp_send_mask = sclp_send_mask;
+       sccb->sclp_receive_mask = sclp_receive_mask;
+       sccb->header.response_code = SCLP_RC_NORMAL_COMPLETION;
+
+       debug("sclp, write event mask: control-program send mask 0x%08x",
+             sclp_cp_send_mask);
+       debug("sclp, write event mask: control-program receive mask 0x%08x",
+             sclp_cp_receive_mask);
+       debug("sclp, write event mask: sclp send mask 0x%08x",
+             sclp_send_mask);
+       debug("sclp, write event mask: sclp receive mask 0x%08x",
+             sclp_receive_mask);
+
+out:
+       debug("sclp, write event mask: response code 0x%02x",
+             sccb->header.response_code);
+
+       setcc(cpu, 0);
+       sclp_interrupt(_sccb);
+
+       return may_do_cpu_work(cpu);
+}
+
+static struct sclp_call_register sclp_write_event_data_register = {
+       .sclp_code = SCLP_CMD_WRITE_EVENT_DATA,
+       .handler   = sclp_write_event_data
+};
+
+static struct sclp_call_register sclp_read_event_data_register = {
+       .sclp_code = SCLP_CMD_READ_EVENT_DATA,
+       .handler   = sclp_read_event_data
+};
+
+static struct sclp_call_register sclp_write_event_mask_register = {
+       .sclp_code = SCLP_CMD_WRITE_EVENT_MASK,
+       .handler   = sclp_write_event_mask
+};
+
+void sclp_event_facility_init(void)
+{
+       zllist_init(&sclp_event_types_list);
+
+       sclp_register(&sclp_write_event_mask_register);
+       sclp_register(&sclp_write_event_data_register);
+       sclp_register(&sclp_read_event_data_register);
+}
+
+__ZLAUTOINIT(sclp_event_facility_init)
Index: zlive/sclp/sclp.c
===================================================================
--- /dev/null
+++ zlive/sclp/sclp.c
@@ -0,0 +1,92 @@
+/*
+ * z/Live service call instruction interceptions
+ * Copyright IBM Corp. 2007
+ * Author: Carsten Otte <[EMAIL PROTECTED]>
+ *
+ * This file is licensed under the terms of the GNU General Public License(GPL)
+ */
+
+#include <zlautoinit.h>
+#include <zlmessage.h>
+#include <zlintercept.h>
+#include <zlsclp.h>
+#include <zlpriv.h>
+#include <zlcpu_lib.h>
+#include <zlinterrupt.h>
+
+static struct zllist sclp_handlers;
+
+int sclp_service_call(struct zlcpu *cpu)
+{
+       uint64_t sccb  = cpu->gpr->regs[cl_get_ipbh0(cpu) & 0xf];
+       uint64_t code = cpu->gpr->regs[(cl_get_ipbh0(cpu) & 0xf0) >> 4];
+       struct zllist *entry;
+       struct sclp_call_register *scr;
+
+       // FIXME: check_region(cpu, addr, addr + length - 1);
+       check_addr(cpu, sccb);
+       if (sccb & ~SCLP_SCCB_ADDRESS_BITS) {
+               log("cpu %d: invalid sccb address 0x%lx", cpu->cpuno, sccb);
+               goto out;
+       }
+       for (entry = sclp_handlers.next; entry != &sclp_handlers;
+            entry = entry->next) {
+               scr = (struct sclp_call_register *) entry;
+               if (scr->sclp_code == code) {
+                       debug("cpu %d: sclp service call 0x%lx, sccb 0x%lx, "
+                             "addr 0x%lx",
+                             cpu->cpuno, code, sccb, cl_get_psw(cpu).addr);
+                       return scr->handler(cpu, sccb);
+               }
+       }
+       log("cpu %d: unknown sclp service call 0x%lx, sccb 0x%lx, addr 0x%lx",
+           cpu->cpuno, code, sccb, cl_get_psw(cpu).addr);
+out:
+       setcc(cpu, 3);
+       return may_do_cpu_work(cpu);
+}
+
+static int _sclp_interrupt(struct zlcpu *cpu, void *__param, int cleanup)
+{
+        struct lowcore *lowcore;
+        uint32_t param = (unsigned long)__param;
+
+       if (cleanup) {
+               log ("cpu %d: dropping sclp interrupt, sccb 0x%x",
+                    cpu->cpuno, param);
+               return 0;
+       }
+       if (!(cl_get_gcr(cpu, 0) && 0x00000200) || ext_int_masked(cpu))
+               return -EAGAIN;
+       lowcore = (struct lowcore *) (glo_origin + cl_get_prefix(cpu));
+       lowcore->ext_params = param;
+       return enter_extint(cpu, EXTINT_SERVICE_SIGNAL);
+}
+
+/* delivers asynchronous service-signal interruption for finished sccb */
+void sclp_interrupt(uint32_t extint_param)
+{
+       struct zlcpu *cpu = get_interrupt_cpu();
+
+       if (!cpu)
+               report_it("cannot get interrupt cpu, loosing interrupt");
+       debug("extint_param=0x%x", extint_param);
+       add_cpu_work_kick(cpu, _sclp_interrupt, (void *)(unsigned 
long)extint_param);
+       put_cpu(cpu);
+}
+
+/* registers a handler for a particular SCLP command code */
+void sclp_register(struct sclp_call_register *scr)
+{
+       zllist_add ((struct zllist *)scr, &sclp_handlers);
+       debug("added sclp handler for commmand 0x%04lx", scr->sclp_code)
+}
+
+void init_sclp(void)
+{
+       // initialize sclp_handlers list
+       sclp_handlers.next = &sclp_handlers;
+       sclp_handlers.prev = &sclp_handlers;
+       autoinit_sclp(); // see makefile magic
+       register_privileged_handler(PRIV_SCLP_CALL, sclp_service_call);
+}
Index: zlive/sclp/scp_read_info.c
===================================================================
--- /dev/null
+++ zlive/sclp/scp_read_info.c
@@ -0,0 +1,46 @@
+/*
+ * z/Live scp read info sclp call
+ * Copyright IBM Corp. 2007
+ * Author: Carsten Otte <[EMAIL PROTECTED]>
+ *
+ * This file is licensed under the terms of the GNU General Public License(GPL)
+ */
+
+#include <string.h>
+
+#include <zlintercept.h>
+#include <zlglobals.h>
+#include <zlautoinit.h>
+#include <zlsclp.h>
+#include <zlcpu.h>
+#include <zlcpu_lib.h>
+
+static int scp_read_info(struct zlcpu *cpu, uint32_t _sccb)
+{
+       struct sccb_scp_read_info *sccb = (void *)(_sccb + glo_origin);
+
+       sccb->mem_code = glo_memsize>>20;
+       sccb->increment = 1;
+       sccb->header.response_code = 0x10;
+       setcc(cpu, 3);
+       return may_do_cpu_work(cpu);
+}
+
+static struct sclp_call_register read_scp_info_register = {
+       .sclp_code = SCLP_CMD_SCP_READ_INFO,
+       .handler   = scp_read_info
+};
+
+static struct sclp_call_register read_scp_info_force_register = {
+       .sclp_code = SCLP_CMD_SCP_READ_INFO_FORCE,
+       .handler   = scp_read_info
+};
+
+
+void read_scp_info_init(void)
+{
+       sclp_register (&read_scp_info_register);
+       sclp_register (&read_scp_info_force_register);
+}
+
+__ZLAUTOINIT(read_scp_info_init)
Index: zlive/sclp/signal_quiesce.c
===================================================================
--- /dev/null
+++ zlive/sclp/signal_quiesce.c
@@ -0,0 +1,45 @@
+/*
+ * z/Live console device driver
+ * Copyright IBM Corp. 2007
+ * Author: Martin Peschke <[EMAIL PROTECTED]>
+ *
+ * This file is licensed under the terms of the GNU General Public License(GPL)
+ */
+
+#include <unistd.h>
+#include <signal.h>
+#include <linux/errno.h>
+
+#include <zlautoinit.h>
+#include <zlmessage.h>
+#include <zlio_signal.h>
+#include <zlcpu.h>
+#include <zlcpu_lib.h>
+#include <zlsclp.h>
+
+static uint16_t signal_quiesce_send(void *__event, uint16_t length)
+{
+       struct event_buffer_signal_quiesce *event = __event;
+
+       if (length < sizeof(struct event_buffer_signal_quiesce))
+               return SCLP_RC_SOME_EVENTS_SUPPRESSED;
+
+       event->header.length = sizeof(struct event_buffer_signal_quiesce);
+       event->header.type = SCLP_EVENT_SIGNAL_QUIESCE;
+       event->header.flags &= ~SCLP_EVENT_BUFFER_ACCEPTED;
+       // FIXME: timeout (curently ignored by Linux, anyway)
+
+       return SCLP_RC_NORMAL_COMPLETION;
+}
+
+static struct sclp_event_types signal_quiesce = {
+       .send_mask = SCLP_EVENT_MASK_SIGNAL_QUIESCE,
+       .send = signal_quiesce_send,
+};
+
+void signal_quiesce_init(void)
+{
+       sclp_register_event(&signal_quiesce);
+}
+
+__ZLAUTOINIT(signal_quiesce_init)



-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel

Reply via email to