summary refs log tree commit diff
path: root/arch/s390
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-10-11 08:50:01 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2008-10-11 08:50:01 -0700
commit37d9869ed928268409b48f52c57449918c0fd307 (patch)
tree7dd954260d723d1e0716b6432ba07b5c7be7f2ac /arch/s390
parent098ef215b1e87cff51f983bae4e4e1358b932ec9 (diff)
parent89d49841e9e7a90b04b036b7dbe7521b55edbe24 (diff)
downloadlinux-37d9869ed928268409b48f52c57449918c0fd307.tar.gz
Merge branch 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6: (27 commits)
  [S390] Fix checkstack for s390
  [S390] fix initialization of stp
  [S390] 3215: Remove tasklet.
  [S390] console flush on panic / reboot
  [S390] introduce dirty bit for kvm live migration
  [S390] Add ioctl support for EMC Symmetrix Subsystem Control I/O
  [S390] xpram: per device block request queues.
  [S390] dasd: fix message flood for unsolicited interrupts
  [S390] Move private simple udelay function to arch/s390/lib/delay.c.
  [S390] dcssblk: add >2G DCSSs support and stacked contiguous DCSSs support.
  [S390] ptrace changes
  [S390] s390: use sys_pause for 31bit pause entry point
  [S390] qdio enhanced SIGA (iqdio) support.
  [S390] cio: fix cio_tpi.
  [S390] cio: Correct use of ! and &
  [S390] cio: inline assembly cleanup
  [S390] bus_id -> dev_set_name() for css and ccw busses
  [S390] bus_id ->dev_name() conversions in qdio
  [S390] Use s390_root_dev_* in kvm_virtio.
  [S390] more bus_id -> dev_name conversions
  ...
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/Kconfig1
-rw-r--r--arch/s390/include/asm/dasd.h13
-rw-r--r--arch/s390/include/asm/delay.h1
-rw-r--r--arch/s390/include/asm/pgtable.h45
-rw-r--r--arch/s390/include/asm/ptrace.h1
-rw-r--r--arch/s390/include/asm/qdio.h8
-rw-r--r--arch/s390/include/asm/syscall.h80
-rw-r--r--arch/s390/include/asm/thread_info.h2
-rw-r--r--arch/s390/kernel/compat_linux.c8
-rw-r--r--arch/s390/kernel/compat_linux.h1
-rw-r--r--arch/s390/kernel/compat_wrapper.S2
-rw-r--r--arch/s390/kernel/entry.S50
-rw-r--r--arch/s390/kernel/entry64.S42
-rw-r--r--arch/s390/kernel/ptrace.c61
-rw-r--r--arch/s390/kernel/signal.c13
-rw-r--r--arch/s390/kernel/syscalls.S2
-rw-r--r--arch/s390/kernel/time.c2
-rw-r--r--arch/s390/lib/delay.c13
-rw-r--r--arch/s390/mm/extmem.c251
19 files changed, 493 insertions, 103 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 8d41908e2513..4c03049e7db9 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -74,6 +74,7 @@ config S390
 	select HAVE_KPROBES
 	select HAVE_KRETPROBES
 	select HAVE_KVM if 64BIT
+	select HAVE_ARCH_TRACEHOOK
 
 source "init/Kconfig"
 
diff --git a/arch/s390/include/asm/dasd.h b/arch/s390/include/asm/dasd.h
index 3f002e13d024..55b2b80cdf6e 100644
--- a/arch/s390/include/asm/dasd.h
+++ b/arch/s390/include/asm/dasd.h
@@ -3,6 +3,8 @@
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ * EMC Symmetrix ioctl Copyright EMC Corporation, 2008
+ * Author.........: Nigel Hislop <hislop_nigel@emc.com>
  *
  * This file is the interface of the DASD device driver, which is exported to user space
  * any future changes wrt the API will result in a change of the APIVERSION reported
@@ -202,6 +204,16 @@ typedef struct attrib_data_t {
 #define DASD_SEQ_PRESTAGE  0x4
 #define DASD_REC_ACCESS    0x5
 
+/*
+ * Perform EMC Symmetrix I/O
+ */
+typedef struct dasd_symmio_parms {
+	unsigned char reserved[8];	/* compat with older releases */
+	unsigned long long psf_data;	/* char * cast to u64 */
+	unsigned long long rssd_result; /* char * cast to u64 */
+	int psf_data_len;
+	int rssd_result_len;
+} __attribute__ ((packed)) dasd_symmio_parms_t;
 
 /********************************************************************************
  * SECTION: Definition of IOCTLs
@@ -247,6 +259,7 @@ typedef struct attrib_data_t {
 /* Set Attributes (cache operations) */
 #define BIODASDSATTR   _IOW(DASD_IOCTL_LETTER,2,attrib_data_t) 
 
+#define BIODASDSYMMIO  _IOWR(DASD_IOCTL_LETTER, 240, dasd_symmio_parms_t)
 
 #endif				/* DASD_H */
 
diff --git a/arch/s390/include/asm/delay.h b/arch/s390/include/asm/delay.h
index 78357314c450..a356c958e260 100644
--- a/arch/s390/include/asm/delay.h
+++ b/arch/s390/include/asm/delay.h
@@ -15,6 +15,7 @@
 #define _S390_DELAY_H
 
 extern void __udelay(unsigned long usecs);
+extern void udelay_simple(unsigned long usecs);
 extern void __delay(unsigned long loops);
 
 #define udelay(n) __udelay(n)
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 0bdb704ae051..1a928f84afd6 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -281,6 +281,9 @@ extern char empty_zero_page[PAGE_SIZE];
 #define RCP_GR_BIT	50
 #define RCP_GC_BIT	49
 
+/* User dirty bit for KVM's migration feature */
+#define KVM_UD_BIT	47
+
 #ifndef __s390x__
 
 /* Bits in the segment table address-space-control-element */
@@ -575,12 +578,16 @@ static inline void ptep_rcp_copy(pte_t *ptep)
 	unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
 
 	skey = page_get_storage_key(page_to_phys(page));
-	if (skey & _PAGE_CHANGED)
+	if (skey & _PAGE_CHANGED) {
 		set_bit_simple(RCP_GC_BIT, pgste);
+		set_bit_simple(KVM_UD_BIT, pgste);
+	}
 	if (skey & _PAGE_REFERENCED)
 		set_bit_simple(RCP_GR_BIT, pgste);
-	if (test_and_clear_bit_simple(RCP_HC_BIT, pgste))
+	if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) {
 		SetPageDirty(page);
+		set_bit_simple(KVM_UD_BIT, pgste);
+	}
 	if (test_and_clear_bit_simple(RCP_HR_BIT, pgste))
 		SetPageReferenced(page);
 #endif
@@ -744,6 +751,40 @@ static inline pte_t pte_mkspecial(pte_t pte)
 	return pte;
 }
 
+#ifdef CONFIG_PGSTE
+/*
+ * Get (and clear) the user dirty bit for a PTE.
+ */
+static inline int kvm_s390_test_and_clear_page_dirty(struct mm_struct *mm,
+						     pte_t *ptep)
+{
+	int dirty;
+	unsigned long *pgste;
+	struct page *page;
+	unsigned int skey;
+
+	if (!mm->context.pgstes)
+		return -EINVAL;
+	rcp_lock(ptep);
+	pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
+	page = virt_to_page(pte_val(*ptep));
+	skey = page_get_storage_key(page_to_phys(page));
+	if (skey & _PAGE_CHANGED) {
+		set_bit_simple(RCP_GC_BIT, pgste);
+		set_bit_simple(KVM_UD_BIT, pgste);
+	}
+	if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) {
+		SetPageDirty(page);
+		set_bit_simple(KVM_UD_BIT, pgste);
+	}
+	dirty = test_and_clear_bit_simple(KVM_UD_BIT, pgste);
+	if (skey & _PAGE_CHANGED)
+		page_clear_dirty(page);
+	rcp_unlock(ptep);
+	return dirty;
+}
+#endif
+
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
 static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
 					    unsigned long addr, pte_t *ptep)
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index af2c9ac28a07..a7226f8143fb 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -490,6 +490,7 @@ extern void user_disable_single_step(struct task_struct *);
 
 #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
 #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN)
+#define user_stack_pointer(regs)((regs)->gprs[15])
 #define regs_return_value(regs)((regs)->gprs[2])
 #define profile_pc(regs) instruction_pointer(regs)
 extern void show_regs(struct pt_regs * regs);
diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h
index 6813772171f2..4734c3f05354 100644
--- a/arch/s390/include/asm/qdio.h
+++ b/arch/s390/include/asm/qdio.h
@@ -299,7 +299,13 @@ struct qdio_ssqd_desc {
 	u8 mbccnt;
 	u16 qdioac2;
 	u64 sch_token;
-	u64:64;
+	u8 mro;
+	u8 mri;
+	u8:8;
+	u8 sbalic;
+	u16:16;
+	u8:8;
+	u8 mmwc;
 } __attribute__ ((packed));
 
 /* params are: ccw_device, qdio_error, queue_number,
diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h
new file mode 100644
index 000000000000..6e623971fbb9
--- /dev/null
+++ b/arch/s390/include/asm/syscall.h
@@ -0,0 +1,80 @@
+/*
+ * Access to user system call parameters and results
+ *
+ *  Copyright IBM Corp. 2008
+ *  Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ */
+
+#ifndef _ASM_SYSCALL_H
+#define _ASM_SYSCALL_H	1
+
+#include <asm/ptrace.h>
+
+static inline long syscall_get_nr(struct task_struct *task,
+				  struct pt_regs *regs)
+{
+	if (regs->trap != __LC_SVC_OLD_PSW)
+		return -1;
+	return regs->gprs[2];
+}
+
+static inline void syscall_rollback(struct task_struct *task,
+				    struct pt_regs *regs)
+{
+	regs->gprs[2] = regs->orig_gpr2;
+}
+
+static inline long syscall_get_error(struct task_struct *task,
+				     struct pt_regs *regs)
+{
+	return (regs->gprs[2] >= -4096UL) ? -regs->gprs[2] : 0;
+}
+
+static inline long syscall_get_return_value(struct task_struct *task,
+					    struct pt_regs *regs)
+{
+	return regs->gprs[2];
+}
+
+static inline void syscall_set_return_value(struct task_struct *task,
+					    struct pt_regs *regs,
+					    int error, long val)
+{
+	regs->gprs[2] = error ? -error : val;
+}
+
+static inline void syscall_get_arguments(struct task_struct *task,
+					 struct pt_regs *regs,
+					 unsigned int i, unsigned int n,
+					 unsigned long *args)
+{
+	BUG_ON(i + n > 6);
+#ifdef CONFIG_COMPAT
+	if (test_tsk_thread_flag(task, TIF_31BIT)) {
+		if (i + n == 6)
+			args[--n] = (u32) regs->args[0];
+		while (n-- > 0)
+			args[n] = (u32) regs->gprs[2 + i + n];
+	}
+#endif
+	if (i + n == 6)
+		args[--n] = regs->args[0];
+	memcpy(args, &regs->gprs[2 + i], n * sizeof(args[0]));
+}
+
+static inline void syscall_set_arguments(struct task_struct *task,
+					 struct pt_regs *regs,
+					 unsigned int i, unsigned int n,
+					 const unsigned long *args)
+{
+	BUG_ON(i + n > 6);
+	if (i + n == 6)
+		regs->args[0] = args[--n];
+	memcpy(&regs->gprs[2 + i], args, n * sizeof(args[0]));
+}
+
+#endif	/* _ASM_SYSCALL_H */
diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h
index 91a8f93ad355..ea40a9d690fc 100644
--- a/arch/s390/include/asm/thread_info.h
+++ b/arch/s390/include/asm/thread_info.h
@@ -86,6 +86,7 @@ static inline struct thread_info *current_thread_info(void)
  * thread information flags bit numbers
  */
 #define TIF_SYSCALL_TRACE	0	/* syscall trace active */
+#define TIF_NOTIFY_RESUME	1	/* callback before returning to user */
 #define TIF_SIGPENDING		2	/* signal pending */
 #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 #define TIF_RESTART_SVC		4	/* restart svc with new svc number */
@@ -100,6 +101,7 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_RESTORE_SIGMASK	20	/* restore signal mask in do_signal() */
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
+#define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
 #define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index d7f22226fc4e..98e246dc0233 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -608,14 +608,6 @@ asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv, struct time
 	return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
 }
 
-/* These are here just in case some old sparc32 binary calls it. */
-asmlinkage long sys32_pause(void)
-{
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	return -ERESTARTNOHAND;
-}
-
 asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf,
 				size_t count, u32 poshi, u32 poslo)
 {
diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h
index 20723a062017..05f8516366ab 100644
--- a/arch/s390/kernel/compat_linux.h
+++ b/arch/s390/kernel/compat_linux.h
@@ -206,7 +206,6 @@ long sys32_gettimeofday(struct compat_timeval __user *tv,
 			struct timezone __user *tz);
 long sys32_settimeofday(struct compat_timeval __user *tv,
 			struct timezone __user *tz);
-long sys32_pause(void);
 long sys32_pread64(unsigned int fd, char __user *ubuf, size_t count,
 		   u32 poshi, u32 poslo);
 long sys32_pwrite64(unsigned int fd, const char __user *ubuf,
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index 328a20e880b5..ee51ca9e23b5 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -128,8 +128,6 @@ sys32_alarm_wrapper:
 	llgfr	%r2,%r2			# unsigned int
 	jg	sys_alarm		# branch to system call
 
-#sys32_pause_wrapper			# void
-
 	.globl	compat_sys_utime_wrapper
 compat_sys_utime_wrapper:
 	llgtr	%r2,%r2			# char *
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 708cf9cf9a35..ed500ef799b7 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -49,9 +49,9 @@ SP_ILC	     =	STACK_FRAME_OVERHEAD + __PT_ILC
 SP_TRAP      =	STACK_FRAME_OVERHEAD + __PT_TRAP
 SP_SIZE      =	STACK_FRAME_OVERHEAD + __PT_SIZE
 
-_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
 		 _TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
-_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
 		 _TIF_MCCK_PENDING)
 
 STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
@@ -318,6 +318,8 @@ sysc_work:
 	bo	BASED(sysc_reschedule)
 	tm	__TI_flags+3(%r9),_TIF_SIGPENDING
 	bnz	BASED(sysc_sigpending)
+	tm	__TI_flags+3(%r9),_TIF_NOTIFY_RESUME
+	bnz	BASED(sysc_notify_resume)
 	tm	__TI_flags+3(%r9),_TIF_RESTART_SVC
 	bo	BASED(sysc_restart)
 	tm	__TI_flags+3(%r9),_TIF_SINGLE_STEP
@@ -356,6 +358,16 @@ sysc_sigpending:
 	b	BASED(sysc_work_loop)
 
 #
+# _TIF_NOTIFY_RESUME is set, call do_notify_resume
+#
+sysc_notify_resume:
+	la	%r2,SP_PTREGS(%r15)	# load pt_regs
+	l	%r1,BASED(.Ldo_notify_resume)
+	la	%r14,BASED(sysc_work_loop)
+	br	%r1			# call do_notify_resume
+
+
+#
 # _TIF_RESTART_SVC is set, set up registers and restart svc
 #
 sysc_restart:
@@ -378,20 +390,21 @@ sysc_singlestep:
 	br	%r1			# branch to do_single_step
 
 #
-# call trace before and after sys_call
+# call tracehook_report_syscall_entry/tracehook_report_syscall_exit before
+# and after the system call
 #
 sysc_tracesys:
-	l	%r1,BASED(.Ltrace)
+	l	%r1,BASED(.Ltrace_entry)
 	la	%r2,SP_PTREGS(%r15)	# load pt_regs
 	la	%r3,0
 	srl	%r7,2
 	st	%r7,SP_R2(%r15)
 	basr	%r14,%r1
-	clc	SP_R2(4,%r15),BASED(.Lnr_syscalls)
+	cl	%r2,BASED(.Lnr_syscalls)
 	bnl	BASED(sysc_tracenogo)
 	l	%r8,BASED(.Lsysc_table)
-	l	%r7,SP_R2(%r15) 	# strace might have changed the
-	sll	%r7,2			#  system call
+	lr	%r7,%r2
+	sll	%r7,2			# *4
 	l	%r8,0(%r7,%r8)
 sysc_tracego:
 	lm	%r3,%r6,SP_R3(%r15)
@@ -401,9 +414,8 @@ sysc_tracego:
 sysc_tracenogo:
 	tm	__TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
 	bz	BASED(sysc_return)
-	l	%r1,BASED(.Ltrace)
+	l	%r1,BASED(.Ltrace_exit)
 	la	%r2,SP_PTREGS(%r15)	# load pt_regs
-	la	%r3,1
 	la	%r14,BASED(sysc_return)
 	br	%r1
 
@@ -666,6 +678,8 @@ io_work_loop:
 	bo	BASED(io_reschedule)
 	tm	__TI_flags+3(%r9),_TIF_SIGPENDING
 	bnz	BASED(io_sigpending)
+	tm	__TI_flags+3(%r9),_TIF_NOTIFY_RESUME
+	bnz	BASED(io_notify_resume)
 	b	BASED(io_restore)
 io_work_done:
 
@@ -704,6 +718,19 @@ io_sigpending:
 	TRACE_IRQS_OFF
 	b	BASED(io_work_loop)
 
+#
+# _TIF_SIGPENDING is set, call do_signal
+#
+io_notify_resume:
+	TRACE_IRQS_ON
+	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
+	la	%r2,SP_PTREGS(%r15)	# load pt_regs
+	l	%r1,BASED(.Ldo_notify_resume)
+	basr	%r14,%r1		# call do_signal
+	stnsm	__SF_EMPTY(%r15),0xfc	# disable I/O and ext. interrupts
+	TRACE_IRQS_OFF
+	b	BASED(io_work_loop)
+
 /*
  * External interrupt handler routine
  */
@@ -1070,6 +1097,8 @@ cleanup_io_leave_insn:
 .Ldo_IRQ:	.long	do_IRQ
 .Ldo_extint:	.long	do_extint
 .Ldo_signal:	.long	do_signal
+.Ldo_notify_resume:
+		.long	do_notify_resume
 .Lhandle_per:	.long	do_single_step
 .Ldo_execve:	.long	do_execve
 .Lexecve_tail:	.long	execve_tail
@@ -1079,7 +1108,8 @@ cleanup_io_leave_insn:
 .Lpreempt_schedule_irq:
 		.long	preempt_schedule_irq
 #endif
-.Ltrace:	.long	syscall_trace
+.Ltrace_entry:	.long	do_syscall_trace_enter
+.Ltrace_exit:	.long	do_syscall_trace_exit
 .Lschedtail:	.long	schedule_tail
 .Lsysc_table:	.long	sys_call_table
 #ifdef CONFIG_TRACE_IRQFLAGS
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index fee10177dbfc..d7ce150453f2 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -52,9 +52,9 @@ SP_SIZE      =	STACK_FRAME_OVERHEAD + __PT_SIZE
 STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
 STACK_SIZE  = 1 << STACK_SHIFT
 
-_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
 		 _TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
-_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
 		 _TIF_MCCK_PENDING)
 
 #define BASED(name) name-system_call(%r13)
@@ -310,6 +310,8 @@ sysc_work:
 	jo	sysc_reschedule
 	tm	__TI_flags+7(%r9),_TIF_SIGPENDING
 	jnz	sysc_sigpending
+	tm	__TI_flags+7(%r9),_TIF_NOTIFY_RESUME
+	jnz	sysc_notify_resume
 	tm	__TI_flags+7(%r9),_TIF_RESTART_SVC
 	jo	sysc_restart
 	tm	__TI_flags+7(%r9),_TIF_SINGLE_STEP
@@ -345,6 +347,14 @@ sysc_sigpending:
 	j	sysc_work_loop
 
 #
+# _TIF_NOTIFY_RESUME is set, call do_notify_resume
+#
+sysc_notify_resume:
+	la	%r2,SP_PTREGS(%r15)	# load pt_regs
+	larl	%r14,sysc_work_loop
+	jg	do_notify_resume	# call do_notify_resume
+
+#
 # _TIF_RESTART_SVC is set, set up registers and restart svc
 #
 sysc_restart:
@@ -367,20 +377,19 @@ sysc_singlestep:
 	jg	do_single_step		# branch to do_sigtrap
 
 #
-# call syscall_trace before and after system call
-# special linkage: %r12 contains the return address for trace_svc
+# call tracehook_report_syscall_entry/tracehook_report_syscall_exit before
+# and after the system call
 #
 sysc_tracesys:
 	la	%r2,SP_PTREGS(%r15)	# load pt_regs
 	la	%r3,0
 	srl	%r7,2
 	stg	%r7,SP_R2(%r15)
-	brasl	%r14,syscall_trace
+	brasl	%r14,do_syscall_trace_enter
 	lghi	%r0,NR_syscalls
-	clg	%r0,SP_R2(%r15)
+	clgr	%r0,%r2
 	jnh	sysc_tracenogo
-	lg	%r7,SP_R2(%r15)		# strace might have changed the
-	sll	%r7,2			# system call
+	slag	%r7,%r2,2		# *4
 	lgf	%r8,0(%r7,%r10)
 sysc_tracego:
 	lmg	%r3,%r6,SP_R3(%r15)
@@ -391,9 +400,8 @@ sysc_tracenogo:
 	tm	__TI_flags+7(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
 	jz	sysc_return
 	la	%r2,SP_PTREGS(%r15)	# load pt_regs
-	la	%r3,1
 	larl	%r14,sysc_return	# return point is sysc_return
-	jg	syscall_trace
+	jg	do_syscall_trace_exit
 
 #
 # a new process exits the kernel with ret_from_fork
@@ -672,6 +680,8 @@ io_work_loop:
 	jo	io_reschedule
 	tm	__TI_flags+7(%r9),_TIF_SIGPENDING
 	jnz	io_sigpending
+	tm	__TI_flags+7(%r9),_TIF_NOTIFY_RESUME
+	jnz	io_notify_resume
 	j	io_restore
 io_work_done:
 
@@ -712,6 +722,18 @@ io_sigpending:
 	TRACE_IRQS_OFF
 	j	io_work_loop
 
+#
+# _TIF_NOTIFY_RESUME or is set, call do_notify_resume
+#
+io_notify_resume:
+	TRACE_IRQS_ON
+	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
+	la	%r2,SP_PTREGS(%r15)	# load pt_regs
+	brasl	%r14,do_notify_resume	# call do_notify_resume
+	stnsm	__SF_EMPTY(%r15),0xfc	# disable I/O and ext. interrupts
+	TRACE_IRQS_OFF
+	j	io_work_loop
+
 /*
  * External interrupt handler routine
  */
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index c8b08289eb87..1f31be1ecc4b 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -35,6 +35,7 @@
 #include <linux/signal.h>
 #include <linux/elf.h>
 #include <linux/regset.h>
+#include <linux/tracehook.h>
 
 #include <asm/segment.h>
 #include <asm/page.h>
@@ -639,40 +640,44 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
 }
 #endif
 
-asmlinkage void
-syscall_trace(struct pt_regs *regs, int entryexit)
+asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
 {
-	if (unlikely(current->audit_context) && entryexit)
-		audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]), regs->gprs[2]);
-
-	if (!test_thread_flag(TIF_SYSCALL_TRACE))
-		goto out;
-	if (!(current->ptrace & PT_PTRACED))
-		goto out;
-	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
-				 ? 0x80 : 0));
+	long ret;
 
 	/*
-	 * If the debuffer has set an invalid system call number,
-	 * we prepare to skip the system call restart handling.
+	 * The sysc_tracesys code in entry.S stored the system
+	 * call number to gprs[2].
 	 */
-	if (!entryexit && regs->gprs[2] >= NR_syscalls)
+	ret = regs->gprs[2];
+	if (test_thread_flag(TIF_SYSCALL_TRACE) &&
+	    (tracehook_report_syscall_entry(regs) ||
+	     regs->gprs[2] >= NR_syscalls)) {
+		/*
+		 * Tracing decided this syscall should not happen or the
+		 * debugger stored an invalid system call number. Skip
+		 * the system call and the system call restart handling.
+		 */
 		regs->trap = -1;
-
-	/*
-	 * this isn't the same as continuing with a signal, but it will do
-	 * for normal use.  strace only continues with a signal if the
-	 * stopping signal is not SIGTRAP.  -brl
-	 */
-	if (current->exit_code) {
-		send_sig(current->exit_code, current, 1);
-		current->exit_code = 0;
+		ret = -1;
 	}
- out:
-	if (unlikely(current->audit_context) && !entryexit)
-		audit_syscall_entry(test_thread_flag(TIF_31BIT)?AUDIT_ARCH_S390:AUDIT_ARCH_S390X,
-				    regs->gprs[2], regs->orig_gpr2, regs->gprs[3],
-				    regs->gprs[4], regs->gprs[5]);
+
+	if (unlikely(current->audit_context))
+		audit_syscall_entry(test_thread_flag(TIF_31BIT) ?
+					AUDIT_ARCH_S390 : AUDIT_ARCH_S390X,
+				    regs->gprs[2], regs->orig_gpr2,
+				    regs->gprs[3], regs->gprs[4],
+				    regs->gprs[5]);
+	return ret;
+}
+
+asmlinkage void do_syscall_trace_exit(struct pt_regs *regs)
+{
+	if (unlikely(current->audit_context))
+		audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]),
+				   regs->gprs[2]);
+
+	if (test_thread_flag(TIF_SYSCALL_TRACE))
+		tracehook_report_syscall_exit(regs, 0);
 }
 
 /*
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index b97682040215..4f7fc3059a8e 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -24,6 +24,7 @@
 #include <linux/tty.h>
 #include <linux/personality.h>
 #include <linux/binfmts.h>
+#include <linux/tracehook.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/lowcore.h>
@@ -507,6 +508,12 @@ void do_signal(struct pt_regs *regs)
 			 */
 			if (current->thread.per_info.single_step)
 				set_thread_flag(TIF_SINGLE_STEP);
+
+			/*
+			 * Let tracing know that we've done the handler setup.
+			 */
+			tracehook_signal_handler(signr, &info, &ka, regs,
+					 test_thread_flag(TIF_SINGLE_STEP));
 		}
 		return;
 	}
@@ -526,3 +533,9 @@ void do_signal(struct pt_regs *regs)
 		set_thread_flag(TIF_RESTART_SVC);
 	}
 }
+
+void do_notify_resume(struct pt_regs *regs)
+{
+	clear_thread_flag(TIF_NOTIFY_RESUME);
+	tracehook_notify_resume(regs);
+}
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
index c66d35e55142..3ae303914b42 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -37,7 +37,7 @@ SYSCALL(sys_stime,sys_ni_syscall,sys32_stime_wrapper)		/* 25 old stime syscall *
 SYSCALL(sys_ptrace,sys_ptrace,sys32_ptrace_wrapper)
 SYSCALL(sys_alarm,sys_alarm,sys32_alarm_wrapper)
 NI_SYSCALL							/* old fstat syscall */
-SYSCALL(sys_pause,sys_pause,sys32_pause)
+SYSCALL(sys_pause,sys_pause,sys_pause)
 SYSCALL(sys_utime,sys_utime,compat_sys_utime_wrapper)		/* 30 */
 NI_SYSCALL							/* old stty syscall */
 NI_SYSCALL							/* old gtty syscall */
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index 06acb1a18bbc..b94e9e3b694a 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -1356,7 +1356,7 @@ static void __init stp_reset(void)
 
 	stp_page = alloc_bootmem_pages(PAGE_SIZE);
 	rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000);
-	if (rc == 1)
+	if (rc == 0)
 		set_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags);
 	else if (stp_online) {
 		printk(KERN_WARNING "Running on non STP capable machine.\n");
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c
index 0953cee05efc..6ccb9fab055a 100644
--- a/arch/s390/lib/delay.c
+++ b/arch/s390/lib/delay.c
@@ -92,3 +92,16 @@ out:
 	local_irq_restore(flags);
 	preempt_enable();
 }
+
+/*
+ * Simple udelay variant. To be used on startup and reboot
+ * when the interrupt handler isn't working.
+ */
+void udelay_simple(unsigned long usecs)
+{
+	u64 end;
+
+	end = get_clock() + ((u64) usecs << 12);
+	while (get_clock() < end)
+		cpu_relax();
+}
diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c
index f231f5ec74b6..580fc64cc735 100644
--- a/arch/s390/mm/extmem.c
+++ b/arch/s390/mm/extmem.c
@@ -43,20 +43,40 @@
 #define DCSS_FINDSEG    0x0c
 #define DCSS_LOADNOLY   0x10
 #define DCSS_SEGEXT     0x18
+#define DCSS_LOADSHRX	0x20
+#define DCSS_LOADNSRX	0x24
+#define DCSS_FINDSEGX	0x2c
+#define DCSS_SEGEXTX	0x38
 #define DCSS_FINDSEGA   0x0c
 
 struct qrange {
-	unsigned int  start; // 3byte start address, 1 byte type
-	unsigned int  end;   // 3byte end address, 1 byte reserved
+	unsigned long  start; /* last byte type */
+	unsigned long  end;   /* last byte reserved */
 };
 
 struct qout64 {
+	unsigned long segstart;
+	unsigned long segend;
+	int segcnt;
+	int segrcnt;
+	struct qrange range[6];
+};
+
+#ifdef CONFIG_64BIT
+struct qrange_old {
+	unsigned int start; /* last byte type */
+	unsigned int end;   /* last byte reserved */
+};
+
+/* output area format for the Diag x'64' old subcode x'18' */
+struct qout64_old {
 	int segstart;
 	int segend;
 	int segcnt;
 	int segrcnt;
-	struct qrange range[6];
+	struct qrange_old range[6];
 };
+#endif
 
 struct qin64 {
 	char qopcode;
@@ -86,6 +106,55 @@ static DEFINE_MUTEX(dcss_lock);
 static LIST_HEAD(dcss_list);
 static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC",
 					"EW/EN-MIXED" };
+static int loadshr_scode, loadnsr_scode, findseg_scode;
+static int segext_scode, purgeseg_scode;
+static int scode_set;
+
+/* set correct Diag x'64' subcodes. */
+static int
+dcss_set_subcodes(void)
+{
+#ifdef CONFIG_64BIT
+	char *name = kmalloc(8 * sizeof(char), GFP_DMA);
+	unsigned long rx, ry;
+	int rc;
+
+	if (name == NULL)
+		return -ENOMEM;
+
+	rx = (unsigned long) name;
+	ry = DCSS_FINDSEGX;
+
+	strcpy(name, "dummy");
+	asm volatile(
+		"	diag	%0,%1,0x64\n"
+		"0:	ipm	%2\n"
+		"	srl	%2,28\n"
+		"	j	2f\n"
+		"1:	la	%2,3\n"
+		"2:\n"
+		EX_TABLE(0b, 1b)
+		: "+d" (rx), "+d" (ry), "=d" (rc) : : "cc");
+
+	kfree(name);
+	/* Diag x'64' new subcodes are supported, set to new subcodes */
+	if (rc != 3) {
+		loadshr_scode = DCSS_LOADSHRX;
+		loadnsr_scode = DCSS_LOADNSRX;
+		purgeseg_scode = DCSS_PURGESEG;
+		findseg_scode = DCSS_FINDSEGX;
+		segext_scode = DCSS_SEGEXTX;
+		return 0;
+	}
+#endif
+	/* Diag x'64' new subcodes are not supported, set to old subcodes */
+	loadshr_scode = DCSS_LOADNOLY;
+	loadnsr_scode = DCSS_LOADNSR;
+	purgeseg_scode = DCSS_PURGESEG;
+	findseg_scode = DCSS_FINDSEG;
+	segext_scode = DCSS_SEGEXT;
+	return 0;
+}
 
 /*
  * Create the 8 bytes, ebcdic VM segment name from
@@ -135,25 +204,45 @@ segment_by_name (char *name)
  * Perform a function on a dcss segment.
  */
 static inline int
-dcss_diag (__u8 func, void *parameter,
+dcss_diag(int *func, void *parameter,
            unsigned long *ret1, unsigned long *ret2)
 {
 	unsigned long rx, ry;
 	int rc;
 
+	if (scode_set == 0) {
+		rc = dcss_set_subcodes();
+		if (rc < 0)
+			return rc;
+		scode_set = 1;
+	}
 	rx = (unsigned long) parameter;
-	ry = (unsigned long) func;
-	asm volatile(
+	ry = (unsigned long) *func;
+
 #ifdef CONFIG_64BIT
-		"	sam31\n"
-		"	diag	%0,%1,0x64\n"
-		"	sam64\n"
+	/* 64-bit Diag x'64' new subcode, keep in 64-bit addressing mode */
+	if (*func > DCSS_SEGEXT)
+		asm volatile(
+			"	diag	%0,%1,0x64\n"
+			"	ipm	%2\n"
+			"	srl	%2,28\n"
+			: "+d" (rx), "+d" (ry), "=d" (rc) : : "cc");
+	/* 31-bit Diag x'64' old subcode, switch to 31-bit addressing mode */
+	else
+		asm volatile(
+			"	sam31\n"
+			"	diag	%0,%1,0x64\n"
+			"	sam64\n"
+			"	ipm	%2\n"
+			"	srl	%2,28\n"
+			: "+d" (rx), "+d" (ry), "=d" (rc) : : "cc");
 #else
+	asm volatile(
 		"	diag	%0,%1,0x64\n"
-#endif
 		"	ipm	%2\n"
 		"	srl	%2,28\n"
 		: "+d" (rx), "+d" (ry), "=d" (rc) : : "cc");
+#endif
 	*ret1 = rx;
 	*ret2 = ry;
 	return rc;
@@ -190,14 +279,45 @@ query_segment_type (struct dcss_segment *seg)
 	qin->qoutlen = sizeof(struct qout64);
 	memcpy (qin->qname, seg->dcss_name, 8);
 
-	diag_cc = dcss_diag (DCSS_SEGEXT, qin, &dummy, &vmrc);
+	diag_cc = dcss_diag(&segext_scode, qin, &dummy, &vmrc);
 
+	if (diag_cc < 0) {
+		rc = diag_cc;
+		goto out_free;
+	}
 	if (diag_cc > 1) {
 		PRINT_WARN ("segment_type: diag returned error %ld\n", vmrc);
 		rc = dcss_diag_translate_rc (vmrc);
 		goto out_free;
 	}
 
+#ifdef CONFIG_64BIT
+	/* Only old format of output area of Diagnose x'64' is supported,
+	   copy data for the new format. */
+	if (segext_scode == DCSS_SEGEXT) {
+		struct qout64_old *qout_old;
+		qout_old = kzalloc(sizeof(struct qout64_old), GFP_DMA);
+		if (qout_old == NULL) {
+			rc = -ENOMEM;
+			goto out_free;
+		}
+		memcpy(qout_old, qout, sizeof(struct qout64_old));
+		qout->segstart = (unsigned long) qout_old->segstart;
+		qout->segend = (unsigned long) qout_old->segend;
+		qout->segcnt = qout_old->segcnt;
+		qout->segrcnt = qout_old->segrcnt;
+
+		if (qout->segcnt > 6)
+			qout->segrcnt = 6;
+		for (i = 0; i < qout->segrcnt; i++) {
+			qout->range[i].start =
+				(unsigned long) qout_old->range[i].start;
+			qout->range[i].end =
+				(unsigned long) qout_old->range[i].end;
+		}
+		kfree(qout_old);
+	}
+#endif
 	if (qout->segcnt > 6) {
 		rc = -ENOTSUPP;
 		goto out_free;
@@ -269,6 +389,30 @@ segment_type (char* name)
 }
 
 /*
+ * check if segment collides with other segments that are currently loaded
+ * returns 1 if this is the case, 0 if no collision was found
+ */
+static int
+segment_overlaps_others (struct dcss_segment *seg)
+{
+	struct list_head *l;
+	struct dcss_segment *tmp;
+
+	BUG_ON(!mutex_is_locked(&dcss_lock));
+	list_for_each(l, &dcss_list) {
+		tmp = list_entry(l, struct dcss_segment, list);
+		if ((tmp->start_addr >> 20) > (seg->end >> 20))
+			continue;
+		if ((tmp->end >> 20) < (seg->start_addr >> 20))
+			continue;
+		if (seg == tmp)
+			continue;
+		return 1;
+	}
+	return 0;
+}
+
+/*
  * real segment loading function, called from segment_load
  */
 static int
@@ -276,7 +420,8 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
 {
 	struct dcss_segment *seg = kmalloc(sizeof(struct dcss_segment),
 			GFP_DMA);
-	int dcss_command, rc, diag_cc;
+	int rc, diag_cc;
+	unsigned long start_addr, end_addr, dummy;
 
 	if (seg == NULL) {
 		rc = -ENOMEM;
@@ -287,6 +432,13 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
 	if (rc < 0)
 		goto out_free;
 
+	if (loadshr_scode == DCSS_LOADSHRX) {
+		if (segment_overlaps_others(seg)) {
+			rc = -EBUSY;
+			goto out_free;
+		}
+	}
+
 	rc = vmem_add_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
 
 	if (rc)
@@ -316,20 +468,28 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
 	}
 
 	if (do_nonshared)
-		dcss_command = DCSS_LOADNSR;
+		diag_cc = dcss_diag(&loadnsr_scode, seg->dcss_name,
+				&start_addr, &end_addr);
 	else
-		dcss_command = DCSS_LOADNOLY;
-
-	diag_cc = dcss_diag(dcss_command, seg->dcss_name,
-			&seg->start_addr, &seg->end);
+		diag_cc = dcss_diag(&loadshr_scode, seg->dcss_name,
+				&start_addr, &end_addr);
+	if (diag_cc < 0) {
+		dcss_diag(&purgeseg_scode, seg->dcss_name,
+				&dummy, &dummy);
+		rc = diag_cc;
+		goto out_resource;
+	}
 	if (diag_cc > 1) {
 		PRINT_WARN ("segment_load: could not load segment %s - "
-				"diag returned error (%ld)\n",name,seg->end);
-		rc = dcss_diag_translate_rc (seg->end);
-		dcss_diag(DCSS_PURGESEG, seg->dcss_name,
-				&seg->start_addr, &seg->end);
+				"diag returned error (%ld)\n",
+				name, end_addr);
+		rc = dcss_diag_translate_rc(end_addr);
+		dcss_diag(&purgeseg_scode, seg->dcss_name,
+				&dummy, &dummy);
 		goto out_resource;
 	}
+	seg->start_addr = start_addr;
+	seg->end = end_addr;
 	seg->do_nonshared = do_nonshared;
 	atomic_set(&seg->ref_count, 1);
 	list_add(&seg->list, &dcss_list);
@@ -423,8 +583,8 @@ int
 segment_modify_shared (char *name, int do_nonshared)
 {
 	struct dcss_segment *seg;
-	unsigned long dummy;
-	int dcss_command, rc, diag_cc;
+	unsigned long start_addr, end_addr, dummy;
+	int rc, diag_cc;
 
 	mutex_lock(&dcss_lock);
 	seg = segment_by_name (name);
@@ -445,38 +605,51 @@ segment_modify_shared (char *name, int do_nonshared)
 		goto out_unlock;
 	}
 	release_resource(seg->res);
-	if (do_nonshared) {
-		dcss_command = DCSS_LOADNSR;
+	if (do_nonshared)
 		seg->res->flags &= ~IORESOURCE_READONLY;
-	} else {
-		dcss_command = DCSS_LOADNOLY;
+	else
 		if (seg->vm_segtype == SEG_TYPE_SR ||
 		    seg->vm_segtype == SEG_TYPE_ER)
 			seg->res->flags |= IORESOURCE_READONLY;
-	}
+
 	if (request_resource(&iomem_resource, seg->res)) {
 		PRINT_WARN("segment_modify_shared: could not reload segment %s"
 			   " - overlapping resources\n", name);
 		rc = -EBUSY;
 		kfree(seg->res);
-		goto out_del;
+		goto out_del_mem;
+	}
+
+	dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy);
+	if (do_nonshared)
+		diag_cc = dcss_diag(&loadnsr_scode, seg->dcss_name,
+				&start_addr, &end_addr);
+	else
+		diag_cc = dcss_diag(&loadshr_scode, seg->dcss_name,
+				&start_addr, &end_addr);
+	if (diag_cc < 0) {
+		rc = diag_cc;
+		goto out_del_res;
 	}
-	dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
-	diag_cc = dcss_diag(dcss_command, seg->dcss_name,
-			&seg->start_addr, &seg->end);
 	if (diag_cc > 1) {
 		PRINT_WARN ("segment_modify_shared: could not reload segment %s"
-				" - diag returned error (%ld)\n",name,seg->end);
-		rc = dcss_diag_translate_rc (seg->end);
-		goto out_del;
+				" - diag returned error (%ld)\n",
+				name, end_addr);
+		rc = dcss_diag_translate_rc(end_addr);
+		goto out_del_res;
 	}
+	seg->start_addr = start_addr;
+	seg->end = end_addr;
 	seg->do_nonshared = do_nonshared;
 	rc = 0;
 	goto out_unlock;
- out_del:
+ out_del_res:
+	release_resource(seg->res);
+	kfree(seg->res);
+ out_del_mem:
 	vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
 	list_del(&seg->list);
-	dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
+	dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy);
 	kfree(seg);
  out_unlock:
 	mutex_unlock(&dcss_lock);
@@ -510,7 +683,7 @@ segment_unload(char *name)
 	kfree(seg->res);
 	vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
 	list_del(&seg->list);
-	dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
+	dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy);
 	kfree(seg);
 out_unlock:
 	mutex_unlock(&dcss_lock);
@@ -545,7 +718,7 @@ segment_save(char *name)
 	endpfn = (seg->end) >> PAGE_SHIFT;
 	sprintf(cmd1, "DEFSEG %s", name);
 	for (i=0; i<seg->segcnt; i++) {
-		sprintf(cmd1+strlen(cmd1), " %X-%X %s",
+		sprintf(cmd1+strlen(cmd1), " %lX-%lX %s",
 			seg->range[i].start >> PAGE_SHIFT,
 			seg->range[i].end >> PAGE_SHIFT,
 			segtype_string[seg->range[i].start & 0xff]);